rhales 0.4.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 (115) 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 -1
  20. data/Gemfile +29 -0
  21. data/Gemfile.lock +189 -0
  22. data/README.md +686 -868
  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 +47 -0
  64. data/lib/rhales/core/context.rb +354 -0
  65. data/lib/rhales/{rue_document.rb → core/rue_document.rb} +56 -38
  66. data/lib/rhales/{template_engine.rb → core/template_engine.rb} +66 -59
  67. data/lib/rhales/{view.rb → core/view.rb} +112 -135
  68. data/lib/rhales/{view_composition.rb → core/view_composition.rb} +78 -8
  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/{earliest_injection_detector.rb → hydration/earliest_injection_detector.rb} +4 -0
  73. data/lib/rhales/hydration/hydration_data_aggregator.rb +487 -0
  74. data/lib/rhales/{hydration_endpoint.rb → hydration/hydration_endpoint.rb} +16 -12
  75. data/lib/rhales/{hydration_injector.rb → hydration/hydration_injector.rb} +4 -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/{link_based_injection_detector.rb → hydration/link_based_injection_detector.rb} +4 -0
  79. data/lib/rhales/{mount_point_detector.rb → hydration/mount_point_detector.rb} +4 -0
  80. data/lib/rhales/{safe_injection_validator.rb → hydration/safe_injection_validator.rb} +4 -0
  81. data/lib/rhales/hydration.rb +13 -0
  82. data/lib/rhales/{refinements → integrations/refinements}/require_refinements.rb +3 -1
  83. data/lib/rhales/{tilt.rb → integrations/tilt.rb} +22 -15
  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 +9 -7
  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 +3 -1
  98. data/lib/rhales.rb +41 -24
  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 +141 -23
  111. data/CLAUDE.locale.txt +0 -7
  112. data/lib/rhales/context.rb +0 -239
  113. data/lib/rhales/hydration_data_aggregator.rb +0 -221
  114. data/lib/rhales/hydrator.rb +0 -141
  115. data/lib/rhales/parsers/handlebars-grammar-review.txt +0 -39
@@ -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,4 +1,6 @@
1
1
  # lib/rhales/configuration.rb
2
+ #
3
+ # frozen_string_literal: true
2
4
 
3
5
  module Rhales
4
6
  # Hydration-specific configuration settings
@@ -143,6 +145,18 @@ module Rhales
143
145
  # Hydration settings
144
146
  attr_accessor :hydration
145
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
+
146
160
  def initialize
147
161
  # Set sensible defaults
148
162
  @default_locale = 'en'
@@ -160,6 +174,25 @@ module Rhales
160
174
  @cache_parsed_templates = true
161
175
  @cache_ttl = 3600 # 1 hour
162
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?
163
196
  end
164
197
 
165
198
  # Build API base URL from site configuration
@@ -253,6 +286,20 @@ module Rhales
253
286
  yield(configuration) if block_given?
254
287
  configuration.validate!
255
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
+
256
303
  configuration
257
304
  end
258
305