@githolon/dsl 0.101.6 → 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.
- package/dart/CHANGELOG.md +13 -0
- package/dart/lib/nomos_client.dart +3 -52
- package/dart/lib/src/dev_cloud.dart +5 -0
- package/dart/lib/src/home.dart +10 -15
- package/dart/lib/src/nms_conformance_runtime.dart +12 -0
- package/dart/lib/src/nms_generated_runtime.dart +29 -0
- package/dart/lib/src/nms_test_environment.dart +8 -0
- package/dart/lib/src/node_runner_transport.dart +56 -18
- package/dart/lib/src/provider.dart +5 -1
- package/dart/lib/src/record_origin.dart +55 -0
- package/dart/lib/src/runner/node-entry.mjs +9105 -0
- package/dart/lib/src/runner/offline-install.mjs +4729 -0
- package/dart/lib/src/session_bound.dart +23 -10
- package/dart/lib/src/source_trust.dart +51 -0
- package/dart/lib/src/test_harness.dart +490 -58
- package/dart/lib/src/webview_bridge.dart +167 -58
- package/dart/lib/src/workspace_name.dart +7 -1
- package/dart/pubspec.lock +3 -3
- package/dart/pubspec.yaml +4 -2
- package/dart/test/acquire_session_credentials_test.dart +34 -17
- package/dart/test/acquire_session_test.dart +109 -24
- package/dart/test/adv_realm_interference_test.dart +227 -99
- package/dart/test/bundle_version_pairing_test.dart +1 -1
- package/dart/test/cloud_bound_topology_test.dart +1 -1
- package/dart/test/cluster_attested_test.dart +52 -35
- package/dart/test/cluster_births_test.dart +5 -2
- package/dart/test/cluster_device_keyed_acceptance_test.dart +5 -2
- package/dart/test/cluster_local_autosync_test.dart +5 -2
- package/dart/test/cluster_scale_test.dart +5 -2
- package/dart/test/compat_test.dart +1 -1
- package/dart/test/dlq_session_surface_test.dart +2 -1
- package/dart/test/errors_test.dart +1 -1
- package/dart/test/first_app_gauntlet_test.dart +78 -51
- package/dart/test/four_layer_nested_topology_test.dart +1 -1
- package/dart/test/harness_phase_timeout_test.dart +1 -1
- package/dart/test/home_parity_test.dart +9 -5
- package/dart/test/local_sync_inert_test.dart +22 -14
- package/dart/test/node_runner_transport_test.dart +9 -5
- package/dart/test/null_slot_test.dart +1 -1
- package/dart/test/parent_signer_recovery_test.dart +5 -2
- package/dart/test/schema_validation_test.dart +1 -1
- package/dart/test/sealing_client_test.dart +2 -1
- package/dart/test/session_bound_test.dart +92 -119
- package/dart/test/stale_bundle_test.dart +1 -1
- package/dart/test/test_harness_test.dart +77 -22
- package/dart/test/vo_read_typing_test.dart +32 -14
- package/dart/test/watch_after_offer_stall_test.dart +2 -1
- package/dart/test/webview_bridge_test.dart +17 -4
- package/dart/test/wire_test.dart +1 -1
- package/dart_types/CHANGELOG.md +8 -0
- package/dart_types/lib/nomos_types.dart +7 -6
- package/dart_types/lib/src/activity.dart +23 -13
- package/dart_types/lib/src/foreign_ref.dart +61 -112
- package/dart_types/lib/src/invitation.dart +96 -0
- package/dart_types/lib/src/nomos_ref.dart +97 -59
- package/dart_types/pubspec.yaml +1 -1
- package/dart_types/test/surfaced_test.dart +125 -19
- package/package.json +7 -3
- package/runtime/generated-application-host.js +8851 -0
- package/src/activity.ts +2 -2
- package/src/aggregate.ts +24 -1
- package/src/application_composition.ts +282 -0
- package/src/application_topology.ts +151 -0
- package/src/attested_core.ts +2 -2
- package/src/authoring_context.ts +9 -0
- package/src/birth_meter_ensure.ts +1 -1
- package/src/births.ts +53 -5
- package/src/build_package.ts +79 -71
- package/src/business_birth.ts +93 -10
- package/src/clear_directive.ts +3 -1
- package/src/codegen_dart.ts +369 -420
- package/src/codegen_dart_application.ts +1508 -0
- package/src/codegen_dart_client.ts +156 -95
- package/src/codegen_dart_scenario.ts +299 -0
- package/src/codegen_openapi.ts +8 -3
- package/src/codegen_proof.ts +1113 -1137
- package/src/codegen_provider_dart.ts +12 -1
- package/src/codegen_ts.ts +1176 -496
- package/src/compat_package_main.ts +22 -10
- package/src/compile_package_main.ts +1536 -337
- package/src/contract.ts +10 -4
- package/src/dart_barrel_guard.ts +5 -1
- package/src/describe_model.ts +13 -5
- package/src/directive.ts +244 -5
- package/src/engine_entry.ts +56 -13
- package/src/engine_javascript.ts +31 -0
- package/src/evolve_preview.ts +3 -12
- package/src/framework/application_home.ts +24 -10
- package/src/framework/capability.ts +15 -1
- package/src/framework/domain_lifecycle.ts +8 -0
- package/src/framework/framework_aggregates.ts +2 -2
- package/src/framework/genesis.ts +11 -1
- package/src/framework/home.ts +178 -75
- package/src/framework/impure_capability.ts +24 -7
- package/src/framework/relations.ts +13 -5
- package/src/framework/workspaces.ts +13 -12
- package/src/generated_client_names.ts +42 -3
- package/src/idof_lint.ts +65 -13
- package/src/index.ts +46 -12
- package/src/intent.ts +587 -0
- package/src/law_check.ts +64 -16
- package/src/precondition.ts +16 -4
- package/src/read_projection_namespace.ts +2 -7
- package/src/recipient.ts +33 -0
- package/src/relation_schema.ts +93 -0
- package/src/secondary_ensure.ts +11 -2
- package/src/shape_compat.ts +11 -1
- package/src/usd.ts +30 -8
- package/src/usd_layers.ts +447 -246
- package/src/usd_state.ts +1 -1
- package/src/value_object.ts +49 -13
- package/src/wire_encode.ts +124 -26
- package/src/workspace_sharing.ts +269 -0
- package/src/zod_introspection.ts +84 -0
- package/dart/example/nomos_secure_key_store.dart +0 -82
- package/dart/example/nomos_webview_transport.dart +0 -63
- package/dart/lib/nomos_headless.dart +0 -50
- package/dart/lib/testing.dart +0 -14
- package/dart/test/co2_product_gauntlet_test.dart +0 -244
- 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).
|
|
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
|
-
//
|
|
8
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
21
|
-
|
|
19
|
+
/// The application/workspace that owns the record.
|
|
20
|
+
String get workspace => _workspace;
|
|
22
21
|
|
|
23
|
-
/// The
|
|
24
|
-
|
|
22
|
+
/// The stable aggregate kind carried by this reference.
|
|
23
|
+
String get type => _type;
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
/// The stable identity of the record within its workspace.
|
|
26
|
+
String get id => _id;
|
|
27
27
|
|
|
28
|
-
/// The stable
|
|
29
|
-
///
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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(
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
69
|
-
|
|
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
|
}
|
package/dart_types/pubspec.yaml
CHANGED
|
@@ -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.
|
|
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(
|
|
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,
|
|
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(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
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'),
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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.
|
|
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
|
}
|