@githolon/dsl 0.65.0 → 0.65.1

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 CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.43.0
2
+
3
+ - `NomosBridge.foreignReader({cloud})` — a `NomosForeignReader` backed by the device's multi-workspace bridge
4
+ plane, so a generated `ForeignRef` (`t.foreignRef`) resolves against real data: it mounts the foreign
5
+ workspace on demand (`connect(session: ws, allowUnborn: true)`, idempotent) and reads it
6
+ (`session(ws).queryById(id)`); `watch` re-reads on each sync tick. A locator resolver, not a foreign key —
7
+ the foreign holon is mounted only when you resolve. Requires `nomos_types >= 0.1.1` (the `ForeignRef` types).
8
+
1
9
  ## 0.41.0
2
10
  - `NomosTestHarness` emits named phase-progress diagnostics (install → spawn runner → await ready → connect, plus per-session progress in `cluster`) and each `connect()` carries a `connectTimeout` (default 120s) that throws a NAMED remedy instead of hanging — so a multi-test AppSim run can tell install vs runner-wait vs session-block vs deadlock (co2 feedback).
3
11
 
package/dart/pubspec.yaml CHANGED
@@ -11,7 +11,7 @@ description: >-
11
11
  Nomos 2 Dart frontend types — the hand-written kernel wire types plus the
12
12
  code-generated per-domain aggregate + directive-payload types. (De)serializes
13
13
  the EXACT serde JSON the Rust kernel + projection produce/consume.
14
- version: 0.41.0
14
+ version: 0.43.0
15
15
 
16
16
  environment:
17
17
  sdk: ^3.5.0
@@ -20,7 +20,7 @@ dependencies:
20
20
  # The pure-data core (wire types, offer codec, NomosReads, schema validation, error
21
21
  # info). nomos_client depends on and re-exports it, so existing imports are unchanged.
22
22
  # For local monorepo dev, pubspec_overrides.yaml points this at ../dart_types.
23
- nomos_types: ^0.1.0
23
+ nomos_types: ^0.1.1
24
24
  json_schema: ^5.2.2
25
25
  crypto: ^3.0.0
26
26
 
@@ -1,3 +1,11 @@
1
+ ## 0.1.1
2
+
3
+ - Add `t.foreignRef` runtime types: `ForeignRef<T>` (a typed cross-workspace locator), `NomosForeignReader` /
4
+ `NomosForeignWorkspaceReader`, the sealed `ForeignResolveResult<T>` (`ForeignFound`/`ForeignNotFound`/
5
+ `ForeignDenied`/`ForeignUnreachable`), and `ForeignAttestation`. Generated read models type a `foreignRef`
6
+ field as `ForeignRef<Target>`; `.resolve/.resolveResult/.watch/.exists` are the informational lookup,
7
+ `.attest` is gated on the attested-read lane. Purely additive.
8
+
1
9
  ## 0.1.0
2
10
  - Initial release. The pure-data core split out of `nomos_client`: kernel wire types,
3
11
  the offer codec, `NomosReads`, the tri-state `NomosSlot`, aggregate metadata, schema
@@ -11,7 +11,7 @@ description: >-
11
11
  Pure kernel wire/data types for Nomos Dart frontends — no transport, no bridge,
12
12
  no runtime. The hand-written serde-JSON-compatible types plus the offer codec,
13
13
  reactive read engine, schema validation, and data-only error/trace types.
14
- version: 0.1.0
14
+ version: 0.1.1
15
15
 
16
16
  environment:
17
17
  sdk: ^3.5.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.65.0",
3
+ "version": "0.65.1",
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",
@@ -674,6 +674,15 @@ function emitDart(
674
674
  writeGenerated(FRAMEWORK_FILE, generateDartDomain(shared.frameworkMod));
675
675
  }
676
676
 
677
+ // CROSS-DOMAIN `t.foreignRef` (auto import). A foreignRef field typed `ForeignRef<CatalogueListing>` +
678
+ // `CatalogueListing.fromJson` needs the TARGET aggregate's Dart class — which lives in the target DOMAIN's
679
+ // generated file. Within ONE package the compiler knows which domain owns each aggregate, so we auto-emit
680
+ // the import (no manual `dartImports` config). Map every aggregate id → its domain's generated file base.
681
+ const aggIdToDartFile = new Map<string, string>();
682
+ for (const m of modules) {
683
+ for (const agg of (m.aggregates as { id: string }[])) aggIdToDartFile.set(agg.id, m.name);
684
+ }
685
+
677
686
  // 2b. one generated file per composed domain — the TYPES (`<name>.dart`) + the async bridge
678
687
  // CLIENT (`<name>.client.dart`, the Flutter sibling of `<name>.client.ts`).
679
688
  for (const mod of modules) {
@@ -684,7 +693,28 @@ function emitDart(
684
693
  // framework import. Only pass the import when this domain actually folds a framework symbol.
685
694
  const { modForDart, skips, foldsFramework } = domainDedupOpts(mod, shared);
686
695
  const domainFrameworkImport = foldsFramework ? frameworkImportUri : undefined;
687
- const src = generateDartDomain(modForDart, {
696
+ // AUTO cross-domain foreignRef imports: for each foreignRef whose target aggregate lives in ANOTHER
697
+ // tenant domain, import that domain's generated file so `ForeignRef<Target>` + `Target.fromJson` resolve.
698
+ // A target that is framework-shared resolves via the frameworkImportUri (not in the tenant map), so it is
699
+ // skipped here. Merged with any manual `dartImports`; deduped by uri.
700
+ const foreignRefImportUris = new Set<string>();
701
+ for (const agg of (modForDart.aggregates as { fields: Record<string, { foreignRef?: { targetAggregateId: string } }> }[])) {
702
+ for (const f of Object.values(agg.fields)) {
703
+ const tid = f.foreignRef?.targetAggregateId;
704
+ if (tid === undefined) continue;
705
+ const targetFile = aggIdToDartFile.get(tid);
706
+ if (targetFile !== undefined && targetFile !== modForDart.name) foreignRefImportUris.add(`${targetFile}.dart`);
707
+ }
708
+ }
709
+ const mergedDartImports = [
710
+ ...(modForDart.dartImports ?? []),
711
+ ...[...foreignRefImportUris]
712
+ .filter((uri) => !(modForDart.dartImports ?? []).some((i) => i.uri === uri))
713
+ .sort()
714
+ .map((uri) => ({ uri })),
715
+ ];
716
+ const modForDartWithImports = mergedDartImports.length > 0 ? { ...modForDart, dartImports: mergedDartImports } : modForDart;
717
+ const src = generateDartDomain(modForDartWithImports, {
688
718
  ...skips,
689
719
  ...(domainFrameworkImport !== undefined ? { frameworkImportUri: domainFrameworkImport } : {}),
690
720
  });
@@ -857,18 +887,29 @@ function emitDartPackages(
857
887
  // ── the TYPES package — pure data, `nomos_types` only ──
858
888
  const typesGen = freshGenDir(packages.types);
859
889
  const typesSources = new Map<string, string>(); // fileBase → src (for alias validation + purity)
890
+ // The SIBLING generated type files a types-package file MAY import (a cross-domain `t.foreignRef` types its
891
+ // field as the target aggregate's class, which lives in the target domain's file). A sibling types file is
892
+ // still PURE (no runtime/bridge surface — the purity gate exists to keep nomos_client out, not to isolate
893
+ // domain files from each other; Dart allows type-import cycles for mutual refs).
894
+ const siblingTypeFiles = new Set<string>([...modules.map((m) => `${m.name}.dart`), `${FRAMEWORK_FILE}.dart`]);
860
895
  const writeTypes = (fileBase: string, src: string): void => {
861
896
  if (!src.includes(DART_PACKAGE_IMPORT)) {
862
897
  fail(`generated Dart for '${fileBase}' does not carry the expected support import — codegen_dart header drifted`);
863
898
  }
864
899
  const pure = src.replace(DART_PACKAGE_IMPORT, DART_TYPES_IMPORT);
865
- // PURITY, fail-closed: only the nomos_types barrel + the relative framework file may be imported.
900
+ // PURITY, fail-closed: only the nomos_types barrel, the framework file, and SIBLING generated type files
901
+ // (cross-domain foreignRef targets) may be imported. Runtime/bridge surfaces (nomos_client) stay out.
866
902
  for (const line of pure.split("\n")) {
867
903
  const m = /^import\s+'([^']+)'/.exec(line.trim());
868
- if (m !== null && m[1] !== "package:nomos_types/nomos_types.dart" && m[1] !== `${FRAMEWORK_FILE}.dart`) {
904
+ if (
905
+ m !== null &&
906
+ m[1] !== "package:nomos_types/nomos_types.dart" &&
907
+ m[1] !== `${FRAMEWORK_FILE}.dart` &&
908
+ !siblingTypeFiles.has(m[1]!)
909
+ ) {
869
910
  fail(
870
911
  `types-package purity: generated '${fileBase}.dart' imports '${m[1]}' — a types file may only ` +
871
- `import the nomos_types core (runtime/bridge surfaces belong in the client package)`,
912
+ `import the nomos_types core, the framework file, or a sibling generated domain file`,
872
913
  );
873
914
  }
874
915
  }
@@ -879,11 +920,28 @@ function emitDartPackages(
879
920
  };
880
921
 
881
922
  if (shared.frameworkMod !== undefined) writeTypes(FRAMEWORK_FILE, generateDartDomain(shared.frameworkMod));
923
+ // CROSS-DOMAIN foreignRef (layered): map aggregate id → its domain's type file, so a foreignRef field's
924
+ // target class resolves via a sibling import (the purity gate now permits sibling type files).
925
+ const aggIdToTypeFile = new Map<string, string>();
926
+ for (const m of modules) for (const agg of (m.aggregates as { id: string }[])) aggIdToTypeFile.set(agg.id, m.name);
882
927
  const perDomain = modules.map((mod) => ({ mod, dd: domainDedupOpts(mod, shared) }));
883
928
  for (const { mod, dd } of perDomain) {
929
+ const frImports = new Set<string>();
930
+ for (const agg of (dd.modForDart.aggregates as { fields: Record<string, { foreignRef?: { targetAggregateId: string } }> }[])) {
931
+ for (const f of Object.values(agg.fields)) {
932
+ const tid = f.foreignRef?.targetAggregateId;
933
+ const tf = tid !== undefined ? aggIdToTypeFile.get(tid) : undefined;
934
+ if (tf !== undefined && tf !== dd.modForDart.name) frImports.add(`${tf}.dart`);
935
+ }
936
+ }
937
+ const merged = [
938
+ ...(dd.modForDart.dartImports ?? []),
939
+ ...[...frImports].filter((uri) => !(dd.modForDart.dartImports ?? []).some((i) => i.uri === uri)).sort().map((uri) => ({ uri })),
940
+ ];
941
+ const modForTypes = merged.length > 0 ? { ...dd.modForDart, dartImports: merged } : dd.modForDart;
884
942
  writeTypes(
885
943
  mod.name,
886
- generateDartDomain(dd.modForDart, {
944
+ generateDartDomain(modForTypes, {
887
945
  ...dd.skips,
888
946
  ...(dd.foldsFramework ? { frameworkImportUri: `${FRAMEWORK_FILE}.dart` } : {}),
889
947
  }),