rhales 0.3.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/.github/renovate.json5 +52 -0
  3. data/.github/workflows/ci.yml +123 -0
  4. data/.github/workflows/claude-code-review.yml +69 -0
  5. data/.github/workflows/claude.yml +49 -0
  6. data/.github/workflows/code-smells.yml +146 -0
  7. data/.github/workflows/ruby-lint.yml +78 -0
  8. data/.github/workflows/yardoc.yml +126 -0
  9. data/.gitignore +55 -0
  10. data/.pr_agent.toml +63 -0
  11. data/.pre-commit-config.yaml +89 -0
  12. data/.prettierignore +8 -0
  13. data/.prettierrc +38 -0
  14. data/.reek.yml +98 -0
  15. data/.rubocop.yml +428 -0
  16. data/.serena/.gitignore +3 -0
  17. data/.yardopts +56 -0
  18. data/CHANGELOG.md +44 -0
  19. data/CLAUDE.md +1 -2
  20. data/Gemfile +29 -0
  21. data/Gemfile.lock +189 -0
  22. data/README.md +706 -589
  23. data/Rakefile +46 -0
  24. data/debug_context.rb +25 -0
  25. data/demo/rhales-roda-demo/.gitignore +7 -0
  26. data/demo/rhales-roda-demo/Gemfile +32 -0
  27. data/demo/rhales-roda-demo/Gemfile.lock +151 -0
  28. data/demo/rhales-roda-demo/MAIL.md +405 -0
  29. data/demo/rhales-roda-demo/README.md +376 -0
  30. data/demo/rhales-roda-demo/RODA-TEMPLATE-ENGINES.md +192 -0
  31. data/demo/rhales-roda-demo/Rakefile +49 -0
  32. data/demo/rhales-roda-demo/app.rb +325 -0
  33. data/demo/rhales-roda-demo/bin/rackup +26 -0
  34. data/demo/rhales-roda-demo/config.ru +13 -0
  35. data/demo/rhales-roda-demo/db/migrate/001_create_rodauth_tables.rb +266 -0
  36. data/demo/rhales-roda-demo/db/migrate/002_create_rodauth_password_tables.rb +79 -0
  37. data/demo/rhales-roda-demo/db/migrate/003_add_admin_account.rb +68 -0
  38. data/demo/rhales-roda-demo/templates/change_login.rue +31 -0
  39. data/demo/rhales-roda-demo/templates/change_password.rue +36 -0
  40. data/demo/rhales-roda-demo/templates/close_account.rue +31 -0
  41. data/demo/rhales-roda-demo/templates/create_account.rue +40 -0
  42. data/demo/rhales-roda-demo/templates/dashboard.rue +150 -0
  43. data/demo/rhales-roda-demo/templates/home.rue +78 -0
  44. data/demo/rhales-roda-demo/templates/layouts/main.rue +168 -0
  45. data/demo/rhales-roda-demo/templates/login.rue +65 -0
  46. data/demo/rhales-roda-demo/templates/logout.rue +25 -0
  47. data/demo/rhales-roda-demo/templates/reset_password.rue +26 -0
  48. data/demo/rhales-roda-demo/templates/verify_account.rue +27 -0
  49. data/demo/rhales-roda-demo/test_full_output.rb +27 -0
  50. data/demo/rhales-roda-demo/test_simple.rb +24 -0
  51. data/docs/.gitignore +9 -0
  52. data/docs/architecture/data-flow.md +499 -0
  53. data/examples/dashboard-with-charts.rue +271 -0
  54. data/examples/form-with-validation.rue +180 -0
  55. data/examples/simple-page.rue +61 -0
  56. data/examples/vue.rue +136 -0
  57. data/generate-json-schemas.ts +158 -0
  58. data/json_schemer_migration_summary.md +172 -0
  59. data/lib/rhales/adapters/base_auth.rb +2 -0
  60. data/lib/rhales/adapters/base_request.rb +2 -0
  61. data/lib/rhales/adapters/base_session.rb +2 -0
  62. data/lib/rhales/adapters.rb +7 -0
  63. data/lib/rhales/configuration.rb +161 -1
  64. data/lib/rhales/core/context.rb +354 -0
  65. data/lib/rhales/{rue_document.rb → core/rue_document.rb} +59 -43
  66. data/lib/rhales/{template_engine.rb → core/template_engine.rb} +80 -33
  67. data/lib/rhales/core/view.rb +529 -0
  68. data/lib/rhales/{view_composition.rb → core/view_composition.rb} +81 -9
  69. data/lib/rhales/core.rb +9 -0
  70. data/lib/rhales/errors/hydration_collision_error.rb +2 -0
  71. data/lib/rhales/errors.rb +2 -0
  72. data/lib/rhales/hydration/earliest_injection_detector.rb +153 -0
  73. data/lib/rhales/hydration/hydration_data_aggregator.rb +487 -0
  74. data/lib/rhales/hydration/hydration_endpoint.rb +215 -0
  75. data/lib/rhales/hydration/hydration_injector.rb +175 -0
  76. data/lib/rhales/{hydration_registry.rb → hydration/hydration_registry.rb} +2 -0
  77. data/lib/rhales/hydration/hydrator.rb +102 -0
  78. data/lib/rhales/hydration/link_based_injection_detector.rb +195 -0
  79. data/lib/rhales/hydration/mount_point_detector.rb +109 -0
  80. data/lib/rhales/hydration/safe_injection_validator.rb +103 -0
  81. data/lib/rhales/hydration.rb +13 -0
  82. data/lib/rhales/{refinements → integrations/refinements}/require_refinements.rb +7 -13
  83. data/lib/rhales/{tilt.rb → integrations/tilt.rb} +26 -18
  84. data/lib/rhales/integrations.rb +6 -0
  85. data/lib/rhales/middleware/json_responder.rb +191 -0
  86. data/lib/rhales/middleware/schema_validator.rb +300 -0
  87. data/lib/rhales/middleware.rb +6 -0
  88. data/lib/rhales/parsers/handlebars_parser.rb +2 -0
  89. data/lib/rhales/parsers/rue_format_parser.rb +55 -36
  90. data/lib/rhales/parsers.rb +9 -0
  91. data/lib/rhales/{csp.rb → security/csp.rb} +27 -3
  92. data/lib/rhales/utils/json_serializer.rb +114 -0
  93. data/lib/rhales/utils/logging_helpers.rb +75 -0
  94. data/lib/rhales/utils/schema_extractor.rb +132 -0
  95. data/lib/rhales/utils/schema_generator.rb +194 -0
  96. data/lib/rhales/utils.rb +40 -0
  97. data/lib/rhales/version.rb +5 -1
  98. data/lib/rhales.rb +47 -19
  99. data/lib/tasks/rhales_schema.rake +197 -0
  100. data/package.json +10 -0
  101. data/pnpm-lock.yaml +345 -0
  102. data/pnpm-workspace.yaml +2 -0
  103. data/proofs/error_handling.rb +79 -0
  104. data/proofs/expanded_object_inheritance.rb +82 -0
  105. data/proofs/partial_context_scoping_fix.rb +168 -0
  106. data/proofs/ui_context_partial_inheritance.rb +236 -0
  107. data/rhales.gemspec +14 -6
  108. data/schema_vs_data_comparison.md +254 -0
  109. data/test_direct_access.rb +36 -0
  110. metadata +142 -18
  111. data/CLAUDE.locale.txt +0 -7
  112. data/lib/rhales/context.rb +0 -240
  113. data/lib/rhales/hydration_data_aggregator.rb +0 -220
  114. data/lib/rhales/hydrator.rb +0 -141
  115. data/lib/rhales/parsers/handlebars-grammar-review.txt +0 -39
  116. data/lib/rhales/view.rb +0 -412
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env -S pnpm exec tsx
2
+
3
+ /**
4
+ * Generate JSON Schemas and TypeScript types from Zod configuration schemas
5
+ *
6
+ * Usage:
7
+ * pnpm exec tsx scripts/generate-json-schemas.ts # Generate main schema + types
8
+ * pnpm exec tsx scripts/generate-json-schemas.ts --openapi # Include OpenAPI schemas
9
+ * pnpm exec tsx scripts/generate-json-schemas.ts --watch # Watch mode (future)
10
+ *
11
+ * NOTE: The `-S` flag in the hasbang allows `env` to handle multiple arguments.
12
+ */
13
+
14
+ import { writeFileSync, mkdirSync } from 'fs';
15
+ import { join } from 'path';
16
+ import { z } from 'zod/v4';
17
+ import { configSchema as mutableConfigSchema } from '../schemas/config/mutable';
18
+ import { configSchema as staticConfigSchema } from '../schemas/config/static';
19
+ import { configSchema as runtimeConfigSchema } from '../schemas/config/runtime';
20
+
21
+ const ONETIME_HOME = process.env.ONETIME_HOME || process.cwd();
22
+
23
+ const OUTPUT_MAIN_SCHEMA = join(ONETIME_HOME, 'public/web/dist/schemas/runtime.schema.json');
24
+ const OUTPUT_SCHEMAS_DIR = join(ONETIME_HOME, 'etc/schemas');
25
+
26
+ /**
27
+ * Generate individual JSON schema files
28
+ */
29
+ function generateIndividualSchemas(): void {
30
+ mkdirSync(OUTPUT_SCHEMAS_DIR, { recursive: true });
31
+
32
+ const schemas = [
33
+ {
34
+ schema: staticConfigSchema,
35
+ name: 'config.schema',
36
+ description: 'Static configuration settings loaded from config.yaml',
37
+ },
38
+ {
39
+ schema: mutableConfigSchema,
40
+ name: 'mutable.schema',
41
+ description: 'Dynamic mutable config loaded from mutable.yaml',
42
+ },
43
+ {
44
+ schema: runtimeConfigSchema,
45
+ name: 'runtime.schema',
46
+ description: 'Combined configuration schema for both static and mutable config',
47
+ },
48
+ ];
49
+
50
+ schemas.forEach(({ schema, name, description }) => {
51
+ const jsonSchema = z.toJSONSchema(schema, {
52
+ target: 'draft-2020-12',
53
+ unrepresentable: 'any',
54
+ cycles: 'ref',
55
+ reused: 'inline',
56
+ });
57
+
58
+ const schemaWithMeta = {
59
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
60
+ $id: `https://onetimesecret.com/schemas/${name}.json`,
61
+ title: name
62
+ .split('-')
63
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
64
+ .join(' '),
65
+ description,
66
+ ...jsonSchema,
67
+ };
68
+
69
+ const outputPath = join(OUTPUT_SCHEMAS_DIR, `${name}.json`);
70
+ writeFileSync(outputPath, JSON.stringify(schemaWithMeta, null, 2) + '\n');
71
+ console.log(`Generated: ${outputPath}`);
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Generate main configuration schema as YAML
77
+ */
78
+ function generateMainSchema(): void {
79
+ const jsonSchema = z.toJSONSchema(staticConfigSchema, {
80
+ target: 'draft-2020-12',
81
+ unrepresentable: 'any',
82
+ cycles: 'ref',
83
+ reused: 'inline',
84
+ });
85
+
86
+ const schemaWithMeta = {
87
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
88
+ $id: 'https://onetimesecret.com/schemas/config.schema.json',
89
+ title: 'OneTimeSecret Configuration',
90
+ description: 'Configuration schema for OneTimeSecret application',
91
+ ...jsonSchema,
92
+ };
93
+
94
+ mkdirSync(join(OUTPUT_MAIN_SCHEMA, '..'), { recursive: true });
95
+ writeFileSync(OUTPUT_MAIN_SCHEMA, JSON.stringify(schemaWithMeta, null, 2) + '\n');
96
+ console.log(`Generated: ${OUTPUT_MAIN_SCHEMA}`);
97
+ }
98
+
99
+ /**
100
+ * Generate OpenAPI schemas (optional)
101
+ */
102
+ function generateOpenAPISchemas(): void {
103
+ const schemas = [
104
+ { schema: staticConfigSchema, name: 'static' },
105
+ { schema: mutableConfigSchema, name: 'mutable' },
106
+ { schema: runtimeConfigSchema, name: 'runtime' },
107
+ ];
108
+
109
+ schemas.forEach(({ schema, name }) => {
110
+ const openAPISchema = z.toJSONSchema(schema, {
111
+ target: 'draft-7',
112
+ unrepresentable: 'any',
113
+ cycles: 'ref',
114
+ reused: 'ref',
115
+ });
116
+
117
+ const schemaWithMeta = {
118
+ title: name
119
+ .split('-')
120
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
121
+ .join(' '),
122
+ description: `OpenAPI schema for ${name}`,
123
+ ...openAPISchema,
124
+ };
125
+
126
+ const outputPath = join(OUTPUT_SCHEMAS_DIR, `${name}.openapi.json`);
127
+ writeFileSync(outputPath, JSON.stringify(schemaWithMeta, null, 2) + '\n');
128
+ console.log(`Generated: ${outputPath}`);
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Main execution
134
+ */
135
+ function main(): void {
136
+ const includeOpenAPI = process.argv.includes('--openapi');
137
+ const watchMode = process.argv.includes('--watch');
138
+
139
+ if (watchMode) {
140
+ console.log('Watch mode not yet implemented');
141
+ return;
142
+ }
143
+
144
+ generateMainSchema();
145
+ generateIndividualSchemas();
146
+
147
+ if (includeOpenAPI) {
148
+ generateOpenAPISchemas();
149
+ }
150
+
151
+ console.log('Schema generation complete');
152
+ }
153
+
154
+ if (import.meta.url === `file://${process.argv[1]}`) {
155
+ main();
156
+ }
157
+
158
+ export { generateMainSchema, generateIndividualSchemas, generateOpenAPISchemas };
@@ -0,0 +1,172 @@
1
+ # JSON Schema Migration Summary: json-schema → json_schemer
2
+
3
+ ## Migration Complete ✓
4
+
5
+ Successfully migrated from `json-schema` gem to `json_schemer` for better JSON Schema Draft 2020-12 support.
6
+
7
+ ## Changes Made
8
+
9
+ ### 1. Dependency Update
10
+ - **File**: `rhales.gemspec`
11
+ - **Change**: Replaced `json-schema ~> 4.0` with `json_schemer ~> 2.3`
12
+ - **Reason**: Better Draft 2020-12 support, modern API, superior performance
13
+
14
+ ### 2. Middleware Implementation
15
+ - **File**: `lib/rhales/middleware/schema_validator.rb`
16
+ - **Changes**:
17
+ - Replaced `require 'json-schema'` with `require 'json_schemer'`
18
+ - Updated `load_schema_cached` to create JSONSchemer validator objects
19
+ - Removed `$schema` and `$id` stripping logic (json_schemer handles this natively)
20
+ - Replaced `JSON::Validator.fully_validate` with `schema.validate(data).to_a`
21
+ - Added `format_errors` method for human-readable error messages
22
+ - Maintained backward-compatible error message format
23
+
24
+ ### 3. Test Updates
25
+ - **Files**:
26
+ - `spec/rhales/middleware/schema_validator_spec.rb`
27
+ - `spec/rhales/integration/schema_validation_spec.rb`
28
+ - **Changes**:
29
+ - Added `require 'fileutils'` where needed
30
+ - Added `require 'rack'` for Rack::Request
31
+ - All existing tests pass without modification to test logic
32
+
33
+ ### 4. Documentation
34
+ - **File**: `CHANGELOG.md`
35
+ - **Added**: Entry documenting the migration and performance improvements
36
+
37
+ ## Key Benefits
38
+
39
+ ### 1. JSON Schema Draft 2020-12 Support
40
+ - Full support for latest schema standard
41
+ - Native handling of `$schema` and `$id` fields
42
+ - Better specification compliance
43
+
44
+ ### 2. Performance Improvement
45
+ - **Before** (json-schema): ~2ms average validation time
46
+ - **After** (json_schemer): ~0.047ms average validation time
47
+ - **Improvement**: ~42x faster (98% reduction)
48
+
49
+ ### 3. Better Error Messages
50
+ json_schemer provides structured error objects with:
51
+ - `data_pointer`: JSON Pointer to the invalid data
52
+ - `schema_pointer`: JSON Pointer to the schema rule
53
+ - `type`: Type of validation error
54
+ - `error`: Human-readable message
55
+ - Full error context for debugging
56
+
57
+ ### 4. Modern API
58
+ ```ruby
59
+ # Old (json-schema)
60
+ errors = JSON::Validator.fully_validate(schema, data, version: :draft4)
61
+
62
+ # New (json_schemer)
63
+ validator = JSONSchemer.schema(schema)
64
+ errors = validator.validate(data).to_a
65
+ ```
66
+
67
+ ## Error Message Examples
68
+
69
+ ### Type Mismatch
70
+ ```
71
+ The property '/authenticated' of type string did not match the following type: boolean
72
+ ```
73
+
74
+ ### Missing Required Field
75
+ ```
76
+ The property '/' is missing required field(s): id, email
77
+ ```
78
+
79
+ ### Enum Validation
80
+ ```
81
+ The property '/role' must be one of: admin, user, guest
82
+ ```
83
+
84
+ ### Range Validation
85
+ ```
86
+ The property '/age' must be >= 0
87
+ The property '/age' must be <= 150
88
+ ```
89
+
90
+ ## Test Results
91
+
92
+ ### All Tests Pass
93
+ ```
94
+ 533 examples, 0 failures
95
+ Finished in 0.30839 seconds
96
+ ```
97
+
98
+ ### Schema Validation Tests
99
+ ```
100
+ 26 examples, 0 failures
101
+ - 20 middleware unit tests
102
+ - 6 integration tests
103
+ ```
104
+
105
+ ### Performance Test
106
+ ```
107
+ Average validation time: 0.0473 ms
108
+ Validated 10,000 times in 0.4726 seconds
109
+ Performance target: < 5ms ✓
110
+ ```
111
+
112
+ ## Compatibility
113
+
114
+ ### Schema Format
115
+ No changes needed to existing schemas:
116
+ ```json
117
+ {
118
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
119
+ "$id": "https://rhales.dev/schemas/example.json",
120
+ "type": "object",
121
+ "properties": { ... }
122
+ }
123
+ ```
124
+
125
+ ### Middleware Configuration
126
+ No changes needed to middleware setup:
127
+ ```ruby
128
+ use Rhales::Middleware::SchemaValidator,
129
+ schemas_dir: './public/schemas',
130
+ fail_on_error: ENV['RACK_ENV'] == 'development'
131
+ ```
132
+
133
+ ### Error Handling
134
+ Backward-compatible error message format maintained for existing error checks in tests and applications.
135
+
136
+ ## Files Modified
137
+
138
+ 1. `/Users/d/Projects/opensource/onetime/rhales/rhales.gemspec`
139
+ 2. `/Users/d/Projects/opensource/onetime/rhales/lib/rhales/middleware/schema_validator.rb`
140
+ 3. `/Users/d/Projects/opensource/onetime/rhales/spec/rhales/middleware/schema_validator_spec.rb`
141
+ 4. `/Users/d/Projects/opensource/onetime/rhales/spec/rhales/integration/schema_validation_spec.rb`
142
+ 5. `/Users/d/Projects/opensource/onetime/rhales/CHANGELOG.md`
143
+
144
+ ## Acceptance Criteria - All Met ✓
145
+
146
+ - [x] `json_schemer` added to gemspec
147
+ - [x] `json-schema` removed from gemspec
148
+ - [x] Middleware updated to use json_schemer
149
+ - [x] Error formatting updated for better messages
150
+ - [x] All middleware tests passing (20/20)
151
+ - [x] All integration tests passing (6/6)
152
+ - [x] Demo schemas validate correctly
153
+ - [x] Full test suite passes (533/533 examples)
154
+ - [x] Performance maintained (< 0.05ms, well under 5ms target)
155
+ - [x] CHANGELOG updated
156
+ - [x] Backward-compatible error messages
157
+
158
+ ## Next Steps
159
+
160
+ 1. Deploy to staging environment
161
+ 2. Monitor validation performance metrics
162
+ 3. Consider leveraging json_schemer's additional features:
163
+ - Remote schema references ($ref to URLs)
164
+ - Custom format validators
165
+ - OpenAPI schema support
166
+ - Meta-schema validation
167
+
168
+ ## References
169
+
170
+ - json_schemer: https://github.com/davishmcclurg/json_schemer
171
+ - JSON Schema Draft 2020-12: https://json-schema.org/draft/2020-12/schema
172
+ - Migration commit: feature/29-contract branch
@@ -1,4 +1,6 @@
1
1
  # lib/rhales/adapters/base_auth.rb
2
+ #
3
+ # frozen_string_literal: true
2
4
 
3
5
  module Rhales
4
6
  module Adapters
@@ -1,4 +1,6 @@
1
1
  # lib/rhales/adapters/base_request.rb
2
+ #
3
+ # frozen_string_literal: true
2
4
 
3
5
  module Rhales
4
6
  module Adapters
@@ -1,4 +1,6 @@
1
1
  # lib/rhales/adapters/base_session.rb
2
+ #
3
+ # frozen_string_literal: true
2
4
 
3
5
  module Rhales
4
6
  module Adapters
@@ -0,0 +1,7 @@
1
+ # lib/rhales/adapters.rb
2
+ #
3
+ # frozen_string_literal: true
4
+
5
+ require_relative 'adapters/base_auth'
6
+ require_relative 'adapters/base_session'
7
+ require_relative 'adapters/base_request'
@@ -1,6 +1,117 @@
1
1
  # lib/rhales/configuration.rb
2
+ #
3
+ # frozen_string_literal: true
2
4
 
3
5
  module Rhales
6
+ # Hydration-specific configuration settings
7
+ #
8
+ # Controls how hydration scripts are injected into HTML templates.
9
+ # Supports multiple injection strategies for different performance characteristics:
10
+ #
11
+ # ## Traditional Strategies
12
+ # - `:late` (default) - injects before </body> tag (safest, backwards compatible)
13
+ # - `:early` - injects before detected mount points for improved performance
14
+ # - `:earliest` - injects in HTML head section for maximum performance
15
+ #
16
+ # ## Link-Based Strategies (API endpoints)
17
+ # - `:link` - basic link reference to API endpoint
18
+ # - `:prefetch` - browser prefetch for future page loads
19
+ # - `:preload` - high priority preload for current page
20
+ # - `:modulepreload` - ES module preloading
21
+ # - `:lazy` - intersection observer-based lazy loading
22
+ class HydrationConfiguration
23
+ VALID_STRATEGIES = [:late, :early, :earliest, :link, :prefetch, :preload, :modulepreload, :lazy].freeze
24
+ LINK_BASED_STRATEGIES = [:link, :prefetch, :preload, :modulepreload, :lazy].freeze
25
+ DEFAULT_API_CACHE_TTL = 300 # 5 minutes
26
+
27
+ # Injection strategy - one of VALID_STRATEGIES
28
+ attr_accessor :injection_strategy
29
+
30
+ # Array of CSS selectors to detect frontend mount points
31
+ attr_accessor :mount_point_selectors
32
+
33
+ # Whether to fallback to late injection when no mount points detected
34
+ attr_accessor :fallback_to_late
35
+
36
+ # Whether to fallback to late injection when early injection is unsafe
37
+ attr_accessor :fallback_when_unsafe
38
+
39
+ # Disable early injection for specific templates (array of template names)
40
+ attr_accessor :disable_early_for_templates
41
+
42
+ # API endpoint configuration for link-based strategies
43
+ attr_accessor :api_endpoint_enabled, :api_endpoint_path
44
+
45
+ # Link tag configuration
46
+ attr_accessor :link_crossorigin
47
+
48
+ # Module export configuration for :modulepreload strategy
49
+ attr_accessor :module_export_enabled
50
+
51
+ # Lazy loading configuration
52
+ attr_accessor :lazy_mount_selector
53
+
54
+ # Data attribute reflection system
55
+ attr_accessor :reflection_enabled
56
+
57
+ # Caching configuration for API endpoints
58
+ attr_accessor :api_cache_enabled, :api_cache_ttl
59
+
60
+ # CORS configuration for API endpoints
61
+ attr_accessor :cors_enabled, :cors_origin
62
+
63
+ def initialize
64
+ # Traditional strategy settings
65
+ @injection_strategy = :late
66
+ @mount_point_selectors = ['#app', '#root', '[data-rsfc-mount]', '[data-mount]']
67
+ @fallback_to_late = true
68
+ @fallback_when_unsafe = true
69
+ @disable_early_for_templates = []
70
+
71
+ # API endpoint settings
72
+ @api_endpoint_enabled = false
73
+ @api_endpoint_path = '/api/hydration'
74
+
75
+ # Link tag settings
76
+ @link_crossorigin = true
77
+
78
+ # Module export settings
79
+ @module_export_enabled = false
80
+
81
+ # Lazy loading settings
82
+ @lazy_mount_selector = '#app'
83
+
84
+ # Reflection system settings
85
+ @reflection_enabled = true
86
+
87
+ # Caching settings
88
+ @api_cache_enabled = false
89
+ @api_cache_ttl = DEFAULT_API_CACHE_TTL
90
+
91
+ # CORS settings
92
+ @cors_enabled = false
93
+ @cors_origin = '*'
94
+ end
95
+
96
+ # Validate the injection strategy
97
+ def injection_strategy=(strategy)
98
+ unless VALID_STRATEGIES.include?(strategy)
99
+ raise ArgumentError, "Invalid injection strategy: #{strategy}. Valid options: #{VALID_STRATEGIES.join(', ')}"
100
+ end
101
+ @injection_strategy = strategy
102
+ end
103
+
104
+ # Check if current strategy is link-based
105
+ def link_based_strategy?
106
+ LINK_BASED_STRATEGIES.include?(@injection_strategy)
107
+ end
108
+
109
+ # Check if API endpoints should be enabled
110
+ def api_endpoints_required?
111
+ link_based_strategy? || @api_endpoint_enabled
112
+ end
113
+ end
114
+
4
115
  # Configuration management for Rhales library
5
116
  #
6
117
  # Provides a clean, testable alternative to global configuration access.
@@ -31,6 +142,21 @@ module Rhales
31
142
  # Performance settings
32
143
  attr_accessor :cache_parsed_templates, :cache_ttl
33
144
 
145
+ # Hydration settings
146
+ attr_accessor :hydration
147
+
148
+ # Schema validation settings
149
+ attr_accessor :enable_schema_validation, :fail_on_validation_error, :schemas_dir
150
+
151
+ # JSON response settings
152
+ attr_accessor :enable_json_responder, :json_responder_include_metadata
153
+
154
+ # Logging settings
155
+ attr_accessor :allowed_unescaped_variables
156
+
157
+ # Hydration mismatch reporting settings
158
+ attr_accessor :hydration_mismatch_format, :hydration_authority
159
+
34
160
  def initialize
35
161
  # Set sensible defaults
36
162
  @default_locale = 'en'
@@ -47,6 +173,26 @@ module Rhales
47
173
  @site_ssl_enabled = false
48
174
  @cache_parsed_templates = true
49
175
  @cache_ttl = 3600 # 1 hour
176
+ @hydration = HydrationConfiguration.new
177
+
178
+ # Schema validation defaults
179
+ @enable_schema_validation = true
180
+ @fail_on_validation_error = false # Set by environment in middleware
181
+ @schemas_dir = './public/schemas' # Default to implementing project's public directory
182
+
183
+ # JSON responder defaults
184
+ @enable_json_responder = true
185
+ @json_responder_include_metadata = false
186
+
187
+ # Logging defaults
188
+ @allowed_unescaped_variables = []
189
+
190
+ # Hydration mismatch reporting defaults
191
+ @hydration_mismatch_format = :compact # :compact, :multiline, :sidebyside, :json
192
+ @hydration_authority = :schema # :schema or :data
193
+
194
+ # Yield to block for configuration if provided
195
+ yield(self) if block_given?
50
196
  end
51
197
 
52
198
  # Build API base URL from site configuration
@@ -86,7 +232,7 @@ module Rhales
86
232
  'worker-src' => ["'self'"],
87
233
  'manifest-src' => ["'self'"],
88
234
  'prefetch-src' => ["'self'"],
89
- 'upgrade-insecure-requests' => []
235
+ 'upgrade-insecure-requests' => [],
90
236
  }.freeze
91
237
  end
92
238
 
@@ -140,6 +286,20 @@ module Rhales
140
286
  yield(configuration) if block_given?
141
287
  configuration.validate!
142
288
  configuration.freeze!
289
+
290
+ # Debug log the configuration (guard against stale test mocks)
291
+ if Rhales.logger
292
+ require_relative 'utils/logging_helpers'
293
+ extend Rhales::Utils::LoggingHelpers
294
+
295
+ log_with_metadata(Rhales.logger, :debug, 'Rhales configured',
296
+ hydration_mismatch_format: configuration.hydration_mismatch_format,
297
+ hydration_authority: configuration.hydration_authority,
298
+ enable_schema_validation: configuration.enable_schema_validation,
299
+ fail_on_validation_error: configuration.fail_on_validation_error
300
+ )
301
+ end
302
+
143
303
  configuration
144
304
  end
145
305