@githolon/dsl 0.101.3 → 0.101.5
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/package.json +1 -1
- package/src/codegen_proof.ts +26 -17
- package/src/compile_package_main.ts +8 -2
- package/src/zod_lazy.ts +14 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.101.
|
|
3
|
+
"version": "0.101.5",
|
|
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",
|
package/src/codegen_proof.ts
CHANGED
|
@@ -470,14 +470,13 @@ function authorityConformanceLegLines(
|
|
|
470
470
|
` const realFetch2 = globalThis.fetch;`,
|
|
471
471
|
` globalThis.fetch = (() => { throw new Error("OFFLINE PROOF VIOLATED: authority-conformance touched the network"); }) as typeof fetch;`,
|
|
472
472
|
` try {`,
|
|
473
|
-
` // (a) SPY on offerDirective: capture what the generated client passes
|
|
474
|
-
` //
|
|
473
|
+
` // (a) SPY on offerDirective: capture what the generated client passes WITHOUT admitting a synthetic`,
|
|
474
|
+
` // business write, re-encode the v2 envelope, and assert security.actor IS the actor.`,
|
|
475
475
|
` const ACTOR = "user:proof-conformance";`,
|
|
476
476
|
` let captured: { domain: string; directiveId: string; payload: unknown; opts?: { domainHash?: string; actor?: string } } | undefined;`,
|
|
477
|
-
` const realOffer: typeof holon.offerDirective = holon.offerDirective.bind(holon);`,
|
|
478
477
|
` holon.offerDirective = (domain, directiveId, payload, opts) => {`,
|
|
479
478
|
` captured = { domain, directiveId, payload, opts };`,
|
|
480
|
-
` return
|
|
479
|
+
` return Promise.resolve("0000000000000000000000000000000000000000");`,
|
|
481
480
|
` };`,
|
|
482
481
|
` try {`,
|
|
483
482
|
` await ${factory}(holon, { actor: ACTOR }).${leg.directiveId}(${payloadEntries});`,
|
|
@@ -2576,8 +2575,9 @@ export function legsForDomain(
|
|
|
2576
2575
|
* (gaps 1+3, co2 feedback), with its taxonomy (compile-valid | standalone-provable | child-birth-provable).
|
|
2577
2576
|
* A CHILD-ONLY law (no standalone create, installed only via a parent birth) is registered under its OWN
|
|
2578
2577
|
* domain key pointing at the parent birth that proves it. `githolon proof [--domain <key>]` resolves for
|
|
2579
|
-
* every domain. The default is the first
|
|
2580
|
-
*
|
|
2578
|
+
* every domain. The default is the first BUSINESS birth: that is the product surface `proof --live`
|
|
2579
|
+
* promises to exercise even when the same domain also exposes ordinary standalone creates. Otherwise use
|
|
2580
|
+
* the first standalone-provable domain, then the first child-birth-provable, then the first compiled domain. */
|
|
2581
2581
|
export function proofLegsIndex(
|
|
2582
2582
|
modules: readonly DomainModule[],
|
|
2583
2583
|
packageInterface?: Readonly<Record<string, DomainInterface>>,
|
|
@@ -2608,9 +2608,10 @@ export function proofLegsIndex(
|
|
|
2608
2608
|
}
|
|
2609
2609
|
}
|
|
2610
2610
|
if (order.length === 0) return null;
|
|
2611
|
+
const businessBirthFirst = order.find((d) => domains[d]!.childBirth?.businessAggregateId !== undefined);
|
|
2611
2612
|
const standaloneFirst = order.find((d) => (domains[d]!.legs ?? []).includes("standalone-provable"));
|
|
2612
2613
|
const childBirthFirst = order.find((d) => (domains[d]!.legs ?? []).includes("child-birth-provable"));
|
|
2613
|
-
const def = standaloneFirst ?? childBirthFirst ?? order[0]!;
|
|
2614
|
+
const def = businessBirthFirst ?? standaloneFirst ?? childBirthFirst ?? order[0]!;
|
|
2614
2615
|
return { default: def, domains };
|
|
2615
2616
|
}
|
|
2616
2617
|
|
|
@@ -2625,7 +2626,7 @@ function v2IdentityAndCleanupPreamble(opts: TsProofOptions, hashConst: string, n
|
|
|
2625
2626
|
void opts;
|
|
2626
2627
|
void hashConst;
|
|
2627
2628
|
return [
|
|
2628
|
-
`// Nomos prepared
|
|
2629
|
+
`// Nomos prepared an isolated signed application workspace and installed the package before entering generated application code.`,
|
|
2629
2630
|
`// The application proof supplies business facts only; identity/custody/law selection stay underneath.`,
|
|
2630
2631
|
`const fail: (m: string) => never = (m) => { throw new Error(m); };`,
|
|
2631
2632
|
`const ok = (m: string) => console.log("✓ " + m);`,
|
|
@@ -2636,9 +2637,9 @@ function v2IdentityAndCleanupPreamble(opts: TsProofOptions, hashConst: string, n
|
|
|
2636
2637
|
`let runError: unknown = null;`,
|
|
2637
2638
|
`try {`,
|
|
2638
2639
|
``,
|
|
2639
|
-
`// ${n()}. the one managed entry: the logged-in user's durable Nomos home`,
|
|
2640
|
+
`// ${n()}. the one managed entry: an isolated application beneath the logged-in user's durable Nomos home`,
|
|
2640
2641
|
`if (process.env.NOMOS_PROOF_MANAGED !== "1" || !AUTHOR_SECRET) fail("run this cloud proof through: githolon proof --live");`,
|
|
2641
|
-
`ok(\`Nomos
|
|
2642
|
+
`ok(\`Nomos application ready — \${WS}\`);`,
|
|
2642
2643
|
];
|
|
2643
2644
|
}
|
|
2644
2645
|
|
|
@@ -2987,12 +2988,14 @@ function generateBootstrapOnlyProof(
|
|
|
2987
2988
|
}
|
|
2988
2989
|
|
|
2989
2990
|
export function generateTsProof(modules: readonly DomainModule[], opts: TsProofOptions): string {
|
|
2990
|
-
// PRIMARY-DOMAIN SELECTION:
|
|
2991
|
-
// (
|
|
2992
|
-
//
|
|
2993
|
-
//
|
|
2994
|
-
|
|
2995
|
-
|
|
2991
|
+
// PRIMARY-DOMAIN SELECTION: a declared BUSINESS birth is always first because `proof --live` promises the
|
|
2992
|
+
// product's one `app.birth(facts)` surface, not a convenient auxiliary create from the same law. Without
|
|
2993
|
+
// one, drive a STANDALONE ungated create; then a generic `.births()` child; then a bootstrap-provable gated
|
|
2994
|
+
// create. Either way, the marker = the primary domain's FULL legs (so the offline runner + index agree).
|
|
2995
|
+
const hasBusinessBirth = (m: DomainModule): boolean =>
|
|
2996
|
+
(m.directives as Directive<unknown>[]).some(
|
|
2997
|
+
(d) => (d as { businessBirth?: unknown }).businessBirth !== undefined,
|
|
2998
|
+
);
|
|
2996
2999
|
const hasStandaloneCreate = (m: DomainModule): boolean =>
|
|
2997
3000
|
(m.directives as Directive<unknown>[]).some((d) => isStandaloneCreate(d));
|
|
2998
3001
|
const hasBirth = (m: DomainModule): boolean => hasBirthDirective(m);
|
|
@@ -3006,7 +3009,7 @@ export function generateTsProof(modules: readonly DomainModule[], opts: TsProofO
|
|
|
3006
3009
|
}) !== undefined;
|
|
3007
3010
|
} catch { return false; }
|
|
3008
3011
|
};
|
|
3009
|
-
const mod = modules.find(hasStandaloneCreate) ?? modules.find(hasBirth) ?? modules.find(isBootstrapProvable);
|
|
3012
|
+
const mod = modules.find(hasBusinessBirth) ?? modules.find(hasStandaloneCreate) ?? modules.find(hasBirth) ?? modules.find(isBootstrapProvable);
|
|
3010
3013
|
if (mod === undefined) {
|
|
3011
3014
|
// No provable creating write anywhere. If a GATED create exists but its authority can't be seeded, surface
|
|
3012
3015
|
// the loud bootstrap diagnostic (never a false green); else the generic "add a .creates" remedy.
|
|
@@ -3027,6 +3030,12 @@ export function generateTsProof(modules: readonly DomainModule[], opts: TsProofO
|
|
|
3027
3030
|
const primaryLegs = legsForDomain(mod, modules, opts.interface);
|
|
3028
3031
|
const childBirth = primaryLegs.childBirth;
|
|
3029
3032
|
|
|
3033
|
+
// A business-birth domain may also contain `addSite`-style standalone creates. Those are useful secondary
|
|
3034
|
+
// verbs, but they must never steal the live acceptance proof from the one public application birth.
|
|
3035
|
+
if (childBirth?.businessAggregateId !== undefined) {
|
|
3036
|
+
return generateBirthOnlyProof(mod, modules, opts, primaryLegs);
|
|
3037
|
+
}
|
|
3038
|
+
|
|
3030
3039
|
// The standalone-create lane needs an UNGATED create (isStandaloneCreate — never a gated/birth/attestation
|
|
3031
3040
|
// create, which the gate would refuse dispatched with no seeded authority). Absent one, the primary write
|
|
3032
3041
|
// is the birth leg (a `.births()` domain) or the relation-bootstrap leg (a gated-create domain).
|
|
@@ -2365,6 +2365,7 @@ async function main(): Promise<void> {
|
|
|
2365
2365
|
// Exec the bin DIRECTLY (not via `node`): esbuild's postinstall replaces the
|
|
2366
2366
|
// JS shim with the platform-native binary, which only an exec can run.
|
|
2367
2367
|
const esbuildBin = path.join(path.dirname(esbuildPkgJson), esbuildBinRel ?? "bin/esbuild");
|
|
2368
|
+
const esbuildMod = (await import(pathToFileURL(path.join(path.dirname(esbuildPkgJson), "lib", "main.js")).href)) as typeof import("esbuild");
|
|
2368
2369
|
|
|
2369
2370
|
const canonicalizeEngineJavascript = (source: string): string => {
|
|
2370
2371
|
// esbuild includes module labels derived from the package's install topology in
|
|
@@ -2391,7 +2392,6 @@ async function main(): Promise<void> {
|
|
|
2391
2392
|
// package as the binary) so a resolve-plugin can stub zod's locale barrel to en-only —
|
|
2392
2393
|
// the CLI binary has no plugin surface. Same bundle options + minify; deterministic
|
|
2393
2394
|
// (pinned esbuild version, deterministic minifier).
|
|
2394
|
-
const esbuildMod = (await import(pathToFileURL(path.join(path.dirname(esbuildPkgJson), "lib", "main.js")).href)) as typeof import("esbuild");
|
|
2395
2395
|
const localeStripToEn = {
|
|
2396
2396
|
name: "nomos-zod-locales-en-only",
|
|
2397
2397
|
setup(build: import("esbuild").PluginBuild) {
|
|
@@ -2778,7 +2778,13 @@ async function main(): Promise<void> {
|
|
|
2778
2778
|
// ── 5. the typed TS client (#10 — the web sibling of codegen_dart), with the
|
|
2779
2779
|
// deployed law's content hash baked in (emitted AFTER the package is hashed) ──
|
|
2780
2780
|
const clientPath = path.join(outDir, `${cfg.name}.client.ts`);
|
|
2781
|
-
|
|
2781
|
+
const clientSource = generateTsClient(presentationDomainModules, { packageName: cfg.name, domainHash, interface: packageInterface, compat: nomosCompat });
|
|
2782
|
+
try {
|
|
2783
|
+
await esbuildMod.transform(clientSource, { loader: "ts", format: "esm", target: "es2020", logLevel: "silent" });
|
|
2784
|
+
} catch (e) {
|
|
2785
|
+
fail(`generated TypeScript client is not syntactically valid — this is a Nomos codegen bug: ${(e as Error).message}`);
|
|
2786
|
+
}
|
|
2787
|
+
writeFileSync(clientPath, clientSource, "utf8");
|
|
2782
2788
|
|
|
2783
2789
|
// ── 6. the typed Dart frontend (opt-in; the Flutter sibling of step 5, emitted
|
|
2784
2790
|
// after the package hash like the TS client) ──
|
package/src/zod_lazy.ts
CHANGED
|
@@ -26,12 +26,22 @@ export function zodUnwrapLazy(zt: z.ZodTypeAny): z.ZodTypeAny {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const capFirst = (s: string): string => (s.length === 0 ? s : s[0]!.toUpperCase() + s.slice(1));
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
/** Turn one structural path component into a valid TS/Dart identifier component.
|
|
31
|
+
* `*` is the record-value marker, not tenant vocabulary, so name it `Value`. */
|
|
32
|
+
function typeNamePart(segment: string): string {
|
|
33
|
+
if (segment === "*") return "Value";
|
|
34
|
+
const words = segment.split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
35
|
+
const joined = words.map(capFirst).join("") || "Field";
|
|
36
|
+
return /^[A-Za-z]/.test(joined) ? joined : `N${joined}`;
|
|
37
|
+
}
|
|
30
38
|
|
|
31
39
|
/**
|
|
32
40
|
* A PascalCase type name from a payload path (`saveTree.root` → `SaveTreeRoot`), array markers
|
|
33
|
-
* dropped
|
|
34
|
-
* TS
|
|
41
|
+
* dropped and record wildcards named `Value` (`saveJson.data.*` → `SaveJsonDataValue`). The SAME
|
|
42
|
+
* base the TS and Dart recursive-type synthesizers use so a recursive type's TS alias and Dart
|
|
43
|
+
* class agree in the common case. Every segment is sanitized here because schema object keys may
|
|
44
|
+
* contain punctuation even though generated language identifiers may not.
|
|
35
45
|
*/
|
|
36
46
|
export function recursiveTypeBaseName(path: string): string {
|
|
37
47
|
return (
|
|
@@ -39,7 +49,7 @@ export function recursiveTypeBaseName(path: string): string {
|
|
|
39
49
|
.replace(/\[\]/g, "")
|
|
40
50
|
.split(/[.]/)
|
|
41
51
|
.filter(Boolean)
|
|
42
|
-
.map(
|
|
52
|
+
.map(typeNamePart)
|
|
43
53
|
.join("") || "Recursive"
|
|
44
54
|
);
|
|
45
55
|
}
|