@githolon/dsl 0.108.6 → 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 +2083 -1248
- 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
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/// Console enrolment, device side — the Dart twin of
|
|
2
|
+
/// `peer-office/src/runtime/console_enrolment.ts` (identity_target_model.md
|
|
3
|
+
/// D22/D23).
|
|
4
|
+
///
|
|
5
|
+
/// The person signs in with the tenant's provider (a Firebase ID token for
|
|
6
|
+
/// CO2). The device proves it holds its Ed25519 key by signing
|
|
7
|
+
/// [consoleEnrolRequestBytes], then POSTs the token, its public key, the proof
|
|
8
|
+
/// and the workspaces it wants to the console's enroller. The console verifies
|
|
9
|
+
/// the token once, off the ledger, and submits `enrollDevice { principal:
|
|
10
|
+
/// <scope>:<subject>, keyHash }` into each workspace; from then on the device
|
|
11
|
+
/// authors with its own key and no provider token ever reaches an intent.
|
|
12
|
+
///
|
|
13
|
+
/// The platform shell performs this as the Peer Office's console-enrolment
|
|
14
|
+
/// effect: it holds both the device secret (its identity store) and the
|
|
15
|
+
/// provider. Both byte formats are pinned by the golden vector
|
|
16
|
+
/// `peer-office/test/fixtures/console_enrol_request_vector.json`.
|
|
17
|
+
library;
|
|
18
|
+
|
|
19
|
+
import 'dart:convert';
|
|
20
|
+
import 'dart:typed_data';
|
|
21
|
+
|
|
22
|
+
import 'package:crypto/crypto.dart' show sha256;
|
|
23
|
+
import 'package:ed25519_edwards/ed25519_edwards.dart' as ed25519;
|
|
24
|
+
import 'package:nomos_types/nomos_kernel_protocol.dart' as nomos_protocol;
|
|
25
|
+
|
|
26
|
+
/// Where an enrolled principal's device key is enrolled: the application's
|
|
27
|
+
/// console enroller, its tenant and the enrolled provider scope declared in
|
|
28
|
+
/// law. Application configuration, never authority.
|
|
29
|
+
final class NomosConsoleEnrolment {
|
|
30
|
+
const NomosConsoleEnrolment({
|
|
31
|
+
required this.console,
|
|
32
|
+
required this.tenant,
|
|
33
|
+
required this.scope,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/// The console's origin, e.g. `http://127.0.0.1:8797`.
|
|
37
|
+
final String console;
|
|
38
|
+
|
|
39
|
+
/// The console tenant, e.g. `co2-platform`.
|
|
40
|
+
final String tenant;
|
|
41
|
+
|
|
42
|
+
/// The enrolled provider scope, e.g. `co2`; principals are `<scope>:<subject>`.
|
|
43
|
+
final String scope;
|
|
44
|
+
|
|
45
|
+
nomos_protocol.ConsoleEnrolmentRoute toRoute() =>
|
|
46
|
+
nomos_protocol.ConsoleEnrolmentRoute(
|
|
47
|
+
console: console, tenant: tenant, scope: scope);
|
|
48
|
+
|
|
49
|
+
@override
|
|
50
|
+
bool operator ==(Object other) =>
|
|
51
|
+
other is NomosConsoleEnrolment &&
|
|
52
|
+
other.console == console &&
|
|
53
|
+
other.tenant == tenant &&
|
|
54
|
+
other.scope == scope;
|
|
55
|
+
|
|
56
|
+
@override
|
|
57
|
+
int get hashCode => Object.hash(console, tenant, scope);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// `nomos-console-enrol-v1` followed by a NUL byte.
|
|
61
|
+
final String consoleEnrolRequestTag =
|
|
62
|
+
'nomos-console-enrol-v1${String.fromCharCode(0)}';
|
|
63
|
+
final String _nul = String.fromCharCode(0);
|
|
64
|
+
|
|
65
|
+
/// The key hash the ledger names a device by: sha256 hex of its raw Ed25519 public key.
|
|
66
|
+
String consoleDeviceKeyHash(List<int> publicKey) =>
|
|
67
|
+
sha256.convert(publicKey).toString();
|
|
68
|
+
|
|
69
|
+
/// The bytes a device signs to ask for enrolment: tag, tenant, scope, its key
|
|
70
|
+
/// hash, the requested workspaces (sorted, newline-separated) and the provider
|
|
71
|
+
/// token's sha256, NUL-separated. Byte-identical to the console's
|
|
72
|
+
/// `enrolRequestBytes`.
|
|
73
|
+
Uint8List consoleEnrolRequestBytes({
|
|
74
|
+
required String tenant,
|
|
75
|
+
required String scope,
|
|
76
|
+
required String keyHash,
|
|
77
|
+
required Iterable<String> workspaces,
|
|
78
|
+
required String providerToken,
|
|
79
|
+
}) {
|
|
80
|
+
final sorted = [...workspaces]..sort();
|
|
81
|
+
final head = utf8.encode('$consoleEnrolRequestTag$tenant$_nul$scope$_nul'
|
|
82
|
+
'$keyHash$_nul${sorted.join('\n')}$_nul');
|
|
83
|
+
final digest = sha256.convert(utf8.encode(providerToken)).bytes;
|
|
84
|
+
return Uint8List.fromList([...head, ...digest]);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Unpadded base64url, the console's wire form for keys and signatures.
|
|
88
|
+
String consoleBase64Url(List<int> bytes) =>
|
|
89
|
+
base64Url.encode(bytes).replaceAll('=', '');
|
|
90
|
+
|
|
91
|
+
/// An Ed25519 device key held by the shell. The secret never leaves [sign].
|
|
92
|
+
final class NomosConsoleEnrolmentDevice {
|
|
93
|
+
NomosConsoleEnrolmentDevice._(this._key);
|
|
94
|
+
|
|
95
|
+
/// The 32-byte RFC 8032 seed the kernel mints and the identity store keeps.
|
|
96
|
+
factory NomosConsoleEnrolmentDevice.fromSeed(List<int> seed) {
|
|
97
|
+
if (seed.length != ed25519.SeedSize) {
|
|
98
|
+
throw ArgumentError('a device secret is a 32-byte Ed25519 seed');
|
|
99
|
+
}
|
|
100
|
+
return NomosConsoleEnrolmentDevice._(
|
|
101
|
+
ed25519.newKeyFromSeed(Uint8List.fromList(seed)));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
final ed25519.PrivateKey _key;
|
|
105
|
+
|
|
106
|
+
Uint8List get publicKey => Uint8List.fromList(ed25519.public(_key).bytes);
|
|
107
|
+
|
|
108
|
+
Uint8List sign(List<int> message) =>
|
|
109
|
+
ed25519.sign(_key, Uint8List.fromList(message));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/// The path and JSON body of one enrolment request, carrying the device's possession proof.
|
|
113
|
+
final class NomosConsoleEnrolmentRequest {
|
|
114
|
+
const NomosConsoleEnrolmentRequest({required this.path, required this.body});
|
|
115
|
+
|
|
116
|
+
final String path;
|
|
117
|
+
final Map<String, Object> body;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
NomosConsoleEnrolmentRequest consoleEnrolmentRequest({
|
|
121
|
+
required String tenant,
|
|
122
|
+
required String scope,
|
|
123
|
+
required String providerToken,
|
|
124
|
+
required NomosConsoleEnrolmentDevice device,
|
|
125
|
+
required Iterable<String> workspaces,
|
|
126
|
+
}) {
|
|
127
|
+
final publicKey = device.publicKey;
|
|
128
|
+
if (publicKey.length != 32) {
|
|
129
|
+
throw ArgumentError('the device public key must be a 32-byte Ed25519 key');
|
|
130
|
+
}
|
|
131
|
+
if (providerToken.isEmpty) {
|
|
132
|
+
throw ArgumentError('a provider token is required to enrol a device');
|
|
133
|
+
}
|
|
134
|
+
final unique = <String>{...workspaces}.toList();
|
|
135
|
+
if (unique.isEmpty) throw ArgumentError('enrol into at least one workspace');
|
|
136
|
+
final keyHash = consoleDeviceKeyHash(publicKey);
|
|
137
|
+
final signature = device.sign(consoleEnrolRequestBytes(
|
|
138
|
+
tenant: tenant,
|
|
139
|
+
scope: scope,
|
|
140
|
+
keyHash: keyHash,
|
|
141
|
+
workspaces: unique,
|
|
142
|
+
providerToken: providerToken,
|
|
143
|
+
));
|
|
144
|
+
return NomosConsoleEnrolmentRequest(
|
|
145
|
+
path: '/v1/tenants/${Uri.encodeComponent(tenant)}'
|
|
146
|
+
'/providers/${Uri.encodeComponent(scope)}/enrolments',
|
|
147
|
+
body: {
|
|
148
|
+
'providerToken': providerToken,
|
|
149
|
+
'devicePublicKey': consoleBase64Url(publicKey),
|
|
150
|
+
'deviceSignature': consoleBase64Url(signature),
|
|
151
|
+
'workspaces': unique,
|
|
152
|
+
},
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/// The console's record of an enrolled device (console.ts `DeviceRecord`).
|
|
157
|
+
final class NomosConsoleEnrolledDevice {
|
|
158
|
+
const NomosConsoleEnrolledDevice({
|
|
159
|
+
required this.keyHash,
|
|
160
|
+
required this.principal,
|
|
161
|
+
required this.workspaces,
|
|
162
|
+
this.refused = const {},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
final String keyHash;
|
|
166
|
+
final String principal;
|
|
167
|
+
|
|
168
|
+
/// Workspace → the head its `enrollDevice` was admitted at. Includes the
|
|
169
|
+
/// console's fan-out: every workspace the person belongs to (their Home and
|
|
170
|
+
/// everything born below it), not only those requested.
|
|
171
|
+
final Map<String, String> workspaces;
|
|
172
|
+
|
|
173
|
+
/// Workspace → why the console's fan-out into it was refused.
|
|
174
|
+
final Map<String, String> refused;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/// The console answered, but not with an enrolment.
|
|
178
|
+
final class NomosConsoleEnrolmentRefused implements Exception {
|
|
179
|
+
const NomosConsoleEnrolmentRefused(this.status, this.message,
|
|
180
|
+
{this.code = '', this.retryable});
|
|
181
|
+
|
|
182
|
+
final int status;
|
|
183
|
+
final String message;
|
|
184
|
+
|
|
185
|
+
/// The console's stable refusal code (empty from an older console).
|
|
186
|
+
final String code;
|
|
187
|
+
|
|
188
|
+
/// The console's own retry verdict; null when it gave none.
|
|
189
|
+
final bool? retryable;
|
|
190
|
+
|
|
191
|
+
@override
|
|
192
|
+
String toString() => 'console enrolment refused (HTTP $status): $message';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/// One console exchange: status and raw body.
|
|
196
|
+
final class NomosConsoleResponse {
|
|
197
|
+
const NomosConsoleResponse({required this.status, required this.body});
|
|
198
|
+
|
|
199
|
+
final int status;
|
|
200
|
+
final String body;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/// Minimal POST shape, so a shell can inject its own transport.
|
|
204
|
+
typedef NomosConsolePost = Future<NomosConsoleResponse> Function(
|
|
205
|
+
Uri url, String body);
|
|
206
|
+
|
|
207
|
+
/// Enrol [device] for the person [providerToken] names into [workspaces],
|
|
208
|
+
/// through the console at [console].
|
|
209
|
+
Future<NomosConsoleEnrolledDevice> enrolWithConsole({
|
|
210
|
+
required String console,
|
|
211
|
+
required String tenant,
|
|
212
|
+
required String scope,
|
|
213
|
+
required String providerToken,
|
|
214
|
+
required NomosConsoleEnrolmentDevice device,
|
|
215
|
+
required Iterable<String> workspaces,
|
|
216
|
+
required NomosConsolePost post,
|
|
217
|
+
}) async {
|
|
218
|
+
final request = consoleEnrolmentRequest(
|
|
219
|
+
tenant: tenant,
|
|
220
|
+
scope: scope,
|
|
221
|
+
providerToken: providerToken,
|
|
222
|
+
device: device,
|
|
223
|
+
workspaces: workspaces,
|
|
224
|
+
);
|
|
225
|
+
final base = console.replaceFirst(RegExp(r'/+$'), '');
|
|
226
|
+
final response =
|
|
227
|
+
await post(Uri.parse('$base${request.path}'), jsonEncode(request.body));
|
|
228
|
+
Object? answer;
|
|
229
|
+
try {
|
|
230
|
+
answer = jsonDecode(response.body);
|
|
231
|
+
} catch (_) {
|
|
232
|
+
answer = null;
|
|
233
|
+
}
|
|
234
|
+
final record =
|
|
235
|
+
answer is Map<String, Object?> ? answer : const <String, Object?>{};
|
|
236
|
+
if (response.status != 201) {
|
|
237
|
+
final error = record['error'];
|
|
238
|
+
final code = record['code'];
|
|
239
|
+
final retryable = record['retryable'];
|
|
240
|
+
throw NomosConsoleEnrolmentRefused(
|
|
241
|
+
response.status,
|
|
242
|
+
error is String
|
|
243
|
+
? error
|
|
244
|
+
: 'the console answered HTTP ${response.status}',
|
|
245
|
+
code: code is String ? code : '',
|
|
246
|
+
retryable: retryable is bool ? retryable : null);
|
|
247
|
+
}
|
|
248
|
+
final keyHash = record['keyHash'];
|
|
249
|
+
final principal = record['principal'];
|
|
250
|
+
final heads = record['workspaces'];
|
|
251
|
+
if (keyHash is! String || principal is! String || heads is! Map) {
|
|
252
|
+
throw NomosConsoleEnrolmentRefused(
|
|
253
|
+
response.status, 'the console answered 201 without a device record');
|
|
254
|
+
}
|
|
255
|
+
final refused = record['refused'];
|
|
256
|
+
return NomosConsoleEnrolledDevice(
|
|
257
|
+
keyHash: keyHash,
|
|
258
|
+
principal: principal,
|
|
259
|
+
workspaces: {
|
|
260
|
+
for (final entry in heads.entries)
|
|
261
|
+
if (entry.key is String && entry.value is String)
|
|
262
|
+
entry.key as String: entry.value as String,
|
|
263
|
+
},
|
|
264
|
+
refused: {
|
|
265
|
+
if (refused is Map)
|
|
266
|
+
for (final entry in refused.entries)
|
|
267
|
+
if (entry.key is String && entry.value is String)
|
|
268
|
+
entry.key as String: entry.value as String,
|
|
269
|
+
},
|
|
270
|
+
);
|
|
271
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import 'dart:convert';
|
|
2
|
+
import 'dart:io';
|
|
3
|
+
|
|
4
|
+
import 'console_enrolment.dart' show NomosConsoleResponse;
|
|
5
|
+
|
|
6
|
+
/// The native shells' console transport: one JSON POST, the answer's status
|
|
7
|
+
/// and body. No retry and no interpretation: Peer Office owns both.
|
|
8
|
+
Future<NomosConsoleResponse> nomosDefaultConsolePost(
|
|
9
|
+
Uri url, String body) async {
|
|
10
|
+
final client = HttpClient()..connectionTimeout = const Duration(seconds: 30);
|
|
11
|
+
try {
|
|
12
|
+
final request = await client.postUrl(url);
|
|
13
|
+
request.headers
|
|
14
|
+
..contentType = ContentType.json
|
|
15
|
+
..set(HttpHeaders.acceptHeader, 'application/json');
|
|
16
|
+
request.add(utf8.encode(body));
|
|
17
|
+
final response = await request.close().timeout(const Duration(seconds: 60));
|
|
18
|
+
final text = await response
|
|
19
|
+
.transform(utf8.decoder)
|
|
20
|
+
.join()
|
|
21
|
+
.timeout(const Duration(seconds: 60));
|
|
22
|
+
return NomosConsoleResponse(status: response.statusCode, body: text);
|
|
23
|
+
} finally {
|
|
24
|
+
client.close(force: true);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import 'console_enrolment.dart' show NomosConsoleResponse;
|
|
2
|
+
|
|
3
|
+
/// A platform without `dart:io` has no default console transport; its shell
|
|
4
|
+
/// registers one (`registerConsolePost`) or the enrolment effect is refused.
|
|
5
|
+
Future<NomosConsoleResponse> nomosDefaultConsolePost(Uri url, String body) =>
|
|
6
|
+
Future.error(UnsupportedError(
|
|
7
|
+
'this platform has no default console transport; register one'));
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
// NOMOS TEST CLOUD (co2 #4) —
|
|
2
|
-
// `githolon cloud dev` (the SAME
|
|
1
|
+
// NOMOS TEST CLOUD (co2 #4) — an unattended, real-sync test cloud for AppSim: start/stop a local
|
|
2
|
+
// `githolon cloud dev` (the SAME kernel host production runs), front it with a PARTITION PROXY so a test can
|
|
3
3
|
// go online/offline deterministically, and inspect the remote head/sequence — all sharing the production
|
|
4
|
-
//
|
|
4
|
+
// Reception/session clients (the sessions connect to [origin] exactly like they connect to the real cloud).
|
|
5
5
|
//
|
|
6
6
|
// ```dart
|
|
7
7
|
// final cloud = await NomosTestCloud.start(serverEntry: devServerPath); // spawns the dev cloud + proxy
|
|
8
8
|
// final harness = await NomosTestHarness.cloudBound(cloud: cloud, lawUsdzPaths: [...], platformWorkspace: 'co2-platform', subject: 'user:test');
|
|
9
9
|
// // ... author offline ...
|
|
10
10
|
// cloud.setOnline(false); // PARTITION — the up leg can't reach custody
|
|
11
|
-
// await harness.
|
|
11
|
+
// await harness.converge(workspaces: ['estate']); // stays local; nothing lands remotely
|
|
12
12
|
// cloud.setOnline(true); // heal the partition
|
|
13
|
-
// await harness.
|
|
13
|
+
// await harness.converge(workspaces: ['estate']); // converges; the write lands on remote main
|
|
14
14
|
// final remote = await cloud.remoteHead('estate'); // inspect remote head + commit count
|
|
15
15
|
// await cloud.stop();
|
|
16
16
|
// ```
|
|
@@ -68,7 +68,14 @@ class NomosTestCloud {
|
|
|
68
68
|
final Uri _upstream; // the real dev-cloud origin the proxy forwards to
|
|
69
69
|
final HttpClient _client;
|
|
70
70
|
final void Function(String line)? _onDiagnostic;
|
|
71
|
-
|
|
71
|
+
|
|
72
|
+
/// Base64 of this universe's pinned ed25519 trust root, when the shell has one.
|
|
73
|
+
/// Every peer in this ephemeral trust universe pins the same anchor before it
|
|
74
|
+
/// replays or births anything; production bakes its own into the kernel.
|
|
75
|
+
final String? trustRootPublicKey;
|
|
76
|
+
|
|
77
|
+
/// The retired name for [trustRootPublicKey]; kept for one release.
|
|
78
|
+
String? get testKRootPublic => trustRootPublicKey;
|
|
72
79
|
bool _online = true;
|
|
73
80
|
bool _stopped = false;
|
|
74
81
|
|
|
@@ -78,10 +85,11 @@ class NomosTestCloud {
|
|
|
78
85
|
this._upstream,
|
|
79
86
|
this._client,
|
|
80
87
|
this._onDiagnostic,
|
|
81
|
-
this.
|
|
88
|
+
this.trustRootPublicKey,
|
|
82
89
|
);
|
|
83
90
|
|
|
84
|
-
/// The base URL
|
|
91
|
+
/// The base URL of this development cloud. Placement, not an interaction
|
|
92
|
+
/// session, determines whether a workspace follows it.
|
|
85
93
|
/// PROXY, so [setOnline] deterministically severs/heals the whole plane's link to custody.
|
|
86
94
|
String get origin => 'http://${_proxy.address.host}:${_proxy.port}';
|
|
87
95
|
|
|
@@ -151,11 +159,12 @@ class NomosTestCloud {
|
|
|
151
159
|
);
|
|
152
160
|
}
|
|
153
161
|
final decoded = jsonDecode(text);
|
|
154
|
-
if (decoded
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
162
|
+
if (decoded
|
|
163
|
+
case {
|
|
164
|
+
'token': final String token,
|
|
165
|
+
'issuer': final String issuer,
|
|
166
|
+
'audience': final String audience,
|
|
167
|
+
} when token.isNotEmpty && issuer.isNotEmpty && audience.isNotEmpty) {
|
|
159
168
|
return DevIdentityToken(
|
|
160
169
|
token: token,
|
|
161
170
|
issuer: issuer,
|
|
@@ -169,7 +178,7 @@ class NomosTestCloud {
|
|
|
169
178
|
|
|
170
179
|
/// Start the test cloud: spawn `node <serverEntry> --port <n> [--ephemeral] [--data <dir>]`, wait until its
|
|
171
180
|
/// `/health` answers, then bring up the partition proxy in front of it. [serverEntry] is the dev-server
|
|
172
|
-
/// entry (`
|
|
181
|
+
/// entry (`platform-shells/node/local-development/server.ts` in-repo, or `dist/dev-server.mjs` from a published `githolon`) — the
|
|
173
182
|
/// caller resolves it (the same seam the offline harness uses for its install helper). [node] defaults to
|
|
174
183
|
/// `node` on PATH.
|
|
175
184
|
static Future<NomosTestCloud> start({
|
|
@@ -194,16 +203,50 @@ class NomosTestCloud {
|
|
|
194
203
|
/// not made current on the parent merely to make it available to a child.
|
|
195
204
|
List<String> lawUsdzPaths = const [],
|
|
196
205
|
int? applicationMaxChildWorkspacesPerUser,
|
|
197
|
-
|
|
206
|
+
|
|
207
|
+
/// The runtime bundle the shell runs (`holon.wasm`, `kernel.repository.xml`,
|
|
208
|
+
/// `bootstrap.law.usdz`, `nomos.law.usdz`). Defaults to the candidate/offline
|
|
209
|
+
/// runtime this process was pointed at.
|
|
210
|
+
String? runtimeDirectory,
|
|
211
|
+
|
|
212
|
+
/// Mint this universe's ed25519 trust root at boot and pin its public half.
|
|
213
|
+
/// A platform can only be born under a root warranted to a trust root.
|
|
214
|
+
bool? mintTrustRoot,
|
|
215
|
+
|
|
216
|
+
/// Serve this universe's ES256 identity provider (JWKS + the operator mint
|
|
217
|
+
/// door the warranted first-device enrolment onboards through).
|
|
218
|
+
bool? testIdentityProvider,
|
|
219
|
+
Duration readyTimeout = const Duration(seconds: 90),
|
|
198
220
|
void Function(String line)? onDiagnostic,
|
|
199
221
|
}) async {
|
|
200
222
|
final chosenPort = port == 0 ? await _freePort() : port;
|
|
223
|
+
// A platform birth needs this universe's trust root SECRET to sign root's warrant and the
|
|
224
|
+
// platform's birth certificate, and onboarding needs an identity provider: when a platform is
|
|
225
|
+
// requested the shell mints both unless told otherwise.
|
|
226
|
+
final mintsTrustRoot = mintTrustRoot ?? (platform != null);
|
|
227
|
+
final servesIdentityProvider = testIdentityProvider ?? (platform != null);
|
|
228
|
+
final runtime = runtimeDirectory ??
|
|
229
|
+
Platform.environment['NOMOS_CANDIDATE_RUNTIME'] ??
|
|
230
|
+
Platform.environment['NOMOS_OFFLINE_RUNTIME'];
|
|
231
|
+
// The partition proxy is the cloud's public origin: the peer is booted with it as its provider, so
|
|
232
|
+
// the cloud must advertise it (discovery, placement, leases) exactly as production advertises the
|
|
233
|
+
// origin a request arrives at. A peer never talks to an origin it was not booted with.
|
|
234
|
+
final proxy = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
|
201
235
|
final args = <String>[
|
|
202
236
|
serverEntry,
|
|
203
237
|
'--port',
|
|
204
238
|
'$chosenPort',
|
|
205
|
-
|
|
206
|
-
|
|
239
|
+
'--public-origin',
|
|
240
|
+
'http://${proxy.address.host}:${proxy.port}',
|
|
241
|
+
// NOMOS_TEST_CLOUD_DATA keeps the custodian's Git custody on disk after the run (inspection with
|
|
242
|
+
// git of what the custodian admitted and birthed), instead of the deleted temporary directory.
|
|
243
|
+
if (ephemeral && Platform.environment['NOMOS_TEST_CLOUD_DATA'] == null)
|
|
244
|
+
'--ephemeral',
|
|
245
|
+
if (dataDir ?? Platform.environment['NOMOS_TEST_CLOUD_DATA']
|
|
246
|
+
case final data?) ...['--data', data],
|
|
247
|
+
if (runtime != null) ...['--runtime', runtime],
|
|
248
|
+
if (mintsTrustRoot) '--mint-trust-root',
|
|
249
|
+
if (servesIdentityProvider) '--test-identity-provider',
|
|
207
250
|
if (platform != null) ...['--platform', platform],
|
|
208
251
|
if (applicationMaxChildWorkspacesPerUser != null) ...[
|
|
209
252
|
'--application-max-child-workspaces-per-user',
|
|
@@ -224,6 +267,7 @@ class NomosTestCloud {
|
|
|
224
267
|
if (serverTail.length > 24) serverTail.removeAt(0);
|
|
225
268
|
log('$stream: $line');
|
|
226
269
|
}
|
|
270
|
+
|
|
227
271
|
proc.stdout
|
|
228
272
|
.transform(utf8.decoder)
|
|
229
273
|
.transform(const LineSplitter())
|
|
@@ -242,7 +286,7 @@ class NomosTestCloud {
|
|
|
242
286
|
// half-born platform's typed refusals.
|
|
243
287
|
final deadline = DateTime.now().add(readyTimeout);
|
|
244
288
|
var ready = false;
|
|
245
|
-
String?
|
|
289
|
+
String? trustRootPublicKey;
|
|
246
290
|
while (DateTime.now().isBefore(deadline)) {
|
|
247
291
|
if (prematureExitCode != null) break;
|
|
248
292
|
try {
|
|
@@ -253,7 +297,9 @@ class NomosTestCloud {
|
|
|
253
297
|
final health = jsonDecode(body) as Map<String, dynamic>;
|
|
254
298
|
final platformReady = health['platformReady'];
|
|
255
299
|
if (platform == null || platformReady == true) {
|
|
256
|
-
|
|
300
|
+
trustRootPublicKey =
|
|
301
|
+
(health['trustRootPublicKey'] ?? health['testKRootPublic'])
|
|
302
|
+
?.toString();
|
|
257
303
|
ready = true;
|
|
258
304
|
break;
|
|
259
305
|
}
|
|
@@ -265,8 +311,10 @@ class NomosTestCloud {
|
|
|
265
311
|
}
|
|
266
312
|
if (!ready) {
|
|
267
313
|
if (prematureExitCode == null) proc.kill(ProcessSignal.sigkill);
|
|
314
|
+
await proxy.close(force: true);
|
|
268
315
|
final exited = prematureExitCode;
|
|
269
|
-
final tail =
|
|
316
|
+
final tail =
|
|
317
|
+
serverTail.isEmpty ? '' : '\nserver tail:\n${serverTail.join('\n')}';
|
|
270
318
|
throw NomosTestCloudException(
|
|
271
319
|
exited == null
|
|
272
320
|
? 'the dev cloud did not answer /health${platform != null ? ' with platformReady:true' : ''} within ${readyTimeout.inSeconds}s (serverEntry: $serverEntry)$tail'
|
|
@@ -278,14 +326,13 @@ class NomosTestCloud {
|
|
|
278
326
|
);
|
|
279
327
|
|
|
280
328
|
// The partition proxy — forwards to the dev cloud when ONLINE, fails fast when OFFLINE.
|
|
281
|
-
final proxy = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
|
282
329
|
final cloud = NomosTestCloud._(
|
|
283
330
|
proc,
|
|
284
331
|
proxy,
|
|
285
332
|
upstream,
|
|
286
333
|
client,
|
|
287
334
|
onDiagnostic,
|
|
288
|
-
|
|
335
|
+
trustRootPublicKey,
|
|
289
336
|
);
|
|
290
337
|
proxy.listen(cloud._handleProxy);
|
|
291
338
|
log('partition proxy at ${cloud.origin} → $upstream');
|
|
@@ -5,27 +5,40 @@ import 'package:meta/meta.dart' show internal;
|
|
|
5
5
|
/// One compiler-authored, nominal domain call.
|
|
6
6
|
///
|
|
7
7
|
/// Generated applications construct this directly from their typed input. The
|
|
8
|
-
/// host may carry it but cannot reinterpret its value; the kernel
|
|
9
|
-
///
|
|
10
|
-
/// exact identities embedded in [canonicalUsda].
|
|
8
|
+
/// host may carry it but cannot reinterpret its value; the kernel derives the
|
|
9
|
+
/// exact Protobuf descriptor from installed law and authors canonical USDA.
|
|
11
10
|
@internal
|
|
12
11
|
abstract interface class NmsGeneratedCall {
|
|
13
12
|
String get domain;
|
|
14
13
|
String get directive;
|
|
15
|
-
|
|
14
|
+
String get protobufType;
|
|
15
|
+
Uint8List get protobufPayload;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/// One compiler-authored nominal application query.
|
|
19
19
|
///
|
|
20
20
|
/// The public application method retains its generated Dart parameter types. This value is the
|
|
21
|
-
/// cross-language continuation of those types
|
|
22
|
-
///
|
|
23
|
-
///
|
|
21
|
+
/// cross-language continuation of those types. Its operation-specific Protobuf
|
|
22
|
+
/// message is generated from the same law graph as the public Dart method and
|
|
23
|
+
/// the kernel's installed descriptor.
|
|
24
24
|
@internal
|
|
25
25
|
abstract interface class NmsGeneratedQuery {
|
|
26
26
|
String get domain;
|
|
27
27
|
String get query;
|
|
28
|
-
|
|
28
|
+
String get protobufType;
|
|
29
|
+
Uint8List get protobufPayload;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// One compiler-authored nominal application result.
|
|
33
|
+
///
|
|
34
|
+
/// The peer office transports the kernel's query-specific Protobuf `Any`
|
|
35
|
+
/// without interpreting it. Generated application code checks [protobufType]
|
|
36
|
+
/// and decodes [protobufPayload] with the operation bindings emitted from the
|
|
37
|
+
/// same composed law graph as its public Dart API.
|
|
38
|
+
@internal
|
|
39
|
+
abstract interface class NmsGeneratedResult {
|
|
40
|
+
String get protobufType;
|
|
41
|
+
Uint8List get protobufPayload;
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
/// Constructor namespace reserved for generated application code.
|
|
@@ -33,21 +46,24 @@ abstract interface class NmsGeneratedQuery {
|
|
|
33
46
|
/// Keeping the three transport facts in one immutable value prevents generated
|
|
34
47
|
/// code from accidentally pairing bytes from one directive with routing hints
|
|
35
48
|
/// from another. Untrusted callers gain no authority by constructing one: the
|
|
36
|
-
/// kernel independently validates the
|
|
49
|
+
/// kernel independently validates the operation Protobuf against admitted law.
|
|
37
50
|
@internal
|
|
38
51
|
abstract final class NmsInternalGeneratedCalls {
|
|
39
52
|
static NmsGeneratedCall create({
|
|
40
53
|
required String domain,
|
|
41
54
|
required String directive,
|
|
42
|
-
required
|
|
55
|
+
required String protobufType,
|
|
56
|
+
required Uint8List protobufPayload,
|
|
43
57
|
}) {
|
|
44
58
|
if (domain.isEmpty || directive.isEmpty) {
|
|
45
|
-
throw ArgumentError(
|
|
59
|
+
throw ArgumentError(
|
|
60
|
+
'A generated Nomos call needs nominal routing identity.');
|
|
46
61
|
}
|
|
47
|
-
if (
|
|
48
|
-
throw ArgumentError(
|
|
62
|
+
if (!protobufType.startsWith('type.nomos.dev/')) {
|
|
63
|
+
throw ArgumentError(
|
|
64
|
+
'A generated Nomos call needs one exact typed Protobuf payload.');
|
|
49
65
|
}
|
|
50
|
-
return _GeneratedCall(domain, directive,
|
|
66
|
+
return _GeneratedCall(domain, directive, protobufType, protobufPayload);
|
|
51
67
|
}
|
|
52
68
|
}
|
|
53
69
|
|
|
@@ -57,20 +73,47 @@ abstract final class NmsInternalGeneratedQueries {
|
|
|
57
73
|
static NmsGeneratedQuery create({
|
|
58
74
|
required String domain,
|
|
59
75
|
required String query,
|
|
60
|
-
required
|
|
76
|
+
required String protobufType,
|
|
77
|
+
required Uint8List protobufPayload,
|
|
61
78
|
}) {
|
|
62
79
|
if (domain.isEmpty || query.isEmpty) {
|
|
63
|
-
throw ArgumentError(
|
|
80
|
+
throw ArgumentError(
|
|
81
|
+
'A generated Nomos query needs nominal routing identity.');
|
|
82
|
+
}
|
|
83
|
+
// No-argument reads (first/take) canonically encode as zero bytes. The
|
|
84
|
+
// nominal type identifies the message; installed law validates its fields.
|
|
85
|
+
// Payload length cannot distinguish a valid empty message from missing input.
|
|
86
|
+
if (!protobufType.startsWith('type.nomos.dev/')) {
|
|
87
|
+
throw ArgumentError(
|
|
88
|
+
'A generated Nomos query needs one exact typed Protobuf payload.');
|
|
64
89
|
}
|
|
65
|
-
|
|
66
|
-
|
|
90
|
+
return _GeneratedQuery(domain, query, protobufType, protobufPayload);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/// Constructor namespace reserved for the shared peer office.
|
|
95
|
+
@internal
|
|
96
|
+
abstract final class NmsInternalGeneratedResults {
|
|
97
|
+
static NmsGeneratedResult create({
|
|
98
|
+
required String protobufType,
|
|
99
|
+
required Uint8List protobufPayload,
|
|
100
|
+
}) {
|
|
101
|
+
// A valid Protobuf message containing only default values has the canonical
|
|
102
|
+
// wire representation of zero bytes. In particular, a generated query
|
|
103
|
+
// whose repeated result is empty must still cross this boundary as its
|
|
104
|
+
// exact nominal result type. The type URL supplies that identity; payload
|
|
105
|
+
// length is not a type or validity signal.
|
|
106
|
+
if (!protobufType.startsWith('type.nomos.dev/')) {
|
|
107
|
+
throw ArgumentError(
|
|
108
|
+
'A generated Nomos result needs one exact typed Protobuf payload.');
|
|
67
109
|
}
|
|
68
|
-
return
|
|
110
|
+
return _GeneratedResult(protobufType, protobufPayload);
|
|
69
111
|
}
|
|
70
112
|
}
|
|
71
113
|
|
|
72
114
|
final class _GeneratedCall implements NmsGeneratedCall {
|
|
73
|
-
const _GeneratedCall(
|
|
115
|
+
const _GeneratedCall(
|
|
116
|
+
this.domain, this.directive, this.protobufType, this.protobufPayload);
|
|
74
117
|
|
|
75
118
|
@override
|
|
76
119
|
final String domain;
|
|
@@ -79,11 +122,15 @@ final class _GeneratedCall implements NmsGeneratedCall {
|
|
|
79
122
|
final String directive;
|
|
80
123
|
|
|
81
124
|
@override
|
|
82
|
-
final
|
|
125
|
+
final String protobufType;
|
|
126
|
+
|
|
127
|
+
@override
|
|
128
|
+
final Uint8List protobufPayload;
|
|
83
129
|
}
|
|
84
130
|
|
|
85
131
|
final class _GeneratedQuery implements NmsGeneratedQuery {
|
|
86
|
-
const _GeneratedQuery(
|
|
132
|
+
const _GeneratedQuery(
|
|
133
|
+
this.domain, this.query, this.protobufType, this.protobufPayload);
|
|
87
134
|
|
|
88
135
|
@override
|
|
89
136
|
final String domain;
|
|
@@ -92,5 +139,18 @@ final class _GeneratedQuery implements NmsGeneratedQuery {
|
|
|
92
139
|
final String query;
|
|
93
140
|
|
|
94
141
|
@override
|
|
95
|
-
final
|
|
142
|
+
final String protobufType;
|
|
143
|
+
|
|
144
|
+
@override
|
|
145
|
+
final Uint8List protobufPayload;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
final class _GeneratedResult implements NmsGeneratedResult {
|
|
149
|
+
const _GeneratedResult(this.protobufType, this.protobufPayload);
|
|
150
|
+
|
|
151
|
+
@override
|
|
152
|
+
final String protobufType;
|
|
153
|
+
|
|
154
|
+
@override
|
|
155
|
+
final Uint8List protobufPayload;
|
|
96
156
|
}
|