Conversation
WalkthroughConverts exception/exit-based license validation to a status-driven model across Node and Ruby: validators now return statuses ('valid' | 'expired' | 'invalid' | 'missing') and log info/warnings instead of raising or exiting; startup initializers, utils, tests, and docs updated to the new status API and production-only paid-license messaging. Changes
Sequence Diagram(s)sequenceDiagram
participant App as Application / Rails boot
participant Engine as ReactOnRailsPro::Engine
participant License as LicenseValidator
participant Node as Node renderer (master.ts)
participant Logger as Logger
App->>Engine: after_initialize / check_license
Engine->>License: license_status
License->>License: load_license_string -> decode_license -> check_plan -> check_expiration
License-->>Engine: :valid / :expired / :invalid / :missing
Engine->>Logger: log info or warn message
Note over Node,License: Node master.ts calls getLicenseStatus() and logs similarly
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
size-limit report 📦
|
Pull Request ReviewThis PR implements a significant architectural change to the React on Rails Pro licensing model, moving from a "license-required" approach (app crashes without valid license) to a "license-optional with attribution" approach (app always runs, shows HTML comment indicating license status). ✅ Strengths1. Excellent Architectural Simplification
2. Strong Security Practices
3. Comprehensive Test Coverage
4. Graceful Degradation
|
Greptile OverviewGreptile SummaryThis PR changes React on Rails Pro from a “license-required” model to a “license-optional with attribution” model. On the Ruby side, Pro licensing is now represented as a status ( On the Node renderer side, license validation is similarly status-based ( Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
autonumber
participant App as Rails app boot
participant Engine as ReactOnRailsPro::Engine
participant LV as ReactOnRailsPro::LicenseValidator
participant Utils as ReactOnRailsPro::Utils
participant View as Rails view render
App->>Engine: initializer "check_license"
Engine->>LV: license_status()
LV-->>Engine: :valid | :missing | :expired | :invalid
Engine->>Engine: log_license_issue / info
View->>Utils: pro_attribution_comment()
Utils->>LV: license_status()
LV-->>Utils: status symbol
Utils-->>View: "<!-- Powered by ... | STATUS -->"
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@packages/react-on-rails-pro-node-renderer/src/shared/licenseValidator.ts`:
- Around line 105-126: Update the JSDoc for the checkExpiration function to
accurately list all possible return values: 'valid', 'expired', and 'invalid'
(used when the license.exp field is missing). Modify the `@returns` description on
the checkExpiration function to mention each status and the condition that
produces it (e.g., 'invalid' when exp is absent, 'expired' when exp < now,
'valid' otherwise), so the doc correctly reflects the implementation.
In `@react_on_rails_pro/lib/react_on_rails_pro/license_validator.rb`:
- Around line 29-37: The method license_data currently caches and returns
decoded license info even when license_status is :expired or :invalid; change it
so decoded data is only cached/returned when license_status == :valid: call
license_status, and only set/return `@license_data` if license_status equals
:valid (otherwise ensure `@license_data` is nil), and mirror this behavior at the
other caching site referenced (the similar cache assignments around lines 64-66)
so callers never receive decoded data for non-valid licenses; use the existing
license_status and `@license_data` symbols to locate and adjust the logic.
- Around line 73-83: The load_license_string method currently calls
File.read(config_path).strip without guarding against IO/encoding/permission
errors; update load_license_string to rescue standard file-read exceptions
(e.g., Errno::EACCES, Errno::ENOENT, Encoding::InvalidByteSequenceError,
IOError, and StandardError as a fallback) when reading config_path, log a
warning via Rails.logger.warn (or process logger) that the license file could
not be read including the error message, and return nil so the method maintains
its "never raises" contract; keep the existing ENV.fetch behavior and only apply
the rescue around the File.read(config_path).strip call.
🧹 Nitpick comments (1)
react_on_rails_pro/spec/react_on_rails_pro/license_validator_spec.rb (1)
59-63: Consider using a more robust caching verification approach.Testing caching by expecting
determine_license_status(a private method) to not be called couples the test to implementation details. If the internal method name changes, this test will break even though the behavior is correct.A more robust approach would verify caching via observable behavior:
♻️ Suggested alternative for verifying caching
it "caches the result" do - described_class.license_status - expect(described_class).not_to receive(:determine_license_status) - described_class.license_status + # Verify same object is returned (cached) + first_call = described_class.license_status + second_call = described_class.license_status + expect(first_call).to equal(second_call) end
Code Review: License Requirement RemovalI've reviewed PR #2324 and overall this is an excellent refactoring. The architectural shift from "fail-fast" to "warn-and-continue" is well-executed across both Ruby and TypeScript codebases. Here's my detailed feedback: ✅ Strengths1. Excellent API DesignThe new status-based API ( # Before: Exception-based (forces error handling everywhere)
def validated_license_data\!
# raises on error
end
# After: Status-based (allows graceful degradation)
def license_status
# returns symbol, never raises
endThis makes the code much easier to reason about and test. 2. Consistent Implementation Across LanguagesBoth Ruby and TypeScript implementations follow the same three-step pattern:
The parallel structure makes maintenance easier and reduces cognitive load. 3. Comprehensive Test CoverageThe test changes are thorough:
4. Security MaintainedJWT verification remains secure:
|
|
| Branch | abanoub/2323-license-optional-attribution |
| Testbed | github-actions |
Click to view all benchmark results
| Benchmark | failed_pct | Benchmark Result % (Result Δ%) | Upper Boundary % (Limit %) | p50_latency | Benchmark Result ms (Result Δ%) | Upper Boundary ms (Limit %) | p90_latency | Benchmark Result ms (Result Δ%) | Upper Boundary ms (Limit %) | p99_latency | Benchmark Result ms (Result Δ%) | Upper Boundary ms (Limit %) | rps | Benchmark Result req/s (Result Δ%) | Lower Boundary req/s (Limit %) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| /: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 3,167.10(0.00%)Baseline: 3,167.10 | 4,117.23 (76.92%) | 📈 view plot 🚷 view threshold | 3,851.36(0.00%)Baseline: 3,851.36 | 5,006.77 (76.92%) | 📈 view plot 🚷 view threshold | 33,082.55(0.00%)Baseline: 33,082.55 | 43,007.32 (76.92%) | 📈 view plot 🚷 view threshold | 2.58(0.00%)Baseline: 2.58 | 1.81 (70.00%) |
| /: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 33.88(0.00%)Baseline: 33.88 | 44.04 (76.92%) | 📈 view plot 🚷 view threshold | 55.60(0.00%)Baseline: 55.60 | 72.28 (76.92%) | 📈 view plot 🚷 view threshold | 380.20(0.00%)Baseline: 380.20 | 494.26 (76.92%) | 📈 view plot 🚷 view threshold | 217.36(0.00%)Baseline: 217.36 | 152.15 (70.00%) |
| /apollo_graphql: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 43.01(0.00%)Baseline: 43.01 | 55.91 (76.92%) | 📈 view plot 🚷 view threshold | 117.75(0.00%)Baseline: 117.75 | 153.07 (76.92%) | 📈 view plot 🚷 view threshold | 494.28(0.00%)Baseline: 494.28 | 642.56 (76.92%) | 📈 view plot 🚷 view threshold | 130.97(0.00%)Baseline: 130.97 | 91.68 (70.00%) |
| /async_components_demo: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 32.23(0.00%)Baseline: 32.23 | 41.90 (76.92%) | 📈 view plot 🚷 view threshold | 44.62(0.00%)Baseline: 44.62 | 58.01 (76.92%) | 📈 view plot 🚷 view threshold | 372.87(0.00%)Baseline: 372.87 | 484.73 (76.92%) | 📈 view plot 🚷 view threshold | 183.80(0.00%)Baseline: 183.80 | 128.66 (70.00%) |
| /async_on_server_sync_on_client: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 19.80(0.00%)Baseline: 19.80 | 25.74 (76.92%) | 📈 view plot 🚷 view threshold | 32.04(0.00%)Baseline: 32.04 | 41.65 (76.92%) | 📈 view plot 🚷 view threshold | 277.57(0.00%)Baseline: 277.57 | 360.84 (76.92%) | 📈 view plot 🚷 view threshold | 379.49(0.00%)Baseline: 379.49 | 265.64 (70.00%) |
| /async_on_server_sync_on_client_client_render: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 17.12(0.00%)Baseline: 17.12 | 22.26 (76.92%) | 📈 view plot 🚷 view threshold | 25.65(0.00%)Baseline: 25.65 | 33.34 (76.92%) | 📈 view plot 🚷 view threshold | 189.01(0.00%)Baseline: 189.01 | 245.71 (76.92%) | 📈 view plot 🚷 view threshold | 345.02(0.00%)Baseline: 345.02 | 241.51 (70.00%) |
| /async_render_function_returns_component: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 19.79(0.00%)Baseline: 19.79 | 25.73 (76.92%) | 📈 view plot 🚷 view threshold | 26.72(0.00%)Baseline: 26.72 | 34.74 (76.92%) | 📈 view plot 🚷 view threshold | 227.43(0.00%)Baseline: 227.43 | 295.66 (76.92%) | 📈 view plot 🚷 view threshold | 299.31(0.00%)Baseline: 299.31 | 209.52 (70.00%) |
| /async_render_function_returns_string: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 19.77(0.00%)Baseline: 19.77 | 25.70 (76.92%) | 📈 view plot 🚷 view threshold | 26.56(0.00%)Baseline: 26.56 | 34.53 (76.92%) | 📈 view plot 🚷 view threshold | 227.11(0.00%)Baseline: 227.11 | 295.24 (76.92%) | 📈 view plot 🚷 view threshold | 299.99(0.00%)Baseline: 299.99 | 209.99 (70.00%) |
| /broken_app: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 145.57(0.00%)Baseline: 145.57 | 189.24 (76.92%) | 📈 view plot 🚷 view threshold | 424.22(0.00%)Baseline: 424.22 | 551.49 (76.92%) | 📈 view plot 🚷 view threshold | 7,873.03(0.00%)Baseline: 7,873.03 | 10,234.94 (76.92%) | 📈 view plot 🚷 view threshold | 23.14(0.00%)Baseline: 23.14 | 16.20 (70.00%) |
| /broken_app: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 17.72(0.00%)Baseline: 17.72 | 23.04 (76.92%) | 📈 view plot 🚷 view threshold | 43.84(0.00%)Baseline: 43.84 | 56.99 (76.92%) | 📈 view plot 🚷 view threshold | 186.63(0.00%)Baseline: 186.63 | 242.62 (76.92%) | 📈 view plot 🚷 view threshold | 333.40(0.00%)Baseline: 333.40 | 233.38 (70.00%) |
| /cached_react_helmet: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 17.06(0.00%)Baseline: 17.06 | 22.18 (76.92%) | 📈 view plot 🚷 view threshold | 28.10(0.00%)Baseline: 28.10 | 36.53 (76.92%) | 📈 view plot 🚷 view threshold | 197.63(0.00%)Baseline: 197.63 | 256.92 (76.92%) | 📈 view plot 🚷 view threshold | 443.48(0.00%)Baseline: 443.48 | 310.44 (70.00%) |
| /cached_redux_component: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 17.95(0.00%)Baseline: 17.95 | 23.34 (76.92%) | 📈 view plot 🚷 view threshold | 30.05(0.00%)Baseline: 30.05 | 39.06 (76.92%) | 📈 view plot 🚷 view threshold | 214.04(0.00%)Baseline: 214.04 | 278.25 (76.92%) | 📈 view plot 🚷 view threshold | 420.05(0.00%)Baseline: 420.05 | 294.04 (70.00%) |
| /client_side_hello_world: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 11.92(0.00%)Baseline: 11.92 | 15.50 (76.92%) | 📈 view plot 🚷 view threshold | 15.53(0.00%)Baseline: 15.53 | 20.19 (76.92%) | 📈 view plot 🚷 view threshold | 137.83(0.00%)Baseline: 137.83 | 179.18 (76.92%) | 📈 view plot 🚷 view threshold | 496.10(0.00%)Baseline: 496.10 | 347.27 (70.00%) |
| /client_side_hello_world: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 17.85(0.00%)Baseline: 17.85 | 23.20 (76.92%) | 📈 view plot 🚷 view threshold | 28.62(0.00%)Baseline: 28.62 | 37.21 (76.92%) | 📈 view plot 🚷 view threshold | 203.09(0.00%)Baseline: 203.09 | 264.02 (76.92%) | 📈 view plot 🚷 view threshold | 437.21(0.00%)Baseline: 437.21 | 306.05 (70.00%) |
| /client_side_hello_world_shared_store: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 8.53(0.00%)Baseline: 8.53 | 11.09 (76.92%) | 📈 view plot 🚷 view threshold | 16.35(0.00%)Baseline: 16.35 | 21.26 (76.92%) | 📈 view plot 🚷 view threshold | 203.42(0.00%)Baseline: 203.42 | 264.45 (76.92%) | 📈 view plot 🚷 view threshold | 646.94(0.00%)Baseline: 646.94 | 452.86 (70.00%) |
| /client_side_hello_world_shared_store: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 17.93(0.00%)Baseline: 17.93 | 23.31 (76.92%) | 📈 view plot 🚷 view threshold | 21.47(0.00%)Baseline: 21.47 | 27.91 (76.92%) | 📈 view plot 🚷 view threshold | 361.60(0.00%)Baseline: 361.60 | 470.08 (76.92%) | 📈 view plot 🚷 view threshold | 325.45(0.00%)Baseline: 325.45 | 227.81 (70.00%) |
| /client_side_hello_world_shared_store_controller: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 9.73(0.00%)Baseline: 9.73 | 12.65 (76.92%) | 📈 view plot 🚷 view threshold | 18.83(0.00%)Baseline: 18.83 | 24.48 (76.92%) | 📈 view plot 🚷 view threshold | 150.97(0.00%)Baseline: 150.97 | 196.26 (76.92%) | 📈 view plot 🚷 view threshold | 676.65(0.00%)Baseline: 676.65 | 473.65 (70.00%) |
| /client_side_hello_world_shared_store_controller: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 17.96(0.00%)Baseline: 17.96 | 23.35 (76.92%) | 📈 view plot 🚷 view threshold | 28.81(0.00%)Baseline: 28.81 | 37.45 (76.92%) | 📈 view plot 🚷 view threshold | 203.68(0.00%)Baseline: 203.68 | 264.78 (76.92%) | 📈 view plot 🚷 view threshold | 436.51(0.00%)Baseline: 436.51 | 305.56 (70.00%) |
| /client_side_hello_world_shared_store_defer: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 9.65(0.00%)Baseline: 9.65 | 12.54 (76.92%) | 📈 view plot 🚷 view threshold | 19.11(0.00%)Baseline: 19.11 | 24.84 (76.92%) | 📈 view plot 🚷 view threshold | 112.85(0.00%)Baseline: 112.85 | 146.70 (76.92%) | 📈 view plot 🚷 view threshold | 697.64(0.00%)Baseline: 697.64 | 488.35 (70.00%) |
| /client_side_hello_world_shared_store_defer: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 14.27(0.00%)Baseline: 14.27 | 18.55 (76.92%) | 📈 view plot 🚷 view threshold | 23.76(0.00%)Baseline: 23.76 | 30.89 (76.92%) | 📈 view plot 🚷 view threshold | 234.52(0.00%)Baseline: 234.52 | 304.88 (76.92%) | 📈 view plot 🚷 view threshold | 441.06(0.00%)Baseline: 441.06 | 308.74 (70.00%) |
| /client_side_log_throw: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 7.49(0.00%)Baseline: 7.49 | 9.74 (76.92%) | 📈 view plot 🚷 view threshold | 13.04(0.00%)Baseline: 13.04 | 16.95 (76.92%) | 📈 view plot 🚷 view threshold | 165.73(0.00%)Baseline: 165.73 | 215.45 (76.92%) | 📈 view plot 🚷 view threshold | 779.41(0.00%)Baseline: 779.41 | 545.59 (70.00%) |
| /client_side_log_throw: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 15.81(0.00%)Baseline: 15.81 | 20.55 (76.92%) | 📈 view plot 🚷 view threshold | 38.97(0.00%)Baseline: 38.97 | 50.66 (76.92%) | 📈 view plot 🚷 view threshold | 171.46(0.00%)Baseline: 171.46 | 222.90 (76.92%) | 📈 view plot 🚷 view threshold | 370.84(0.00%)Baseline: 370.84 | 259.59 (70.00%) |
| /client_side_manual_render: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 11.03(0.00%)Baseline: 11.03 | 14.34 (76.92%) | 📈 view plot 🚷 view threshold | 18.53(0.00%)Baseline: 18.53 | 24.09 (76.92%) | 📈 view plot 🚷 view threshold | 59.55(0.00%)Baseline: 59.55 | 77.41 (76.92%) | 📈 view plot 🚷 view threshold | 769.13(0.00%)Baseline: 769.13 | 538.39 (70.00%) |
| /client_side_manual_render: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 17.69(0.00%)Baseline: 17.69 | 23.00 (76.92%) | 📈 view plot 🚷 view threshold | 27.90(0.00%)Baseline: 27.90 | 36.27 (76.92%) | 📈 view plot 🚷 view threshold | 194.80(0.00%)Baseline: 194.80 | 253.24 (76.92%) | 📈 view plot 🚷 view threshold | 444.94(0.00%)Baseline: 444.94 | 311.46 (70.00%) |
| /client_side_rescript_hello_world: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 11.31(0.00%)Baseline: 11.31 | 14.70 (76.92%) | 📈 view plot 🚷 view threshold | 19.42(0.00%)Baseline: 19.42 | 25.25 (76.92%) | 📈 view plot 🚷 view threshold | 67.04(0.00%)Baseline: 67.04 | 87.15 (76.92%) | 📈 view plot 🚷 view threshold | 735.83(0.00%)Baseline: 735.83 | 515.08 (70.00%) |
| /console_logs_in_async_server: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 2,117.64(0.00%)Baseline: 2,117.64 | 2,752.93 (76.92%) | 📈 view plot 🚷 view threshold | 2,182.71(0.00%)Baseline: 2,182.71 | 2,837.52 (76.92%) | 📈 view plot 🚷 view threshold | 23,404.80(0.00%)Baseline: 23,404.80 | 30,426.24 (76.92%) | 📈 view plot 🚷 view threshold | 2.75(0.00%)Baseline: 2.75 | 1.93 (70.00%) |
| /context_function_return_jsx: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 7.80(0.00%)Baseline: 7.80 | 10.14 (76.92%) | 📈 view plot 🚷 view threshold | 13.01(0.00%)Baseline: 13.01 | 16.91 (76.92%) | 📈 view plot 🚷 view threshold | 140.35(0.00%)Baseline: 140.35 | 182.46 (76.92%) | 📈 view plot 🚷 view threshold | 787.63(0.00%)Baseline: 787.63 | 551.34 (70.00%) |
| /context_function_return_jsx: Pro | 📈 view plot 🚷 view threshold | 100.00(0.00%)Baseline: 100.00 | 130.00 (76.92%) | 📈 view plot 🚷 view threshold | 12.81(0.00%)Baseline: 12.81 | 16.65 (76.92%) | 📈 view plot 🚷 view threshold | 21.23(0.00%)Baseline: 21.23 | 27.60 (76.92%) | 📈 view plot 🚷 view threshold | 200.77(0.00%)Baseline: 200.77 | 261.00 (76.92%) | 📈 view plot 🚷 view threshold | 501.11(0.00%)Baseline: 501.11 | 350.78 (70.00%) |
| /css_modules_images_fonts_example: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 348.06(0.00%)Baseline: 348.06 | 452.48 (76.92%) | 📈 view plot 🚷 view threshold | 434.02(0.00%)Baseline: 434.02 | 564.23 (76.92%) | 📈 view plot 🚷 view threshold | 4,205.82(0.00%)Baseline: 4,205.82 | 5,467.57 (76.92%) | 📈 view plot 🚷 view threshold | 23.32(0.00%)Baseline: 23.32 | 16.32 (70.00%) |
| /css_modules_images_fonts_example: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 17.99(0.00%)Baseline: 17.99 | 23.39 (76.92%) | 📈 view plot 🚷 view threshold | 27.68(0.00%)Baseline: 27.68 | 35.98 (76.92%) | 📈 view plot 🚷 view threshold | 248.56(0.00%)Baseline: 248.56 | 323.13 (76.92%) | 📈 view plot 🚷 view threshold | 428.46(0.00%)Baseline: 428.46 | 299.92 (70.00%) |
| /empty: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 5.35(0.00%)Baseline: 5.35 | 6.95 (76.92%) | 📈 view plot 🚷 view threshold | 8.25(0.00%)Baseline: 8.25 | 10.72 (76.92%) | 📈 view plot 🚷 view threshold | 57.69(0.00%)Baseline: 57.69 | 75.00 (76.92%) | 📈 view plot 🚷 view threshold | 1,486.08(0.00%)Baseline: 1,486.08 | 1,040.26 (70.00%) |
| /image_example: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 343.49(0.00%)Baseline: 343.49 | 446.54 (76.92%) | 📈 view plot 🚷 view threshold | 432.51(0.00%)Baseline: 432.51 | 562.26 (76.92%) | 📈 view plot 🚷 view threshold | 6,235.32(0.00%)Baseline: 6,235.32 | 8,105.92 (76.92%) | 📈 view plot 🚷 view threshold | 17.23(0.00%)Baseline: 17.23 | 12.06 (70.00%) |
| /image_example: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 18.20(0.00%)Baseline: 18.20 | 23.66 (76.92%) | 📈 view plot 🚷 view threshold | 46.69(0.00%)Baseline: 46.69 | 60.70 (76.92%) | 📈 view plot 🚷 view threshold | 192.42(0.00%)Baseline: 192.42 | 250.15 (76.92%) | 📈 view plot 🚷 view threshold | 323.52(0.00%)Baseline: 323.52 | 226.46 (70.00%) |
| /lazy_apollo_graphql: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 51.14(0.00%)Baseline: 51.14 | 66.48 (76.92%) | 📈 view plot 🚷 view threshold | 79.83(0.00%)Baseline: 79.83 | 103.78 (76.92%) | 📈 view plot 🚷 view threshold | 549.91(0.00%)Baseline: 549.91 | 714.88 (76.92%) | 📈 view plot 🚷 view threshold | 151.63(0.00%)Baseline: 151.63 | 106.14 (70.00%) |
| /loadable: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 23.24(0.00%)Baseline: 23.24 | 30.21 (76.92%) | 📈 view plot 🚷 view threshold | 33.61(0.00%)Baseline: 33.61 | 43.69 (76.92%) | 📈 view plot 🚷 view threshold | 136.16(0.00%)Baseline: 136.16 | 177.01 (76.92%) | 📈 view plot 🚷 view threshold | 361.07(0.00%)Baseline: 361.07 | 252.75 (70.00%) |
| /manual_render_test: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 9.23(0.00%)Baseline: 9.23 | 12.00 (76.92%) | 📈 view plot 🚷 view threshold | 17.94(0.00%)Baseline: 17.94 | 23.32 (76.92%) | 📈 view plot 🚷 view threshold | 112.70(0.00%)Baseline: 112.70 | 146.51 (76.92%) | 📈 view plot 🚷 view threshold | 727.46(0.00%)Baseline: 727.46 | 509.22 (70.00%) |
| /posts_page: Pro | 📈 view plot 🚷 view threshold | 100.00(0.00%)Baseline: 100.00 | 130.00 (76.92%) | 📈 view plot 🚷 view threshold | 8.11(0.00%)Baseline: 8.11 | 10.54 (76.92%) | 📈 view plot 🚷 view threshold | 12.49(0.00%)Baseline: 12.49 | 16.24 (76.92%) | 📈 view plot 🚷 view threshold | 89.99(0.00%)Baseline: 89.99 | 116.99 (76.92%) | 📈 view plot 🚷 view threshold | 976.98(0.00%)Baseline: 976.98 | 683.89 (70.00%) |
| /pure_component: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 344.02(0.00%)Baseline: 344.02 | 447.23 (76.92%) | 📈 view plot 🚷 view threshold | 426.37(0.00%)Baseline: 426.37 | 554.28 (76.92%) | 📈 view plot 🚷 view threshold | 4,055.42(0.00%)Baseline: 4,055.42 | 5,272.05 (76.92%) | 📈 view plot 🚷 view threshold | 23.56(0.00%)Baseline: 23.56 | 16.49 (70.00%) |
| /pure_component: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 13.07(0.00%)Baseline: 13.07 | 16.99 (76.92%) | 📈 view plot 🚷 view threshold | 24.49(0.00%)Baseline: 24.49 | 31.84 (76.92%) | 📈 view plot 🚷 view threshold | 329.04(0.00%)Baseline: 329.04 | 427.75 (76.92%) | 📈 view plot 🚷 view threshold | 438.33(0.00%)Baseline: 438.33 | 306.83 (70.00%) |
| /pure_component_wrapped_in_function: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 10.90(0.00%)Baseline: 10.90 | 14.17 (76.92%) | 📈 view plot 🚷 view threshold | 13.04(0.00%)Baseline: 13.04 | 16.95 (76.92%) | 📈 view plot 🚷 view threshold | 222.75(0.00%)Baseline: 222.75 | 289.57 (76.92%) | 📈 view plot 🚷 view threshold | 529.66(0.00%)Baseline: 529.66 | 370.76 (70.00%) |
| /pure_component_wrapped_in_function: Pro | 📈 view plot 🚷 view threshold | 100.00(0.00%)Baseline: 100.00 | 130.00 (76.92%) | 📈 view plot 🚷 view threshold | 15.40(0.00%)Baseline: 15.40 | 20.02 (76.92%) | 📈 view plot 🚷 view threshold | 25.75(0.00%)Baseline: 25.75 | 33.48 (76.92%) | 📈 view plot 🚷 view threshold | 173.55(0.00%)Baseline: 173.55 | 225.62 (76.92%) | 📈 view plot 🚷 view threshold | 497.69(0.00%)Baseline: 497.69 | 348.38 (70.00%) |
| /react_helmet: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 346.96(0.00%)Baseline: 346.96 | 451.05 (76.92%) | 📈 view plot 🚷 view threshold | 584.84(0.00%)Baseline: 584.84 | 760.29 (76.92%) | 📈 view plot 🚷 view threshold | 3,792.56(0.00%)Baseline: 3,792.56 | 4,930.33 (76.92%) | 📈 view plot 🚷 view threshold | 17.18(0.00%)Baseline: 17.18 | 12.03 (70.00%) |
| /react_helmet: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 18.77(0.00%)Baseline: 18.77 | 24.40 (76.92%) | 📈 view plot 🚷 view threshold | 28.80(0.00%)Baseline: 28.80 | 37.44 (76.92%) | 📈 view plot 🚷 view threshold | 194.25(0.00%)Baseline: 194.25 | 252.53 (76.92%) | 📈 view plot 🚷 view threshold | 411.81(0.00%)Baseline: 411.81 | 288.27 (70.00%) |
| /react_helmet_broken: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 362.11(0.00%)Baseline: 362.11 | 470.74 (76.92%) | 📈 view plot 🚷 view threshold | 449.08(0.00%)Baseline: 449.08 | 583.80 (76.92%) | 📈 view plot 🚷 view threshold | 4,152.63(0.00%)Baseline: 4,152.63 | 5,398.42 (76.92%) | 📈 view plot 🚷 view threshold | 22.61(0.00%)Baseline: 22.61 | 15.83 (70.00%) |
| /react_helmet_broken: Pro | 📈 view plot 🚷 view threshold | 100.00(0.00%)Baseline: 100.00 | 130.00 (76.92%) | 📈 view plot 🚷 view threshold | 16.38(0.00%)Baseline: 16.38 | 21.29 (76.92%) | 📈 view plot 🚷 view threshold | 19.58(0.00%)Baseline: 19.58 | 25.45 (76.92%) | 📈 view plot 🚷 view threshold | 324.16(0.00%)Baseline: 324.16 | 421.41 (76.92%) | 📈 view plot 🚷 view threshold | 354.79(0.00%)Baseline: 354.79 | 248.35 (70.00%) |
| /react_router: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 366.83(0.00%)Baseline: 366.83 | 476.88 (76.92%) | 📈 view plot 🚷 view threshold | 462.22(0.00%)Baseline: 462.22 | 600.89 (76.92%) | 📈 view plot 🚷 view threshold | 4,163.97(0.00%)Baseline: 4,163.97 | 5,413.16 (76.92%) | 📈 view plot 🚷 view threshold | 22.10(0.00%)Baseline: 22.10 | 15.47 (70.00%) |
| /react_router: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 13.98(0.00%)Baseline: 13.98 | 18.17 (76.92%) | 📈 view plot 🚷 view threshold | 21.55(0.00%)Baseline: 21.55 | 28.02 (76.92%) | 📈 view plot 🚷 view threshold | 193.61(0.00%)Baseline: 193.61 | 251.69 (76.92%) | 📈 view plot 🚷 view threshold | 474.72(0.00%)Baseline: 474.72 | 332.30 (70.00%) |
| /redis_receiver: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 64.11(0.00%)Baseline: 64.11 | 83.34 (76.92%) | 📈 view plot 🚷 view threshold | 106.63(0.00%)Baseline: 106.63 | 138.62 (76.92%) | 📈 view plot 🚷 view threshold | 892.24(0.00%)Baseline: 892.24 | 1,159.91 (76.92%) | 📈 view plot 🚷 view threshold | 104.37(0.00%)Baseline: 104.37 | 73.06 (70.00%) |
| /render_js: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 323.54(0.00%)Baseline: 323.54 | 420.60 (76.92%) | 📈 view plot 🚷 view threshold | 385.99(0.00%)Baseline: 385.99 | 501.79 (76.92%) | 📈 view plot 🚷 view threshold | 6,255.65(0.00%)Baseline: 6,255.65 | 8,132.34 (76.92%) | 📈 view plot 🚷 view threshold | 18.32(0.00%)Baseline: 18.32 | 12.82 (70.00%) |
| /render_js: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 17.43(0.00%)Baseline: 17.43 | 22.66 (76.92%) | 📈 view plot 🚷 view threshold | 36.98(0.00%)Baseline: 36.98 | 48.07 (76.92%) | 📈 view plot 🚷 view threshold | 192.00(0.00%)Baseline: 192.00 | 249.60 (76.92%) | 📈 view plot 🚷 view threshold | 335.29(0.00%)Baseline: 335.29 | 234.70 (70.00%) |
| /rendered_html: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 397.47(0.00%)Baseline: 397.47 | 516.71 (76.92%) | 📈 view plot 🚷 view threshold | 445.40(0.00%)Baseline: 445.40 | 579.02 (76.92%) | 📈 view plot 🚷 view threshold | 2,875.43(0.00%)Baseline: 2,875.43 | 3,738.06 (76.92%) | 📈 view plot 🚷 view threshold | 22.91(0.00%)Baseline: 22.91 | 16.04 (70.00%) |
| /rendered_html: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 17.81(0.00%)Baseline: 17.81 | 23.15 (76.92%) | 📈 view plot 🚷 view threshold | 26.86(0.00%)Baseline: 26.86 | 34.92 (76.92%) | 📈 view plot 🚷 view threshold | 243.69(0.00%)Baseline: 243.69 | 316.80 (76.92%) | 📈 view plot 🚷 view threshold | 438.04(0.00%)Baseline: 438.04 | 306.63 (70.00%) |
|
| Branch | abanoub/2323-license-optional-attribution |
| Testbed | github-actions |
Click to view all benchmark results
| Benchmark | failed_pct | Benchmark Result % (Result Δ%) | Upper Boundary % (Limit %) | p50_latency | Benchmark Result ms (Result Δ%) | Upper Boundary ms (Limit %) | p90_latency | Benchmark Result ms (Result Δ%) | Upper Boundary ms (Limit %) | p99_latency | Benchmark Result ms (Result Δ%) | Upper Boundary ms (Limit %) | rps | Benchmark Result req/s (Result Δ%) | Lower Boundary req/s (Limit %) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| /rsc_posts_page_over_http: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 19.45(0.00%)Baseline: 19.45 | 25.29 (76.92%) | 📈 view plot 🚷 view threshold | 32.60(0.00%)Baseline: 32.60 | 42.38 (76.92%) | 📈 view plot 🚷 view threshold | 223.89(0.00%)Baseline: 223.89 | 291.06 (76.92%) | 📈 view plot 🚷 view threshold | 393.76(0.00%)Baseline: 393.76 | 275.63 (70.00%) |
| /rsc_posts_page_over_redis: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 60.25(0.00%)Baseline: 60.25 | 78.33 (76.92%) | 📈 view plot 🚷 view threshold | 92.48(0.00%)Baseline: 92.48 | 120.22 (76.92%) | 📈 view plot 🚷 view threshold | 811.90(0.00%)Baseline: 811.90 | 1,055.47 (76.92%) | 📈 view plot 🚷 view threshold | 113.91(0.00%)Baseline: 113.91 | 79.74 (70.00%) |
| /server_render_with_timeout: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 15.03(0.00%)Baseline: 15.03 | 19.54 (76.92%) | 📈 view plot 🚷 view threshold | 24.55(0.00%)Baseline: 24.55 | 31.91 (76.92%) | 📈 view plot 🚷 view threshold | 236.53(0.00%)Baseline: 236.53 | 307.49 (76.92%) | 📈 view plot 🚷 view threshold | 428.02(0.00%)Baseline: 428.02 | 299.61 (70.00%) |
| /server_router: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 19.78(0.00%)Baseline: 19.78 | 25.71 (76.92%) | 📈 view plot 🚷 view threshold | 32.13(0.00%)Baseline: 32.13 | 41.77 (76.92%) | 📈 view plot 🚷 view threshold | 279.06(0.00%)Baseline: 279.06 | 362.78 (76.92%) | 📈 view plot 🚷 view threshold | 376.67(0.00%)Baseline: 376.67 | 263.67 (70.00%) |
| /server_router_client_render: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 18.53(0.00%)Baseline: 18.53 | 24.09 (76.92%) | 📈 view plot 🚷 view threshold | 23.88(0.00%)Baseline: 23.88 | 31.04 (76.92%) | 📈 view plot 🚷 view threshold | 215.22(0.00%)Baseline: 215.22 | 279.79 (76.92%) | 📈 view plot 🚷 view threshold | 318.90(0.00%)Baseline: 318.90 | 223.23 (70.00%) |
| /server_side_hello_world: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 350.58(0.00%)Baseline: 350.58 | 455.75 (76.92%) | 📈 view plot 🚷 view threshold | 432.11(0.00%)Baseline: 432.11 | 561.74 (76.92%) | 📈 view plot 🚷 view threshold | 4,084.55(0.00%)Baseline: 4,084.55 | 5,309.91 (76.92%) | 📈 view plot 🚷 view threshold | 23.57(0.00%)Baseline: 23.57 | 16.50 (70.00%) |
| /server_side_hello_world: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 18.64(0.00%)Baseline: 18.64 | 24.23 (76.92%) | 📈 view plot 🚷 view threshold | 32.74(0.00%)Baseline: 32.74 | 42.56 (76.92%) | 📈 view plot 🚷 view threshold | 205.16(0.00%)Baseline: 205.16 | 266.71 (76.92%) | 📈 view plot 🚷 view threshold | 315.73(0.00%)Baseline: 315.73 | 221.01 (70.00%) |
| /server_side_hello_world_es5: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 289.17(0.00%)Baseline: 289.17 | 375.92 (76.92%) | 📈 view plot 🚷 view threshold | 388.45(0.00%)Baseline: 388.45 | 504.99 (76.92%) | 📈 view plot 🚷 view threshold | 7,324.35(0.00%)Baseline: 7,324.35 | 9,521.66 (76.92%) | 📈 view plot 🚷 view threshold | 17.03(0.00%)Baseline: 17.03 | 11.92 (70.00%) |
| /server_side_hello_world_es5: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 24.02(0.00%)Baseline: 24.02 | 31.23 (76.92%) | 📈 view plot 🚷 view threshold | 32.87(0.00%)Baseline: 32.87 | 42.73 (76.92%) | 📈 view plot 🚷 view threshold | 133.41(0.00%)Baseline: 133.41 | 173.43 (76.92%) | 📈 view plot 🚷 view threshold | 369.55(0.00%)Baseline: 369.55 | 258.69 (70.00%) |
| /server_side_hello_world_hooks: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 281.60(0.00%)Baseline: 281.60 | 366.08 (76.92%) | 📈 view plot 🚷 view threshold | 424.16(0.00%)Baseline: 424.16 | 551.41 (76.92%) | 📈 view plot 🚷 view threshold | 4,238.40(0.00%)Baseline: 4,238.40 | 5,509.92 (76.92%) | 📈 view plot 🚷 view threshold | 23.57(0.00%)Baseline: 23.57 | 16.50 (70.00%) |
| /server_side_hello_world_hooks: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 14.81(0.00%)Baseline: 14.81 | 19.25 (76.92%) | 📈 view plot 🚷 view threshold | 20.58(0.00%)Baseline: 20.58 | 26.75 (76.92%) | 📈 view plot 🚷 view threshold | 368.85(0.00%)Baseline: 368.85 | 479.50 (76.92%) | 📈 view plot 🚷 view threshold | 328.02(0.00%)Baseline: 328.02 | 229.61 (70.00%) |
| /server_side_hello_world_props: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 352.54(0.00%)Baseline: 352.54 | 458.30 (76.92%) | 📈 view plot 🚷 view threshold | 435.15(0.00%)Baseline: 435.15 | 565.69 (76.92%) | 📈 view plot 🚷 view threshold | 3,800.34(0.00%)Baseline: 3,800.34 | 4,940.44 (76.92%) | 📈 view plot 🚷 view threshold | 23.62(0.00%)Baseline: 23.62 | 16.53 (70.00%) |
| /server_side_hello_world_shared_store: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 706.88(0.00%)Baseline: 706.88 | 918.94 (76.92%) | 📈 view plot 🚷 view threshold | 973.81(0.00%)Baseline: 973.81 | 1,265.95 (76.92%) | 📈 view plot 🚷 view threshold | 8,769.88(0.00%)Baseline: 8,769.88 | 11,400.84 (76.92%) | 📈 view plot 🚷 view threshold | 11.23(0.00%)Baseline: 11.23 | 7.86 (70.00%) |
| /server_side_hello_world_shared_store: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 20.97(0.00%)Baseline: 20.97 | 27.26 (76.92%) | 📈 view plot 🚷 view threshold | 30.88(0.00%)Baseline: 30.88 | 40.14 (76.92%) | 📈 view plot 🚷 view threshold | 212.45(0.00%)Baseline: 212.45 | 276.19 (76.92%) | 📈 view plot 🚷 view threshold | 377.21(0.00%)Baseline: 377.21 | 264.05 (70.00%) |
| /server_side_hello_world_shared_store_controller: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 712.27(0.00%)Baseline: 712.27 | 925.95 (76.92%) | 📈 view plot 🚷 view threshold | 963.20(0.00%)Baseline: 963.20 | 1,252.16 (76.92%) | 📈 view plot 🚷 view threshold | 7,742.64(0.00%)Baseline: 7,742.64 | 10,065.43 (76.92%) | 📈 view plot 🚷 view threshold | 8.64(0.00%)Baseline: 8.64 | 6.05 (70.00%) |
| /server_side_hello_world_shared_store_controller: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 21.05(0.00%)Baseline: 21.05 | 27.36 (76.92%) | 📈 view plot 🚷 view threshold | 30.68(0.00%)Baseline: 30.68 | 39.88 (76.92%) | 📈 view plot 🚷 view threshold | 221.10(0.00%)Baseline: 221.10 | 287.43 (76.92%) | 📈 view plot 🚷 view threshold | 377.31(0.00%)Baseline: 377.31 | 264.12 (70.00%) |
| /server_side_hello_world_shared_store_defer: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 681.85(0.00%)Baseline: 681.85 | 886.40 (76.92%) | 📈 view plot 🚷 view threshold | 929.29(0.00%)Baseline: 929.29 | 1,208.08 (76.92%) | 📈 view plot 🚷 view threshold | 8,630.78(0.00%)Baseline: 8,630.78 | 11,220.01 (76.92%) | 📈 view plot 🚷 view threshold | 11.42(0.00%)Baseline: 11.42 | 7.99 (70.00%) |
| /server_side_hello_world_shared_store_defer: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 21.35(0.00%)Baseline: 21.35 | 27.76 (76.92%) | 📈 view plot 🚷 view threshold | 33.55(0.00%)Baseline: 33.55 | 43.61 (76.92%) | 📈 view plot 🚷 view threshold | 244.83(0.00%)Baseline: 244.83 | 318.28 (76.92%) | 📈 view plot 🚷 view threshold | 369.76(0.00%)Baseline: 369.76 | 258.83 (70.00%) |
| /server_side_hello_world_with_options: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 346.19(0.00%)Baseline: 346.19 | 450.05 (76.92%) | 📈 view plot 🚷 view threshold | 435.92(0.00%)Baseline: 435.92 | 566.70 (76.92%) | 📈 view plot 🚷 view threshold | 3,979.94(0.00%)Baseline: 3,979.94 | 5,173.92 (76.92%) | 📈 view plot 🚷 view threshold | 23.58(0.00%)Baseline: 23.58 | 16.51 (70.00%) |
| /server_side_hello_world_with_options: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 21.00(0.00%)Baseline: 21.00 | 27.30 (76.92%) | 📈 view plot 🚷 view threshold | 32.08(0.00%)Baseline: 32.08 | 41.70 (76.92%) | 📈 view plot 🚷 view threshold | 230.22(0.00%)Baseline: 230.22 | 299.29 (76.92%) | 📈 view plot 🚷 view threshold | 364.21(0.00%)Baseline: 364.21 | 254.95 (70.00%) |
| /server_side_log_throw: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 354.74(0.00%)Baseline: 354.74 | 461.16 (76.92%) | 📈 view plot 🚷 view threshold | 450.51(0.00%)Baseline: 450.51 | 585.66 (76.92%) | 📈 view plot 🚷 view threshold | 4,214.80(0.00%)Baseline: 4,214.80 | 5,479.24 (76.92%) | 📈 view plot 🚷 view threshold | 22.83(0.00%)Baseline: 22.83 | 15.98 (70.00%) |
| /server_side_log_throw: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 18.03(0.00%)Baseline: 18.03 | 23.44 (76.92%) | 📈 view plot 🚷 view threshold | 28.45(0.00%)Baseline: 28.45 | 36.98 (76.92%) | 📈 view plot 🚷 view threshold | 204.64(0.00%)Baseline: 204.64 | 266.03 (76.92%) | 📈 view plot 🚷 view threshold | 434.73(0.00%)Baseline: 434.73 | 304.31 (70.00%) |
| /server_side_log_throw_plain_js: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 272.90(0.00%)Baseline: 272.90 | 354.77 (76.92%) | 📈 view plot 🚷 view threshold | 433.22(0.00%)Baseline: 433.22 | 563.19 (76.92%) | 📈 view plot 🚷 view threshold | 4,962.16(0.00%)Baseline: 4,962.16 | 6,450.81 (76.92%) | 📈 view plot 🚷 view threshold | 22.80(0.00%)Baseline: 22.80 | 15.96 (70.00%) |
| /server_side_log_throw_plain_js: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 16.96(0.00%)Baseline: 16.96 | 22.05 (76.92%) | 📈 view plot 🚷 view threshold | 25.90(0.00%)Baseline: 25.90 | 33.67 (76.92%) | 📈 view plot 🚷 view threshold | 235.20(0.00%)Baseline: 235.20 | 305.76 (76.92%) | 📈 view plot 🚷 view threshold | 455.44(0.00%)Baseline: 455.44 | 318.81 (70.00%) |
| /server_side_log_throw_raise: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 352.59(0.00%)Baseline: 352.59 | 458.37 (76.92%) | 📈 view plot 🚷 view threshold | 444.82(0.00%)Baseline: 444.82 | 578.27 (76.92%) | 📈 view plot 🚷 view threshold | 3,890.05(0.00%)Baseline: 3,890.05 | 5,057.07 (76.92%) | 📈 view plot 🚷 view threshold | 23.06(0.00%)Baseline: 23.06 | 16.14 (70.00%) |
| /server_side_log_throw_raise: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 9.67(0.00%)Baseline: 9.67 | 12.57 (76.92%) | 📈 view plot 🚷 view threshold | 14.34(0.00%)Baseline: 14.34 | 18.64 (76.92%) | 📈 view plot 🚷 view threshold | 102.17(0.00%)Baseline: 102.17 | 132.82 (76.92%) | 📈 view plot 🚷 view threshold | 805.79(0.00%)Baseline: 805.79 | 564.05 (70.00%) |
| /server_side_log_throw_raise_invoker: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 8.02(0.00%)Baseline: 8.02 | 10.43 (76.92%) | 📈 view plot 🚷 view threshold | 17.17(0.00%)Baseline: 17.17 | 22.32 (76.92%) | 📈 view plot 🚷 view threshold | 69.74(0.00%)Baseline: 69.74 | 90.66 (76.92%) | 📈 view plot 🚷 view threshold | 858.25(0.00%)Baseline: 858.25 | 600.78 (70.00%) |
| /server_side_log_throw_raise_invoker: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 16.30(0.00%)Baseline: 16.30 | 21.19 (76.92%) | 📈 view plot 🚷 view threshold | 25.69(0.00%)Baseline: 25.69 | 33.40 (76.92%) | 📈 view plot 🚷 view threshold | 176.95(0.00%)Baseline: 176.95 | 230.03 (76.92%) | 📈 view plot 🚷 view threshold | 483.40(0.00%)Baseline: 483.40 | 338.38 (70.00%) |
| /server_side_redux_app: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 367.17(0.00%)Baseline: 367.17 | 477.32 (76.92%) | 📈 view plot 🚷 view threshold | 455.38(0.00%)Baseline: 455.38 | 591.99 (76.92%) | 📈 view plot 🚷 view threshold | 4,149.93(0.00%)Baseline: 4,149.93 | 5,394.91 (76.92%) | 📈 view plot 🚷 view threshold | 22.59(0.00%)Baseline: 22.59 | 15.81 (70.00%) |
| /server_side_redux_app: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 21.57(0.00%)Baseline: 21.57 | 28.04 (76.92%) | 📈 view plot 🚷 view threshold | 33.58(0.00%)Baseline: 33.58 | 43.65 (76.92%) | 📈 view plot 🚷 view threshold | 242.52(0.00%)Baseline: 242.52 | 315.28 (76.92%) | 📈 view plot 🚷 view threshold | 366.53(0.00%)Baseline: 366.53 | 256.57 (70.00%) |
| /server_side_redux_app_cached: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 9.96(0.00%)Baseline: 9.96 | 12.95 (76.92%) | 📈 view plot 🚷 view threshold | 18.08(0.00%)Baseline: 18.08 | 23.50 (76.92%) | 📈 view plot 🚷 view threshold | 82.60(0.00%)Baseline: 82.60 | 107.38 (76.92%) | 📈 view plot 🚷 view threshold | 748.44(0.00%)Baseline: 748.44 | 523.91 (70.00%) |
| /server_side_redux_app_cached: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 19.41(0.00%)Baseline: 19.41 | 25.23 (76.92%) | 📈 view plot 🚷 view threshold | 26.74(0.00%)Baseline: 26.74 | 34.76 (76.92%) | 📈 view plot 🚷 view threshold | 224.72(0.00%)Baseline: 224.72 | 292.14 (76.92%) | 📈 view plot 🚷 view threshold | 305.80(0.00%)Baseline: 305.80 | 214.06 (70.00%) |
| /stream_async_components: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 18.01(0.00%)Baseline: 18.01 | 23.41 (76.92%) | 📈 view plot 🚷 view threshold | 35.09(0.00%)Baseline: 35.09 | 45.62 (76.92%) | 📈 view plot 🚷 view threshold | 195.78(0.00%)Baseline: 195.78 | 254.51 (76.92%) | 📈 view plot 🚷 view threshold | 326.65(0.00%)Baseline: 326.65 | 228.65 (70.00%) |
| /turbo_frame_tag_hello_world: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 8.22(0.00%)Baseline: 8.22 | 10.69 (76.92%) | 📈 view plot 🚷 view threshold | 19.11(0.00%)Baseline: 19.11 | 24.84 (76.92%) | 📈 view plot 🚷 view threshold | 76.85(0.00%)Baseline: 76.85 | 99.91 (76.92%) | 📈 view plot 🚷 view threshold | 812.33(0.00%)Baseline: 812.33 | 568.63 (70.00%) |
| /turbolinks_cache_disabled: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 10.17(0.00%)Baseline: 10.17 | 13.22 (76.92%) | 📈 view plot 🚷 view threshold | 21.29(0.00%)Baseline: 21.29 | 27.68 (76.92%) | 📈 view plot 🚷 view threshold | 127.39(0.00%)Baseline: 127.39 | 165.61 (76.92%) | 📈 view plot 🚷 view threshold | 650.39(0.00%)Baseline: 650.39 | 455.27 (70.00%) |
| /turbolinks_cache_disabled: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 16.17(0.00%)Baseline: 16.17 | 21.02 (76.92%) | 📈 view plot 🚷 view threshold | 25.94(0.00%)Baseline: 25.94 | 33.72 (76.92%) | 📈 view plot 🚷 view threshold | 185.42(0.00%)Baseline: 185.42 | 241.05 (76.92%) | 📈 view plot 🚷 view threshold | 362.28(0.00%)Baseline: 362.28 | 253.60 (70.00%) |
| /xhr_refresh: Core | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 687.60(0.00%)Baseline: 687.60 | 893.88 (76.92%) | 📈 view plot 🚷 view threshold | 931.75(0.00%)Baseline: 931.75 | 1,211.28 (76.92%) | 📈 view plot 🚷 view threshold | 8,097.52(0.00%)Baseline: 8,097.52 | 10,526.78 (76.92%) | 📈 view plot 🚷 view threshold | 11.58(0.00%)Baseline: 11.58 | 8.11 (70.00%) |
| /xhr_refresh: Pro | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 21.37(0.00%)Baseline: 21.37 | 27.78 (76.92%) | 📈 view plot 🚷 view threshold | 33.15(0.00%)Baseline: 33.15 | 43.09 (76.92%) | 📈 view plot 🚷 view threshold | 169.55(0.00%)Baseline: 169.55 | 220.41 (76.92%) | 📈 view plot 🚷 view threshold | 372.12(0.00%)Baseline: 372.12 | 260.48 (70.00%) |
| Pro Node Renderer: react_ssr (non-RSC) | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 4.76(0.00%)Baseline: 4.76 | 6.19 (76.92%) | 📈 view plot 🚷 view threshold | 10.14(0.00%)Baseline: 10.14 | 13.18 (76.92%) | 📈 view plot 🚷 view threshold | 16.47(0.00%)Baseline: 16.47 | 21.41 (76.92%) | 📈 view plot 🚷 view threshold | 1,649.86(0.00%)Baseline: 1,649.86 | 1,154.90 (70.00%) |
| Pro Node Renderer: simple_eval (non-RSC) | 📈 view plot 🚷 view threshold | 0.00(0.00%)Baseline: 0.00 | 0.00 (0.00%) | 📈 view plot 🚷 view threshold | 4.53(0.00%)Baseline: 4.53 | 5.89 (76.92%) | 📈 view plot 🚷 view threshold | 13.04(0.00%)Baseline: 13.04 | 16.95 (76.92%) | 📈 view plot 🚷 view threshold | 20.23(0.00%)Baseline: 20.23 | 26.30 (76.92%) | 📈 view plot 🚷 view threshold | 1,431.69(0.00%)Baseline: 1,431.69 | 1,002.18 (70.00%) |
PR Review: Remove license requirement for React on Rails ProSummaryThis PR successfully transitions React on Rails Pro from a "license-required" to "license-optional with attribution" model. The implementation is clean, well-tested, and maintains backward compatibility while achieving the stated goal. ✅ Strengths1. Excellent API Design
2. Comprehensive Test Coverage
3. Security Best Practices
4. Clean Code
🔍 Code Quality ObservationsRuby Implementation (
|
PR Review: Remove license requirement for React on Rails ProOverviewThis is a significant and well-executed refactoring that transforms React on Rails Pro from a "license-required" model to a "license-optional with attribution" model. The changes are comprehensive, touching both Ruby and TypeScript codebases, with thorough test coverage. Strengths1. Excellent Architecture & Design
2. Security Best PracticesThe security aspects are handled correctly with proper signature verification and RS256 enforcement. Comments explain security rationale clearly. 3. Comprehensive Testing
4. Documentation & User Experience
Issues & Concerns1. Performance: Redundant Status Checks in
|
Code Review - PR #2324: Remove License Requirement for React on Rails ProThank you for this comprehensive refactor! This is a significant architectural change that fundamentally alters the licensing model. Overall, the implementation is well-structured and follows best practices. Here's my detailed feedback: ✅ Strengths1. Excellent Separation of Concerns
2. Robust Error Handling
3. Strong Test Coverage
4. Security Best Practices
5. Good Caching Strategy
|
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
react_on_rails_pro/spec/react_on_rails_pro/license_validator_spec.rb (1)
32-46: Restore original ENV value to avoid test pollution.The suite deletes
REACT_ON_RAILS_PRO_LICENSEwithout preserving the original value. If this variable was set before the test, the deletion will persist after the test completes, affecting subsequent tests or the host environment.🧪 Suggested fix
before do described_class.reset! stub_const("ReactOnRailsPro::LicensePublicKey::KEY", test_public_key) + `@original_license` = ENV["REACT_ON_RAILS_PRO_LICENSE"] ENV.delete("REACT_ON_RAILS_PRO_LICENSE") allow(Rails).to receive_messages(logger: mock_logger, root: mock_root) end after do described_class.reset! - ENV.delete("REACT_ON_RAILS_PRO_LICENSE") + if `@original_license` + ENV["REACT_ON_RAILS_PRO_LICENSE"] = `@original_license` + else + ENV.delete("REACT_ON_RAILS_PRO_LICENSE") + end end
Code Review: License Optional with AttributionThis is a significant architectural change that shifts React on Rails Pro from a license-enforced to an attribution-based licensing model. Overall, the implementation is well-structured and thorough. Here are my findings: ✅ Strengths1. Excellent Code Quality
2. Security Best Practices
3. Non-Blocking Architecture
4. Consistent Attribution
5. Test Coverage
🔍 Observations & Minor Suggestions1. Typo in Comment (knip.ts:76)// License validator: reset() is used in tests, getLicenseStatus/LicenseStatus imported by master.ts✅ This accurately describes the exports and is helpful for understanding the code's usage. 2. Security Consideration: File Path TraversalIn both
These are safe because they use hardcoded path components. However, if this were ever changed to accept user input, consider validating the path doesn't contain Current code is secure ✅ - just noting for future reference. 3. Consistent Error MessagesThe warning messages are well-structured and consistent across Ruby and TypeScript:
Suggestion: Consider adding a link to the license purchase page in the "No license found" warning (similar to what the Engine does). This would make it easier for users to get licensed. Example: "No license found. Running in unlicensed mode. Get a license at https://www.shakacode.com/react-on-rails-pro/"4. Cache InvalidationBoth implementations cache the license status. The Question: What happens if a user updates their license while the app is running?
This is likely acceptable for your use case, but worth documenting if not already covered elsewhere. 5. Open Source Helper MethodIn # Note: This only checks gem presence, not license validityThis is correct behavior for the open-source package, but the comment could be clearer: # Checks if React on Rails Pro gem is installed
# Note: This only checks gem presence, NOT license validity or status.
# To check license status, use ReactOnRailsPro::LicenseValidator.license_status🎯 Architecture ReviewLicense Validation Flow
This is efficient and well-designed. ✅ Attribution Generation (Pro Utils)The Question: Is this comment injected into every server-rendered component? If so, is there any performance concern with calling 🚨 Potential Issues1. No Breaking Issues FoundThis PR doesn't introduce any security vulnerabilities, logic errors, or breaking changes. The migration path from "license-required" to "license-optional" is clean. 2. Backward CompatibilityExisting users with valid licenses continue to work as before. Users without licenses now get a functioning app instead of a crash. This is a pure improvement. ✅ 📝 Documentation & ChangelogChangelog Entries NeededAs per CLAUDE.md guidelines, this PR should update CHANGELOG_PRO.md (Pro-only changes): Suggested entry: #### Breaking Changes
- [PR 2324](https://github.com/shakacode/react_on_rails/pull/2324) by [AbanoubGhadban](https://github.com/AbanoubGhadban): Changed React on Rails Pro licensing model from "license-required" to "license-optional with attribution". Apps now run regardless of license status, displaying an HTML comment indicating license state. Removed grace period logic and free evaluation license concept. **Migration:** No action required - apps with expired or missing licenses will continue running with an attribution comment instead of crashing.Documentation UpdatesConsider documenting:
✅ Testing RecommendationsManual Testing Checklist (from PR description)The test plan looks good. I'd add:
CI TestingAll existing tests should pass. The new specs comprehensively cover the changed behavior. ✅ 🏆 Overall AssessmentCode Quality: ⭐⭐⭐⭐⭐ (Excellent) SummaryThis is a high-quality PR that achieves its goal of making React on Rails Pro license-optional while maintaining attribution. The implementation is secure, well-tested, and follows best practices. No blocking issues found. Recommendations
Excellent work! 🎉 |
Code Review: PR 2324Great work on this architectural change! Here is my detailed review: Strengths
Issues and Recommendations1. Caching patterns differ - TypeScript uses !== undefined, Ruby uses defined?. Consider documenting why caching is safe. 2. Missing validation - No check for empty/malformed license strings. Add pre-check for clearer errors. 3. Inconsistent messages - Ruby mentions Running in unlicensed mode but TypeScript file read errors do not. 4. HTML comment injection risk - Low likelihood but consider escaping if future changes add user data. 5. Timezone handling - Use Time.now.utc.to_i for clarity or document UTC is implicit. 6. Test coverage gap - Add TypeScript test for file read failures matching Ruby tests. Security AssessmentOverall: Good security posture. JWT verification mandatory, algorithm enforced, no sensitive data exposure. ApprovalLGTM with minor suggestions. Issues are minor, none blocking. Ensure CI passes and consider test additions. Great work maintaining security in the new licensing model! |
Code Review: License-Optional Attribution ModelI've completed a thorough review of this PR. Overall, this is a well-designed, security-conscious refactoring that successfully transitions from a "crash-on-invalid-license" model to a "warn-and-continue" model. The code quality is excellent with strong test coverage. ✅ Strengths1. Security Best Practices
2. Clean Architecture
3. Code Quality
4. Test Coverage
🔍 Areas for Consideration1. Production Enforcement Gap (Medium Priority)The new model warns but doesn't prevent production use without a valid license. This shifts enforcement from technical (app crashes) to legal (license violation warnings). Current behavior:
Potential issues:
Suggestions:
Example: # In engine.rb initializer
if Rails.env.production? && ENV['REACT_ON_RAILS_PRO_ENFORCE_LICENSE'] == 'true'
unless status == :valid
raise ReactOnRailsPro::Error, "Production deployment requires valid license"
end
end2. Plan Validation Logic (Low Priority)The backwards compatibility logic is correct but could be documented more explicitly: # Current (line 89 in license_validator.rb)
return :valid unless plan # No plan field = valid
# Consider adding explanatory constant:
BACKWARDS_COMPATIBLE_NO_PLAN = true
return :valid unless plan # Old paid licenses have no 'plan' field - treat as validQuestion: Are there legitimate old licenses with 3. Error Handling: File Read Failures (Low Priority)Line 57-58 in rescue StandardError => e
log_license_warning("Failed to read license file: #{e.message}. Running in unlicensed mode.")Current: File permission errors are logged as warnings, license treated as missing. Consider: Should permission errors be treated as # Possible improvement:
if config_path.exist?
begin
return File.read(config_path).strip
rescue StandardError => e
log_license_warning("Failed to read license file: #{e.message}. Running in unlicensed mode.")
return :file_read_error # Distinguish from true :missing
end
end4. TypeScript: Process.cwd() Assumption (Low Priority)Line 56 in const configPath = path.join(process.cwd(), 'config', 'react_on_rails_pro_license.key');Potential issue: If Node process is started from a different directory, Mitigation: Document that Node renderer must be started from Rails root, or consider using 🧪 Testing RecommendationsBefore merging, verify these scenarios: Manual Testing Checklist (from PR description):
Additional Testing:
📋 Documentation Updates NeededBased on the changelog entries, it looks like docs are updated. Verify these are clear:
🎯 SummaryThis is high-quality work that achieves its goals effectively: ✅ Approve with suggestions - The code is production-ready, secure, and well-tested. Recommended follow-ups (can be separate PRs):
No blocking issues found. The architectural change is sound and implementation is solid. 💡 Minor Nitpicks (Optional)
Recommendation: APPROVE ✅ The security, architecture, and test coverage are excellent. The production enforcement gap is a business/product decision rather than a code quality issue. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@CHANGELOG.md`:
- Line 28: Remove the changelog entry that begins with "License-Optional
Attribution Model" (the entry referencing PR 2324) from the root CHANGELOG.md
and add it to the Pro changelog instead, keeping only the user-visible
description about React on Rails Pro working without a license for
evaluation/dev/testing/CI and that paid licenses are required for production
(retain the note about old free licenses being treated as
invalid/backwards-compatible plan handling), but remove the clause that mentions
documentation updates (README, LICENSE_SETUP, CI_SETUP); ensure the Pro
changelog entry references PR 2324 and the author attribution as in the
original.
In `@react_on_rails_pro/CHANGELOG.md`:
- Line 24: Update the CHANGELOG entry line to remove the documentation-only
phrase "Documentation overhauled across README, LICENSE_SETUP, and CI_SETUP
guides" so the entry only contains user-visible changes: keep the
License-Optional Attribution Model description, the `plan` field validation
details, the note about old free licenses being invalid, and the PR/author
attribution (the text in the current line that references `"paid"` plan
validation, old free licenses, and PR 2324 by AbanoubGhadban), but delete the
doc-overhaul clause to comply with changelog guidelines.
🧹 Nitpick comments (5)
react_on_rails_pro/CI_SETUP.md (2)
27-71: GitHub Actions workflow example is well-structured.The example properly separates test and deployment jobs, with clear comments indicating that tests don't need a license while production deployment does. The use of GitHub secrets for the license is appropriate.
Minor suggestion: Consider adding
cache: npmorcache: pnpmto the Node setup action for faster CI runs.⚡ Optional: Add caching to speed up CI
- name: Set up Node uses: actions/setup-node@v3 with: node-version: '18' + cache: 'pnpm'
232-242: Troubleshooting guidance should mention the new attribution comment.According to the PR summary, the application now emits an HTML attribution comment indicating license state (e.g.,
<!-- Powered by React on Rails Pro (c) ShakaCode | UNLICENSED -->). The troubleshooting section should mention this as a way to verify license status in production.📝 Suggested addition for verification
Add after line 242:
**Q: How can I verify the license status in production?** A: Check the HTML source of your rendered pages for the attribution comment: - `<!-- Powered by React on Rails Pro (c) ShakaCode | LICENSED -->` - Valid paid license - `<!-- Powered by React on Rails Pro (c) ShakaCode | UNLICENSED -->` - No license present - `<!-- Powered by React on Rails Pro (c) ShakaCode | LICENSE EXPIRED -->` - License expired - `<!-- Powered by React on Rails Pro (c) ShakaCode | INVALID LICENSE -->` - Invalid licensereact_on_rails_pro/README.md (1)
441-503: FAQ comprehensively addresses licensing questions.The FAQ section thoroughly covers common licensing questions and technical topics. The answers are clear and actionable.
Consider adding a question about the HTML attribution comment that's generated, as mentioned in the PR summary. This would help users understand how to verify license status at runtime.
react_on_rails_pro/LICENSE_SETUP.md (2)
38-40: CI/CD guidance correctly reflects optional licensing.The comment "CI works without a license" is accurate and helpful. However, consider rephrasing to be more explicit that licenses are only needed for production deployment steps, not CI test/build steps.
📝 Suggested clarification
-# CI/CD (optional — CI works without a license) -# Add to your CI environment variables if needed +# CI/CD tests/builds work without a license +# Only add license to environment variables for production deployment steps
133-148: JWT format documentation accurately reflects plan field.The technical details correctly document the optional "plan" field and note that only "paid" is valid for production. This aligns with the plan validation logic added in this PR.
Minor suggestion: Consider adding that older licenses without a "plan" field are treated as valid for backward compatibility, as mentioned in the PR commit message.
|
|
||
| #### Changed | ||
|
|
||
| - **License-Optional Attribution Model**: React on Rails Pro now works without a license for evaluation, development, testing, and CI/CD. A paid license is only required for production deployments. Old free licenses are now treated as invalid — only paid licenses (or licenses without a `plan` field for backwards compatibility) are accepted. Documentation updated across README, LICENSE_SETUP, and CI_SETUP guides. [PR 2324](https://github.com/shakacode/react_on_rails/pull/2324) by [AbanoubGhadban](https://github.com/AbanoubGhadban). |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check if CHANGELOG_PRO.md exists and look at both changelog files
echo "=== Checking for CHANGELOG_PRO.md ==="
find . -name "CHANGELOG_PRO.md" -o -name "CHANGELOG.md" | head -20
echo -e "\n=== CHANGELOG.md around line 28 ==="
sed -n '20,35p' CHANGELOG.md
echo -e "\n=== Checking CHANGELOG_PRO.md if it exists ==="
if [ -f "react_on_rails_pro/CHANGELOG_PRO.md" ]; then
echo "File found at react_on_rails_pro/CHANGELOG_PRO.md"
head -50 react_on_rails_pro/CHANGELOG_PRO.md
else
echo "Not found at react_on_rails_pro/CHANGELOG_PRO.md"
fiRepository: shakacode/react_on_rails
Length of output: 1326
🏁 Script executed:
# Check the react_on_rails_pro/CHANGELOG.md file
echo "=== react_on_rails_pro/CHANGELOG.md ==="
cat react_on_rails_pro/CHANGELOG.mdRepository: shakacode/react_on_rails
Length of output: 39588
Move this entry to the Pro changelog and remove the documentation mention.
This is a Pro-specific feature ("React on Rails Pro now works without a license...") and should only appear in react_on_rails_pro/CHANGELOG.md, not in the root CHANGELOG.md. Additionally, per changelog guidelines, remove the documentation-updates clause since only user-visible changes (features, bug fixes, breaking changes, deprecations, performance improvements) belong in the changelog.
Suggested fix
Remove the entire entry from CHANGELOG.md at line 28. Then update react_on_rails_pro/CHANGELOG.md to remove the documentation mention:
- **License-Optional Attribution Model**: React on Rails Pro now works without a license for evaluation, development, testing, and CI/CD. A paid license is only required for production deployments. Added `plan` field validation to both Ruby and Node.js license validators — only `"paid"` plan (or no plan field for backwards compatibility) is accepted. Old free licenses are now treated as invalid. Documentation overhauled across README, LICENSE_SETUP, and CI_SETUP guides. [PR 2324](https://github.com/shakacode/react_on_rails/pull/2324) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
+ **License-Optional Attribution Model**: React on Rails Pro now works without a license for evaluation, development, testing, and CI/CD. A paid license is only required for production deployments. Added `plan` field validation to both Ruby and Node.js license validators — only `"paid"` plan (or no plan field for backwards compatibility) is accepted. Old free licenses are now treated as invalid. [PR 2324](https://github.com/shakacode/react_on_rails/pull/2324) by [AbanoubGhadban](https://github.com/AbanoubGhadban).🤖 Prompt for AI Agents
In `@CHANGELOG.md` at line 28, Remove the changelog entry that begins with
"License-Optional Attribution Model" (the entry referencing PR 2324) from the
root CHANGELOG.md and add it to the Pro changelog instead, keeping only the
user-visible description about React on Rails Pro working without a license for
evaluation/dev/testing/CI and that paid licenses are required for production
(retain the note about old free licenses being treated as
invalid/backwards-compatible plan handling), but remove the clause that mentions
documentation updates (README, LICENSE_SETUP, CI_SETUP); ensure the Pro
changelog entry references PR 2324 and the author attribution as in the
original.
PR #2324 Review: License-Optional Attribution ModelOverviewThis PR transforms React on Rails Pro from a "license-required" model to a "license-optional with attribution" model. The application now runs regardless of license status, displaying HTML comments indicating the license state instead of crashing. Code Quality & Best Practices ✅Strengths
Potential Issues & Concerns1.
|
Code Review: License Model Change (License-Required → License-Optional)I've completed a thorough review of PR #2324. Overall, this is a well-implemented, high-quality change with excellent test coverage and symmetric Ruby/TypeScript implementations. Below are my findings: ✅ Strengths1. Excellent Code Quality
2. Robust Cryptographic Security
3. Production-Ready Error Handling
4. Thoughtful Backward Compatibility
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@react_on_rails_pro/LICENSE_SETUP.md`:
- Around line 166-167: Line with the bare email "[email protected]" violates
MD034; update the text in LICENSE_SETUP.md by replacing the bare email with a
mailto link (wrap the existing [email protected] in a mailto: link) so
markdownlint no longer flags it, leaving the surrounding bullet text and the
Sales line unchanged.
- Around line 166-168: The numbered list in LICENSE_SETUP.md skips from "1.
Email: [email protected]" to "3. Sales: [email protected]"; change the
"3." before the Sales entry to "2." so the sequence reads 1., 2.; update the
second list item text ("Sales:
[[email protected]](mailto:[email protected]) for pricing") accordingly.
Comprehensive PR Review: License-Optional Attribution ModelThis is a significant architectural change that fundamentally alters the licensing model from "license-required" to "license-optional with attribution." Overall, the implementation is solid and well-tested. ✅ Strengths1. Excellent Code Quality
2. Robust Error Handling
3. Good Architecture
🔍 Areas for Improvement1. Security ConsiderationsThe TypeScript version is MORE secure - it explicitly enforces RS256 via algorithms array, preventing algorithm substitution attacks. Consider adding runtime assertion in Ruby. 2. Test Coverage GapMissing test case: Malformed JWT (not proper JWT format). Current tests cover invalid signatures but not completely malformed tokens. 3. Error Messages Could Be More ActionableConsider adding HOW to configure the license: "Set REACT_ON_RAILS_PRO_LICENSE or create config/react_on_rails_pro_license.key" 4. Plan Field ValidationCurrent logic treats any plan other than "paid" as invalid. Consider centralized plan allowlist if adding enterprise/trial plans. 🔧 Performance Assessment✅ File I/O only happens once per process 🔒 Security AssessmentStrengths: RS256 verification, no code execution, no sensitive logging 📋 Test CoverageWell-Covered: All license states, plan validation, caching, reset 🎉 Final VerdictOverall: LGTM with minor suggestions 👍Well-executed refactor: Before Merging:
Risk Level: Low 🟢The parallel Ruby/TypeScript implementation is impressive. Great consistency! Excellent work @AbanoubGhadban! 🚀 |
Code Review: PR #2324 - Remove license requirement for React on Rails ProSummaryThis PR implements a significant architectural change, moving from a "license-required" model (app crashes without valid license) to a "license-optional with attribution" model (app runs with HTML comments indicating license status). This is a well-executed refactor with comprehensive changes across Ruby and TypeScript codebases. ✅ Strengths1. Consistent Architecture Across LanguagesThe Ruby and TypeScript implementations mirror each other perfectly:
2. Security Best Practices Maintained
3. Clean API Evolution
4. Comprehensive Test Updates
5. Good Logging HygieneTypeScript properly switched from
|
Code Review: License-Optional Attribution ModelThis is a major architectural change that fundamentally alters React on Rails Pro's licensing model. Overall, the implementation is well-structured and thorough, with only minor documentation improvements suggested. ✅ Strengths
|
PR Review: Remove license requirement for React on Rails Pro - use HTML attribution commentSummaryThis PR represents a significant architectural change to the licensing model from "license-required" to "license-optional with attribution". The implementation is generally solid, but there are several important areas that need attention. ✅ Strengths1. Excellent Code SymmetryThe Ruby and TypeScript implementations mirror each other beautifully:
This consistency will make maintenance much easier. 2. Non-Blocking DesignThe refactor successfully removes all
3. Comprehensive Test CoverageTests cover all four license states and edge cases (missing exp field, invalid signature, etc.). The test refactoring properly removes deprecated methods. 4. Clean API SurfaceThe removal of unused exports simplifies the API to just what's needed.
|
PR Review: Remove license requirement for React on Rails ProOverall AssessmentThis is a well-executed architectural change that transforms React on Rails Pro from a "license-required" to a "license-optional with attribution" model. The implementation is thorough, consistent across both Ruby and TypeScript codebases, and includes comprehensive test coverage. ✅ Strengths1. Architectural Consistency
2. Security Best Practices Maintained
3. Excellent Test Coverage
4. Non-Breaking Change
5. Documentation Updates
|
Summary
Changes React on Rails Pro licensing model from "license-required" to "license-optional with attribution". The app now runs regardless of license status, displaying an HTML comment indicating the license state and logging a warning for license issues in production.
Addresses #2323
Changes
Behavior Changes
UNLICENSEDcommentLICENSE EXPIREDcommentINVALID LICENSEcommentLicensedcommentWhat's Removed
licensed?,license_data(Ruby);isLicensed(),getLicenseData()(TS) had no production callers and have been removed along with their caching logic (@license_data/cachedLicenseData) andlogLicenseInfomethodsconsole.warn/console.login TS license validator — Replaced with Pino logger (log.warn)HTML Attribution Comments
License Logging
License issues are logged at startup with environment-aware messages:
Production:
Rails.logger.warnwith violation message and license URL[React on Rails Pro] No license found. Using React on Rails Pro in production without a valid license violates the license terms. Get a license at https://www.shakacode.com/react-on-rails-pro/Development/Test:
Rails.logger.infowith reassuring message (no warning)[React on Rails Pro] No license found. No license required for development/test environments.TypeScript (Node renderer):
log.warnfor license problems (no environment detection available)Thread Safety
LicenseValidator.license_statusnow uses aMutexto prevent race conditions in multi-threaded environmentsFiles Changed
Ruby:
react_on_rails_pro/lib/react_on_rails_pro/license_validator.rb— New status-based API with thread-safe caching; removedlicensed?,license_data,log_license_info, and@license_datacachingreact_on_rails_pro/lib/react_on_rails_pro/engine.rb— Environment-aware log messages (warn in prod, info in dev/test)react_on_rails_pro/lib/react_on_rails_pro/utils.rb— Attribution comment; removedlicensed?delegatorreact_on_rails/lib/react_on_rails/utils.rb— Check gem presence onlyTypeScript:
packages/react-on-rails-pro-node-renderer/src/shared/licenseValidator.ts— Non-blocking validation; improved error handling for non-Error exceptions; removedisLicensed(),getLicenseData(),logLicenseInfo(),cachedLicenseData; replacedconsole.warnwith Pino loggerpackages/react-on-rails-pro-node-renderer/src/master.ts— Use new APITests:
license_validator_spec.rb— Removed.licensed?,.license_datatest blocks; added thread safety testengine_spec.rb— New integration tests for environment-aware license logginglicenseValidator.test.ts— RemovedisLicensed/getLicenseDatatests; added test for error message logging; mock Pino logger instead ofconsole.warnutils_spec.rb— Updated for new APIConfig:
knip.ts— Updated comment for licenseValidator entry pointTest plan
Summary by CodeRabbit
New Features
Behavior
Documentation
Tests
✏️ Tip: You can customize this high-level summary in your review settings.