hecks 3.10.0 → 3.12.0
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.
- checksums.yaml +4 -4
- data/examples/pizzas/bluebook/pizzas.bluebook +29 -0
- data/examples/pizzas/bluebook/pizzas.hecksagon +7 -0
- data/exe/hecks +4 -4
- data/lib/hecks/adapters/driven/d1.rb +2 -10
- data/lib/hecks/adapters/driven/heki.adapter +1 -1
- data/lib/hecks/adapters/driven/heki.rb +2 -12
- data/lib/hecks/adapters/driven/lambda.adapter +1 -1
- data/lib/hecks/adapters/driven/lambda.rb +3 -18
- data/lib/hecks/adapters/driven/postgres.rb +4 -11
- data/lib/hecks/adapters/driven/sqlite.adapter +1 -1
- data/lib/hecks/adapters/driven/sqlite.rb +2 -10
- data/lib/hecks/adapters/driving/admission.rb +46 -0
- data/lib/hecks/adapters/driving/cli/nesting.rb +36 -0
- data/lib/hecks/adapters/driving/cli/shorthand.rb +88 -0
- data/lib/hecks/adapters/driving/cli.rb +127 -0
- data/lib/hecks/adapters/driving/cli_runner/answers.rb +160 -0
- data/lib/hecks/adapters/driving/cli_runner/resolution.rb +158 -0
- data/lib/hecks/adapters/driving/cli_runner/settling.rb +120 -0
- data/lib/hecks/adapters/driving/cli_runner/streaming.rb +93 -0
- data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +47 -0
- data/lib/hecks/adapters/driving/cli_runner.rb +70 -0
- data/lib/hecks/adapters/driving/command_request.rb +121 -0
- data/lib/hecks/adapters/driving/handle.rb +214 -0
- data/lib/hecks/adapters/driving/json.rb +136 -0
- data/lib/hecks/adapters/driving/launcher_options.rb +267 -0
- data/lib/hecks/adapters/driving/mcp/properties.rb +49 -0
- data/lib/hecks/adapters/driving/mcp/tool_calls.rb +116 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/auditing.rb +53 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/calling.rb +71 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/reading.rb +99 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions.rb +18 -0
- data/lib/hecks/adapters/driving/mcp.rb +159 -0
- data/lib/hecks/adapters/driving/mcp_guide_cache.rb +78 -0
- data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +97 -0
- data/lib/hecks/adapters/driving/mcp_scope/env_problems.rb +69 -0
- data/lib/hecks/adapters/driving/mcp_scope/presenter.rb +83 -0
- data/lib/hecks/adapters/driving/mcp_scope.rb +213 -0
- data/lib/hecks/adapters/driving/newcomer.rb +50 -0
- data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +171 -0
- data/lib/hecks/adapters/driving/ruby/chapter.rb +91 -0
- data/lib/hecks/adapters/driving/ruby.rb +83 -0
- data/lib/hecks/adapters/driving/usage_cache.rb +144 -0
- data/lib/hecks/{doors.rb → adapters/driving.rb} +10 -6
- data/lib/hecks/behaviors/expectations/boot.rb +1 -1
- data/lib/hecks/bench/ruby_runner.rb +1 -1
- data/lib/hecks/bluebook/ask_resolution.rb +130 -0
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +8 -2
- data/lib/hecks/bluebook/assembly/contracts/read_models.rb +1 -1
- data/lib/hecks/bluebook/assembly/contracts/rules.rb +4 -2
- data/lib/hecks/bluebook/assembly/contracts/structure.rb +3 -1
- data/lib/hecks/bluebook/assembly/marks.rb +4 -15
- data/lib/hecks/bluebook/assembly/scalars.rb +39 -0
- data/lib/hecks/bluebook/attribute.rb +1 -1
- data/lib/hecks/bluebook/behaviour/command.rb +13 -8
- data/lib/hecks/bluebook/behaviour/policy.rb +30 -0
- data/lib/hecks/bluebook/capabilities/attribute_values.rb +72 -0
- data/lib/hecks/bluebook/capabilities.rb +91 -9
- data/lib/hecks/bluebook/domain_port.rb +16 -4
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +18 -6
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +13 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/computed_sources.rb +98 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/fan_out_rows.rb +42 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +14 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +69 -3
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +17 -10
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +5 -0
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -0
- data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +8 -1
- data/lib/hecks/bluebook/dsl/command_builder/operands.rb +121 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +2 -0
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +10 -1
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +45 -2
- data/lib/hecks/bluebook/dsl/policy_builder.rb +47 -10
- data/lib/hecks/bluebook/dsl/rule_reference.rb +7 -4
- data/lib/hecks/bluebook/dsl/world_builder.rb +1 -1
- data/lib/hecks/bluebook/expression/ast_json/emitters.rb +6 -0
- data/lib/hecks/bluebook/expression/ast_json.rb +9 -6
- data/lib/hecks/bluebook/expression/ast_reader.rb +14 -9
- data/lib/hecks/bluebook/expression/projection.json +36 -0
- data/lib/hecks/bluebook/expression/resolver/operations.rb +31 -0
- data/lib/hecks/bluebook/expression/resolver/parsing.rb +38 -5
- data/lib/hecks/bluebook/expression/resolver/scanning.rb +22 -5
- data/lib/hecks/bluebook/expression/resolver/values.rb +10 -0
- data/lib/hecks/bluebook/expression/resolver.rb +20 -1
- data/lib/hecks/bluebook/hecksagon.rb +23 -3
- data/lib/hecks/bluebook/lifecycle.rb +22 -3
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +13 -1
- data/lib/hecks/bluebook/meta_validator/modes.rb +4 -1
- data/lib/hecks/bluebook/meta_validator/readings.rb +24 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +6 -3
- data/lib/hecks/bluebook/meta_validator/shapes.rb +5 -0
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +1 -1
- data/lib/hecks/bluebook/meta_validator.rb +12 -12
- data/lib/hecks/bluebook/model_check/ask_checks.rb +71 -0
- data/lib/hecks/bluebook/model_check/policy_checks.rb +2 -1
- data/lib/hecks/bluebook/model_check/reference_checks.rb +70 -0
- data/lib/hecks/bluebook/model_check.rb +8 -2
- data/lib/hecks/bluebook/policy.rb +4 -2
- data/lib/hecks/bluebook/smoke_test.rb +1 -1
- data/lib/hecks/bluebook/synthesizer.rb +2 -0
- data/lib/hecks/bluebook.rb +2 -0
- data/lib/hecks/cli/command_table.rb +1 -1
- data/lib/hecks/cli/console.rb +2 -1
- data/lib/hecks/cli/document.rb +1 -1
- data/lib/hecks/cli/launcher_words.rb +4 -4
- data/lib/hecks/cli/mcp.rb +4 -4
- data/lib/hecks/cli/project_cli/launcher_source.rb +2 -2
- data/lib/hecks/cli/project_cli/templates.rb +5 -5
- data/lib/hecks/cli/project_cli.rb +9 -6
- data/lib/hecks/cli/run.rb +2 -2
- data/lib/hecks/cli/smoke_http/checks.rb +4 -1
- data/lib/hecks/cli/smoke_http/transport.rb +3 -3
- data/lib/hecks/cli/smoke_http.rb +3 -0
- data/lib/hecks/codemod.rb +5 -2
- data/lib/hecks/corpus/routes.rb +7 -0
- data/lib/hecks/corpus/rust.rb +3 -2
- data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -4
- data/lib/hecks/doc/reference/rendering.rb +6 -3
- data/lib/hecks/forms/app/commands.rb +8 -7
- data/lib/hecks/forms/app/queries.rb +2 -1
- data/lib/hecks/forms/app.rb +1 -1
- data/lib/hecks/forms/record_renderer.rb +1 -1
- data/lib/hecks/framework/bluebook/privacy.bluebook +11 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +4 -1
- data/lib/hecks/fuzzing/failure_triage.rb +2 -1
- data/lib/hecks/fuzzing/mutation/run.rb +11 -4
- data/lib/hecks/fuzzing/properties/catalog.rb +6 -4
- data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +18 -11
- data/lib/hecks/fuzzing/properties/guards.rb +1 -1
- data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +1 -1
- data/lib/hecks/fuzzing/self_consistency.rb +6 -2
- data/lib/hecks/fuzzing/shrinker.rb +3 -1
- data/lib/hecks/fuzzing/value_generator.rb +19 -5
- data/lib/hecks/gate/stages.yml +33 -7
- data/lib/hecks/grammar/evolve.rb +1 -1
- data/lib/hecks/grammar/expression_operators.json +372 -0
- data/lib/hecks/grammar/operators.rb +3 -1
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +10 -10
- data/lib/hecks/hecks/adapters/codebase/inspection/rubycritic.rb +35 -0
- data/lib/hecks/hecks/adapters/codebase/inspection.rb +104 -0
- data/lib/hecks/hecks/adapters/codebase/publishing.rb +2 -1
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +12 -2
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +2 -1
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +1 -1
- data/lib/hecks/hecks/adapters/cost_explorer.rb +8 -5
- data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +2 -1
- data/lib/hecks/hecks/adapters/finding_github.rb +13 -6
- data/lib/hecks/hecks/adapters/first_admin.rb +2 -2
- data/lib/hecks/hecks/adapters/github_rulesets.rb +6 -3
- data/lib/hecks/hecks/adapters/in_process_boot.rb +1 -1
- data/lib/hecks/hecks/adapters/journal_store/compaction.rb +1 -1
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +10 -20
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +28 -5
- data/lib/hecks/hecks/adapters/local_files.rb +2 -2
- data/lib/hecks/hecks/adapters/rehearsal/audit_report.rb +107 -0
- data/lib/hecks/hecks/adapters/rehearsal/census.rb +71 -0
- data/lib/hecks/hecks/adapters/rehearsal/declaration.rb +133 -0
- data/lib/hecks/hecks/adapters/rehearsal/environment.rb +83 -0
- data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +142 -0
- data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +96 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_census.rb +100 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +69 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_store.rb +133 -0
- data/lib/hecks/hecks/adapters/rehearsal/rows.rb +41 -0
- data/lib/hecks/hecks/adapters/rehearsal/rust_audit.rb +83 -0
- data/lib/hecks/hecks/adapters/rehearsal/subject.rb +104 -0
- data/lib/hecks/hecks/adapters/rehearsal.rb +54 -0
- data/lib/hecks/hecks/adapters/rehearsal_store.adapter +7 -0
- data/lib/hecks/hecks/adapters/rehearsal_store.rb +81 -0
- data/lib/hecks/hecks/adapters/terminal.rb +13 -11
- data/lib/hecks/hecks/codebase.behaviors +13 -1
- data/lib/hecks/hecks/codebase.bluebook +239 -5
- data/lib/hecks/hecks/custodian.behaviors +24 -6
- data/lib/hecks/hecks/custodian.bluebook +6 -1227
- data/lib/hecks/hecks/deploy.behaviors +1 -1
- data/lib/hecks/hecks/deploy.world +1 -3
- data/lib/hecks/hecks/hecks.behaviors +1 -1
- data/lib/hecks/hecks/hecks.hecksagon +53 -18
- data/lib/hecks/hecks/hecks.world +13 -10
- data/lib/hecks/hecks/rehearsal.bluebook +477 -0
- data/lib/hecks/hecks/site.behaviors +1 -1
- data/lib/hecks/hecks/site.world +0 -1
- data/lib/hecks/hecks/tooling.bluebook +1238 -0
- data/lib/hecks/indifferent_key.rb +20 -0
- data/lib/hecks/language/adapter.bluebook +13 -3
- data/lib/hecks/language/bluebook/aggregate.bluebook +23 -0
- data/lib/hecks/language/bluebook/bluebook.behaviors +23 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +15 -0
- data/lib/hecks/language/bluebook/entity.bluebook +18 -0
- data/lib/hecks/language/bluebook/policy.behaviors +19 -0
- data/lib/hecks/language/bluebook/policy.bluebook +9 -1
- data/lib/hecks/language/bluebook/query.bluebook +1 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +63 -4
- data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -1
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +22 -0
- data/lib/hecks/language/oidc.json +10 -0
- data/lib/hecks/language/port.bluebook +4 -4
- data/lib/hecks/literal.rb +12 -3
- data/lib/hecks/ports/key_vault.rb +7 -2
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +21 -10
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +4 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +2 -1
- data/lib/hecks/ports/persistence/repository_factory.rb +6 -3
- data/lib/hecks/projection_files/expression_tables.rb +7 -2
- data/lib/hecks/projections/deploy/box/compose.rb +6 -4
- data/lib/hecks/projections/deploy/box/edge.rb +62 -0
- data/lib/hecks/projections/deploy/box/logging.rb +99 -0
- data/lib/hecks/projections/deploy/box/roll_scripts.rb +16 -8
- data/lib/hecks/projections/deploy/box/settings/cdn.rb +40 -0
- data/lib/hecks/projections/deploy/box/settings/logs.rb +40 -0
- data/lib/hecks/projections/deploy/box/settings/patterns.rb +11 -0
- data/lib/hecks/projections/deploy/box/settings/types.rb +16 -1
- data/lib/hecks/projections/deploy/box/settings.rb +6 -2
- data/lib/hecks/projections/deploy/box/stack_yaml.rb +5 -2
- data/lib/hecks/projections/deploy/box/templates/Makefile.tmpl +16 -0
- data/lib/hecks/projections/deploy/box/templates/box.yaml.tmpl +8 -4
- data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +32 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/box/templates/edge.mk.tmpl +17 -0
- data/lib/hecks/projections/deploy/box/templates/edge.yaml.tmpl +65 -0
- data/lib/hecks/projections/deploy/box/templates/log-group.yaml.tmpl +12 -0
- data/lib/hecks/projections/deploy/box/templates/log-policy.yaml.tmpl +7 -0
- data/lib/hecks/projections/deploy/box/templates/render-compose-taskdef.sh.tmpl +5 -4
- data/lib/hecks/projections/deploy/box/templates/render-compose.sh.tmpl +5 -4
- data/lib/hecks/projections/deploy/box.rb +15 -3
- data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
- data/lib/hecks/projections/deploy/shared.rb +5 -2
- data/lib/hecks/projections/model/deviations.rb +2 -2
- data/lib/hecks/projections/model.rb +2 -2
- data/lib/hecks/projections/oidc.rb +13 -1
- data/lib/hecks/projections/shape.rb +5 -2
- data/lib/hecks/projections/site/cms_editor/attributes.rb +26 -6
- data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
- data/lib/hecks/projections/site/cms_editor/checks.rb +14 -1
- data/lib/hecks/projections/site/cms_editor/clearing.rb +70 -0
- data/lib/hecks/projections/site/cms_editor/color.rb +124 -0
- data/lib/hecks/projections/site/cms_editor/composition.rb +42 -0
- data/lib/hecks/projections/site/cms_editor/destructive.rb +61 -0
- data/lib/hecks/projections/site/cms_editor/drafts.rb +102 -0
- data/lib/hecks/projections/site/cms_editor/hints.rb +74 -0
- data/lib/hecks/projections/site/cms_editor/icons.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/key_kinds.rb +31 -0
- data/lib/hecks/projections/site/cms_editor/limits.rb +72 -0
- data/lib/hecks/projections/site/cms_editor/media.rb +1 -1
- data/lib/hecks/projections/site/cms_editor/moment.rb +34 -0
- data/lib/hecks/projections/site/cms_editor/palette.rb +115 -0
- data/lib/hecks/projections/site/cms_editor/pickers.rb +85 -0
- data/lib/hecks/projections/site/cms_editor/preview.rb +91 -0
- data/lib/hecks/projections/site/cms_editor/relations.rb +92 -0
- data/lib/hecks/projections/site/cms_editor/scale_checks.rb +66 -0
- data/lib/hecks/projections/site/cms_editor/scheduling.rb +150 -0
- data/lib/hecks/projections/site/cms_editor/schema.rb +96 -19
- data/lib/hecks/projections/site/cms_editor/setting.rb +52 -9
- data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +18 -1
- data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +251 -57
- data/lib/hecks/projections/site/cms_editor/templates/src/assets.ts.tmpl +98 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +32 -24
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/app.css.tmpl +412 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/autosave.js.tmpl +144 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/blocks.js.tmpl +500 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_doc.js.tmpl +175 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_editor.js.tmpl +418 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/epoch.js.tmpl +61 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/forms.js.tmpl +210 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/lists.js.tmpl +40 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/main.js.tmpl +26 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/media_picker.js.tmpl +232 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/moments.js.tmpl +73 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/pickers.js.tmpl +152 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/preview.js.tmpl +98 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/shell.js.tmpl +140 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/toast.js.tmpl +66 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/choices.ts.tmpl +99 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +78 -24
- data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +6 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/flash.ts.tmpl +52 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +19 -2
- data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +31 -8
- data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +36 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +131 -2
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/availability.ts.tmpl +15 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/block_list.js.tmpl +213 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/blocks.ts.tmpl +275 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +8 -5
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/detail.ts.tmpl +88 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/dialogs.ts.tmpl +43 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +229 -34
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +40 -81
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/icons.ts.tmpl +15 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +29 -12
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/links.ts.tmpl +100 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/moments.ts.tmpl +44 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +53 -17
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +178 -88
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/paging.ts.tmpl +82 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +110 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/preview.ts.tmpl +87 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/related.ts.tmpl +97 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +160 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +211 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/table.ts.tmpl +151 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/theme.js.tmpl +16 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/values.ts.tmpl +69 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/words.ts.tmpl +97 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +35 -0
- data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +2 -1
- data/lib/hecks/projections/site/cms_editor/theme.rb +29 -0
- data/lib/hecks/projections/site/cms_editor/theme_checks.rb +57 -0
- data/lib/hecks/projections/site/cms_editor.rb +49 -23
- data/lib/hecks/projections/site/role_probe.rb +2 -0
- data/lib/hecks/projections/site/site_root/workflow.rb +5 -0
- data/lib/hecks/projector/cli_audience.rb +22 -1
- data/lib/hecks/projector/cli_projector/listing.rb +1 -1
- data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
- data/lib/hecks/projector/cli_projector/usage.rb +15 -4
- data/lib/hecks/projector/docs_projector/closing.rb +1 -1
- data/lib/hecks/projector/docs_projector.rb +1 -1
- data/lib/hecks/projector/exporter/bindings.rb +40 -10
- data/lib/hecks/projector/exporter/capability_values.rb +55 -0
- data/lib/hecks/projector/narrate_projector/reactions.rb +1 -1
- data/lib/hecks/projector/target.rb +11 -0
- data/lib/hecks/projector.rb +32 -5
- data/lib/hecks/quality_control/adapters/github_checks.rb +12 -8
- data/lib/hecks/quality_control/adapters/github_issues.rb +8 -4
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +2 -2
- data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep.rb +1 -1
- data/lib/hecks/quality_control/quality_control.bluebook +6 -2
- data/lib/hecks/release/approval.rb +64 -0
- data/lib/hecks/router/{door.rb → aggregate_reader.rb} +5 -4
- data/lib/hecks/router/namespace_installer.rb +16 -16
- data/lib/hecks/router.rb +1 -1
- data/lib/hecks/runtime/best_effort.rb +22 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -2
- data/lib/hecks/runtime/command_interpreter.rb +3 -2
- data/lib/hecks/runtime/command_rules/emission.rb +1 -1
- data/lib/hecks/runtime/dispatcher.rb +4 -4
- data/lib/hecks/runtime/entity_element/location.rb +1 -1
- data/lib/hecks/runtime/event.rb +5 -0
- data/lib/hecks/runtime/identity.rb +7 -6
- data/lib/hecks/runtime/interpreting.rb +2 -1
- data/lib/hecks/runtime/invocation_builder.rb +1 -1
- data/lib/hecks/runtime/loader/boot_steps.rb +8 -5
- data/lib/hecks/runtime/loader.rb +10 -10
- data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -4
- data/lib/hecks/runtime/policy_interpreter/fan_out.rb +3 -3
- data/lib/hecks/runtime/policy_interpreter.rb +6 -6
- data/lib/hecks/runtime/port_operation_interpreter.rb +1 -1
- data/lib/hecks/runtime/reaction_invocation.rb +1 -1
- data/lib/hecks/runtime/rebuild_sweep.rb +11 -1
- data/lib/hecks/runtime/registry/ask_verification.rb +35 -0
- data/lib/hecks/runtime/registry/hecksagon_rules.rb +10 -0
- data/lib/hecks/runtime/registry/merging.rb +1 -1
- data/lib/hecks/runtime/registry/providers.rb +16 -0
- data/lib/hecks/runtime/registry/read_repository.rb +6 -4
- data/lib/hecks/runtime/registry/verification.rb +4 -1
- data/lib/hecks/runtime/registry/world_defaults.rb +29 -0
- data/lib/hecks/runtime/registry.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter/compensation.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter/delivery.rb +4 -4
- data/lib/hecks/runtime/saga_interpreter/transitions.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter.rb +3 -3
- data/lib/hecks/runtime/tenant_check.rb +5 -4
- data/lib/hecks/runtime/value/coercion.rb +2 -2
- data/lib/hecks/runtime/value/validation.rb +16 -4
- data/lib/hecks/runtime.rb +9 -9
- data/lib/hecks/rust_build/host.rb +11 -4
- data/lib/hecks/rust_build/prebuilt_binary.rb +101 -0
- data/lib/hecks/rust_build/project_rust/target_ir.rb +1 -1
- data/lib/hecks/rust_build/wasm.rb +1 -1
- data/lib/hecks/rust_build/wasm_browser.rb +1 -1
- data/lib/hecks/rust_build.rb +11 -0
- data/lib/hecks/served_options.rb +53 -0
- data/lib/hecks/site/bluebook/site.bluebook +1 -0
- data/lib/hecks/storehouse/audit.rb +1 -1
- data/lib/hecks/storehouse/dispatching.rb +8 -6
- data/lib/hecks/storehouse/introspection.rb +2 -2
- data/lib/hecks/storehouse/querying.rb +6 -4
- data/lib/hecks/storehouse.rb +4 -4
- data/lib/hecks/tools/ci_gate_decision.rb +35 -0
- data/lib/hecks/tools/ci_gates.rb +20 -1
- data/lib/hecks/tools/comment_style/source_file.rb +4 -1
- data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +4 -1
- data/lib/hecks/tools/lanes/files.rb +8 -0
- data/lib/hecks/tools/lanes/prebuilt_workflow.rb +81 -0
- data/lib/hecks/tools/lanes/rows.rb +6 -0
- data/lib/hecks/tools/lanes.rb +1 -0
- data/lib/hecks/tools/oidc_manifests.rb +4 -5
- data/lib/hecks/tools/regeneration_run.rb +11 -4
- data/lib/hecks/tools/release_only.rb +111 -0
- data/lib/hecks/tools/site_routes/editor_files.rb +12 -5
- data/lib/hecks/tools/tenant_provisioning.rb +2 -2
- data/lib/hecks/tools/tools_doc.rb +4 -4
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +19 -5
- data/lib/hecks.rb +15 -15
- data/lib/rubocop/cop/hecks/env_dump.rb +69 -0
- data/lib/rubocop/cop/hecks/monotonic_duration.rb +53 -0
- data/lib/rubocop/cop/hecks/no_wall_clock_in_runtime.rb +34 -0
- data/lib/rubocop/cop/hecks/raw_shell_interpolation.rb +79 -0
- data/lib/rubocop/cop/hecks/sleep_in_spec.rb +34 -0
- data/lib/rubocop/cop/hecks/swallowed_rescue.rb +37 -0
- data/lib/rubocop/cop/hecks/symbol_string_key_mix.rb +50 -0
- data/lib/rubocop/cop/hecks/untyped_raise.rb +37 -0
- data/prebuilt/9ee54e2f0d4d6d3fe046827779b221e02de665fba911a048ae5dd8b8fbfb7d90.marshal +0 -0
- data/prebuilt/d74a00e996222c1d8b676d5959092effc46b4dc59e0555f3bf9554ac58e3094a.marshal +0 -0
- data/prebuilt/verdicts-df19f35868d3284a70f55e42dcef87ef4e65e6a678e5135f72e1f6cff4c1357b.json +1 -0
- data/rust/.gitignore +6 -0
- data/rust/Cargo.toml +6 -0
- data/rust/build/src/binding_pass.rs +103 -0
- data/rust/build/src/cargo_sync.rs +6 -0
- data/rust/build/src/lineage_pass.rs +3 -3
- data/rust/build/src/main.rs +17 -5
- data/rust/build/src/pipeline.rs +48 -5
- data/rust/build/src/seams_pass.rs +123 -0
- data/rust/build/src/translation_pass.rs +167 -0
- data/rust/codegen/src/asks.rs +103 -0
- data/rust/codegen/src/commands.rs +13 -8
- data/rust/codegen/src/constraints.rs +25 -0
- data/rust/codegen/src/domain_generator.rs +2 -0
- data/rust/codegen/src/expr_emitter.rs +13 -0
- data/rust/codegen/src/json_codec.rs +54 -15
- data/rust/codegen/src/main.rs +1 -0
- data/rust/codegen/src/mutations.rs +128 -3
- data/rust/codegen/src/queries.rs +11 -2
- data/rust/codegen/src/reactions.rs +1 -1
- data/rust/codegen/src/types.rs +166 -8
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/src/api.rs +4 -4
- data/rust/host/src/bin/validate_harness.rs +43 -0
- data/rust/host/src/boundary_fuzz/expr_json.rs +2 -2
- data/rust/host/src/boundary_fuzz/ir.rs +1 -0
- data/rust/host/src/boundary_fuzz/server.rs +1 -1
- data/rust/host/src/checkout.rs +35 -19
- data/rust/host/src/commerce_ir.rs +408 -2
- data/rust/host/src/expr_json.rs +118 -0
- data/rust/host/src/extension.rs +13 -1
- data/rust/host/src/lib.rs +1 -0
- data/rust/host/src/mint.rs +1 -1
- data/rust/host/src/payments/tests.rs +27 -1
- data/rust/host/src/payments.rs +12 -4
- data/rust/host/src/platform_signin/attack_tests.rs +1100 -0
- data/rust/host/src/platform_signin/config.rs +512 -0
- data/rust/host/src/platform_signin/cookie.rs +237 -0
- data/rust/host/src/platform_signin/extension.rs +190 -0
- data/rust/host/src/platform_signin/fetcher.rs +322 -0
- data/rust/host/src/platform_signin/handler.rs +251 -0
- data/rust/host/src/platform_signin/handler_tests.rs +554 -0
- data/rust/host/src/platform_signin/jti.rs +196 -0
- data/rust/host/src/platform_signin/jwks.rs +542 -0
- data/rust/host/src/platform_signin/jws.rs +249 -0
- data/rust/host/src/platform_signin/known_answer_tests.rs +237 -0
- data/rust/host/src/platform_signin/mapping_tests.rs +254 -0
- data/rust/host/src/platform_signin/mod.rs +75 -0
- data/rust/host/src/platform_signin/mode_tests.rs +382 -0
- data/rust/host/src/platform_signin/pages.rs +204 -0
- data/rust/host/src/platform_signin/query.rs +233 -0
- data/rust/host/src/platform_signin/session.rs +151 -0
- data/rust/host/src/platform_signin/settings.rs +385 -0
- data/rust/host/src/platform_signin/strict_json.rs +351 -0
- data/rust/host/src/platform_signin/test_support.rs +235 -0
- data/rust/host/src/platform_signin/ttl_tests.rs +94 -0
- data/rust/host/src/platform_signin/verify.rs +604 -0
- data/rust/host/src/platform_signin/wiring_support.rs +319 -0
- data/rust/host/src/query_step.rs +22 -4
- data/rust/host/src/reference_validate.rs +653 -108
- data/rust/host/src/resend.rs +2 -0
- data/rust/host/src/server.rs +19 -6
- data/rust/host/src/ui_schema.rs +132 -5
- data/rust/host/src/web/newsletter.rs +7 -8
- data/rust/host/src/web/newsletter_send.rs +38 -13
- data/rust/host/src/web/registrations.rs +229 -26
- data/rust/host/src/web.rs +53 -9
- data/rust/parser/src/emit.rs +38 -6
- data/rust/parser/src/expr/ast_json.rs +7 -1
- data/rust/parser/src/expr/resolver.rs +171 -6
- data/rust/parser/src/ir.rs +7 -0
- data/rust/parser/src/keywords.rs +24 -0
- data/rust/parser/src/main.rs +3 -0
- data/rust/parser/src/parse/aggregate.rs +2 -1
- data/rust/parser/src/parse/chapter.rs +2 -2
- data/rust/parser/src/parse/command.rs +2 -0
- data/rust/parser/src/parse/hecksagon.rs +5 -2
- data/rust/parser/src/parse/lifecycle.rs +81 -0
- data/rust/parser/src/parse/mod.rs +15 -1
- data/rust/parser/src/parse/policy.rs +13 -2
- data/rust/parser/src/parse/value_object.rs +34 -17
- data/rust/parser/src/ruby_value.rs +1 -1
- data/rust/src/exemplar/commands.rs +4 -4
- data/rust/src/exemplar/constraints.rs +1 -1
- data/rust/src/exemplar/json.rs +43 -1
- data/rust/src/kernel/cli.rs +7 -5
- data/rust/src/kernel/dispatch.rs +2 -2
- data/rust/src/kernel/dispatch_guard_tests.rs +1 -1
- data/rust/src/kernel/expr.rs +66 -3
- data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
- data/rust/src/kernel/expression_operators/text.rs +26 -2
- data/rust/src/kernel/json.rs +15 -0
- data/rust/src/kernel/mod.rs +1 -1
- data/rust/src/kernel/orchestrate.rs +54 -5
- data/rust/src/kernel/orchestrate_guard_tests.rs +67 -0
- data/rust/src/kernel/pattern.rs +60 -0
- data/rust/src/kernel/reference_lookup.rs +90 -7
- metadata +178 -38
- data/lib/hecks/doors/cli_door/nesting.rb +0 -34
- data/lib/hecks/doors/cli_door/shorthand.rb +0 -85
- data/lib/hecks/doors/cli_door.rb +0 -124
- data/lib/hecks/doors/cli_runner/answers.rb +0 -138
- data/lib/hecks/doors/cli_runner/resolution.rb +0 -146
- data/lib/hecks/doors/cli_runner/settling.rb +0 -115
- data/lib/hecks/doors/cli_runner/streaming.rb +0 -90
- data/lib/hecks/doors/cli_runner/suggestions.rb +0 -43
- data/lib/hecks/doors/cli_runner.rb +0 -66
- data/lib/hecks/doors/command_request.rb +0 -119
- data/lib/hecks/doors/handle.rb +0 -208
- data/lib/hecks/doors/json_door.rb +0 -132
- data/lib/hecks/doors/launcher_options.rb +0 -247
- data/lib/hecks/doors/mcp_door/properties.rb +0 -47
- data/lib/hecks/doors/mcp_door/tool_calls.rb +0 -113
- data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +0 -51
- data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +0 -69
- data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +0 -97
- data/lib/hecks/doors/mcp_door/tool_definitions.rb +0 -15
- data/lib/hecks/doors/mcp_door.rb +0 -156
- data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +0 -92
- data/lib/hecks/doors/mcp_door_scope/env_problems.rb +0 -55
- data/lib/hecks/doors/mcp_door_scope/presenter.rb +0 -78
- data/lib/hecks/doors/mcp_door_scope.rb +0 -201
- data/lib/hecks/doors/mcp_guide_cache.rb +0 -75
- data/lib/hecks/doors/ruby_door/aggregate_door.rb +0 -162
- data/lib/hecks/doors/ruby_door/chapter.rb +0 -89
- data/lib/hecks/doors/ruby_door.rb +0 -80
- data/lib/hecks/doors/usage_cache.rb +0 -139
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_widget.js.tmpl +0 -282
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/media_picker.js.tmpl +0 -109
- data/prebuilt/c28d6d9db14eea3e17161e9d9c262efee30b256cf97693a7cfd552bce24b2f7f.marshal +0 -0
- data/prebuilt/cb375cba61ca0dbe8ddb9739c306510fe05e5f4b7a9b6955caff8224c63ea0e0.marshal +0 -0
- data/prebuilt/verdicts-d6d584ad43b5f3cebf88aafbbdbf024c38574acf18e06adffbc555f7786b1c2f.json +0 -1
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
require "json"
|
|
2
|
-
require_relative "cli_door"
|
|
3
|
-
require_relative "command_request"
|
|
4
|
-
require_relative "json_door"
|
|
5
|
-
require_relative "launcher_options"
|
|
6
|
-
require_relative "../projector"
|
|
7
|
-
require_relative "../ports/clock"
|
|
8
|
-
require_relative "cli_runner/answers"
|
|
9
|
-
require_relative "cli_runner/resolution"
|
|
10
|
-
require_relative "cli_runner/settling"
|
|
11
|
-
require_relative "cli_runner/streaming"
|
|
12
|
-
require_relative "cli_runner/suggestions"
|
|
13
|
-
|
|
14
|
-
module Hecks
|
|
15
|
-
module Doors
|
|
16
|
-
# Parses and dispatches a command line against a `Projector::CliProjector` projection.
|
|
17
|
-
# Does no IO: it answers `[text, status]` and leaves printing and exiting to its callers.
|
|
18
|
-
module CliRunner
|
|
19
|
-
# The class an adapter raises when the tool it wraps refuses.
|
|
20
|
-
TOOL_REFUSAL = "Hecks::Adapters::ConsoleCapture::Failure".freeze
|
|
21
|
-
# The words that open the query namespace; `ask` is the older spelling.
|
|
22
|
-
QUERY_WORDS = %w[query ask].freeze
|
|
23
|
-
|
|
24
|
-
extend Resolution
|
|
25
|
-
extend Suggestions
|
|
26
|
-
extend Answers
|
|
27
|
-
extend Settling
|
|
28
|
-
extend Streaming
|
|
29
|
-
|
|
30
|
-
module_function
|
|
31
|
-
|
|
32
|
-
# Runs one command line against a booted domain and answers the text to print.
|
|
33
|
-
# The booted domain's own chapter is projected, or an attached one its first word names.
|
|
34
|
-
#
|
|
35
|
-
# @param runtime [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted domain
|
|
36
|
-
# @param argv [Array<String>] an optional `query` (or `ask`), the command or query name, then
|
|
37
|
-
# `path=value` pairs; `--help`, `-h`, `help` or nothing answers usage
|
|
38
|
-
# @param program [String] how the caller was invoked, echoed in usage and hints
|
|
39
|
-
# @return [Array(String, Integer)] the text and the status: 0 answered, 1 refused or misused
|
|
40
|
-
# @raise [Runtime::WiringError] if a repository or the clock adapter cannot be resolved
|
|
41
|
-
# @raise [Runtime::StaleWrite] if concurrent writers beat the command through every retry
|
|
42
|
-
def call(runtime:, argv:, program: "hecks run")
|
|
43
|
-
plan = resolve(runtime, argv, program)
|
|
44
|
-
return plan[:answer] if plan[:answer]
|
|
45
|
-
|
|
46
|
-
dispatch(runtime, plan[:spec], plan[:name], plan[:rest], plan[:program], plan[:asking],
|
|
47
|
-
bluebook: plan[:bluebook], launcher: plan[:launcher])
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Answers a command line that asks only for usage, from the projection alone.
|
|
51
|
-
#
|
|
52
|
-
# Needs a registry and no bound adapter, so a `Runtime::Loader::Described` serves: the
|
|
53
|
-
# help text, the no-argument usage, a command's `--help` and an unknown one's hint all come
|
|
54
|
-
# out byte-identical to `call`'s.
|
|
55
|
-
#
|
|
56
|
-
# @param runtime [#registry] a booted domain, or what `Hecks.describe` answers
|
|
57
|
-
# @param argv [Array<String>] as for `call`
|
|
58
|
-
# @param program [String] how the caller was invoked
|
|
59
|
-
# @return [Array(String, Integer), nil] the text and status, or nil when the line would
|
|
60
|
-
# run a command or question and so needs a booted domain
|
|
61
|
-
def usage(runtime:, argv:, program: "hecks run")
|
|
62
|
-
UsageCache.fetch(runtime, argv, program, audience: audience_key) { resolve(runtime, argv, program)[:answer] }
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
require_relative "../runtime/errors"
|
|
2
|
-
|
|
3
|
-
module Hecks
|
|
4
|
-
module Doors
|
|
5
|
-
# Turns an external command request into the dispatcher's `to:`/`with:` envelope.
|
|
6
|
-
#
|
|
7
|
-
# aggregate command: { to: "record-id", with: { declared: "facts" } }
|
|
8
|
-
# entity command: { to: { aggregate: "...", entity: "..." }, with: { ... } }
|
|
9
|
-
module CommandRequest
|
|
10
|
-
module_function
|
|
11
|
-
|
|
12
|
-
# Splits a request, explicit envelope or flat Hash, into routing (`to:`) and facts (`with:`).
|
|
13
|
-
# Keys are symbolized at every depth; in a flat Hash everything but the receiver is a fact.
|
|
14
|
-
#
|
|
15
|
-
# @param input [Hash] the request, with String or Symbol keys
|
|
16
|
-
# @param receiver [Symbol, nil] `:aggregate`, `:entity`, or `nil` for a command with none
|
|
17
|
-
# @param legacy_receiver [Symbol, String, Hash, nil] the flat key that may carry the
|
|
18
|
-
# receiver instead of `to:`: a name for `:aggregate`, `{ aggregate:, entity: }` for
|
|
19
|
-
# `:entity`
|
|
20
|
-
# @return [Hash{Symbol => Object}] `{ with: facts }`, plus `to:` when `receiver` is set
|
|
21
|
-
# @raise [Runtime::TypeMismatch] if the request is malformed or the route does not fit
|
|
22
|
-
# the receiver kind
|
|
23
|
-
# @raise [ArgumentError] if `receiver` is not `nil`, `:aggregate` or `:entity`
|
|
24
|
-
def normalize(input, receiver:, legacy_receiver: nil)
|
|
25
|
-
request = symbolize(input)
|
|
26
|
-
raise Runtime::TypeMismatch, "a command request must be a hash" unless request.is_a?(Hash)
|
|
27
|
-
|
|
28
|
-
route, facts = split(request, receiver: receiver, legacy_receiver: legacy_receiver)
|
|
29
|
-
validate_route!(route, receiver)
|
|
30
|
-
|
|
31
|
-
envelope = { with: facts }
|
|
32
|
-
envelope[:to] = route if receiver
|
|
33
|
-
envelope
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def split(request, receiver:, legacy_receiver:)
|
|
37
|
-
return split_envelope(request) if request.key?(:with)
|
|
38
|
-
|
|
39
|
-
flat = request.dup
|
|
40
|
-
route = flat.delete(:to)
|
|
41
|
-
route = take_legacy_route(flat, receiver, legacy_receiver) if route.nil?
|
|
42
|
-
[route, flat]
|
|
43
|
-
end
|
|
44
|
-
private_class_method :split
|
|
45
|
-
|
|
46
|
-
def split_envelope(request)
|
|
47
|
-
loose = request.keys - [:to, :with]
|
|
48
|
-
unless loose.empty?
|
|
49
|
-
raise Runtime::TypeMismatch,
|
|
50
|
-
"an explicit command envelope takes routing in to: and facts in with:, not loose #{loose.sort.join(", ")}"
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
facts = request[:with]
|
|
54
|
-
raise Runtime::TypeMismatch, "with: must be a hash of command facts" unless facts.is_a?(Hash)
|
|
55
|
-
|
|
56
|
-
[request[:to], facts]
|
|
57
|
-
end
|
|
58
|
-
private_class_method :split_envelope
|
|
59
|
-
|
|
60
|
-
def take_legacy_route(flat, receiver, legacy_receiver)
|
|
61
|
-
return unless legacy_receiver
|
|
62
|
-
|
|
63
|
-
return flat.delete(legacy_receiver.to_sym) if receiver == :aggregate
|
|
64
|
-
|
|
65
|
-
return unless receiver == :entity && legacy_receiver.is_a?(Hash)
|
|
66
|
-
|
|
67
|
-
aggregate_key = legacy_receiver.fetch(:aggregate).to_sym
|
|
68
|
-
entity_key = legacy_receiver.fetch(:entity).to_sym
|
|
69
|
-
return unless flat.key?(aggregate_key) || flat.key?(entity_key)
|
|
70
|
-
|
|
71
|
-
{ aggregate: flat.delete(aggregate_key), entity: flat.delete(entity_key) }
|
|
72
|
-
end
|
|
73
|
-
private_class_method :take_legacy_route
|
|
74
|
-
|
|
75
|
-
# One self-contained check per closed receiver kind, plus a backstop.
|
|
76
|
-
def validate_route!(route, receiver)
|
|
77
|
-
case receiver
|
|
78
|
-
when nil then refuse_receiver(route)
|
|
79
|
-
when :aggregate then require_identity(route)
|
|
80
|
-
when :entity then require_entity_route(route)
|
|
81
|
-
else raise ArgumentError, "unknown receiver kind #{receiver.inspect}"
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
private_class_method :validate_route!
|
|
85
|
-
|
|
86
|
-
def refuse_receiver(route)
|
|
87
|
-
raise Runtime::TypeMismatch, "this command does not take a receiver in to:" unless route.nil?
|
|
88
|
-
end
|
|
89
|
-
private_class_method :refuse_receiver
|
|
90
|
-
|
|
91
|
-
def require_identity(route)
|
|
92
|
-
return unless route.nil? || route.to_s.empty? || route.is_a?(Hash)
|
|
93
|
-
|
|
94
|
-
raise Runtime::TypeMismatch, "to: must name the receiving aggregate identity"
|
|
95
|
-
end
|
|
96
|
-
private_class_method :require_identity
|
|
97
|
-
|
|
98
|
-
def require_entity_route(route)
|
|
99
|
-
raise Runtime::TypeMismatch, "to: for an entity command must contain aggregate: and entity:" unless route.is_a?(Hash)
|
|
100
|
-
|
|
101
|
-
extra = route.keys - [:aggregate, :entity]
|
|
102
|
-
missing = [:aggregate, :entity].select { |key| route[key].nil? || route[key].to_s.empty? }
|
|
103
|
-
return if extra.empty? && missing.empty?
|
|
104
|
-
|
|
105
|
-
raise Runtime::TypeMismatch, "to: for an entity command must contain only aggregate: and entity:"
|
|
106
|
-
end
|
|
107
|
-
private_class_method :require_entity_route
|
|
108
|
-
|
|
109
|
-
def symbolize(value)
|
|
110
|
-
case value
|
|
111
|
-
when Hash then value.to_h { |key, nested| [key.to_sym, symbolize(nested)] }
|
|
112
|
-
when Array then value.map { |nested| symbolize(nested) }
|
|
113
|
-
else value
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
private_class_method :symbolize
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|
data/lib/hecks/doors/handle.rb
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
require_relative "../naming"
|
|
2
|
-
require_relative "../runtime/caller"
|
|
3
|
-
require_relative "../ports/authorization"
|
|
4
|
-
|
|
5
|
-
module Hecks
|
|
6
|
-
module Doors
|
|
7
|
-
# A record in hand: what `Pizza.create_pizza!(...)` and `Pizza.find(id)`
|
|
8
|
-
# give back. One shared class per aggregate; verbs are per-handle singleton methods.
|
|
9
|
-
#
|
|
10
|
-
# Pizza.create_pizza!(...).add_topping!(...).purchase!(...)
|
|
11
|
-
class Handle
|
|
12
|
-
attr_reader :id
|
|
13
|
-
|
|
14
|
-
# @param dispatcher [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted
|
|
15
|
-
# dispatcher this record's verbs, `events` and `reload` go through
|
|
16
|
-
# @param domain [String] the owning chapter's name, the first half of `fqn`
|
|
17
|
-
# @param aggregate [Bluebook::Aggregate] the IR of the aggregate this record is one of
|
|
18
|
-
# @param instance [Runtime::Instance] the stored record; its `id` and `state` are
|
|
19
|
-
# read once here and the instance itself is not retained
|
|
20
|
-
def initialize(dispatcher:, domain:, aggregate:, instance:)
|
|
21
|
-
@dispatcher = dispatcher
|
|
22
|
-
@domain = domain
|
|
23
|
-
@ir = aggregate
|
|
24
|
-
@id = instance.id
|
|
25
|
-
@state = instance.state
|
|
26
|
-
define_reference_accessors
|
|
27
|
-
define_verb_methods
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Reads one field's raw stored value, without hydrating a reference the way the
|
|
31
|
-
# reference accessor of the same name does.
|
|
32
|
-
#
|
|
33
|
-
# @param key [Symbol, String] the attribute name
|
|
34
|
-
# @return [Object, nil] the value held in state (a scalar, a value object, a list,
|
|
35
|
-
# or a referenced record's id); `nil` when the field is unset or not in state
|
|
36
|
-
def [](key) = redacted(key.to_sym)
|
|
37
|
-
|
|
38
|
-
# Answers the record's state as a Hash, with `:id` merged in last so it
|
|
39
|
-
# always wins over a same-named `id` attribute (BurningManPrep::Item).
|
|
40
|
-
#
|
|
41
|
-
# @return [Hash{Symbol => Object}] every state field by attribute name, plus `:id`
|
|
42
|
-
def to_h = @state.to_h { |key, _| [key, redacted(key)] }.merge(id: @id)
|
|
43
|
-
|
|
44
|
-
# Names the aggregate this record belongs to, in the form every dispatch verb and
|
|
45
|
-
# event is addressed by.
|
|
46
|
-
#
|
|
47
|
-
# @return [String] the fully qualified aggregate name, such as `"Pizzas::Pizza"`
|
|
48
|
-
def fqn = "#{@domain}::#{@ir.hecks_name}"
|
|
49
|
-
|
|
50
|
-
# Lists the events this one record has emitted, filtered out of the dispatcher's
|
|
51
|
-
# whole event log on each call.
|
|
52
|
-
#
|
|
53
|
-
# @return [Array<Runtime::Event>] this record's events in the order the log holds
|
|
54
|
-
# them; `[]` when it has emitted none
|
|
55
|
-
def events
|
|
56
|
-
@dispatcher.events.select { |event| event.aggregate == fqn && event.id == @id }
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# Refreshes this handle's state from the repository, picking up writes made through
|
|
60
|
-
# another handle or door. Keeps the current state when the record is not found.
|
|
61
|
-
#
|
|
62
|
-
# @return [Doors::Handle] this handle, so the call chains
|
|
63
|
-
# @raise [Runtime::WiringError] if the aggregate's persistence bind cannot be
|
|
64
|
-
# resolved into a repository
|
|
65
|
-
def reload
|
|
66
|
-
stored = repository.find(@id)
|
|
67
|
-
@state = stored.state if stored
|
|
68
|
-
self
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Equality is (fqn, id): two handles to the same record are equal, and
|
|
72
|
-
# `other.is_a?(self.class)` can't tell aggregates apart since they share one class.
|
|
73
|
-
#
|
|
74
|
-
# @param other [Object] anything; only another `Handle` can be equal
|
|
75
|
-
# @return [Boolean] true when `other` is a `Handle` with the same `fqn` and `id`
|
|
76
|
-
def ==(other) = other.is_a?(Handle) && other.fqn == fqn && other.id == @id
|
|
77
|
-
alias eql? ==
|
|
78
|
-
def hash = [Handle, fqn, @id].hash
|
|
79
|
-
|
|
80
|
-
def inspect
|
|
81
|
-
fields = @state.map { |key, value| "#{key}=#{value.inspect}" }.join(" ")
|
|
82
|
-
"#<#{@ir.hecks_name} #{@id} #{fields}>"
|
|
83
|
-
end
|
|
84
|
-
alias to_s inspect
|
|
85
|
-
|
|
86
|
-
# Answers a field reader: `pizza.name` reads `name` out of state. A
|
|
87
|
-
# declared field not yet written arrives here too, as `nil`.
|
|
88
|
-
#
|
|
89
|
-
# @param name [Symbol] the method called, read as an attribute or lifecycle field name
|
|
90
|
-
# @param args [Array<Object>] ignored by a reader; passed on to `super` otherwise
|
|
91
|
-
# @param kwargs [Hash{Symbol => Object}] ignored by a reader; passed on to `super` otherwise
|
|
92
|
-
# @return [Object, nil] the field's value; `nil` when nothing is written yet
|
|
93
|
-
# @raise [NoMethodError] if `name` is neither a key in state nor a declared field
|
|
94
|
-
def method_missing(name, *args, **kwargs, &)
|
|
95
|
-
return redacted(name) if @state.key?(name) || reader?(name)
|
|
96
|
-
|
|
97
|
-
super
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def respond_to_missing?(name, include_private = false)
|
|
101
|
-
@state.key?(name) || reader?(name) || super
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
private
|
|
105
|
-
|
|
106
|
-
def repository = @dispatcher.registry.repository(@domain, @ir)
|
|
107
|
-
|
|
108
|
-
# Masks any Privacy::Marking leaf the caller isn't granted to read, and
|
|
109
|
-
# masks an unidentified caller outright (a leak is worse than a refusal
|
|
110
|
-
# commands allow). Nesting is masked one level deep only.
|
|
111
|
-
def redacted(field)
|
|
112
|
-
raw = @state[field]
|
|
113
|
-
marked_rows(field).each do |row|
|
|
114
|
-
raw = masked(raw, row) unless authorized_for?(row[:readable_by][:value].to_s)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
raw
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# The privacy markings that name `field` or a path beneath it.
|
|
121
|
-
def marked_rows(field)
|
|
122
|
-
marked_paths.select { |row| row[:attribute_path][:value].to_s.split(".", 2).first == field.to_s }
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# `raw` with the marked leaf masked: the whole value for a marked field, one nested leaf of a
|
|
126
|
-
# value object for a marked path beneath it.
|
|
127
|
-
def masked(raw, row)
|
|
128
|
-
segments = row[:attribute_path][:value].to_s.split(".", 2)
|
|
129
|
-
return "[redacted]" if segments.size == 1
|
|
130
|
-
|
|
131
|
-
raw.is_a?(Runtime::Value) ? raw.with(segments[1], "[redacted]") : raw
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
# Cached per handle so an unattached-Privacy domain never pays for a query
|
|
135
|
-
# dispatch on every read.
|
|
136
|
-
def marked_paths
|
|
137
|
-
return @marked_paths if defined?(@marked_paths)
|
|
138
|
-
return @marked_paths = [] unless @dispatcher.registry.bluebook("Privacy")
|
|
139
|
-
|
|
140
|
-
@marked_paths = @dispatcher.query("Privacy::Marking.ForDomain", domain: fqn)
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
# False outright for an unidentified caller or an unattached domain, never
|
|
144
|
-
# the weak fallback a command's own role check allows.
|
|
145
|
-
def authorized_for?(role)
|
|
146
|
-
caller = Runtime::Caller.current
|
|
147
|
-
return false unless caller&.actor_id
|
|
148
|
-
return false unless @dispatcher.registry.authorization_provider_for(@domain)
|
|
149
|
-
|
|
150
|
-
Ports::Authorization.holds_role?(@dispatcher.registry, actor_id: caller.actor_id, role: role,
|
|
151
|
-
as_of: caller.as_of, scope: caller.scope)
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
def reader?(name)
|
|
155
|
-
!@ir.attribute(name).nil? || @ir.lifecycle&.field&.to_sym == name
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
# Real singleton methods, not method_missing: a verb named `freeze` or
|
|
159
|
-
# `send` (both real, e.g. Account::Freeze, ExternalTransfer::Send) would
|
|
160
|
-
# otherwise silently hit the Kernel method instead of dispatching.
|
|
161
|
-
def define_verb_methods
|
|
162
|
-
@ir.commands.reject(&:creates?).each do |command|
|
|
163
|
-
define_singleton_method("#{Naming.snake(command.hecks_name)}!") do |**args|
|
|
164
|
-
run(command, **args)
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
# `@ir.identified_by` is only the single-head shorthand (nil for a
|
|
170
|
-
# composite identity, e.g. SafeDepositBox's branch_code/box_number);
|
|
171
|
-
# this reads every head through `identity_heads` instead.
|
|
172
|
-
def run(command, **args)
|
|
173
|
-
@state = @dispatcher.dispatch("#{fqn}.#{command.hecks_name}", to: @id, with: args).instance.state
|
|
174
|
-
self
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
# Lazy hop: `transfer.source_account` resolves to the actual record only
|
|
178
|
-
# when called; nothing loads until then, so chains like
|
|
179
|
-
# `payment.disputed_by_customer.name` stay lazy at every step.
|
|
180
|
-
#
|
|
181
|
-
# Defined before verb methods so a same-named verb wins the name on the
|
|
182
|
-
# rare collision; `initialize` calls this first for that reason.
|
|
183
|
-
#
|
|
184
|
-
# The accessor is named like the attribute itself, never `<name>_id`
|
|
185
|
-
# (ADR 0025) — `piece.account` and `piece[:account]` (bracket access,
|
|
186
|
-
# the raw id) never collide despite sharing a name.
|
|
187
|
-
def define_reference_accessors
|
|
188
|
-
@ir.attributes.select(&:reference?).each { |attribute| define_reference_accessor(attribute) }
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
# One lazy reader for a reference attribute.
|
|
192
|
-
def define_reference_accessor(attribute)
|
|
193
|
-
target = attribute.type.resolve
|
|
194
|
-
# Cross-domain, or otherwise unresolvable — no accessor rather than a guess.
|
|
195
|
-
return unless target
|
|
196
|
-
|
|
197
|
-
target_fqn = "#{@domain}::#{target.hecks_name}"
|
|
198
|
-
define_singleton_method(attribute.name) do
|
|
199
|
-
value = self[attribute.name]
|
|
200
|
-
door = Object.const_get(target_fqn)
|
|
201
|
-
next Array(value).map { |identity| door.find(identity) } if attribute.list?
|
|
202
|
-
|
|
203
|
-
value && door.find(value)
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
end
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
require "json"
|
|
2
|
-
require_relative "handle"
|
|
3
|
-
require_relative "command_request"
|
|
4
|
-
require_relative "../naming"
|
|
5
|
-
require_relative "../runtime/errors"
|
|
6
|
-
require_relative "../runtime/value"
|
|
7
|
-
|
|
8
|
-
module Hecks
|
|
9
|
-
module Doors
|
|
10
|
-
# The JSON door: translates URL segments and parsed JSON bodies to and from the facade.
|
|
11
|
-
# No HTTP lives here; every miss raises `Runtime::NotFound`, distinguished by message.
|
|
12
|
-
module JsonDoor
|
|
13
|
-
module_function
|
|
14
|
-
|
|
15
|
-
# Resolves a domain name and an aggregate name, as two URL segments carry them, to
|
|
16
|
-
# that aggregate's door.
|
|
17
|
-
#
|
|
18
|
-
# The name is checked against the current boot's IR before Ruby's constant table, so
|
|
19
|
-
# a stale same-named constant from an earlier boot is never returned.
|
|
20
|
-
#
|
|
21
|
-
# @param dispatcher [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted dispatcher
|
|
22
|
-
# @param domain [String, Symbol] the chapter name, such as `"Banking"`
|
|
23
|
-
# @param name [String, Symbol] the aggregate's declared name, such as `"Customer"`
|
|
24
|
-
# @return [Module] the aggregate door installed at `domain::name`
|
|
25
|
-
# @raise [Runtime::NotFound] if the chapter or its aggregate is not declared
|
|
26
|
-
# @raise [NameError] if the aggregate has no facade constant (`install_doors: false`)
|
|
27
|
-
def aggregate(dispatcher, domain, name)
|
|
28
|
-
ir = dispatcher.registry.bluebook(domain)&.aggregate(name)
|
|
29
|
-
raise Runtime::NotFound, "#{domain} declares no aggregate named #{name.inspect}" unless ir
|
|
30
|
-
|
|
31
|
-
Object.const_get("#{domain}::#{ir.hecks_name}")
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# Names the door method that creates a record of this aggregate: the first command
|
|
35
|
-
# it declares that `creates?`, spelled as a Ruby caller would (`"create_pizza!"`).
|
|
36
|
-
#
|
|
37
|
-
# @param klass [Module] an aggregate door, as `aggregate` returns
|
|
38
|
-
# @return [String] the method name to `public_send` to the door
|
|
39
|
-
# @raise [Runtime::NotFound] if the aggregate declares no creating command
|
|
40
|
-
def creating_command(klass)
|
|
41
|
-
creating = klass.ir.commands.find(&:creates?)
|
|
42
|
-
raise Runtime::NotFound, "#{klass.ir.hecks_name} declares no creating command" unless creating
|
|
43
|
-
|
|
44
|
-
"#{Naming.snake(creating.hecks_name)}!"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Confirms that a command name arriving as text is one a `Handle` of this aggregate
|
|
48
|
-
# answers, before a caller `public_send`s it.
|
|
49
|
-
#
|
|
50
|
-
# A `Handle` defines only the non-creating commands, so the creating command is
|
|
51
|
-
# rejected here rather than failing later as a raw `NoMethodError`.
|
|
52
|
-
#
|
|
53
|
-
# @param klass [Module] an aggregate door, as `aggregate` returns
|
|
54
|
-
# @param name [String, Symbol] the wanted method name with its bang, such as
|
|
55
|
-
# `"add_topping!"`
|
|
56
|
-
# @return [String] `name` as a String, unchanged, when a `Handle` answers it
|
|
57
|
-
# @raise [Runtime::NotFound] if no non-creating command has that method name
|
|
58
|
-
def validate_command!(klass, name)
|
|
59
|
-
wanted = name.to_s
|
|
60
|
-
dispatchable = klass.ir.commands.reject(&:creates?).map { |command| "#{Naming.snake(command.hecks_name)}!" }
|
|
61
|
-
return wanted if dispatchable.include?(wanted)
|
|
62
|
-
|
|
63
|
-
raise Runtime::NotFound, "#{klass.ir.hecks_name} declares no command named #{wanted.inspect}"
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Fetches one record by id, raising instead of answering nil on a miss.
|
|
67
|
-
#
|
|
68
|
-
# @param klass [Module] an aggregate door, as `aggregate` returns
|
|
69
|
-
# @param id [String] the record's identity, as the URL carried it
|
|
70
|
-
# @return [Doors::Handle] the record in hand
|
|
71
|
-
# @raise [Runtime::NotFound] if the repository holds no record with that id
|
|
72
|
-
def find!(klass, id)
|
|
73
|
-
klass.find(id) or raise Runtime::NotFound, "no #{klass.ir.hecks_name} found for id #{id.inspect}"
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# Converts every Hash key to a Symbol, at every depth of a parsed JSON body.
|
|
77
|
-
#
|
|
78
|
-
# @param value [Hash, Array, Object] parsed JSON: a Hash or Array is walked, any
|
|
79
|
-
# other value is a leaf
|
|
80
|
-
# @return [Hash{Symbol => Object}, Array, Object] a new structure of the same shape
|
|
81
|
-
# with Symbol keys; a leaf is returned as it came
|
|
82
|
-
def deep_symbolize(value)
|
|
83
|
-
case value
|
|
84
|
-
when Hash then value.to_h { |k, v| [k.to_sym, deep_symbolize(v)] }
|
|
85
|
-
when Array then value.map { |item| deep_symbolize(item) }
|
|
86
|
-
else value
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# Unwraps a record, a query row, or any value holding `Runtime::Value`s into plain
|
|
91
|
-
# Hashes, Arrays and scalars a JSON encoder can walk.
|
|
92
|
-
#
|
|
93
|
-
# Delegates to `Runtime::Value.materialize`; the only addition is `#to_h` on a
|
|
94
|
-
# `Handle`, which `materialize` does not recognize.
|
|
95
|
-
#
|
|
96
|
-
# @param value [Doors::Handle, Runtime::Value, Hash, Array, Object] what to unwrap;
|
|
97
|
-
# a `Handle` is read through its `to_h`, so its `:id` comes along
|
|
98
|
-
# @return [Hash, Array, Object] the same data with every `Runtime::Value` replaced
|
|
99
|
-
# by a Hash of its fields; any other value is returned as it came
|
|
100
|
-
def materialize(value)
|
|
101
|
-
value = value.to_h if value.is_a?(Handle)
|
|
102
|
-
Runtime::Value.materialize(value)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# Turns a command's JSON body, raw or already parsed, into the `to:`/`with:`
|
|
106
|
-
# envelope a dispatcher takes. The result splats into `Dispatcher#dispatch`.
|
|
107
|
-
#
|
|
108
|
-
# @param body [String, Hash] raw JSON text, or the Hash it parses to
|
|
109
|
-
# @param receiver [Symbol, nil] `:aggregate`, `:entity`, or `nil` for none
|
|
110
|
-
# (see `CommandRequest.normalize`)
|
|
111
|
-
# @param legacy_receiver [Symbol, String, Hash{Symbol => Symbol, String}, nil] the flat key,
|
|
112
|
-
# or pair of keys, a body without `to` may name its receiver under; `nil` accepts none
|
|
113
|
-
# @return [Hash{Symbol => Object}] `{ with: facts }`, plus `to:` unless `receiver` is `nil`
|
|
114
|
-
# @raise [JSON::ParserError] if `body` is a String that is not valid JSON
|
|
115
|
-
# @raise [Runtime::TypeMismatch] if the body is not a JSON object or its routing is malformed
|
|
116
|
-
# @raise [ArgumentError] if `receiver` is not `nil`, `:aggregate` or `:entity`
|
|
117
|
-
def command_request(body, receiver:, legacy_receiver: nil)
|
|
118
|
-
input = body.is_a?(String) ? parse(body) : body
|
|
119
|
-
CommandRequest.normalize(input, receiver: receiver, legacy_receiver: legacy_receiver)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# Parses a raw request body, leaving keys as Strings. `JSON::ParserError` propagates
|
|
123
|
-
# unwrapped.
|
|
124
|
-
#
|
|
125
|
-
# @param raw_json [String] JSON text, such as a POST body
|
|
126
|
-
# @return [Hash{String => Object}, Array, String, Numeric, Boolean, nil] whatever
|
|
127
|
-
# the text encodes
|
|
128
|
-
# @raise [JSON::ParserError] if the text is not valid JSON
|
|
129
|
-
def parse(raw_json) = JSON.parse(raw_json)
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|