@supacloud/compiler 0.55.1 → 0.57.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.
@@ -0,0 +1,9 @@
1
+ import * as ts from "@supacloud/db/typescript";
2
+ import type { Diagnostic } from "./types";
3
+ interface GovernedClass {
4
+ declaration: ts.ClassDeclaration;
5
+ name: string;
6
+ }
7
+ /** A conservative source check for typed command references, not a JavaScript sandbox. */
8
+ export declare function scanCommandBoundaries(source: ts.SourceFile, file: string, checker: ts.TypeChecker, commands: readonly GovernedClass[], boundRoutes: ReadonlyMap<ts.MethodDeclaration, string>): Promise<Diagnostic[]>;
9
+ export {};
@@ -5,8 +5,8 @@ export interface DatabaseContractsOptions {
5
5
  outDir: string;
6
6
  /** Official PostgREST snapshot. Omit when the project does not use PostgREST. */
7
7
  postgrestTypes?: string;
8
- /** Drizzle query-builder module. Omit when the project does not use Drizzle. */
9
- drizzleSchema?: string;
8
+ /** ZenStack query-builder module. Omit when the project does not use ZenStack. */
9
+ modelSchema?: string;
10
10
  /** Explicit identity/role label for reviewing snapshot provenance. Not an authorization proof. */
11
11
  role: string;
12
12
  /** Role-scoped pg_graphql snapshot exported by graphql-schema. Omit when GraphQL is unused. */
@@ -23,6 +23,43 @@ var __esm = (fn, res, err) => () => {
23
23
  throw err[0];
24
24
  return res;
25
25
  };
26
+ var __dispose = Symbol.dispose || /* @__PURE__ */ Symbol.for("Symbol.dispose");
27
+ var __asyncDispose = Symbol.asyncDispose || /* @__PURE__ */ Symbol.for("Symbol.asyncDispose");
28
+ var __using = (stack, value, async) => {
29
+ if (value != null) {
30
+ if (typeof value !== "object" && typeof value !== "function")
31
+ throw TypeError('Object expected to be assigned to "using" declaration');
32
+ var dispose;
33
+ if (async)
34
+ dispose = value[__asyncDispose];
35
+ if (dispose === undefined)
36
+ dispose = value[__dispose];
37
+ if (typeof dispose !== "function")
38
+ throw TypeError("Object not disposable");
39
+ stack.push([async, dispose, value]);
40
+ } else if (async) {
41
+ stack.push([async]);
42
+ }
43
+ return value;
44
+ };
45
+ var __callDispose = (stack, error, hasError) => {
46
+ var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
47
+ return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
48
+ }, fail = (e) => error = hasError ? new E(e, error, "An error was suppressed during disposal") : (hasError = true, e), next = (it) => {
49
+ while (it = stack.pop()) {
50
+ try {
51
+ var result = it[1] && it[1].call(it[2]);
52
+ if (it[0])
53
+ return Promise.resolve(result).then(next, (e) => (fail(e), next()));
54
+ } catch (e) {
55
+ fail(e);
56
+ }
57
+ }
58
+ if (hasError)
59
+ throw error;
60
+ };
61
+ return next();
62
+ };
26
63
 
27
64
  // node_modules/typebox/build/system/arguments/arguments.mjs
28
65
  function Match(args, match) {
@@ -10513,88 +10550,91 @@ init_delivery_files2();
10513
10550
  import { isBuiltin } from "node:module";
10514
10551
  import { readFile as readFile2 } from "node:fs/promises";
10515
10552
  import { join as join2, resolve as resolve3 } from "node:path";
10516
- import * as ts2 from "@typescript/typescript6";
10553
+ import * as ts2 from "@supacloud/db/typescript";
10517
10554
 
10518
10555
  // src/delivery-imports.ts
10519
- import * as ts from "@typescript/typescript6";
10520
- function staticDeliveryImports(path, contents) {
10521
- if (!/\.[cm]?[jt]sx?$/.test(path))
10522
- return contents;
10523
- const source = ts.createSourceFile(path, new TextDecoder().decode(contents), ts.ScriptTarget.Latest, true);
10524
- const computed = [];
10525
- function scan(node) {
10526
- if (ts.isCallExpression(node) && (node.expression.kind === ts.SyntaxKind.ImportKeyword || ts.isIdentifier(node.expression) && node.expression.text === "require")) {
10527
- const argument = node.arguments[0];
10528
- if (!argument || !ts.isStringLiteral(argument) && !ts.isNoSubstitutionTemplateLiteral(argument))
10529
- computed.push(node);
10530
- }
10531
- ts.forEachChild(node, scan);
10532
- }
10533
- scan(source);
10534
- if (computed.length === 0)
10535
- return contents;
10536
- const reject = () => {
10537
- throw new Error("Computed module loading is not supported in independent delivery bundles.");
10538
- };
10539
- if (!ts.isExternalModule(source))
10540
- return reject();
10541
- const host = ts.createCompilerHost({ noLib: true, noResolve: true, allowJs: true });
10542
- host.getSourceFile = (name) => name === path ? source : undefined;
10543
- const checker = ts.createProgram([path], { noLib: true, noResolve: true, allowJs: true }, host).getTypeChecker();
10544
- const replacements = new Map;
10545
- const removed = new Set;
10546
- for (const call of computed) {
10547
- let visit = function(node) {
10548
- const referenced = ts.isIdentifier(node) ? ts.isShorthandPropertyAssignment(node.parent) ? checker.getShorthandAssignmentValueSymbol(node.parent) : ts.isExportSpecifier(node.parent) ? checker.getExportSpecifierLocalTargetSymbol(node.parent) : checker.getSymbolAtLocation(node) : undefined;
10549
- if (ts.isIdentifier(node) && node !== declarationName && referenced === symbol) {
10550
- const use = node.parent;
10551
- if (!ts.isCallExpression(use) || use.expression !== node || use.arguments.length !== 1 || use.questionDotToken || use.typeArguments?.length)
10552
- return reject();
10553
- const value = use.arguments[0];
10554
- if (!value || !ts.isStringLiteral(value) && !ts.isNoSubstitutionTemplateLiteral(value))
10555
- return reject();
10556
- references++;
10557
- replacements.set(use, ts.factory.createCallExpression(call.expression, undefined, [value]));
10556
+ import * as ts from "@supacloud/db/typescript";
10557
+ async function staticDeliveryImports(path, contents) {
10558
+ let __stack = [];
10559
+ try {
10560
+ if (!/\.[cm]?[jt]sx?$/.test(path))
10561
+ return contents;
10562
+ const syntax = await ts.createSourceFile(path, new TextDecoder().decode(contents));
10563
+ let source = syntax;
10564
+ const computed = [];
10565
+ function scan(node) {
10566
+ if (ts.isCallExpression(node) && (node.expression.kind === ts.SyntaxKind.ImportKeyword || ts.isIdentifier(node.expression) && node.expression.text === "require")) {
10567
+ const argument = node.arguments[0];
10568
+ if (!argument || !ts.isStringLiteral(argument) && !ts.isNoSubstitutionTemplateLiteral(argument))
10569
+ computed.push(node);
10558
10570
  }
10559
- ts.forEachChild(node, visit);
10571
+ ts.forEachChild(node, scan);
10572
+ }
10573
+ scan(source);
10574
+ if (computed.length === 0)
10575
+ return contents;
10576
+ const reject = () => {
10577
+ throw new Error("Computed module loading is not supported in independent delivery bundles.");
10560
10578
  };
10561
- const statement = call.parent;
10562
- const block = statement.parent;
10563
- const declaration = block.parent;
10564
- if (call.expression.kind !== ts.SyntaxKind.ImportKeyword || call.arguments.length !== 1 || !ts.isReturnStatement(statement) || !ts.isBlock(block) || block.statements.length !== 1 || !ts.isFunctionDeclaration(declaration) || declaration.parent !== source || !declaration.name || declaration.modifiers?.length || declaration.asteriskToken || declaration.typeParameters?.length || declaration.parameters.length !== 1)
10565
- return reject();
10566
- const parameter = declaration.parameters[0];
10567
- const argument = call.arguments[0];
10568
- if (!parameter || !ts.isIdentifier(parameter.name) || parameter.initializer || parameter.dotDotDotToken || !argument || !ts.isIdentifier(argument) || checker.getSymbolAtLocation(argument) !== checker.getSymbolAtLocation(parameter.name))
10569
- return reject();
10570
- const symbol = checker.getSymbolAtLocation(declaration.name);
10571
- if (!symbol || symbol.declarations?.length !== 1)
10579
+ if (!ts.isExternalModule(source))
10572
10580
  return reject();
10573
- const declarationName = declaration.name;
10574
- let references = 0;
10575
- visit(source);
10576
- if (references === 0)
10577
- return reject();
10578
- removed.add(declaration);
10579
- }
10580
- const transformed = ts.transform(source, [(context) => {
10581
- const visit = (node) => {
10582
- if (ts.isFunctionDeclaration(node) && removed.has(node))
10583
- return;
10584
- const replacement = ts.isCallExpression(node) ? replacements.get(node) : undefined;
10585
- if (replacement)
10586
- return replacement;
10587
- return ts.visitEachChild(node, visit, context);
10588
- };
10589
- return (node) => ts.visitNode(node, visit, ts.isSourceFile) ?? node;
10590
- }]);
10591
- try {
10592
- const transformedSource = transformed.transformed[0];
10593
- if (!transformedSource)
10581
+ const program = __using(__stack, await ts.createProgram([path], { noLib: true, noResolve: true, allowJs: true }, { sources: new Map([[path, source.text]]) }), 1);
10582
+ const boundSource = program.getSourceFile(path);
10583
+ if (!boundSource)
10594
10584
  return reject();
10595
- return new TextEncoder().encode(ts.createPrinter().printFile(transformedSource));
10585
+ computed.length = 0;
10586
+ source = boundSource;
10587
+ scan(source);
10588
+ const checker = program.getTypeChecker();
10589
+ const replacements = new Map;
10590
+ const removed = new Set;
10591
+ for (const call of computed) {
10592
+ const statement = call.parent;
10593
+ const block = statement.parent;
10594
+ const declaration = block.parent;
10595
+ if (call.expression.kind !== ts.SyntaxKind.ImportKeyword || call.arguments.length !== 1 || !ts.isReturnStatement(statement) || !ts.isBlock(block) || block.statements.length !== 1 || !ts.isFunctionDeclaration(declaration) || declaration.parent !== source || !declaration.name || declaration.modifiers?.length || declaration.asteriskToken || declaration.typeParameters?.length || declaration.parameters.length !== 1)
10596
+ return reject();
10597
+ const parameter = declaration.parameters[0];
10598
+ const argument = call.arguments[0];
10599
+ if (!parameter || !ts.isIdentifier(parameter.name) || parameter.initializer || parameter.dotDotDotToken || !argument || !ts.isIdentifier(argument) || await checker.getSymbolAtLocation(argument) !== await checker.getSymbolAtLocation(parameter.name))
10600
+ return reject();
10601
+ const symbol = await checker.getSymbolAtLocation(declaration.name);
10602
+ if (!symbol || symbol.declarations?.length !== 1)
10603
+ return reject();
10604
+ const declarationName = declaration.name;
10605
+ let references = 0;
10606
+ async function visit(node) {
10607
+ const referenced = ts.isIdentifier(node) ? ts.isShorthandPropertyAssignment(node.parent) ? await checker.getShorthandAssignmentValueSymbol(node.parent) : ts.isExportSpecifier(node.parent) ? await checker.getExportSpecifierLocalTargetSymbol(node.parent) : await checker.getSymbolAtLocation(node) : undefined;
10608
+ if (ts.isIdentifier(node) && node !== declarationName && referenced === symbol) {
10609
+ const use = node.parent;
10610
+ if (!ts.isCallExpression(use) || use.expression !== node || use.arguments.length !== 1 || use.questionDotToken || use.typeArguments?.length)
10611
+ return reject();
10612
+ const value = use.arguments[0];
10613
+ if (!value || !ts.isStringLiteral(value) && !ts.isNoSubstitutionTemplateLiteral(value))
10614
+ return reject();
10615
+ references++;
10616
+ replacements.set(use, `import(${value.getText(source)})`);
10617
+ }
10618
+ await ts.forEachChildAsync(node, visit);
10619
+ }
10620
+ await visit(source);
10621
+ if (references === 0)
10622
+ return reject();
10623
+ removed.add(declaration);
10624
+ }
10625
+ const edits = [
10626
+ ...[...removed].map((node) => ({ start: node.getStart(source), end: node.end, text: "" })),
10627
+ ...[...replacements].map(([node, text]) => ({ start: node.getStart(source), end: node.end, text }))
10628
+ ].sort((a, b) => b.start - a.start);
10629
+ let output = source.text;
10630
+ for (const edit of edits)
10631
+ output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);
10632
+ return new TextEncoder().encode(output);
10633
+ } catch (_catch) {
10634
+ var _err = _catch, _hasErr = 1;
10596
10635
  } finally {
10597
- transformed.dispose();
10636
+ var _promise = __callDispose(__stack, _err, _hasErr);
10637
+ _promise && await _promise;
10598
10638
  }
10599
10639
  }
10600
10640
 
@@ -10718,7 +10758,7 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
10718
10758
  return { contents: code, loader: "ts" };
10719
10759
  const bytes = await readFile2(args.path);
10720
10760
  inputs.set(resolve3(args.path), digest(bytes));
10721
- return { contents: staticDeliveryImports(args.path, bytes), loader: args.loader };
10761
+ return { contents: await staticDeliveryImports(args.path, bytes), loader: args.loader };
10722
10762
  });
10723
10763
  }
10724
10764
  }]
@@ -10746,7 +10786,7 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
10746
10786
  if (/\.[cm]?js$/.test(path)) {
10747
10787
  let check = function(node) {
10748
10788
  const specifier = ts2.isImportDeclaration(node) || ts2.isExportDeclaration(node) ? node.moduleSpecifier : ts2.isCallExpression(node) && (node.expression.kind === ts2.SyntaxKind.ImportKeyword || ts2.isIdentifier(node.expression) && /^(?:__)?require$/.test(node.expression.text) || ts2.isPropertyAccessExpression(node.expression) && node.expression.name.text === "require" && ts2.isMetaProperty(node.expression.expression) && node.expression.expression.keywordToken === ts2.SyntaxKind.ImportKeyword) ? node.arguments[0] : undefined;
10749
- if (specifier && ts2.isStringLiteralLike(specifier)) {
10789
+ if (specifier && ts2.isStringLiteralLikeNode(specifier)) {
10750
10790
  if (!isBuiltin(specifier.text) && specifier.text !== "bun" && !specifier.text.startsWith("bun:")) {
10751
10791
  throw new Error("Independent bundles cannot retain external package imports.");
10752
10792
  }
@@ -10754,7 +10794,7 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
10754
10794
  }
10755
10795
  ts2.forEachChild(node, check);
10756
10796
  };
10757
- const source = ts2.createSourceFile(path, new TextDecoder().decode(bytes), ts2.ScriptTarget.Latest, true);
10797
+ const source = await ts2.createSourceFile(path, new TextDecoder().decode(bytes), ts2.ScriptTarget.Latest, true);
10758
10798
  check(source);
10759
10799
  }
10760
10800
  files.set(`bundle/${path}`, bytes);
@@ -1,2 +1,2 @@
1
1
  /** Resolve private literal-only import wrappers without permitting an open dependency set. */
2
- export declare function staticDeliveryImports(path: string, contents: Uint8Array): Uint8Array;
2
+ export declare function staticDeliveryImports(path: string, contents: Uint8Array): Promise<Uint8Array>;
@@ -5,6 +5,7 @@ import { type GenerateOptions } from "./generate";
5
5
  export declare function renderDeliveryTarget(graph: ApplicationGraph, target: DeliveryTarget, options: GenerateOptions): {
6
6
  applicationCode: string;
7
7
  manifestJson: string;
8
+ executionPlan: import("./types").CompiledExecutionManifest;
8
9
  contractsManifestJson: string;
9
10
  clientCode?: string;
10
11
  openApiCode?: string;
@@ -0,0 +1,39 @@
1
+ import type { ApplicationGraph, ControllerNode, Diagnostic, ModuleNode, ProviderNode, Scope } from "./types";
2
+ export interface DependencyFlags {
3
+ self?: boolean;
4
+ skipSelf?: boolean;
5
+ }
6
+ export interface StaticProvider {
7
+ module: ModuleNode;
8
+ provider: ProviderNode;
9
+ }
10
+ export type DependencyResolution = {
11
+ kind: "provider";
12
+ relation: "local" | "imported" | "root";
13
+ target: StaticProvider;
14
+ } | {
15
+ kind: "context";
16
+ scope: "request" | "job";
17
+ } | {
18
+ kind: "external";
19
+ } | {
20
+ kind: "missing";
21
+ } | {
22
+ kind: "ambiguous";
23
+ candidates: StaticProvider[];
24
+ };
25
+ export declare function dependencyFlags(owner: Pick<ProviderNode | ControllerNode, "dependencyOptions" | "optionalDeps" | "selfDeps" | "skipSelfDeps" | "hostDeps">, token: string, index?: number): {
26
+ optional: boolean;
27
+ self: boolean;
28
+ skipSelf: boolean;
29
+ host: boolean;
30
+ };
31
+ /** Follow only explicit public exports; a diamond preserves the original instance. */
32
+ export declare function exportedProviders(graph: ApplicationGraph, module: ModuleNode, token: string, seen?: Set<string>): StaticProvider[];
33
+ /** One compile-time resolution rule for validation, generated factories and manifests. */
34
+ export declare function resolveDependency(graph: ApplicationGraph, module: ModuleNode, token: string, scope?: Scope, flags?: DependencyFlags): DependencyResolution;
35
+ /** Includes implicit root dependencies required before a module factory can run. */
36
+ export declare function moduleDependencies(graph: ApplicationGraph, module: ModuleNode): string[];
37
+ export declare function scopeCanDependOn(owner: Scope, dependency: Scope): boolean;
38
+ /** Invalid static wiring never becomes an executable artifact, including writeOnError. */
39
+ export declare function blocksStaticCompilation(diagnostic: Diagnostic): boolean;
@@ -23,6 +23,43 @@ var __esm = (fn, res, err) => () => {
23
23
  throw err[0];
24
24
  return res;
25
25
  };
26
+ var __dispose = Symbol.dispose || /* @__PURE__ */ Symbol.for("Symbol.dispose");
27
+ var __asyncDispose = Symbol.asyncDispose || /* @__PURE__ */ Symbol.for("Symbol.asyncDispose");
28
+ var __using = (stack, value, async) => {
29
+ if (value != null) {
30
+ if (typeof value !== "object" && typeof value !== "function")
31
+ throw TypeError('Object expected to be assigned to "using" declaration');
32
+ var dispose;
33
+ if (async)
34
+ dispose = value[__asyncDispose];
35
+ if (dispose === undefined)
36
+ dispose = value[__dispose];
37
+ if (typeof dispose !== "function")
38
+ throw TypeError("Object not disposable");
39
+ stack.push([async, dispose, value]);
40
+ } else if (async) {
41
+ stack.push([async]);
42
+ }
43
+ return value;
44
+ };
45
+ var __callDispose = (stack, error, hasError) => {
46
+ var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
47
+ return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
48
+ }, fail = (e) => error = hasError ? new E(e, error, "An error was suppressed during disposal") : (hasError = true, e), next = (it) => {
49
+ while (it = stack.pop()) {
50
+ try {
51
+ var result = it[1] && it[1].call(it[2]);
52
+ if (it[0])
53
+ return Promise.resolve(result).then(next, (e) => (fail(e), next()));
54
+ } catch (e) {
55
+ fail(e);
56
+ }
57
+ }
58
+ if (hasError)
59
+ throw error;
60
+ };
61
+ return next();
62
+ };
26
63
 
27
64
  // src/repair-plan.ts
28
65
  function createDiagnosticRepairPlan(diagnostics) {
@@ -71,7 +108,7 @@ function classifyFix(fix) {
71
108
  import { createHash, randomUUID } from "node:crypto";
72
109
  import { lstat, readFile, realpath, rename, unlink, writeFile } from "node:fs/promises";
73
110
  import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
74
- import * as ts from "@typescript/typescript6";
111
+ import * as ts from "@supacloud/db/typescript";
75
112
  async function applyDiagnosticFix(fix, options = {}) {
76
113
  if (!fix || typeof fix.targetFile !== "string")
77
114
  throw new Error("Invalid DiagnosticFix");
@@ -88,7 +125,8 @@ async function applyDiagnosticFix(fix, options = {}) {
88
125
  if (options.expectedSourceHash !== undefined && options.expectedSourceHash !== sourceHash) {
89
126
  throw new Error("Fix source changed since preview; analyze the project again");
90
127
  }
91
- let source = parse(file, original);
128
+ const originalSource = await parse(file, original);
129
+ let source = originalSource;
92
130
  let content;
93
131
  switch (fix.type) {
94
132
  case "set_command_mode": {
@@ -100,15 +138,16 @@ async function applyDiagnosticFix(fix, options = {}) {
100
138
  if (!current || current.initializer.getText(source) !== fix.expectedExpression) {
101
139
  throw new Error("Command mode changed since diagnosis; analyze the project again");
102
140
  }
103
- content = replaceProperty(source, object, fix.property, ts.factory.createStringLiteral(fix.value));
141
+ content = await replaceProperty(source, object, fix.property, ts.factory.createStringLiteral(fix.value, ts.TokenFlags.None));
104
142
  break;
105
143
  }
106
144
  case "add_module_import": {
107
145
  if (!fix.importPath || !fix.symbol)
108
146
  throw new Error("Module fix requires importPath and symbol");
109
147
  identifier(fix.symbol);
110
- const withImport = importSymbol(source, fix.importPath, fix.symbol);
111
- source = parse(file, withImport);
148
+ const withImport = await importSymbol(source, fix.importPath, fix.symbol);
149
+ const importedSource = await parse(file, withImport);
150
+ source = importedSource;
112
151
  const object = unique(moduleObjects(source).filter((candidate) => !fix.targetModule || stringProperty(candidate, "name") === fix.targetModule), "target module");
113
152
  const imports = property(object, "imports");
114
153
  if (imports && !ts.isArrayLiteralExpression(imports.initializer)) {
@@ -117,7 +156,7 @@ async function applyDiagnosticFix(fix, options = {}) {
117
156
  const values = imports && ts.isArrayLiteralExpression(imports.initializer) ? imports.initializer.elements : [];
118
157
  if (values.some(ts.isSpreadElement))
119
158
  throw new Error("Module imports cannot contain spread elements");
120
- content = values.some((value) => ts.isIdentifier(value) && value.text === fix.symbol) ? withImport : replaceProperty(source, object, "imports", ts.factory.createArrayLiteralExpression([
159
+ content = values.some((value) => ts.isIdentifier(value) && value.text === fix.symbol) ? withImport : await replaceProperty(source, object, "imports", ts.factory.createArrayLiteralExpression([
121
160
  ...values,
122
161
  ts.factory.createIdentifier(fix.symbol)
123
162
  ]));
@@ -134,7 +173,7 @@ async function applyDiagnosticFix(fix, options = {}) {
134
173
  if (current && (!ts.isStringLiteral(current.initializer) || current.initializer.text !== permission)) {
135
174
  throw new Error("Command permission already exists with a different value");
136
175
  }
137
- content = current ? original : replaceProperty(source, object, "permission", ts.factory.createStringLiteral(permission));
176
+ content = current ? original : await replaceProperty(source, object, "permission", ts.factory.createStringLiteral(permission, ts.TokenFlags.None));
138
177
  break;
139
178
  }
140
179
  case "add_route_parameter_binding": {
@@ -152,13 +191,14 @@ async function applyDiagnosticFix(fix, options = {}) {
152
191
  throw new Error("Framework import must be static");
153
192
  }
154
193
  const edited = original.slice(0, parameter.getStart(source)) + `@${binding}(${JSON.stringify(fix.parameter)}) ` + original.slice(parameter.getStart(source));
155
- content = importSymbol(parse(file, edited), framework.moduleSpecifier.text, binding);
194
+ const editedSource = await parse(file, edited);
195
+ content = await importSymbol(editedSource, framework.moduleSpecifier.text, binding);
156
196
  break;
157
197
  }
158
198
  default:
159
199
  throw new Error(`Diagnostic fix '${fix.type}' requires a manual semantic decision; no files changed`);
160
200
  }
161
- parse(file, content);
201
+ await parse(file, content);
162
202
  const result = { file, changed: content !== original, content, sourceHash };
163
203
  if (options.dryRun === false && result.changed) {
164
204
  const temporary = `${file}.supacloud-fix-${randomUUID()}`;
@@ -173,8 +213,8 @@ async function applyDiagnosticFix(fix, options = {}) {
173
213
  }
174
214
  return result;
175
215
  }
176
- function parse(file, text) {
177
- const result = ts.transpileModule(text, {
216
+ async function parse(file, text) {
217
+ const result = await ts.transpileModule(text, {
178
218
  fileName: file,
179
219
  reportDiagnostics: true,
180
220
  compilerOptions: { target: ts.ScriptTarget.ESNext, experimentalDecorators: true }
@@ -182,7 +222,7 @@ function parse(file, text) {
182
222
  if (result.diagnostics?.some((item) => item.category === ts.DiagnosticCategory.Error)) {
183
223
  throw new Error("Cannot fix syntactically invalid TypeScript");
184
224
  }
185
- return ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
225
+ return await ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
186
226
  }
187
227
  function unique(items, description) {
188
228
  const [item] = items;
@@ -213,14 +253,14 @@ function stringProperty(object, key) {
213
253
  const value = property(object, key)?.initializer;
214
254
  return value && ts.isStringLiteral(value) ? value.text : undefined;
215
255
  }
216
- function replaceProperty(source, object, key, value) {
256
+ async function replaceProperty(source, object, key, value) {
217
257
  const previous = property(object, key);
218
- const replacement = ts.factory.createPropertyAssignment(key, value);
219
- const properties = object.properties.map((item) => item === previous ? replacement : item);
220
- if (!previous)
221
- properties.push(replacement);
222
- const updated = ts.factory.updateObjectLiteralExpression(object, properties);
223
- return source.text.slice(0, object.getStart(source)) + ts.createPrinter().printNode(ts.EmitHint.Expression, updated, source) + source.text.slice(object.end);
258
+ const text = await ts.printNode(value);
259
+ if (previous)
260
+ return source.text.slice(0, previous.initializer.getStart(source)) + text + source.text.slice(previous.initializer.end);
261
+ const position = object.end - 1;
262
+ const separator = object.properties.length && !object.properties.hasTrailingComma ? "," : "";
263
+ return source.text.slice(0, position) + `${separator} ${key}: ${text}` + source.text.slice(position);
224
264
  }
225
265
  function findClass(source, name) {
226
266
  return unique(source.statements.filter((statement) => ts.isClassDeclaration(statement) && statement.name?.text === name), `class '${name}'`);
@@ -249,7 +289,7 @@ function moduleObjects(source) {
249
289
  }
250
290
  return result;
251
291
  }
252
- function importSymbol(source, path, symbol) {
292
+ async function importSymbol(source, path, symbol) {
253
293
  identifier(symbol);
254
294
  const current = resolve(source.fileName).replace(/\.(tsx?|mts|cts)$/, "");
255
295
  const target = resolve(dirname(source.fileName), path).replace(/\.(tsx?|mts|cts)$/, "");
@@ -259,7 +299,7 @@ function importSymbol(source, path, symbol) {
259
299
  if (matches.length > 1)
260
300
  throw new Error(`Ambiguous imports from '${path}'`);
261
301
  const match = matches[0];
262
- if (match && ts.isImportDeclaration(match) && match.importClause?.namedBindings && ts.isNamedImports(match.importClause.namedBindings) && !match.importClause.isTypeOnly) {
302
+ if (match && ts.isImportDeclaration(match) && match.importClause?.namedBindings && ts.isNamedImports(match.importClause.namedBindings) && match.importClause.phaseModifier !== ts.SyntaxKind.TypeKeyword) {
263
303
  if (match.importClause.namedBindings.elements.some((item) => item.name.text === symbol))
264
304
  return source.text;
265
305
  const bindings = match.importClause.namedBindings;
@@ -267,7 +307,7 @@ function importSymbol(source, path, symbol) {
267
307
  ...bindings.elements,
268
308
  ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(symbol))
269
309
  ]);
270
- return source.text.slice(0, bindings.getStart(source)) + ts.createPrinter().printNode(ts.EmitHint.Unspecified, updated, source) + source.text.slice(bindings.end);
310
+ return source.text.slice(0, bindings.getStart(source)) + await ts.printNode(updated) + source.text.slice(bindings.end);
271
311
  }
272
312
  if (match)
273
313
  throw new Error(`Import from '${path}' is not a named value import`);
@@ -0,0 +1,8 @@
1
+ import type { CommandExecutionCapabilities, CompiledExecutionManifest, Diagnostic } from "./types";
2
+ /** Internal delivery error; the public validator returns structured diagnostics. */
3
+ export declare class ExecutionManifestValidationError extends Error {
4
+ readonly diagnostics: Diagnostic[];
5
+ constructor(diagnostics: Diagnostic[]);
6
+ }
7
+ /** Validate a compiler-produced plan against deployment declarations, never runtime attestations. */
8
+ export declare function validateExecutionManifest(plan: CompiledExecutionManifest, capabilities?: CommandExecutionCapabilities): Diagnostic[];
@@ -1,5 +1,5 @@
1
- import type { ApplicationGraph, OpenApiOptions } from "./types";
2
- export interface GenerateOptions {
1
+ import type { ApplicationGraph, CompiledExecutionManifest, OpenApiOptions, ValidateOptions } from "./types";
2
+ export interface GenerateOptions extends Pick<ValidateOptions, "moduleBoundaryPreset" | "moduleBoundaries" | "commandCapabilities"> {
3
3
  rootDir: string;
4
4
  outDir: string;
5
5
  generateClient?: boolean;
@@ -14,6 +14,7 @@ export interface GenerateOptions {
14
14
  export interface RenderedArtifacts {
15
15
  applicationCode: string;
16
16
  manifestJson: string;
17
+ executionPlan: CompiledExecutionManifest;
17
18
  contractsManifestJson: string;
18
19
  clientCode?: string;
19
20
  openApiCode?: string;
@@ -3,4 +3,4 @@
3
3
  * selections, fragments and conditional fields. Unsupported wire types fail closed.
4
4
  */
5
5
  export type GraphqlOperationKind = "query" | "mutation";
6
- export declare function renderGraphqlValidators(source: string, operationNames: readonly string[], operationKinds?: ReadonlyMap<string, GraphqlOperationKind>): string;
6
+ export declare function renderGraphqlValidators(source: string, operationNames: readonly string[], operationKinds?: ReadonlyMap<string, GraphqlOperationKind>): Promise<string>;
@@ -1,6 +1,6 @@
1
- import * as ts from "@typescript/typescript6";
1
+ import * as ts from "@supacloud/db/typescript";
2
2
  import type { SourceMigrationResult } from "./migrations";
3
3
  import type { Diagnostic } from "./types";
4
4
  /** Never replaces the root array helper in constructor/custom pipeline usages. */
5
- export declare function migrateHttpProviderImports(source: string, fileName: string): SourceMigrationResult;
6
- export declare function scanHttpProviderImports(source: ts.SourceFile, file: string): Diagnostic[];
5
+ export declare function migrateHttpProviderImports(source: string, fileName: string): Promise<SourceMigrationResult>;
6
+ export declare function scanHttpProviderImports(source: ts.SourceFile, file: string): Promise<Diagnostic[]>;
@@ -4,7 +4,7 @@ export interface IncrementalCompileResult extends CompileResult {
4
4
  }
5
5
  export interface IncrementalCompiler {
6
6
  compile(options: CompileOptions, changedPaths?: string[]): Promise<IncrementalCompileResult>;
7
- reset(): void;
7
+ reset(): Promise<void>;
8
8
  getCache?(): DependencyGraphCache;
9
9
  }
10
10
  export declare function createDependencyGraphCache(): DependencyGraphCache;
package/dist/index.d.ts CHANGED
@@ -38,6 +38,7 @@ export { TraitCompiler } from "./traits";
38
38
  export type { TraitCompilation, TraitHandler, TraitKind, TraitRecord } from "./traits";
39
39
  export { generateApplication, renderApplication, renderClient, renderOpenApi } from "./generate";
40
40
  export type { GenerateOptions, RenderedArtifacts } from "./generate";
41
+ export { validateExecutionManifest } from "./execution-manifest";
41
42
  export { buildContractManifest } from "./contract-manifest";
42
43
  export type { ContractManifest } from "./contract-manifest";
43
44
  export { diffOpenApiDocuments, exportGeneratedOpenApiJson, formatOpenApiDiff, loadGeneratedOpenApiDocument, parseOpenApiDocument, readOpenApiJson, serializeOpenApiJson, writeOpenApiJson, OpenApiDocumentError, } from "./openapi-tools";
@@ -47,12 +48,12 @@ export type { MigrateFileResult, MigrateProjectOptions, MigrateProjectResult, So
47
48
  export { validateGraph, COMPILER_DIAGNOSTIC_CODES } from "./validate";
48
49
  export { scanGeneratedArtifacts, scanProductionSource, TYPE_SAFETY_DIAGNOSTIC_CODES } from "./type-safety";
49
50
  export type { TypeSafetyScanOptions } from "./type-safety";
50
- export { scanDrizzleSql, SQL_SAFETY_DIAGNOSTIC_CODES } from "./sql-safety";
51
+ export { scanQuerySql, SQL_SAFETY_DIAGNOSTIC_CODES } from "./sql-safety";
51
52
  export { DEFAULT_SUPACLOUD_CONFIG, compileOptionsFromConfig, defineSupacloudConfig, loadSupacloudConfig, resolveSupacloudConfig, } from "./config";
52
53
  export type { SupaCloudConfig } from "./config";
53
54
  export { camelName } from "./util";
54
55
  export { ANGULAR_ENTERPRISE_RULES, CLEAN_ARCHITECTURE_RULES, MODULAR_MONOLITH_RULES, MODULE_BOUNDARY_PROFILES, getModuleBoundaryPreset, getModuleBoundaryProfile, resolveModuleBoundaries, } from "./profiles";
55
- export type { ApplicationGraph, AspectRefNode, CachedModuleEntry, CheckProjectResult, CommandExecutionCapabilities, CommandNode, CompileOptions, DatabaseGovernanceOptions, CompileResult, CompileStats, ControllerNode, DependencyGraphCache, DependencyGraphIndex, Diagnostic, DiagnosticFix, EffectCompilerOptions, EffectErrorMappingNode, EffectRetryPolicy, EffectRouteNode, ModuleBoundaryPresetName, ModuleBoundaryProfile, ModuleBoundaryRule, ModuleNode, JobNode, ProviderKind, ProviderNode, QueryNode, RouteNode, Scope, TokenKind, TypeSafetyOptions, ValidateOptions, WatchEvent, WatchHandle, WatchOptions, FeatureSpecNode, FeatureTransitionNode, FeatureDatabaseSourceNode, FeaturePersistenceNode, GraphqlOptions, GraphqlContractSummary, OpenApiOptions, OpenApiSecurityScheme, OpenApiServer, } from "./types";
56
+ export type { ApplicationGraph, AspectRefNode, CachedModuleEntry, CheckProjectResult, CommandExecutionCapabilities, CommandNode, CompileOptions, DatabaseGovernanceOptions, CompileResult, CompileStats, CompiledExecutionManifest, ExecutionPlanCommand, ExecutionPlanJob, ExecutionPlanModule, ExecutionPlanProvider, ExecutionPlanProviderEdge, ExecutionPlanRoute, ControllerNode, DependencyGraphCache, DependencyOptions, DependencyGraphIndex, Diagnostic, DiagnosticFix, EffectCompilerOptions, EffectErrorMappingNode, EffectRetryPolicy, EffectRouteNode, ModuleBoundaryPresetName, ModuleBoundaryProfile, ModuleBoundaryRule, ModuleNode, JobNode, ProviderKind, ProviderNode, QueryNode, RouteNode, Scope, TokenKind, TypeSafetyOptions, ValidateOptions, WatchEvent, WatchHandle, WatchOptions, FeatureSpecNode, FeatureTransitionNode, FeatureDatabaseSourceNode, FeaturePersistenceNode, GraphqlOptions, GraphqlContractSummary, OpenApiOptions, OpenApiSecurityScheme, OpenApiServer, } from "./types";
56
57
  export { inspectRouteContracts, validateRouteContracts } from "./route-contracts";
57
58
  export { validateEffectPolicies, validateJobPolicies } from "./effect-governance";
58
59
  export { pullGraphqlSchema } from "./graphql-schema";