@githolon/dsl 0.108.3 → 0.108.6
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 +10 -0
- package/dart/lib/src/application_framework_calls.dart +21 -0
- package/dart/lib/src/dev_cloud.dart +67 -0
- package/dart/lib/src/nms_test_environment.dart +1 -1
- package/dart/lib/src/runner/node-entry.mjs +372 -106
- package/dart/lib/src/runner/offline-install.mjs +171 -11
- package/dart/lib/src/session_bound.dart +58 -30
- package/dart/lib/src/test_harness.dart +60 -98
- package/dart/lib/src/webview_bridge.dart +212 -32
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/node_runner_transport_test.dart +5 -5
- package/dart/test/webview_bridge_test.dart +6 -0
- package/dart_types/CHANGELOG.md +4 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +428 -2
- package/dart_types/pubspec.yaml +1 -1
- package/package.json +1 -1
- package/runtime/generated-application-host.js +314 -82
- package/src/application_topology.ts +120 -28
- package/src/births.ts +27 -0
- package/src/codegen_call_usda.ts +9 -4
- package/src/codegen_dart_application.ts +146 -37
- package/src/codegen_dart_client.ts +225 -160
- package/src/codegen_dart_framework_calls.ts +89 -4
- package/src/codegen_ts.ts +135 -60
- package/src/compile_package_main.ts +3544 -1460
- package/src/directive.ts +320 -118
- package/src/fields.ts +2 -3
- package/src/framework/application_home.ts +3 -0
- package/src/framework/auth_provider_law.ts +20 -16
- package/src/framework/genesis.ts +32 -1
- package/src/framework/home.ts +45 -8
- package/src/framework/signing_identity.ts +78 -0
- package/src/framework/workspaces.ts +9 -1
- package/src/framework_call_dart_enums.ts +33 -0
- package/src/framework_call_definitions.ts +11 -2
- package/src/index.ts +12 -0
- package/src/intent.ts +525 -194
- package/src/law_graph.ts +32 -4
- package/src/law_graph_usda.ts +3 -0
- package/src/package_config.ts +16 -1
- package/src/read.ts +33 -11
- package/src/wire.ts +1 -0
- package/src/wire_encode.ts +3 -3
package/src/law_graph.ts
CHANGED
|
@@ -595,6 +595,8 @@ export interface LawIntentNode {
|
|
|
595
595
|
readonly workspaceRelations: readonly LawStructuralRef<"workspace-relation">[];
|
|
596
596
|
/** Exact signed parent-workspace effects may propose this call; authority is still `.requires`. */
|
|
597
597
|
readonly acceptsWorkspaceEffect: boolean;
|
|
598
|
+
/** Recovery-only admission: the verified source workspace must be the target's exact birth parent. */
|
|
599
|
+
readonly acceptsVerifiedBirthParentRecovery: boolean;
|
|
598
600
|
/** Client proof selected by law for this exact public offer. Absence retains the ordinary
|
|
599
601
|
* session-credential posture. */
|
|
600
602
|
readonly offerAuthenticationProof?: "enrolledDevice";
|
|
@@ -1484,6 +1486,8 @@ export function discoverLawGraph(
|
|
|
1484
1486
|
foreignReads: [],
|
|
1485
1487
|
workspaceRelations,
|
|
1486
1488
|
acceptsWorkspaceEffect: intent.acceptsWorkspaceEffectGate === true,
|
|
1489
|
+
acceptsVerifiedBirthParentRecovery:
|
|
1490
|
+
intent.acceptsVerifiedBirthParentRecoveryGate === true,
|
|
1487
1491
|
...(isBusinessIntent(intent) && intent.offerAuthenticationProof !== undefined
|
|
1488
1492
|
? { offerAuthenticationProof: intent.offerAuthenticationProof }
|
|
1489
1493
|
: {}),
|
|
@@ -1672,6 +1676,8 @@ export function discoverLawGraph(
|
|
|
1672
1676
|
relation.label,
|
|
1673
1677
|
namespacedRelationTypes,
|
|
1674
1678
|
domainKey,
|
|
1679
|
+
relation.global,
|
|
1680
|
+
relation.authoredObjectType,
|
|
1675
1681
|
),
|
|
1676
1682
|
] as const));
|
|
1677
1683
|
const relationPredicateNodes = new Map<LawStructuralSid<"relation-predicate">, LawRelationPredicateNode>();
|
|
@@ -1704,7 +1710,10 @@ export function discoverLawGraph(
|
|
|
1704
1710
|
for (const [index, intentNode] of intentNodes.entries()) {
|
|
1705
1711
|
const declaration = intents.find((intent) => intent.id === intentNode.entity.label)!;
|
|
1706
1712
|
const gate = declaration.requiresRelationGate;
|
|
1707
|
-
if (
|
|
1713
|
+
if (
|
|
1714
|
+
declaration.acceptsWorkspaceEffectGate === true &&
|
|
1715
|
+
declaration.acceptsVerifiedBirthParentRecoveryGate !== true
|
|
1716
|
+
) {
|
|
1708
1717
|
if (gate === undefined || gate.object !== "workspace:self" || gate.objectFrom !== undefined) {
|
|
1709
1718
|
fail(
|
|
1710
1719
|
`intent '${declaration.id}' .acceptsWorkspaceEffect() requires a static ` +
|
|
@@ -1752,7 +1761,12 @@ export function discoverLawGraph(
|
|
|
1752
1761
|
...intentNode,
|
|
1753
1762
|
authorization: {
|
|
1754
1763
|
relation: candidates[0] === undefined
|
|
1755
|
-
? {
|
|
1764
|
+
? {
|
|
1765
|
+
kind: "dependency-export",
|
|
1766
|
+
entityKind: "relation",
|
|
1767
|
+
label: exactLabel,
|
|
1768
|
+
domain: module.name,
|
|
1769
|
+
}
|
|
1756
1770
|
: ref(candidates[0].entity),
|
|
1757
1771
|
object: authorizationObject,
|
|
1758
1772
|
...(objectFrom === undefined ? {} : { objectFrom }),
|
|
@@ -1771,7 +1785,12 @@ export function discoverLawGraph(
|
|
|
1771
1785
|
fail(`aggregate '${aggregate.id}' read relation '${relationName}' is ambiguous across relation types`);
|
|
1772
1786
|
}
|
|
1773
1787
|
const readPolicy: LawTargetRef<"relation" | "policy"> = candidates[0] === undefined
|
|
1774
|
-
? {
|
|
1788
|
+
? {
|
|
1789
|
+
kind: "dependency-export",
|
|
1790
|
+
entityKind: "relation",
|
|
1791
|
+
label: relationLabel,
|
|
1792
|
+
domain: module.name,
|
|
1793
|
+
}
|
|
1775
1794
|
: ref(candidates[0].entity);
|
|
1776
1795
|
const entry = aggregateByLabel.get(aggregate.id)!;
|
|
1777
1796
|
const updated = { ...entry.node, readPolicy };
|
|
@@ -3030,10 +3049,19 @@ function linkRelationAllowed(
|
|
|
3030
3049
|
owner: string,
|
|
3031
3050
|
namespacedTypes: ReadonlySet<string>,
|
|
3032
3051
|
domainKey: string,
|
|
3052
|
+
ownerIsGlobal: boolean,
|
|
3053
|
+
ownerObjectType: string,
|
|
3033
3054
|
): LawAllowedSubject[] {
|
|
3034
3055
|
return sortStructuralValues(allowed.map((subject): LawAllowedSubject => {
|
|
3035
3056
|
if (subject.kind === "wildcard") return { kind: "wildcard" };
|
|
3036
|
-
|
|
3057
|
+
// A global relation over `workspace` may coexist with application-local
|
|
3058
|
+
// `workspace` relations in the same domain. Its self-typed subjects are the
|
|
3059
|
+
// same global object class, not the coincidentally named local class.
|
|
3060
|
+
// Otherwise `workspace:self#child@workspace:<child>` compiles as allowing
|
|
3061
|
+
// only `<domain>__workspace:*`, making the correctly proven workspace actor
|
|
3062
|
+
// impossible to authorize.
|
|
3063
|
+
const subjectType = namespacedTypes.has(subject.type) &&
|
|
3064
|
+
!(ownerIsGlobal && subject.type === ownerObjectType)
|
|
3037
3065
|
? qualifyRelationType(domainKey, subject.type)
|
|
3038
3066
|
: subject.type;
|
|
3039
3067
|
if (subject.kind === "direct") return { kind: "direct", type: subjectType };
|
package/src/law_graph_usda.ts
CHANGED
|
@@ -986,6 +986,9 @@ function emitIntent(
|
|
|
986
986
|
...(intent.acceptsWorkspaceEffect
|
|
987
987
|
? [`${pad}custom uniform bool nomos:acceptsWorkspaceEffect = true`]
|
|
988
988
|
: []),
|
|
989
|
+
...(intent.acceptsVerifiedBirthParentRecovery
|
|
990
|
+
? [`${pad}custom uniform token nomos:workspaceEffectAdmission = "VerifiedBirthParentRecovery"`]
|
|
991
|
+
: []),
|
|
989
992
|
...(intent.offerAuthenticationProof === "enrolledDevice"
|
|
990
993
|
? [`${pad}custom uniform token nomos:offerAuthenticationProof = "EnrolledDevice"`]
|
|
991
994
|
: []),
|
package/src/package_config.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
isApplicationHomeGenesis,
|
|
9
9
|
type ApplicationHomeGenesis,
|
|
10
10
|
} from "./application_home_genesis.js";
|
|
11
|
+
import type { WorkspaceRole } from "./births.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* One cohesive, vertically sliced business capability inside a domain.
|
|
@@ -73,6 +74,9 @@ export interface NomosPackageConfig {
|
|
|
73
74
|
* Required for a published application: Nomos never invents a child-workspace allowance. */
|
|
74
75
|
readonly application?: {
|
|
75
76
|
readonly maxChildWorkspacesPerUser: number;
|
|
77
|
+
/** Target-owned roles granted at genesis to the cryptographically verified platform workspace.
|
|
78
|
+
* These are law constants, not caller or host input. */
|
|
79
|
+
readonly parentWorkspaceRoles?: readonly WorkspaceRole[];
|
|
76
80
|
/** Tenant law which must hold from the application's first usable home state. Every entry is
|
|
77
81
|
* an ordinary offer executed through the child's gate; omission declares no tenant ceremony. */
|
|
78
82
|
readonly homeGenesis?: ApplicationHomeGenesis;
|
|
@@ -221,7 +225,18 @@ export function validateNomosPackageConfig(value: unknown): {
|
|
|
221
225
|
) {
|
|
222
226
|
throw new Error(
|
|
223
227
|
"application.homeGenesis must be declared with applicationHomeGenesis(...); " +
|
|
224
|
-
|
|
228
|
+
"Nomos will not reinterpret an untyped genesis recipe",
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
if (
|
|
232
|
+
config.application.parentWorkspaceRoles !== undefined &&
|
|
233
|
+
(!Array.isArray(config.application.parentWorkspaceRoles) ||
|
|
234
|
+
config.application.parentWorkspaceRoles.some(
|
|
235
|
+
(role) => typeof role !== "string" || !/^[A-Za-z][A-Za-z0-9_-]*$/.test(role),
|
|
236
|
+
))
|
|
237
|
+
) {
|
|
238
|
+
throw new Error(
|
|
239
|
+
"application.parentWorkspaceRoles must contain workspaceRole(...) declarations",
|
|
225
240
|
);
|
|
226
241
|
}
|
|
227
242
|
}
|
package/src/read.ts
CHANGED
|
@@ -112,9 +112,9 @@ type ProjectionShape<F extends Record<string, Field>> = {
|
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
114
|
* Decode one framework query's standard projected rows from the SAME aggregate field declarations
|
|
115
|
-
* that authored its law.
|
|
116
|
-
*
|
|
117
|
-
*
|
|
115
|
+
* that authored its law. Every runtime member is obtained from `Field.zod`, so there is no second
|
|
116
|
+
* field-name/type list and no unvalidated object crosses into a framework plan. Historical bool
|
|
117
|
+
* strings are lifted before that one generated schema validates the current projection.
|
|
118
118
|
*
|
|
119
119
|
* Historical captured reads may contain either the current `{ type, id, data }` projection envelope
|
|
120
120
|
* or the earlier flat data row. Both pass through the identical derived schema before being returned.
|
|
@@ -133,18 +133,40 @@ export function readFrameworkDeclaredRows<
|
|
|
133
133
|
);
|
|
134
134
|
}
|
|
135
135
|
const fields: Readonly<Record<string, Field>> = aggregate.fields;
|
|
136
|
-
const shape =
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
136
|
+
const shape: Record<string, z.ZodTypeAny> = {};
|
|
137
|
+
for (const name in fields) {
|
|
138
|
+
const field = fields[name]!;
|
|
139
|
+
const schema = field.zod;
|
|
140
|
+
if (typeof schema?.optional !== "function") {
|
|
141
|
+
throw new Error(
|
|
142
|
+
`framework read('${query.id}') field '${aggregate.id}.${name}' has no executable schema`,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
shape[name] = schema.optional();
|
|
146
|
+
}
|
|
147
|
+
// A workspace is folded under the law carried by each historical intent, while a read is
|
|
148
|
+
// interpreted by the law that is current now. Retired fields therefore remain honest custody
|
|
149
|
+
// evidence but are not members of the current nominal projection. Strip those historical
|
|
150
|
+
// members at this typed boundary; validating them against today's schema would retroactively
|
|
151
|
+
// apply new law to old state and make ordinary evolution impossible.
|
|
152
|
+
const data = z.object(shape as ProjectionShape<StoredFields<F>>).strip() as z.ZodType<ReadModelRow<F>>;
|
|
153
|
+
// Recognize the envelope before validating its data. Known current members remain fully typed;
|
|
154
|
+
// historical members are deliberately outside the current projection above.
|
|
143
155
|
const envelope = z.object({ data: z.unknown() }).passthrough();
|
|
144
156
|
const row = z.union([envelope, z.unknown()])
|
|
145
157
|
.transform((value) => {
|
|
146
158
|
const wrapped = envelope.safeParse(value);
|
|
147
|
-
|
|
159
|
+
const projected = wrapped.success ? wrapped.data.data : value;
|
|
160
|
+
if (projected === null || typeof projected !== "object" || Array.isArray(projected)) {
|
|
161
|
+
return projected;
|
|
162
|
+
}
|
|
163
|
+
const lifted = { ...(projected as Record<string, unknown>) };
|
|
164
|
+
for (const name in fields) {
|
|
165
|
+
if (fields[name]?.kind !== "bool") continue;
|
|
166
|
+
if (lifted[name] === "true") lifted[name] = true;
|
|
167
|
+
else if (lifted[name] === "false") lifted[name] = false;
|
|
168
|
+
}
|
|
169
|
+
return lifted;
|
|
148
170
|
})
|
|
149
171
|
.pipe(data);
|
|
150
172
|
return z.array(row).parse(readFrameworkDeclared(query.id, args));
|
package/src/wire.ts
CHANGED
package/src/wire_encode.ts
CHANGED
|
@@ -229,7 +229,7 @@ function encodeKernelValue(field: Field | undefined, value: unknown, op?: FieldO
|
|
|
229
229
|
// a map's entry value is a leaf scalar.
|
|
230
230
|
if (typeof value === "number" && Number.isInteger(value)) return { Int: value };
|
|
231
231
|
if (typeof value === "string") return { Str: value };
|
|
232
|
-
if (typeof value === "boolean") return {
|
|
232
|
+
if (typeof value === "boolean") return { Bool: value };
|
|
233
233
|
// Enum values are strings; refs are id strings — both handled above.
|
|
234
234
|
// NAMED diagnostic (never `field '?'`): identify the aggregate + field + the shape we got, and — when the
|
|
235
235
|
// field metadata was UNAVAILABLE (a sibling write whose target schema didn't reach the encoder) — say so,
|
|
@@ -249,8 +249,8 @@ function encodeKernelValue(field: Field | undefined, value: unknown, op?: FieldO
|
|
|
249
249
|
const kindLabel = field.kind === "map" ? `map (${field.mapValueKind ?? "?"}-valued)` : field.kind;
|
|
250
250
|
throw new Error(
|
|
251
251
|
`${aggName}.${fieldName} is a '${kindLabel}' field${expected ? ` (value object ${expected})` : ""}, ` +
|
|
252
|
-
`but got ${describeShape(value)} (${JSON.stringify(value)}) — kernel scalars are Str | Int
|
|
253
|
-
`A structured value needs a
|
|
252
|
+
`but got ${describeShape(value)} (${JSON.stringify(value)}) — kernel scalars are Str | Bool | Int. ` +
|
|
253
|
+
`A structured value needs a declared value-object field; a set/map needs its additive write.`,
|
|
254
254
|
);
|
|
255
255
|
}
|
|
256
256
|
|