@intentius/chant 0.19.1 → 0.21.0

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.
Files changed (164) hide show
  1. package/dist/build-params.d.ts +108 -0
  2. package/dist/build-params.d.ts.map +1 -0
  3. package/dist/build.d.ts +79 -1
  4. package/dist/build.d.ts.map +1 -1
  5. package/dist/cli/commands/build.d.ts +31 -0
  6. package/dist/cli/commands/build.d.ts.map +1 -1
  7. package/dist/cli/commands/check-lexicon-examples.d.ts +41 -0
  8. package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -0
  9. package/dist/cli/commands/check-lexicon-intrinsics.d.ts +71 -0
  10. package/dist/cli/commands/check-lexicon-intrinsics.d.ts.map +1 -0
  11. package/dist/cli/commands/check-lexicon.d.ts +1 -1
  12. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  13. package/dist/cli/commands/lint.d.ts +27 -0
  14. package/dist/cli/commands/lint.d.ts.map +1 -1
  15. package/dist/cli/handlers/build.d.ts.map +1 -1
  16. package/dist/cli/handlers/components.d.ts.map +1 -1
  17. package/dist/cli/handlers/lint.d.ts.map +1 -1
  18. package/dist/cli/handlers/run-client.d.ts +1 -1
  19. package/dist/cli/handlers/run-client.d.ts.map +1 -1
  20. package/dist/cli/handlers/run.d.ts.map +1 -1
  21. package/dist/cli/main.d.ts.map +1 -1
  22. package/dist/cli/plugins.d.ts +16 -0
  23. package/dist/cli/plugins.d.ts.map +1 -1
  24. package/dist/cli/registry.d.ts +10 -0
  25. package/dist/cli/registry.d.ts.map +1 -1
  26. package/dist/codegen/docs-sections.d.ts.map +1 -1
  27. package/dist/codegen/docs-types.d.ts +2 -0
  28. package/dist/codegen/docs-types.d.ts.map +1 -1
  29. package/dist/components/cli-support.d.ts +12 -5
  30. package/dist/components/cli-support.d.ts.map +1 -1
  31. package/dist/components/discover.d.ts +62 -7
  32. package/dist/components/discover.d.ts.map +1 -1
  33. package/dist/components/sandbox/driver.d.ts +12 -0
  34. package/dist/components/sandbox/driver.d.ts.map +1 -0
  35. package/dist/components/sandbox/run.d.ts +42 -0
  36. package/dist/components/sandbox/run.d.ts.map +1 -0
  37. package/dist/composite.d.ts +5 -0
  38. package/dist/composite.d.ts.map +1 -1
  39. package/dist/config.d.ts +71 -0
  40. package/dist/config.d.ts.map +1 -1
  41. package/dist/declarable.d.ts +16 -0
  42. package/dist/declarable.d.ts.map +1 -1
  43. package/dist/discovery/collect.d.ts.map +1 -1
  44. package/dist/discovery/entity-wire-codec.d.ts +166 -0
  45. package/dist/discovery/entity-wire-codec.d.ts.map +1 -0
  46. package/dist/discovery/entity-wire.d.ts +50 -0
  47. package/dist/discovery/entity-wire.d.ts.map +1 -0
  48. package/dist/discovery/fold-import.d.ts +239 -0
  49. package/dist/discovery/fold-import.d.ts.map +1 -0
  50. package/dist/discovery/index.d.ts +74 -1
  51. package/dist/discovery/index.d.ts.map +1 -1
  52. package/dist/discovery/sandbox/bundle.d.ts +18 -0
  53. package/dist/discovery/sandbox/bundle.d.ts.map +1 -0
  54. package/dist/discovery/sandbox/child-errors.d.ts +15 -0
  55. package/dist/discovery/sandbox/child-errors.d.ts.map +1 -0
  56. package/dist/discovery/sandbox/driver.d.ts +13 -0
  57. package/dist/discovery/sandbox/driver.d.ts.map +1 -0
  58. package/dist/discovery/sandbox/run.d.ts +69 -0
  59. package/dist/discovery/sandbox/run.d.ts.map +1 -0
  60. package/dist/errors.d.ts +9 -1
  61. package/dist/errors.d.ts.map +1 -1
  62. package/dist/fold/fold.d.ts +299 -0
  63. package/dist/fold/fold.d.ts.map +1 -0
  64. package/dist/fold/foldable-helpers.d.ts +121 -0
  65. package/dist/fold/foldable-helpers.d.ts.map +1 -0
  66. package/dist/fold/subset.d.ts +134 -0
  67. package/dist/fold/subset.d.ts.map +1 -0
  68. package/dist/index.d.ts +2 -0
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/lexicon-output.d.ts +7 -2
  71. package/dist/lexicon-output.d.ts.map +1 -1
  72. package/dist/lexicon-schema.d.ts +4 -2
  73. package/dist/lexicon-schema.d.ts.map +1 -1
  74. package/dist/lexicon.d.ts +131 -1
  75. package/dist/lexicon.d.ts.map +1 -1
  76. package/dist/lifecycle/release-ledger.d.ts +11 -0
  77. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  78. package/dist/lint/component-checks.d.ts +7 -1
  79. package/dist/lint/component-checks.d.ts.map +1 -1
  80. package/dist/lint/rules/evl001-non-literal-expression.d.ts.map +1 -1
  81. package/dist/lint/rules/evl003-dynamic-property-access.d.ts.map +1 -1
  82. package/dist/params.d.ts +60 -0
  83. package/dist/params.d.ts.map +1 -0
  84. package/dist/provenance.d.ts +21 -0
  85. package/dist/provenance.d.ts.map +1 -1
  86. package/dist/runtime.d.ts +10 -1
  87. package/dist/runtime.d.ts.map +1 -1
  88. package/package.json +2 -1
  89. package/src/build-params.test.ts +144 -0
  90. package/src/build-params.ts +207 -0
  91. package/src/build.test.ts +38 -0
  92. package/src/build.ts +144 -7
  93. package/src/cli/commands/build.test.ts +220 -2
  94. package/src/cli/commands/build.ts +111 -3
  95. package/src/cli/commands/check-lexicon-examples.test.ts +92 -0
  96. package/src/cli/commands/check-lexicon-examples.ts +103 -0
  97. package/src/cli/commands/check-lexicon-intrinsics.test.ts +179 -0
  98. package/src/cli/commands/check-lexicon-intrinsics.ts +348 -0
  99. package/src/cli/commands/check-lexicon.test.ts +34 -0
  100. package/src/cli/commands/check-lexicon.ts +137 -1
  101. package/src/cli/commands/lint.ts +31 -3
  102. package/src/cli/commands/onboard.ts +1 -1
  103. package/src/cli/component-security-boundary.test.ts +170 -0
  104. package/src/cli/handlers/build.ts +24 -3
  105. package/src/cli/handlers/components.ts +9 -2
  106. package/src/cli/handlers/dev.ts +1 -1
  107. package/src/cli/handlers/graph.ts +7 -5
  108. package/src/cli/handlers/lifecycle.ts +2 -2
  109. package/src/cli/handlers/lint.ts +2 -0
  110. package/src/cli/handlers/misc.ts +2 -2
  111. package/src/cli/handlers/run-client.ts +1 -1
  112. package/src/cli/handlers/run.ts +20 -5
  113. package/src/cli/main.test.ts +22 -0
  114. package/src/cli/main.ts +39 -0
  115. package/src/cli/plugins.ts +20 -4
  116. package/src/cli/registry.ts +10 -0
  117. package/src/cli/security-boundary.test.ts +135 -0
  118. package/src/codegen/docs-sections.test.ts +67 -0
  119. package/src/codegen/docs-sections.ts +7 -3
  120. package/src/codegen/docs-types.ts +2 -0
  121. package/src/components/cli-support.ts +22 -10
  122. package/src/components/discover.ts +127 -25
  123. package/src/components/sandbox/driver.ts +114 -0
  124. package/src/components/sandbox/run.test.ts +185 -0
  125. package/src/components/sandbox/run.ts +177 -0
  126. package/src/composite.test.ts +21 -0
  127. package/src/composite.ts +20 -1
  128. package/src/config.ts +81 -0
  129. package/src/declarable.ts +20 -0
  130. package/src/discovery/collect.ts +17 -3
  131. package/src/discovery/entity-wire-codec.ts +487 -0
  132. package/src/discovery/entity-wire.test.ts +240 -0
  133. package/src/discovery/entity-wire.ts +67 -0
  134. package/src/discovery/fold-import.test.ts +1598 -0
  135. package/src/discovery/fold-import.ts +1998 -0
  136. package/src/discovery/index.test.ts +191 -1
  137. package/src/discovery/index.ts +242 -1
  138. package/src/discovery/sandbox/bundle.ts +218 -0
  139. package/src/discovery/sandbox/child-errors.ts +65 -0
  140. package/src/discovery/sandbox/driver.ts +147 -0
  141. package/src/discovery/sandbox/run.test.ts +179 -0
  142. package/src/discovery/sandbox/run.ts +196 -0
  143. package/src/errors.ts +9 -1
  144. package/src/fold/fold.test.ts +812 -0
  145. package/src/fold/fold.ts +805 -0
  146. package/src/fold/foldable-helpers.ts +171 -0
  147. package/src/fold/subset-doc-parity.test.ts +210 -0
  148. package/src/fold/subset.test.ts +352 -0
  149. package/src/fold/subset.ts +383 -0
  150. package/src/index.ts +2 -0
  151. package/src/lexicon-output.ts +7 -2
  152. package/src/lexicon-schema.test.ts +57 -0
  153. package/src/lexicon-schema.ts +8 -1
  154. package/src/lexicon.ts +132 -1
  155. package/src/lifecycle/git.test.ts +10 -5
  156. package/src/lifecycle/release-ledger.test.ts +28 -0
  157. package/src/lifecycle/release-ledger.ts +11 -0
  158. package/src/lint/component-checks.ts +8 -1
  159. package/src/lint/rules/evl001-non-literal-expression.ts +26 -110
  160. package/src/lint/rules/evl003-dynamic-property-access.ts +11 -2
  161. package/src/params.test.ts +22 -0
  162. package/src/params.ts +66 -0
  163. package/src/provenance.ts +22 -0
  164. package/src/runtime.ts +11 -2
@@ -0,0 +1,50 @@
1
+ /**
2
+ * chant #1045 (Phase 1) — the JSON wire format for a discovered, named,
3
+ * ref-resolved entity set, plus (below) the standalone `discover()` +
4
+ * encode entry point.
5
+ *
6
+ * The codec itself — {@link WireValue}, {@link EntitySetWire},
7
+ * {@link encodeEntitySet}, {@link decodeEntitySet}, and friends — lives in
8
+ * `./entity-wire-codec.ts` (chant #1045 Phase 2 split this out) and is
9
+ * re-exported here unchanged. That file has NO dependency on `discover()` (or
10
+ * anything that pulls in the `typescript` compiler package), which matters
11
+ * because chant #1045 Phase 2's sandboxed child bundles JUST the codec —
12
+ * bundling this file, `discoverEntitySetJson` and all, would drag `discover`
13
+ * → `fold-import` → `typescript` (a multi-megabyte CJS package that doesn't
14
+ * survive ESM bundling on its own) into a driver that only ever needs to
15
+ * encode, never to discover. See `./sandbox/driver.ts`.
16
+ */
17
+ export type { WireValue, WireDeclarableEntity, WireLexiconOutputEntity, WireEntity, EntitySetWire, } from "./entity-wire-codec.js";
18
+ export { encodeEntitySet, decodeEntitySet } from "./entity-wire-codec.js";
19
+ import type { FoldDecision } from "./index.js";
20
+ import { type DiscoveryOptions } from "./index.js";
21
+ import { type EntitySetWire } from "./entity-wire-codec.js";
22
+ /** A discovery run's full result as pure JSON — {@link encodeEntitySet} plus the already-JSON-safe rest of {@link DiscoveryResult} (`./index.ts`). */
23
+ export interface DiscoveredEntitiesJson {
24
+ entitySet: EntitySetWire;
25
+ sourceFiles: string[];
26
+ /** `DiscoveryError.toJSON()` output — see `../errors.ts`. */
27
+ errors: Array<{
28
+ name: string;
29
+ file: string;
30
+ message: string;
31
+ type: string;
32
+ }>;
33
+ foldDecisions: FoldDecision[];
34
+ }
35
+ /**
36
+ * Run discovery over `path` — scanning files, importing/folding modules,
37
+ * naming entities, and resolving `AttrRef`s (all unchanged, reusing
38
+ * `discover()` as-is) — and return the result as pure JSON via
39
+ * {@link encodeEntitySet}. This is the boundary chant#1045 Phase 2 moved into
40
+ * a sandboxed child process for the run-fallback subset — see
41
+ * `./sandbox/run.ts` — Phase 1 only proved the data can cross it losslessly
42
+ * (see the fold-vs-JSON differential in `examples/`).
43
+ *
44
+ * Reuses `discover()` unchanged, so the fold/run-fallback split and the
45
+ * `planFoldTaint` identity-taint invariant (`./fold-import.ts`) are exactly
46
+ * what they are today — this function only serializes whatever `discover()`
47
+ * already decided to produce.
48
+ */
49
+ export declare function discoverEntitySetJson(path: string, options?: DiscoveryOptions): Promise<DiscoveredEntitiesJson>;
50
+ //# sourceMappingURL=entity-wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-wire.d.ts","sourceRoot":"","sources":["../../src/discovery/entity-wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,YAAY,EACV,SAAS,EACT,oBAAoB,EACpB,uBAAuB,EACvB,UAAU,EACV,aAAa,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAY,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAO1E,sJAAsJ;AACtJ,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,aAAa,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,6DAA6D;IAC7D,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7E,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAQrH"}
@@ -0,0 +1,239 @@
1
+ import { type Declarable } from "../declarable.js";
2
+ import { type CompositeInstance } from "../composite.js";
3
+ import type { IntrinsicDef } from "../lexicon.js";
4
+ import type { BuildParamValue } from "../build-params.js";
5
+ /**
6
+ * Bridges the static folder ({@link ../fold/fold}, #1026) into discovery
7
+ * (#1022/#1023, epic #1019): attempts to fold one source file into real
8
+ * `Declarable`/`CompositeInstance` instances with zero execution of the
9
+ * file's own top-level code, so `discover()` can skip `importModule` for it
10
+ * entirely.
11
+ *
12
+ * The folder only reduces expressions to plain values — it has no notion of
13
+ * lexicon resource classes or composites. This module supplies that missing
14
+ * piece: it reads the file's `import` declarations to learn which module
15
+ * each `new Type(...)` constructor or bare composite-factory call names,
16
+ * resolves and imports *that* module (a trusted lexicon/vendor module, not
17
+ * the file under fold), and constructs the real resource/composite instance
18
+ * from the folded props. Importing the lexicon module is not a regression on
19
+ * "no module execution" — the run path already imports it to get the same
20
+ * class/function; the only thing skipped here is executing the file's *own*
21
+ * statements.
22
+ *
23
+ * chant #1023 (epic #1019 Phase 5) extends this from leaf resources
24
+ * (`new Type(...)`) to composite factory calls — `SomeComposite({...})`,
25
+ * `propagate(SomeComposite({...}), {...})`, member access on the result
26
+ * (`web.deployment`), and destructuring (`const { a, b } = SomeComposite(...)`
27
+ * or `export const { a, b } = SomeComposite(...)`). A composite factory is a
28
+ * pure function of its props (EVL009/EVL010 guarantee its body only
29
+ * references props, sibling members, and imports), so — exactly like a
30
+ * resource constructor — it's safe to resolve through the file's imports and
31
+ * actually invoke with statically-folded props: no need to pre-verify "is
32
+ * this specifically a registered composite" via a shared registry (which
33
+ * would be unreliable across separately-loaded module instances of
34
+ * `@intentius/chant` anyway) — {@link resolveCallExpression} just resolves,
35
+ * invokes, and lets the RESULT speak. If it satisfies
36
+ * {@link isCompositeInstance} (or, for a plain resource-returning helper,
37
+ * {@link isDeclarable}), it's used. Nested composites and `propagate()`'d
38
+ * shared props need no special-casing: a nested composite is just another
39
+ * member the real factory call already produced (real JS execution inside a
40
+ * trusted module), and `propagate` is just another resolvable imported
41
+ * function that receives a live `CompositeInstance` plus folded shared props
42
+ * and returns it — `expandComposite()` (invoked downstream by
43
+ * `collectEntities`, unchanged) does the recursive expansion and the shared-
44
+ * prop merge exactly as it does for the run path.
45
+ */
46
+ /** One exported `const` name folded to a real, constructed `Declarable` or `CompositeInstance`. */
47
+ export type FoldedEntity = [name: string, entity: Declarable | CompositeInstance];
48
+ export type FoldFileResult = {
49
+ ok: true;
50
+ entities: FoldedEntity[];
51
+ /**
52
+ * chant #1020 — EVERY exported name's fully-resolved value, not just
53
+ * the `Declarable`/`CompositeInstance` ones already in `entities`: a
54
+ * plain value folds too (a string, a number, a plain object), it just
55
+ * contributes nothing to `entities` (see {@link applyResolvedValue}).
56
+ * This is the table another file's cross-file reference resolves
57
+ * against — see `buildExternals` below and the module doc on
58
+ * `planFoldTaint` for why a resource/composite value here MUST be the
59
+ * exact same object every referencing file sees.
60
+ */
61
+ exportedValues: Map<string, unknown>;
62
+ /**
63
+ * chant #1044 — the OTHER project files whose exported OBJECTS this
64
+ * fold consumed (a cross-file `Declarable`, composite instance, or any
65
+ * other non-primitive reached through `buildExternals`/a re-export).
66
+ *
67
+ * Object identity is the thing that cannot survive one side of the
68
+ * build folding while the other runs, so `planFoldTaint` needs to know
69
+ * who consumed whose objects: if a file here is forced back to run, the
70
+ * instance THIS file already captured is not the instance discovery
71
+ * will collect, and serialization fails on an entity with no logical
72
+ * name. A primitive (string, number, boolean, null) is never recorded —
73
+ * it has no identity to disagree about.
74
+ */
75
+ liveSources: ReadonlySet<string>;
76
+ } | {
77
+ ok: false;
78
+ reason: string;
79
+ };
80
+ /**
81
+ * A per-build memo (chant #1020) so a project file imported by several
82
+ * others is folded exactly ONCE — every referrer resolves against the SAME
83
+ * `FoldFileResult`, and therefore the SAME constructed
84
+ * `Declarable`/`CompositeInstance` objects, no matter how many files
85
+ * cross-file-reference it or in what order discovery visits them. Also
86
+ * tracks the current resolution call chain (`stack`) so a genuine reference
87
+ * cycle (fileA needs fileB needs fileA) is DETECTED — rather than an
88
+ * infinite recursion / a promise awaiting itself forever — and reported as a
89
+ * located `FoldError` naming the cycle path.
90
+ *
91
+ * `discover()` creates exactly one session per `{ fold: true }` build and
92
+ * passes it to every top-level `tryFoldFile` call, so its own per-file loop
93
+ * and any cross-file reference reaching into the same file share the
94
+ * identical cache. Callers that don't care about cross-file sharing (unit
95
+ * tests exercising a single file in isolation) can omit it — {@link tryFoldFile}
96
+ * creates a private, single-call session on their behalf.
97
+ */
98
+ export interface FoldSession {
99
+ readonly intrinsics: readonly IntrinsicDef[];
100
+ readonly cache: Map<string, Promise<FoldFileResult>>;
101
+ readonly stack: string[];
102
+ /**
103
+ * Per-build memo (chant #1020 hang fix) for {@link importModule} itself —
104
+ * keyed by resolved absolute module path, shared session-wide exactly like
105
+ * {@link cache} above. Cross-file resolution means MANY files in one
106
+ * directory can each independently resolve the SAME constructor/composite-
107
+ * factory import (e.g. every file that constructs an AWS resource imports
108
+ * the same lexicon barrel) — before this, every one of those calls issued
109
+ * its own `await import(path)`, relying entirely on the runtime's own
110
+ * module cache to make the repeats cheap. That assumption holds for a
111
+ * plain `node`/`tsx` process, but NOT for a real dynamic import running
112
+ * inside a vitest worker: `vite-node`'s own SSR module graph can take a
113
+ * real, non-trivial amount of wall-clock time to re-resolve/re-register an
114
+ * already-loaded module on EVERY call, not just the first — harmless at
115
+ * single-digit call counts, but #1020's cross-file resolution can issue
116
+ * several times as many `importModule` calls for the same handful of large
117
+ * lexicon barrels within one `discover()` pass as the pre-#1020 single-file
118
+ * fold did. Memoizing the import itself (not just the path resolution)
119
+ * caps it at exactly one real `import()` per unique path per session,
120
+ * regardless of how many files reference it — this is what actually keeps
121
+ * a session-local retry (e.g. `sandbox-differential.test.ts`'s
122
+ * `vi.resetModules()` + rebuild path, which reruns fold from a cold
123
+ * module cache) from compounding into a multi-minute stall. Purely a cache
124
+ * over an idempotent operation (the same resolved path always yields the
125
+ * same module namespace object) — doesn't change what folds.
126
+ */
127
+ readonly importCache: Map<string, Promise<Record<string, unknown>>>;
128
+ /**
129
+ * Per-build memo (chant #1020 hang fix) for {@link resolveModulePath}'s
130
+ * RELATIVE/absolute-specifier branch only — keyed by
131
+ * `${dirname(fromFile)}\0${specifier}`. See {@link resolveModulePathMemoized}'s
132
+ * doc for the full story, including why bare (package) specifiers are
133
+ * memoized in a separate, process-wide cache instead of this session-
134
+ * scoped one: a relative specifier resolves against PROJECT source, which
135
+ * `chant build --watch` can legitimately change between rebuilds (a new
136
+ * sibling file appearing mid-session), so this cache is intentionally
137
+ * thrown away with the rest of the session at the end of every
138
+ * `discover()` call, unlike the bare-specifier one.
139
+ */
140
+ readonly resolvePathCache: Map<string, string>;
141
+ /**
142
+ * chant #1064 — this build's resolved build-time parameter values (see
143
+ * ../build-params.ts), consulted only by {@link buildExternals}'s one
144
+ * recognized bare-specifier case: a named `params` import resolving to
145
+ * ../params.ts. `undefined` when the build supplied none (no `chant.config.ts`
146
+ * `buildParams` declared, or the caller didn't pass any) — a project that
147
+ * doesn't use build-time parameters pays nothing extra here.
148
+ */
149
+ readonly buildParams?: Readonly<Record<string, BuildParamValue>>;
150
+ }
151
+ /** Create a fresh, empty {@link FoldSession}. */
152
+ export declare function createFoldSession(intrinsics?: readonly IntrinsicDef[], buildParams?: Readonly<Record<string, BuildParamValue>>): FoldSession;
153
+ /**
154
+ * Attempt to fold one source file with zero execution of its own top-level
155
+ * code. Returns the folded, instantiated entities on success, or a reason
156
+ * to fall back to the run path (`importModule`) on the first construct
157
+ * outside the fold subset.
158
+ *
159
+ * @param intrinsics - Lexicon-registered intrinsic tags (chant #1039), e.g.
160
+ * AWS's `Sub`. Threaded down to {@link fold}/{@link foldResource} so a
161
+ * registered tagged template folds instead of unconditionally throwing
162
+ * "unregistered tagged template intrinsic". Defaults to none — the caller
163
+ * (`discover()`, ultimately `chant build --fold`) is expected to pass the
164
+ * target lexicons' combined `intrinsics()`. Ignored when `session` is
165
+ * given (its own `intrinsics`, fixed at creation, apply instead).
166
+ * @param session - chant #1020: share ONE {@link FoldSession} across every
167
+ * file in a build (as `discover()` does) so a project file imported by
168
+ * several others folds exactly once and every referrer shares the same
169
+ * constructed entities — see {@link FoldSession}'s doc. Omit for a
170
+ * standalone, single-file fold attempt (creates a private session scoped
171
+ * to just this call — a cross-file reference reachable from `file` still
172
+ * resolves, just without sharing its cache with any other top-level call).
173
+ */
174
+ export declare function tryFoldFile(file: string, intrinsics?: readonly IntrinsicDef[], session?: FoldSession): Promise<FoldFileResult>;
175
+ /**
176
+ * A file that folds successfully in isolation must still be forced back to
177
+ * run if some OTHER discovered file — one that itself falls back to run —
178
+ * imports it (directly, or transitively through another sibling file it
179
+ * imports). Composite folding is what makes this reachable: `network.ts`
180
+ * exporting `export const network = VpcDefault({})` folds cleanly on its
181
+ * own (no cross-file reference needed), landing its Declarables (`vpc`, its
182
+ * subnets, …) in `entities` as ONE set of real objects, built by literally
183
+ * invoking `VpcDefault` from inside `tryFoldFile` — bypassing `network.ts`
184
+ * as a module entirely (that's the whole point of folding it).
185
+ *
186
+ * Before chant #1020, a sibling file like `alb.ts` that did
187
+ * `import { network } from "./network"; ... vpcId: network.vpc.VpcId`
188
+ * could never fold that cross-file reference and fell back to run — but
189
+ * running `alb.ts` for real re-executes `import "./network"` for real too,
190
+ * which (via Node's module cache) produces the SAME `network.ts` module
191
+ * instance for every OTHER run-fallback file that imports it, but a
192
+ * DIFFERENT one than the object `tryFoldFile("network.ts")` already built.
193
+ * `alb.ts`'s AttrRef for `network.vpc.VpcId` then points at an object
194
+ * that's never in the `entities` map (only the folded one is), so it can
195
+ * never be assigned a logical name and serialization fails outright — not
196
+ * drift, a crash.
197
+ *
198
+ * The fix: fold and run must never disagree about which object identity a
199
+ * given file's exports have. Since `network.ts` itself doesn't need
200
+ * anything cross-file to fold (only a file's own successful fold could ever
201
+ * reach this taint — an unresolvable cross-file reference already fails
202
+ * that file's OWN fold attempt), the safe rule is to force `network.ts`
203
+ * back to run too, so both `alb.ts`'s real import and `network.ts`'s own
204
+ * discovery entry resolve through the exact same `importModule` call and
205
+ * share the exact same singleton module instance. This has to propagate
206
+ * transitively (if `alb.ts` itself is only reachable by importing a file
207
+ * that imports `network.ts`), so this is a forward-reachability walk over
208
+ * the discovered files' relative-import graph, seeded from every file that
209
+ * doesn't fold on its own.
210
+ *
211
+ * chant #1044 adds the OTHER half of the same hazard, in the opposite
212
+ * direction along the same edges. Forward taint covers "a run file imports a
213
+ * folded file"; it does not cover "a FOLDED file consumed the objects of a
214
+ * file that later got forced to run". Once a plain-call intrinsic can fold,
215
+ * that second case is easy to reach: in `lexicons/aws/examples/lambda-api`,
216
+ * `health-api.ts` folds and captures `params.ts`'s real `Parameter` instance
217
+ * through `Ref(environment)`, while `params.ts` itself is forced to run
218
+ * because a DIFFERENT sibling (`data-bucket.ts`) imports it and falls back.
219
+ * Discovery then collects the run instance and serializes the folded one —
220
+ * the same "Logical name not set" crash described above, arriving from the
221
+ * other side. So `liveSources` (see {@link FoldFileResult}) contributes
222
+ * reverse edges here: a tainted file taints every folded file that captured
223
+ * one of its objects. Only object identity propagates — a file that imported
224
+ * a plain string from a tainted file has nothing to disagree about.
225
+ *
226
+ * chant #1020 changes the calculus but not this function: `alb.ts` can now
227
+ * often fold `network.vpc.VpcId` too (see `buildExternals`/`foldFileMemoized`
228
+ * above), by reusing THE EXACT SAME `tryFoldFile("network.ts")` call (memoized
229
+ * per `FoldSession`) that `discover()`'s own per-file loop also uses — so
230
+ * `alb.ts` and `network.ts` share one real `vpc` object without ever
231
+ * disagreeing. This invariant is still needed for whatever STILL falls back
232
+ * after #1020 (a call-as-a-value construct, #1044; a shape #1020 doesn't
233
+ * cover): the edge collection below is unconditional — it doesn't care
234
+ * whether an edge happens to ALSO be used for cross-file value resolution —
235
+ * so the exact same forced-taint safety net still applies to that remaining
236
+ * boundary, unchanged.
237
+ */
238
+ export declare function planFoldTaint(files: readonly string[], wouldFold: ReadonlyMap<string, boolean>, liveSources?: ReadonlyMap<string, ReadonlySet<string>>): Promise<Set<string>>;
239
+ //# sourceMappingURL=fold-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold-import.d.ts","sourceRoot":"","sources":["../../src/discovery/fold-import.ts"],"names":[],"mappings":"AAMA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAuB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAgB3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,mGAAmG;AACnG,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,iBAAiB,CAAC,CAAC;AAElF,MAAM,MAAM,cAAc,GACtB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB;;;;;;;;;OASG;IACH,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC;;;;;;;;;;;;OAYG;IACH,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAClC,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IACzB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACpE;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;CAClE;AAED,iDAAiD;AACjD,wBAAgB,iBAAiB,CAC/B,UAAU,GAAE,SAAS,YAAY,EAAO,EACxC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,GACtD,WAAW,CAEb;AAsmDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,SAAS,YAAY,EAAO,EACxC,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,cAAc,CAAC,CAEzB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,GACrD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CA8EtB"}
@@ -1,5 +1,72 @@
1
1
  import type { Declarable } from "../declarable.js";
2
2
  import type { DiscoveryError } from "../errors.js";
3
+ import type { IntrinsicDef } from "../lexicon.js";
4
+ import type { BuildParamProvenance } from "../provenance.js";
5
+ /**
6
+ * Per-file fold-vs-run outcome (chant #1022, epic #1019), populated only
7
+ * when {@link DiscoveryOptions.fold} was requested. Lets a caller (`chant
8
+ * build --fold`) report which files skipped module execution and which
9
+ * fell back to the run path, and why.
10
+ */
11
+ export interface FoldDecision {
12
+ /** Absolute path of the source file this decision covers. */
13
+ file: string;
14
+ /** "fold" — folded statically, zero execution. "run" — imported/executed as before. */
15
+ mode: "fold" | "run";
16
+ /** Why the file fell back to run. Present only when `mode === "run"` and fold was requested. */
17
+ reason?: string;
18
+ /** Number of entities the fold produced. Present only when `mode === "fold"`. */
19
+ resourceCount?: number;
20
+ }
21
+ /**
22
+ * Optional inputs to {@link discover}.
23
+ */
24
+ export interface DiscoveryOptions {
25
+ /**
26
+ * chant #1022/#1023 (epic #1019) — opt-in: for each source file, try to
27
+ * fold it to `Declarable`/`CompositeInstance` entities statically (no
28
+ * module execution) before falling back to importing/running it. Anything
29
+ * the folder can't represent (a non-`new`, non-composite-call export, a
30
+ * cross-file-only reference, …) falls back per-file — see
31
+ * {@link planFoldTaint} for the one case where a file that WOULD fold in
32
+ * isolation is still forced back to run, to keep fold and run from ever
33
+ * disagreeing about a shared entity's identity. Default `false` — behavior
34
+ * is unchanged unless requested.
35
+ */
36
+ fold?: boolean;
37
+ /**
38
+ * chant #1039 — lexicon-registered intrinsic tags (e.g. AWS's `Sub`) to
39
+ * recognize while folding. Threaded down to `tryFoldFile`/the static
40
+ * folder so a registered tagged template folds instead of falling back to
41
+ * run. Only meaningful when {@link fold} is set; ignored otherwise.
42
+ * Default: none (an intrinsic-using file still folds up to that point,
43
+ * then falls back to run at the unregistered tag).
44
+ */
45
+ intrinsics?: IntrinsicDef[];
46
+ /**
47
+ * chant #1045 Phase 2 — opt-in: whatever would otherwise reach the
48
+ * in-process `importModule` step (every file, when {@link fold} isn't set;
49
+ * only the per-file run-fallback remainder, when it is) instead runs
50
+ * together, isolated, in one sandboxed child process — see
51
+ * `./sandbox/run.ts`. Folded files are unaffected: fold already executes
52
+ * zero of a file's own top-level code, so it stays in this process exactly
53
+ * as it does today. Default `false` — behavior, including performance
54
+ * (no bundling, no child process, no IPC), is unchanged unless requested.
55
+ */
56
+ sandbox?: boolean;
57
+ /**
58
+ * chant #1064 — this build's resolved build-time parameter values (see
59
+ * ../build-params.ts's `resolveBuildParams`, driven by the CLI's
60
+ * `--param`/`--params-file`/declared `env` mapping/`chant.config.ts`
61
+ * defaults). Populated into `../params.ts`'s shared `params` object
62
+ * (`setBuildParams`, below) before any project file is imported or folded,
63
+ * and threaded into the fold session so a `params.<name>` reference
64
+ * resolves to a literal instead of an unresolved identifier. Default: none
65
+ * — `params` stays empty, matching a project that declares no
66
+ * `buildParams` at all.
67
+ */
68
+ buildParams?: BuildParamProvenance[];
69
+ }
3
70
  /**
4
71
  * Result of the discovery process
5
72
  */
@@ -12,6 +79,11 @@ export interface DiscoveryResult {
12
79
  sourceFiles: string[];
13
80
  /** Array of errors encountered during discovery */
14
81
  errors: DiscoveryError[];
82
+ /**
83
+ * Per-file fold-vs-run decisions (#1022). Empty unless
84
+ * {@link DiscoveryOptions.fold} was set.
85
+ */
86
+ foldDecisions: FoldDecision[];
15
87
  }
16
88
  /**
17
89
  * Discovers all declarable entities in a directory by scanning files,
@@ -19,7 +91,8 @@ export interface DiscoveryResult {
19
91
  * a dependency graph.
20
92
  *
21
93
  * @param path - The directory path to discover entities in
94
+ * @param options - Optional discovery behavior, e.g. {@link DiscoveryOptions.fold}
22
95
  * @returns DiscoveryResult with entities, dependencies, sourceFiles, and errors
23
96
  */
24
- export declare function discover(path: string): Promise<DiscoveryResult>;
97
+ export declare function discover(path: string, options?: DiscoveryOptions): Promise<DiscoveryResult>;
25
98
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/discovery/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAOhD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,8DAA8D;IAC9D,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACvC,qDAAqD;IACrD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mDAAmD;IACnD,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAqGrE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/discovery/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAQ/C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAI1D;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,uFAAuF;IACvF,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,gGAAgG;IAChG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;;OAUG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;IAE5B;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,8DAA8D;IAC9D,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACvC,qDAAqD;IACrD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mDAAmD;IACnD,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB;;;OAGG;IACH,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAoQjG"}
@@ -0,0 +1,18 @@
1
+ export interface BundleResult {
2
+ /** Absolute, REALPATH'd path to the bundled entry file — this and {@link bundleDir} are what the caller grants `--allow-fs-read` to. macOS's `/tmp` is a symlink to `/private/tmp`; an un-canonicalized path here would silently fail to match Node's own (already-canonicalized) permission check. */
3
+ bundlePath: string;
4
+ /** Absolute, REALPATH'd directory containing {@link bundlePath} — remove with `rmSync(bundleDir, { recursive: true, force: true })` once done. */
5
+ bundleDir: string;
6
+ /** Directories the child ALSO needs `--allow-fs-read` for — the resolved locations of {@link EXTERNAL_PACKAGES}, which are deliberately left unbundled (see {@link externalTrustedPackagesPlugin}'s doc). Empty when none of those packages were actually imported. */
7
+ externalReadPaths: string[];
8
+ /** Wall-clock bundling time — chant#1045 asks this be measured and reported, not silently accepted. */
9
+ durationMs: number;
10
+ /** Bundle size in bytes. */
11
+ bytes: number;
12
+ }
13
+ /**
14
+ * Bundle `driverSource` (see {@link import("./driver.js").generateDriverSource})
15
+ * into a single self-contained ESM file.
16
+ */
17
+ export declare function bundleDriver(driverSource: string): Promise<BundleResult>;
18
+ //# sourceMappingURL=bundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../../src/discovery/sandbox/bundle.ts"],"names":[],"mappings":"AA4KA,MAAM,WAAW,YAAY;IAC3B,uSAAuS;IACvS,UAAU,EAAE,MAAM,CAAC;IACnB,kJAAkJ;IAClJ,SAAS,EAAE,MAAM,CAAC;IAClB,uQAAuQ;IACvQ,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,uGAAuG;IACvG,UAAU,EAAE,MAAM,CAAC;IACnB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CA4B9E"}
@@ -0,0 +1,15 @@
1
+ import { DiscoveryError, type DiscoveryErrorType } from "../../errors.js";
2
+ /**
3
+ * Classify one error raised while executing run-fallback project source (or
4
+ * chant's own collect/resolve/encode step) inside the sandboxed child.
5
+ *
6
+ * @param file - The project source file being executed when `err` was
7
+ * thrown, or `""` for an error not attributable to one specific file (e.g.
8
+ * `collectEntities`/`resolveAttrRefs` over the whole batch).
9
+ * @param fallbackType - The {@link DiscoveryErrorType} to use when `err`
10
+ * isn't a permission denial — mirrors how `discover()` itself types a
11
+ * plain import failure `"import"` vs. a collection/resolution failure
12
+ * `"resolution"`.
13
+ */
14
+ export declare function classifyChildError(file: string, err: unknown, fallbackType?: DiscoveryErrorType): DiscoveryError;
15
+ //# sourceMappingURL=child-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-errors.d.ts","sourceRoot":"","sources":["../../../src/discovery/sandbox/child-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAkCvE;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,OAAO,EACZ,YAAY,GAAE,kBAA6B,GAC1C,cAAc,CAchB"}
@@ -0,0 +1,13 @@
1
+ export interface GenerateDriverOptions {
2
+ /** Absolute paths to the run-fallback files this build decided NOT to fold — see `discover()`'s fold/taint loop in `../index.ts`. */
3
+ files: readonly string[];
4
+ /** The build root — threaded to `collectEntities` exactly as `discover()` threads its own `path` argument, so cross-directory stack-prefix disambiguation (chant #932) is computed the same way for this subset. */
5
+ buildRoot: string;
6
+ }
7
+ /**
8
+ * Generate the driver module's full TypeScript source. Written to a tmp file
9
+ * and bundled (see `./bundle.ts`) before being handed to a sandboxed child —
10
+ * never executed directly by the parent process.
11
+ */
12
+ export declare function generateDriverSource(options: GenerateDriverOptions): string;
13
+ //# sourceMappingURL=driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../../src/discovery/sandbox/driver.ts"],"names":[],"mappings":"AA4CA,MAAM,WAAW,qBAAqB;IACpC,qIAAqI;IACrI,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,oNAAoN;IACpN,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAqF3E"}
@@ -0,0 +1,69 @@
1
+ import type { Declarable } from "../../declarable.js";
2
+ import { DiscoveryError } from "../../errors.js";
3
+ /**
4
+ * chant #1045 Phase 2 — runs every run-fallback file for a build TOGETHER, as
5
+ * one bundled module graph, inside one sandboxed child process, and returns
6
+ * the same shape `discover()`'s own in-process run path would have produced:
7
+ * a named, ref-resolved entities map plus any errors.
8
+ *
9
+ * Isolation mechanics (verified on Node v24.13.1 — see the chant#1045 PR
10
+ * description for the full write-up):
11
+ * - `--permission --allow-fs-read=<bundle dir>,<project dir>[,<trusted
12
+ * external package dirs>]` — no filesystem write, no child-process, no
13
+ * worker-thread access. Bundling with esbuild first (not a packaging
14
+ * change — see `./bundle.ts`) means the child needs NO TypeScript loader
15
+ * (no `tsx`, so no `--allow-worker` and no writable temp dir either),
16
+ * unlike the plain `tsx`-based run path. The "trusted external package
17
+ * dirs" allowance is narrow and specific: `./bundle.ts` deliberately
18
+ * leaves a couple of chant/lexicon-internal dependencies (`typescript`)
19
+ * unbundled and resolves them to their real, fixed location instead —
20
+ * project source never controls what's installed there.
21
+ * - The env is a spawn-time scrub (`env: {}` below, plus `PATH` — see the
22
+ * option below), not `--permission`: Node's Permission Model does not gate
23
+ * `process.env` at all (confirmed: every key stays readable even under
24
+ * `--permission`).
25
+ * - Network egress is NOT addressed here — Node has no flag for it. See the
26
+ * chant#1045 PR description / docs for the residual-risk statement and
27
+ * deployment guidance (a container with no egress, a network namespace).
28
+ * This function does not claim to close that gap.
29
+ *
30
+ * What does NOT run inside the child: fold (`tryFoldFile`, `../fold-import`)
31
+ * stays exactly where it is today, in the parent, unsandboxed — fold already
32
+ * executes zero of the file's own top-level code (chant #1022/#1023), so
33
+ * isolating it buys nothing and would only cost a bundle+spawn per build.
34
+ * Only genuine run-fallback files are handed to this function.
35
+ */
36
+ export interface SandboxRunResult {
37
+ /** Named, ref-resolved entities from the run-fallback set — decoded from the child's `EntitySetWire` response, functionally indistinguishable from what `importModule` + `collectEntities` + `resolveAttrRefs` would have produced in-process for this same file set (see `../entity-wire.ts`'s `decodeEntitySet` doc). */
38
+ entities: Map<string, Declarable>;
39
+ /** Import/collection/resolution/permission errors, already chant-shaped (see `./child-errors.ts` — a permission denial names the file and the operation, never a raw `ERR_ACCESS_DENIED`). */
40
+ errors: DiscoveryError[];
41
+ /** esbuild bundling wall-clock time — chant#1045 asks this be measured, not silently accepted. */
42
+ bundleMs: number;
43
+ /** Bundle size in bytes. */
44
+ bundleBytes: number;
45
+ /**
46
+ * Entity name → declaring file, for every entity in {@link entities} whose
47
+ * provenance (`../../provenance.ts`) named one. The wire format itself
48
+ * doesn't carry this (`encodeEntitySet` intentionally drops build metadata,
49
+ * not declared configuration) — it rides back as a small side channel so a
50
+ * parent-side merge collision against the fold-only set (a bare name
51
+ * genuinely exported by both a folded and a run-fallback file in the same
52
+ * directory) can name the real file, not the entity name. See `../index.ts`.
53
+ */
54
+ provenanceByName: Record<string, string>;
55
+ }
56
+ /**
57
+ * Run `files` (already decided "run" by `discover()`'s fold/taint pass)
58
+ * together, isolated, in one sandboxed child process. Returns the same
59
+ * `{ entities, errors }` shape the parent's own `collectEntities` +
60
+ * `resolveAttrRefs` would have — see `../index.ts`'s `discover()`, which
61
+ * merges this result into the entities it collected from folded files.
62
+ *
63
+ * @param files - Absolute paths to run-fallback files.
64
+ * @param buildRoot - The directory `discover()` was pointed at — threaded to
65
+ * `collectEntities` inside the child (stack-prefix disambiguation, #932)
66
+ * and used to compute the project-directory read allowance.
67
+ */
68
+ export declare function runFallbackFilesSandboxed(files: readonly string[], buildRoot: string): Promise<SandboxRunResult>;
69
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/discovery/sandbox/run.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAA2B,MAAM,cAAc,CAAC;AAMvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,2TAA2T;IAC3T,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,8LAA8L;IAC9L,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,kGAAkG;IAClG,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;;OAQG;IACH,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAgBD;;;;;;;;;;;GAWG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CAsC3B"}
package/dist/errors.d.ts CHANGED
@@ -1,7 +1,15 @@
1
1
  /**
2
2
  * Error types for chant discovery, build, and lint failures
3
3
  */
4
- export type DiscoveryErrorType = "import" | "resolution" | "circular";
4
+ /**
5
+ * `"permission"` (chant #1045 Phase 2) — a run-fallback file executing inside
6
+ * the sandboxed child (`./discovery/sandbox/`) hit Node's Permission Model
7
+ * (`ERR_ACCESS_DENIED`) — filesystem, child-process, or worker-thread access
8
+ * outside the sandbox's allowlist. Distinct from `"import"` (a module simply
9
+ * failed to load/execute for an ordinary reason) so a permission denial is
10
+ * recognizable as a sandbox boundary hit, not a generic import failure.
11
+ */
12
+ export type DiscoveryErrorType = "import" | "resolution" | "circular" | "permission";
5
13
  /**
6
14
  * Error during file discovery or module import
7
15
  */
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,YAAY,GAAG,UAAU,CAAC;AAEtE;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;gBAEtB,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB;IAOnE,MAAM;;;;;;CAQP;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAEhB,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAM/C,MAAM;;;;;CAOP;AAED;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM;IAUjB,MAAM;;;;;;;;CAUP"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,YAAY,CAAC;AAErF;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;gBAEtB,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB;IAOnE,MAAM;;;;;;CAQP;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAEhB,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAM/C,MAAM;;;;;CAOP;AAED;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM;IAUjB,MAAM;;;;;;;;CAUP"}