@githolon/dsl 0.103.11 → 0.103.13
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/runner/node-entry.mjs +234 -170
- package/dart/lib/src/runner/offline-install.mjs +111 -123
- package/dart/lib/src/webview_bridge.dart +11 -11
- package/dart/pubspec.yaml +1 -1
- package/dart/test/webview_bridge_test.dart +10 -7
- package/dart_types/CHANGELOG.md +1 -1
- package/dart_types/lib/nomos_types.dart +4 -4
- package/dart_types/lib/src/versioned_nomos_ref.dart +13 -11
- package/package.json +1 -1
- package/runtime/generated-application-host.js +424 -237
- package/src/aggregate.ts +3 -1
- package/src/build_package.ts +77 -6
- package/src/check_package_main.ts +39 -16
- package/src/codegen_dart.ts +185 -48
- package/src/codegen_dart_application.ts +82 -16
- package/src/codegen_dart_client.ts +38 -10
- package/src/codegen_dot.ts +3 -3
- package/src/codegen_proof.ts +24 -2
- package/src/codegen_ts.ts +32 -19
- package/src/compile_package_main.ts +68 -11
- package/src/derived.ts +17 -0
- package/src/directive.ts +65 -0
- package/src/engine_entry.ts +22 -2
- package/src/enum_type.ts +71 -0
- package/src/fields.ts +135 -5
- package/src/flow_gate.ts +2 -1
- package/src/framework/workspaces.ts +73 -0
- package/src/idof_lint.ts +5 -1
- package/src/index.ts +20 -0
- package/src/kernel_capabilities.ts +12 -1
- package/src/law_check.ts +107 -28
- package/src/law_graph.ts +151 -20
- package/src/law_graph_usda.ts +23 -0
- package/src/law_value_type.ts +10 -3
- package/src/lsp_server.ts +26 -16
- package/src/package_config.ts +112 -9
- package/src/package_feature_topology.ts +174 -0
- package/src/plan_source_slice.ts +6 -0
- package/src/report.ts +6 -0
- package/src/stable_ids_for_module.ts +1 -0
- package/src/value_object.ts +9 -2
- package/src/workspace_sharding.ts +4 -4
package/src/aggregate.ts
CHANGED
|
@@ -196,6 +196,8 @@ export interface AggregateHandle<
|
|
|
196
196
|
readonly hasMany: HasManyFields<F>;
|
|
197
197
|
/** Brand so a plain string is never accepted where a handle is required. */
|
|
198
198
|
readonly __isAggregateHandle: true;
|
|
199
|
+
/** Name-only dependency handle. Export-safe, but never itself discoverable as domain law. */
|
|
200
|
+
readonly __isForwardRef?: true;
|
|
199
201
|
/** DOMAIN CONTRACTS this aggregate `.implements(...)` — the stable public shapes it satisfies (compile-
|
|
200
202
|
* checked). Codegen marks the aggregate as implementing them so cross-domain refs can target the CONTRACT
|
|
201
203
|
* instead of this concrete type. Additive metadata (not hashed law). OMITTED when it implements none. */
|
|
@@ -730,5 +732,5 @@ export function instance<Id extends string, F extends Record<string, Field>>(
|
|
|
730
732
|
* and every forward ref keeps compiling for free.
|
|
731
733
|
*/
|
|
732
734
|
export function forwardRef<const Id extends string>(id: Id): AggregateHandle<Id, Record<string, never>> {
|
|
733
|
-
return { id, fields: {}, hasMany: {}, __isAggregateHandle: true };
|
|
735
|
+
return { id, fields: {}, hasMany: {}, __isAggregateHandle: true, __isForwardRef: true };
|
|
734
736
|
}
|
package/src/build_package.ts
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* removed so tenant tooling cannot accidentally create a second law representation.
|
|
25
25
|
*/
|
|
26
26
|
import { createHash } from "node:crypto";
|
|
27
|
+
import { z } from "zod";
|
|
27
28
|
|
|
28
29
|
import type { AggregateHandle } from "./aggregate.js";
|
|
29
30
|
import type { Directive } from "./directive.js";
|
|
@@ -33,7 +34,7 @@ import type { QueryDecl } from "./query.js";
|
|
|
33
34
|
import type { SpatialDecl } from "./spatial.js";
|
|
34
35
|
import type { AnySum } from "./sum.js";
|
|
35
36
|
import type { AnyExtremum } from "./extremum.js";
|
|
36
|
-
import type { DerivedDecl } from "./derived.js";
|
|
37
|
+
import type { AnyDerivedDecl, DerivedDecl, TemporalEnumDecl } from "./derived.js";
|
|
37
38
|
import type { CombinedDecl } from "./combined.js";
|
|
38
39
|
import type { ImpureCapabilityDecl } from "./codegen_provider_dart.js";
|
|
39
40
|
import type { WorkspaceTypeDecl } from "./workspace_type.js";
|
|
@@ -68,7 +69,7 @@ import {
|
|
|
68
69
|
type RelationTypeDecl,
|
|
69
70
|
} from "./relation_schema.js";
|
|
70
71
|
import { collectValueObjectDescriptors } from "./value_object.js";
|
|
71
|
-
import { expandCapabilityExports } from "./capability_exports.js";
|
|
72
|
+
import { expandCapabilityExports, isCapabilityDecl } from "./capability_exports.js";
|
|
72
73
|
import { RelationTuple, relationTuplesByObject } from "./framework/relations.js";
|
|
73
74
|
import { signerDelegationByUser } from "./framework/signing_identity.js";
|
|
74
75
|
import { AuthProvider, setAuthProvider, authProvider } from "./framework/workspaces.js";
|
|
@@ -111,7 +112,8 @@ export function aggregatesOf(mod: Mod): AggregateHandle[] {
|
|
|
111
112
|
if (
|
|
112
113
|
v &&
|
|
113
114
|
typeof v === "object" &&
|
|
114
|
-
(v as { __isAggregateHandle?: boolean }).__isAggregateHandle === true
|
|
115
|
+
(v as { __isAggregateHandle?: boolean }).__isAggregateHandle === true &&
|
|
116
|
+
(v as { __isForwardRef?: boolean }).__isForwardRef !== true
|
|
115
117
|
) {
|
|
116
118
|
out.push(v as AggregateHandle);
|
|
117
119
|
}
|
|
@@ -215,6 +217,17 @@ export function composeDomainModule(spec: DomainModuleSpec): DomainModule {
|
|
|
215
217
|
// `capability()` bundles expand into discoverable entries (the package plane's
|
|
216
218
|
// merge point) — the quartet validation below then passes without re-exports.
|
|
217
219
|
merged = expandCapabilityExports(merged);
|
|
220
|
+
const capabilityByAggregate = new Map<string, ImpureCapabilityDecl>();
|
|
221
|
+
for (const value of Object.values(merged)) {
|
|
222
|
+
if (isCapabilityDecl(value)) {
|
|
223
|
+
const capability = value as unknown as ImpureCapabilityDecl;
|
|
224
|
+
capabilityByAggregate.set(capability.aggregate.id, capability);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
for (const capability of spec.impureCapabilities ?? []) {
|
|
228
|
+
capabilityByAggregate.set(capability.aggregate.id, capability);
|
|
229
|
+
}
|
|
230
|
+
const declaredCapabilities = [...capabilityByAggregate.values()];
|
|
218
231
|
// METERED BIRTH: inject the sanctioning `nomosBirthRecordEnsure` directive + meter aggregates
|
|
219
232
|
// into a `.births()`-declaring domain at the SAME seam the engine merge applies it — the
|
|
220
233
|
// Ensure→NomosBirthRecord manifest declaration is what admits the auto-appended record through
|
|
@@ -272,6 +285,27 @@ export function composeDomainModule(spec: DomainModuleSpec): DomainModule {
|
|
|
272
285
|
: executableDirectivesForLanguage(applicationLanguage, discoveredDirectives, domain),
|
|
273
286
|
conflictPolicies,
|
|
274
287
|
);
|
|
288
|
+
// A business intent may direct a capability obligation as one private,
|
|
289
|
+
// atomic consequence. Language closure deliberately removes private effect
|
|
290
|
+
// directives from the application write surface; capability lifecycle law is
|
|
291
|
+
// different: the task declaration must retain its complete quartet so the
|
|
292
|
+
// kernel can seal the obligation and later judge provider receipts. Re-seat
|
|
293
|
+
// those exact framework-derived directives after closure. Generated tenant
|
|
294
|
+
// clients still expose only the declared language intents.
|
|
295
|
+
for (const capability of declaredCapabilities) {
|
|
296
|
+
const lifecycleDirectives = [
|
|
297
|
+
capability.obligation,
|
|
298
|
+
capability.complete,
|
|
299
|
+
capability.fail,
|
|
300
|
+
capability.block,
|
|
301
|
+
capability.deadLetter,
|
|
302
|
+
] as unknown as Directive<any>[];
|
|
303
|
+
for (const directive of lifecycleDirectives) {
|
|
304
|
+
if (!directives.some((candidate) => candidate.id === directive.id)) {
|
|
305
|
+
directives.push(directive);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
275
309
|
// Invitations are ordinary, replayed law hidden behind the generated application. Each sharing
|
|
276
310
|
// policy contributes one possession-proof redemption directive; it is injected after the tenant
|
|
277
311
|
// language has been closed so it cannot become a second public lane.
|
|
@@ -492,7 +526,7 @@ export function composeDomainModule(spec: DomainModuleSpec): DomainModule {
|
|
|
492
526
|
domain,
|
|
493
527
|
);
|
|
494
528
|
const directiveIds = new Set(directives.map((d) => d.id));
|
|
495
|
-
for (const task of
|
|
529
|
+
for (const task of declaredCapabilities) {
|
|
496
530
|
for (const directive of [task.obligation, task.complete, task.fail, task.block, task.deadLetter]) {
|
|
497
531
|
if (!directiveIds.has(directive.id)) {
|
|
498
532
|
throw new Error(
|
|
@@ -516,9 +550,46 @@ export function composeDomainModule(spec: DomainModuleSpec): DomainModule {
|
|
|
516
550
|
}
|
|
517
551
|
const counts = [...(spec.counts ?? [])];
|
|
518
552
|
const spatials = [...(spec.spatials ?? [])];
|
|
519
|
-
const
|
|
553
|
+
const temporalEnums: TemporalEnumDecl[] = aggregates.flatMap((aggregate) =>
|
|
554
|
+
Object.entries(aggregate.fields).flatMap(([sourceField, field]) =>
|
|
555
|
+
(field.temporalEnums ?? []).map((declaration) => {
|
|
556
|
+
if (field.isTimestamp !== true) {
|
|
557
|
+
throw new Error(
|
|
558
|
+
`domain '${domain}' temporal enum '${declaration.id}' targets ${aggregate.id}.${sourceField}, ` +
|
|
559
|
+
"which is not a t.timestamp() field",
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
const values = [
|
|
563
|
+
declaration.missing,
|
|
564
|
+
declaration.initial,
|
|
565
|
+
...declaration.transitions.map((transition) => transition.value),
|
|
566
|
+
] as [string, ...string[]];
|
|
567
|
+
return {
|
|
568
|
+
kind: "temporalEnum" as const,
|
|
569
|
+
id: declaration.id,
|
|
570
|
+
of: aggregate.id,
|
|
571
|
+
sourceField,
|
|
572
|
+
missing: declaration.missing,
|
|
573
|
+
initial: declaration.initial,
|
|
574
|
+
transitions: declaration.transitions,
|
|
575
|
+
returns: z.enum(values),
|
|
576
|
+
};
|
|
577
|
+
}),
|
|
578
|
+
),
|
|
579
|
+
);
|
|
580
|
+
const derivedById = new Map<string, AnyDerivedDecl>();
|
|
581
|
+
for (const declaration of [...(spec.deriveds ?? []), ...temporalEnums]) {
|
|
582
|
+
const existing = derivedById.get(declaration.id);
|
|
583
|
+
if (existing !== undefined) {
|
|
584
|
+
throw new Error(
|
|
585
|
+
`domain '${domain}' declares read '${declaration.id}' more than once; temporal and generic derived reads share one namespace`,
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
derivedById.set(declaration.id, declaration);
|
|
589
|
+
}
|
|
590
|
+
const deriveds = [...derivedById.values()];
|
|
520
591
|
const combineds = [...(spec.combineds ?? [])];
|
|
521
|
-
const impureCapabilities =
|
|
592
|
+
const impureCapabilities = declaredCapabilities;
|
|
522
593
|
const sums = [...(spec.sums ?? [])];
|
|
523
594
|
const mins = [...(spec.mins ?? [])];
|
|
524
595
|
const maxes = [...(spec.maxes ?? [])];
|
|
@@ -16,6 +16,7 @@ import { pathToFileURL } from "node:url";
|
|
|
16
16
|
|
|
17
17
|
import { composeDomainModule, type Mod } from "./build_package.js";
|
|
18
18
|
import type { DomainModule } from "./codegen_dart.js";
|
|
19
|
+
import { bindEnumTypeExports } from "./enum_type.js";
|
|
19
20
|
import { checkDomainModules, formatFindings, hasRefusal, type Finding } from "./law_check.js";
|
|
20
21
|
import { LawSourceMap } from "./law_source_map.js";
|
|
21
22
|
import {
|
|
@@ -29,17 +30,18 @@ import {
|
|
|
29
30
|
import { parseStableIdLockfile } from "./stable_id_lockfile.js";
|
|
30
31
|
import {
|
|
31
32
|
validateNomosPackageConfig,
|
|
32
|
-
type
|
|
33
|
+
type NormalizedNomosPackageConfig,
|
|
34
|
+
type NormalizedNomosPackageDomainConfig,
|
|
33
35
|
} from "./package_config.js";
|
|
34
36
|
import { assertPublicPackageImports } from "./package_source_imports.js";
|
|
37
|
+
import {
|
|
38
|
+
assertPackageFeatureTopology,
|
|
39
|
+
packageFeatureTopologyFindings,
|
|
40
|
+
} from "./package_feature_topology.js";
|
|
35
41
|
import { packageDependencyUsageFindings } from "./package_dependency_usage.js";
|
|
36
42
|
|
|
37
|
-
interface DomainConfig {
|
|
38
|
-
|
|
39
|
-
name?: string;
|
|
40
|
-
modules: string[];
|
|
41
|
-
}
|
|
42
|
-
interface PackageConfig extends NomosPackageConfig {
|
|
43
|
+
interface DomainConfig extends NormalizedNomosPackageDomainConfig {}
|
|
44
|
+
interface PackageConfig extends NormalizedNomosPackageConfig {
|
|
43
45
|
readonly domains: readonly DomainConfig[];
|
|
44
46
|
}
|
|
45
47
|
|
|
@@ -87,6 +89,15 @@ export async function loadComposedModulesWithSources(
|
|
|
87
89
|
}
|
|
88
90
|
const composed: DomainModule[] = [];
|
|
89
91
|
const domainFiles = new Map<string, string[]>();
|
|
92
|
+
let sourceTopologyFindings: readonly Finding[] = [];
|
|
93
|
+
try {
|
|
94
|
+
sourceTopologyFindings = packageFeatureTopologyFindings(
|
|
95
|
+
assertPackageFeatureTopology(cfg.domains, cfgDir),
|
|
96
|
+
cfgDir,
|
|
97
|
+
);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
fail(`package feature topology refused: ${(error as Error).message}`);
|
|
100
|
+
}
|
|
90
101
|
for (const d of cfg.domains) {
|
|
91
102
|
const mods: Mod[] = [];
|
|
92
103
|
const files: string[] = [];
|
|
@@ -102,7 +113,9 @@ export async function loadComposedModulesWithSources(
|
|
|
102
113
|
}
|
|
103
114
|
for (const abs of files) {
|
|
104
115
|
// Cache-bust so a re-import (the LSP re-check after an edit) re-evaluates the edited module.
|
|
105
|
-
|
|
116
|
+
const mod = (await import(`${pathToFileURL(abs).href}?t=${Date.now()}`)) as Mod;
|
|
117
|
+
bindEnumTypeExports(mod, abs);
|
|
118
|
+
mods.push(mod);
|
|
106
119
|
}
|
|
107
120
|
domainFiles.set(d.key, files);
|
|
108
121
|
composed.push(composeDomainModule({ name: d.name ?? d.key, domain: d.key, modules: mods }));
|
|
@@ -110,12 +123,15 @@ export async function loadComposedModulesWithSources(
|
|
|
110
123
|
return {
|
|
111
124
|
modules: composed,
|
|
112
125
|
domainFiles,
|
|
113
|
-
dependencyFindings:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
126
|
+
dependencyFindings: [
|
|
127
|
+
...sourceTopologyFindings,
|
|
128
|
+
...packageDependencyUsageFindings({
|
|
129
|
+
packageName: cfg.name,
|
|
130
|
+
exportedDomains: cfg.domains.map((domain) => domain.key),
|
|
131
|
+
runtimeDependencies,
|
|
132
|
+
modules: composed,
|
|
133
|
+
}),
|
|
134
|
+
],
|
|
119
135
|
};
|
|
120
136
|
}
|
|
121
137
|
|
|
@@ -240,14 +256,21 @@ async function main(): Promise<void> {
|
|
|
240
256
|
if (asJson) {
|
|
241
257
|
const srcMap = new LawSourceMap(domainFiles);
|
|
242
258
|
const out = findings.map((f) => {
|
|
243
|
-
const loc = srcMap.locate(f.domain, f.directiveId);
|
|
259
|
+
const loc = f.source ?? srcMap.locate(f.domain, f.directiveId);
|
|
244
260
|
return {
|
|
245
261
|
domain: f.domain,
|
|
246
262
|
...(f.directiveId !== undefined ? { directiveId: f.directiveId } : {}),
|
|
247
263
|
level: f.level,
|
|
248
264
|
what: f.what,
|
|
249
265
|
fix: f.fix,
|
|
250
|
-
...(loc !== undefined
|
|
266
|
+
...(loc !== undefined
|
|
267
|
+
? {
|
|
268
|
+
file: loc.file,
|
|
269
|
+
line: loc.line,
|
|
270
|
+
column: loc.column,
|
|
271
|
+
...("fallback" in loc ? { fallback: loc.fallback } : {}),
|
|
272
|
+
}
|
|
273
|
+
: {}),
|
|
251
274
|
};
|
|
252
275
|
});
|
|
253
276
|
process.stdout.write(JSON.stringify(out) + "\n");
|