@githolon/dsl 0.1.2 → 0.1.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/LICENSE.md CHANGED
@@ -24,6 +24,15 @@ with it; we keep the rest for now.
24
24
  - offer the Nomos runtime, or anything materially similar, as a hosted service;
25
25
  - reverse-engineer the holon wasm runtime.
26
26
 
27
+ ## Data retention
28
+
29
+ This is a pre-release we are actively evaluating. Workspaces you retire stop
30
+ counting toward your quota but are NOT deleted: **we retain all workspace data
31
+ (ledgers, law, intents) and may examine it to evaluate how the product is
32
+ used.** Don't put anything in a pre-release workspace you wouldn't want the
33
+ builders to read. If you need something truly expunged, ask:
34
+ jack@captainapp.co.uk.
35
+
27
36
  ## The rest
28
37
 
29
38
  Provided **as is**, with no warranty of any kind; to the maximum extent
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.1.2",
3
+ "version": "0.1.6",
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_ts.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  * TS CLIENT CODEGEN (#10) — the WEB sibling of `codegen_dart.ts`.
10
10
  *
11
11
  * Dart apps get generated payload classes / read models / typed query accessors;
12
- * until this file, a web app on `githolonent` hand-typed directive ids and
12
+ * until this file, a web app on `@githolon/client` hand-typed directive ids and
13
13
  * payload shapes against the raw `dispatch()` surface. `generateTsClient(modules,
14
14
  * opts)` closes that: ONE generated `.ts` file per package, emitted by
15
15
  * `nomos-compile` AFTER the package is hashed (the deployed law's content hash is
@@ -27,7 +27,7 @@
27
27
  * * a CLIENT FACTORY per domain — typed `dispatch` wrappers bound to the baked
28
28
  * domainHash, typed declared-query accessors, and by-id read/watch helpers —
29
29
  * over a STRUCTURAL `NomosHolon` interface, so the file has ZERO imports and
30
- * binds to `githolonent`'s `connect()` result (browser or node) as-is.
30
+ * binds to `@githolon/client`'s `connect()` result (browser or node) as-is.
31
31
  *
32
32
  * Like every emitter here: NO FALLBACK. An unsupported zod shape throws at compile
33
33
  * time, never degrades to `any` silently.
@@ -219,9 +219,9 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
219
219
  out.push(
220
220
  `// AUTO-GENERATED by nomos-compile — typed TS client for package "${opts.packageName}".`,
221
221
  `// Regenerated on every compile; do not edit. Zero imports: bind it to any holon`,
222
- `// exposing the githolonent surface (the structural NomosHolon below), e.g.`,
222
+ `// exposing the @githolon/client surface (the structural NomosHolon below), e.g.`,
223
223
  `//`,
224
- `// import { connect } from "githolonent";`,
224
+ `// import { connect } from "@githolon/client";`,
225
225
  `// import { ${lcFirst(camel(modules[0]?.domain ?? "domain"))}Client } from "./build/${opts.packageName}.client.js";`,
226
226
  `// const holon = await connect({ cloud, workspace, clientId });`,
227
227
  `// const app = ${lcFirst(camel(modules[0]?.domain ?? "domain"))}Client(holon);`,
@@ -232,7 +232,7 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
232
232
  `/** One projection row: the aggregate's wire type, its id, and the folded fields. */`,
233
233
  `export interface Row<T> { type: string; id: string; data: T }`,
234
234
  ``,
235
- `/** The holon surface this client binds to (structurally satisfied by githolonent). */`,
235
+ `/** The holon surface this client binds to (structurally satisfied by @githolon/client). */`,
236
236
  `export interface NomosHolon {`,
237
237
  ` dispatch(domain: string, directiveId: string, payload: unknown, opts: { domainHash: string }): Promise<string>;`,
238
238
  ` query(queryId: string, params?: Record<string, unknown>): Promise<unknown>;`,
@@ -442,7 +442,24 @@ async function main(): Promise<void> {
442
442
  const { manifestsPath } = writeIdentity(identity, outDir);
443
443
 
444
444
  // ── 4. the one-call deploy body (package + per-workspace manifest overlay) ──
445
+ // SELF-DESCRIBING: `summary` states what the (otherwise hex-opaque) package
446
+ // contains — purely derived from the inputs (no timestamps), ignored by the
447
+ // deploy endpoint, and mirrored as build/<name>.summary.txt for a human or
448
+ // agent who simply cats the build output.
449
+ const summary = {
450
+ package: cfg.name,
451
+ domainHash,
452
+ domains: domainModules.map((m) => ({
453
+ domain: m.domain ?? m.name,
454
+ aggregates: m.aggregates.map((a) => a.id),
455
+ directives: m.directives.map((d) => d.id),
456
+ queries: (m.queries ?? []).map((q) => q.id),
457
+ counts: (m.counts ?? []).map((c) => c.id),
458
+ identityHash: identity.hashes[m.domain ?? m.name],
459
+ })),
460
+ };
445
461
  const deployBody = {
462
+ summary,
446
463
  packageUsda: text,
447
464
  readManifest,
448
465
  identityManifests: identity.manifests,
@@ -450,6 +467,20 @@ async function main(): Promise<void> {
450
467
  };
451
468
  const deployPath = path.join(outDir, `${cfg.name}.deploy.json`);
452
469
  writeFileSync(deployPath, JSON.stringify(deployBody) + "\n", "utf8");
470
+ const summaryTxt = [
471
+ `${cfg.name} — compiled Nomos domain package`,
472
+ `law (domainHash): ${domainHash} # sha256(${cfg.name}.package.usda) — content-addressed`,
473
+ ...summary.domains.flatMap((d) => [
474
+ `domain '${d.domain}'${d.identityHash ? ` (identity ${d.identityHash.slice(0, 12)}…)` : " (EXCLUDED from identity manifest)"}`,
475
+ ` aggregates: ${d.aggregates.join(", ") || "—"}`,
476
+ ` directives: ${d.directives.join(", ") || "—"}`,
477
+ ` queries: ${d.queries.join(", ") || "—"} counts: ${d.counts.join(", ") || "—"}`,
478
+ ]),
479
+ `deploy: POST ${cfg.name}.deploy.json to /v1/workspaces/<ws>/domains (or: githolon deploy <ws>)`,
480
+ `typed client: ${cfg.name}.client.ts — ${cfg.name}Client(holon), law hash baked in`,
481
+ ``,
482
+ ].join("\n");
483
+ writeFileSync(path.join(outDir, `${cfg.name}.summary.txt`), summaryTxt, "utf8");
453
484
 
454
485
  // ── 5. the typed TS client (#10 — the web sibling of codegen_dart), with the
455
486
  // deployed law's content hash baked in (emitted AFTER the package is hashed) ──
@@ -488,9 +519,10 @@ async function main(): Promise<void> {
488
519
  console.log(` deploy ${rel(deployPath)}`);
489
520
  console.log(``);
490
521
  console.log(`deploy (Nomos Cloud):`);
491
- console.log(` curl -X POST -H 'content-type: application/json' \\`);
492
- console.log(` --data-binary @${rel(deployPath)} \\`);
493
- console.log(` https://nomos.captainapp.co.uk/v1/workspaces/<ws>/domains`);
522
+ console.log(` githolon ws create <ws> && githolon deploy <ws> # the secret is saved + sent for you`);
523
+ console.log(` # raw lane: curl -X POST -H 'content-type: application/json' -H 'Authorization: Bearer <workspaceSecret>' \\`);
524
+ console.log(` # --data-binary @${rel(deployPath)} https://nomos.captainapp.co.uk/v1/workspaces/<ws>/domains`);
525
+ console.log(`prove it: npm run e2e # offline write -> sync -> admission -> cloud query, live`);
494
526
  }
495
527
 
496
528
  await main();
package/src/ops.ts CHANGED
@@ -93,11 +93,32 @@ function addressOf(agg: Target): { aggregateId: string; aggregateType?: string }
93
93
  return { aggregateId: (agg as AggregateHandle).id };
94
94
  }
95
95
 
96
- /** Set a scalar field. Field name + value type are both checked. */
96
+ /**
97
+ * Set a scalar (or map-whole/ref) field. Field name + value type are both checked.
98
+ *
99
+ * REFUSES set-kind fields — at the TYPE level (the parameter collapses to an
100
+ * instructive error string) AND at runtime (so the sealed engine refuses non-TS
101
+ * callers too): `set()` on an AddWins set would OVERWRITE the merge — concurrent
102
+ * adds would silently lose. The additive write is {@link addToSet}.
103
+ */
97
104
  export function set<
98
105
  A extends Target,
99
106
  K extends keyof Fields<A> & string,
100
- >(agg: A, field: K, value: FieldValue<Fields<A>[K]>): FieldOp {
107
+ >(
108
+ agg: A,
109
+ field: K &
110
+ (Fields<A>[K] extends { kind: "set" }
111
+ ? `TYPE ERROR: '${K}' is a set field — set() would OVERWRITE the merge; use addToSet(handle, "${K}", values)`
112
+ : K),
113
+ value: FieldValue<Fields<A>[K]>,
114
+ ): FieldOp {
115
+ const f = (agg as { fields?: Record<string, { kind?: string }> }).fields?.[field];
116
+ if (f?.kind === "set") {
117
+ throw new Error(
118
+ `set('${field}'): '${field}' is a set field — set() would OVERWRITE the merge ` +
119
+ `(concurrent adds would be lost). Use addToSet(handle, '${field}', values) — the additive write.`,
120
+ );
121
+ }
101
122
  return { ...addressOf(agg), field, kind: "set", value };
102
123
  }
103
124