@githolon/dsl 0.70.1 → 0.71.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/src/webview_bridge.dart +13 -3
- package/dart/pubspec.yaml +1 -1
- package/dart_types/CHANGELOG.md +8 -0
- package/dart_types/lib/nomos_types.dart +3 -0
- package/dart_types/lib/src/principal.dart +56 -0
- package/dart_types/pubspec.yaml +1 -1
- package/package.json +1 -1
- package/src/codegen_dart_client.ts +43 -1
- package/src/codegen_ts.ts +54 -1
- package/src/compile_package_main.ts +12 -5
package/dart/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
## 0.47.0
|
|
2
|
+
|
|
3
|
+
- **Fix: `NomosBridge.createWorkspace` hardcoded `domain: "workspaces"`** in the underlying signed offer —
|
|
4
|
+
a tenant birthing through their OWN platform's custom law (e.g. a `birthEstateWorkspace` directive under a
|
|
5
|
+
`co2_platform` domain) was refused, because the sealed intent always claimed `domain: "workspaces"`
|
|
6
|
+
regardless of which law actually declares the requested `directiveId`. Added a `domain` parameter
|
|
7
|
+
(default `"workspaces"`, fully back-compatible) — call
|
|
8
|
+
`bridge.createWorkspace(domain: 'co2_platform', directiveId: 'birthEstateWorkspace', domainHash: ..., ...)`
|
|
9
|
+
to birth through a custom platform law. **This release was overdue**: the fix landed in `nomos_flutter`
|
|
10
|
+
0.52.2's bundled JS runtime, but this Dart-level API surface lives in `nomos_client` and was never
|
|
11
|
+
republished alongside it — a real release-process gap, not a client-side workaround. Requires
|
|
12
|
+
`nomos_flutter >= 0.52.2` to match the bundled runtime behavior.
|
|
13
|
+
|
|
1
14
|
## 0.46.0
|
|
2
15
|
|
|
3
16
|
- Custody lifecycle on `NomosBridge`/`NomosSession`: `connect(..., onCustodyBreak: CustodyBreakPolicy)`,
|
|
@@ -1169,10 +1169,18 @@ class NomosBridge {
|
|
|
1169
1169
|
}));
|
|
1170
1170
|
|
|
1171
1171
|
/// MAKE A WORKSPACE — the one-call tenant path. A child workspace under a platform/[parent] is a SIGNED
|
|
1172
|
-
/// control-plane offer; the holon seals `createWorkspace` (or [directiveId] `birthChild
|
|
1173
|
-
///
|
|
1174
|
-
///
|
|
1172
|
+
/// control-plane offer; the holon seals `createWorkspace` (or [directiveId] `birthChild`, or ANY
|
|
1173
|
+
/// tenant-defined `.births()` directive — see [domain]) with the requester's device key ([authorSecret],
|
|
1174
|
+
/// as [actor], e.g. `user:<uid>`) and relays it to the parent's gateway. Returns the worker verdict
|
|
1175
|
+
/// (`{ok, status, body}`). The tenant move is one line:
|
|
1175
1176
|
/// `await bridge.createWorkspace(name: 'foo', parent: 'my-platform', actor: 'user:$uid', authorSecret: key)`.
|
|
1177
|
+
///
|
|
1178
|
+
/// [domain] defaults to `'workspaces'` (the generic root-style governance law every platform's
|
|
1179
|
+
/// createWorkspace/birthChild rides). To birth through the PARENT'S OWN custom platform law instead (e.g.
|
|
1180
|
+
/// a tenant `birthEstateWorkspace` under a `co2_platform` domain), pass that domain's key + [domainHash]:
|
|
1181
|
+
/// `bridge.createWorkspace(domain: 'co2_platform', directiveId: 'birthEstateWorkspace', domainHash: ...)`.
|
|
1182
|
+
/// The kernel looks up `(domain, directiveId)` in the ACTIVE installed law — [domain] must name the law
|
|
1183
|
+
/// that actually declares [directiveId], never assume `'workspaces'`.
|
|
1176
1184
|
Future<Map<String, Object?>> createWorkspace({
|
|
1177
1185
|
required String parent,
|
|
1178
1186
|
required String actor,
|
|
@@ -1180,6 +1188,7 @@ class NomosBridge {
|
|
|
1180
1188
|
String? name,
|
|
1181
1189
|
Object? payload,
|
|
1182
1190
|
String directiveId = 'createWorkspace',
|
|
1191
|
+
String domain = 'workspaces',
|
|
1183
1192
|
String? domainHash,
|
|
1184
1193
|
String? authToken,
|
|
1185
1194
|
}) async {
|
|
@@ -1192,6 +1201,7 @@ class NomosBridge {
|
|
|
1192
1201
|
if (name != null) 'name': name,
|
|
1193
1202
|
if (payload != null) 'payload': payload,
|
|
1194
1203
|
'directiveId': directiveId,
|
|
1204
|
+
'domain': domain,
|
|
1195
1205
|
if (domainHash != null) 'domainHash': domainHash,
|
|
1196
1206
|
if (authToken != null) 'authToken': authToken,
|
|
1197
1207
|
}));
|
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.47.0
|
|
15
15
|
|
|
16
16
|
environment:
|
|
17
17
|
sdk: ^3.5.0
|
package/dart_types/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.2.0
|
|
2
|
+
|
|
3
|
+
- `NomosPrincipal` / `NomosDeviceSecret` — branded identity types for the generated cross-workspace birth
|
|
4
|
+
methods (`.births()` directives). `actor`/`authorSecret` were previously bare, adjacent, same-shaped
|
|
5
|
+
strings — a transposition footgun with no compiler check. `NomosPrincipal.user(uid)`/`.parse('user:<uid>')`
|
|
6
|
+
and the opaque `NomosDeviceSecret` (redacts in `toString()`) make swapping them a type error. Purely
|
|
7
|
+
additive.
|
|
8
|
+
|
|
1
9
|
## 0.1.4
|
|
2
10
|
|
|
3
11
|
- Custody-lifecycle types: `NomosCustodyBreak`, `NomosCustodyStatus`, `NomosCustodyEvent`,
|
|
@@ -33,6 +33,9 @@ export 'src/errors.dart';
|
|
|
33
33
|
export 'src/foreign_ref.dart';
|
|
34
34
|
export 'src/activity.dart';
|
|
35
35
|
export 'src/nomos_ref.dart';
|
|
36
|
+
// Branded identity wrappers (NomosPrincipal / NomosDeviceSecret) for the generated cross-workspace
|
|
37
|
+
// birth methods — actor/authorSecret are distinct types, so a transposition is a compile error.
|
|
38
|
+
export 'src/principal.dart';
|
|
36
39
|
// The CUSTODY-LIFECYCLE types (rebirth_and_custody_lifecycle.md): NomosCustodyBreak / NomosCustodyStatus /
|
|
37
40
|
// CustodyBreakPolicy — custody incompatibility as a first-class, typed, app-decidable event. Pure data.
|
|
38
41
|
export 'src/custody.dart';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
|
|
2
|
+
// remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
|
|
3
|
+
// wasm32-wasip1 artifact {kernel · projection · embedded QuickJS engine}.
|
|
4
|
+
// If a file isn't this / hosting this / authoring for this / proving this — it's gone.
|
|
5
|
+
|
|
6
|
+
/// BRANDED IDENTITY TYPES for the generated cross-workspace birth methods.
|
|
7
|
+
///
|
|
8
|
+
/// A `.births()` directive's generated wrapper takes an `actor` (WHO births) and an optional
|
|
9
|
+
/// `authorSecret` (the signing key). Both were previously bare strings — two adjacent same-shaped
|
|
10
|
+
/// params that a caller can transpose with NO compiler error and a silent runtime failure (the same
|
|
11
|
+
/// bug class as a raw `domain`/`directiveId` swap). These wrappers make the transposition a type
|
|
12
|
+
/// error: `NomosPrincipal` and `NomosDeviceSecret` are distinct types, so passing one where the other
|
|
13
|
+
/// belongs won't compile. The generated method unwraps `.wire` to call the (unchanged) runtime
|
|
14
|
+
/// primitive `NomosBridge.createWorkspace(actor: String, authorSecret: String?, …)`.
|
|
15
|
+
|
|
16
|
+
/// A verified principal identity (`user:<uid>` on the wire). Construct with [NomosPrincipal.user]
|
|
17
|
+
/// from a bare uid, or [NomosPrincipal.parse] from a `user:<uid>` wire string.
|
|
18
|
+
class NomosPrincipal {
|
|
19
|
+
/// The bare uid (no `user:` prefix).
|
|
20
|
+
final String uid;
|
|
21
|
+
const NomosPrincipal._(this.uid);
|
|
22
|
+
|
|
23
|
+
/// From a bare uid (e.g. an auth-provider user id) — the common case.
|
|
24
|
+
factory NomosPrincipal.user(String uid) => NomosPrincipal._(uid);
|
|
25
|
+
|
|
26
|
+
/// From a `user:<uid>` wire string — throws [ArgumentError] on any other shape.
|
|
27
|
+
factory NomosPrincipal.parse(String wire) {
|
|
28
|
+
if (!wire.startsWith('user:')) {
|
|
29
|
+
throw ArgumentError('NomosPrincipal.parse: expected "user:<uid>", got "$wire"');
|
|
30
|
+
}
|
|
31
|
+
return NomosPrincipal._(wire.substring(5));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// The wire form the kernel seals as the captured principal: `user:<uid>`.
|
|
35
|
+
String get wire => 'user:$uid';
|
|
36
|
+
|
|
37
|
+
@override
|
|
38
|
+
bool operator ==(Object other) => other is NomosPrincipal && other.uid == uid;
|
|
39
|
+
@override
|
|
40
|
+
int get hashCode => uid.hashCode;
|
|
41
|
+
@override
|
|
42
|
+
String toString() => wire;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// A device signing secret (base64). A distinct type from [NomosPrincipal] so it can't be swapped
|
|
46
|
+
/// with `actor`; its [toString] NEVER leaks the secret (redacted), so it is safe in logs/errors.
|
|
47
|
+
class NomosDeviceSecret {
|
|
48
|
+
final String _base64;
|
|
49
|
+
const NomosDeviceSecret(this._base64);
|
|
50
|
+
|
|
51
|
+
/// The base64 wire form handed to the (unchanged) runtime primitive.
|
|
52
|
+
String get wire => _base64;
|
|
53
|
+
|
|
54
|
+
@override
|
|
55
|
+
String toString() => 'NomosDeviceSecret(***)';
|
|
56
|
+
}
|
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.
|
|
14
|
+
version: 0.2.0
|
|
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.71.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",
|
|
@@ -184,9 +184,14 @@ export function generateDartBridgeClient(mod: DomainModule, opts: DartBridgeClie
|
|
|
184
184
|
const methods: string[] = [];
|
|
185
185
|
|
|
186
186
|
// ── directives → typed offer ──
|
|
187
|
-
|
|
187
|
+
// A `.births()` directive (birthsChild === true) is NOT a same-workspace write — it is a signed
|
|
188
|
+
// cross-workspace governance offer to a PARENT. It gets a typed `bridge.createWorkspace(...)` wrapper
|
|
189
|
+
// (below), NOT an `offerOutcome`; excluded here so a frontend dev can never call it as a local write.
|
|
190
|
+
const allDirs = (mod.directives as AnyDirective[]).filter(
|
|
188
191
|
(d) => d && typeof d.id === "string" && typeof (d as { payloadSchema?: unknown }).payloadSchema === "object",
|
|
189
192
|
);
|
|
193
|
+
const birthDirs = allDirs.filter((d) => (d as { birthsChild?: boolean }).birthsChild === true);
|
|
194
|
+
const dirs = allDirs.filter((d) => (d as { birthsChild?: boolean }).birthsChild !== true);
|
|
190
195
|
for (const d of dirs) {
|
|
191
196
|
const payloadClass = `${cap(d.id)}Payload`;
|
|
192
197
|
const stamps = autoStampFields((d as unknown as { payloadSchema: z.ZodTypeAny }).payloadSchema);
|
|
@@ -268,6 +273,43 @@ export function generateDartBridgeClient(mod: DomainModule, opts: DartBridgeClie
|
|
|
268
273
|
}
|
|
269
274
|
}
|
|
270
275
|
|
|
276
|
+
// ── `.births()` directives → typed CROSS-WORKSPACE birth (bridge.createWorkspace) ──
|
|
277
|
+
// Each births a CHILD WORKSPACE under `parent` via a signed governance offer routed by the PARENT'S
|
|
278
|
+
// law (POST /v2/workspaces/<parent>/<directiveId>) — never a same-workspace write. The declaring
|
|
279
|
+
// domain's key + directiveId + baked domainHash are all bound at codegen time, so a frontend dev
|
|
280
|
+
// never hand-writes the four raw strings this replaces (the co2 production bug).
|
|
281
|
+
for (const d of birthDirs) {
|
|
282
|
+
const payloadClass = `${cap(d.id)}Payload`;
|
|
283
|
+
const method = safeMethod(d.id);
|
|
284
|
+
methods.push(
|
|
285
|
+
` /// Births a CHILD WORKSPACE named by \`${payloadClass}\` under [parent], via a SIGNED cross-workspace`,
|
|
286
|
+
` /// governance offer to the parent's \`${domain}/${d.id}\` law (POST /v2/workspaces/<parent>/${d.id}) —`,
|
|
287
|
+
` /// NOT a same-workspace write, which is why it takes [parent]/[actor] (the requesting principal, e.g.`,
|
|
288
|
+
` /// \`user:<uid>\`) unlike the other generated methods. The declaring domain, directiveId, and law hash`,
|
|
289
|
+
` /// are baked in. Returns the parent gateway's verdict; [authorSecret] defaults to the bridge's device key.`,
|
|
290
|
+
` /// [actor] is a [NomosPrincipal] and [authorSecret] a [NomosDeviceSecret] — distinct types so the two`,
|
|
291
|
+
` /// can never be transposed (a bare-string swap would silently misfire).`,
|
|
292
|
+
` Future<Map<String, Object?>> ${method}({`,
|
|
293
|
+
` required String parent,`,
|
|
294
|
+
` required NomosPrincipal actor,`,
|
|
295
|
+
` NomosDeviceSecret? authorSecret,`,
|
|
296
|
+
` required ${payloadClass} payload,`,
|
|
297
|
+
` String? authToken,`,
|
|
298
|
+
` }) =>`,
|
|
299
|
+
` bridge.createWorkspace(`,
|
|
300
|
+
` domain: ${dartStr(domain)},`,
|
|
301
|
+
` directiveId: ${dartStr(d.id)},`,
|
|
302
|
+
` domainHash: domainHash,`,
|
|
303
|
+
` parent: parent,`,
|
|
304
|
+
` actor: actor.wire,`,
|
|
305
|
+
` authorSecret: authorSecret?.wire,`,
|
|
306
|
+
` payload: payload.toPayloadJson(),`,
|
|
307
|
+
` authToken: authToken,`,
|
|
308
|
+
` );`,
|
|
309
|
+
``,
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
271
313
|
// ── declared queries → one-shot + reactive ──
|
|
272
314
|
for (const q of (mod.queries ?? []) as QueryDecl[]) {
|
|
273
315
|
const model = readModelClassName(q.returns);
|
package/src/codegen_ts.ts
CHANGED
|
@@ -787,6 +787,11 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
|
|
|
787
787
|
);
|
|
788
788
|
const encPresent = encMap !== null;
|
|
789
789
|
const encConst = encryptionConstName(opts.packageName);
|
|
790
|
+
// A package declaring ≥1 `.births()` directive emits the branded identity wrappers (below) its typed
|
|
791
|
+
// birth methods take for `actor`/`authorSecret`. Births-free packages emit nothing (byte-identical).
|
|
792
|
+
const hasBirths = modules.some((m) =>
|
|
793
|
+
(m.directives as Directive<unknown>[]).some((d) => (d as { birthsChild?: boolean })?.birthsChild === true),
|
|
794
|
+
);
|
|
790
795
|
// ACTIVITY FEED (architecture/activity_descriptors.md): the package's declared `.activity(...)` descriptors.
|
|
791
796
|
// Empty ⇒ NOTHING activity-related emits (byte-identical to a pre-activity compile).
|
|
792
797
|
const activityEntries = collectActivityDescriptors(modules);
|
|
@@ -950,9 +955,17 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
|
|
|
950
955
|
` /** THE ONE ENCODER offer (the single v2-envelope codec lives in @githolon/client \`encodeIntentOfferBytes\`):`,
|
|
951
956
|
` * hand the holon a PLANNED directive + the verified \`actor\`; the holon encodes + offers. The generated`,
|
|
952
957
|
` * client calls THIS, never building offer bytes itself — so there is exactly ONE copy of the wire format. */`,
|
|
953
|
-
` offerDirective(domain: string, directiveId: string, payload: unknown, opts?: { domainHash?: string; actor?: string; returnCreated?: boolean }): Promise<string>;`,
|
|
958
|
+
` offerDirective(domain: string, directiveId: string, payload: unknown, opts?: { domainHash?: string; actor?: string; returnCreated?: boolean }): Promise<string | { head: string; created?: { type: string; id: string }[]; workspace?: string }>;`,
|
|
954
959
|
` /** Opaque-bytes offer — retained for carriers that already hold an encoded envelope (back-compat). */`,
|
|
955
960
|
` offer(intentBytes: string | Uint8Array): Promise<string>;`,
|
|
961
|
+
...(hasBirths
|
|
962
|
+
? [
|
|
963
|
+
` /** BIRTH A CHILD WORKSPACE (a signed CROSS-WORKSPACE governance offer to \`parent\`) — OPTIONAL:`,
|
|
964
|
+
` * @githolon/client's connect() attaches it. The generated \`.births()\` methods call this, binding`,
|
|
965
|
+
` * the declaring domain/directiveId/law hash so a frontend dev never hand-writes those raw strings. */`,
|
|
966
|
+
` createWorkspace?(opts: { domain: string; directiveId: string; domainHash?: string; parent: string; actor: string; authorSecret?: string; payload?: unknown; name?: string; authToken?: string }): Promise<{ ok?: boolean; status?: number; body?: unknown }>;`,
|
|
967
|
+
]
|
|
968
|
+
: []),
|
|
956
969
|
` /** The workspace this holon is bound to — the \`workspace\` of every [NomosRef] this client composes. */`,
|
|
957
970
|
` workspace: string;`,
|
|
958
971
|
...(encPresent
|
|
@@ -1046,6 +1059,25 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
|
|
|
1046
1059
|
``,
|
|
1047
1060
|
);
|
|
1048
1061
|
|
|
1062
|
+
// BRANDED IDENTITY WRAPPERS for the typed cross-workspace birth methods: `actor` (NomosPrincipal) and
|
|
1063
|
+
// `authorSecret` (NomosDeviceSecret) are distinct branded strings, so a caller can't transpose the two
|
|
1064
|
+
// (a bare-string swap would compile and silently misfire). Emitted iff the package declares `.births()`.
|
|
1065
|
+
if (hasBirths) {
|
|
1066
|
+
out.push(
|
|
1067
|
+
`/** A verified principal identity (\`user:<uid>\` on the wire) — construct with [nomosPrincipal]. A distinct`,
|
|
1068
|
+
` * branded type from [NomosDeviceSecret] so the two birth-method params can never be transposed. */`,
|
|
1069
|
+
`export type NomosPrincipal = string & { readonly __nomosPrincipal: unique symbol };`,
|
|
1070
|
+
`/** A device signing secret (base64) — construct with [nomosDeviceSecret]. Distinct from [NomosPrincipal]. */`,
|
|
1071
|
+
`export type NomosDeviceSecret = string & { readonly __nomosDeviceSecret: unique symbol };`,
|
|
1072
|
+
`/** Brand a principal: a bare uid (\`ada\`) or a wire string (\`user:ada\`) → \`user:ada\`. */`,
|
|
1073
|
+
`export const nomosPrincipal = (uidOrWire: string): NomosPrincipal =>`,
|
|
1074
|
+
` (uidOrWire.startsWith("user:") ? uidOrWire : \`user:\${uidOrWire}\`) as NomosPrincipal;`,
|
|
1075
|
+
`/** Brand a device signing secret (base64). */`,
|
|
1076
|
+
`export const nomosDeviceSecret = (base64: string): NomosDeviceSecret => base64 as NomosDeviceSecret;`,
|
|
1077
|
+
``,
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1049
1081
|
if (encPresent) {
|
|
1050
1082
|
out.push(
|
|
1051
1083
|
`// ── E2E SEALING (the sealing client) — baked map + KeyStore + seal/read helpers ──`,
|
|
@@ -1723,6 +1755,27 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
|
|
|
1723
1755
|
`export type ${payloadName} = ${tsTypeOfPayload(schema, stamps, mint ? [mint.field] : [], placed, lazyReg, d.id)};`,
|
|
1724
1756
|
``,
|
|
1725
1757
|
);
|
|
1758
|
+
// A `.births()` directive is NOT a same-workspace write — it is a signed CROSS-WORKSPACE governance
|
|
1759
|
+
// offer to a PARENT. It gets a typed `holon.createWorkspace(...)` wrapper (declaring domain +
|
|
1760
|
+
// directiveId + baked domainHash bound at codegen time), NOT an `offerDirective`, so a frontend dev
|
|
1761
|
+
// never hand-writes the four raw strings this replaces (the co2 production bug).
|
|
1762
|
+
if ((d as { birthsChild?: boolean }).birthsChild === true) {
|
|
1763
|
+
const birthPayload = stamps.length ? `stampNow(payload, ${JSON.stringify(stamps)})` : "payload";
|
|
1764
|
+
const gateBirthDoc = gate ? ` GATED: needs \`actor\` (\`${gate.relation}\`).` : "";
|
|
1765
|
+
methods.push(
|
|
1766
|
+
` /** Births a CHILD WORKSPACE (named by \`${payloadName}\`) under \`parent\`, via a SIGNED cross-workspace`,
|
|
1767
|
+
` * governance offer to the parent's \`${domain}/${d.id}\` law (POST /v2/workspaces/<parent>/${d.id}) — NOT a`,
|
|
1768
|
+
` * same-workspace write, hence \`parent\`/\`actor\` (the requesting principal, e.g. \`user:<uid>\`) unlike the`,
|
|
1769
|
+
` * other methods. Declaring domain, directiveId, and law hash are baked in; returns the parent gateway's`,
|
|
1770
|
+
` * verdict. \`authorSecret\` defaults to the holon's device key.${gateBirthDoc} */`,
|
|
1771
|
+
` ${d.id}: (opts: { parent: string; actor: NomosPrincipal; authorSecret?: NomosDeviceSecret; payload: ${payloadName}; authToken?: string }): Promise<{ ok?: boolean; status?: number; body?: unknown }> => {`,
|
|
1772
|
+
...(gateGuard ? [` if (!opts.actor || !opts.actor.trim()) throw new MissingOfferAuthority(${JSON.stringify(domain)}, ${JSON.stringify(d.id)}, ${JSON.stringify(gate!.relation)});`] : []),
|
|
1773
|
+
` const _payload = opts.payload;`,
|
|
1774
|
+
` return (holon.createWorkspace ?? (() => { throw new Error("this holon predates cross-workspace births — upgrade @githolon/client"); }))({ domain: ${JSON.stringify(domain)}, directiveId: ${JSON.stringify(d.id)}, domainHash, parent: opts.parent, actor: opts.actor, authorSecret: opts.authorSecret, payload: ${birthPayload.replace("payload", "_payload")}, authToken: opts.authToken });`,
|
|
1775
|
+
` },`,
|
|
1776
|
+
);
|
|
1777
|
+
continue;
|
|
1778
|
+
}
|
|
1726
1779
|
// THE ONE WRITE OUTCOME (architecture/nomos_ref.md): EVERY directive method returns Promise<NomosOutcome>
|
|
1727
1780
|
// — `created` (typed refs of all minted aggregates, from returnCreated) + `head`, plus `target` for the
|
|
1728
1781
|
// front-door-mint lane (the one statically-known addressed instance). One async block covers every case.
|
|
@@ -433,6 +433,9 @@ const DART_SUPPORT_CORE_SRC = [
|
|
|
433
433
|
"foreign_ref.dart",
|
|
434
434
|
"activity.dart",
|
|
435
435
|
"nomos_ref.dart",
|
|
436
|
+
// Branded identity wrappers (NomosPrincipal/NomosDeviceSecret) — the generated cross-workspace birth
|
|
437
|
+
// methods type `actor`/`authorSecret` as these (not bare strings), so both must vendor. Pure data.
|
|
438
|
+
"principal.dart",
|
|
436
439
|
// The custody-lifecycle types (NomosCustodyBreak/NomosCustodyStatus/CustodyBreakPolicy) — the generated
|
|
437
440
|
// client + the vendored bridge reference them through the barrel, so they must vendor. Pure data.
|
|
438
441
|
"custody.dart",
|
|
@@ -865,11 +868,15 @@ function emitDart(
|
|
|
865
868
|
|
|
866
869
|
/** The pure-core support import generated TYPES files carry in layered-packages mode. */
|
|
867
870
|
const DART_TYPES_IMPORT = `import 'package:nomos_types/nomos_types.dart';`;
|
|
868
|
-
/** Version constraints the scaffolded pubspecs pin — move together with the Dart packages' releases.
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
//
|
|
872
|
-
|
|
871
|
+
/** Version constraints the scaffolded pubspecs pin — move together with the Dart packages' releases.
|
|
872
|
+
* Caret on 0.x is EXACT-MINOR (`^0.45.0` = `<0.46.0`), so these must track the CURRENT release, not
|
|
873
|
+
* just the floor generated code needs — a lagging pin forces tenants into dependency_overrides. */
|
|
874
|
+
// 0.1.4: custody-lifecycle types (CustodyBreakPolicy et al).
|
|
875
|
+
// 0.2.0: branded birth identities (NomosPrincipal/NomosDeviceSecret) — the generated cross-workspace
|
|
876
|
+
// `.births()` methods type actor/authorSecret as these, so a layered package needs nomos_types 0.2.0.
|
|
877
|
+
const NOMOS_TYPES_DEP = "^0.2.0";
|
|
878
|
+
// 0.46.0: custody lifecycle on NomosBridge/NomosSession (onCustodyBreak/custodyStatus/salvage lanes).
|
|
879
|
+
const NOMOS_CLIENT_DEP = "^0.46.0";
|
|
873
880
|
|
|
874
881
|
const isPubPackageName = (s: string): boolean => /^[a-z][a-z0-9_]*$/.test(s);
|
|
875
882
|
|