@githolon/dsl 0.66.0 → 0.68.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 +14 -0
- package/dart/lib/src/webview_bridge.dart +71 -2
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart_types/CHANGELOG.md +14 -0
- package/dart_types/lib/nomos_types.dart +2 -0
- package/dart_types/lib/src/activity.dart +173 -0
- package/dart_types/lib/src/foreign_ref.dart +6 -0
- package/dart_types/lib/src/nomos_ref.dart +75 -0
- package/dart_types/pubspec.yaml +1 -1
- package/package.json +1 -1
- package/src/activity.ts +197 -0
- package/src/codegen_dart.ts +168 -2
- package/src/codegen_dart_client.ts +97 -43
- package/src/codegen_ts.ts +215 -58
- package/src/compile_package_main.ts +28 -3
- package/src/directive.ts +28 -0
- package/src/index.ts +1 -0
package/dart/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 0.45.0
|
|
2
|
+
|
|
3
|
+
- `offerOutcome(...)` — the one outcome-returning offer lane generated clients now call for EVERY directive:
|
|
4
|
+
returns `NomosOfferOutcome` with workspace-stamped `created` (`NomosCreated` gains `workspace` + a
|
|
5
|
+
`NomosRef get ref` view). Activity raw rows carry `created` + `workspace`. Requires `nomos_types >= 0.1.3`.
|
|
6
|
+
|
|
7
|
+
## 0.44.0
|
|
8
|
+
|
|
9
|
+
- Activity-feed runtime reads on `NomosBridge`/`NomosSession`: `activityLog({base, limit})` — the committed
|
|
10
|
+
intent log as raw rows `{intentId, domain, directiveId, actorSubject, occurredAt, payload}` (decoded
|
|
11
|
+
payload; the verified author; the physical HLC) — and `watchActivity({base})`, a stream re-deriving the
|
|
12
|
+
feed on every sync tick. Generic (raw Maps); the generated `renderActivity` (from directives' declared
|
|
13
|
+
`.activity()` metadata) types them into `ActivityEvent`s. Requires `nomos_types >= 0.1.2`.
|
|
14
|
+
|
|
1
15
|
## 0.43.0
|
|
2
16
|
|
|
3
17
|
- `NomosBridge.foreignReader({cloud})` — a `NomosForeignReader` backed by the device's multi-workspace bridge
|
|
@@ -23,6 +23,7 @@ import 'package:nomos_types/nomos_types.dart'
|
|
|
23
23
|
nomosErrorFromInfo,
|
|
24
24
|
NomosTraceContext,
|
|
25
25
|
NomosErrorInfo,
|
|
26
|
+
NomosRef,
|
|
26
27
|
NomosForeignReader,
|
|
27
28
|
NomosForeignWorkspaceReader,
|
|
28
29
|
ForeignAttestation;
|
|
@@ -104,7 +105,15 @@ class SyncStatus {
|
|
|
104
105
|
class NomosCreated {
|
|
105
106
|
final String type;
|
|
106
107
|
final String id;
|
|
107
|
-
|
|
108
|
+
|
|
109
|
+
/// The workspace the offer ran on (NomosRef). Additive — defaults to '' on older runners that
|
|
110
|
+
/// don't stamp it; then [ref] is workspace-blank (still a valid locator on the local plane).
|
|
111
|
+
final String workspace;
|
|
112
|
+
const NomosCreated({required this.type, required this.id, this.workspace = ''});
|
|
113
|
+
|
|
114
|
+
/// The canonical [NomosRef] view — the `{workspace,type,id}` triple, followable/serializable
|
|
115
|
+
/// (`nomos://<workspace>/<type>/<id>`). One reference, everywhere.
|
|
116
|
+
NomosRef get ref => NomosRef(workspace: workspace, type: type, id: id);
|
|
108
117
|
@override
|
|
109
118
|
String toString() => id;
|
|
110
119
|
}
|
|
@@ -604,6 +613,10 @@ class NomosOfferOutcome {
|
|
|
604
613
|
final String head;
|
|
605
614
|
final List<NomosCreated> created;
|
|
606
615
|
|
|
616
|
+
/// The workspace the offer ran on (NomosRef). Additive; '' on older runners. Each [created] ref already
|
|
617
|
+
/// carries this, so `outcome.created.first.ref` is the full followable `{workspace,type,id}` locator.
|
|
618
|
+
final String workspace;
|
|
619
|
+
|
|
607
620
|
/// The born child workspace name(s), when the offer ran a `.births()` directive (else empty). Each is a
|
|
608
621
|
/// LOCAL workspace on this device's plane, resident in the shared engine plane the moment it is born:
|
|
609
622
|
/// `bridge.session(name)` returns its handle, and `bridge.connect(session: name)` (no `restoreFrom`) mounts
|
|
@@ -616,6 +629,7 @@ class NomosOfferOutcome {
|
|
|
616
629
|
const NomosOfferOutcome({
|
|
617
630
|
required this.head,
|
|
618
631
|
required this.created,
|
|
632
|
+
this.workspace = '',
|
|
619
633
|
this.born = const [],
|
|
620
634
|
this.birthOutcomes = const [],
|
|
621
635
|
});
|
|
@@ -965,6 +979,32 @@ class NomosBridge {
|
|
|
965
979
|
List<Map<String, Object?>>? attestations,
|
|
966
980
|
bool? force,
|
|
967
981
|
String? session,
|
|
982
|
+
}) =>
|
|
983
|
+
offerOutcome(
|
|
984
|
+
domain: domain,
|
|
985
|
+
directiveId: directiveId,
|
|
986
|
+
payload: payload,
|
|
987
|
+
actor: actor,
|
|
988
|
+
domainHash: domainHash,
|
|
989
|
+
attestations: attestations,
|
|
990
|
+
force: force,
|
|
991
|
+
session: session,
|
|
992
|
+
);
|
|
993
|
+
|
|
994
|
+
/// THE ONE OUTCOME-RETURNING OFFER LANE — [offerDirective] answering the full typed [NomosOfferOutcome]
|
|
995
|
+
/// (head + law-minted `created` NomosRefs + births), for EVERY generated method (create or mutate). A pure
|
|
996
|
+
/// mutation returns `created: []`; a `.creates(...)` plan returns the minted aggregate id(s), each already
|
|
997
|
+
/// carrying the session [workspace] so `outcome.created.first.ref` is a complete followable NomosRef with no
|
|
998
|
+
/// query-after round-trip. [offerCreates] is the historical alias (identical behavior).
|
|
999
|
+
Future<NomosOfferOutcome> offerOutcome({
|
|
1000
|
+
required String domain,
|
|
1001
|
+
required String directiveId,
|
|
1002
|
+
required Object? payload,
|
|
1003
|
+
String? actor,
|
|
1004
|
+
String? domainHash,
|
|
1005
|
+
List<Map<String, Object?>>? attestations,
|
|
1006
|
+
bool? force,
|
|
1007
|
+
String? session,
|
|
968
1008
|
}) async {
|
|
969
1009
|
final r = _asMap(await _call('offerDirective', {
|
|
970
1010
|
'domain': domain,
|
|
@@ -992,13 +1032,17 @@ class NomosBridge {
|
|
|
992
1032
|
.map((m) => (m['workspace'] ?? '').toString())
|
|
993
1033
|
.where((s) => s.isNotEmpty),
|
|
994
1034
|
]..removeWhere((s) => s.isEmpty);
|
|
1035
|
+
// The offer ran on this workspace (NomosRef) — stamp every minted ref with it so it is a complete locator.
|
|
1036
|
+
final ws = (r['workspace'] ?? '').toString();
|
|
995
1037
|
return NomosOfferOutcome(
|
|
996
1038
|
head: r['head'].toString(),
|
|
1039
|
+
workspace: ws,
|
|
997
1040
|
created: ((r['created'] as List?) ?? const [])
|
|
998
1041
|
.whereType<Map>()
|
|
999
1042
|
.map((m) => NomosCreated(
|
|
1000
1043
|
type: (m['type'] ?? '').toString(),
|
|
1001
|
-
id: (m['id'] ?? '').toString()
|
|
1044
|
+
id: (m['id'] ?? '').toString(),
|
|
1045
|
+
workspace: ws))
|
|
1002
1046
|
.toList(),
|
|
1003
1047
|
born: bornNames,
|
|
1004
1048
|
birthOutcomes: births,
|
|
@@ -1168,6 +1212,26 @@ class NomosBridge {
|
|
|
1168
1212
|
.toList();
|
|
1169
1213
|
}
|
|
1170
1214
|
|
|
1215
|
+
/// RUNTIME activity feed — per-committed-intent rows (newest-first) from the local ledger, each carrying
|
|
1216
|
+
/// `{intentId, domain, directiveId, actorSubject, occurredAt, payload}` (payload = the DECODED directive
|
|
1217
|
+
/// payload). `base` = a commit-oid cursor (only intents newer than it); omitted = from the tip bounded by
|
|
1218
|
+
/// `limit` (default 200). Generic raw rows — the typed shaping is the codegen `renderActivity`.
|
|
1219
|
+
Future<List<Map<String, dynamic>>> activityLog(
|
|
1220
|
+
{String? base, int? limit}) async {
|
|
1221
|
+
final r = _asMap(await _call('activityLog', {
|
|
1222
|
+
if (base != null) 'base': base,
|
|
1223
|
+
if (limit != null) 'limit': limit,
|
|
1224
|
+
}));
|
|
1225
|
+
return ((r['rows'] as List?) ?? const [])
|
|
1226
|
+
.map((e) => (e as Map).cast<String, dynamic>())
|
|
1227
|
+
.toList();
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
/// Watch the RUNTIME activity feed: a stream that re-emits the newest-first activity rows on every local
|
|
1231
|
+
/// change (doorbell/sync tick). `base` = a commit-oid cursor. Cancelling drops the watch on the runner.
|
|
1232
|
+
Stream<List<dynamic>> watchActivity({String? base, String? session}) =>
|
|
1233
|
+
_watchStream(kind: 'activity', base: base, session: session);
|
|
1234
|
+
|
|
1171
1235
|
/// Mint an ed25519 DEVICE KEY in-kernel → `{secret, public}` (base64). The SECRET stays on this device
|
|
1172
1236
|
/// (persist it in secure storage); pass it to [connect] as `authorSecret` (or per-offer `signWith`) so the
|
|
1173
1237
|
/// holon SIGNS each intent. The PUBLIC half is what gets enrolled so the gate re-verifies the signature on
|
|
@@ -1594,6 +1658,7 @@ class NomosBridge {
|
|
|
1594
1658
|
String? id,
|
|
1595
1659
|
String? spatialId,
|
|
1596
1660
|
NomosBbox? bbox,
|
|
1661
|
+
String? base,
|
|
1597
1662
|
String? session}) {
|
|
1598
1663
|
final subId = 'w${++_seq}';
|
|
1599
1664
|
late final StreamController<List<dynamic>> ctrl;
|
|
@@ -1606,6 +1671,7 @@ class NomosBridge {
|
|
|
1606
1671
|
if (id != null) 'id': id,
|
|
1607
1672
|
if (spatialId != null) 'spatialId': spatialId,
|
|
1608
1673
|
if (bbox != null) 'bbox': bbox.toJson(),
|
|
1674
|
+
if (base != null) 'base': base,
|
|
1609
1675
|
if (session != null) 'session': session,
|
|
1610
1676
|
}),
|
|
1611
1677
|
onCancel: () async {
|
|
@@ -1709,6 +1775,9 @@ class NomosSession extends NomosBridge {
|
|
|
1709
1775
|
[String? session]) =>
|
|
1710
1776
|
parent.watchSpatial(spatialId, bbox, session ?? workspace);
|
|
1711
1777
|
@override
|
|
1778
|
+
Stream<List<dynamic>> watchActivity({String? base, String? session}) =>
|
|
1779
|
+
parent.watchActivity(base: base, session: session ?? workspace);
|
|
1780
|
+
@override
|
|
1712
1781
|
Stream<Map<String, Object?>> watchCompatibility(
|
|
1713
1782
|
Map<String, Object?> requirement,
|
|
1714
1783
|
[String? session]) =>
|
package/dart/pubspec.lock
CHANGED
package/dart/pubspec.yaml
CHANGED
|
@@ -11,7 +11,7 @@ description: >-
|
|
|
11
11
|
Nomos 2 Dart frontend types — the hand-written kernel wire types plus the
|
|
12
12
|
code-generated per-domain aggregate + directive-payload types. (De)serializes
|
|
13
13
|
the EXACT serde JSON the Rust kernel + projection produce/consume.
|
|
14
|
-
version: 0.
|
|
14
|
+
version: 0.45.0
|
|
15
15
|
|
|
16
16
|
environment:
|
|
17
17
|
sdk: ^3.5.0
|
|
@@ -20,7 +20,7 @@ dependencies:
|
|
|
20
20
|
# The pure-data core (wire types, offer codec, NomosReads, schema validation, error
|
|
21
21
|
# info). nomos_client depends on and re-exports it, so existing imports are unchanged.
|
|
22
22
|
# For local monorepo dev, pubspec_overrides.yaml points this at ../dart_types.
|
|
23
|
-
nomos_types: ^0.1.
|
|
23
|
+
nomos_types: ^0.1.3
|
|
24
24
|
json_schema: ^5.2.2
|
|
25
25
|
crypto: ^3.0.0
|
|
26
26
|
|
package/dart_types/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 0.1.3
|
|
2
|
+
|
|
3
|
+
- `NomosRef` — THE one typed reference `{workspace, type, id}`: value semantics, the canonical
|
|
4
|
+
`nomos://<workspace>/<type>/<id>` uri (`uri`/`parse`, encode round-trip), `fromJson` (object or uri),
|
|
5
|
+
`resolve()` over the multi-workspace reader. `ActivityRef` gains `workspace` + a `.ref` view; `ForeignRef`
|
|
6
|
+
gains `.ref`. Every reference shape now converges on the one triple. Purely additive.
|
|
7
|
+
|
|
8
|
+
## 0.1.2
|
|
9
|
+
|
|
10
|
+
- Activity-feed runtime types: `ActivityEvent` (the shared activity row — kind/actor/occurredAt, rendered
|
|
11
|
+
title+message, stable `titleKey`/`messageKey` + params for localization, typed `refs`, category/icon/
|
|
12
|
+
severity, domain/directiveId provenance), `ActivityRef`, `ActivitySeverity`, `renderActivityTemplate`.
|
|
13
|
+
Consumed by the generated `renderActivity`/`describe`/`describeHistory`. Purely additive.
|
|
14
|
+
|
|
1
15
|
## 0.1.1
|
|
2
16
|
|
|
3
17
|
- Add `t.foreignRef` runtime types: `ForeignRef<T>` (a typed cross-workspace locator), `NomosForeignReader` /
|
|
@@ -31,3 +31,5 @@ export 'src/errors.dart';
|
|
|
31
31
|
// `NomosForeignReader`/`NomosForeignWorkspaceReader` read surfaces + the named resolve outcomes. Pure data +
|
|
32
32
|
// abstract interfaces (no bridge) — so both the layered TYPES package and nomos_client resolve them.
|
|
33
33
|
export 'src/foreign_ref.dart';
|
|
34
|
+
export 'src/activity.dart';
|
|
35
|
+
export 'src/nomos_ref.dart';
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// NOMOS — the ACTIVITY-FEED runtime types (directive `.activity(...)` descriptors). The shared, tenant-
|
|
2
|
+
// agnostic shape a client renders from the intent log: a directive DECLARES its activity metadata (kind,
|
|
3
|
+
// message template, refs, params) and the generated `renderActivity` turns each committed intent into an
|
|
4
|
+
// [ActivityEvent] — no string-enricher guessing meaning beside the truth. The kernel/ledger stays the audit
|
|
5
|
+
// truth; this is a pure client-side human projection.
|
|
6
|
+
//
|
|
7
|
+
// These live in the pure `nomos_types` core (no bridge/lifecycle) so BOTH the layered TYPES package (where
|
|
8
|
+
// the generated pure `renderActivity` lives) AND the runtime `nomos_client` package resolve them.
|
|
9
|
+
library;
|
|
10
|
+
|
|
11
|
+
import 'nomos_ref.dart';
|
|
12
|
+
|
|
13
|
+
/// A declared navigation target on an activity row: the referenced aggregate/contract TYPE + the resolved id
|
|
14
|
+
/// (read from a payload field the directive named). Replaces the old enricher's blind id-probing — the app
|
|
15
|
+
/// knows exactly what `id` points at and can deep-link/resolve it.
|
|
16
|
+
class ActivityRef {
|
|
17
|
+
final String type;
|
|
18
|
+
final String id;
|
|
19
|
+
|
|
20
|
+
/// The source workspace (additive — empty on rows rendered before refs carried it).
|
|
21
|
+
final String workspace;
|
|
22
|
+
|
|
23
|
+
const ActivityRef({required this.type, required this.id, this.workspace = ''});
|
|
24
|
+
|
|
25
|
+
/// The canonical reference view (`nomos://<workspace>/<type>/<id>`).
|
|
26
|
+
NomosRef get ref => NomosRef(workspace: workspace, type: type, id: id);
|
|
27
|
+
|
|
28
|
+
factory ActivityRef.fromJson(Map<String, dynamic> j) => ActivityRef(
|
|
29
|
+
type: (j['type'] ?? '') as String,
|
|
30
|
+
id: (j['id'] ?? '') as String,
|
|
31
|
+
workspace: (j['workspace'] ?? '') as String);
|
|
32
|
+
Map<String, dynamic> toJson() =>
|
|
33
|
+
{'type': type, 'id': id, if (workspace.isNotEmpty) 'workspace': workspace};
|
|
34
|
+
|
|
35
|
+
@override
|
|
36
|
+
bool operator ==(Object other) =>
|
|
37
|
+
other is ActivityRef && other.type == type && other.id == id && other.workspace == workspace;
|
|
38
|
+
@override
|
|
39
|
+
int get hashCode => Object.hash(type, id, workspace);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Row prominence — a declared default the app may style or threshold on.
|
|
43
|
+
enum ActivitySeverity {
|
|
44
|
+
info,
|
|
45
|
+
success,
|
|
46
|
+
warning,
|
|
47
|
+
critical;
|
|
48
|
+
|
|
49
|
+
static ActivitySeverity fromWire(String? s) {
|
|
50
|
+
switch (s) {
|
|
51
|
+
case 'success':
|
|
52
|
+
return ActivitySeverity.success;
|
|
53
|
+
case 'warning':
|
|
54
|
+
return ActivitySeverity.warning;
|
|
55
|
+
case 'critical':
|
|
56
|
+
return ActivitySeverity.critical;
|
|
57
|
+
default:
|
|
58
|
+
return ActivitySeverity.info;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
String get wire => name;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// A rendered activity row — the tenant-agnostic "tiny shared activity contract". Produced by the generated
|
|
66
|
+
/// `renderActivity(intentMeta, payload)` from a directive's declared `.activity(...)` descriptor. The UI
|
|
67
|
+
/// consumes this directly (title/message already interpolated; `refs` for navigation; `titleKey`/`messageKey`
|
|
68
|
+
/// + `params` for later localization).
|
|
69
|
+
class ActivityEvent {
|
|
70
|
+
/// The intent id — a stable per-event identity (dedupe/order key).
|
|
71
|
+
final String eventId;
|
|
72
|
+
|
|
73
|
+
/// The declared STABLE event kind (e.g. `"site.created"`).
|
|
74
|
+
final String kind;
|
|
75
|
+
|
|
76
|
+
/// The intent's author (principal) — the "who".
|
|
77
|
+
final String actorSubject;
|
|
78
|
+
|
|
79
|
+
/// When it happened (the intent's physical HLC timestamp, ISO-8601 when available).
|
|
80
|
+
final String occurredAt;
|
|
81
|
+
|
|
82
|
+
/// The rendered title (template interpolated); [titleKey] + [params] localize it later.
|
|
83
|
+
final String title;
|
|
84
|
+
|
|
85
|
+
/// The rendered message (template interpolated); [messageKey] + [params] localize it later.
|
|
86
|
+
final String message;
|
|
87
|
+
|
|
88
|
+
/// Stable i18n key for the title (`activity.<kind>.title`).
|
|
89
|
+
final String titleKey;
|
|
90
|
+
|
|
91
|
+
/// Stable i18n key for the message (`activity.<kind>.message`).
|
|
92
|
+
final String messageKey;
|
|
93
|
+
|
|
94
|
+
/// The interpolation params (name → display value, read from the payload) — for localized re-rendering.
|
|
95
|
+
final Map<String, String> params;
|
|
96
|
+
|
|
97
|
+
/// Declared navigation targets (name → typed ref).
|
|
98
|
+
final Map<String, ActivityRef> refs;
|
|
99
|
+
|
|
100
|
+
/// Optional grouping category (e.g. `"estate"`).
|
|
101
|
+
final String? category;
|
|
102
|
+
|
|
103
|
+
/// Optional default icon token (app-interpreted).
|
|
104
|
+
final String? icon;
|
|
105
|
+
|
|
106
|
+
/// Row prominence (default [ActivitySeverity.info]).
|
|
107
|
+
final ActivitySeverity severity;
|
|
108
|
+
|
|
109
|
+
/// Provenance — the domain + directive that produced this event.
|
|
110
|
+
final String domain;
|
|
111
|
+
final String directiveId;
|
|
112
|
+
|
|
113
|
+
const ActivityEvent({
|
|
114
|
+
required this.eventId,
|
|
115
|
+
required this.kind,
|
|
116
|
+
required this.actorSubject,
|
|
117
|
+
required this.occurredAt,
|
|
118
|
+
required this.title,
|
|
119
|
+
required this.message,
|
|
120
|
+
required this.titleKey,
|
|
121
|
+
required this.messageKey,
|
|
122
|
+
required this.params,
|
|
123
|
+
required this.refs,
|
|
124
|
+
required this.severity,
|
|
125
|
+
required this.domain,
|
|
126
|
+
required this.directiveId,
|
|
127
|
+
this.category,
|
|
128
|
+
this.icon,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
factory ActivityEvent.fromJson(Map<String, dynamic> j) => ActivityEvent(
|
|
132
|
+
eventId: (j['eventId'] ?? '') as String,
|
|
133
|
+
kind: (j['kind'] ?? '') as String,
|
|
134
|
+
actorSubject: (j['actorSubject'] ?? '') as String,
|
|
135
|
+
occurredAt: (j['occurredAt'] ?? '') as String,
|
|
136
|
+
title: (j['title'] ?? '') as String,
|
|
137
|
+
message: (j['message'] ?? '') as String,
|
|
138
|
+
titleKey: (j['titleKey'] ?? '') as String,
|
|
139
|
+
messageKey: (j['messageKey'] ?? '') as String,
|
|
140
|
+
params: ((j['params'] as Map?)?.cast<String, dynamic>() ?? const {})
|
|
141
|
+
.map((k, v) => MapEntry(k, '$v')),
|
|
142
|
+
refs: ((j['refs'] as Map?)?.cast<String, dynamic>() ?? const {})
|
|
143
|
+
.map((k, v) => MapEntry(k, ActivityRef.fromJson((v as Map).cast<String, dynamic>()))),
|
|
144
|
+
category: j['category'] as String?,
|
|
145
|
+
icon: j['icon'] as String?,
|
|
146
|
+
severity: ActivitySeverity.fromWire(j['severity'] as String?),
|
|
147
|
+
domain: (j['domain'] ?? '') as String,
|
|
148
|
+
directiveId: (j['directiveId'] ?? '') as String,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
Map<String, dynamic> toJson() => {
|
|
152
|
+
'eventId': eventId,
|
|
153
|
+
'kind': kind,
|
|
154
|
+
'actorSubject': actorSubject,
|
|
155
|
+
'occurredAt': occurredAt,
|
|
156
|
+
'title': title,
|
|
157
|
+
'message': message,
|
|
158
|
+
'titleKey': titleKey,
|
|
159
|
+
'messageKey': messageKey,
|
|
160
|
+
'params': params,
|
|
161
|
+
'refs': refs.map((k, v) => MapEntry(k, v.toJson())),
|
|
162
|
+
if (category != null) 'category': category,
|
|
163
|
+
if (icon != null) 'icon': icon,
|
|
164
|
+
'severity': severity.wire,
|
|
165
|
+
'domain': domain,
|
|
166
|
+
'directiveId': directiveId,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/// Interpolate `{name}` placeholders in [template] from [vars] — the render helper the generated
|
|
171
|
+
/// `renderActivity` uses. A missing var renders empty (the compiler already validated every placeholder).
|
|
172
|
+
String renderActivityTemplate(String template, Map<String, String> vars) =>
|
|
173
|
+
template.replaceAllMapped(RegExp(r'\{([a-zA-Z0-9_]+)\}'), (m) => vars[m.group(1)] ?? '');
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
// this barrel, and its `NomosBridge` implements [NomosForeignReader] over the device's multi-workspace plane.
|
|
15
15
|
library;
|
|
16
16
|
|
|
17
|
+
import 'nomos_ref.dart';
|
|
18
|
+
|
|
17
19
|
/// Reads a FOREIGN workspace on demand — the surface a [ForeignRef] resolves against. It is STRUCTURAL: any
|
|
18
20
|
/// object with this shape works. `nomos_client`'s `NomosBridge` implements it over the device's local
|
|
19
21
|
/// multi-workspace plane (`bridge.session(ws).queryById(id)`, mounting the workspace lazily); the TS twin is
|
|
@@ -111,6 +113,10 @@ class ForeignRef<T> {
|
|
|
111
113
|
/// The foreign aggregate type this locator points at.
|
|
112
114
|
final String type;
|
|
113
115
|
|
|
116
|
+
/// The canonical reference view (`nomos://<workspace>/<type>/<id>`) — a [ForeignRef] IS a typed view over
|
|
117
|
+
/// the one reference triple.
|
|
118
|
+
NomosRef get ref => NomosRef(workspace: workspace, type: type, id: id);
|
|
119
|
+
|
|
114
120
|
/// The target's decoder (the aggregate `fromJson` factory), applied to a resolved row's flat `data` map.
|
|
115
121
|
final T Function(Map<String, dynamic> data, [String id]) _decode;
|
|
116
122
|
|
|
@@ -0,0 +1,75 @@
|
|
|
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.
|
|
6
|
+
//
|
|
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.
|
|
10
|
+
library;
|
|
11
|
+
|
|
12
|
+
import 'foreign_ref.dart';
|
|
13
|
+
|
|
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;
|
|
19
|
+
|
|
20
|
+
/// The aggregate TYPE (the read-projection type tag, e.g. `estate.EstateSite` or `EstateSite`).
|
|
21
|
+
final String type;
|
|
22
|
+
|
|
23
|
+
/// The instance id (law-minted or law-defined).
|
|
24
|
+
final String id;
|
|
25
|
+
|
|
26
|
+
const NomosRef({required this.workspace, required this.type, required this.id});
|
|
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)}';
|
|
32
|
+
|
|
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
|
+
}
|
|
48
|
+
|
|
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,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Map<String, dynamic> toJson() => {'workspace': workspace, 'type': type, 'id': id};
|
|
61
|
+
|
|
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);
|
|
67
|
+
|
|
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;
|
|
75
|
+
}
|
package/dart_types/pubspec.yaml
CHANGED
|
@@ -11,7 +11,7 @@ description: >-
|
|
|
11
11
|
Pure kernel wire/data types for Nomos Dart frontends — no transport, no bridge,
|
|
12
12
|
no runtime. The hand-written serde-JSON-compatible types plus the offer codec,
|
|
13
13
|
reactive read engine, schema validation, and data-only error/trace types.
|
|
14
|
-
version: 0.1.
|
|
14
|
+
version: 0.1.3
|
|
15
15
|
|
|
16
16
|
environment:
|
|
17
17
|
sdk: ^3.5.0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.68.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",
|