@githolon/dsl 0.101.5 → 0.102.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.
Files changed (120) hide show
  1. package/dart/CHANGELOG.md +13 -0
  2. package/dart/lib/nomos_client.dart +3 -52
  3. package/dart/lib/src/dev_cloud.dart +5 -0
  4. package/dart/lib/src/home.dart +10 -15
  5. package/dart/lib/src/nms_conformance_runtime.dart +12 -0
  6. package/dart/lib/src/nms_generated_runtime.dart +29 -0
  7. package/dart/lib/src/nms_test_environment.dart +8 -0
  8. package/dart/lib/src/node_runner_transport.dart +56 -18
  9. package/dart/lib/src/provider.dart +5 -1
  10. package/dart/lib/src/record_origin.dart +55 -0
  11. package/dart/lib/src/runner/node-entry.mjs +9105 -0
  12. package/dart/lib/src/runner/offline-install.mjs +4729 -0
  13. package/dart/lib/src/session_bound.dart +23 -10
  14. package/dart/lib/src/source_trust.dart +51 -0
  15. package/dart/lib/src/test_harness.dart +490 -58
  16. package/dart/lib/src/webview_bridge.dart +167 -58
  17. package/dart/lib/src/workspace_name.dart +7 -1
  18. package/dart/pubspec.lock +3 -3
  19. package/dart/pubspec.yaml +4 -2
  20. package/dart/test/acquire_session_credentials_test.dart +34 -17
  21. package/dart/test/acquire_session_test.dart +109 -24
  22. package/dart/test/adv_realm_interference_test.dart +227 -99
  23. package/dart/test/bundle_version_pairing_test.dart +1 -1
  24. package/dart/test/cloud_bound_topology_test.dart +1 -1
  25. package/dart/test/cluster_attested_test.dart +52 -35
  26. package/dart/test/cluster_births_test.dart +5 -2
  27. package/dart/test/cluster_device_keyed_acceptance_test.dart +5 -2
  28. package/dart/test/cluster_local_autosync_test.dart +5 -2
  29. package/dart/test/cluster_scale_test.dart +5 -2
  30. package/dart/test/compat_test.dart +1 -1
  31. package/dart/test/dlq_session_surface_test.dart +2 -1
  32. package/dart/test/errors_test.dart +1 -1
  33. package/dart/test/first_app_gauntlet_test.dart +78 -51
  34. package/dart/test/four_layer_nested_topology_test.dart +1 -1
  35. package/dart/test/harness_phase_timeout_test.dart +1 -1
  36. package/dart/test/home_parity_test.dart +9 -5
  37. package/dart/test/local_sync_inert_test.dart +22 -14
  38. package/dart/test/node_runner_transport_test.dart +9 -5
  39. package/dart/test/null_slot_test.dart +1 -1
  40. package/dart/test/parent_signer_recovery_test.dart +5 -2
  41. package/dart/test/schema_validation_test.dart +1 -1
  42. package/dart/test/sealing_client_test.dart +2 -1
  43. package/dart/test/session_bound_test.dart +92 -119
  44. package/dart/test/stale_bundle_test.dart +1 -1
  45. package/dart/test/test_harness_test.dart +77 -22
  46. package/dart/test/vo_read_typing_test.dart +32 -14
  47. package/dart/test/watch_after_offer_stall_test.dart +2 -1
  48. package/dart/test/webview_bridge_test.dart +17 -4
  49. package/dart/test/wire_test.dart +1 -1
  50. package/dart_types/CHANGELOG.md +8 -0
  51. package/dart_types/lib/nomos_types.dart +7 -6
  52. package/dart_types/lib/src/activity.dart +23 -13
  53. package/dart_types/lib/src/foreign_ref.dart +61 -112
  54. package/dart_types/lib/src/invitation.dart +96 -0
  55. package/dart_types/lib/src/nomos_ref.dart +97 -59
  56. package/dart_types/pubspec.yaml +1 -1
  57. package/dart_types/test/surfaced_test.dart +125 -19
  58. package/package.json +7 -3
  59. package/runtime/generated-application-host.js +8851 -0
  60. package/src/activity.ts +2 -2
  61. package/src/aggregate.ts +24 -1
  62. package/src/application_composition.ts +282 -0
  63. package/src/application_topology.ts +151 -0
  64. package/src/attested_core.ts +2 -2
  65. package/src/authoring_context.ts +9 -0
  66. package/src/birth_meter_ensure.ts +1 -1
  67. package/src/births.ts +53 -5
  68. package/src/build_package.ts +79 -71
  69. package/src/business_birth.ts +93 -10
  70. package/src/clear_directive.ts +3 -1
  71. package/src/codegen_dart.ts +369 -420
  72. package/src/codegen_dart_application.ts +1508 -0
  73. package/src/codegen_dart_client.ts +156 -95
  74. package/src/codegen_dart_scenario.ts +299 -0
  75. package/src/codegen_openapi.ts +8 -3
  76. package/src/codegen_proof.ts +1113 -1137
  77. package/src/codegen_provider_dart.ts +12 -1
  78. package/src/codegen_ts.ts +1176 -496
  79. package/src/compat_package_main.ts +22 -10
  80. package/src/compile_package_main.ts +1536 -337
  81. package/src/contract.ts +10 -4
  82. package/src/dart_barrel_guard.ts +5 -1
  83. package/src/describe_model.ts +13 -5
  84. package/src/directive.ts +244 -5
  85. package/src/engine_entry.ts +56 -13
  86. package/src/engine_javascript.ts +31 -0
  87. package/src/evolve_preview.ts +3 -12
  88. package/src/framework/application_home.ts +24 -10
  89. package/src/framework/capability.ts +15 -1
  90. package/src/framework/domain_lifecycle.ts +8 -0
  91. package/src/framework/framework_aggregates.ts +2 -2
  92. package/src/framework/genesis.ts +11 -1
  93. package/src/framework/home.ts +178 -75
  94. package/src/framework/impure_capability.ts +24 -7
  95. package/src/framework/relations.ts +13 -5
  96. package/src/framework/workspaces.ts +13 -12
  97. package/src/generated_client_names.ts +42 -3
  98. package/src/idof_lint.ts +65 -13
  99. package/src/index.ts +46 -12
  100. package/src/intent.ts +587 -0
  101. package/src/law_check.ts +64 -16
  102. package/src/precondition.ts +16 -4
  103. package/src/read_projection_namespace.ts +2 -7
  104. package/src/recipient.ts +33 -0
  105. package/src/relation_schema.ts +93 -0
  106. package/src/secondary_ensure.ts +11 -2
  107. package/src/shape_compat.ts +11 -1
  108. package/src/usd.ts +30 -8
  109. package/src/usd_layers.ts +447 -246
  110. package/src/usd_state.ts +1 -1
  111. package/src/value_object.ts +49 -13
  112. package/src/wire_encode.ts +124 -26
  113. package/src/workspace_sharing.ts +269 -0
  114. package/src/zod_introspection.ts +84 -0
  115. package/dart/example/nomos_secure_key_store.dart +0 -82
  116. package/dart/example/nomos_webview_transport.dart +0 -63
  117. package/dart/lib/nomos_headless.dart +0 -50
  118. package/dart/lib/testing.dart +0 -14
  119. package/dart/test/co2_product_gauntlet_test.dart +0 -244
  120. package/src/framework/identity.ts +0 -537
@@ -0,0 +1,96 @@
1
+ library;
2
+
3
+ /// A framework-owned authority coordinate established from verified custody and representation.
4
+ final class Identity<TSubject> {
5
+ final String id;
6
+ final String address;
7
+
8
+ const Identity._(this.id, this.address);
9
+ }
10
+
11
+ /// The durable, independently attributable participant using an application.
12
+ ///
13
+ /// This is not a tenant Person row, login token, device, or application state.
14
+ final class User {
15
+ final Identity<User> identity;
16
+
17
+ const User._(this.identity);
18
+ }
19
+
20
+ abstract final class NmsInternalUsers {
21
+ static User create(
22
+ {required String identityId, required String identityAddress}) =>
23
+ User._(Identity<User>._(identityId, identityAddress));
24
+ }
25
+
26
+ /// A framework-created delivery address for one User.
27
+ ///
28
+ /// It is deliberately not a string: an email address, identity-provider uid,
29
+ /// principal, record id, or arbitrary application value cannot be passed to a
30
+ /// generated invitation action by mistake. A recipient carries no authority.
31
+ final class Recipient<TSubject> {
32
+ final String _address;
33
+
34
+ const Recipient._(this._address);
35
+
36
+ @override
37
+ bool operator ==(Object other) =>
38
+ other is Recipient<TSubject> && other._address == _address;
39
+
40
+ @override
41
+ int get hashCode => _address.hashCode;
42
+
43
+ @override
44
+ String toString() => 'Recipient<$TSubject>';
45
+ }
46
+
47
+ /// A single-use invitation to become a recipient of a business grant.
48
+ ///
49
+ /// Nomos owns creation, proof, redemption, replay rejection and delivery. Your
50
+ /// product owns transport: put [link] in an email, message, QR code or any other
51
+ /// channel. The transport address is never treated as the invited identity.
52
+ final class Invitation<TSubject> {
53
+ final Recipient<TSubject> recipient;
54
+ final String _token;
55
+
56
+ const Invitation._(this.recipient, this._token);
57
+
58
+ /// Attach this invitation to your application's join URL.
59
+ ///
60
+ /// The capability is kept in the URL fragment so ordinary HTTP servers and
61
+ /// access logs do not receive it. The generated application redeems the link.
62
+ String link(String baseUrl) {
63
+ final base = Uri.parse(baseUrl);
64
+ if (!base.hasScheme || base.host.isEmpty) {
65
+ throw ArgumentError.value(baseUrl, 'baseUrl', 'must be an absolute URL');
66
+ }
67
+ return base.replace(fragment: 'nomos-invitation=$_token').toString();
68
+ }
69
+ }
70
+
71
+ /// Framework-only construction and wire lowering for generated clients.
72
+ abstract final class NmsInternalInvitations {
73
+ static Recipient<TSubject> recipient<TSubject>(String address) {
74
+ if (address.trim().isEmpty)
75
+ throw StateError('Nomos produced an empty recipient address.');
76
+ return Recipient<TSubject>._(address);
77
+ }
78
+
79
+ static Invitation<TSubject> invitation<TSubject>({
80
+ required String address,
81
+ required String token,
82
+ }) =>
83
+ Invitation<TSubject>._(recipient<TSubject>(address), token);
84
+
85
+ static String address<TSubject>(Recipient<TSubject> recipient) =>
86
+ recipient._address;
87
+
88
+ static String token<TSubject>(Invitation<TSubject> invitation) =>
89
+ invitation._token;
90
+ }
91
+
92
+ /// Framework-only payload serializer used by generated directive classes.
93
+ abstract final class NmsInternalRecipients {
94
+ static String address<TSubject>(Recipient<TSubject> recipient) =>
95
+ NmsInternalInvitations.address(recipient);
96
+ }
@@ -1,75 +1,113 @@
1
- // NOMOS — THE ONE REFERENCE (architecture/nomos_ref.md). A [NomosRef] is the canonical, globally-unique,
2
- // workspace-qualified identity of an aggregate instance: `{ workspace, type, id }`, with the stable string
3
- // form `nomos://<workspace>/<type>/<id>`. It travels WITH the data by default — every generated read row,
4
- // write outcome, and activity ref carries (or views as) one — so a dev holding a thing can always point at
5
- // it: no client-side UUID pre-minting, no loose {workspaceId, id} string pairs, no re-query-and-diff.
1
+ // NOMOS — THE ONE REFERENCE (architecture/nomos_ref.md).
6
2
  //
7
- // A NomosRef is a LOCATOR (like ForeignRef, which remains the TYPED per-field view): `resolve` is an
8
- // informational read over the device's multi-workspace plane; law-grade attestation stays on the declared
9
- // attested-read lane. Pure nomos_types — no bridge/lifecycle imports.
3
+ // Tenant code gets a typed, inspectable identity value that it can retain, serialize and hand back to a
4
+ // generated business action/read. It cannot construct one or use it to reach runtime machinery.
10
5
  library;
11
6
 
12
- import 'foreign_ref.dart';
7
+ /// A framework-created, workspace-qualified reference to one generated aggregate type.
8
+ ///
9
+ /// Nomos creates these from committed business outcomes and projected records. Keep the value and pass it
10
+ /// to generated actions, `find` and `watchOne`; do not copy an id into application state. [TAggregate]
11
+ /// prevents a reference to one business kind being passed where another is required.
12
+ final class NomosRef<TAggregate> {
13
+ final String _workspace;
14
+ final String _type;
15
+ final String _id;
13
16
 
14
- /// The canonical typed reference to an aggregate instance: workspace + aggregate type + instance id.
15
- /// Value semantics; `uri` is the stable interop string (`nomos://<workspace>/<type>/<id>`).
16
- class NomosRef {
17
- /// The workspace holding the instance.
18
- final String workspace;
17
+ const NomosRef._(this._workspace, this._type, this._id);
19
18
 
20
- /// The aggregate TYPE (the read-projection type tag, e.g. `estate.EstateSite` or `EstateSite`).
21
- final String type;
19
+ /// The application/workspace that owns the record.
20
+ String get workspace => _workspace;
22
21
 
23
- /// The instance id (law-minted or law-defined).
24
- final String id;
22
+ /// The stable aggregate kind carried by this reference.
23
+ String get type => _type;
25
24
 
26
- const NomosRef({required this.workspace, required this.type, required this.id});
25
+ /// The stable identity of the record within its workspace.
26
+ String get id => _id;
27
27
 
28
- /// The stable string form — survives URLs, nav params, JSON, logs. Segments are URI-encoded so a
29
- /// workspace/type/id containing `/` or spaces round-trips.
30
- String get uri =>
31
- 'nomos://${Uri.encodeComponent(workspace)}/${Uri.encodeComponent(type)}/${Uri.encodeComponent(id)}';
28
+ /// The stable, portable address of this business record.
29
+ ///
30
+ /// Keep this in navigation state, URLs or messages when another part of the
31
+ /// application needs to recover the typed reference through its generated
32
+ /// aggregate collection. An address never grants access: generated reads and
33
+ /// actions still verify the signed-in person's authority when it is used.
34
+ String get address => 'nomos://${Uri.encodeComponent(_workspace)}/'
35
+ '${Uri.encodeComponent(_type)}/${Uri.encodeComponent(_id)}';
32
36
 
33
- /// Parse a `nomos://<workspace>/<type>/<id>` string (the inverse of [uri]). Throws [FormatException]
34
- /// on anything else.
35
- factory NomosRef.parse(String uri) {
36
- final u = Uri.tryParse(uri);
37
- if (u == null || u.scheme != 'nomos') {
38
- throw FormatException('NomosRef.parse: not a nomos:// uri', uri);
39
- }
40
- // nomos://<ws>/<type>/<id> — the workspace lands as the authority (host), type/id as path segments.
41
- final ws = Uri.decodeComponent(u.host);
42
- final segs = u.pathSegments.map(Uri.decodeComponent).toList();
43
- if (ws.isEmpty || segs.length != 2 || segs[0].isEmpty || segs[1].isEmpty) {
44
- throw FormatException('NomosRef.parse: expected nomos://<workspace>/<type>/<id>', uri);
45
- }
46
- return NomosRef(workspace: ws, type: segs[0], id: segs[1]);
47
- }
37
+ @override
38
+ bool operator ==(Object other) =>
39
+ other is NomosRef<Object?> &&
40
+ other._workspace == _workspace &&
41
+ other._type == _type &&
42
+ other._id == _id;
43
+
44
+ @override
45
+ int get hashCode => Object.hash(_workspace, _type, _id);
46
+
47
+ @override
48
+ String toString() => 'NomosRef<$TAggregate>';
49
+ }
50
+
51
+ /// Framework-only codec and locator access for generated implementation code.
52
+ ///
53
+ /// This is intentionally withheld from `package:nomos_types/nomos_types.dart` and from generated tenant
54
+ /// package barrels. It exists because Dart privacy is library-scoped: generated implementation libraries
55
+ /// need one explicit, auditable construction and wire-codec door while tenant code receives [NomosRef].
56
+ abstract final class NmsInternalNomosRefs {
57
+ static NomosRef<TAggregate> create<TAggregate>({
58
+ required String workspace,
59
+ required String type,
60
+ required String id,
61
+ }) =>
62
+ NomosRef<TAggregate>._(workspace, type, id);
48
63
 
49
- /// Accepts the `{workspace,type,id}` object OR the `nomos://` uri string.
50
- factory NomosRef.fromJson(Object? j) {
51
- if (j is String) return NomosRef.parse(j);
52
- final m = (j as Map).cast<String, dynamic>();
53
- return NomosRef(
54
- workspace: (m['workspace'] ?? '') as String,
55
- type: (m['type'] ?? '') as String,
56
- id: (m['id'] ?? '') as String,
64
+ static String workspace<TAggregate>(NomosRef<TAggregate> reference) =>
65
+ reference._workspace;
66
+
67
+ static String type<TAggregate>(NomosRef<TAggregate> reference) =>
68
+ reference._type;
69
+
70
+ static String id<TAggregate>(NomosRef<TAggregate> reference) => reference._id;
71
+
72
+ static NomosRef<TAggregate> fromJson<TAggregate>(Object? value) {
73
+ if (value is String) return fromUri<TAggregate>(value);
74
+ final map = (value as Map).cast<String, dynamic>();
75
+ return create<TAggregate>(
76
+ workspace: (map['workspace'] ?? '') as String,
77
+ type: (map['type'] ?? '') as String,
78
+ id: (map['id'] ?? '') as String,
57
79
  );
58
80
  }
59
81
 
60
- Map<String, dynamic> toJson() => {'workspace': workspace, 'type': type, 'id': id};
82
+ static Map<String, dynamic> toJson<TAggregate>(
83
+ NomosRef<TAggregate> reference,
84
+ ) =>
85
+ {
86
+ 'workspace': reference._workspace,
87
+ 'type': reference._type,
88
+ 'id': reference._id,
89
+ };
61
90
 
62
- /// Informational lookup of the referenced instance over the device's multi-workspace plane (the same
63
- /// reader `ForeignRef.resolve` uses — `bridge.foreignReader()` in nomos_client). Returns the raw
64
- /// `{type,id,data}` rows for the id in the ref's workspace (empty ⇒ not found / not visible).
65
- Future<List<Map<String, dynamic>>> resolve(NomosForeignReader nomos) =>
66
- nomos.foreignWorkspace(workspace).queryById(id);
91
+ static NomosRef<TAggregate> fromUri<TAggregate>(String value) {
92
+ final uri = Uri.tryParse(value);
93
+ if (uri == null || uri.scheme != 'nomos') {
94
+ throw FormatException('Expected a Nomos reference', value);
95
+ }
96
+ final workspace = Uri.decodeComponent(uri.host);
97
+ final segments = uri.pathSegments.map(Uri.decodeComponent).toList();
98
+ if (workspace.isEmpty ||
99
+ segments.length != 2 ||
100
+ segments[0].isEmpty ||
101
+ segments[1].isEmpty) {
102
+ throw FormatException('Expected a complete Nomos reference', value);
103
+ }
104
+ return create<TAggregate>(
105
+ workspace: workspace,
106
+ type: segments[0],
107
+ id: segments[1],
108
+ );
109
+ }
67
110
 
68
- @override
69
- bool operator ==(Object other) =>
70
- other is NomosRef && other.workspace == workspace && other.type == type && other.id == id;
71
- @override
72
- int get hashCode => Object.hash(workspace, type, id);
73
- @override
74
- String toString() => uri;
111
+ static String toUri<TAggregate>(NomosRef<TAggregate> reference) =>
112
+ reference.address;
75
113
  }
@@ -9,7 +9,7 @@ description: >-
9
9
  Pure kernel wire/data types for Nomos Dart frontends — no transport, no bridge,
10
10
  no runtime. The hand-written serde-JSON-compatible types plus the offer codec,
11
11
  reactive read engine, schema validation, and data-only error/trace types.
12
- version: 0.7.1
12
+ version: 0.8.0
13
13
 
14
14
  environment:
15
15
  sdk: ^3.5.0
@@ -1,7 +1,92 @@
1
1
  import 'package:nomos_types/nomos_types.dart';
2
+ import 'package:nomos_types/src/invitation.dart' show NmsInternalInvitations;
3
+ import 'package:nomos_types/src/nomos_ref.dart' show NmsInternalNomosRefs;
2
4
  import 'package:test/test.dart';
3
5
 
6
+ final class _Asset {}
7
+
4
8
  void main() {
9
+ test(
10
+ 'Invitation is transport-neutral and keeps its capability in the URL fragment',
11
+ () {
12
+ final invitation = NmsInternalInvitations.invitation<User>(
13
+ address: 'nomos-invitation:v1:public-key',
14
+ token: 'bearer-capability',
15
+ );
16
+
17
+ final link = invitation.link('https://tenant.example/join?campaign=summer');
18
+ final uri = Uri.parse(link);
19
+ expect(uri.origin, 'https://tenant.example');
20
+ expect(uri.path, '/join');
21
+ expect(uri.queryParameters, {'campaign': 'summer'});
22
+ expect(uri.fragment, 'nomos-invitation=bearer-capability');
23
+ expect(invitation.toString(), isNot(contains('bearer-capability')));
24
+ });
25
+
26
+ test('NomosRef compares by its public address', () {
27
+ final first = NmsInternalNomosRefs.create<_Asset>(
28
+ workspace: 'estate-one',
29
+ type: 'EstateAsset',
30
+ id: 'asset-one',
31
+ );
32
+ final same = NmsInternalNomosRefs.create<_Asset>(
33
+ workspace: 'estate-one',
34
+ type: 'EstateAsset',
35
+ id: 'asset-one',
36
+ );
37
+ final differentWorkspace = NmsInternalNomosRefs.create<_Asset>(
38
+ workspace: 'estate-two',
39
+ type: 'EstateAsset',
40
+ id: 'asset-one',
41
+ );
42
+
43
+ expect(first, same);
44
+ expect(first.hashCode, same.hashCode);
45
+ expect(first, isNot(differentWorkspace));
46
+ expect(first.workspace, 'estate-one');
47
+ expect(first.type, 'EstateAsset');
48
+ expect(first.id, 'asset-one');
49
+ expect(first.address, 'nomos://estate-one/EstateAsset/asset-one');
50
+ expect(NmsInternalNomosRefs.fromUri<_Asset>(first.address), first);
51
+ });
52
+
53
+ test('NomosRef address round-trips escaped public identity', () {
54
+ final reference = NmsInternalNomosRefs.create<_Asset>(
55
+ workspace: 'estate/one',
56
+ type: 'Estate Asset',
57
+ id: 'asset/one',
58
+ );
59
+
60
+ expect(
61
+ reference.address,
62
+ 'nomos://estate%2Fone/Estate%20Asset/asset%2Fone',
63
+ );
64
+ expect(NmsInternalNomosRefs.fromUri<_Asset>(reference.address), reference);
65
+ });
66
+
67
+ test(
68
+ 'business activity names who performed it without exposing an actor lane',
69
+ () {
70
+ const event = ActivityEvent(
71
+ eventId: 'event-1',
72
+ kind: 'estate.created',
73
+ performedBy: 'user:ada',
74
+ occurredAt: '2026-07-20T00:00:00Z',
75
+ title: 'Estate created',
76
+ message: 'Ada created the estate',
77
+ titleKey: 'activity.estate.created.title',
78
+ messageKey: 'activity.estate.created.message',
79
+ params: {},
80
+ refs: {},
81
+ severity: ActivitySeverity.success,
82
+ domain: 'estate',
83
+ directiveId: 'createEstate',
84
+ );
85
+ expect(event.performedBy, 'user:ada');
86
+ expect(event.toJson(), containsPair('performedBy', 'user:ada'));
87
+ expect(event.toJson(), isNot(contains('actorSubject')));
88
+ });
89
+
5
90
  group('SurfacedValue', () {
6
91
  test('a plain scalar decodes RESOLVED', () {
7
92
  final v = SurfacedValue<String>.fromJson('hello', (x) => x as String);
@@ -11,7 +96,9 @@ void main() {
11
96
  expect(v.pending, isEmpty);
12
97
  });
13
98
 
14
- test('the __surfaced envelope decodes PENDING (value + occurredAt + nullable author)', () {
99
+ test(
100
+ 'the __surfaced envelope decodes PENDING (value + occurredAt + nullable author)',
101
+ () {
15
102
  final v = SurfacedValue<String>.fromJson({
16
103
  '__surfaced': {
17
104
  'pending': [
@@ -34,29 +121,41 @@ void main() {
34
121
  expect(v.pending, hasLength(2));
35
122
  expect(v.pending[0].value, 'a');
36
123
  expect(v.pending[0].author, 'user:ada');
37
- expect(v.pending[0].occurredAt, const Hlc(physical: 10, logical: 1, replica: 7));
124
+ expect(v.pending[0].occurredAt,
125
+ const Hlc(physical: 10, logical: 1, replica: 7));
38
126
  expect(v.pending[1].value, 'b');
39
127
  expect(v.pending[1].author, isNull);
40
128
  });
41
129
 
42
- test('decode() off a flat data map: absent/null => null (partial-fold doctrine)', () {
43
- expect(SurfacedValue.decode<String>({}, 'title', (x) => x as String), isNull);
44
- expect(SurfacedValue.decode<String>({'title': null}, 'title', (x) => x as String), isNull);
45
- final v = SurfacedValue.decode<String>({'title': 't'}, 'title', (x) => x as String);
130
+ test(
131
+ 'decode() off a flat data map: absent/null => null (partial-fold doctrine)',
132
+ () {
133
+ expect(SurfacedValue.decode<String>({}, 'title', (x) => x as String),
134
+ isNull);
135
+ expect(
136
+ SurfacedValue.decode<String>(
137
+ {'title': null}, 'title', (x) => x as String),
138
+ isNull);
139
+ final v = SurfacedValue.decode<String>(
140
+ {'title': 't'}, 'title', (x) => x as String);
46
141
  expect(v, const SurfacedResolved<String>('t'));
47
142
  });
48
143
 
49
- test('mixed-schema values stay withheld until field evolution is available', () {
50
- final v = SurfacedValue<String>.fromJson({
51
- '__surfaced': {
52
- 'status': 'evolutionRequired',
53
- 'targetSchema': 'title-v2',
54
- 'evolution': {
55
- 'sourceSchemas': ['title-v1'],
56
- 'authoredUnder': ['law-v1'],
144
+ test('mixed-schema values stay withheld until field evolution is available',
145
+ () {
146
+ final v = SurfacedValue<String>.fromJson(
147
+ {
148
+ '__surfaced': {
149
+ 'status': 'evolutionRequired',
150
+ 'targetSchema': 'title-v2',
151
+ 'evolution': {
152
+ 'sourceSchemas': ['title-v1'],
153
+ 'authoredUnder': ['law-v1'],
154
+ },
155
+ },
57
156
  },
58
- },
59
- }, (_) => throw StateError('must not cast an old value to the current type'));
157
+ (_) => throw StateError(
158
+ 'must not cast an old value to the current type'));
60
159
  expect(v, isA<SurfacedEvolutionRequired<String>>());
61
160
  final blocked = v as SurfacedEvolutionRequired<String>;
62
161
  expect(blocked.targetSchema, 'title-v2');
@@ -66,18 +165,25 @@ void main() {
66
165
  });
67
166
 
68
167
  test('value equality holds on both arms', () {
69
- expect(const SurfacedResolved<String>('x'), const SurfacedResolved<String>('x'));
168
+ expect(const SurfacedResolved<String>('x'),
169
+ const SurfacedResolved<String>('x'));
70
170
  final p1 = SurfacedValue<String>.fromJson({
71
171
  '__surfaced': {
72
172
  'pending': [
73
- {'value': 'a', 'occurredAt': {'physical': 1, 'logical': 0, 'replica': 1}},
173
+ {
174
+ 'value': 'a',
175
+ 'occurredAt': {'physical': 1, 'logical': 0, 'replica': 1}
176
+ },
74
177
  ],
75
178
  },
76
179
  }, (x) => x as String);
77
180
  final p2 = SurfacedValue<String>.fromJson({
78
181
  '__surfaced': {
79
182
  'pending': [
80
- {'value': 'a', 'occurredAt': {'physical': 1, 'logical': 0, 'replica': 1}},
183
+ {
184
+ 'value': 'a',
185
+ 'occurredAt': {'physical': 1, 'logical': 0, 'replica': 1}
186
+ },
81
187
  ],
82
188
  },
83
189
  }, (x) => x as String);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.101.5",
3
+ "version": "0.102.0",
4
4
  "type": "module",
5
5
  "description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -21,6 +21,7 @@
21
21
  "./compose": "./src/compose.ts",
22
22
  "./usd": "./src/usd.ts",
23
23
  "./usd-layers": "./src/usd_layers.ts",
24
+ "./application-composition": "./src/application_composition.ts",
24
25
  "./usd-state": "./src/usd_state.ts",
25
26
  "./engine-entry": "./src/engine_entry.ts",
26
27
  "./workspace-type": "./src/workspace_type.ts",
@@ -31,7 +32,6 @@
31
32
  "./codegen-dart": "./src/codegen_dart.ts",
32
33
  "./codegen-dot": "./src/codegen_dot.ts",
33
34
  "./codegen-provider": "./src/codegen_provider_dart.ts",
34
- "./framework/identity": "./src/framework/identity.ts",
35
35
  "./framework/disclosure": "./src/framework/disclosure.ts",
36
36
  "./framework/bootstrap": "./src/framework/bootstrap.ts",
37
37
  "./framework/domain_lifecycle": "./src/framework/domain_lifecycle.ts",
@@ -43,12 +43,14 @@
43
43
  "files": [
44
44
  "src",
45
45
  "!src/**/*.test.ts",
46
+ "!src/framework/identity.ts",
46
47
  "dart",
47
48
  "!dart/.dart_tool",
48
49
  "!dart/build",
49
50
  "dart_types",
50
51
  "!dart_types/.dart_tool",
51
52
  "!dart_types/build",
53
+ "runtime",
52
54
  "compile_package.mjs",
53
55
  "check_package.mjs",
54
56
  "compat_package.mjs",
@@ -58,19 +60,21 @@
58
60
  "access": "public"
59
61
  },
60
62
  "scripts": {
63
+ "build:application-runtime": "node scripts/build_application_runtime.mjs",
64
+ "prepack": "npm run build:application-runtime",
61
65
  "typecheck": "tsc --noEmit",
62
66
  "test": "vitest run"
63
67
  },
64
68
  "dependencies": {
65
69
  "esbuild": "0.24.2",
66
70
  "tsx": "^4.19.2",
71
+ "typescript": "^5.6.3",
67
72
  "vscode-languageserver": "^9.0.1",
68
73
  "vscode-languageserver-textdocument": "^1.0.12",
69
74
  "zod": "^4.4.3"
70
75
  },
71
76
  "devDependencies": {
72
77
  "@types/node": "^25.9.2",
73
- "typescript": "^5.6.3",
74
78
  "vitest": "^2.1.8"
75
79
  }
76
80
  }