@supacloud/compiler 0.9.0 → 0.11.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.
package/README.md CHANGED
@@ -12,6 +12,11 @@ bun add @supacloud/compiler
12
12
 
13
13
  ## 零配置项目
14
14
 
15
+ 需要完整运行入口时,使用 `supacloud-cli app init --root ./orders --name orders`。
16
+ 模板将本包放在 `devDependencies`,预置状态规格、治理能力、类型检查和本地测试。
17
+ 编译产物的 HTTP method / scope 保留字面量联合类型,可直接传给 Elysia 适配器;
18
+ 跨运行时依赖字典使用构造器/工厂参数类型连接,局部依赖保留类型推断和错误检查。
19
+
15
20
  在项目根目录执行:
16
21
 
17
22
  ```bash
@@ -252,6 +257,24 @@ bun test
252
257
  bun run build
253
258
  ```
254
259
 
260
+ ## Route Contract Policy
261
+
262
+ Enable `requireRouteContracts: true` in `defineSupacloudConfig(...)` or
263
+ `CompileOptions` to report `route-contract-required` errors in both compile and
264
+ check (including JSON diagnostics). Changing this option invalidates incremental
265
+ results. Combine it with `writeOnError: false` when programmatic compilation must
266
+ not emit files on errors.
267
+
268
+ `inspectRouteContracts(graph)` lists each route and its missing body, params,
269
+ query, and response declarations. Required inputs are detected from handler
270
+ bindings and controller/route path parameters. Responses always require an
271
+ explicit declaration, including intentional void contracts.
272
+
273
+ This checks declaration coverage only, not schema quality, handler/schema type
274
+ equivalence, or database authorization. It deliberately does not auto-fix missing
275
+ schemas with `unknown` placeholders. Consumers must define the actual contracts
276
+ and test decoding separately. The policy defaults to false for existing projects.
277
+
255
278
  ## License
256
279
 
257
280
  MIT
package/dist/cli.js CHANGED
@@ -2264,7 +2264,7 @@ import { access, mkdir, rename, unlink, writeFile } from "node:fs/promises";
2264
2264
  import { join as join2 } from "node:path";
2265
2265
  var HEADER = "// GENERATED BY @supacloud/compiler — do not edit";
2266
2266
  var INTERFACES = `export interface CompiledRoute {
2267
- method: string;
2267
+ method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
2268
2268
  path: string;
2269
2269
  handler: string;
2270
2270
  body?: unknown;
@@ -2335,7 +2335,7 @@ export type CompiledAspect = (
2335
2335
  export interface CompiledController {
2336
2336
  path: string;
2337
2337
  serviceKey: string;
2338
- scope: string;
2338
+ scope: "application" | "request" | "job";
2339
2339
  routes: CompiledRoute[];
2340
2340
  }
2341
2341
 
@@ -2949,7 +2949,7 @@ ${indent(item, 2)}`).join(",")}
2949
2949
  switch (provider.kind) {
2950
2950
  case "class": {
2951
2951
  const useClass = this.imports.add(provider.useClass ?? provider.token, provider.importPath, provider.importModule);
2952
- const args = provider.deps.map((dep) => this.depExpr(dep, kind, this.depOptions(provider, dep))).join(", ");
2952
+ const args = provider.deps.map((dep, index) => this.typedDepExpr(dep, kind, this.depOptions(provider, dep), `ConstructorParameters<typeof ${useClass}>[${index}]`)).join(", ");
2953
2953
  const local = this.localVar(isMulti ? provider.useClass ?? `${provider.token}Item` : provider.token, kind);
2954
2954
  return {
2955
2955
  constLine: `const ${local} = ${this.instantiate(useClass, args, kind, provider.functionalInjects)};`,
@@ -2970,7 +2970,7 @@ ${indent(item, 2)}`).join(",")}
2970
2970
  return { constLine, key, expr: local2 };
2971
2971
  }
2972
2972
  const factory = this.imports.add(provider.useFactoryName ?? "", provider.importPath, provider.importModule);
2973
- const args = provider.deps.map((dep) => this.depExpr(dep, kind, this.depOptions(provider, dep))).join(", ");
2973
+ const args = provider.deps.map((dep, index) => this.typedDepExpr(dep, kind, this.depOptions(provider, dep), `Parameters<typeof ${factory}>[${index}]`)).join(", ");
2974
2974
  const local = this.localVar(isMulti ? provider.useFactoryName ?? `${provider.token}Item` : provider.token, kind);
2975
2975
  return { constLine: `const ${local} = ${factory}(${args});`, key, expr: local };
2976
2976
  }
@@ -2984,7 +2984,7 @@ ${indent(item, 2)}`).join(",")}
2984
2984
  }
2985
2985
  emitController(controller, kind) {
2986
2986
  const className = this.imports.add(controller.className, controller.importPath);
2987
- const args = controller.deps.map((dep) => this.depExpr(dep, kind, this.depOptions(controller, dep))).join(", ");
2987
+ const args = controller.deps.map((dep, index) => this.typedDepExpr(dep, kind, this.depOptions(controller, dep), `ConstructorParameters<typeof ${className}>[${index}]`)).join(", ");
2988
2988
  const key = camelName(controller.className);
2989
2989
  const local = this.localVar(controller.className, kind);
2990
2990
  return {
@@ -3042,6 +3042,13 @@ ${indent(item, 2)}`).join(",")}
3042
3042
  host: "hostDeps" in node ? node.hostDeps?.includes(token) ?? false : false
3043
3043
  };
3044
3044
  }
3045
+ typedDepExpr(token, kind, options, type) {
3046
+ const expression = this.depExpr(token, kind, options);
3047
+ const localProvider = this.module.providers.find((provider) => this.locals[kind].get(provider.token) === expression);
3048
+ if (expression === "undefined" || localProvider && !(localProvider.kind === "factory" && !localProvider.useFactoryName))
3049
+ return expression;
3050
+ return `${expression} as ${type}`;
3051
+ }
3045
3052
  depExpr(token, kind, options = {}) {
3046
3053
  const isOptional = options.optional ?? false;
3047
3054
  const isSelf = options.self ?? false;
@@ -4675,6 +4682,39 @@ function isAnyKeyword(node) {
4675
4682
  return node.kind === ts4.SyntaxKind.AnyKeyword;
4676
4683
  }
4677
4684
 
4685
+ // src/route-contracts.ts
4686
+ function inspectRouteContracts(graph) {
4687
+ return graph.modules.flatMap((module) => module.controllers.flatMap((controller) => controller.routes.map((route) => {
4688
+ const missing = [];
4689
+ if ((route.hasBodyBinding || route.handlerParams?.some((param) => param.kind === "body")) && !route.body)
4690
+ missing.push("body");
4691
+ if ((route.pathParams?.length || route.paramBindings?.length || route.handlerParams?.some((param) => param.kind === "param") || /:[^/]+/.test(`${controller.path}/${route.path}`)) && !route.params)
4692
+ missing.push("params");
4693
+ if ((route.queryBindings?.length || route.handlerParams?.some((param) => param.kind === "query")) && !route.query)
4694
+ missing.push("query");
4695
+ if (!route.response)
4696
+ missing.push("response");
4697
+ return {
4698
+ module: module.name,
4699
+ controller: controller.className,
4700
+ handler: route.handler,
4701
+ method: route.method,
4702
+ path: `${controller.path}${route.path}`,
4703
+ file: controller.file,
4704
+ missing
4705
+ };
4706
+ })));
4707
+ }
4708
+ function validateRouteContracts(graph) {
4709
+ return inspectRouteContracts(graph).filter((route) => route.missing.length).map((route) => ({
4710
+ severity: "error",
4711
+ code: "route-contract-required",
4712
+ file: route.file,
4713
+ message: `${route.controller}.${route.handler} (${route.method} ${route.path}) is missing contract declarations: ${route.missing.join(", ")}.`,
4714
+ suggestion: "Declare the missing schemas and test actual request/response decoding. An opaque schema is not proof of validation."
4715
+ }));
4716
+ }
4717
+
4678
4718
  // src/compile.ts
4679
4719
  async function compileProject(options) {
4680
4720
  const graph = await analyzeProject(options.rootDir, options.include, options.cache, options.changedPaths);
@@ -4697,6 +4737,8 @@ async function compileProject(options) {
4697
4737
  }
4698
4738
  }
4699
4739
  const typeSafety = resolveTypeSafety(options);
4740
+ if (options.requireRouteContracts)
4741
+ diagnostics.push(...validateRouteContracts(graph));
4700
4742
  const rendered = renderApplication(graph, {
4701
4743
  rootDir: options.rootDir,
4702
4744
  outDir: options.outDir,
@@ -4760,6 +4802,8 @@ async function checkProject(options) {
4760
4802
  }
4761
4803
  }
4762
4804
  const typeSafety = resolveTypeSafety(options);
4805
+ if (options.requireRouteContracts)
4806
+ diagnostics.push(...validateRouteContracts(graph));
4763
4807
  const rendered = renderApplication(graph, {
4764
4808
  rootDir: options.rootDir,
4765
4809
  outDir: options.outDir,
@@ -5137,6 +5181,7 @@ function optionsKeyOf(options) {
5137
5181
  allowRouteCommandBindings: options.allowRouteCommandBindings,
5138
5182
  commandCapabilities: options.commandCapabilities,
5139
5183
  disallowControllerDirectDb: options.disallowControllerDirectDb,
5184
+ requireRouteContracts: options.requireRouteContracts,
5140
5185
  detectOrphanModules: options.detectOrphanModules,
5141
5186
  generateClient: options.generateClient,
5142
5187
  generatePermissions: options.generatePermissions,
@@ -5392,6 +5437,7 @@ var DEFAULT_SUPACLOUD_CONFIG = {
5392
5437
  outDir: "generated",
5393
5438
  include: ["**/*.module.ts", "**/*.ts"],
5394
5439
  strict: true,
5440
+ requireRouteContracts: false,
5395
5441
  generateClient: true,
5396
5442
  generatePermissions: true,
5397
5443
  treeShakeUnusedProviders: true,
@@ -5411,6 +5457,7 @@ function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
5411
5457
  outDir: resolve5(cwd, resolved.outDir ?? DEFAULT_SUPACLOUD_CONFIG.outDir),
5412
5458
  include: resolved.include ?? [...DEFAULT_SUPACLOUD_CONFIG.include],
5413
5459
  strict: resolved.strict ?? DEFAULT_SUPACLOUD_CONFIG.strict,
5460
+ requireRouteContracts: resolved.requireRouteContracts ?? DEFAULT_SUPACLOUD_CONFIG.requireRouteContracts,
5414
5461
  generateClient: resolved.generateClient ?? DEFAULT_SUPACLOUD_CONFIG.generateClient,
5415
5462
  generatePermissions: resolved.generatePermissions ?? DEFAULT_SUPACLOUD_CONFIG.generatePermissions,
5416
5463
  moduleBoundaryPreset: resolved.moduleBoundaryPreset ?? DEFAULT_SUPACLOUD_CONFIG.moduleBoundaryPreset,
@@ -5438,6 +5485,7 @@ function compileOptionsFromConfig(config, cwd = process.cwd()) {
5438
5485
  outDir: resolved.outDir,
5439
5486
  include: resolved.include,
5440
5487
  strict: resolved.strict,
5488
+ requireRouteContracts: resolved.requireRouteContracts,
5441
5489
  generateClient: resolved.generateClient,
5442
5490
  generatePermissions: resolved.generatePermissions,
5443
5491
  moduleBoundaryPreset: resolved.moduleBoundaryPreset,
package/dist/config.d.ts CHANGED
@@ -4,6 +4,7 @@ export interface SupaCloudConfig {
4
4
  outDir?: string;
5
5
  include?: string[];
6
6
  strict?: boolean;
7
+ requireRouteContracts?: boolean;
7
8
  generateClient?: boolean;
8
9
  generatePermissions?: boolean;
9
10
  moduleBoundaryPreset?: ModuleBoundaryPresetName;
@@ -20,6 +21,7 @@ export declare function resolveSupacloudConfig(config?: SupaCloudConfig, cwd?: s
20
21
  outDir: string;
21
22
  include: string[];
22
23
  strict: boolean;
24
+ requireRouteContracts: boolean;
23
25
  generateClient: boolean;
24
26
  generatePermissions: boolean;
25
27
  moduleBoundaryPreset: ModuleBoundaryPresetName;
package/dist/index.d.ts CHANGED
@@ -24,3 +24,4 @@ export type { SupaCloudConfig } from "./config";
24
24
  export { camelName } from "./util";
25
25
  export { ANGULAR_ENTERPRISE_RULES, CLEAN_ARCHITECTURE_RULES, MODULAR_MONOLITH_RULES, MODULE_BOUNDARY_PROFILES, getModuleBoundaryPreset, getModuleBoundaryProfile, resolveModuleBoundaries, } from "./profiles";
26
26
  export type { ApplicationGraph, AspectRefNode, CachedModuleEntry, CheckProjectResult, CommandExecutionCapabilities, CommandNode, CompileOptions, CompileResult, CompileStats, ControllerNode, DependencyGraphCache, DependencyGraphIndex, Diagnostic, DiagnosticFix, ModuleBoundaryPresetName, ModuleBoundaryProfile, ModuleBoundaryRule, ModuleNode, JobNode, ProviderKind, ProviderNode, QueryNode, RouteNode, Scope, TokenKind, TypeSafetyOptions, ValidateOptions, WatchEvent, WatchHandle, WatchOptions, FeatureSpecNode, FeatureTransitionNode, } from "./types";
27
+ export { inspectRouteContracts, validateRouteContracts } from "./route-contracts";
package/dist/index.js CHANGED
@@ -2545,7 +2545,7 @@ import { access, mkdir, rename as rename2, unlink as unlink2, writeFile as write
2545
2545
  import { join as join2 } from "node:path";
2546
2546
  var HEADER = "// GENERATED BY @supacloud/compiler — do not edit";
2547
2547
  var INTERFACES = `export interface CompiledRoute {
2548
- method: string;
2548
+ method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
2549
2549
  path: string;
2550
2550
  handler: string;
2551
2551
  body?: unknown;
@@ -2616,7 +2616,7 @@ export type CompiledAspect = (
2616
2616
  export interface CompiledController {
2617
2617
  path: string;
2618
2618
  serviceKey: string;
2619
- scope: string;
2619
+ scope: "application" | "request" | "job";
2620
2620
  routes: CompiledRoute[];
2621
2621
  }
2622
2622
 
@@ -3230,7 +3230,7 @@ ${indent(item, 2)}`).join(",")}
3230
3230
  switch (provider.kind) {
3231
3231
  case "class": {
3232
3232
  const useClass = this.imports.add(provider.useClass ?? provider.token, provider.importPath, provider.importModule);
3233
- const args = provider.deps.map((dep) => this.depExpr(dep, kind, this.depOptions(provider, dep))).join(", ");
3233
+ const args = provider.deps.map((dep, index) => this.typedDepExpr(dep, kind, this.depOptions(provider, dep), `ConstructorParameters<typeof ${useClass}>[${index}]`)).join(", ");
3234
3234
  const local = this.localVar(isMulti ? provider.useClass ?? `${provider.token}Item` : provider.token, kind);
3235
3235
  return {
3236
3236
  constLine: `const ${local} = ${this.instantiate(useClass, args, kind, provider.functionalInjects)};`,
@@ -3251,7 +3251,7 @@ ${indent(item, 2)}`).join(",")}
3251
3251
  return { constLine, key, expr: local2 };
3252
3252
  }
3253
3253
  const factory2 = this.imports.add(provider.useFactoryName ?? "", provider.importPath, provider.importModule);
3254
- const args = provider.deps.map((dep) => this.depExpr(dep, kind, this.depOptions(provider, dep))).join(", ");
3254
+ const args = provider.deps.map((dep, index) => this.typedDepExpr(dep, kind, this.depOptions(provider, dep), `Parameters<typeof ${factory2}>[${index}]`)).join(", ");
3255
3255
  const local = this.localVar(isMulti ? provider.useFactoryName ?? `${provider.token}Item` : provider.token, kind);
3256
3256
  return { constLine: `const ${local} = ${factory2}(${args});`, key, expr: local };
3257
3257
  }
@@ -3265,7 +3265,7 @@ ${indent(item, 2)}`).join(",")}
3265
3265
  }
3266
3266
  emitController(controller, kind) {
3267
3267
  const className = this.imports.add(controller.className, controller.importPath);
3268
- const args = controller.deps.map((dep) => this.depExpr(dep, kind, this.depOptions(controller, dep))).join(", ");
3268
+ const args = controller.deps.map((dep, index) => this.typedDepExpr(dep, kind, this.depOptions(controller, dep), `ConstructorParameters<typeof ${className}>[${index}]`)).join(", ");
3269
3269
  const key = camelName(controller.className);
3270
3270
  const local = this.localVar(controller.className, kind);
3271
3271
  return {
@@ -3323,6 +3323,13 @@ ${indent(item, 2)}`).join(",")}
3323
3323
  host: "hostDeps" in node ? node.hostDeps?.includes(token) ?? false : false
3324
3324
  };
3325
3325
  }
3326
+ typedDepExpr(token, kind, options, type) {
3327
+ const expression = this.depExpr(token, kind, options);
3328
+ const localProvider = this.module.providers.find((provider) => this.locals[kind].get(provider.token) === expression);
3329
+ if (expression === "undefined" || localProvider && !(localProvider.kind === "factory" && !localProvider.useFactoryName))
3330
+ return expression;
3331
+ return `${expression} as ${type}`;
3332
+ }
3326
3333
  depExpr(token, kind, options = {}) {
3327
3334
  const isOptional = options.optional ?? false;
3328
3335
  const isSelf = options.self ?? false;
@@ -4856,6 +4863,39 @@ function isAnyKeyword(node) {
4856
4863
  return node.kind === ts5.SyntaxKind.AnyKeyword;
4857
4864
  }
4858
4865
 
4866
+ // src/route-contracts.ts
4867
+ function inspectRouteContracts(graph) {
4868
+ return graph.modules.flatMap((module) => module.controllers.flatMap((controller) => controller.routes.map((route) => {
4869
+ const missing = [];
4870
+ if ((route.hasBodyBinding || route.handlerParams?.some((param) => param.kind === "body")) && !route.body)
4871
+ missing.push("body");
4872
+ if ((route.pathParams?.length || route.paramBindings?.length || route.handlerParams?.some((param) => param.kind === "param") || /:[^/]+/.test(`${controller.path}/${route.path}`)) && !route.params)
4873
+ missing.push("params");
4874
+ if ((route.queryBindings?.length || route.handlerParams?.some((param) => param.kind === "query")) && !route.query)
4875
+ missing.push("query");
4876
+ if (!route.response)
4877
+ missing.push("response");
4878
+ return {
4879
+ module: module.name,
4880
+ controller: controller.className,
4881
+ handler: route.handler,
4882
+ method: route.method,
4883
+ path: `${controller.path}${route.path}`,
4884
+ file: controller.file,
4885
+ missing
4886
+ };
4887
+ })));
4888
+ }
4889
+ function validateRouteContracts(graph) {
4890
+ return inspectRouteContracts(graph).filter((route) => route.missing.length).map((route) => ({
4891
+ severity: "error",
4892
+ code: "route-contract-required",
4893
+ file: route.file,
4894
+ message: `${route.controller}.${route.handler} (${route.method} ${route.path}) is missing contract declarations: ${route.missing.join(", ")}.`,
4895
+ suggestion: "Declare the missing schemas and test actual request/response decoding. An opaque schema is not proof of validation."
4896
+ }));
4897
+ }
4898
+
4859
4899
  // src/compile.ts
4860
4900
  async function compileProject(options) {
4861
4901
  const graph = await analyzeProject(options.rootDir, options.include, options.cache, options.changedPaths);
@@ -4878,6 +4918,8 @@ async function compileProject(options) {
4878
4918
  }
4879
4919
  }
4880
4920
  const typeSafety = resolveTypeSafety(options);
4921
+ if (options.requireRouteContracts)
4922
+ diagnostics.push(...validateRouteContracts(graph));
4881
4923
  const rendered = renderApplication(graph, {
4882
4924
  rootDir: options.rootDir,
4883
4925
  outDir: options.outDir,
@@ -4941,6 +4983,8 @@ async function checkProject(options) {
4941
4983
  }
4942
4984
  }
4943
4985
  const typeSafety = resolveTypeSafety(options);
4986
+ if (options.requireRouteContracts)
4987
+ diagnostics.push(...validateRouteContracts(graph));
4944
4988
  const rendered = renderApplication(graph, {
4945
4989
  rootDir: options.rootDir,
4946
4990
  outDir: options.outDir,
@@ -5125,6 +5169,7 @@ function optionsKeyOf(options) {
5125
5169
  allowRouteCommandBindings: options.allowRouteCommandBindings,
5126
5170
  commandCapabilities: options.commandCapabilities,
5127
5171
  disallowControllerDirectDb: options.disallowControllerDirectDb,
5172
+ requireRouteContracts: options.requireRouteContracts,
5128
5173
  detectOrphanModules: options.detectOrphanModules,
5129
5174
  generateClient: options.generateClient,
5130
5175
  generatePermissions: options.generatePermissions,
@@ -5570,6 +5615,7 @@ var DEFAULT_SUPACLOUD_CONFIG = {
5570
5615
  outDir: "generated",
5571
5616
  include: ["**/*.module.ts", "**/*.ts"],
5572
5617
  strict: true,
5618
+ requireRouteContracts: false,
5573
5619
  generateClient: true,
5574
5620
  generatePermissions: true,
5575
5621
  treeShakeUnusedProviders: true,
@@ -5589,6 +5635,7 @@ function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
5589
5635
  outDir: resolve6(cwd, resolved.outDir ?? DEFAULT_SUPACLOUD_CONFIG.outDir),
5590
5636
  include: resolved.include ?? [...DEFAULT_SUPACLOUD_CONFIG.include],
5591
5637
  strict: resolved.strict ?? DEFAULT_SUPACLOUD_CONFIG.strict,
5638
+ requireRouteContracts: resolved.requireRouteContracts ?? DEFAULT_SUPACLOUD_CONFIG.requireRouteContracts,
5592
5639
  generateClient: resolved.generateClient ?? DEFAULT_SUPACLOUD_CONFIG.generateClient,
5593
5640
  generatePermissions: resolved.generatePermissions ?? DEFAULT_SUPACLOUD_CONFIG.generatePermissions,
5594
5641
  moduleBoundaryPreset: resolved.moduleBoundaryPreset ?? DEFAULT_SUPACLOUD_CONFIG.moduleBoundaryPreset,
@@ -5616,6 +5663,7 @@ function compileOptionsFromConfig(config, cwd = process.cwd()) {
5616
5663
  outDir: resolved.outDir,
5617
5664
  include: resolved.include,
5618
5665
  strict: resolved.strict,
5666
+ requireRouteContracts: resolved.requireRouteContracts,
5619
5667
  generateClient: resolved.generateClient,
5620
5668
  generatePermissions: resolved.generatePermissions,
5621
5669
  moduleBoundaryPreset: resolved.moduleBoundaryPreset,
@@ -5653,6 +5701,7 @@ export {
5653
5701
  generateFeatureSource,
5654
5702
  getModuleBoundaryPreset,
5655
5703
  getModuleBoundaryProfile,
5704
+ inspectRouteContracts,
5656
5705
  loadSupacloudConfig,
5657
5706
  renderApplication,
5658
5707
  resolveModuleBoundaries,
@@ -5661,5 +5710,6 @@ export {
5661
5710
  scanProductionSource,
5662
5711
  validateFeatureSpec,
5663
5712
  validateGraph,
5713
+ validateRouteContracts,
5664
5714
  watchProject
5665
5715
  };
@@ -0,0 +1,12 @@
1
+ import type { ApplicationGraph, Diagnostic } from "./types";
2
+ /** Declaration coverage only; runtime decoding and database behavior require separate tests. */
3
+ export declare function inspectRouteContracts(graph: ApplicationGraph): {
4
+ module: string;
5
+ controller: string;
6
+ handler: string;
7
+ method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
8
+ path: string;
9
+ file: string;
10
+ missing: ("query" | "body" | "params" | "response")[];
11
+ }[];
12
+ export declare function validateRouteContracts(graph: ApplicationGraph): Diagnostic[];
package/dist/types.d.ts CHANGED
@@ -290,6 +290,8 @@ export interface ApplicationGraph {
290
290
  };
291
291
  }
292
292
  export interface CompileOptions {
293
+ /** Require schemas for bound route inputs and responses. Does not prove runtime validation. */
294
+ requireRouteContracts?: boolean;
293
295
  /** Project root directory (containing tsconfig). */
294
296
  rootDir: string;
295
297
  /** Glob patterns, defaults to ['**\/*.module.ts', '**\/*.ts']. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/compiler",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Static compiler for @supacloud/app metadata: builds the application graph from AST, validates it, and generates reflection-free factory code",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",