@githolon/dsl 0.114.0 → 0.115.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/operation-contract.wasm +0 -0
- package/dart/CHANGELOG.md +40 -0
- package/dart/lib/src/application_framework_calls.dart +7 -1
- package/dart/lib/src/console_enrolment.dart +7 -0
- package/dart/lib/src/console_http_io.dart +22 -15
- package/dart/lib/src/dev_cloud.dart +62 -0
- package/dart/lib/src/operation_receipts.dart +74 -7
- package/dart/lib/src/reception/dart_reception.dart +26 -6
- package/dart/lib/src/runner/node-entry.mjs +7129 -4424
- package/dart/lib/src/runtime_v2_transport.dart +3 -0
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/console_enrolment_test.dart +47 -0
- package/dart/test/model_adoption_test.dart +49 -0
- package/dart/test/runtime_projections_test.dart +41 -0
- package/dart_types/CHANGELOG.md +24 -0
- package/dart_types/lib/src/approved_model.dart +78 -1
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +528 -2
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +24 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +1897 -112
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +98 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +16 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +43 -2
- package/dart_types/pubspec.yaml +1 -1
- package/package.json +4 -2
- package/src/aggregate.ts +93 -0
- package/src/anonymous_value_interning.ts +205 -0
- package/src/baseline.ts +27 -0
- package/src/baseline_export.ts +432 -0
- package/src/baseline_import.ts +312 -0
- package/src/baseline_usda.ts +186 -0
- package/src/birth_key_rule.ts +472 -0
- package/src/births.ts +207 -24
- package/src/build_provenance.ts +10 -0
- package/src/business_birth.ts +50 -4
- package/src/check_package_main.ts +50 -6
- package/src/codegen_call_proto.ts +5 -18
- package/src/codegen_dart.ts +95 -3
- package/src/codegen_dart_client.ts +52 -6
- package/src/codegen_dart_facade.ts +57 -35
- package/src/codegen_dart_framework_calls.ts +20 -1
- package/src/codegen_proof.ts +5 -2
- package/src/codegen_result_proto.ts +8 -6
- package/src/codegen_result_usda.ts +4 -0
- package/src/codegen_ts.ts +109 -10
- package/src/compatibility_graph.ts +41 -4
- package/src/compatibility_usda.ts +11 -1
- package/src/compile_package_main.ts +214 -51
- package/src/composed_wire_identity.ts +24 -0
- package/src/directive.ts +6 -0
- package/src/domain_requirements.ts +75 -0
- package/src/engine_javascript.ts +12 -6
- package/src/fields.ts +109 -0
- package/src/identity_usda.ts +77 -51
- package/src/index.ts +25 -1
- package/src/intent.ts +5 -0
- package/src/law_graph.ts +142 -1
- package/src/law_graph_usda.ts +25 -141
- package/src/law_layer_prims.ts +199 -0
- package/src/law_unit_selection.ts +45 -0
- package/src/law_version.ts +107 -0
- package/src/package_config.ts +44 -0
- package/src/package_dependencies.ts +8 -0
- package/src/value_object.ts +6 -3
- package/src/wire.ts +2 -0
- package/src/wire_paths.ts +17 -0
- package/src/workspace_routing.ts +1 -1
package/src/codegen_dart.ts
CHANGED
|
@@ -699,6 +699,8 @@ export interface AggFieldSpec {
|
|
|
699
699
|
dartType: string;
|
|
700
700
|
/** A canonical semantic string wrapper whose wire representation remains String. */
|
|
701
701
|
semanticString?: "sha256" | "git-object-id";
|
|
702
|
+
/** A typed id (`t.brandedId(Name)` / `t.uuid()`): the zero-cost extension type wrapping the wire String. */
|
|
703
|
+
brandedId?: string;
|
|
702
704
|
enumValues?: string[];
|
|
703
705
|
/** For an own-id string field represented as `NomosRef<TAggregate>`. */
|
|
704
706
|
valueClass?: string;
|
|
@@ -923,6 +925,9 @@ function readKeyParamSpec(
|
|
|
923
925
|
if (fieldSpec.semanticString === "git-object-id") {
|
|
924
926
|
return { dartType: "GitObjectId", valueExpr: `${paramName}.value` };
|
|
925
927
|
}
|
|
928
|
+
if (fieldSpec.brandedId !== undefined) {
|
|
929
|
+
return { dartType: fieldSpec.brandedId, valueExpr: `${paramName}.value` };
|
|
930
|
+
}
|
|
926
931
|
return { dartType: "String", valueExpr: paramName };
|
|
927
932
|
}
|
|
928
933
|
|
|
@@ -1032,7 +1037,9 @@ function aggFieldSpec(
|
|
|
1032
1037
|
// field schema marked them `.optional()`.
|
|
1033
1038
|
const optional = isCollectionKind(field.kind) ? false : field.isOptional;
|
|
1034
1039
|
switch (field.kind) {
|
|
1035
|
-
case "string":
|
|
1040
|
+
case "string": {
|
|
1041
|
+
// A TYPED ID field (`t.brandedId(Name)` / `t.uuid()`) reads as its extension type, never a String.
|
|
1042
|
+
const brand = valueClass === undefined ? brandedIdMetaOf(field.zod as z.ZodTypeAny) : undefined;
|
|
1036
1043
|
return {
|
|
1037
1044
|
name,
|
|
1038
1045
|
wireName,
|
|
@@ -1042,9 +1049,10 @@ function aggFieldSpec(
|
|
|
1042
1049
|
? "Sha256Digest"
|
|
1043
1050
|
: isGitObjectIdSchema(field.zod as z.ZodTypeAny)
|
|
1044
1051
|
? "GitObjectId"
|
|
1045
|
-
: "String"
|
|
1052
|
+
: brand ?? "String"
|
|
1046
1053
|
: `NomosRef<${valueClass}>`,
|
|
1047
1054
|
optional,
|
|
1055
|
+
...(brand !== undefined ? { brandedId: brand } : {}),
|
|
1048
1056
|
...(valueClass === undefined && isSha256DigestSchema(field.zod as z.ZodTypeAny)
|
|
1049
1057
|
? { semanticString: "sha256" as const }
|
|
1050
1058
|
: {}),
|
|
@@ -1055,6 +1063,7 @@ function aggFieldSpec(
|
|
|
1055
1063
|
? { valueClass, valueAggregateType }
|
|
1056
1064
|
: {}),
|
|
1057
1065
|
};
|
|
1066
|
+
}
|
|
1058
1067
|
case "json":
|
|
1059
1068
|
// A NAMED VALUE OBJECT (`ValueObject.field()`) types as its generated Dart class
|
|
1060
1069
|
// (typed decode via `.fromProjected`, the EvidenceRef pattern). Otherwise
|
|
@@ -3172,6 +3181,11 @@ function parseField(s: AggFieldSpec, aggregate: string): string {
|
|
|
3172
3181
|
? `() { final v = ${reader}; return v == null ? null : GitObjectId(v); }()`
|
|
3173
3182
|
: `GitObjectId(${reader})`;
|
|
3174
3183
|
}
|
|
3184
|
+
if (s.brandedId !== undefined) {
|
|
3185
|
+
return opt
|
|
3186
|
+
? `() { final v = ${reader}; return v == null ? null : ${s.brandedId}(v); }()`
|
|
3187
|
+
: `${s.brandedId}(${reader})`;
|
|
3188
|
+
}
|
|
3175
3189
|
return reader;
|
|
3176
3190
|
}
|
|
3177
3191
|
case "json":
|
|
@@ -3260,7 +3274,9 @@ function slotDecodeCallback(s: AggFieldSpec, mode: "aggregate" | "readModel"): s
|
|
|
3260
3274
|
? `(v) => Sha256Digest(v as String)`
|
|
3261
3275
|
: s.semanticString === "git-object-id"
|
|
3262
3276
|
? `(v) => GitObjectId(v as String)`
|
|
3263
|
-
:
|
|
3277
|
+
: s.brandedId !== undefined
|
|
3278
|
+
? `(v) => ${s.brandedId}(v as String)`
|
|
3279
|
+
: `(v) => v as String`;
|
|
3264
3280
|
case "json":
|
|
3265
3281
|
if (s.voClass !== undefined) {
|
|
3266
3282
|
return `(v) => ${s.voClass}.fromProjected((v as Map).cast<String, Object?>())`;
|
|
@@ -3413,6 +3429,11 @@ function parseReadModelField(s: AggFieldSpec, aggregate: string): string {
|
|
|
3413
3429
|
? `() { final v = ${reader}; return v == null ? null : GitObjectId(v); }()`
|
|
3414
3430
|
: `GitObjectId(${reader})`;
|
|
3415
3431
|
}
|
|
3432
|
+
if (s.brandedId !== undefined) {
|
|
3433
|
+
return opt
|
|
3434
|
+
? `() { final v = ${reader}; return v == null ? null : ${s.brandedId}(v); }()`
|
|
3435
|
+
: `${s.brandedId}(${reader})`;
|
|
3436
|
+
}
|
|
3416
3437
|
return reader;
|
|
3417
3438
|
}
|
|
3418
3439
|
case "json":
|
|
@@ -4993,6 +5014,65 @@ export interface GenerateDartDomainOptions {
|
|
|
4993
5014
|
* because it was present in the composed law.
|
|
4994
5015
|
*/
|
|
4995
5016
|
readonly additionalValueObjects?: readonly ValueObjectDescriptor[];
|
|
5017
|
+
/** Branded-id extension types another file (the package's `nomos_framework.dart`) declares because ≥2
|
|
5018
|
+
* domains use them; this domain references them via {@link frameworkImportUri}. */
|
|
5019
|
+
readonly skipBrandNames?: ReadonlySet<string>;
|
|
5020
|
+
/** Branded-id extension types this file declares for the package (the framework file's shared set). */
|
|
5021
|
+
readonly extraBrandNames?: readonly string[];
|
|
5022
|
+
}
|
|
5023
|
+
|
|
5024
|
+
/**
|
|
5025
|
+
* Every branded-id name (`brandedId(...)`, `t.brandedId(...)`, `t.uuid()`) whose Dart extension type this
|
|
5026
|
+
* domain's generated types reference: typed-id aggregate fields, top-level payload fields of its public
|
|
5027
|
+
* directives (business births render their public payload), and value-object fields. The package counts
|
|
5028
|
+
* these per domain so a brand used by two domains is declared ONCE, in the framework file.
|
|
5029
|
+
*/
|
|
5030
|
+
export function dartBrandNamesForModule(mod: DomainModule): Set<string> {
|
|
5031
|
+
const brands = new Set<string>();
|
|
5032
|
+
const publicAggregates = mod.aggregates.filter(
|
|
5033
|
+
(a) => (a as { businessBirthInternal?: unknown }).businessBirthInternal !== true,
|
|
5034
|
+
);
|
|
5035
|
+
for (const agg of publicAggregates) {
|
|
5036
|
+
for (const f of Object.values(agg.fields as Record<string, Field>)) {
|
|
5037
|
+
if (f.kind !== "string") continue;
|
|
5038
|
+
const b = brandedIdMetaOf(f.zod as z.ZodTypeAny);
|
|
5039
|
+
if (b !== undefined) brands.add(b);
|
|
5040
|
+
}
|
|
5041
|
+
}
|
|
5042
|
+
const directives = (mod.applicationIntents ?? mod.directives)
|
|
5043
|
+
.filter((d) => (d as { businessBirthInternal?: unknown }).businessBirthInternal !== true)
|
|
5044
|
+
.map((d) => {
|
|
5045
|
+
const birth = (d as { businessBirth?: { publicPayloadSchema?: z.ZodTypeAny } }).businessBirth;
|
|
5046
|
+
return birth?.publicPayloadSchema === undefined ? d : { ...d, payloadSchema: birth.publicPayloadSchema };
|
|
5047
|
+
});
|
|
5048
|
+
for (const dir of directives) {
|
|
5049
|
+
const schema = (dir as { payloadSchema?: unknown }).payloadSchema;
|
|
5050
|
+
if (!schema || typeof schema !== "object" || zodTypeName(schema as z.ZodTypeAny) !== "ZodObject") continue;
|
|
5051
|
+
const rawShape = (zodDef(schema as z.ZodTypeAny) as { shape?: Record<string, z.ZodTypeAny> | (() => Record<string, z.ZodTypeAny>) }).shape;
|
|
5052
|
+
const shp = typeof rawShape === "function" ? rawShape() : rawShape ?? {};
|
|
5053
|
+
for (let zt of Object.values(shp)) {
|
|
5054
|
+
for (let hops = 0; hops < 8 && (zodTypeName(zt) === "ZodOptional" || zodTypeName(zt) === "ZodDefault" || zodTypeName(zt) === "ZodArray"); hops++) {
|
|
5055
|
+
zt = zodTypeName(zt) === "ZodArray" ? zodArrayElement(zt) : zodInnerType(zt);
|
|
5056
|
+
}
|
|
5057
|
+
const b = brandedIdMetaOf(zt);
|
|
5058
|
+
if (b !== undefined) brands.add(b);
|
|
5059
|
+
}
|
|
5060
|
+
}
|
|
5061
|
+
const walk = (f: ValueObjectFieldDescriptor): void => {
|
|
5062
|
+
if (f.type === "string" && f.brand !== undefined && f.idOf === undefined) brands.add(f.brand);
|
|
5063
|
+
else if (f.type === "array") walk(f.items);
|
|
5064
|
+
else if (f.type === "map") walk(f.values);
|
|
5065
|
+
};
|
|
5066
|
+
for (const d of [
|
|
5067
|
+
...collectValueObjectDescriptors(publicAggregates),
|
|
5068
|
+
...collectPayloadValueObjectDescriptors(directives),
|
|
5069
|
+
]) {
|
|
5070
|
+
for (const f of Object.values(d.fields ?? {})) walk(f);
|
|
5071
|
+
for (const arm of Object.values(d.union ?? {})) {
|
|
5072
|
+
if ("fields" in arm) for (const f of Object.values(arm.fields)) walk(f);
|
|
5073
|
+
}
|
|
5074
|
+
}
|
|
5075
|
+
return brands;
|
|
4996
5076
|
}
|
|
4997
5077
|
|
|
4998
5078
|
/** Generate the full Dart source for one domain module. */
|
|
@@ -5098,6 +5178,16 @@ export function generateDartDomain(mod: DomainModule, opts: GenerateDartDomainOp
|
|
|
5098
5178
|
else if (f.type === "array") walkUnitField(f.items);
|
|
5099
5179
|
else if (f.type === "map") walkUnitField(f.values);
|
|
5100
5180
|
};
|
|
5181
|
+
// TYPED-ID aggregate fields (`t.brandedId(Name)` / `t.uuid()`) declare their extension type with the
|
|
5182
|
+
// aggregate that owns them (skipping aggregates another file declares).
|
|
5183
|
+
for (const agg of mod.aggregates) {
|
|
5184
|
+
if (opts.skipAggregateIds?.has(agg.id) === true) continue;
|
|
5185
|
+
for (const f of Object.values(agg.fields as Record<string, Field>)) {
|
|
5186
|
+
if (f.kind !== "string") continue;
|
|
5187
|
+
const b = brandedIdMetaOf(f.zod as z.ZodTypeAny);
|
|
5188
|
+
if (b !== undefined) brandNames.add(b);
|
|
5189
|
+
}
|
|
5190
|
+
}
|
|
5101
5191
|
for (const d of localValueObjects) {
|
|
5102
5192
|
for (const f of Object.values(d.fields ?? {})) walkUnitField(f);
|
|
5103
5193
|
for (const arm of Object.values(d.union ?? {})) {
|
|
@@ -5128,6 +5218,8 @@ export function generateDartDomain(mod: DomainModule, opts: GenerateDartDomainOp
|
|
|
5128
5218
|
} catch { /* an unsupported payload shape is reported by the payload emitter, not here */ }
|
|
5129
5219
|
}
|
|
5130
5220
|
}
|
|
5221
|
+
for (const b of opts.skipBrandNames ?? []) brandNames.delete(b);
|
|
5222
|
+
for (const b of opts.extraBrandNames ?? []) brandNames.add(b);
|
|
5131
5223
|
const unitBlock = [...unitNames].sort().map((u) => [
|
|
5132
5224
|
`/// UNIT \`${u}\` — a ZERO-COST wrapper over the wire's plain JSON number (Dart extension`,
|
|
5133
5225
|
`/// type): passing a bare double (or another unit) where [${u}] is required is a COMPILE`,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BUSINESS_BIRTH_KEY_PAYLOAD_FIELD } from "./births.js";
|
|
1
2
|
import { dartRefusalDecoders } from "./codegen_refusal.js";
|
|
2
3
|
// NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
|
|
3
4
|
// remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
|
|
@@ -99,7 +100,7 @@ import { publicClientInterface, type DomainInterface } from "./compatibility_gra
|
|
|
99
100
|
import { emitApplicationCompatibilityUsda } from "./compatibility_usda.js";
|
|
100
101
|
import { BUSINESS_CORRECTION_DIRECTIVE } from "./framework/business_corrections.js";
|
|
101
102
|
import { deriveDirectiveRecordTarget } from "./workspace_routing.js";
|
|
102
|
-
import { voMetaOf } from "./value_object.js";
|
|
103
|
+
import { brandedIdMetaOf, voMetaOf } from "./value_object.js";
|
|
103
104
|
import {
|
|
104
105
|
buildNomosDescribeModel,
|
|
105
106
|
type NomosDescribeModel,
|
|
@@ -389,6 +390,11 @@ function dartKeyType(
|
|
|
389
390
|
if (f?.kind === "string" && isSha256DigestSchema(f.zod as z.ZodTypeAny)) {
|
|
390
391
|
return "Sha256Digest";
|
|
391
392
|
}
|
|
393
|
+
// A typed-id key (`t.brandedId(Name)` / `t.uuid()`) is its extension type, never a bare String.
|
|
394
|
+
if (f?.kind === "string" && !key.includes(".")) {
|
|
395
|
+
const brand = brandedIdMetaOf(f.zod as z.ZodTypeAny);
|
|
396
|
+
if (brand !== undefined) return brand;
|
|
397
|
+
}
|
|
392
398
|
if (f?.kind === "string" && isGitObjectIdSchema(f.zod as z.ZodTypeAny)) {
|
|
393
399
|
return "GitObjectId";
|
|
394
400
|
}
|
|
@@ -435,6 +441,13 @@ function dartKeyExpr(agg: AggregateHandle | undefined, key: string): string {
|
|
|
435
441
|
) {
|
|
436
442
|
return `${param}.value`;
|
|
437
443
|
}
|
|
444
|
+
if (
|
|
445
|
+
field?.kind === "string" &&
|
|
446
|
+
!key.includes(".") &&
|
|
447
|
+
brandedIdMetaOf(field.zod as z.ZodTypeAny) !== undefined
|
|
448
|
+
) {
|
|
449
|
+
return `${param}.value`;
|
|
450
|
+
}
|
|
438
451
|
if (field?.kind !== "ref") return param;
|
|
439
452
|
return field.foreignRef !== undefined
|
|
440
453
|
? `NmsInternalNomosRefs.id(${param}.ref)`
|
|
@@ -491,6 +504,8 @@ function dartUsdaBasePresentValue(
|
|
|
491
504
|
? `Sha256Digest(${value})`
|
|
492
505
|
: spec.semanticString === "git-object-id"
|
|
493
506
|
? `GitObjectId(${value})`
|
|
507
|
+
: spec.brandedId !== undefined
|
|
508
|
+
? `${spec.brandedId}(${value})`
|
|
494
509
|
: value;
|
|
495
510
|
}
|
|
496
511
|
case "ref": {
|
|
@@ -1305,7 +1320,7 @@ export function generateDartDomainClient(
|
|
|
1305
1320
|
const compilerInternal = sourceTrustViaIds.has(directive.id);
|
|
1306
1321
|
const businessBirth = (
|
|
1307
1322
|
directive as unknown as {
|
|
1308
|
-
businessBirth?: { publicPayloadSchema: z.ZodTypeAny };
|
|
1323
|
+
businessBirth?: { publicPayloadSchema: z.ZodTypeAny; keyField?: string };
|
|
1309
1324
|
}
|
|
1310
1325
|
).businessBirth;
|
|
1311
1326
|
const specs = introspectPayload(
|
|
@@ -1360,6 +1375,15 @@ export function generateDartDomainClient(
|
|
|
1360
1375
|
arguments_.push("principal", "bornAt");
|
|
1361
1376
|
access.set("principal", { value: "nmsInternalBirthPrincipal" });
|
|
1362
1377
|
access.set("bornAt", { value: "nmsInternalBornAt" });
|
|
1378
|
+
// A minted birth's law admits a key the client reserved ahead of dispatch (CAP-804).
|
|
1379
|
+
if (businessBirth.keyField === undefined) {
|
|
1380
|
+
extraParameters.push("String? nmsInternalBirthKey");
|
|
1381
|
+
arguments_.push("nmsInternalBirthKey");
|
|
1382
|
+
access.set(BUSINESS_BIRTH_KEY_PAYLOAD_FIELD, {
|
|
1383
|
+
value: "nmsInternalBirthKey!",
|
|
1384
|
+
present: "nmsInternalBirthKey != null",
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1363
1387
|
}
|
|
1364
1388
|
for (const input of dartBusinessRecordInputs(directive, mod.aggregates)) {
|
|
1365
1389
|
const origin = `NmsInternalRecordOrigins.require(payload.${input.argument})`;
|
|
@@ -1954,7 +1978,8 @@ export function generateDartDomainClient(
|
|
|
1954
1978
|
domain: string;
|
|
1955
1979
|
rootId: string;
|
|
1956
1980
|
namespace: string;
|
|
1957
|
-
keyField
|
|
1981
|
+
keyField?: string;
|
|
1982
|
+
keyType?: { type: string; brand: string };
|
|
1958
1983
|
seedDirectiveId?: string;
|
|
1959
1984
|
genesisDirectiveIds?: readonly string[];
|
|
1960
1985
|
publicPayloadSchema: z.ZodTypeAny;
|
|
@@ -2010,6 +2035,18 @@ export function generateDartDomainClient(
|
|
|
2010
2035
|
const birthSpecsByName = new Map(
|
|
2011
2036
|
birthSpecs.map((spec) => [spec.name, spec])
|
|
2012
2037
|
);
|
|
2038
|
+
// A minted birth (the default) has no business key; an owned one seals to the child's address
|
|
2039
|
+
// before dispatch, so it reserves its key from the kernel's own minter and hands it to the law.
|
|
2040
|
+
const mintedBirth = businessBirth.keyField === undefined;
|
|
2041
|
+
const birthKeyPrelude = !mintedBirth
|
|
2042
|
+
? []
|
|
2043
|
+
: ownedBirthDescriptor === undefined
|
|
2044
|
+
? [` const String? nmsInternalBirthKey = null;`]
|
|
2045
|
+
: [
|
|
2046
|
+
` final String? nmsInternalBirthKey = await session.mintId(${dartStr(
|
|
2047
|
+
businessBirth.aggregateId
|
|
2048
|
+
)});`,
|
|
2049
|
+
];
|
|
2013
2050
|
const ownedBirthPrelude =
|
|
2014
2051
|
ownedBirthDescriptor === undefined
|
|
2015
2052
|
? []
|
|
@@ -2017,9 +2054,17 @@ export function generateDartDomainClient(
|
|
|
2017
2054
|
` final nmsInternalOwnedKey = await session.nomosOwnedBirthScopeKey(`,
|
|
2018
2055
|
` ${dartStr(ownedBirthDescriptor.scope)}, ${dartStr(
|
|
2019
2056
|
businessBirth.namespace
|
|
2020
|
-
)},
|
|
2021
|
-
|
|
2022
|
-
|
|
2057
|
+
)}, ${
|
|
2058
|
+
mintedBirth
|
|
2059
|
+
? "nmsInternalBirthKey!"
|
|
2060
|
+
: `payload.${dartMemberName(businessBirth.keyField!)}${
|
|
2061
|
+
businessBirth.keyType?.type === "brandedId" || businessBirth.keyType?.type === "uuid"
|
|
2062
|
+
? ".value"
|
|
2063
|
+
: ""
|
|
2064
|
+
}`
|
|
2065
|
+
}, ${dartStr(birthRuntimeType!)}, ${dartStr(
|
|
2066
|
+
businessBirth.rootId
|
|
2067
|
+
)});`,
|
|
2023
2068
|
` final nmsInternalOwnedKeySubject = nmsInternalOwnedKey.ownedKeySubject;`,
|
|
2024
2069
|
` if (nmsInternalOwnedKeySubject == null || nmsInternalOwnedKeySubject.isEmpty) {`,
|
|
2025
2070
|
` throw StateError('Nomos did not return the framework-owned device identity for .owned() custody');`,
|
|
@@ -2148,6 +2193,7 @@ export function generateDartDomainClient(
|
|
|
2148
2193
|
),
|
|
2149
2194
|
]),
|
|
2150
2195
|
` final bornAt = DateTime.now().toUtc().toIso8601String();`,
|
|
2196
|
+
...birthKeyPrelude,
|
|
2151
2197
|
...ownedBirthPrelude,
|
|
2152
2198
|
...birthSealPrelude,
|
|
2153
2199
|
...(birthEncryption === undefined
|
|
@@ -5,6 +5,7 @@ import { refusalContracts, refusalType, refusalDecoder } from "./codegen_refusal
|
|
|
5
5
|
// application contract: business inputs in, business ids/models out. It deliberately has no public
|
|
6
6
|
// session/session/workspace/actor/sync surface.
|
|
7
7
|
import type { z } from "zod";
|
|
8
|
+
import { brandedIdMetaOf } from "./value_object.js";
|
|
8
9
|
|
|
9
10
|
import type { AggregateHandle } from "./aggregate.js";
|
|
10
11
|
import type { Directive } from "./directive.js";
|
|
@@ -153,6 +154,11 @@ function keyType(
|
|
|
153
154
|
) {
|
|
154
155
|
return "GitObjectId";
|
|
155
156
|
}
|
|
157
|
+
// A typed-id key (`t.brandedId(Name)` / `t.uuid()`) is its extension type, never a bare String.
|
|
158
|
+
if (field?.kind === "string" && !key.includes(".")) {
|
|
159
|
+
const brand = brandedIdMetaOf(field.zod as z.ZodTypeAny);
|
|
160
|
+
if (brand !== undefined) return brand;
|
|
161
|
+
}
|
|
156
162
|
return "String";
|
|
157
163
|
}
|
|
158
164
|
|
|
@@ -381,7 +387,7 @@ export function generateDartApplication(
|
|
|
381
387
|
const source = aggregate.fields[name]!;
|
|
382
388
|
const value = source.kind === "enum" ? `${access}?.wire`
|
|
383
389
|
: source.kind === "ref" ? `${access}?.id`
|
|
384
|
-
: source.kind === "string" && (isSha256DigestSchema(source.zod) || isGitObjectIdSchema(source.zod)) ? `${access}?.value`
|
|
390
|
+
: source.kind === "string" && (isSha256DigestSchema(source.zod) || isGitObjectIdSchema(source.zod) || brandedIdMetaOf(source.zod as z.ZodTypeAny) !== undefined) ? `${access}?.value`
|
|
385
391
|
: access;
|
|
386
392
|
return ` ${member(name)}: ${value},`;
|
|
387
393
|
}),
|
|
@@ -900,7 +906,9 @@ export function generateDartApplication(
|
|
|
900
906
|
aggregateId: string;
|
|
901
907
|
namespace: string;
|
|
902
908
|
rootId: string;
|
|
903
|
-
|
|
909
|
+
keyMode?: "minted" | "field";
|
|
910
|
+
keyField?: string;
|
|
911
|
+
keyType?: { type: string; brand: string };
|
|
904
912
|
};
|
|
905
913
|
birthsChild?: boolean;
|
|
906
914
|
}
|
|
@@ -993,39 +1001,53 @@ export function generateDartApplication(
|
|
|
993
1001
|
` return _nmsReception.fetchWorkspace(reference.workspace);`,
|
|
994
1002
|
` }`,
|
|
995
1003
|
``,
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
`
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1004
|
+
// Open/fetch BY KEY exist only for a birth keyed by a declared business fact. A minted birth
|
|
1005
|
+
// (the default) has no business key: its address is the NomosRef its birth returned.
|
|
1006
|
+
// The key param is the key field's TYPED ID (its extension type, declared with the birth payload in
|
|
1007
|
+
// this domain's types); `.value` is its wire string.
|
|
1008
|
+
...(birth.keyField === undefined
|
|
1009
|
+
? []
|
|
1010
|
+
: (() => {
|
|
1011
|
+
const typedKey = birth.keyType !== undefined &&
|
|
1012
|
+
(birth.keyType.type === "brandedId" || birth.keyType.type === "uuid");
|
|
1013
|
+
const keyParam = typedKey ? `${birth.keyType!.brand} key` : "String key";
|
|
1014
|
+
const keyWire = typedKey ? "key.value" : "key";
|
|
1015
|
+
return [
|
|
1016
|
+
` /// Open the ${birth.aggregateId} whose ${birth.keyField} is [key].`,
|
|
1017
|
+
` /// THE OFFICE NAMES THE WORKSPACE this key addresses: the derivation is law,`,
|
|
1018
|
+
` /// and a generated copy of it would silently address a different workspace`,
|
|
1019
|
+
` /// the moment either side moved.`,
|
|
1020
|
+
` Future<${targetApplication}> open(${keyParam}) async => _nmsOpenReference(`,
|
|
1021
|
+
` NmsInternalNomosRefs.create<${rootType}>(`,
|
|
1022
|
+
` workspace: await _nmsReception.keyedBirthWorkspace(`,
|
|
1023
|
+
` namespace: ${JSON.stringify(birth.namespace)}, key: ${keyWire},`,
|
|
1024
|
+
` ),`,
|
|
1025
|
+
` type: ${JSON.stringify(birth.aggregateId)},`,
|
|
1026
|
+
` id: ${JSON.stringify(birth.rootId)},`,
|
|
1027
|
+
` ),`,
|
|
1028
|
+
` );`,
|
|
1029
|
+
``,
|
|
1030
|
+
` /// Fetch the ${birth.aggregateId} whose ${birth.keyField} is [key] onto this device now,`,
|
|
1031
|
+
` /// opening and reading nothing: its placement's follow mounts the provider's head in`,
|
|
1032
|
+
` /// the background. Completes once that follow exists (e.g. prefetching every workspace`,
|
|
1033
|
+
` /// a list names, all at once, so each is local before it is tapped).`,
|
|
1034
|
+
` Future<void> fetch(${keyParam}) async => _nmsReception.fetchWorkspace(`,
|
|
1035
|
+
` await _nmsReception.keyedBirthWorkspace(`,
|
|
1036
|
+
` namespace: ${JSON.stringify(birth.namespace)}, key: ${keyWire},`,
|
|
1037
|
+
` ),`,
|
|
1038
|
+
` );`,
|
|
1039
|
+
``,
|
|
1040
|
+
` /// Kernel-owned progress updates while [open] prepares this workspace.`,
|
|
1041
|
+
` /// ONE LANE: the stream is the whole surface. A synchronous snapshot`,
|
|
1042
|
+
` /// would have to answer before the office has named the workspace, so`,
|
|
1043
|
+
` /// it could only ever answer null or hold a cached name of its own.`,
|
|
1044
|
+
` Stream<ApplicationWorkspaceOpenProgress> watchOpenProgress(${keyParam}) =>`,
|
|
1045
|
+
` Stream<String>.fromFuture(_nmsReception.keyedBirthWorkspace(`,
|
|
1046
|
+
` namespace: ${JSON.stringify(birth.namespace)}, key: ${keyWire},`,
|
|
1047
|
+
` )).asyncExpand(_nmsReception.streams.workspaceOpenProgress);`,
|
|
1048
|
+
``,
|
|
1049
|
+
];
|
|
1050
|
+
})()),
|
|
1029
1051
|
]);
|
|
1030
1052
|
addCollectionMember(birth.aggregateId, "mine", [
|
|
1031
1053
|
` /// The ${birth.aggregateId} lives founded by the signed-in person.`,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertDomainRequirements, type DomainUnitRequirement } from "./domain_requirements.js";
|
|
1
2
|
import type { z } from "zod";
|
|
2
3
|
|
|
3
4
|
import type { Directive } from "./directive.js";
|
|
@@ -177,6 +178,12 @@ export function generateDartApplicationFrameworkCalls(
|
|
|
177
178
|
readonly lawUnitSet: string;
|
|
178
179
|
/** The compiled package closure (`build/<name>.law.usdz`): the bytes a device stages. Not what a target serves. */
|
|
179
180
|
readonly lawPackageSha256: string;
|
|
181
|
+
/**
|
|
182
|
+
* THE PER-DOMAIN REQUIREMENTS (CAP-666): per application domain key, its unit hash and the identity of its
|
|
183
|
+
* generated compatibility requirement. Absent or empty emits an empty table (a package with no application
|
|
184
|
+
* interface); the getter itself is always emitted, since the runtime interface is exhaustive.
|
|
185
|
+
*/
|
|
186
|
+
readonly domainRequirements?: readonly DomainUnitRequirement[];
|
|
180
187
|
},
|
|
181
188
|
): string | undefined {
|
|
182
189
|
for (const [name, value] of [["law unit set", descriptor.lawUnitSet], ["package", descriptor.lawPackageSha256]] as const) {
|
|
@@ -184,6 +191,8 @@ export function generateDartApplicationFrameworkCalls(
|
|
|
184
191
|
throw new Error(`Dart framework call codegen: the application's ${name} identity must be 64 lowercase hex, not '${value}'`);
|
|
185
192
|
}
|
|
186
193
|
}
|
|
194
|
+
const domainRequirements = [...(descriptor.domainRequirements ?? [])].sort((a, b) => a.domainKey < b.domainKey ? -1 : a.domainKey > b.domainKey ? 1 : 0);
|
|
195
|
+
assertDomainRequirements(domainRequirements);
|
|
187
196
|
const frameworkEnumDartTypes = collectFixedFrameworkDartEnums().dartTypes;
|
|
188
197
|
const fixedEmitted = FIXED_CALLS.flatMap((definition) => laws.flatMap((law) => {
|
|
189
198
|
const declares = law.graph.nodes.some((node) =>
|
|
@@ -622,7 +631,7 @@ export function generateDartApplicationFrameworkCalls(
|
|
|
622
631
|
`import 'package:fixnum/fixnum.dart' show Int64;`,
|
|
623
632
|
`import 'operation_payloads.pb.dart' as _nmsop;`,
|
|
624
633
|
`import 'package:nomos_types/nomos_kernel_protocol.dart' show BirthCertificate;`,
|
|
625
|
-
`import 'package:nomos_types/nomos_types.dart' show NomosSlot, Sha256Digest;`,
|
|
634
|
+
`import 'package:nomos_types/nomos_types.dart' show NomosDomainRequirement, NomosSlot, Sha256Digest;`,
|
|
626
635
|
`import 'package:nomos_client/src/application_framework_calls.dart';`,
|
|
627
636
|
`import 'package:nomos_client/src/generated_call.dart';`,
|
|
628
637
|
``,
|
|
@@ -651,6 +660,16 @@ export function generateDartApplicationFrameworkCalls(
|
|
|
651
660
|
` String get lawUnitSet => ${JSON.stringify(descriptor.lawUnitSet)};`,
|
|
652
661
|
` @override`,
|
|
653
662
|
` String get lawPackageSha256 => ${JSON.stringify(descriptor.lawPackageSha256)};`,
|
|
663
|
+
` @override`,
|
|
664
|
+
...(domainRequirements.length === 0
|
|
665
|
+
? [` Map<String, NomosDomainRequirement> get domainRequirements => const {};`]
|
|
666
|
+
: [
|
|
667
|
+
` Map<String, NomosDomainRequirement> get domainRequirements => const {`,
|
|
668
|
+
...domainRequirements.map((requirement) =>
|
|
669
|
+
` ${JSON.stringify(requirement.domainKey)}: NomosDomainRequirement(domainKey: ${JSON.stringify(requirement.domainKey)}, `
|
|
670
|
+
+ `unitSha256: ${JSON.stringify(requirement.unitSha256)}, requirementSha256: ${JSON.stringify(requirement.requirementSha256)}),`),
|
|
671
|
+
` };`,
|
|
672
|
+
]),
|
|
654
673
|
``,
|
|
655
674
|
...methods,
|
|
656
675
|
`}`,
|
package/src/codegen_proof.ts
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
* Deterministic codegen: the emitted bytes are a pure function of the modules +
|
|
33
33
|
* package name + domain hash — no timestamps or generation-time randomness.
|
|
34
34
|
*/
|
|
35
|
+
import { BUSINESS_BIRTH_KEY_PAYLOAD_FIELD } from "./births.js";
|
|
35
36
|
import type { z } from "zod";
|
|
36
37
|
|
|
37
38
|
import { BUSINESS_BIRTH_SEED_PAYLOAD_FIELD, type AggregateHandle } from "./aggregate.js";
|
|
@@ -2836,10 +2837,12 @@ function attachBusinessEncryption(
|
|
|
2836
2837
|
const directive = (mod?.directives as Directive<unknown>[] | undefined)?.find(
|
|
2837
2838
|
(candidate) => candidate.id === leg.birthDirectiveId,
|
|
2838
2839
|
) as (Directive<unknown> & {
|
|
2839
|
-
businessBirth?: { namespace?: string; keyField?: string };
|
|
2840
|
+
businessBirth?: { namespace?: string; keyField?: string; keyMode?: string };
|
|
2840
2841
|
}) | undefined;
|
|
2841
2842
|
const namespace = directive?.businessBirth?.namespace;
|
|
2842
|
-
|
|
2843
|
+
// A minted birth's key rides the hidden reserved-key field (CAP-804).
|
|
2844
|
+
const keyField = directive?.businessBirth?.keyField
|
|
2845
|
+
?? (directive?.businessBirth?.keyMode === "minted" ? BUSINESS_BIRTH_KEY_PAYLOAD_FIELD : undefined);
|
|
2843
2846
|
const offered = packageInterface[leg.parentDomain];
|
|
2844
2847
|
const offeredAggregate = offered === undefined
|
|
2845
2848
|
? undefined
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { admitsNull, isGitObjectIdSchema, isSha256DigestSchema, type Field } from "./fields.js";
|
|
2
|
+
import { brandedIdMetaOf } from "./value_object.js";
|
|
2
3
|
import type {
|
|
3
4
|
LawAnonymousValueFieldNode,
|
|
4
5
|
LawAnonymousValueTypeNode,
|
|
@@ -125,12 +126,13 @@ function authoredFieldValue(
|
|
|
125
126
|
return `foreignRef<${target}>(${holon}, ${JSON.stringify(field.foreignRef.targetAggregateId)}, ${selected}, ${foreignWorkspace})`;
|
|
126
127
|
}
|
|
127
128
|
switch (field.kind) {
|
|
128
|
-
case "string":
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
case "string": {
|
|
130
|
+
if (isSha256DigestSchema(field.zod)) return `sha256Digest(${selected})`;
|
|
131
|
+
if (isGitObjectIdSchema(field.zod)) return `gitObjectId(${selected})`;
|
|
132
|
+
// A typed id field (`t.brandedId(Name)` / `t.uuid()`): the wire string IS the id (nominal only).
|
|
133
|
+
const brand = brandedIdMetaOf(field.zod as never);
|
|
134
|
+
return brand === undefined ? selected : `(${selected} as ${brand})`;
|
|
135
|
+
}
|
|
134
136
|
case "position": return selected;
|
|
135
137
|
case "ref":
|
|
136
138
|
return field.foreignRef === undefined &&
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
zodKind,
|
|
16
16
|
zodObjectShape,
|
|
17
17
|
} from "./zod_introspection.js";
|
|
18
|
+
import { brandedIdMetaOf } from "./value_object.js";
|
|
18
19
|
|
|
19
20
|
export interface TsResultField {
|
|
20
21
|
readonly name: string;
|
|
@@ -391,6 +392,9 @@ const decode = (field: Field, expression: string): string => {
|
|
|
391
392
|
? `sha256Digest(_nmsUsdaStringValue(${expression}))`
|
|
392
393
|
: isGitObjectIdSchema(field.zod)
|
|
393
394
|
? `gitObjectId(_nmsUsdaStringValue(${expression}))`
|
|
395
|
+
: brandedIdMetaOf(field.zod as z.ZodTypeAny) !== undefined
|
|
396
|
+
// A typed id field: the wire string IS the id; the brand is nominal only.
|
|
397
|
+
? `(_nmsUsdaStringValue(${expression}) as ${brandedIdMetaOf(field.zod as z.ZodTypeAny)})`
|
|
394
398
|
: `_nmsUsdaStringValue(${expression})`;
|
|
395
399
|
case "position":
|
|
396
400
|
return `_nmsUsdaStringValue(${expression})`;
|