@githolon/dsl 0.108.7 → 0.110.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.
- package/assets/operation-contract.wasm +0 -0
- package/check_package.mjs +12 -15
- package/compile_package.mjs +17 -18
- package/compile_proof.mjs +16 -1
- package/dart/CHANGELOG.md +76 -1
- package/dart/README.md +25 -2
- package/dart/lib/src/admission_decision.dart +41 -0
- package/dart/lib/src/application_framework_calls.dart +52 -2
- package/dart/lib/src/application_model_adoption.dart +187 -0
- package/dart/lib/src/application_status.dart +73 -0
- package/dart/lib/src/console_enrolment.dart +271 -0
- package/dart/lib/src/console_http_io.dart +26 -0
- package/dart/lib/src/console_http_stub.dart +7 -0
- package/dart/lib/src/dev_cloud.dart +69 -22
- package/dart/lib/src/generated_call.dart +83 -23
- package/dart/lib/src/kernel_primitives.dart +119 -0
- package/dart/lib/src/nms_conformance_runtime.dart +1 -1
- package/dart/lib/src/nms_generated_runtime.dart +32 -10
- package/dart/lib/src/nms_test_environment.dart +1 -1
- package/dart/lib/src/node_runner_transport.dart +41 -46
- package/dart/lib/src/observed_session_directory.dart +70 -0
- package/dart/lib/src/operation_receipts.dart +112 -0
- package/dart/lib/src/peer_application_streams.dart +103 -0
- package/dart/lib/src/reception/dart_reception.dart +4280 -0
- package/dart/lib/src/reception/event_desk.dart +211 -0
- package/dart/lib/src/reception/extremum_read.dart +46 -0
- package/dart/lib/src/reception/local_copies.dart +371 -0
- package/dart/lib/src/reception/peer_office_connection.dart +11 -0
- package/dart/lib/src/reception/progress_desk.dart +267 -0
- package/dart/lib/src/reception/reception_contract.dart +11 -0
- package/dart/lib/src/reception/reception_session.dart +284 -0
- package/dart/lib/src/reception/sync_diagnostics.dart +26 -0
- package/dart/lib/src/reception/workspace_preparation_report.dart +126 -0
- package/dart/lib/src/replica_readiness.dart +123 -0
- package/dart/lib/src/runner/node-entry.mjs +23905 -15774
- package/dart/lib/src/runtime_v2_gateway.dart +56 -3
- package/dart/lib/src/runtime_v2_transport.dart +544 -3
- package/dart/lib/src/session_bound.dart +200 -311
- package/dart/lib/src/signing_identity_kernel.dart +84 -0
- package/dart/lib/src/sync_status_projection.dart +548 -0
- package/dart/lib/src/sync_status_reducer.dart +170 -0
- package/dart/lib/src/test_harness.dart +809 -1153
- package/dart/lib/src/testing/test_custody.dart +66 -0
- package/dart/lib/src/testing/test_peer.dart +328 -0
- package/dart/lib/src/typed_watch_registry.dart +169 -0
- package/dart/lib/src/workspace_open_progress.dart +27 -0
- package/dart/pubspec.lock +24 -1
- package/dart/pubspec.yaml +7 -2
- package/dart/pubspec_overrides.yaml +2 -0
- package/dart/test/admission_decision_test.dart +48 -0
- package/dart/test/background_model_adoption_test.dart +228 -0
- package/dart/test/bundle_version_pairing_test.dart +4 -4
- package/dart/test/child_authentication_repair_test.dart +359 -0
- package/dart/test/cloud_bound_local_shell_test.dart +119 -0
- package/dart/test/console_enrolment_refusal_test.dart +52 -0
- package/dart/test/console_enrolment_test.dart +227 -0
- package/dart/test/errors_test.dart +5 -5
- package/dart/test/event_plane_seam_test.dart +50 -164
- package/dart/test/extremum_read_test.dart +58 -0
- package/dart/test/fixtures/wedge/wedge-entry.mjs +3 -21
- package/dart/test/generated_query_test.dart +32 -0
- package/dart/test/harness_phase_timeout_test.dart +18 -23
- package/dart/test/kernel_author_after_read_test.dart +242 -0
- package/dart/test/kernel_fence_test.dart +137 -0
- package/dart/test/local_copies_test.dart +222 -0
- package/dart/test/model_adoption_test.dart +198 -0
- package/dart/test/node_peer_local_custody_test.dart +153 -0
- package/dart/test/offer_authentication_proof_test.dart +352 -52
- package/dart/test/operation_compatibility_test.dart +151 -0
- package/dart/test/platform_credential_effect_test.dart +386 -0
- package/dart/test/receiving_group_open_test.dart +213 -0
- package/dart/test/reception/workspace_preparation_report_test.dart +103 -0
- package/dart/test/reception_span_trace_test.dart +23 -0
- package/dart/test/replica_readiness_test.dart +156 -0
- package/dart/test/runtime_projections_test.dart +92 -0
- package/dart/test/runtime_v2_gateway_test.dart +131 -0
- package/dart/test/signing_identity_kernel_test.dart +75 -0
- package/dart/test/sync_status_preparation_report_test.dart +29 -0
- package/dart/test/sync_status_reducer_test.dart +419 -0
- package/dart/test/test_harness_test.dart +71 -95
- package/dart/test/typed_query_watch_test.dart +170 -0
- package/dart/test/typed_watch_registry_test.dart +249 -0
- package/dart_lints/README.md +18 -0
- package/dart_lints/lib/nomos_lints.dart +70 -0
- package/dart_lints/pubspec.lock +580 -0
- package/dart_lints/pubspec.yaml +12 -0
- package/dart_lints/test/reference_identity_test.dart +75 -0
- package/dart_types/CHANGELOG.md +18 -0
- package/dart_types/lib/nomos_kernel_protocol.dart +21 -1
- package/dart_types/lib/nomos_types.dart +9 -1
- package/dart_types/lib/src/admission_decision.dart +37 -0
- package/dart_types/lib/src/aggregate_meta.dart +1 -1
- package/dart_types/lib/src/approved_model.dart +65 -0
- package/dart_types/lib/src/custody.dart +10 -18
- package/dart_types/lib/src/error_info.dart +4 -4
- package/dart_types/lib/src/errors.dart +29 -29
- package/dart_types/lib/src/foreign_ref.dart +62 -33
- package/dart_types/lib/src/local_work_rejected.dart +3 -3
- package/dart_types/lib/src/nomos_ref.dart +3 -1
- package/dart_types/lib/src/principal.dart +2 -2
- package/dart_types/lib/src/proto/google/protobuf/any.pb.dart +163 -0
- package/dart_types/lib/src/proto/google/protobuf/any.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pb.dart +137 -0
- package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +20721 -10433
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +555 -27
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +387 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pbenum.dart +46 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pb.dart +295 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pbenum.dart +139 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pb.dart +269 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pbenum.dart +103 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pb.dart +417 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pbenum.dart +62 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +9968 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +133 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pb.dart +204 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pbenum.dart +54 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pb.dart +1550 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pb.dart +710 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pb.dart +845 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pb.dart +198 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pb.dart +369 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pb.dart +609 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pbenum.dart +65 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +358 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pbenum.dart +100 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +2231 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +271 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pb.dart +1286 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +636 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pbenum.dart +116 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +1637 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pbenum.dart +175 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pb.dart +1269 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pbenum.dart +129 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +2782 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pbenum.dart +97 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +2232 -8627
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +0 -358
- package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pb.dart +1639 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pbenum.dart +46 -0
- package/dart_types/lib/src/runtime_outcome.dart +133 -0
- package/dart_types/lib/src/subscriptions.dart +116 -23
- package/dart_types/pubspec.yaml +1 -1
- package/dart_types/test/extremum_subscriptions_test.dart +40 -0
- package/dart_types/test/foreign_ref_resolution_test.dart +75 -0
- package/dart_types/test/nomos_ref_address_test.dart +25 -0
- package/dart_types/test/ordered_subscriptions_test.dart +34 -0
- package/operation_contract_check.mjs +24 -0
- package/package.json +11 -6
- package/src/aggregate.ts +70 -10
- package/src/application_topology.ts +18 -11
- package/src/attested.ts +3 -0
- package/src/attested_core.ts +46 -3
- package/src/birth_meter_ensure.ts +19 -7
- package/src/births.ts +29 -4
- package/src/build_package.ts +140 -13
- package/src/business_birth.ts +181 -4
- package/src/codegen_call_proto.ts +1274 -0
- package/src/codegen_call_usda.ts +49 -6
- package/src/codegen_dart.ts +79 -44
- package/src/codegen_dart_client.ts +458 -800
- package/src/{codegen_dart_application.ts → codegen_dart_facade.ts} +331 -582
- package/src/codegen_dart_framework_calls.ts +320 -37
- package/src/codegen_dart_indexed_variant.ts +159 -0
- package/src/codegen_dart_scenario.ts +42 -13
- package/src/codegen_proof.ts +3 -3
- package/src/codegen_provider_dart.ts +5 -0
- package/src/codegen_query_proto.ts +158 -0
- package/src/codegen_refusal.ts +189 -0
- package/src/codegen_result_proto.ts +931 -0
- package/src/codegen_result_usda.ts +4 -0
- package/src/codegen_ts.ts +464 -616
- package/src/codegen_workspace_access.ts +105 -0
- package/src/compatibility_graph.ts +759 -0
- package/src/compatibility_usda.ts +264 -0
- package/src/compile_package_main.ts +1994 -1189
- package/src/custody_placement.ts +156 -0
- package/src/custody_placement_usda.ts +91 -0
- package/src/decl_shapes.ts +21 -2
- package/src/describe_model.ts +1 -0
- package/src/directive.ts +59 -2
- package/src/drivers.ts +51 -0
- package/src/engine_entry.ts +52 -8
- package/src/evolve_preview.ts +11 -4
- package/src/exists.ts +2 -0
- package/src/fields.ts +75 -11
- package/src/flow_gate.ts +2 -1
- package/src/framework/application_home.ts +170 -18
- package/src/framework/attested_receipts.ts +8 -3
- package/src/framework/auth_provider_law.ts +169 -9
- package/src/framework/birth_certificate_law.ts +4 -0
- package/src/framework/capability.ts +34 -3
- package/src/framework/child_authentication.ts +346 -0
- package/src/framework/console_governance.ts +295 -0
- package/src/framework/delegated_roles.ts +301 -0
- package/src/framework/domain_lifecycle.ts +26 -13
- package/src/framework/founding_genesis.ts +193 -0
- package/src/framework/framework_aggregates.ts +1 -1
- package/src/framework/genesis.ts +6 -1
- package/src/framework/governance_relations.ts +19 -0
- package/src/framework/home.ts +5 -734
- package/src/framework/legacy/child_auth_provider_epoch.ts +73 -0
- package/src/framework/model_authority_repair.ts +116 -0
- package/src/framework/model_authority_seed.ts +185 -0
- package/src/framework/model_transition.ts +211 -0
- package/src/framework/owned_custody.ts +1 -1
- package/src/framework/principal_enrollment.ts +302 -0
- package/src/framework/receiving_group.ts +857 -0
- package/src/framework/receiving_group_recovery.ts +314 -0
- package/src/framework/relations.ts +4 -8
- package/src/framework/signing_identity.ts +242 -95
- package/src/framework/source_roster.ts +11 -5
- package/src/framework/workspace_access.ts +149 -0
- package/src/framework/workspace_invariant.ts +73 -52
- package/src/framework/workspaces.ts +407 -40
- package/src/framework_call_definitions.ts +32 -3
- package/src/generated_client_bundle_boundary.ts +97 -0
- package/src/generated_client_names.ts +1 -0
- package/src/identity_usda.ts +27 -0
- package/src/index.ts +183 -12
- package/src/indexed_variant.ts +83 -0
- package/src/intent.ts +173 -45
- package/src/law_check.ts +8 -5
- package/src/law_dependency_index.ts +231 -0
- package/src/law_graph.ts +508 -71
- package/src/law_graph_usda.ts +170 -24
- package/src/law_identity.ts +119 -81
- package/src/law_source_map.ts +4 -1
- package/src/law_units.ts +498 -0
- package/src/law_value_type.ts +7 -3
- package/src/member_authentication.ts +302 -0
- package/src/null_meta.ts +1 -1
- package/src/openusd_compiled_layer.ts +132 -0
- package/src/operation_contract_check.ts +31 -0
- package/src/ordered_read.ts +2 -1
- package/src/package_config.ts +33 -12
- package/src/package_dependencies.ts +1 -0
- package/src/plan_source_slice.ts +30 -1
- package/src/protobuf_field_number.ts +36 -0
- package/src/provenance_wire.ts +6 -0
- package/src/query.ts +2 -1
- package/src/read.ts +50 -0
- package/src/relation.ts +4 -1
- package/src/relation_schema.ts +15 -2
- package/src/report.ts +2 -2
- package/src/sqlite_computation_bundle.ts +78 -0
- package/src/sqlite_computed.ts +102 -0
- package/src/sqlite_counts.ts +154 -0
- package/src/sqlite_layout.ts +823 -0
- package/src/sqlite_reads.ts +275 -0
- package/src/sqlite_samples.ts +185 -0
- package/src/stable_id_identity_bridge.ts +1 -1
- package/src/stable_ids_for_module.ts +16 -4
- package/src/test_call_usda.ts +6 -6
- package/src/usda_relationship_integrity.ts +20 -3
- package/src/usda_text.ts +21 -1
- package/src/value_object.ts +81 -11
- package/src/wire.ts +22 -0
- package/src/wire_encode.ts +227 -20
- package/src/workspace_sharding.ts +15 -6
- package/src/workspace_sharing.ts +51 -49
- package/src/zod_introspection.ts +2 -0
- package/compat_package.mjs +0 -46
- package/dart/lib/src/home.dart +0 -15
- package/dart/lib/src/runner/offline-install.mjs +0 -15367
- package/dart/lib/src/source_trust.dart +0 -51
- package/dart/lib/src/webview_bridge.dart +0 -6540
- package/dart/lib/src/workspace_name.dart +0 -30
- package/dart/test/acquire_session_credentials_test.dart +0 -150
- package/dart/test/acquire_session_test.dart +0 -534
- package/dart/test/adv_realm_interference_test.dart +0 -600
- package/dart/test/cloud_bound_topology_test.dart +0 -168
- package/dart/test/cluster_births_test.dart +0 -202
- package/dart/test/cluster_device_keyed_acceptance_test.dart +0 -105
- package/dart/test/cluster_local_autosync_test.dart +0 -123
- package/dart/test/cluster_scale_test.dart +0 -122
- package/dart/test/compat_test.dart +0 -61
- package/dart/test/dlq_session_surface_test.dart +0 -222
- package/dart/test/first_app_gauntlet_test.dart +0 -386
- package/dart/test/fixtures/wedge/fake-install.mjs +0 -11
- package/dart/test/four_layer_nested_topology_test.dart +0 -290
- package/dart/test/home_parity_test.dart +0 -13
- package/dart/test/local_sync_inert_test.dart +0 -107
- package/dart/test/node_runner_transport_test.dart +0 -78
- package/dart/test/parent_signer_recovery_test.dart +0 -155
- package/dart/test/residency_refusal_test.dart +0 -49
- package/dart/test/sealing_client_test.dart +0 -181
- package/dart/test/session_bound_test.dart +0 -285
- package/dart/test/stale_bundle_test.dart +0 -80
- package/dart/test/vo_read_typing_test.dart +0 -131
- package/dart/test/watch_after_offer_stall_test.dart +0 -100
- package/dart/test/webview_bridge_test.dart +0 -1930
- package/dart/test/workspace_name_test.dart +0 -24
- package/runtime/generated-application-host.js +0 -22860
- package/src/codegen_query_usda.ts +0 -214
- package/src/compat_manifest.ts +0 -26
- package/src/compat_package_main.ts +0 -224
- package/src/shape_compat.ts +0 -352
- package/src/usd_state.ts +0 -505
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dartRefusalDecoders } from "./codegen_refusal.js";
|
|
1
2
|
// NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
|
|
2
3
|
// remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
|
|
3
4
|
// wasm32-wasip1 artifact {kernel · projection · embedded QuickJS engine}.
|
|
@@ -8,25 +9,26 @@
|
|
|
8
9
|
*
|
|
9
10
|
* `codegen_dart.ts` emits the per-domain TYPES: read-model classes (`…ReadModel.fromProjected`),
|
|
10
11
|
* typed action inputs (`…Input` publicly; private directives retain `…Payload`), typed ids and enums. Until this file a Flutter app
|
|
11
|
-
* still hand-typed directive ids + query ids against
|
|
12
|
+
* still hand-typed directive ids + query ids against a raw runtime surface (string + Map). This closes
|
|
12
13
|
* that: ONE generated `<name>.client.dart` per domain, emitted by `nomos-compile` AFTER the package is
|
|
13
14
|
* hashed (the deployed law's content hash baked in), carrying a `<Domain>Client` over a connected
|
|
14
|
-
* [
|
|
15
|
+
* a connected [NomosSession] with:
|
|
15
16
|
*
|
|
16
17
|
* * a typed OFFER method per directive — takes the generated input/implementation DTO, serialises via its
|
|
17
18
|
* canonical USDA, auto-stamps omitted `…At` timestamps (the same caller-clock sugar the TS
|
|
18
19
|
* client applies), returns the new local head;
|
|
19
20
|
* * a typed declared-QUERY accessor per `query(...)` — one-shot `Future<List<…ReadModel>>` + a
|
|
20
|
-
* reactive `watch…` `Stream<List<…ReadModel>>`, parsed off the
|
|
21
|
+
* reactive `watch…` `Stream<List<…ReadModel>>`, parsed off the session's `{type,id,data}` rows;
|
|
21
22
|
* * by-id read/watch + a type-index `list…` per aggregate;
|
|
22
23
|
* * typed O(1) count/sum accessors.
|
|
23
24
|
*
|
|
24
25
|
* It IMPORTS the sibling `<name>.dart` (for the read-model + input classes) and either the vendored
|
|
25
|
-
* `nomos_client.dart` barrel or the package `nomos_client` barrel (for `
|
|
26
|
+
* `nomos_client.dart` barrel or the package `nomos_client` barrel (for `NomosSession`). NO manifest/hash impact —
|
|
26
27
|
* pure frontend codegen, exactly like `codegen_dart.ts`. NO FALLBACK: an unsupported shape throws at compile
|
|
27
28
|
* time.
|
|
28
29
|
*/
|
|
29
30
|
import type { z } from "zod";
|
|
31
|
+
import { MemberAuthenticationKind } from "./member_authentication.js";
|
|
30
32
|
|
|
31
33
|
import {
|
|
32
34
|
BUSINESS_BIRTH_SEED_PAYLOAD_FIELD,
|
|
@@ -65,18 +67,23 @@ import {
|
|
|
65
67
|
type AggFieldSpec,
|
|
66
68
|
type PayloadFieldSpec,
|
|
67
69
|
} from "./codegen_dart.js";
|
|
68
|
-
import type { LawGraph } from "./law_graph.js";
|
|
70
|
+
import type { LawGraph, LawRowReadNode } from "./law_graph.js";
|
|
69
71
|
import {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
DART_CALL_PROTO_PRELUDE,
|
|
73
|
+
emitDartCallProtoEncoder,
|
|
74
|
+
publishingIntentOf,
|
|
75
|
+
type DartCallProtoFieldAccess,
|
|
76
|
+
} from "./codegen_call_proto.js";
|
|
77
|
+
import { DART_CALL_USDA_PRELUDE } from "./codegen_call_usda.js";
|
|
74
78
|
import {
|
|
75
|
-
|
|
79
|
+
emitDartQueryProtoEncoder,
|
|
76
80
|
type QueryScalarKind,
|
|
77
|
-
} from "./
|
|
81
|
+
} from "./codegen_query_proto.js";
|
|
82
|
+
import { emitDartQueryResultProtoDecoder } from "./codegen_result_proto.js";
|
|
78
83
|
import { finishCount } from "./count.js";
|
|
79
84
|
import { finishSum } from "./sum.js";
|
|
85
|
+
import { finishExtremum } from "./extremum.js";
|
|
86
|
+
import { finishExists } from "./exists.js";
|
|
80
87
|
import {
|
|
81
88
|
autoStampFields,
|
|
82
89
|
domainEncryptionMap,
|
|
@@ -87,13 +94,12 @@ import {
|
|
|
87
94
|
isNamespacedAggregate,
|
|
88
95
|
qualifyReadProjectionType,
|
|
89
96
|
} from "./read_projection_namespace.js";
|
|
90
|
-
import {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
} from "./intent.js";
|
|
94
|
-
import { publicClientInterface, type DomainInterface } from "./shape_compat.js";
|
|
97
|
+
import { isBusinessIntent } from "./intent.js";
|
|
98
|
+
import { publicClientInterface, type DomainInterface } from "./compatibility_graph.js";
|
|
99
|
+
import { emitApplicationCompatibilityUsda } from "./compatibility_usda.js";
|
|
95
100
|
import { BUSINESS_CORRECTION_DIRECTIVE } from "./framework/business_corrections.js";
|
|
96
101
|
import { deriveDirectiveRecordTarget } from "./workspace_routing.js";
|
|
102
|
+
import { voMetaOf } from "./value_object.js";
|
|
97
103
|
import {
|
|
98
104
|
buildNomosDescribeModel,
|
|
99
105
|
type NomosDescribeModel,
|
|
@@ -113,16 +119,74 @@ const camel = (s: string) =>
|
|
|
113
119
|
const lcFirst = (s: string) =>
|
|
114
120
|
s.length ? s[0]!.toLowerCase() + s.slice(1) : s;
|
|
115
121
|
|
|
116
|
-
|
|
117
|
-
directiveId: string
|
|
118
|
-
): string => `nmsInternal${cap(camel(directiveId))}`;
|
|
122
|
+
type AnyDirective = Directive<unknown>;
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
interface DartClientOperationSelection {
|
|
125
|
+
readonly publicDirectives: readonly AnyDirective[];
|
|
126
|
+
readonly sourceTrustViaIds: ReadonlySet<string>;
|
|
127
|
+
readonly sourceTrustDirectives: readonly AnyDirective[];
|
|
128
|
+
readonly encoderDirectives: readonly AnyDirective[];
|
|
129
|
+
}
|
|
123
130
|
|
|
124
|
-
|
|
125
|
-
|
|
131
|
+
/**
|
|
132
|
+
* The exact operation surface for which the generated Dart session emits
|
|
133
|
+
* Protobuf encoders. Keeping this selection beside the encoder prevents the
|
|
134
|
+
* package compiler from independently guessing that every internal law
|
|
135
|
+
* directive is a client call.
|
|
136
|
+
*/
|
|
137
|
+
function dartClientOperationSelection(
|
|
138
|
+
mod: DomainModule,
|
|
139
|
+
graph: LawGraph,
|
|
140
|
+
): DartClientOperationSelection {
|
|
141
|
+
const authoredDirectives = mod.directives as AnyDirective[];
|
|
142
|
+
const publicDirectives = (mod.applicationIntents ?? mod.directives).filter(
|
|
143
|
+
(directive): directive is AnyDirective =>
|
|
144
|
+
directive !== undefined &&
|
|
145
|
+
typeof directive.id === "string" &&
|
|
146
|
+
typeof (directive as { payloadSchema?: unknown }).payloadSchema === "object" &&
|
|
147
|
+
(directive as { businessBirthInternal?: unknown }).businessBirthInternal !== true &&
|
|
148
|
+
// A directive the law offers only THROUGH a business intent is not a second client call.
|
|
149
|
+
publishingIntentOf(graph, mod.domain ?? mod.name, directive.id) === undefined,
|
|
150
|
+
);
|
|
151
|
+
const sourceTrustViaIds = new Set(
|
|
152
|
+
publicDirectives.flatMap((directive) =>
|
|
153
|
+
directive.businessSourceTrust === undefined
|
|
154
|
+
? []
|
|
155
|
+
: [directive.businessSourceTrust.viaDirectiveId],
|
|
156
|
+
),
|
|
157
|
+
);
|
|
158
|
+
const sourceTrustDirectives = authoredDirectives.filter((directive) =>
|
|
159
|
+
sourceTrustViaIds.has(directive.id),
|
|
160
|
+
);
|
|
161
|
+
for (const viaDirectiveId of sourceTrustViaIds) {
|
|
162
|
+
if (!sourceTrustDirectives.some((directive) => directive.id === viaDirectiveId)) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Dart source-trust codegen: '${mod.domain ?? mod.name}' has no hidden directive '${viaDirectiveId}'`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
publicDirectives,
|
|
170
|
+
sourceTrustViaIds,
|
|
171
|
+
sourceTrustDirectives,
|
|
172
|
+
encoderDirectives: [
|
|
173
|
+
...new Map(
|
|
174
|
+
[...publicDirectives, ...sourceTrustDirectives]
|
|
175
|
+
.map((directive) => [directive.id, directive] as const),
|
|
176
|
+
).values(),
|
|
177
|
+
],
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Exact private/public directive ids consumed by Dart operation codegen. */
|
|
182
|
+
export function dartBridgeClientOperationDirectiveIds(
|
|
183
|
+
mod: DomainModule,
|
|
184
|
+
graph: LawGraph,
|
|
185
|
+
): readonly string[] {
|
|
186
|
+
return dartClientOperationSelection(mod, graph).encoderDirectives.map(
|
|
187
|
+
(directive) => directive.id,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
126
190
|
|
|
127
191
|
/** Dart reserved words that can't be method names — suffixed `_` if one slips through. */
|
|
128
192
|
const DART_RESERVED = new Set([
|
|
@@ -175,13 +239,9 @@ export const dartInternalSourceTrustMethod = (directiveId: string): string =>
|
|
|
175
239
|
export const dartHashConstName = (fileBase: string): string =>
|
|
176
240
|
`${lcFirst(camel(fileBase))}DomainHash`;
|
|
177
241
|
|
|
178
|
-
/** `todo-nomos` → `
|
|
242
|
+
/** `todo-nomos` → `todoNomosInterface` — the generated structural contract (#72). */
|
|
179
243
|
export const interfaceConstNameDart = (fileBase: string): string =>
|
|
180
|
-
`${lcFirst(camel(fileBase))}
|
|
181
|
-
|
|
182
|
-
/** `todo-nomos` → `todoNomosCompatJson` — the baked client/law compat manifest JSON const (§5). */
|
|
183
|
-
export const compatConstNameDart = (fileBase: string): string =>
|
|
184
|
-
`${lcFirst(camel(fileBase))}CompatJson`;
|
|
244
|
+
`${lcFirst(camel(fileBase))}Interface`;
|
|
185
245
|
|
|
186
246
|
/** Emit a Dart RAW triple-quoted string literal of an object's JSON (the interface is JSON-only
|
|
187
247
|
* data — no `'`/`$`/backslash escaping concerns under `r'''…'''`; JSON never contains `'''`). */
|
|
@@ -189,9 +249,48 @@ function dartRawJson(value: unknown): string {
|
|
|
189
249
|
return `r'''${JSON.stringify(value)}'''`;
|
|
190
250
|
}
|
|
191
251
|
|
|
252
|
+
function dartRawText(value: string): string {
|
|
253
|
+
if (value.includes("'''")) {
|
|
254
|
+
throw new Error("generated Dart raw text contains its triple-quote delimiter");
|
|
255
|
+
}
|
|
256
|
+
return `r'''${value}'''`;
|
|
257
|
+
}
|
|
258
|
+
|
|
192
259
|
const dartStr = (s: string) =>
|
|
193
260
|
`'${s.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
194
261
|
|
|
262
|
+
const dartInterfaceSet = (
|
|
263
|
+
domainKey: string,
|
|
264
|
+
value: DomainInterface,
|
|
265
|
+
): string => {
|
|
266
|
+
const directives = Object.entries(value.directives ?? {})
|
|
267
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
268
|
+
.map(([id, directive]) => {
|
|
269
|
+
const fields = Object.entries(directive.fields ?? {})
|
|
270
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
271
|
+
.map(([name, field]) =>
|
|
272
|
+
`InterfacePayloadField(name: ${dartStr(name)}, kind: ${dartStr(field.kind)}, optional: ${field.optional === true})`
|
|
273
|
+
);
|
|
274
|
+
return `InterfaceDirective(id: ${dartStr(id)}, fields: [${fields.join(", ")}])`;
|
|
275
|
+
});
|
|
276
|
+
const aggregates = Object.entries(value.aggregates ?? {})
|
|
277
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
278
|
+
.map(([sid, aggregate]) => {
|
|
279
|
+
const fields = Object.entries(aggregate.fields ?? {})
|
|
280
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
281
|
+
.map(([fieldSid, field]) =>
|
|
282
|
+
`InterfaceAggregateField(sid: ${dartStr(fieldSid)}, kind: ${dartStr(field.kind)}, label: ${dartStr(field.label ?? fieldSid)})`
|
|
283
|
+
);
|
|
284
|
+
return `InterfaceAggregate(sid: ${dartStr(aggregate.sid ?? sid)}, label: ${dartStr(aggregate.label ?? sid)}, fields: [${fields.join(", ")}])`;
|
|
285
|
+
});
|
|
286
|
+
const foreignReads = Object.entries(value.foreignReads ?? {})
|
|
287
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
288
|
+
.flatMap(([directive, reads]) => reads.map((read) =>
|
|
289
|
+
`InterfaceForeignRead(directive: ${dartStr(directive)}, queryId: ${dartStr(read.queryId)}${read.from === undefined ? "" : `, source: ${dartStr(read.from)}`}${read.policy === undefined ? "" : `, policy: ${dartStr(read.policy)}`}${read.fromPayload === undefined ? "" : `, sourcePayloadField: ${dartStr(read.fromPayload)}`})`
|
|
290
|
+
));
|
|
291
|
+
return `InterfaceSet(domains: [DomainInterface(formatVersion: ${value.v ?? 0}, domain: ${dartStr(value.domain ?? domainKey)}${value.domainSid === undefined ? "" : `, domainSid: ${dartStr(value.domainSid)}`}, directives: [${directives.join(", ")}], aggregates: [${aggregates.join(", ")}], foreignReads: [${foreignReads.join(", ")}])])`;
|
|
292
|
+
};
|
|
293
|
+
|
|
195
294
|
const dartSealedValueName = (field: string): string =>
|
|
196
295
|
`nmsInternalSealed${cap(camel(field))}`;
|
|
197
296
|
|
|
@@ -201,11 +300,11 @@ const dartSealKeyName = (field: string): string =>
|
|
|
201
300
|
/** A schema-specific Dart expression for one public payload field. The USDA
|
|
202
301
|
* encoder consumes typed values directly; any legacy arbitrary-data shape is a
|
|
203
302
|
* compiler refusal, never a route back through JSON. */
|
|
204
|
-
function
|
|
303
|
+
function dartCallProtoFieldAccess(
|
|
205
304
|
domain: string,
|
|
206
305
|
directive: string,
|
|
207
306
|
spec: PayloadFieldSpec
|
|
208
|
-
):
|
|
307
|
+
): DartCallProtoFieldAccess {
|
|
209
308
|
const member = `payload.${dartMemberName(spec.name)}`;
|
|
210
309
|
if (spec.nullAdmits === true) {
|
|
211
310
|
return { value: member, slot: true };
|
|
@@ -358,7 +457,7 @@ function dartKeyParam(key: string): string {
|
|
|
358
457
|
return safeMethod(safe);
|
|
359
458
|
}
|
|
360
459
|
|
|
361
|
-
/** Parse ONE
|
|
460
|
+
/** Parse ONE session row (`{type,id,data}`) into a typed read model, composing the canonical `.ref` from the
|
|
362
461
|
* session workspace (`_ws`, a getter on the client) + the row's type/id. Works for a `Map` (one-shot
|
|
363
462
|
* `query`/`queryById` rows) or a `dynamic` (`watch` stream rows) — indexing resolves on both. */
|
|
364
463
|
function rowToModel(model: string, rowVar: string, workspace = "_ws"): string {
|
|
@@ -402,7 +501,10 @@ function dartUsdaBasePresentValue(
|
|
|
402
501
|
`Dart result USDA codegen: foreign reference '${spec.wireName}' has no workspace-field decoder`
|
|
403
502
|
);
|
|
404
503
|
}
|
|
405
|
-
|
|
504
|
+
// A foreign reference is a typed, workspace-qualified locator. Decoding
|
|
505
|
+
// belongs to the generated application that owns the target domain; a
|
|
506
|
+
// source client must not capture another domain's private codec.
|
|
507
|
+
return `NmsInternalForeignRefs.create<${spec.foreignRefTarget}>(id: ${value}, workspace: ${foreignWorkspaceExpression}, type: '${spec.foreignRefAggregateType}')`;
|
|
406
508
|
}
|
|
407
509
|
if (spec.refIdClass !== undefined) {
|
|
408
510
|
return `NmsInternalNomosRefs.create<${spec.refIdClass}>(workspace: ${workspace}, type: '${spec.refAggregateType}', id: ${value})`;
|
|
@@ -575,6 +677,10 @@ function dartUsdaProjectionValue(
|
|
|
575
677
|
schema: z.ZodTypeAny,
|
|
576
678
|
expression: string
|
|
577
679
|
): string {
|
|
680
|
+
const valueObject = voMetaOf(schema);
|
|
681
|
+
if (valueObject !== undefined) {
|
|
682
|
+
return `${valueObject.name}.fromProjected((${expression}.jsonValue() as Map).cast<String, Object?>())`;
|
|
683
|
+
}
|
|
578
684
|
let inner = schema;
|
|
579
685
|
while (
|
|
580
686
|
zodKind(inner) === "optional" ||
|
|
@@ -615,6 +721,7 @@ interface DartUsdaResultDecoder {
|
|
|
615
721
|
readonly spec: AggFieldSpec;
|
|
616
722
|
readonly required: boolean;
|
|
617
723
|
readonly foreignWorkspacePath?: string;
|
|
724
|
+
readonly foreignWorkspaceName?: string;
|
|
618
725
|
}[];
|
|
619
726
|
readonly computedFields: readonly {
|
|
620
727
|
readonly name: string;
|
|
@@ -665,7 +772,7 @@ function emitDartUsdaResultDecoder(
|
|
|
665
772
|
const selected = `row.field(${JSON.stringify(field.path)})`;
|
|
666
773
|
return ` if (${selected} != null) ${JSON.stringify(
|
|
667
774
|
name
|
|
668
|
-
)}: FieldProvenance(author: ${selected}!.property('nomos:author') is String ? ${selected}
|
|
775
|
+
)}: FieldProvenance(author: ${selected}!.property('nomos:author') is String ? ${selected}!.property('nomos:author') as String : null, wasContested: ${selected}!.property('nomos:wasContested') == true),`;
|
|
669
776
|
});
|
|
670
777
|
return [
|
|
671
778
|
`List<${decoder.model}> ${functionName}(Uint8List bytes, String workspace) {`,
|
|
@@ -678,7 +785,7 @@ function emitDartUsdaResultDecoder(
|
|
|
678
785
|
` }`,
|
|
679
786
|
` final id = row.property('nomos:id');`,
|
|
680
787
|
` if (id is! String) throw const FormatException('USDA row has no string identity');`,
|
|
681
|
-
` return ${decoder.model}(`,
|
|
788
|
+
` return NmsInternalRecordOrigins.remember(${decoder.model}(`,
|
|
682
789
|
` ref: NmsInternalNomosRefs.create<${
|
|
683
790
|
decoder.refType
|
|
684
791
|
}>(workspace: workspace, type: ${JSON.stringify(
|
|
@@ -689,32 +796,33 @@ function emitDartUsdaResultDecoder(
|
|
|
689
796
|
: []),
|
|
690
797
|
...constructorFields,
|
|
691
798
|
...computedFields,
|
|
692
|
-
` );`,
|
|
799
|
+
` ), workspace: workspace, type: ${JSON.stringify(decoder.runtimeType)}, id: id);`,
|
|
693
800
|
` }).toList(growable: false);`,
|
|
694
801
|
`}`,
|
|
695
802
|
`NomosPage<${decoder.model}> _nmsDecode${decoder.model}Page(Uint8List bytes, String workspace) {`,
|
|
696
803
|
` final result = NmsUsdaResult.parse(bytes);`,
|
|
697
804
|
` return NomosPage(rows: ${functionName}(bytes, workspace), cursor: result.cursor, done: result.done);`,
|
|
698
805
|
`}`,
|
|
806
|
+
`/// Framework-internal nominal decoder used by a typed ForeignRef.`,
|
|
807
|
+
`${decoder.model}? nmsInternalDecode${decoder.model}ById(Uint8List bytes, String workspace, String id) {`,
|
|
808
|
+
` for (final row in ${functionName}(bytes, workspace)) {`,
|
|
809
|
+
` if (row.ref.id == id) return row;`,
|
|
810
|
+
` }`,
|
|
811
|
+
` return null;`,
|
|
812
|
+
`}`,
|
|
699
813
|
``,
|
|
700
814
|
];
|
|
701
815
|
}
|
|
702
816
|
|
|
703
|
-
export interface
|
|
817
|
+
export interface DartClientOptions {
|
|
704
818
|
/** Content identity of the built typed USDA closure (`.law.usdz`). */
|
|
705
819
|
readonly domainHash: string;
|
|
706
820
|
/** Flutter asset key for the compiler-authored USDZ transport. Generated
|
|
707
821
|
* child openers use it to inherit an accepted parent model through the
|
|
708
822
|
* child's ordinary author gate. Omit for pure-Dart/vendored clients. */
|
|
709
|
-
|
|
710
|
-
/** This domain's STRUCTURAL INTERFACE (#72) — directives (payload shapes) + aggregates
|
|
711
|
-
* (read shapes, sid-keyed). Baked in as JSON so the app can negotiate shape-compatibility
|
|
712
|
-
* against the workspace's installed offer, NOT by law hash. */
|
|
823
|
+
/** Compiler graph used to generate the one USDA compatibility matrix. */
|
|
713
824
|
readonly interface?: unknown;
|
|
714
|
-
/**
|
|
715
|
-
* this client was generated against. Baked in as JSON (DIAGNOSIS only, never a gate). */
|
|
716
|
-
readonly compat?: unknown;
|
|
717
|
-
/** Where the bridge/runtime support types are imported from. */
|
|
825
|
+
/** Where the session/runtime support types are imported from. */
|
|
718
826
|
readonly supportImport?: "vendored" | "package";
|
|
719
827
|
/**
|
|
720
828
|
* Relative import of the shared `nomos_framework.dart` (framework-shared aggregate types, emitted
|
|
@@ -777,10 +885,10 @@ export interface DartBridgeClientOptions {
|
|
|
777
885
|
};
|
|
778
886
|
}
|
|
779
887
|
|
|
780
|
-
/** Generate the `<name>.client.dart` async
|
|
781
|
-
export function
|
|
888
|
+
/** Generate the `<name>.client.dart` async session client for one domain module. */
|
|
889
|
+
export function generateDartDomainClient(
|
|
782
890
|
mod: DomainModule,
|
|
783
|
-
opts:
|
|
891
|
+
opts: DartClientOptions
|
|
784
892
|
): string {
|
|
785
893
|
const callUsda = opts.callUsda;
|
|
786
894
|
if (callUsda === undefined) {
|
|
@@ -791,25 +899,21 @@ export function generateDartBridgeClient(
|
|
|
791
899
|
"application calls and results may not fall back to generic maps"
|
|
792
900
|
);
|
|
793
901
|
}
|
|
902
|
+
const operationSelection = dartClientOperationSelection(mod, callUsda.graph);
|
|
794
903
|
const authoredDirectives = mod.directives as AnyDirective[];
|
|
795
904
|
const workspaceSharingPolicies: readonly WorkspaceSharingPolicy[] =
|
|
796
905
|
mod.applicationWorkspaceSharing ?? [];
|
|
797
|
-
const
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
.map((receipt) => [receipt.records.id, receipt.records] as const)
|
|
802
|
-
).values(),
|
|
803
|
-
] as AnyDirective[];
|
|
804
|
-
const workspaceSharingReceiptIds = new Set(
|
|
805
|
-
workspaceSharingReceipts.map((directive) => directive.id)
|
|
906
|
+
const workspaceSharingQueryIds = new Set(
|
|
907
|
+
workspaceSharingPolicies.map(
|
|
908
|
+
(policy) => policy.invitationLaw.pendingByRecipient.id
|
|
909
|
+
)
|
|
806
910
|
);
|
|
807
911
|
const publicAggregates = mod.aggregates.filter(
|
|
808
912
|
(a) =>
|
|
809
913
|
(a as { businessBirthInternal?: unknown }).businessBirthInternal !== true
|
|
810
914
|
);
|
|
811
915
|
const publicAggregateIds = new Set(publicAggregates.map((a) => a.id));
|
|
812
|
-
const publicDirectives =
|
|
916
|
+
const publicDirectives = operationSelection.publicDirectives;
|
|
813
917
|
mod = {
|
|
814
918
|
...mod,
|
|
815
919
|
aggregates: publicAggregates,
|
|
@@ -824,7 +928,8 @@ export function generateDartBridgeClient(
|
|
|
824
928
|
queries: mod.queries.filter(
|
|
825
929
|
(q) =>
|
|
826
930
|
(q as { businessBirthInternal?: unknown })
|
|
827
|
-
.businessBirthInternal !== true
|
|
931
|
+
.businessBirthInternal !== true ||
|
|
932
|
+
workspaceSharingQueryIds.has(q.id)
|
|
828
933
|
),
|
|
829
934
|
}),
|
|
830
935
|
...(mod.readModelAggregates === undefined
|
|
@@ -884,6 +989,7 @@ export function generateDartBridgeClient(
|
|
|
884
989
|
: qualifyReadProjectionType(ownerDomain, aggregateType);
|
|
885
990
|
};
|
|
886
991
|
const resultDecoderSources: string[] = [];
|
|
992
|
+
const resultProtoDecoderSources: string[] = [];
|
|
887
993
|
const resultDecoderByAggregate = new Map<string, DartUsdaResultDecoder>();
|
|
888
994
|
{
|
|
889
995
|
for (const aggregate of mod.aggregates) {
|
|
@@ -959,7 +1065,10 @@ export function generateDartBridgeClient(
|
|
|
959
1065
|
required: field.isFromBirth === true,
|
|
960
1066
|
...(foreignWorkspacePath === undefined
|
|
961
1067
|
? {}
|
|
962
|
-
: {
|
|
1068
|
+
: {
|
|
1069
|
+
foreignWorkspacePath,
|
|
1070
|
+
foreignWorkspaceName: spec.foreignRefWorkspaceField,
|
|
1071
|
+
}),
|
|
963
1072
|
};
|
|
964
1073
|
});
|
|
965
1074
|
const computedFields = [
|
|
@@ -1094,17 +1203,6 @@ export function generateDartBridgeClient(
|
|
|
1094
1203
|
}
|
|
1095
1204
|
return needsReadPrincipal(typeId) ? ", null, _client.actor" : "";
|
|
1096
1205
|
};
|
|
1097
|
-
// The DISTINCT encryption scopes this domain defines (across encrypted reads + sealing directives) — the
|
|
1098
|
-
// set the owner ceremony rotates. Empty ⇒ no `encryption` getter is emitted for this domain.
|
|
1099
|
-
const domScopes: string[] = (() => {
|
|
1100
|
-
if (encMap === null) return [];
|
|
1101
|
-
const s = new Set<string>();
|
|
1102
|
-
for (const r of Object.values(encMap.reads))
|
|
1103
|
-
for (const f of Object.values(r)) if (f.owned !== true) s.add(f.scope);
|
|
1104
|
-
for (const dir of Object.values(encMap.directives))
|
|
1105
|
-
for (const f of Object.values(dir)) if (f.owned !== true) s.add(f.scope);
|
|
1106
|
-
return [...s].sort();
|
|
1107
|
-
})();
|
|
1108
1206
|
const ownedScopes: string[] = (() => {
|
|
1109
1207
|
if (encMap === null) return [];
|
|
1110
1208
|
const scopes = new Set<string>();
|
|
@@ -1135,7 +1233,7 @@ export function generateDartBridgeClient(
|
|
|
1135
1233
|
` /// publication. The kernel reads one compiled current pointer; it does not resolve history.`,
|
|
1136
1234
|
` Future<ReferenceVersionStatus<TVersion>> referenceVersionStatus<TVersion, TSeries>(`,
|
|
1137
1235
|
` VersionedNomosRef<TVersion, TSeries> reference) =>`,
|
|
1138
|
-
`
|
|
1236
|
+
` session.checkReferenceVersion(reference);`,
|
|
1139
1237
|
``
|
|
1140
1238
|
);
|
|
1141
1239
|
}
|
|
@@ -1176,10 +1274,6 @@ export function generateDartBridgeClient(
|
|
|
1176
1274
|
// THE STATIC INTERFACE DESCRIPTOR (`XClient.interface`, session_bound_clients.md asks 5/9) —
|
|
1177
1275
|
// what this client EXPECTS of a workspace: the domain key, the law hash it compiled under, and
|
|
1178
1276
|
// the structural interface (#72). `bind(session)` / `session.assertCompatible(...)` consume it.
|
|
1179
|
-
const compatInterfaceHash = (
|
|
1180
|
-
opts.compat as { interfaceHash?: string } | undefined
|
|
1181
|
-
)?.interfaceHash;
|
|
1182
|
-
|
|
1183
1277
|
// ── directives → typed offer ──
|
|
1184
1278
|
// A `.births()` directive is still authored on its bound parent workspace. It therefore uses the
|
|
1185
1279
|
// same typed USDA/Protobuf offer door as every other directive; only the law's effect crosses custody.
|
|
@@ -1188,7 +1282,8 @@ export function generateDartBridgeClient(
|
|
|
1188
1282
|
d &&
|
|
1189
1283
|
typeof d.id === "string" &&
|
|
1190
1284
|
typeof (d as { payloadSchema?: unknown }).payloadSchema === "object" &&
|
|
1191
|
-
(d as { businessBirthInternal?: unknown }).businessBirthInternal !== true
|
|
1285
|
+
(d as { businessBirthInternal?: unknown }).businessBirthInternal !== true &&
|
|
1286
|
+
publishingIntentOf(callUsda.graph, mod.domain ?? mod.name, d.id) === undefined
|
|
1192
1287
|
);
|
|
1193
1288
|
const birthDirs = allDirs.filter(
|
|
1194
1289
|
(d) => (d as { birthsChild?: boolean }).birthsChild === true
|
|
@@ -1196,119 +1291,10 @@ export function generateDartBridgeClient(
|
|
|
1196
1291
|
const dirs = allDirs.filter(
|
|
1197
1292
|
(d) => (d as { birthsChild?: boolean }).birthsChild !== true
|
|
1198
1293
|
);
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
// (for example all-device-loss recovery bound to a named principal) and remain ordinary
|
|
1202
|
-
// generated APIs; their proof posture does not make them automatic lifecycle hooks.
|
|
1203
|
-
const authenticationRecoveryDirs = dirs.filter(
|
|
1204
|
-
(directive) =>
|
|
1205
|
-
isBusinessIntent(directive) &&
|
|
1206
|
-
directive.offerAuthenticationProof === "enrolledDevice" &&
|
|
1207
|
-
introspectPayload(directive.payloadSchema as z.ZodTypeAny, enumDartTypes)
|
|
1208
|
-
.length === 0
|
|
1209
|
-
);
|
|
1210
|
-
if (authenticationRecoveryDirs.length > 1) {
|
|
1211
|
-
throw new Error(
|
|
1212
|
-
`Dart client codegen: '${domain}' declares more than one enrolled-device authentication recovery intent; ` +
|
|
1213
|
-
"the framework cannot choose a unique law-authored recovery operation"
|
|
1214
|
-
);
|
|
1215
|
-
}
|
|
1216
|
-
const authenticationRecovery = authenticationRecoveryDirs[0];
|
|
1217
|
-
const childAuthenticationRecoveries = dirs.flatMap((directive) => {
|
|
1218
|
-
if (!isBusinessIntent(directive)) return [];
|
|
1219
|
-
const aggregateId = childAuthenticationRecoveryAggregateId(directive);
|
|
1220
|
-
if (aggregateId === undefined) return [];
|
|
1221
|
-
const fields = introspectPayload(
|
|
1222
|
-
directive.payloadSchema as z.ZodTypeAny,
|
|
1223
|
-
enumDartTypes,
|
|
1224
|
-
);
|
|
1225
|
-
if (
|
|
1226
|
-
fields.length !== 2 ||
|
|
1227
|
-
fields.some(
|
|
1228
|
-
(field) =>
|
|
1229
|
-
!["workspace", "user"].includes(field.name) ||
|
|
1230
|
-
field.optional ||
|
|
1231
|
-
field.dartType !== "String",
|
|
1232
|
-
)
|
|
1233
|
-
) {
|
|
1234
|
-
throw new Error(
|
|
1235
|
-
`Dart child-authentication recovery '${domain}/${directive.id}' must accept exactly required string fields { workspace, user }`,
|
|
1236
|
-
);
|
|
1237
|
-
}
|
|
1238
|
-
return [{ aggregateId, directive }];
|
|
1239
|
-
});
|
|
1240
|
-
for (const recovery of childAuthenticationRecoveries) {
|
|
1241
|
-
if (
|
|
1242
|
-
childAuthenticationRecoveries.some(
|
|
1243
|
-
(candidate) =>
|
|
1244
|
-
candidate !== recovery &&
|
|
1245
|
-
candidate.aggregateId === recovery.aggregateId,
|
|
1246
|
-
)
|
|
1247
|
-
) {
|
|
1248
|
-
throw new Error(
|
|
1249
|
-
`Dart client codegen: '${domain}' declares more than one authentication repair action for '${recovery.aggregateId}'`,
|
|
1250
|
-
);
|
|
1251
|
-
}
|
|
1252
|
-
const method = safeMethod(recovery.directive.id);
|
|
1253
|
-
const input = dartActionInputClassName(recovery.directive);
|
|
1254
|
-
methods.push(
|
|
1255
|
-
` /// Generated child-open recovery: inspect the child's kernel posture, then ask this`,
|
|
1256
|
-
` /// authenticated parent law to send its committed signer/provider state to that exact child.`,
|
|
1257
|
-
` Future<void> ${dartInternalChildAuthenticationRecoveryMethod(
|
|
1258
|
-
recovery.aggregateId,
|
|
1259
|
-
)}(String workspace) async {`,
|
|
1260
|
-
` final expectedPrincipal = actor ?? bridge.principal ?? '';`,
|
|
1261
|
-
` if (expectedPrincipal.isEmpty) {`,
|
|
1262
|
-
` throw StateError('Child authentication recovery requires the signed-in principal.');`,
|
|
1263
|
-
` }`,
|
|
1264
|
-
` final child = await bridge.acquireSession(workspace);`,
|
|
1265
|
-
` final posture = await child.nmsAuthenticationPosture(principal: expectedPrincipal);`,
|
|
1266
|
-
` if (posture.isReadyFor(expectedPrincipal)) return;`,
|
|
1267
|
-
` await ${method}(${input}(`,
|
|
1268
|
-
` workspace: workspace, user: expectedPrincipal,`,
|
|
1269
|
-
` ));`,
|
|
1270
|
-
` final parentSync = await bridge.sync(admit: true);`,
|
|
1271
|
-
` if (parentSync.offline || parentSync.pushFailed) {`,
|
|
1272
|
-
` throw StateError('Parent authentication recovery could not reach custody: ' +`,
|
|
1273
|
-
` (parentSync.hasPushError() ? parentSync.pushError.message : 'workspace is offline'));`,
|
|
1274
|
-
` }`,
|
|
1275
|
-
` await child.nmsAwaitProviderTokenReady(principal: expectedPrincipal);`,
|
|
1276
|
-
` await child.nmsAwaitAuthenticationReady(principal: expectedPrincipal);`,
|
|
1277
|
-
` }`,
|
|
1278
|
-
``,
|
|
1279
|
-
);
|
|
1280
|
-
}
|
|
1294
|
+
const sourceTrustViaIds = operationSelection.sourceTrustViaIds;
|
|
1295
|
+
const sourceTrustDirectives = operationSelection.sourceTrustDirectives;
|
|
1281
1296
|
const localOfferDirs = [...dirs, ...birthDirs];
|
|
1282
|
-
const
|
|
1283
|
-
dirs.flatMap((directive) =>
|
|
1284
|
-
directive.businessSourceTrust === undefined
|
|
1285
|
-
? []
|
|
1286
|
-
: [directive.businessSourceTrust.viaDirectiveId]
|
|
1287
|
-
)
|
|
1288
|
-
);
|
|
1289
|
-
const sourceTrustDirectives = authoredDirectives.filter((directive) =>
|
|
1290
|
-
sourceTrustViaIds.has(directive.id)
|
|
1291
|
-
);
|
|
1292
|
-
for (const viaDirectiveId of sourceTrustViaIds) {
|
|
1293
|
-
if (
|
|
1294
|
-
!sourceTrustDirectives.some(
|
|
1295
|
-
(directive) => directive.id === viaDirectiveId
|
|
1296
|
-
)
|
|
1297
|
-
) {
|
|
1298
|
-
throw new Error(
|
|
1299
|
-
`Dart source-trust codegen: '${domain}' has no hidden directive '${viaDirectiveId}'`
|
|
1300
|
-
);
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
const encoderDirs = [
|
|
1304
|
-
...new Map(
|
|
1305
|
-
[
|
|
1306
|
-
...localOfferDirs,
|
|
1307
|
-
...sourceTrustDirectives,
|
|
1308
|
-
...workspaceSharingReceipts,
|
|
1309
|
-
].map((directive) => [directive.id, directive] as const)
|
|
1310
|
-
).values(),
|
|
1311
|
-
];
|
|
1297
|
+
const encoderDirs = operationSelection.encoderDirectives;
|
|
1312
1298
|
const callEncoderSources: string[] = [];
|
|
1313
1299
|
const callEncoderByDirective = new Map<
|
|
1314
1300
|
string,
|
|
@@ -1316,9 +1302,7 @@ export function generateDartBridgeClient(
|
|
|
1316
1302
|
>();
|
|
1317
1303
|
const internalRecordTypes = new Map<string, string>();
|
|
1318
1304
|
for (const directive of encoderDirs) {
|
|
1319
|
-
const compilerInternal =
|
|
1320
|
-
sourceTrustViaIds.has(directive.id) ||
|
|
1321
|
-
workspaceSharingReceiptIds.has(directive.id);
|
|
1305
|
+
const compilerInternal = sourceTrustViaIds.has(directive.id);
|
|
1322
1306
|
const businessBirth = (
|
|
1323
1307
|
directive as unknown as {
|
|
1324
1308
|
businessBirth?: { publicPayloadSchema: z.ZodTypeAny };
|
|
@@ -1341,11 +1325,11 @@ export function generateDartBridgeClient(
|
|
|
1341
1325
|
: dartActionInputClassName(directive);
|
|
1342
1326
|
if (compilerInternal) internalRecordTypes.set(directive.id, payloadClass);
|
|
1343
1327
|
const specsByName = new Map(specs.map((spec) => [spec.name, spec]));
|
|
1344
|
-
const access = new Map<string,
|
|
1328
|
+
const access = new Map<string, DartCallProtoFieldAccess>();
|
|
1345
1329
|
for (const spec of specs) {
|
|
1346
1330
|
access.set(
|
|
1347
1331
|
spec.name,
|
|
1348
|
-
|
|
1332
|
+
dartCallProtoFieldAccess(domain, directive.id, spec)
|
|
1349
1333
|
);
|
|
1350
1334
|
}
|
|
1351
1335
|
const extraParameters: string[] = [];
|
|
@@ -1508,7 +1492,7 @@ export function generateDartBridgeClient(
|
|
|
1508
1492
|
});
|
|
1509
1493
|
}
|
|
1510
1494
|
}
|
|
1511
|
-
const encoder =
|
|
1495
|
+
const encoder = emitDartCallProtoEncoder(
|
|
1512
1496
|
callUsda.graph,
|
|
1513
1497
|
callUsda.paths,
|
|
1514
1498
|
domain,
|
|
@@ -1544,29 +1528,6 @@ export function generateDartBridgeClient(
|
|
|
1544
1528
|
``
|
|
1545
1529
|
);
|
|
1546
1530
|
}
|
|
1547
|
-
for (const directive of workspaceSharingReceipts) {
|
|
1548
|
-
const encoder = callEncoderByDirective.get(directive.id);
|
|
1549
|
-
const payloadType = internalRecordTypes.get(directive.id);
|
|
1550
|
-
if (
|
|
1551
|
-
encoder === undefined ||
|
|
1552
|
-
payloadType === undefined ||
|
|
1553
|
-
encoder.arguments.some((argument) => argument !== "now")
|
|
1554
|
-
) {
|
|
1555
|
-
throw new Error(
|
|
1556
|
-
`Dart workspace-sharing codegen: hidden receipt '${domain}/${directive.id}' is not a closed typed record`
|
|
1557
|
-
);
|
|
1558
|
-
}
|
|
1559
|
-
const method = dartInternalWorkspaceSharingReceiptMethod(directive.id);
|
|
1560
|
-
const implementation =
|
|
1561
|
-
encoder.arguments.length === 0
|
|
1562
|
-
? `=>\n _offer(${encoder.functionName}(payload));`
|
|
1563
|
-
: `{\n final now = DateTime.now().toUtc().toIso8601String();\n return _offer(${encoder.functionName}(payload, now));\n }`;
|
|
1564
|
-
methods.push(
|
|
1565
|
-
` /// @internal Compiler-generated workspace-sharing receipt. Not tenant application vocabulary.`,
|
|
1566
|
-
` Future<NomosOfferOutcome> ${method}(${payloadType} payload) ${implementation}`,
|
|
1567
|
-
``
|
|
1568
|
-
);
|
|
1569
|
-
}
|
|
1570
1531
|
const ownedActionCallEncoders = new Map<
|
|
1571
1532
|
string,
|
|
1572
1533
|
{
|
|
@@ -1579,8 +1540,8 @@ export function generateDartBridgeClient(
|
|
|
1579
1540
|
if (ownedScope !== undefined && Object.keys(ownedActions).length > 0) {
|
|
1580
1541
|
const ownedAccess = (
|
|
1581
1542
|
fields: readonly string[]
|
|
1582
|
-
): Map<string,
|
|
1583
|
-
const access = new Map<string,
|
|
1543
|
+
): Map<string, DartCallProtoFieldAccess> => {
|
|
1544
|
+
const access = new Map<string, DartCallProtoFieldAccess>();
|
|
1584
1545
|
for (const field of fields) {
|
|
1585
1546
|
access.set(field, { value: `payload.${dartMemberName(field)}` });
|
|
1586
1547
|
}
|
|
@@ -1618,7 +1579,7 @@ export function generateDartBridgeClient(
|
|
|
1618
1579
|
for (const actions of Object.values(ownedActions)) {
|
|
1619
1580
|
for (const action of ["share", "unshare", "transfer"] as const) {
|
|
1620
1581
|
const directiveId = actions[action];
|
|
1621
|
-
const encoder =
|
|
1582
|
+
const encoder = emitDartCallProtoEncoder(
|
|
1622
1583
|
callUsda.graph,
|
|
1623
1584
|
callUsda.paths,
|
|
1624
1585
|
domain,
|
|
@@ -1634,13 +1595,13 @@ export function generateDartBridgeClient(
|
|
|
1634
1595
|
});
|
|
1635
1596
|
}
|
|
1636
1597
|
}
|
|
1637
|
-
const approvalEncoder =
|
|
1598
|
+
const approvalEncoder = emitDartCallProtoEncoder(
|
|
1638
1599
|
callUsda.graph,
|
|
1639
1600
|
callUsda.paths,
|
|
1640
1601
|
domain,
|
|
1641
1602
|
OWNED_DEVICE_APPROVAL_DIRECTIVE,
|
|
1642
1603
|
"NomosOwnedDeviceApprovalPreparation",
|
|
1643
|
-
new Map<string,
|
|
1604
|
+
new Map<string, DartCallProtoFieldAccess>([
|
|
1644
1605
|
["newKeySubject", { value: "payload.newKeySubject" }],
|
|
1645
1606
|
["ownedCustody", { value: "payload.ownedCustody" }],
|
|
1646
1607
|
["verifiedVia", { value: "payload.verifiedVia" }],
|
|
@@ -1675,48 +1636,10 @@ export function generateDartBridgeClient(
|
|
|
1675
1636
|
const correctionActions = dirs.filter(
|
|
1676
1637
|
(d) => (d as { businessBirth?: unknown }).businessBirth === undefined
|
|
1677
1638
|
);
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
` /// Correct this principal's latest business change. The framework owns target selection and replay.`,
|
|
1683
|
-
` ${correctionsClass} get corrections => ${correctionsClass}(this);`,
|
|
1684
|
-
``
|
|
1685
|
-
);
|
|
1686
|
-
pastDeclarations.push(
|
|
1687
|
-
`/// Result of a reasoned business correction. Framework intent and testimony ids remain private.`,
|
|
1688
|
-
`class ${outcomeClass} {`,
|
|
1689
|
-
` final bool ok;`,
|
|
1690
|
-
` final String kind;`,
|
|
1691
|
-
` final String? reason;`,
|
|
1692
|
-
` final String? message;`,
|
|
1693
|
-
` final String? head;`,
|
|
1694
|
-
` const ${outcomeClass}({required this.ok, required this.kind, this.reason, this.message, this.head});`,
|
|
1695
|
-
` factory ${outcomeClass}.fromJson(Map<String, Object?> json) => ${outcomeClass}(`,
|
|
1696
|
-
` ok: json['ok'] == true, kind: (json['kind'] ?? '') as String,`,
|
|
1697
|
-
` reason: json['reason'] as String?, message: json['message'] as String?, head: json['head'] as String?);`,
|
|
1698
|
-
`}`,
|
|
1699
|
-
``,
|
|
1700
|
-
`/// One business correction lane. Application code provides only its reason.`,
|
|
1701
|
-
`class ${correctionsClass} {`,
|
|
1702
|
-
` final ${className} _client;`,
|
|
1703
|
-
` const ${correctionsClass}(this._client);`,
|
|
1704
|
-
` Future<${outcomeClass}> undo(String reason) => _apply('undo', reason);`,
|
|
1705
|
-
` Future<${outcomeClass}> redo(String reason) => _apply('redo', reason);`,
|
|
1706
|
-
` Future<${outcomeClass}> _apply(String kind, String reason) async {`,
|
|
1707
|
-
` if (reason.trim().isEmpty) throw ArgumentError('corrections.\$kind() needs a reason');`,
|
|
1708
|
-
` final result = await _client.bridge.correctMostRecent(`,
|
|
1709
|
-
` kind: kind, domain: ${dartStr(domain)},`,
|
|
1710
|
-
` actions: const [${correctionActions
|
|
1711
|
-
.map((d) => dartStr(d.id))
|
|
1712
|
-
.join(", ")}],`,
|
|
1713
|
-
` reason: reason, domainHash: _client.domainHash, actor: _client.actor);`,
|
|
1714
|
-
` return ${outcomeClass}.fromJson(result);`,
|
|
1715
|
-
` }`,
|
|
1716
|
-
`}`,
|
|
1717
|
-
``
|
|
1718
|
-
);
|
|
1719
|
-
}
|
|
1639
|
+
// Corrections remain framework law, but no Dart API is emitted until the
|
|
1640
|
+
// peer runtime owns a nominal Runtime v2 correction command. The removed
|
|
1641
|
+
// surface called a JavaScript-only control method and decoded an anonymous
|
|
1642
|
+
// map, so it was neither portable nor end-to-end typed.
|
|
1720
1643
|
for (const d of dirs) {
|
|
1721
1644
|
const payloadClass = dartActionInputClassName(d);
|
|
1722
1645
|
// targetBinding is declared on AnyDirective (directive.ts) — honour it for EVERY
|
|
@@ -1740,7 +1663,7 @@ export function generateDartBridgeClient(
|
|
|
1740
1663
|
// THE AUTHORITY GATE (codegen-time): a directive carrying `.requires(relation)` is GATED — its method
|
|
1741
1664
|
// throws MissingOfferAuthority when `actor` is null/empty, BEFORE any submit, so an actorless gated
|
|
1742
1665
|
// offer is impossible to GENERATE (the war: the gate is structural, not just kernel-side). Secrets never
|
|
1743
|
-
// appear — only the actor identity (the
|
|
1666
|
+
// appear — only the actor identity (the session owns signing).
|
|
1744
1667
|
const gate = (d as { requiresRelationGate?: { relation: string } })
|
|
1745
1668
|
.requiresRelationGate;
|
|
1746
1669
|
const gateGuard =
|
|
@@ -1759,7 +1682,7 @@ export function generateDartBridgeClient(
|
|
|
1759
1682
|
// bound [keyStore] before dispatch (a missing key throws [EncryptionKeyUnavailable] — never a plaintext
|
|
1760
1683
|
// write). One async block covers creates + mutate + gated + stamps; `seal: false` is the escape hatch.
|
|
1761
1684
|
// THE ONE WRITE OUTCOME (architecture/nomos_ref.md): EVERY directive method returns Future<NomosOfferOutcome>
|
|
1762
|
-
// via the ONE lane `
|
|
1685
|
+
// via the ONE lane `session.offerOutcome` — `outcome.created` carries every minted aggregate (each with its
|
|
1763
1686
|
// typed `.ref`), `outcome.head` the new local head. The breaking cut: creates AND non-creates alike.
|
|
1764
1687
|
const createsDoc =
|
|
1765
1688
|
(d as { marker?: string }).marker === "creates"
|
|
@@ -1772,7 +1695,7 @@ export function generateDartBridgeClient(
|
|
|
1772
1695
|
principalField === undefined
|
|
1773
1696
|
? []
|
|
1774
1697
|
: [
|
|
1775
|
-
` final nmsInternalPrincipal = actor
|
|
1698
|
+
` final nmsInternalPrincipal = actor;`,
|
|
1776
1699
|
` if (nmsInternalPrincipal == null || nmsInternalPrincipal.trim().isEmpty) {`,
|
|
1777
1700
|
` throw MissingOfferAuthority(domain: ${dartStr(
|
|
1778
1701
|
domain
|
|
@@ -1787,12 +1710,13 @@ export function generateDartBridgeClient(
|
|
|
1787
1710
|
`Dart call USDA codegen: '${domain}/${d.id}' has no generated encoder`
|
|
1788
1711
|
);
|
|
1789
1712
|
}
|
|
1790
|
-
const
|
|
1713
|
+
const generatedCall = `${callEncoder.functionName}(${[
|
|
1791
1714
|
"payload",
|
|
1792
1715
|
...callEncoder.arguments,
|
|
1793
1716
|
].join(", ")})`;
|
|
1794
|
-
const offerCall = `_offer(${
|
|
1795
|
-
isBusinessIntent(d) &&
|
|
1717
|
+
const offerCall = `_offer(${generatedCall}${
|
|
1718
|
+
isBusinessIntent(d) &&
|
|
1719
|
+
d.authentication?.kind === MemberAuthenticationKind.EnrolledDevice
|
|
1796
1720
|
? ", authenticationProof: NomosOfferAuthenticationProof.enrolledDevice"
|
|
1797
1721
|
: ""
|
|
1798
1722
|
})`;
|
|
@@ -1837,14 +1761,14 @@ export function generateDartBridgeClient(
|
|
|
1837
1761
|
: recordTarget.kind === "premint"
|
|
1838
1762
|
? [
|
|
1839
1763
|
` final ownedRecordType = ${dartStr(runtimeType)};`,
|
|
1840
|
-
` final ownedRecordId = await
|
|
1764
|
+
` final ownedRecordId = await session.mintId(ownedRecordType);`,
|
|
1841
1765
|
` const ownedRecordPreMinted = true;`,
|
|
1842
1766
|
]
|
|
1843
1767
|
: recordTarget.kind === "payload"
|
|
1844
1768
|
? [
|
|
1845
1769
|
` final ownedRecordType = ${dartStr(runtimeType)};`,
|
|
1846
1770
|
` final ownedRecordId = ${
|
|
1847
|
-
|
|
1771
|
+
dartCallProtoFieldAccess(
|
|
1848
1772
|
domain,
|
|
1849
1773
|
d.id,
|
|
1850
1774
|
encryptedSpecs.get(recordTarget.field) ??
|
|
@@ -1865,7 +1789,7 @@ export function generateDartBridgeClient(
|
|
|
1865
1789
|
const ownedKeyPrelude = ownedSeal
|
|
1866
1790
|
? [
|
|
1867
1791
|
...recordPrelude,
|
|
1868
|
-
` final nmsInternalOwnedKey = await
|
|
1792
|
+
` final nmsInternalOwnedKey = await session.nomosOwnedScopeKey(`,
|
|
1869
1793
|
` ${dartStr(Object.values(directiveEncryption)[0]!.scope)},`,
|
|
1870
1794
|
` recordType: ownedRecordType, recordId: ownedRecordId);`,
|
|
1871
1795
|
` final nmsInternalOwnedKeySubject = nmsInternalOwnedKey.ownedKeySubject;`,
|
|
@@ -1912,7 +1836,7 @@ export function generateDartBridgeClient(
|
|
|
1912
1836
|
` if (${key} == null) throw EncryptionKeyUnavailable(${dartStr(
|
|
1913
1837
|
descriptor.scope
|
|
1914
1838
|
)}, ${dartStr(field)});`,
|
|
1915
|
-
` ${sealed} = await
|
|
1839
|
+
` ${sealed} = await session.cryptoSealField(`,
|
|
1916
1840
|
` scopeKey: ${key}.key, scope: ${
|
|
1917
1841
|
descriptor.owned === true
|
|
1918
1842
|
? `${key}.scope`
|
|
@@ -2013,7 +1937,7 @@ export function generateDartBridgeClient(
|
|
|
2013
1937
|
}
|
|
2014
1938
|
}
|
|
2015
1939
|
|
|
2016
|
-
// ── `.births()` directives → typed CROSS-WORKSPACE birth (
|
|
1940
|
+
// ── `.births()` directives → typed CROSS-WORKSPACE birth (session.createWorkspace) ──
|
|
2017
1941
|
// Each births a CHILD WORKSPACE under `parent` via a signed governance offer routed by the PARENT'S
|
|
2018
1942
|
// law (POST /v2/workspaces/<parent>/<directiveId>) — never a same-workspace write. The declaring
|
|
2019
1943
|
// domain's key + directiveId + baked domainHash are all bound at codegen time, so a frontend dev
|
|
@@ -2090,7 +2014,7 @@ export function generateDartBridgeClient(
|
|
|
2090
2014
|
ownedBirthDescriptor === undefined
|
|
2091
2015
|
? []
|
|
2092
2016
|
: [
|
|
2093
|
-
` final nmsInternalOwnedKey = await
|
|
2017
|
+
` final nmsInternalOwnedKey = await session.nomosOwnedBirthScopeKey(`,
|
|
2094
2018
|
` ${dartStr(ownedBirthDescriptor.scope)}, ${dartStr(
|
|
2095
2019
|
businessBirth.namespace
|
|
2096
2020
|
)}, payload.${dartMemberName(businessBirth.keyField)}, ${dartStr(
|
|
@@ -2132,7 +2056,7 @@ export function generateDartBridgeClient(
|
|
|
2132
2056
|
` if (${key} == null) throw EncryptionKeyUnavailable(${dartStr(
|
|
2133
2057
|
descriptor.scope
|
|
2134
2058
|
)}, ${dartStr(field)});`,
|
|
2135
|
-
` ${sealed} = await
|
|
2059
|
+
` ${sealed} = await session.cryptoSealField(`,
|
|
2136
2060
|
` scopeKey: ${key}.key, scope: ${
|
|
2137
2061
|
descriptor.owned === true
|
|
2138
2062
|
? `${key}.scope`
|
|
@@ -2196,7 +2120,7 @@ export function generateDartBridgeClient(
|
|
|
2196
2120
|
` Future<NomosRef<${concreteClassName(
|
|
2197
2121
|
businessBirth.aggregateId
|
|
2198
2122
|
)}>> ${publicMethod}(${payloadClass} payload) async {`,
|
|
2199
|
-
` final principal = actor
|
|
2123
|
+
` final principal = actor;`,
|
|
2200
2124
|
` if (principal == null || principal.trim().isEmpty) {`,
|
|
2201
2125
|
` throw MissingOfferAuthority(domain: ${dartStr(
|
|
2202
2126
|
domain
|
|
@@ -2204,21 +2128,19 @@ export function generateDartBridgeClient(
|
|
|
2204
2128
|
d.id
|
|
2205
2129
|
)}, requires: 'a signed-in Nomos session');`,
|
|
2206
2130
|
` }`,
|
|
2207
|
-
` await _preflightOnce();`,
|
|
2208
|
-
` await _prepareCommand(${dartStr(d.id)});`,
|
|
2209
2131
|
...(businessBirth.domain === domain
|
|
2210
2132
|
? []
|
|
2211
2133
|
: [
|
|
2212
2134
|
` // This parent offer synchronously runs the child genesis plan. Name that exact`,
|
|
2213
2135
|
` // authenticated slice now so birth never composes an unrelated or cold domain.`,
|
|
2214
|
-
` await
|
|
2136
|
+
` await session.prepareDomain(domain: ${dartStr(
|
|
2215
2137
|
businessBirth.domain
|
|
2216
2138
|
)}, directiveId: ${dartStr(
|
|
2217
2139
|
seedDirectiveId
|
|
2218
2140
|
)}, packageHash: ${hashConst});`,
|
|
2219
2141
|
...genesisDirectiveIds.map(
|
|
2220
2142
|
(directiveId) =>
|
|
2221
|
-
` await
|
|
2143
|
+
` await session.prepareDomain(domain: ${dartStr(
|
|
2222
2144
|
businessBirth.domain
|
|
2223
2145
|
)}, directiveId: ${dartStr(
|
|
2224
2146
|
directiveId
|
|
@@ -2298,7 +2220,9 @@ export function generateDartBridgeClient(
|
|
|
2298
2220
|
}
|
|
2299
2221
|
|
|
2300
2222
|
// ── declared queries → one-shot + reactive ──
|
|
2301
|
-
for (const
|
|
2223
|
+
for (const read of [...(mod.queries ?? []), ...(mod.orderedReads ?? [])]) {
|
|
2224
|
+
const ordered = "orderKey" in read ? read : undefined;
|
|
2225
|
+
const q = "orderKey" in read ? { id: read.id, returns: read.of, key: [] as string[] } : read;
|
|
2302
2226
|
const model = readModelClassName(q.returns);
|
|
2303
2227
|
const agg = aggById.get(q.returns);
|
|
2304
2228
|
const params = q.key
|
|
@@ -2307,7 +2231,7 @@ export function generateDartBridgeClient(
|
|
|
2307
2231
|
`required ${dartKeyType(agg, k, enumDartTypes)} ${dartKeyParam(k)}`
|
|
2308
2232
|
)
|
|
2309
2233
|
.join(", ");
|
|
2310
|
-
const queryEncoder =
|
|
2234
|
+
const queryEncoder = emitDartQueryProtoEncoder(
|
|
2311
2235
|
callUsda.graph,
|
|
2312
2236
|
callUsda.paths,
|
|
2313
2237
|
domain,
|
|
@@ -2327,29 +2251,82 @@ export function generateDartBridgeClient(
|
|
|
2327
2251
|
);
|
|
2328
2252
|
callEncoderSources.push(...queryEncoder.source);
|
|
2329
2253
|
const queryCall = queryEncoder.call;
|
|
2254
|
+
const queryNode = callUsda.graph.nodes.find(
|
|
2255
|
+
(node): node is LawRowReadNode =>
|
|
2256
|
+
node.kind === "read" &&
|
|
2257
|
+
(node.readKind === "query" || node.readKind === "ordered") &&
|
|
2258
|
+
node.entity.label === q.id
|
|
2259
|
+
);
|
|
2260
|
+
if (queryNode === undefined) {
|
|
2261
|
+
throw new Error(
|
|
2262
|
+
`Dart result Protobuf codegen: composed law has no '${domain}.${q.id}' query`
|
|
2263
|
+
);
|
|
2264
|
+
}
|
|
2265
|
+
const aggregateDecoder = resultDecoderByAggregate.get(q.returns);
|
|
2266
|
+
if (aggregateDecoder === undefined) {
|
|
2267
|
+
throw new Error(
|
|
2268
|
+
`Dart result Protobuf codegen: '${domain}.${q.id}' has no '${q.returns}' result model`
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2271
|
+
const resultProtoDecoder = emitDartQueryResultProtoDecoder(
|
|
2272
|
+
callUsda.graph,
|
|
2273
|
+
callUsda.paths,
|
|
2274
|
+
queryNode,
|
|
2275
|
+
aggregateDecoder
|
|
2276
|
+
);
|
|
2277
|
+
resultProtoDecoderSources.push(...resultProtoDecoder.source);
|
|
2278
|
+
const decodeRows = resultProtoDecoder.rowsFunction;
|
|
2279
|
+
const decodePage = resultProtoDecoder.pageFunction;
|
|
2330
2280
|
const m = safeMethod(lcFirst(camel(q.id)));
|
|
2331
2281
|
const qScopes = readScopesFor(q.returns);
|
|
2332
2282
|
const qOwned = qScopes.some((scope) => scope.owned === true);
|
|
2333
2283
|
const qPrivate = needsReadPrincipal(q.returns);
|
|
2334
2284
|
const qScopesExpr = scopesExpr(qScopes);
|
|
2335
2285
|
const nominalWatch = qOwned
|
|
2336
|
-
? `
|
|
2286
|
+
? `session.nmsWatch(${queryCall}${
|
|
2337
2287
|
qPrivate ? ", principal: actor" : ""
|
|
2338
|
-
}).asyncMap((
|
|
2288
|
+
}).asyncMap((result) async => _readWithOwnedKeys(${qScopesExpr}, (keys) async => ${decodeRows}(await session.nmsQuery(${queryCall}, keys${
|
|
2339
2289
|
qPrivate ? ", actor" : ""
|
|
2340
|
-
}), _ws), (row) => row.ref))`
|
|
2290
|
+
}), _ws), (row) => row.ref, initial: await ${decodeRows}(result, _ws)))`
|
|
2341
2291
|
: qScopes.length
|
|
2342
|
-
? `Stream.fromFuture(_readKeys(${qScopesExpr})).asyncExpand((keys) =>
|
|
2292
|
+
? `Stream.fromFuture(_readKeys(${qScopesExpr})).asyncExpand((keys) => session.nmsWatch(${queryCall}, keys: keys${
|
|
2343
2293
|
qPrivate ? ", principal: actor" : ""
|
|
2344
|
-
}).
|
|
2345
|
-
: `
|
|
2294
|
+
}).asyncMap((result) => ${decodeRows}(result, _ws)))`
|
|
2295
|
+
: `session.nmsWatch(${queryCall}${
|
|
2346
2296
|
qPrivate ? ", principal: actor" : ""
|
|
2347
|
-
}).
|
|
2297
|
+
}).asyncMap((result) => ${decodeRows}(result, _ws))`;
|
|
2298
|
+
if (ordered !== undefined) {
|
|
2299
|
+
const resultType = ordered.limit === 1 ? `${model}?` : `List<${model}>`;
|
|
2300
|
+
const select = ordered.limit === 1 ? "rows.isEmpty ? null : rows.single" : "rows";
|
|
2301
|
+
const live = qOwned
|
|
2302
|
+
? `_readWithOwnedKeys(${qScopesExpr}, (keys) async => ${decodeRows}(await session.nmsQuery(${queryCall}, keys${qPrivate ? ", actor" : ""}), _ws), (row) => row.ref)`
|
|
2303
|
+
: `${decodeRows}(await session.nmsQuery(${queryCall}${keysArg(q.returns)}), _ws)`;
|
|
2304
|
+
const past = qOwned
|
|
2305
|
+
? `_client._readWithOwnedKeys(${qScopesExpr}, (keys) async => ${decodeRows}(await _client.session.nmsQueryAt(moment, ${queryCall}, keys${qPrivate ? ", _client.actor" : ""}), _client._ws), (row) => row.ref)`
|
|
2306
|
+
: `${decodeRows}(await _client.session.nmsQueryAt(moment, ${queryCall}${pastKeysArg(q.returns)}), _client._ws)`;
|
|
2307
|
+
methods.push(
|
|
2308
|
+
` /// Ordered by installed law, limited to ${ordered.limit} visible records.`,
|
|
2309
|
+
` Future<${resultType}> ${m}() async {`,
|
|
2310
|
+
` final rows = await ${live};`,
|
|
2311
|
+
` return ${select};`,
|
|
2312
|
+
` }`,
|
|
2313
|
+
` Stream<${resultType}> watch${cap(camel(q.id))}() => (${nominalWatch}).map((rows) => ${select});`,
|
|
2314
|
+
``,
|
|
2315
|
+
);
|
|
2316
|
+
pastMethods.push(
|
|
2317
|
+
` Future<${resultType}> ${m}() async {`,
|
|
2318
|
+
` final rows = await ${past};`,
|
|
2319
|
+
` return ${select};`,
|
|
2320
|
+
` }`,
|
|
2321
|
+
``,
|
|
2322
|
+
);
|
|
2323
|
+
continue;
|
|
2324
|
+
}
|
|
2348
2325
|
const pageRead = qOwned
|
|
2349
|
-
? `_readPageWithOwnedKeys(${qScopesExpr}, (keys) async =>
|
|
2326
|
+
? `_readPageWithOwnedKeys(${qScopesExpr}, (keys) async => ${decodePage}(await session.nmsQueryPage(${queryCall}, pageSize: pageSize, cursor: cursor, keys: keys${
|
|
2350
2327
|
qPrivate ? ", principal: actor" : ""
|
|
2351
2328
|
}), _ws), (row) => row.ref)`
|
|
2352
|
-
:
|
|
2329
|
+
: `${decodePage}(await session.nmsQueryPage(${queryCall}, pageSize: pageSize, cursor: cursor${
|
|
2353
2330
|
qScopes.length ? `, keys: await _readKeys(${qScopesExpr})` : ""
|
|
2354
2331
|
}${qPrivate ? ", principal: actor" : ""}), _ws)`;
|
|
2355
2332
|
methods.push(
|
|
@@ -2361,10 +2338,10 @@ export function generateDartBridgeClient(
|
|
|
2361
2338
|
` @Deprecated('Whole-result reads scale with result size; use ${m}Page().')`,
|
|
2362
2339
|
` Future<List<${model}>> ${m}({${params}}) async =>`,
|
|
2363
2340
|
qOwned
|
|
2364
|
-
? ` _readWithOwnedKeys(${qScopesExpr}, (keys) async =>
|
|
2341
|
+
? ` _readWithOwnedKeys(${qScopesExpr}, (keys) async => ${decodeRows}(await session.nmsQuery(${queryCall}, keys${
|
|
2365
2342
|
qPrivate ? ", actor" : ""
|
|
2366
2343
|
}), _ws), (row) => row.ref);`
|
|
2367
|
-
: `
|
|
2344
|
+
: ` ${decodeRows}(await session.nmsQuery(${queryCall}${keysArg(
|
|
2368
2345
|
q.returns
|
|
2369
2346
|
)}), _ws);`,
|
|
2370
2347
|
``,
|
|
@@ -2385,10 +2362,10 @@ export function generateDartBridgeClient(
|
|
|
2385
2362
|
` /// Declared query \`${q.id}\` in the verified world at [moment].`,
|
|
2386
2363
|
` Future<List<${model}>> ${m}({${params}}) async =>`,
|
|
2387
2364
|
qOwned
|
|
2388
|
-
? ` _client._readWithOwnedKeys(${qScopesExpr}, (keys) async =>
|
|
2365
|
+
? ` _client._readWithOwnedKeys(${qScopesExpr}, (keys) async => ${decodeRows}(await _client.session.nmsQueryAt(moment, ${queryCall}, keys${
|
|
2389
2366
|
qPrivate ? ", _client.actor" : ""
|
|
2390
2367
|
}), _client._ws), (row) => row.ref);`
|
|
2391
|
-
: `
|
|
2368
|
+
: ` ${decodeRows}(await _client.session.nmsQueryAt(moment, ${queryCall}${pastKeysArg(
|
|
2392
2369
|
q.returns
|
|
2393
2370
|
)}), _client._ws);`,
|
|
2394
2371
|
``
|
|
@@ -2407,7 +2384,7 @@ export function generateDartBridgeClient(
|
|
|
2407
2384
|
` /// Declared spatial index \`${sp.id}\` — rows of \`${sp.of}\` whose \`${sp.on}\` geometry`,
|
|
2408
2385
|
` /// intersects [bbox] (an R*Tree probe on the local projection, never a scan).`,
|
|
2409
2386
|
` Future<List<${model}>> ${m}({required NomosBbox bbox}) async =>`,
|
|
2410
|
-
` _nmsDecode${model}Rows(await
|
|
2387
|
+
` _nmsDecode${model}Rows(await session.nmsSpatialWithinUsda(${dartStr(
|
|
2411
2388
|
sp.id
|
|
2412
2389
|
)}, bbox), _ws);`,
|
|
2413
2390
|
``,
|
|
@@ -2415,7 +2392,7 @@ export function generateDartBridgeClient(
|
|
|
2415
2392
|
` Stream<List<${model}>> watch${cap(
|
|
2416
2393
|
camel(sp.id)
|
|
2417
2394
|
)}({required NomosBbox bbox}) =>`,
|
|
2418
|
-
`
|
|
2395
|
+
` session.nmsWatchSpatialUsda(${dartStr(
|
|
2419
2396
|
sp.id
|
|
2420
2397
|
)}, bbox).map((usda) => _nmsDecode${model}Rows(usda, _ws));`,
|
|
2421
2398
|
``
|
|
@@ -2435,10 +2412,10 @@ export function generateDartBridgeClient(
|
|
|
2435
2412
|
c.by
|
|
2436
2413
|
}\`.\n Future<int> ${m}(${groupType} ${dartKeyParam(
|
|
2437
2414
|
c.by
|
|
2438
|
-
)}) =>
|
|
2415
|
+
)}) => session.nmsCount(${dartStr(c.id)}, ${groupValue});`
|
|
2439
2416
|
: ` /// Declared count \`${
|
|
2440
2417
|
c.id
|
|
2441
|
-
}\` — the maintained O(1) grand total.\n Future<int> ${m}() =>
|
|
2418
|
+
}\` — the maintained O(1) grand total.\n Future<int> ${m}() => session.nmsCount(${dartStr(
|
|
2442
2419
|
c.id
|
|
2443
2420
|
)});`,
|
|
2444
2421
|
``
|
|
@@ -2449,16 +2426,31 @@ export function generateDartBridgeClient(
|
|
|
2449
2426
|
c.id
|
|
2450
2427
|
}\` at [moment].\n Future<int> ${m}(${groupType} ${dartKeyParam(
|
|
2451
2428
|
c.by
|
|
2452
|
-
)}) => _client.
|
|
2429
|
+
)}) => _client.session.nmsCountAt(moment, ${dartStr(
|
|
2453
2430
|
c.id
|
|
2454
2431
|
)}, ${groupValue});`
|
|
2455
2432
|
: ` /// Declared count \`${
|
|
2456
2433
|
c.id
|
|
2457
|
-
}\` at [moment].\n Future<int> ${m}() => _client.
|
|
2434
|
+
}\` at [moment].\n Future<int> ${m}() => _client.session.nmsCountAt(moment, ${dartStr(
|
|
2458
2435
|
c.id
|
|
2459
2436
|
)});`,
|
|
2460
2437
|
``
|
|
2461
2438
|
);
|
|
2439
|
+
methods.push(
|
|
2440
|
+
` /// Observe the maintained tally; unchanged counts emit no new value.`,
|
|
2441
|
+
` Stream<int> watch${cap(camel(c.id))}(${c.by == null ? "" : `${groupType} ${dartKeyParam(c.by)}`}) => session.nmsWatchCount(${dartStr(c.id)}${c.by == null ? "" : `, ${groupValue}`});`,
|
|
2442
|
+
``,
|
|
2443
|
+
);
|
|
2444
|
+
}
|
|
2445
|
+
for (const membership of (mod.exists_ ?? []).map(finishExists)) {
|
|
2446
|
+
const method = safeMethod(lcFirst(camel(membership.id)));
|
|
2447
|
+
const aggregate = aggById.get(membership.of);
|
|
2448
|
+
const parameter = membership.by == null ? ""
|
|
2449
|
+
: `${dartKeyType(aggregate, membership.by, enumDartTypes)} ${dartKeyParam(membership.by)}`;
|
|
2450
|
+
const args = `${dartStr(membership.id)}${membership.by == null ? "" : `, ${dartKeyExpr(aggregate, membership.by)}`}`;
|
|
2451
|
+
methods.push(` /// Declared membership over the maintained count, never a row scan.`,
|
|
2452
|
+
` Future<bool> ${method}(${parameter}) async => (await session.nmsCount(${args})) > 0;`, ``);
|
|
2453
|
+
pastMethods.push(` Future<bool> ${method}(${parameter}) async => (await _client.session.nmsCountAt(moment, ${args})) > 0;`, ``);
|
|
2462
2454
|
}
|
|
2463
2455
|
for (const s of (mod.sums ?? []).map((raw) => finishSum(raw))) {
|
|
2464
2456
|
const m = safeMethod(lcFirst(camel(s.id)));
|
|
@@ -2472,10 +2464,10 @@ export function generateDartBridgeClient(
|
|
|
2472
2464
|
s.by
|
|
2473
2465
|
}\`.\n Future<int> ${m}(${groupType} ${dartKeyParam(
|
|
2474
2466
|
s.by
|
|
2475
|
-
)}) =>
|
|
2467
|
+
)}) => session.nmsSum(${dartStr(s.id)}, ${groupValue});`
|
|
2476
2468
|
: ` /// Declared sum \`${
|
|
2477
2469
|
s.id
|
|
2478
|
-
}\` — the maintained O(1) grand total.\n Future<int> ${m}() =>
|
|
2470
|
+
}\` — the maintained O(1) grand total.\n Future<int> ${m}() => session.nmsSum(${dartStr(
|
|
2479
2471
|
s.id
|
|
2480
2472
|
)});`,
|
|
2481
2473
|
``
|
|
@@ -2486,18 +2478,36 @@ export function generateDartBridgeClient(
|
|
|
2486
2478
|
s.id
|
|
2487
2479
|
}\` at [moment].\n Future<int> ${m}(${groupType} ${dartKeyParam(
|
|
2488
2480
|
s.by
|
|
2489
|
-
)}) => _client.
|
|
2481
|
+
)}) => _client.session.nmsSumAt(moment, ${dartStr(
|
|
2490
2482
|
s.id
|
|
2491
2483
|
)}, ${groupValue});`
|
|
2492
2484
|
: ` /// Declared sum \`${
|
|
2493
2485
|
s.id
|
|
2494
|
-
}\` at [moment].\n Future<int> ${m}() => _client.
|
|
2486
|
+
}\` at [moment].\n Future<int> ${m}() => _client.session.nmsSumAt(moment, ${dartStr(
|
|
2495
2487
|
s.id
|
|
2496
2488
|
)});`,
|
|
2497
2489
|
``
|
|
2498
2490
|
);
|
|
2499
2491
|
}
|
|
2500
2492
|
|
|
2493
|
+
for (const extremum of [...(mod.mins ?? []), ...(mod.maxes ?? [])].map(finishExtremum)) {
|
|
2494
|
+
const method = safeMethod(lcFirst(camel(extremum.id)));
|
|
2495
|
+
const aggregate = aggById.get(extremum.of);
|
|
2496
|
+
const parameter = extremum.by == null ? ""
|
|
2497
|
+
: `${dartKeyType(aggregate, extremum.by, enumDartTypes)} ${dartKeyParam(extremum.by)}`;
|
|
2498
|
+
const args = `${dartStr(extremum.id)}, ${dartStr(extremum.kind)}${extremum.by == null ? "" : `, ${dartKeyExpr(aggregate, extremum.by)}`}`;
|
|
2499
|
+
methods.push(
|
|
2500
|
+
` /// Declared ${extremum.kind}. Null means no contributing member; zero is a value.`,
|
|
2501
|
+
` Future<int?> ${method}(${parameter}) => session.nmsExtremum(${args});`,
|
|
2502
|
+
``,
|
|
2503
|
+
);
|
|
2504
|
+
pastMethods.push(
|
|
2505
|
+
` /// Declared ${extremum.kind} at [moment].`,
|
|
2506
|
+
` Future<int?> ${method}(${parameter}) => _client.session.nmsExtremumAt(moment, ${args});`,
|
|
2507
|
+
``,
|
|
2508
|
+
);
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2501
2511
|
// ── BUSINESS MERGE CONFLICT DX: keep the heterogeneous Nomos index behind an aggregate-specific,
|
|
2502
2512
|
// chained API. A pending conflict is a typed reference to its own `merge(...)` capability; callers
|
|
2503
2513
|
// inspect all versions and produce a merge result rather than choosing a winner.
|
|
@@ -2531,7 +2541,7 @@ export function generateDartBridgeClient(
|
|
|
2531
2541
|
``,
|
|
2532
2542
|
` /// Nomos-internal aggregate-filtered index used only by generated conflict references.`,
|
|
2533
2543
|
` Future<List<${rowClass}>> _pendingConflictRows(String aggregateType) async =>`,
|
|
2534
|
-
` NmsUsdaConflictResult.parse(await
|
|
2544
|
+
` NmsUsdaConflictResult.parse(await session.nmsPendingConflictsUsda(aggregateType))`,
|
|
2535
2545
|
` .rows.map(${rowClass}.fromUsda).toList(growable: false);`,
|
|
2536
2546
|
``
|
|
2537
2547
|
);
|
|
@@ -2750,7 +2760,7 @@ export function generateDartBridgeClient(
|
|
|
2750
2760
|
``,
|
|
2751
2761
|
` Future<${summaryClass}> summary() async {`,
|
|
2752
2762
|
` final summary = NmsUsdaConflictSummaryResult.parse(`,
|
|
2753
|
-
` await _client.
|
|
2763
|
+
` await _client.session.nmsPendingConflictSummaryUsda());`,
|
|
2754
2764
|
` int count(String aggregatePath) {`,
|
|
2755
2765
|
` for (final entry in summary.byAggregate) {`,
|
|
2756
2766
|
` if (entry.aggregatePath == aggregatePath) return entry.count;`,
|
|
@@ -3014,27 +3024,27 @@ export function generateDartBridgeClient(
|
|
|
3014
3024
|
const nominalByIdWatch = aScopes.length
|
|
3015
3025
|
? `Stream.fromFuture(_readKeys(${aScopesExpr}${
|
|
3016
3026
|
aOwned ? `, [(type: ${dartStr(runtimeType)}, id: id)]` : ""
|
|
3017
|
-
})).asyncExpand((keys) =>
|
|
3027
|
+
})).asyncExpand((keys) => session.nmsWatchByIdUsda(${dartStr(
|
|
3018
3028
|
runtimeType
|
|
3019
3029
|
)}, id, keys: keys${
|
|
3020
3030
|
aPrivate ? ", principal: actor" : ""
|
|
3021
3031
|
}).map((usda) => _nmsDecode${model}Rows(usda, _ws)))`
|
|
3022
|
-
: `
|
|
3032
|
+
: `session.nmsWatchByIdUsda(${dartStr(runtimeType)}, id${
|
|
3023
3033
|
aPrivate ? ", principal: actor" : ""
|
|
3024
3034
|
}).map((usda) => _nmsDecode${model}Rows(usda, _ws))`;
|
|
3025
3035
|
const nominalByTypeWatch = aOwned
|
|
3026
|
-
? `
|
|
3036
|
+
? `session.nmsWatchByTypeUsda(${dartStr(runtimeType)}${
|
|
3027
3037
|
aPrivate ? ", principal: actor" : ""
|
|
3028
|
-
}).asyncMap((
|
|
3038
|
+
}).asyncMap((usda) => _readWithOwnedKeys(${aScopesExpr}, (keys) async => _nmsDecode${model}Rows(await session.nmsQueryByTypeUsda(${dartStr(
|
|
3029
3039
|
runtimeType
|
|
3030
|
-
)}, keys${aPrivate ? ", actor" : ""}), _ws), (row) => row.ref))`
|
|
3040
|
+
)}, keys${aPrivate ? ", actor" : ""}), _ws), (row) => row.ref, initial: _nmsDecode${model}Rows(usda, _ws)))`
|
|
3031
3041
|
: aScopes.length
|
|
3032
|
-
? `Stream.fromFuture(_readKeys(${aScopesExpr})).asyncExpand((keys) =>
|
|
3042
|
+
? `Stream.fromFuture(_readKeys(${aScopesExpr})).asyncExpand((keys) => session.nmsWatchByTypeUsda(${dartStr(
|
|
3033
3043
|
runtimeType
|
|
3034
3044
|
)}, keys: keys${
|
|
3035
3045
|
aPrivate ? ", principal: actor" : ""
|
|
3036
3046
|
}).map((usda) => _nmsDecode${model}Rows(usda, _ws)))`
|
|
3037
|
-
: `
|
|
3047
|
+
: `session.nmsWatchByTypeUsda(${dartStr(runtimeType)}${
|
|
3038
3048
|
aPrivate ? ", principal: actor" : ""
|
|
3039
3049
|
}).map((usda) => _nmsDecode${model}Rows(usda, _ws))`;
|
|
3040
3050
|
methods.push(
|
|
@@ -3044,7 +3054,7 @@ export function generateDartBridgeClient(
|
|
|
3044
3054
|
: ""
|
|
3045
3055
|
}`,
|
|
3046
3056
|
` Future<List<${model}>> ${safeMethod(`${lc}ById`)}(String id) async =>`,
|
|
3047
|
-
` _nmsDecode${model}Rows(await
|
|
3057
|
+
` _nmsDecode${model}Rows(await session.nmsQueryByIdUsda(${dartStr(
|
|
3048
3058
|
runtimeType
|
|
3049
3059
|
)}, id${byIdKeys}), _ws);`,
|
|
3050
3060
|
``,
|
|
@@ -3055,10 +3065,10 @@ export function generateDartBridgeClient(
|
|
|
3055
3065
|
` /// Every ${agg.id} (the type-index probe — O(result), not a scan).`,
|
|
3056
3066
|
` Future<List<${model}>> ${safeMethod(`list${Cap}s`)}() async =>`,
|
|
3057
3067
|
aOwned
|
|
3058
|
-
? ` _readWithOwnedKeys(${aScopesExpr}, (keys) async => _nmsDecode${model}Rows(await
|
|
3068
|
+
? ` _readWithOwnedKeys(${aScopesExpr}, (keys) async => _nmsDecode${model}Rows(await session.nmsQueryByTypeUsda(${dartStr(
|
|
3059
3069
|
runtimeType
|
|
3060
3070
|
)}, keys${aPrivate ? ", actor" : ""}), _ws), (row) => row.ref);`
|
|
3061
|
-
: ` _nmsDecode${model}Rows(await
|
|
3071
|
+
: ` _nmsDecode${model}Rows(await session.nmsQueryByTypeUsda(${dartStr(
|
|
3062
3072
|
runtimeType
|
|
3063
3073
|
)}${keysArg(agg.id)}), _ws);`,
|
|
3064
3074
|
``,
|
|
@@ -3070,184 +3080,25 @@ export function generateDartBridgeClient(
|
|
|
3070
3080
|
pastMethods.push(
|
|
3071
3081
|
` /// Read one ${agg.id} by aggregate id in the verified world at [moment].`,
|
|
3072
3082
|
` Future<List<${model}>> ${safeMethod(`${lc}ById`)}(String id) async =>`,
|
|
3073
|
-
` _nmsDecode${model}Rows(await _client.
|
|
3083
|
+
` _nmsDecode${model}Rows(await _client.session.nmsQueryByIdAtUsda(moment, ${dartStr(
|
|
3074
3084
|
runtimeType
|
|
3075
3085
|
)}, id${pastByIdKeys}), _client._ws);`,
|
|
3076
3086
|
``,
|
|
3077
3087
|
` /// Every ${agg.id} in the verified world at [moment].`,
|
|
3078
3088
|
` Future<List<${model}>> ${safeMethod(`list${Cap}s`)}() async =>`,
|
|
3079
3089
|
aOwned
|
|
3080
|
-
? ` _client._readWithOwnedKeys(${aScopesExpr}, (keys) async => _nmsDecode${model}Rows(await _client.
|
|
3090
|
+
? ` _client._readWithOwnedKeys(${aScopesExpr}, (keys) async => _nmsDecode${model}Rows(await _client.session.nmsQueryByTypeAtUsda(moment, ${dartStr(
|
|
3081
3091
|
runtimeType
|
|
3082
3092
|
)}, keys${
|
|
3083
3093
|
aPrivate ? ", _client.actor" : ""
|
|
3084
3094
|
}), _client._ws), (row) => row.ref);`
|
|
3085
|
-
: ` _nmsDecode${model}Rows(await _client.
|
|
3095
|
+
: ` _nmsDecode${model}Rows(await _client.session.nmsQueryByTypeAtUsda(moment, ${dartStr(
|
|
3086
3096
|
runtimeType
|
|
3087
3097
|
)}${pastKeysArg(agg.id)}), _client._ws);`,
|
|
3088
3098
|
``
|
|
3089
3099
|
);
|
|
3090
3100
|
}
|
|
3091
3101
|
|
|
3092
|
-
if (opts.emitActivity === true)
|
|
3093
|
-
methods.push(
|
|
3094
|
-
` /// Adopt THIS generated model. Nomos proves it against current history; a deliberate`,
|
|
3095
|
-
` /// difference returns a decision whose accept(reason) re-proves and records the reason.`,
|
|
3096
|
-
` NomosModel get model => NomosModel(_adoptGeneratedModel, _restorePreviousGeneratedModel);`,
|
|
3097
|
-
``,
|
|
3098
|
-
` NomosModelReview _nomosModelReview(ModelLifecycleResponse result) {`,
|
|
3099
|
-
` final report = result.hasReview() ? result.review : null;`,
|
|
3100
|
-
` return NomosModelReview(`,
|
|
3101
|
-
` checkedActions: report?.checkedActions.toInt() ?? 0,`,
|
|
3102
|
-
` candidateActions: report?.candidateActions.toInt() ?? 0,`,
|
|
3103
|
-
` sameOutcome: report?.hasSameOutcome() == true ? report!.sameOutcome : null,`,
|
|
3104
|
-
` differences: [`,
|
|
3105
|
-
` for (final difference in report?.differences ?? const [])`,
|
|
3106
|
-
` NomosModelDifference(`,
|
|
3107
|
-
` kind: switch (difference.kind) {`,
|
|
3108
|
-
` ModelDifferenceKind.MODEL_DIFFERENCE_KIND_RULES => NomosModelDifferenceKind.rules,`,
|
|
3109
|
-
` ModelDifferenceKind.MODEL_DIFFERENCE_KIND_OUTCOME => NomosModelDifferenceKind.outcome,`,
|
|
3110
|
-
` ModelDifferenceKind.MODEL_DIFFERENCE_KIND_EVIDENCE => NomosModelDifferenceKind.evidence,`,
|
|
3111
|
-
` _ => NomosModelDifferenceKind.rules,`,
|
|
3112
|
-
` },`,
|
|
3113
|
-
` area: difference.hasArea() ? difference.area : null,`,
|
|
3114
|
-
` action: difference.hasAction() ? difference.action : null,`,
|
|
3115
|
-
` summary: difference.summary,`,
|
|
3116
|
-
` ),`,
|
|
3117
|
-
` ],`,
|
|
3118
|
-
` );`,
|
|
3119
|
-
` }`,
|
|
3120
|
-
``,
|
|
3121
|
-
...(authenticationRecovery === undefined
|
|
3122
|
-
? [` Future<NomosModelAdoption> _adoptGeneratedModel([String? because]) async {`]
|
|
3123
|
-
: [
|
|
3124
|
-
` Future<NomosModelAdoption> _adoptGeneratedModel([String? because]) =>`,
|
|
3125
|
-
` _adoptGeneratedModelAttempt(because, false);`,
|
|
3126
|
-
` Future<NomosModelAdoption> _adoptGeneratedModelAttempt(`,
|
|
3127
|
-
` String? because, bool recoveredProviderEpoch) async {`,
|
|
3128
|
-
]),
|
|
3129
|
-
` final result = await bridge.nomosFrameworkAdoptGeneratedModel(`,
|
|
3130
|
-
` domain: ${dartStr(
|
|
3131
|
-
domain
|
|
3132
|
-
)}, candidateHash: domainHash, because: because);`,
|
|
3133
|
-
` final review = _nomosModelReview(result);`,
|
|
3134
|
-
` final stage = result.stage;`,
|
|
3135
|
-
...(authenticationRecovery === undefined
|
|
3136
|
-
? []
|
|
3137
|
-
: [
|
|
3138
|
-
` if (!result.accepted && !recoveredProviderEpoch) {`,
|
|
3139
|
-
` final posture = await bridge.nmsAuthenticationPosture(principal: actor);`,
|
|
3140
|
-
` if (posture.providerToken == NomosProviderTokenVerification.noMatchingKey) {`,
|
|
3141
|
-
` print('[nomos-model-recovery] local ${domain} posture=' + posture.providerToken.name);`,
|
|
3142
|
-
` await ${safeMethod(
|
|
3143
|
-
authenticationRecovery.id
|
|
3144
|
-
)}(const ${dartActionInputClassName(authenticationRecovery)}());`,
|
|
3145
|
-
` await bridge.nmsAwaitAuthenticationReady(principal: actor);`,
|
|
3146
|
-
` return _adoptGeneratedModelAttempt(because, true);`,
|
|
3147
|
-
` }`,
|
|
3148
|
-
` }`,
|
|
3149
|
-
]),
|
|
3150
|
-
` if ((stage == ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_PROMOTED ||`,
|
|
3151
|
-
` stage == ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_ALREADY_CURRENT) && result.accepted) {`,
|
|
3152
|
-
` return NomosModelAdoption.adopted(`,
|
|
3153
|
-
` summary: stage == ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_PROMOTED`,
|
|
3154
|
-
` ? 'Nomos proved this model against current history and made it active.'`,
|
|
3155
|
-
` : 'This workspace already runs this model or a server-side successor.',`,
|
|
3156
|
-
` review: review);`,
|
|
3157
|
-
` }`,
|
|
3158
|
-
...(opts.lawAssetKey === undefined
|
|
3159
|
-
? []
|
|
3160
|
-
: [
|
|
3161
|
-
` if (stage == ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_STAGING_REQUIRED) {`,
|
|
3162
|
-
` return NomosModelAdoption.needsStaging(`,
|
|
3163
|
-
` summary: 'This workspace is running an older model. Stage this generated USDA candidate through the signed workspace gate before reviewing it.',`,
|
|
3164
|
-
` review: review,`,
|
|
3165
|
-
` stage: () async {`,
|
|
3166
|
-
` await _stageGeneratedModel();`,
|
|
3167
|
-
` return _adoptGeneratedModel();`,
|
|
3168
|
-
` },`,
|
|
3169
|
-
` );`,
|
|
3170
|
-
` }`,
|
|
3171
|
-
]),
|
|
3172
|
-
` if (stage == ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_ACCEPTANCE_REQUIRED) {`,
|
|
3173
|
-
` return NomosModelAdoption.needsDecision(`,
|
|
3174
|
-
` summary: 'This model would change prior business outcomes. Review the differences and record why that is intended.',`,
|
|
3175
|
-
` review: review, accept: (reason) => _adoptGeneratedModel(reason));`,
|
|
3176
|
-
` }`,
|
|
3177
|
-
` final rawError = result.hasMessage() ? result.message.trim() : '';`,
|
|
3178
|
-
` final summary = rawError.isNotEmpty`,
|
|
3179
|
-
` ? rawError`,
|
|
3180
|
-
` : stage == ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_IDENTITY_REQUIRED`,
|
|
3181
|
-
` ? 'Sign in before adopting this model so the decision is accountable.'`,
|
|
3182
|
-
` : 'The workspace changed or refused this adoption. Nothing changed; ask Nomos to try again.';`,
|
|
3183
|
-
` return NomosModelAdoption.blocked(summary: summary, review: review);`,
|
|
3184
|
-
` }`,
|
|
3185
|
-
``,
|
|
3186
|
-
...(opts.lawAssetKey === undefined
|
|
3187
|
-
? []
|
|
3188
|
-
: [
|
|
3189
|
-
` Future<void> _stageGeneratedModel() async {`,
|
|
3190
|
-
` final archive = await rootBundle.load(${dartStr(
|
|
3191
|
-
opts.lawAssetKey
|
|
3192
|
-
)});`,
|
|
3193
|
-
` Future<void> attempt() => bridge.nomosInternalStageGeneratedModel(`,
|
|
3194
|
-
` domain: ${dartStr(domain)},`,
|
|
3195
|
-
` candidateHash: domainHash,`,
|
|
3196
|
-
` lawUsdz: archive.buffer.asUint8List(`,
|
|
3197
|
-
` archive.offsetInBytes, archive.lengthInBytes),`,
|
|
3198
|
-
` );`,
|
|
3199
|
-
...(authenticationRecovery === undefined
|
|
3200
|
-
? [` await attempt();`]
|
|
3201
|
-
: [
|
|
3202
|
-
` try {`,
|
|
3203
|
-
` await attempt();`,
|
|
3204
|
-
` } on NomosModelStageFailure {`,
|
|
3205
|
-
` final posture = await bridge.nmsAuthenticationPosture(principal: actor);`,
|
|
3206
|
-
` print('[nomos-model-recovery] local ${domain} posture=' + posture.providerToken.name);`,
|
|
3207
|
-
` if (posture.providerToken != NomosProviderTokenVerification.noMatchingKey) rethrow;`,
|
|
3208
|
-
` await ${safeMethod(
|
|
3209
|
-
authenticationRecovery.id
|
|
3210
|
-
)}(const ${dartActionInputClassName(
|
|
3211
|
-
authenticationRecovery
|
|
3212
|
-
)}());`,
|
|
3213
|
-
` await bridge.nmsAwaitAuthenticationReady(principal: actor);`,
|
|
3214
|
-
` await attempt();`,
|
|
3215
|
-
` }`,
|
|
3216
|
-
]),
|
|
3217
|
-
` }`,
|
|
3218
|
-
``,
|
|
3219
|
-
]),
|
|
3220
|
-
` Future<NomosModelRestoration> _restorePreviousGeneratedModel([String? because]) async {`,
|
|
3221
|
-
` final result = await bridge.nomosFrameworkRestorePreviousGeneratedModel(`,
|
|
3222
|
-
` domain: ${dartStr(
|
|
3223
|
-
domain
|
|
3224
|
-
)}, currentHash: domainHash, because: because);`,
|
|
3225
|
-
` final review = _nomosModelReview(result);`,
|
|
3226
|
-
` final stage = result.stage;`,
|
|
3227
|
-
` if (stage == ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_RESTORED && result.accepted) {`,
|
|
3228
|
-
` return NomosModelRestoration.restored(`,
|
|
3229
|
-
` summary: 'Nomos re-proved current history and restored the previous model.', review: review);`,
|
|
3230
|
-
` }`,
|
|
3231
|
-
` if (stage == ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_ACCEPTANCE_REQUIRED) {`,
|
|
3232
|
-
` return NomosModelRestoration.needsDecision(`,
|
|
3233
|
-
` summary: 'Restoring the previous model changes which rules govern future work. Review the effects and record why restoration is intended.',`,
|
|
3234
|
-
` review: review, accept: (reason) => _restorePreviousGeneratedModel(reason));`,
|
|
3235
|
-
` }`,
|
|
3236
|
-
` final error = result.hasMessage() ? result.message : '';`,
|
|
3237
|
-
` final summary = stage == ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_IDENTITY_REQUIRED`,
|
|
3238
|
-
` ? 'Sign in before restoring a model so the decision is accountable.'`,
|
|
3239
|
-
` : error.contains('restore-no-previous')`,
|
|
3240
|
-
` ? 'This is the first model for this business; there is no previous model to restore.'`,
|
|
3241
|
-
` : error.contains('restore-current-changed')`,
|
|
3242
|
-
` ? 'The current model changed before restoration could finish. Nothing changed; ask Nomos to review again.'`,
|
|
3243
|
-
` : error.isNotEmpty`,
|
|
3244
|
-
` ? error`,
|
|
3245
|
-
` : 'The workspace refused restoration. Nothing changed and the current model remains active.';`,
|
|
3246
|
-
` return NomosModelRestoration.blocked(summary: summary, review: review);`,
|
|
3247
|
-
` }`,
|
|
3248
|
-
``
|
|
3249
|
-
);
|
|
3250
|
-
|
|
3251
3102
|
const pastClass = `${className}Past`;
|
|
3252
3103
|
const atClass = `${className}At`;
|
|
3253
3104
|
methods.push(
|
|
@@ -3262,7 +3113,7 @@ export function generateDartBridgeClient(
|
|
|
3262
3113
|
` const ${pastClass}(this._client);`,
|
|
3263
3114
|
``,
|
|
3264
3115
|
` Future<List<NomosMoment>> moments({int limit = 100}) async {`,
|
|
3265
|
-
` final moments = await _client.
|
|
3116
|
+
` final moments = await _client.session.moments(limit: limit);`,
|
|
3266
3117
|
` const actions = <String>{${[
|
|
3267
3118
|
...allDirs.map((directive) => directive.id),
|
|
3268
3119
|
...(correctionActions.length > 0 ? [BUSINESS_CORRECTION_DIRECTIVE] : []),
|
|
@@ -3295,7 +3146,7 @@ export function generateDartBridgeClient(
|
|
|
3295
3146
|
// ── REF-TRAVERSAL ACCESSORS (dart_codegen_parity.md P2 + §2a follow-on — ref ergonomics) ──
|
|
3296
3147
|
// For every reference field on a read model, emit a companion extension method that resolves the
|
|
3297
3148
|
// stored locator to the actual target row, composed ONLY from surface that already exists (no new
|
|
3298
|
-
// read path, no new
|
|
3149
|
+
// read path, no new session op). THREE kinds, one grammar (`<Model>Refs on <Model>`):
|
|
3299
3150
|
// 1. SAME-DOMAIN `t.ref(Target)` (target in THIS module) — resolver takes THIS client, dispatches
|
|
3300
3151
|
// to its own `<target>ById` accessor. (The #72 original.)
|
|
3301
3152
|
// 2. CROSS-DOMAIN same-workspace `t.ref(Target)` (target in ANOTHER domain of the package) — the
|
|
@@ -3436,46 +3287,9 @@ export function generateDartBridgeClient(
|
|
|
3436
3287
|
``
|
|
3437
3288
|
);
|
|
3438
3289
|
}
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
// The resolver returns the target's CONCRETE class. We can
|
|
3443
|
-
// only reference it when it is reachable from this file: SAME-domain (already in the imported types),
|
|
3444
|
-
// or a CROSS-DOMAIN concrete target in the package (import its sibling `<name>.dart` `show`-limited).
|
|
3445
|
-
// A contract target (its DTO lives in the shared contracts file) or an unmapped target is left as the
|
|
3446
|
-
// raw `ForeignRef<T>` field — no resolver, no dangling type reference.
|
|
3447
|
-
if (fr.targetIsContract === true) continue;
|
|
3448
|
-
const owner = pkgDomains[targetType];
|
|
3449
|
-
const targetInThisDomain =
|
|
3450
|
-
aggById.has(targetType) || owner?.name === thisDomainName;
|
|
3451
|
-
if (!targetInThisDomain) {
|
|
3452
|
-
if (owner === undefined) continue; // target not in this package — unreachable, skip the resolver
|
|
3453
|
-
// LAYERED-packages mode: the sibling domain's TYPES file lives in the TYPES package, not
|
|
3454
|
-
// beside this client file — a relative `<name>.dart` import points at a nonexistent path in
|
|
3455
|
-
// the client package (the co2 0.75.0 regression). The types-barrel import above already
|
|
3456
|
-
// re-exports every generated concrete class, so the extra import is only needed FLAT.
|
|
3457
|
-
if (opts.typesImportUri === undefined)
|
|
3458
|
-
addImport(`${owner.name}.dart`, concreteClassName(targetType));
|
|
3459
|
-
}
|
|
3460
|
-
const targetConcrete = concreteClassName(targetType);
|
|
3461
|
-
const member = dartMemberName(fieldName);
|
|
3462
|
-
const memberValue = admitsNull(f) ? `${member}.valueOrNull` : member;
|
|
3463
|
-
// The stored locator member is a typed `ForeignRef<Target>?` getter, so the resolver takes a
|
|
3464
|
-
// `remote…` name to avoid colliding with it (and to read as "the far side of the reference").
|
|
3465
|
-
const method = safeMethod(`remote${cap(camel(member))}`);
|
|
3466
|
-
lines.push(
|
|
3467
|
-
` /// Resolve \`${fieldName}\` (${agg.id}.${fieldName} -> ${targetType} @ another workspace, a`,
|
|
3468
|
-
` /// \`t.foreignRef\` locator) over the session-bound multi-workspace plane. The generated`,
|
|
3469
|
-
` /// implementation opens the foreign workspace on demand; tenant code sees only this business method.`,
|
|
3470
|
-
` /// Null locator (absent / empty id or workspace) ⇒ null.`,
|
|
3471
|
-
` Future<${targetConcrete}?> ${method}(NomosEngine engine, {String? cloud}) {`,
|
|
3472
|
-
` final ref = ${memberValue};`,
|
|
3473
|
-
` if (ref == null) return Future<${targetConcrete}?>.value(null);`,
|
|
3474
|
-
` return NmsInternalForeignRefs.resolve(ref, engine.foreignReader(cloud: cloud));`,
|
|
3475
|
-
` }`,
|
|
3476
|
-
``
|
|
3477
|
-
);
|
|
3478
|
-
}
|
|
3290
|
+
// Cross-workspace resolution belongs to the stateless application facade,
|
|
3291
|
+
// which receives Peer Office's binding. Read-model values never accept a
|
|
3292
|
+
// runtime/reception object or open custody themselves.
|
|
3479
3293
|
lines.push(`}`);
|
|
3480
3294
|
refExtensions.push(lines.join("\n"));
|
|
3481
3295
|
}
|
|
@@ -3488,18 +3302,32 @@ export function generateDartBridgeClient(
|
|
|
3488
3302
|
` /// committed intent; a directive`,
|
|
3489
3303
|
` /// outside this generated business package is dropped. Cancel the subscription to stop.`,
|
|
3490
3304
|
` /// A bounded recent activity feed. [limit] is required and kernel-capped.`,
|
|
3491
|
-
` Stream<List<ActivityEvent>> watchRecentActivity({required int limit})
|
|
3492
|
-
`
|
|
3493
|
-
`
|
|
3494
|
-
`
|
|
3495
|
-
`
|
|
3305
|
+
` Stream<List<ActivityEvent>> watchRecentActivity({required int limit}) async* {`,
|
|
3306
|
+
` yield await recentActivity(limit: limit);`,
|
|
3307
|
+
` await for (final _ in session.syncEvents) {`,
|
|
3308
|
+
` yield await recentActivity(limit: limit);`,
|
|
3309
|
+
` }`,
|
|
3310
|
+
` }`,
|
|
3496
3311
|
``,
|
|
3497
3312
|
` /// A bounded one-shot recent activity feed. [limit] is required and kernel-capped.`,
|
|
3498
|
-
` Future<List<ActivityEvent>> recentActivity({String? base, required int limit}) async
|
|
3499
|
-
`
|
|
3500
|
-
`
|
|
3501
|
-
`
|
|
3502
|
-
`
|
|
3313
|
+
` Future<List<ActivityEvent>> recentActivity({String? base, required int limit}) async {`,
|
|
3314
|
+
` if (base != null) {`,
|
|
3315
|
+
` throw UnsupportedError('Historic activity cursors need a nominal Runtime v2 contract.');`,
|
|
3316
|
+
` }`,
|
|
3317
|
+
` return (await session.moments(limit: limit)).map((moment) {`,
|
|
3318
|
+
` final action = moment.action ?? 'recordedChange';`,
|
|
3319
|
+
` final eventDomain = moment.domain ?? ${dartStr(domain)};`,
|
|
3320
|
+
` final kind = '\$eventDomain.\$action';`,
|
|
3321
|
+
` return ActivityEvent(`,
|
|
3322
|
+
` eventId: moment.id, kind: kind, performedBy: moment.performedBy ?? '',`,
|
|
3323
|
+
` occurredAt: moment.occurredAt?.toUtc().toIso8601String() ?? '',`,
|
|
3324
|
+
` title: action, message: 'Recorded \$action in \$eventDomain',`,
|
|
3325
|
+
` titleKey: 'activity.\$kind.title', messageKey: 'activity.\$kind.message',`,
|
|
3326
|
+
` params: const <String, String>{}, refs: const <String, ActivityRef>{},`,
|
|
3327
|
+
` severity: ActivitySeverity.info, domain: eventDomain, directiveId: action,`,
|
|
3328
|
+
` );`,
|
|
3329
|
+
` }).toList(growable: false);`,
|
|
3330
|
+
` }`,
|
|
3503
3331
|
``,
|
|
3504
3332
|
` @Deprecated('Reconstructs ledger history. Use recentActivity with an explicit bounded limit, or a DSL managed count for quantities.')`,
|
|
3505
3333
|
` Future<List<ActivityEvent>> activityLog({String? base, int? limit}) =>`,
|
|
@@ -3515,20 +3343,21 @@ export function generateDartBridgeClient(
|
|
|
3515
3343
|
` NomosDescribeSection section = NomosDescribeSection.root,`,
|
|
3516
3344
|
` String? since, String? performedBy, String? category, int? limit,`,
|
|
3517
3345
|
` }) async {`,
|
|
3518
|
-
`
|
|
3519
|
-
` var events = raw`,
|
|
3520
|
-
` .map((r) => renderActivity(r.cast<String, dynamic>()))`,
|
|
3521
|
-
` .whereType<ActivityEvent>()`,
|
|
3522
|
-
` .toList();`,
|
|
3346
|
+
` var events = await recentActivity(limit: limit ?? 50);`,
|
|
3523
3347
|
` if (performedBy != null) events = events.where((e) => e.performedBy == performedBy).toList();`,
|
|
3524
3348
|
` if (category != null) events = events.where((e) => e.category == category).toList();`,
|
|
3525
3349
|
` if (since != null) events = events.where((e) => e.occurredAt.compareTo(since) >= 0).toList();`,
|
|
3526
3350
|
` final narrative = activityNarrative(events);`,
|
|
3527
3351
|
` var organisation = const NomosOrganisationDescription(complete: false, children: []);`,
|
|
3528
3352
|
` try {`,
|
|
3529
|
-
` final children = (await
|
|
3530
|
-
` final workspace = child
|
|
3531
|
-
` final status = child
|
|
3353
|
+
` final children = (await session.nomosFrameworkChildWorkspaces()).map((child) {`,
|
|
3354
|
+
` final workspace = child.workspace;`,
|
|
3355
|
+
` final status = switch (child.status) {`,
|
|
3356
|
+
` ChildWorkspaceStatus.CHILD_WORKSPACE_STATUS_ACTIVE => 'active',`,
|
|
3357
|
+
` ChildWorkspaceStatus.CHILD_WORKSPACE_STATUS_RETIRED => 'retired',`,
|
|
3358
|
+
` ChildWorkspaceStatus.CHILD_WORKSPACE_STATUS_RECLAIMED => 'reclaimed',`,
|
|
3359
|
+
` _ => 'unknown',`,
|
|
3360
|
+
` };`,
|
|
3532
3361
|
` final summary = status == 'active'`,
|
|
3533
3362
|
` ? 'This part of the organisation is active. Follow its generated description to continue.'`,
|
|
3534
3363
|
` : status == 'retired'`,
|
|
@@ -3537,7 +3366,7 @@ export function generateDartBridgeClient(
|
|
|
3537
3366
|
` ? "This part of the organisation was reclaimed. Its birth remains part of this workspace's history."`,
|
|
3538
3367
|
` : 'This part of the organisation has a newer lifecycle this client does not understand. Its link remains visible.';`,
|
|
3539
3368
|
` return NomosDescribeChild(`,
|
|
3540
|
-
` workspace: workspace, status: status, bornAt: child
|
|
3369
|
+
` workspace: workspace, status: status, bornAt: child.hasBornAt() ? child.bornAt : null, label: workspace,`,
|
|
3541
3370
|
` question: 'What does this part of the organisation do, and what has happened there?', summary: summary);`,
|
|
3542
3371
|
` }).where((child) => child.workspace.isNotEmpty).toList();`,
|
|
3543
3372
|
` organisation = NomosOrganisationDescription(complete: children.every((child) => child.status != 'unknown'), children: children);`,
|
|
@@ -3594,23 +3423,11 @@ export function generateDartBridgeClient(
|
|
|
3594
3423
|
` for (final rawAggregate in ((model['aggregateTypes'] as List?) ?? const [])) {`,
|
|
3595
3424
|
` final aggregate = (rawAggregate as Map).cast<String, dynamic>();`,
|
|
3596
3425
|
` final type = aggregate['type'] as String;`,
|
|
3597
|
-
` final queryType = aggregate['queryType'] as String;`,
|
|
3598
3426
|
` final label = aggregate['label'] as String;`,
|
|
3599
|
-
`
|
|
3600
|
-
`
|
|
3601
|
-
`
|
|
3602
|
-
`
|
|
3603
|
-
` final exact = aggregate['audience'] == 'public' || rows.isNotEmpty;`,
|
|
3604
|
-
` items.add(NomosDescribeItem(`,
|
|
3605
|
-
` kind: 'current', id: '\${aggregate['domain']}.\$type', label: label,`,
|
|
3606
|
-
` summary: exact ? '\${rows.length} \$label record\${rows.length == 1 ? '' : 's'} visible now.' : 'No \$label records are visible to this session.',`,
|
|
3607
|
-
` details: {'domain': aggregate['domain'], 'type': type, 'audience': aggregate['audience'], if (exact) 'count': rows.length else 'status': 'none-visible'}, refs: refs));`,
|
|
3608
|
-
` } catch (_) {`,
|
|
3609
|
-
` items.add(NomosDescribeItem(`,
|
|
3610
|
-
` kind: 'current', id: '\${aggregate['domain']}.\$type', label: label,`,
|
|
3611
|
-
` summary: '\$label exists in the model, but this session cannot read its current records.',`,
|
|
3612
|
-
` details: {'domain': aggregate['domain'], 'type': type, 'audience': aggregate['audience'], 'status': 'unavailable'}));`,
|
|
3613
|
-
` }`,
|
|
3427
|
+
` items.add(NomosDescribeItem(`,
|
|
3428
|
+
` kind: 'current', id: '\${aggregate['domain']}.\$type', label: label,`,
|
|
3429
|
+
` summary: '\$label records are read through the generated typed application API.',`,
|
|
3430
|
+
` details: {'domain': aggregate['domain'], 'type': type, 'audience': aggregate['audience'], 'status': 'typed-read'}));`,
|
|
3614
3431
|
` }`,
|
|
3615
3432
|
` } else if (section == NomosDescribeSection.history) {`,
|
|
3616
3433
|
` title = 'Verified business history';`,
|
|
@@ -3657,7 +3474,7 @@ export function generateDartBridgeClient(
|
|
|
3657
3474
|
` return null;`,
|
|
3658
3475
|
` }`,
|
|
3659
3476
|
` final pendingConflicts = NmsUsdaConflictResult.parse(`,
|
|
3660
|
-
` await
|
|
3477
|
+
` await session.nmsPendingConflictsUsda(null));`,
|
|
3661
3478
|
` for (final conflict in pendingConflicts.rows) {`,
|
|
3662
3479
|
` final aggregatePath = conflict.relationship('nomos:type');`,
|
|
3663
3480
|
` final fieldPath = conflict.relationship('nomos:field');`,
|
|
@@ -3693,7 +3510,7 @@ export function generateDartBridgeClient(
|
|
|
3693
3510
|
` }`,
|
|
3694
3511
|
` final modelPageItems = ((((model['pages'] as Map)['model'] as Map)['items'] as List?) ?? const [])`,
|
|
3695
3512
|
` .map((raw) => (raw as Map).cast<String, dynamic>()).where((item) => item['kind'] == 'verb').toList();`,
|
|
3696
|
-
` for (final entry in await
|
|
3513
|
+
` for (final entry in await session.deadLetters()) {`,
|
|
3697
3514
|
` if (!entry.hasDomain() || !entry.hasDirective()) continue;`,
|
|
3698
3515
|
` final domain = entry.domain; final directive = entry.directive;`,
|
|
3699
3516
|
` Map<String, dynamic>? action;`,
|
|
@@ -3714,7 +3531,7 @@ export function generateDartBridgeClient(
|
|
|
3714
3531
|
` items = [`,
|
|
3715
3532
|
` NomosDescribeItem(kind: 'evidence', id: 'workspace', label: 'Workspace', summary: _ws, details: {'workspace': _ws}),`,
|
|
3716
3533
|
` NomosDescribeItem(kind: 'evidence', id: 'law', label: 'Generated law', summary: domainHash, details: {'domainHash': domainHash}),`,
|
|
3717
|
-
` NomosDescribeItem(kind: 'evidence', id: 'reader', label: 'Verified reader', summary: this.actor ??
|
|
3534
|
+
` NomosDescribeItem(kind: 'evidence', id: 'reader', label: 'Verified reader', summary: this.actor ?? 'anonymous', details: {'actor': this.actor}),`,
|
|
3718
3535
|
` if (latest != null) NomosDescribeItem(kind: 'evidence', id: latest.eventId, label: 'Latest verified moment', summary: latest.eventId,`,
|
|
3719
3536
|
` details: {'occurredAt': latest.occurredAt, 'performedBy': latest.performedBy, 'domain': latest.domain, 'kind': latest.kind}),`,
|
|
3720
3537
|
` ];`,
|
|
@@ -3727,10 +3544,7 @@ export function generateDartBridgeClient(
|
|
|
3727
3544
|
` /// NARRATIVE for ONE thing: the story of the aggregate [aggregateId] — events whose declared refs`,
|
|
3728
3545
|
` /// point at it (only directives declaring a ref to the aggregate appear in its story) + a transcript.`,
|
|
3729
3546
|
` Future<ActivityNarrative> describeHistory(String aggregateId, {int? limit}) async {`,
|
|
3730
|
-
` final
|
|
3731
|
-
` final events = raw`,
|
|
3732
|
-
` .map((r) => renderActivity(r.cast<String, dynamic>()))`,
|
|
3733
|
-
` .whereType<ActivityEvent>()`,
|
|
3547
|
+
` final events = (await recentActivity(limit: limit ?? 50))`,
|
|
3734
3548
|
` .where((e) => e.refs.values.any((ref) => ref.id == aggregateId))`,
|
|
3735
3549
|
` .toList();`,
|
|
3736
3550
|
` return activityNarrative(events);`,
|
|
@@ -3742,30 +3556,38 @@ export function generateDartBridgeClient(
|
|
|
3742
3556
|
return [
|
|
3743
3557
|
`// AUTO-GENERATED by nomos-compile — private runtime implementation for domain "${domain}".`,
|
|
3744
3558
|
`// Regenerated every compile; do not edit or teach this file as an application entry point.`,
|
|
3745
|
-
// GENERATED-CODE lints: the
|
|
3559
|
+
// GENERATED-CODE lints: the session read/watch surface returns dynamic (JSON rows), so typed accessors
|
|
3746
3560
|
// do dynamic member access + casts by construction. Silence the lints that only make sense for
|
|
3747
3561
|
// hand-written code, so this file never adds noise to a tenant's analyzer output (co2 feedback).
|
|
3748
3562
|
// (deprecated_member_use*: the compatibility shims intentionally delegate to the deprecated
|
|
3749
3563
|
// engine-level lanes for one minor version.)
|
|
3750
|
-
`// ignore_for_file: avoid_dynamic_calls, unnecessary_this, unnecessary_cast, prefer_const_constructors, unused_import, unused_local_variable, type_annotate_public_apis, always_specify_types, deprecated_member_use, deprecated_member_use_from_same_package, invalid_use_of_internal_member`,
|
|
3564
|
+
`// ignore_for_file: avoid_dynamic_calls, unnecessary_this, unnecessary_cast, prefer_const_constructors, unused_import, unused_local_variable, type_annotate_public_apis, always_specify_types, deprecated_member_use, deprecated_member_use_from_same_package, invalid_use_of_internal_member, unnecessary_non_null_assertion, unnecessary_null_comparison`,
|
|
3565
|
+
``,
|
|
3566
|
+
`import 'dart:async' show unawaited;`,
|
|
3751
3567
|
``,
|
|
3752
3568
|
// `dart:convert` is needed ONLY for the interface block's `jsonDecode` — the offer lane no longer encodes
|
|
3753
|
-
// any envelope (it routes through `
|
|
3569
|
+
// any envelope (it routes through `session.offerDirective` → THE ONE ENCODER). Omit it when no interface.
|
|
3754
3570
|
...(clientInterface !== undefined ||
|
|
3755
3571
|
opts.emitActivity === true ||
|
|
3756
3572
|
localOfferDirs.length > 0 ||
|
|
3757
3573
|
callEncoderSources.length > 0
|
|
3758
3574
|
? [`import 'dart:convert';`, ``]
|
|
3759
3575
|
: []),
|
|
3760
|
-
...(
|
|
3576
|
+
...(clientInterface !== undefined ||
|
|
3577
|
+
localOfferDirs.length > 0 ||
|
|
3761
3578
|
resultDecoderSources.length > 0 ||
|
|
3579
|
+
resultProtoDecoderSources.length > 0 ||
|
|
3762
3580
|
callEncoderSources.length > 0
|
|
3763
3581
|
? [`import 'dart:typed_data';`, ``]
|
|
3764
3582
|
: []),
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3583
|
+
...(callEncoderSources.length > 0 || resultProtoDecoderSources.length > 0
|
|
3584
|
+
? [
|
|
3585
|
+
`import 'package:fixnum/fixnum.dart' show Int64;`,
|
|
3586
|
+
`import 'operation_payloads.pb.dart' as _nmsop;`,
|
|
3587
|
+
``,
|
|
3588
|
+
]
|
|
3768
3589
|
: []),
|
|
3590
|
+
`import '${supportImport}'${opts.typesImportUri === undefined ? ' hide OwnedCustody, OwnedDeviceRequest' : ''};`,
|
|
3769
3591
|
// Layered-packages mode: the sibling types live in their OWN package — one barrel import
|
|
3770
3592
|
// replaces both the relative types import and the relative framework import.
|
|
3771
3593
|
...(opts.typesImportUri !== undefined
|
|
@@ -3799,7 +3621,7 @@ export function generateDartBridgeClient(
|
|
|
3799
3621
|
`import '${uri}' show ${[...names].sort().join(", ")};`
|
|
3800
3622
|
),
|
|
3801
3623
|
`// Re-export business types only. The runtime import above is an implementation dependency, never`,
|
|
3802
|
-
`// a tenant API: exporting it would create a second raw
|
|
3624
|
+
`// a tenant API: exporting it would create a second raw session/session/sync application lane.`,
|
|
3803
3625
|
...(opts.typesImportUri !== undefined
|
|
3804
3626
|
? [`export '${opts.typesImportUri}';`]
|
|
3805
3627
|
: [`export '${mod.name}.dart';`]),
|
|
@@ -3822,43 +3644,35 @@ export function generateDartBridgeClient(
|
|
|
3822
3644
|
: []),
|
|
3823
3645
|
...(clientInterface !== undefined
|
|
3824
3646
|
? [
|
|
3825
|
-
`///
|
|
3826
|
-
`///
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
clientInterface
|
|
3831
|
-
)};`,
|
|
3647
|
+
`/// Canonical compiler-authored USDA compatibility matrix. Dart carries`,
|
|
3648
|
+
`/// these bytes opaquely; only the kernel interprets them.`,
|
|
3649
|
+
`final Uint8List ${interfaceConstNameDart(mod.name)} = Uint8List.fromList(utf8.encode(${dartRawText(
|
|
3650
|
+
emitApplicationCompatibilityUsda({ [domain]: clientInterface })
|
|
3651
|
+
)}));`,
|
|
3832
3652
|
``,
|
|
3833
3653
|
]
|
|
3834
3654
|
: []),
|
|
3835
|
-
...(
|
|
3655
|
+
...(callEncoderSources.length > 0 || resultProtoDecoderSources.length > 0
|
|
3836
3656
|
? [
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
opts.compat
|
|
3842
|
-
)};`,
|
|
3843
|
-
``,
|
|
3657
|
+
...DART_CALL_PROTO_PRELUDE,
|
|
3658
|
+
...DART_CALL_USDA_PRELUDE,
|
|
3659
|
+
...callEncoderSources,
|
|
3660
|
+
...resultProtoDecoderSources,
|
|
3844
3661
|
]
|
|
3845
3662
|
: []),
|
|
3846
|
-
...(callEncoderSources.length > 0
|
|
3847
|
-
? [...DART_CALL_USDA_PRELUDE, ...callEncoderSources]
|
|
3848
|
-
: []),
|
|
3849
3663
|
...resultDecoderSources,
|
|
3850
3664
|
...pastDeclarations,
|
|
3851
3665
|
...conflictDeclarations,
|
|
3852
|
-
`/// Typed async client for the \`${domain}\` domain, bound to
|
|
3666
|
+
`/// Typed async client for the \`${domain}\` domain, bound to one connected [NomosSession].`,
|
|
3853
3667
|
`///`,
|
|
3854
|
-
`/// Pass \`actor\` (the verified principal uid) to author AS that user — the
|
|
3668
|
+
`/// Pass \`actor\` (the verified principal uid) to author AS that user — the generated client owns`,
|
|
3855
3669
|
`/// carries it with the compiler-generated canonical USDA call as the captured principal,`,
|
|
3856
3670
|
`/// so the kernel seals it as the captured principal and the ReBAC \`.requires(...)\` gate judges the real`,
|
|
3857
3671
|
`/// author. A GATED directive (one whose law declares \`.requires(relation)\`) authored with no actor throws`,
|
|
3858
|
-
`/// [MissingOfferAuthority] BEFORE any submit — an actorless gated offer can't be constructed. The
|
|
3859
|
-
`/// owns
|
|
3672
|
+
`/// [MissingOfferAuthority] BEFORE any submit — an actorless gated offer can't be constructed. The peer`,
|
|
3673
|
+
`/// runtime owns the renewable proof capability; only the actor IDENTITY is bound here, never a secret.`,
|
|
3860
3674
|
`class ${className} {`,
|
|
3861
|
-
` final
|
|
3675
|
+
` final NomosSession session;`,
|
|
3862
3676
|
` final String domainHash;`,
|
|
3863
3677
|
``,
|
|
3864
3678
|
` /// The verified principal uid every offer is authored as (sealed as \`security.actor\` by the one encoder).`,
|
|
@@ -3873,68 +3687,36 @@ export function generateDartBridgeClient(
|
|
|
3873
3687
|
` final NomosKeyStore? keyStore;`,
|
|
3874
3688
|
]
|
|
3875
3689
|
: []),
|
|
3876
|
-
` ${className}(this.
|
|
3690
|
+
` ${className}(this.session, {this.domainHash = ${hashConst}, this.actor${
|
|
3877
3691
|
manualEncryptionPresent ? ", this.keyStore" : ""
|
|
3878
3692
|
}});`,
|
|
3879
3693
|
``,
|
|
3880
|
-
` ///
|
|
3881
|
-
` ///
|
|
3882
|
-
` ///
|
|
3883
|
-
` ///
|
|
3884
|
-
` static const List<
|
|
3694
|
+
` /// Standard OSGi Contract Namespace requirements derived from this law's shape, resolved by`,
|
|
3695
|
+
` /// [bind]. The client's own compatibility matrix is served by [compatibilityMatrixUsda]; there`,
|
|
3696
|
+
` /// is no separate static descriptor, because this class is a library-private part of the`,
|
|
3697
|
+
` /// generated application and nothing — inside it or outside — could read one.`,
|
|
3698
|
+
` static const List<NmsKernelContractRequirement> kernelContracts = [${kernelContracts
|
|
3885
3699
|
.map(
|
|
3886
3700
|
(contract) =>
|
|
3887
|
-
`
|
|
3888
|
-
|
|
3889
|
-
)}: ${dartStr(contract.name)},
|
|
3701
|
+
`NmsKernelContractRequirement(namespace: ${dartStr(
|
|
3702
|
+
contract.namespace
|
|
3703
|
+
)}, name: ${dartStr(contract.name)}, version: ${dartStr(
|
|
3890
3704
|
contract.version
|
|
3891
|
-
)}
|
|
3705
|
+
)})`
|
|
3892
3706
|
)
|
|
3893
3707
|
.join(", ")}];`,
|
|
3894
3708
|
``,
|
|
3895
|
-
`
|
|
3896
|
-
`
|
|
3897
|
-
`
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
: []),
|
|
3901
|
-
...(clientInterface !== undefined
|
|
3902
|
-
? [` interfaceJson: ${interfaceConstNameDart(mod.name)},`]
|
|
3903
|
-
: []),
|
|
3904
|
-
...(opts.compat !== undefined
|
|
3905
|
-
? [` compatJson: ${compatConstNameDart(mod.name)},`]
|
|
3906
|
-
: []),
|
|
3907
|
-
` );`,
|
|
3908
|
-
``,
|
|
3909
|
-
` /// THE SESSION-BOUND CONSTRUCTION PATH (session_bound_clients.md asks 2/5): bind this client to`,
|
|
3910
|
-
` /// [session] with an ASYNC PREFLIGHT — the session's workspace must be reachable, hold the`,
|
|
3911
|
-
` /// \`${domain}\` domain, and serve a structurally compatible interface (#72 shape-compat, the ONE`,
|
|
3912
|
-
` /// compatibility notion). An incompatible session throws [DomainClientSessionMismatch]`,
|
|
3913
|
-
` /// IMMEDIATELY — at provider construction, not two clicks into the app. The synchronous`,
|
|
3914
|
-
` /// constructor remains for codepaths that can't await; it lazily runs the SAME preflight on the`,
|
|
3915
|
-
` /// first dispatch.`,
|
|
3916
|
-
` static Future<void> _catchUpBeforeModelPreparation(NomosSession session) async {`,
|
|
3917
|
-
` try {`,
|
|
3918
|
-
` await session.sync(admit: true);`,
|
|
3919
|
-
` } catch (error) {`,
|
|
3920
|
-
` // Offline-first: inability to reach shared custody does not revoke the local workspace.`,
|
|
3921
|
-
` // The subsequent typed compatibility/model gate remains authoritative and will either`,
|
|
3922
|
-
` // accept the local law or surface the precise governed action still required.`,
|
|
3923
|
-
` print('[nomos-model-catch-up] ${domain} continuing from local custody: ' + error.toString());`,
|
|
3924
|
-
` }`,
|
|
3925
|
-
` }`,
|
|
3926
|
-
``,
|
|
3709
|
+
` /// Bind this stateless domain facade to one already-open local workspace.`,
|
|
3710
|
+
` /// Binding never synchronises custody and never rejects the whole domain because an unrelated`,
|
|
3711
|
+
` /// member evolved. Each real query or offer is validated by the kernel against the law installed`,
|
|
3712
|
+
` /// at this workspace's current local frontier. Compatibility is the kernel's verdict, never an`,
|
|
3713
|
+
` /// application-start lifecycle gate.`,
|
|
3927
3714
|
` static Future<${className}> bind(NomosSession session, {String? actor${
|
|
3928
3715
|
manualEncryptionPresent ? ", NomosKeyStore? keyStore" : ""
|
|
3929
3716
|
}}) async {`,
|
|
3930
3717
|
` final candidate = ${className}(session, actor: actor${
|
|
3931
3718
|
manualEncryptionPresent ? ", keyStore: keyStore" : ""
|
|
3932
3719
|
});`,
|
|
3933
|
-
` // Binding proves that this client can read and author against the law the`,
|
|
3934
|
-
` // workspace already runs. It never deploys, stages, promotes, or rewrites`,
|
|
3935
|
-
` // workspace law. Model rollout is an explicit operator action through`,
|
|
3936
|
-
` // [model], outside application startup.`,
|
|
3937
|
-
` await session.assertCompatible(interface);`,
|
|
3938
3720
|
` // RELEASE COHERENCE: resolve this law's OSGi Contract Namespace requirements before use.`,
|
|
3939
3721
|
` await session.assertKernelCoherence(kernelContracts, lawHash: ${hashConst});`,
|
|
3940
3722
|
...(ownedScope === undefined
|
|
@@ -3944,80 +3726,13 @@ export function generateDartBridgeClient(
|
|
|
3944
3726
|
ownedScope
|
|
3945
3727
|
)}, domain: ${dartStr(domain)}, domainHash: ${hashConst});`,
|
|
3946
3728
|
]),
|
|
3947
|
-
` return candidate
|
|
3729
|
+
` return candidate${
|
|
3948
3730
|
ownedScope === undefined ? "" : ".._ownedIdentityReady = true"
|
|
3949
3731
|
};`,
|
|
3950
3732
|
` }`,
|
|
3951
3733
|
``,
|
|
3952
|
-
` ///
|
|
3953
|
-
`
|
|
3954
|
-
` /// It ACQUIRES the workspace's session on [bridge] first (an already-open one is reused; a device-`,
|
|
3955
|
-
` /// resident/parked/just-born one opens local-only in place) and THEN binds — so a not-open workspace`,
|
|
3956
|
-
` /// fails HERE, at open, never later on the client's first query. The generated stateful application`,
|
|
3957
|
-
` /// privately retains refreshable cloud access for a genuinely-absent authorized workspace.`,
|
|
3958
|
-
` static Future<${className}> open<TAggregate>(NomosBridge bridge, {NomosRef<TAggregate>? ref, String? workspace, String? actor${
|
|
3959
|
-
manualEncryptionPresent ? ", NomosKeyStore? keyStore" : ""
|
|
3960
|
-
}, Future<void> Function()? recoverAuthentication}) async {`,
|
|
3961
|
-
` final ws = ref == null ? workspace : NmsInternalNomosRefs.workspace(ref);`,
|
|
3962
|
-
` if (ws == null || ws.isEmpty) {`,
|
|
3963
|
-
` throw ArgumentError('${className}.open: pass a workspace: or ref: — the workspace to open and bind');`,
|
|
3964
|
-
` }`,
|
|
3965
|
-
` final session = await bridge.acquireSession(ws);`,
|
|
3966
|
-
...(authenticationRecovery === undefined
|
|
3967
|
-
? []
|
|
3968
|
-
: [
|
|
3969
|
-
` if (recoverAuthentication != null) {`,
|
|
3970
|
-
` final posture = await session.nmsAuthenticationPosture(principal: actor);`,
|
|
3971
|
-
` if (!posture.isReadyFor(actor ?? '')) {`,
|
|
3972
|
-
` await recoverAuthentication();`,
|
|
3973
|
-
` await session.nmsAwaitAuthenticationReady(principal: actor);`,
|
|
3974
|
-
` }`,
|
|
3975
|
-
` }`,
|
|
3976
|
-
]),
|
|
3977
|
-
` return bind(session, actor: actor${
|
|
3978
|
-
manualEncryptionPresent ? ", keyStore: keyStore" : ""
|
|
3979
|
-
});`,
|
|
3980
|
-
` }`,
|
|
3981
|
-
``,
|
|
3982
|
-
` /// The session workspace this client is bound to (from the [NomosSession] handle, when constructed with`,
|
|
3983
|
-
` /// one) — the \`workspace\` of every read row's canonical [NomosRef]. '' on a bare (non-session) bridge.`,
|
|
3984
|
-
` String get _ws {`,
|
|
3985
|
-
` final b = bridge;`,
|
|
3986
|
-
` return b is NomosSession ? b.workspace : '';`,
|
|
3987
|
-
` }`,
|
|
3988
|
-
``,
|
|
3989
|
-
` /// The [NomosSession] this client dispatches through, when session-bound (the blessed shape);`,
|
|
3990
|
-
` /// null on a bare (non-session) bridge. Inspectable context: \`client.session?.workspace\`.`,
|
|
3991
|
-
` NomosSession? get session {`,
|
|
3992
|
-
` final b = bridge;`,
|
|
3993
|
-
` return b is NomosSession ? b : null;`,
|
|
3994
|
-
` }`,
|
|
3995
|
-
``,
|
|
3996
|
-
` // LAZY PREFLIGHT (the can't-await constructor path): the first dispatch runs the same`,
|
|
3997
|
-
` // assertCompatible check bind() runs eagerly. Only when session-bound; a bare bridge keeps the`,
|
|
3998
|
-
` // pre-session behavior (the kernel gate remains the fail-closed floor either way).`,
|
|
3999
|
-
` bool _preflighted = false;`,
|
|
4000
|
-
` Future<void> _preflightOnce() async {`,
|
|
4001
|
-
` if (_preflighted) return;`,
|
|
4002
|
-
` _preflighted = true;`,
|
|
4003
|
-
` final b = bridge;`,
|
|
4004
|
-
` if (b is NomosSession) {`,
|
|
4005
|
-
` await b.assertCompatible(interface);`,
|
|
4006
|
-
` }`,
|
|
4007
|
-
` }`,
|
|
4008
|
-
``,
|
|
4009
|
-
` // Command readiness is deliberately separate from client/read compatibility. Binding a`,
|
|
4010
|
-
` // generated application may construct clients for every installed domain; compiling every`,
|
|
4011
|
-
` // offer plan at that point recreates whole-law runtime work. The first actual offer prepares`,
|
|
4012
|
-
` // exactly this authenticated package/domain slice, once, before dispatch.`,
|
|
4013
|
-
` final Set<String> _preparedCommands = <String>{};`,
|
|
4014
|
-
` Future<void> _prepareCommand(String directiveId) async {`,
|
|
4015
|
-
` if (_preparedCommands.contains(directiveId)) return;`,
|
|
4016
|
-
` await bridge.prepareDomain(domain: ${dartStr(
|
|
4017
|
-
domain
|
|
4018
|
-
)}, directiveId: directiveId, packageHash: ${hashConst});`,
|
|
4019
|
-
` _preparedCommands.add(directiveId);`,
|
|
4020
|
-
` }`,
|
|
3734
|
+
` /// Workspace of every canonical [NomosRef] returned by this client.`,
|
|
3735
|
+
` String get _ws => session.workspace;`,
|
|
4021
3736
|
``,
|
|
4022
3737
|
...(ownedScope === undefined || Object.keys(ownedActions).length === 0
|
|
4023
3738
|
? []
|
|
@@ -4036,62 +3751,52 @@ export function generateDartBridgeClient(
|
|
|
4036
3751
|
` bool _ownedIdentityReady = false;`,
|
|
4037
3752
|
` Future<void> _ensureOwnedIdentity() async {`,
|
|
4038
3753
|
` if (_ownedIdentityReady) return;`,
|
|
4039
|
-
` await
|
|
3754
|
+
` await session.nomosEnsureOwnedIdentity(scope: ${dartStr(
|
|
4040
3755
|
ownedScope
|
|
4041
3756
|
)}, domain: ${dartStr(domain)}, domainHash: domainHash);`,
|
|
4042
3757
|
` _ownedIdentityReady = true;`,
|
|
4043
3758
|
` }`,
|
|
4044
3759
|
``,
|
|
4045
3760
|
` Future<NomosOfferOutcome> _ownedRecordAction<TAggregate>(String action, NomosRef<TAggregate> record, String peer) async {`,
|
|
4046
|
-
` await _preflightOnce();`,
|
|
4047
3761
|
` await _ensureOwnedIdentity();`,
|
|
4048
3762
|
` if (NmsInternalNomosRefs.workspace(record) != _ws) throw ArgumentError('$action() cannot use a record from another workspace');`,
|
|
4049
3763
|
` final directiveId = _ownedDirectiveId(NmsInternalNomosRefs.type(record), action);`,
|
|
4050
3764
|
` if (directiveId == null) throw ArgumentError('$action() needs a generated owned record reference');`,
|
|
4051
|
-
` await _prepareCommand(directiveId);`,
|
|
4052
3765
|
` if (peer.trim().isEmpty) throw ArgumentError('$action() needs the person to act with');`,
|
|
4053
|
-
` final payload = await
|
|
3766
|
+
` final payload = await session.nomosPrepareOwnedRecordAction(action: action, scope: ${dartStr(
|
|
4054
3767
|
ownedScope
|
|
4055
3768
|
)}, record: record, peer: peer);`,
|
|
4056
|
-
` final
|
|
3769
|
+
` final generatedCall = switch (directiveId) {`,
|
|
4057
3770
|
...[...ownedActionCallEncoders.entries()].map(
|
|
4058
3771
|
([directiveId, encoder]) =>
|
|
4059
3772
|
` ${dartStr(directiveId)} => ${
|
|
4060
3773
|
encoder.functionName
|
|
4061
3774
|
}(payload as ${encoder.payloadType}),`
|
|
4062
3775
|
),
|
|
4063
|
-
` _ => throw StateError('No generated
|
|
3776
|
+
` _ => throw StateError('No generated Protobuf encoder for owned directive $directiveId'),`,
|
|
4064
3777
|
` };`,
|
|
4065
|
-
` return _offer(
|
|
3778
|
+
` return _offer(generatedCall);`,
|
|
4066
3779
|
` }`,
|
|
4067
3780
|
``,
|
|
4068
3781
|
]),
|
|
4069
3782
|
...(callEncoderSources.length > 0
|
|
4070
3783
|
? [
|
|
4071
|
-
` /// THE ONE DISPATCH LANE every generated directive method routes through
|
|
4072
|
-
` ///
|
|
3784
|
+
` /// THE ONE DISPATCH LANE every generated directive method routes through.`,
|
|
3785
|
+
` /// The kernel prepares and validates the exact authenticated command`,
|
|
3786
|
+
` /// route inside the offer gate, where readiness is shared by every host and cannot become a`,
|
|
3787
|
+
` /// second foreground ceremony maintained by generated clients.`,
|
|
4073
3788
|
` Future<NomosOfferOutcome> _offer(NmsGeneratedCall call, {List<NomosConflictSnapshot> conflictSnapshots = const [], NomosOfferAuthenticationProof authenticationProof = NomosOfferAuthenticationProof.sessionCredentials}) async {`,
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
` Future<NomosOfferOutcome> attempt() => bridge.offerCallUsdaOutcome(call: call, actor: actor, conflictSnapshots: conflictSnapshots, authenticationProof: authenticationProof);`,
|
|
4077
|
-
...(authenticationRecovery === undefined
|
|
4078
|
-
? [` return attempt();`]
|
|
3789
|
+
...(clientInterface === undefined
|
|
3790
|
+
? []
|
|
4079
3791
|
: [
|
|
4080
|
-
`
|
|
4081
|
-
`
|
|
4082
|
-
`
|
|
4083
|
-
`
|
|
4084
|
-
`
|
|
4085
|
-
` if (posture.providerToken != NomosProviderTokenVerification.noMatchingKey) rethrow;`,
|
|
4086
|
-
` await ${safeMethod(
|
|
4087
|
-
authenticationRecovery.id
|
|
4088
|
-
)}(const ${dartActionInputClassName(
|
|
4089
|
-
authenticationRecovery
|
|
4090
|
-
)}());`,
|
|
4091
|
-
` await bridge.nmsAwaitAuthenticationReady(principal: actor);`,
|
|
4092
|
-
` return attempt();`,
|
|
4093
|
-
` }`,
|
|
3792
|
+
` // PARTIAL COMPATIBILITY: examine the exact directive before dispatch. The`,
|
|
3793
|
+
` // session caches this compiler matrix until Peer Office reports law/custody`,
|
|
3794
|
+
` // movement, so repeated writes do no compatibility work. Unrelated reads and`,
|
|
3795
|
+
` // writes remain usable when another member is incompatible.`,
|
|
3796
|
+
` await session.assertOperationCompatible(compatibilityMatrixUsda, domain: call.domain, directive: call.directive);`,
|
|
4094
3797
|
]),
|
|
3798
|
+
` Future<NomosOfferOutcome> attempt() => session.offerGeneratedCallOutcome(call: call, actor: actor, conflictSnapshots: conflictSnapshots, authenticationProof: authenticationProof);`,
|
|
3799
|
+
` return attempt();`,
|
|
4095
3800
|
` }`,
|
|
4096
3801
|
``,
|
|
4097
3802
|
]
|
|
@@ -4102,13 +3807,13 @@ export function generateDartBridgeClient(
|
|
|
4102
3807
|
: [
|
|
4103
3808
|
` /// Opt into all-device-loss recovery with one explicitly designated person.`,
|
|
4104
3809
|
` NomosRecovery get recovery => NomosRecovery(`,
|
|
4105
|
-
`
|
|
3810
|
+
` session: session, domain: ${dartStr(
|
|
4106
3811
|
domain
|
|
4107
3812
|
)}, domainHash: domainHash, scope: ${dartStr(ownedScope)});`,
|
|
4108
3813
|
``,
|
|
4109
3814
|
` /// Add another of this person's devices. Requests are opaque; Nomos owns the handoff.`,
|
|
4110
3815
|
` NomosDevices get devices => NomosDevices(`,
|
|
4111
|
-
`
|
|
3816
|
+
` session: session, domain: ${dartStr(
|
|
4112
3817
|
domain
|
|
4113
3818
|
)}, domainHash: domainHash, actor: actor, scope: ${dartStr(
|
|
4114
3819
|
ownedScope
|
|
@@ -4118,64 +3823,16 @@ export function generateDartBridgeClient(
|
|
|
4118
3823
|
` ));`,
|
|
4119
3824
|
``,
|
|
4120
3825
|
]),
|
|
4121
|
-
// THE OWNER CEREMONY (slice 2): grantAndWrap / revokeAndRotate / rotate — the operator-blind key-epoch
|
|
4122
|
-
// handshake as one call. Bind `actor` (the owner) to author the fan-out. Only for a domain with a scope.
|
|
4123
|
-
...(domScopes.length > 0
|
|
4124
|
-
? [
|
|
4125
|
-
` /// OWNER CEREMONY (slice 2): \`grantAndWrap\` / \`revokeAndRotate\` / \`rotate\` — the operator-blind`,
|
|
4126
|
-
` /// key-epoch handshake as one call. Bind \`actor\` (the owner) to author the fan-out.`,
|
|
4127
|
-
` NomosEncryption get encryption => NomosEncryption(`,
|
|
4128
|
-
` bridge: bridge, domain: ${dartStr(
|
|
4129
|
-
domain
|
|
4130
|
-
)}, domainHash: domainHash, actor: actor,`,
|
|
4131
|
-
` scopes: const [${domScopes
|
|
4132
|
-
.map((s) => dartStr(s))
|
|
4133
|
-
.join(", ")}]);`,
|
|
4134
|
-
``,
|
|
4135
|
-
]
|
|
4136
|
-
: []),
|
|
4137
3826
|
...(clientInterface !== undefined
|
|
4138
3827
|
? [
|
|
4139
|
-
` /// This client's
|
|
4140
|
-
`
|
|
4141
|
-
` String get interfaceJson => ${interfaceConstNameDart(mod.name)};`,
|
|
3828
|
+
` /// This client's exact compiler-authored USDA compatibility matrix.`,
|
|
3829
|
+
` Uint8List get compatibilityMatrixUsda => ${interfaceConstNameDart(mod.name)};`,
|
|
4142
3830
|
``,
|
|
4143
|
-
` Map<String, Object?> get _requirement =>`,
|
|
4144
|
-
` {${dartStr(
|
|
4145
|
-
domain
|
|
4146
|
-
)}: (jsonDecode(interfaceJson) as Map).cast<String, Object?>()};`,
|
|
4147
|
-
``,
|
|
4148
|
-
` /// SHAPE COMPATIBILITY (#72): one-shot verdict for THIS client against the workspace's`,
|
|
4149
|
-
` /// ON-LEDGER offer — \`{ ok, missing[], incompatible[] }\`, by shape not law hash.`,
|
|
4150
|
-
` Future<Map<String, Object?>> checkCompatibility() => bridge.checkCompatibility(_requirement);`,
|
|
4151
|
-
``,
|
|
4152
|
-
` /// SHAPE COMPATIBILITY as a LIVE BINDING (#72): a stream of verdicts that re-emits whenever`,
|
|
4153
|
-
` /// the workspace's installed law changes (a synced install/upgrade from another peer).`,
|
|
4154
|
-
` Stream<Map<String, Object?>> watchCompatibility() => bridge.watchCompatibility(_requirement);`,
|
|
4155
|
-
``,
|
|
4156
|
-
...(opts.compat !== undefined
|
|
4157
|
-
? [
|
|
4158
|
-
` /// THE COMPAT SUPERPOWER (#72b): compute the LIVE per-member verdict for THIS client against the`,
|
|
4159
|
-
` /// workspace's on-ledger offer + arm the pre-call refusal. Await it after connect so a KNOWN-`,
|
|
4160
|
-
` /// incompatible directive throws [LawMismatchError] CLIENT-SIDE at write time (never a server 422).`,
|
|
4161
|
-
` Future<NomosCompat?> checkCompat() => bridge.checkCompat(`,
|
|
4162
|
-
` (jsonDecode(${compatConstNameDart(
|
|
4163
|
-
mod.name
|
|
4164
|
-
)}) as Map).cast<String, Object?>(), _requirement);`,
|
|
4165
|
-
``,
|
|
4166
|
-
` /// THE FEATURE FLAG (dark-launch): true iff [member] exists on the offer AND is compatible — ship`,
|
|
4167
|
-
` /// UI with a member dark, deploy the law, it lights up. Await [checkCompat] once first to arm it.`,
|
|
4168
|
-
` Future<bool> has(String member) => bridge.compatHas(member);`,
|
|
4169
|
-
``,
|
|
4170
|
-
` /// COMPAT SUPERPOWER live events: emits the fresh verdict when a synced law change moves the offer.`,
|
|
4171
|
-
` Stream<NomosCompat> get onLawChanged => bridge.onLawChanged;`,
|
|
4172
|
-
``,
|
|
4173
|
-
]
|
|
4174
|
-
: []),
|
|
4175
3831
|
]
|
|
4176
3832
|
: []),
|
|
4177
3833
|
...methods,
|
|
4178
3834
|
`}`,
|
|
3835
|
+
...dartRefusalDecoders(mod, callUsda.graph, callUsda.paths),
|
|
4179
3836
|
``,
|
|
4180
3837
|
...(refExtensions.length > 0
|
|
4181
3838
|
? [
|
|
@@ -4218,7 +3875,7 @@ function dartEncClassMembers(manualEncryptionPresent: boolean): string[] {
|
|
|
4218
3875
|
` for (final record in records) {`,
|
|
4219
3876
|
` final type = record.type;`,
|
|
4220
3877
|
` final id = record.id;`,
|
|
4221
|
-
` final held = await
|
|
3878
|
+
` final held = await session.nomosOwnedScopeKeys(scope, recordType: type, recordId: id);`,
|
|
4222
3879
|
` for (final key in held) {`,
|
|
4223
3880
|
` if (!keys.any((candidate) => candidate.scope == key.scope && candidate.epoch == key.epoch)) keys.add(key);`,
|
|
4224
3881
|
` }`,
|
|
@@ -4232,9 +3889,10 @@ function dartEncClassMembers(manualEncryptionPresent: boolean): string[] {
|
|
|
4232
3889
|
` Future<List<TModel>> _readWithOwnedKeys<TModel, TAggregate>(`,
|
|
4233
3890
|
` List<({String scope, bool owned})> scopes,`,
|
|
4234
3891
|
` Future<List<TModel>> Function(List<NomosScopeKey>? keys) read,`,
|
|
4235
|
-
` NomosRef<TAggregate> Function(TModel row) reference
|
|
4236
|
-
`
|
|
4237
|
-
`
|
|
3892
|
+
` NomosRef<TAggregate> Function(TModel row) reference, {`,
|
|
3893
|
+
` List<TModel>? initial,`,
|
|
3894
|
+
` }) async {`,
|
|
3895
|
+
` final first = initial ?? await read(await _readKeys(scopes));`,
|
|
4238
3896
|
` if (!scopes.any((scope) => scope.owned) || first.isEmpty) return first;`,
|
|
4239
3897
|
` final records = first.map(reference).map((record) => (`,
|
|
4240
3898
|
` type: NmsInternalNomosRefs.type(record),`,
|