@supacloud/compiler 0.49.0 → 0.50.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -270,6 +270,21 @@ function validateFeatureSpec(spec, module) {
270
270
  if (spec.tenantField !== undefined && !/^[A-Za-z_][A-Za-z0-9_]*$/.test(spec.tenantField)) {
271
271
  error("feature-tenant-boundary-invalid", `Feature ${spec.name} declares an unsafe tenant field.`);
272
272
  }
273
+ const databaseTransition = spec.transitions.some((transition) => transition.persistence?.boundary === "database");
274
+ if (databaseTransition && spec.database === undefined && spec.file !== undefined) {
275
+ error("feature-database-source-required", `Database Feature ${spec.name} must declare its database source, table and rowType.`);
276
+ }
277
+ if (spec.database !== undefined) {
278
+ if (spec.database.source.startsWith("/") || spec.database.source.includes("\\") || spec.database.source.split("/").includes("..") || !/^[A-Za-z0-9._/-]+$/.test(spec.database.source)) {
279
+ error("feature-database-source-invalid", `Feature ${spec.name} declares an unsafe database source.`);
280
+ }
281
+ if (!/^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(spec.database.table)) {
282
+ error("feature-database-table-invalid", `Feature ${spec.name} must use a schema-qualified database table.`);
283
+ }
284
+ if (!/^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*$/.test(spec.database.rowType)) {
285
+ error("feature-database-row-type-invalid", `Feature ${spec.name} declares an unsafe database row type.`);
286
+ }
287
+ }
273
288
  const names = new Set;
274
289
  for (const transition of spec.transitions) {
275
290
  if (!transition.name.trim() || names.has(transition.name)) {
@@ -375,6 +390,17 @@ function validateFeatureSpec(spec, module) {
375
390
  }
376
391
  }
377
392
  }
393
+ const declaredTags = module ? new Set(module.controllers.flatMap((controller) => controller.routes.flatMap((route) => route.tags ?? []))) : new Set;
394
+ if (transition.persistence !== undefined && declaredTags.size > 0 && transition.invalidateTags === undefined) {
395
+ error("feature-invalidation-tags-required", `Persistent transition ${transition.name} must declare invalidateTags when Feature ${spec.name} exposes query tags.`);
396
+ }
397
+ if (transition.invalidateTags !== undefined && declaredTags.size > 0) {
398
+ for (const tag of transition.invalidateTags) {
399
+ if (!declaredTags.has(tag)) {
400
+ error("feature-invalidation-tag-unresolved", `Transition ${transition.name} invalidates '${tag}', but Feature ${spec.name} does not declare that query tag.`);
401
+ }
402
+ }
403
+ }
378
404
  if (transition.route) {
379
405
  const routes = module.controllers.flatMap((controller) => controller.routes.filter((route) => `${route.method} ${joinRoutePaths(controller.path, route.path)}` === transition.route));
380
406
  if (routes.length !== 1) {
@@ -406,6 +432,7 @@ function generateFeatureSource(spec) {
406
432
  const sourceSpec = {
407
433
  name: spec.name,
408
434
  states: spec.states,
435
+ ...spec.database === undefined ? {} : { database: spec.database },
409
436
  tenantField: spec.tenantField ?? "tenant_id",
410
437
  transitions: Object.fromEntries(transitions.map((transition) => {
411
438
  const { name, ...options } = transition;
@@ -1424,8 +1451,9 @@ var init_validate = __esm(() => {
1424
1451
  "feature-governance-drift": { code: "SC6105", docsUrl: "https://supacloud.dev/errors/SC6105" },
1425
1452
  "feature-persistence-invalid": { code: "SC6110", docsUrl: "https://supacloud.dev/errors/SC6110" },
1426
1453
  "feature-persistence-drift": { code: "SC6111", docsUrl: "https://supacloud.dev/errors/SC6111" },
1454
+ "feature-invalidation-tag-unresolved": { code: "SC6113", docsUrl: "https://supacloud.dev/errors/SC6113" },
1427
1455
  "feature-tenant-boundary-invalid": { code: "SC6112", docsUrl: "https://supacloud.dev/errors/SC6112" },
1428
- "feature-tenant-boundary-drift": { code: "SC6113", docsUrl: "https://supacloud.dev/errors/SC6113" },
1456
+ "feature-tenant-boundary-drift": { code: "SC6127", docsUrl: "https://supacloud.dev/errors/SC6127" },
1429
1457
  "feature-query-tenant-boundary": { code: "SC6114", docsUrl: "https://supacloud.dev/errors/SC6114" },
1430
1458
  "feature-job-tenant-boundary": { code: "SC6115", docsUrl: "https://supacloud.dev/errors/SC6115" },
1431
1459
  "feature-command-tenant-boundary": { code: "SC6116", docsUrl: "https://supacloud.dev/errors/SC6116" },
@@ -1434,6 +1462,11 @@ var init_validate = __esm(() => {
1434
1462
  "feature-job-mode": { code: "SC6119", docsUrl: "https://supacloud.dev/errors/SC6119" },
1435
1463
  "feature-job-contract": { code: "SC6120", docsUrl: "https://supacloud.dev/errors/SC6120" },
1436
1464
  "feature-job-context": { code: "SC6121", docsUrl: "https://supacloud.dev/errors/SC6121" },
1465
+ "feature-database-source-required": { code: "SC6122", docsUrl: "https://supacloud.dev/errors/SC6122" },
1466
+ "feature-database-source-invalid": { code: "SC6123", docsUrl: "https://supacloud.dev/errors/SC6123" },
1467
+ "feature-database-table-invalid": { code: "SC6124", docsUrl: "https://supacloud.dev/errors/SC6124" },
1468
+ "feature-database-row-type-invalid": { code: "SC6125", docsUrl: "https://supacloud.dev/errors/SC6125" },
1469
+ "feature-invalidation-tags-required": { code: "SC6126", docsUrl: "https://supacloud.dev/errors/SC6126" },
1437
1470
  "feature-route-unresolved": { code: "SC6106", docsUrl: "https://supacloud.dev/errors/SC6106" },
1438
1471
  "feature-route-drift": { code: "SC6107", docsUrl: "https://supacloud.dev/errors/SC6107" },
1439
1472
  "invalid-feature-spec": { code: "SC6108", docsUrl: "https://supacloud.dev/errors/SC6108" }
@@ -1514,6 +1547,7 @@ function buildContractManifest(graph, artifacts) {
1514
1547
  features.push({
1515
1548
  name: module.featureSpec.name,
1516
1549
  states: [...module.featureSpec.states],
1550
+ ...module.featureSpec.database === undefined ? {} : { database: module.featureSpec.database },
1517
1551
  ...module.featureSpec.tenantField === undefined ? {} : { tenantField: module.featureSpec.tenantField },
1518
1552
  transitions: module.featureSpec.transitions.map((transition) => {
1519
1553
  const job = transition.job === undefined ? undefined : (module.jobs ?? []).find((candidate) => candidate.className === transition.job || candidate.name === transition.job);
@@ -19613,6 +19647,10 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
19613
19647
  if (!ts7.isObjectLiteralExpression(input))
19614
19648
  return invalid();
19615
19649
  const name = stringLiteralProp(input, "name");
19650
+ const databaseExpr = getProp(input, "database");
19651
+ const database = databaseExpr && ts7.isObjectLiteralExpression(databaseExpr) ? parseFeatureDatabaseSource(databaseExpr) : undefined;
19652
+ if (databaseExpr !== undefined && database === undefined)
19653
+ return invalid();
19616
19654
  const tenantField = stringLiteralProp(input, "tenantField");
19617
19655
  const statesExpr = getProp(input, "states");
19618
19656
  const transitionObject = getProp(input, "transitions");
@@ -19672,12 +19710,29 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
19672
19710
  return {
19673
19711
  name,
19674
19712
  states,
19713
+ ...database === undefined ? {} : { database },
19675
19714
  ...tenantField === undefined ? {} : { tenantField },
19676
19715
  transitions,
19677
19716
  file: sourcePath(ctx.rootDir, input.getSourceFile().fileName),
19678
19717
  line: lineOf(input)
19679
19718
  };
19680
19719
  }
19720
+ function parseFeatureDatabaseSource(input) {
19721
+ if (input.properties.some((property) => !ts7.isPropertyAssignment(property)))
19722
+ return;
19723
+ const source = stringLiteralProp(input, "source");
19724
+ const table = stringLiteralProp(input, "table");
19725
+ const rowType = stringLiteralProp(input, "rowType");
19726
+ if (!source || !table || !rowType)
19727
+ return;
19728
+ if (source.startsWith("/") || source.includes("\\") || source.split("/").includes("..") || !/^[A-Za-z0-9._/-]+$/.test(source))
19729
+ return;
19730
+ if (!/^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(table))
19731
+ return;
19732
+ if (!/^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*$/.test(rowType))
19733
+ return;
19734
+ return { source, table, rowType };
19735
+ }
19681
19736
  function parseFeaturePersistence(input) {
19682
19737
  if (input.properties.some((property) => !ts7.isPropertyAssignment(property)))
19683
19738
  return;
@@ -24951,10 +25006,10 @@ import { readFileSync as readFileSync4 } from "node:fs";
24951
25006
  import { resolve as resolve18 } from "node:path";
24952
25007
 
24953
25008
  // src/migration-app-version.ts
24954
- var MIGRATION_APP_VERSION = "0.30.0";
25009
+ var MIGRATION_APP_VERSION = "0.31.1";
24955
25010
 
24956
25011
  // src/migration-elysia-version.ts
24957
- var MIGRATION_ELYSIA_VERSION = "0.35.0";
25012
+ var MIGRATION_ELYSIA_VERSION = "0.35.2";
24958
25013
 
24959
25014
  // src/migration-policy.ts
24960
25015
  var cachedCompilerVersion;
@@ -1,4 +1,4 @@
1
- import type { ApplicationGraph, FeaturePersistenceNode } from "./types";
1
+ import type { ApplicationGraph, FeatureDatabaseSourceNode, FeaturePersistenceNode } from "./types";
2
2
  export interface ContractManifest {
3
3
  version: 1;
4
4
  commands: Array<{
@@ -41,6 +41,7 @@ export interface ContractManifest {
41
41
  features: Array<{
42
42
  name: string;
43
43
  states: string[];
44
+ database?: FeatureDatabaseSourceNode;
44
45
  tenantField?: string;
45
46
  transitions: Array<{
46
47
  name: string;
package/dist/index.d.ts CHANGED
@@ -52,7 +52,7 @@ export { DEFAULT_SUPACLOUD_CONFIG, compileOptionsFromConfig, defineSupacloudConf
52
52
  export type { SupaCloudConfig } from "./config";
53
53
  export { camelName } from "./util";
54
54
  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, FeaturePersistenceNode, GraphqlOptions, GraphqlContractSummary, OpenApiOptions, OpenApiSecurityScheme, OpenApiServer, } from "./types";
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
56
  export { inspectRouteContracts, validateRouteContracts } from "./route-contracts";
57
57
  export { validateEffectPolicies, validateJobPolicies } from "./effect-governance";
58
58
  export { pullGraphqlSchema } from "./graphql-schema";
package/dist/index.js CHANGED
@@ -269,6 +269,21 @@ function validateFeatureSpec(spec, module) {
269
269
  if (spec.tenantField !== undefined && !/^[A-Za-z_][A-Za-z0-9_]*$/.test(spec.tenantField)) {
270
270
  error("feature-tenant-boundary-invalid", `Feature ${spec.name} declares an unsafe tenant field.`);
271
271
  }
272
+ const databaseTransition = spec.transitions.some((transition) => transition.persistence?.boundary === "database");
273
+ if (databaseTransition && spec.database === undefined && spec.file !== undefined) {
274
+ error("feature-database-source-required", `Database Feature ${spec.name} must declare its database source, table and rowType.`);
275
+ }
276
+ if (spec.database !== undefined) {
277
+ if (spec.database.source.startsWith("/") || spec.database.source.includes("\\") || spec.database.source.split("/").includes("..") || !/^[A-Za-z0-9._/-]+$/.test(spec.database.source)) {
278
+ error("feature-database-source-invalid", `Feature ${spec.name} declares an unsafe database source.`);
279
+ }
280
+ if (!/^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(spec.database.table)) {
281
+ error("feature-database-table-invalid", `Feature ${spec.name} must use a schema-qualified database table.`);
282
+ }
283
+ if (!/^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*$/.test(spec.database.rowType)) {
284
+ error("feature-database-row-type-invalid", `Feature ${spec.name} declares an unsafe database row type.`);
285
+ }
286
+ }
272
287
  const names = new Set;
273
288
  for (const transition of spec.transitions) {
274
289
  if (!transition.name.trim() || names.has(transition.name)) {
@@ -374,6 +389,17 @@ function validateFeatureSpec(spec, module) {
374
389
  }
375
390
  }
376
391
  }
392
+ const declaredTags = module ? new Set(module.controllers.flatMap((controller) => controller.routes.flatMap((route) => route.tags ?? []))) : new Set;
393
+ if (transition.persistence !== undefined && declaredTags.size > 0 && transition.invalidateTags === undefined) {
394
+ error("feature-invalidation-tags-required", `Persistent transition ${transition.name} must declare invalidateTags when Feature ${spec.name} exposes query tags.`);
395
+ }
396
+ if (transition.invalidateTags !== undefined && declaredTags.size > 0) {
397
+ for (const tag of transition.invalidateTags) {
398
+ if (!declaredTags.has(tag)) {
399
+ error("feature-invalidation-tag-unresolved", `Transition ${transition.name} invalidates '${tag}', but Feature ${spec.name} does not declare that query tag.`);
400
+ }
401
+ }
402
+ }
377
403
  if (transition.route) {
378
404
  const routes = module.controllers.flatMap((controller) => controller.routes.filter((route) => `${route.method} ${joinRoutePaths(controller.path, route.path)}` === transition.route));
379
405
  if (routes.length !== 1) {
@@ -405,6 +431,7 @@ function generateFeatureSource(spec) {
405
431
  const sourceSpec = {
406
432
  name: spec.name,
407
433
  states: spec.states,
434
+ ...spec.database === undefined ? {} : { database: spec.database },
408
435
  tenantField: spec.tenantField ?? "tenant_id",
409
436
  transitions: Object.fromEntries(transitions.map((transition) => {
410
437
  const { name, ...options } = transition;
@@ -1423,8 +1450,9 @@ var init_validate = __esm(() => {
1423
1450
  "feature-governance-drift": { code: "SC6105", docsUrl: "https://supacloud.dev/errors/SC6105" },
1424
1451
  "feature-persistence-invalid": { code: "SC6110", docsUrl: "https://supacloud.dev/errors/SC6110" },
1425
1452
  "feature-persistence-drift": { code: "SC6111", docsUrl: "https://supacloud.dev/errors/SC6111" },
1453
+ "feature-invalidation-tag-unresolved": { code: "SC6113", docsUrl: "https://supacloud.dev/errors/SC6113" },
1426
1454
  "feature-tenant-boundary-invalid": { code: "SC6112", docsUrl: "https://supacloud.dev/errors/SC6112" },
1427
- "feature-tenant-boundary-drift": { code: "SC6113", docsUrl: "https://supacloud.dev/errors/SC6113" },
1455
+ "feature-tenant-boundary-drift": { code: "SC6127", docsUrl: "https://supacloud.dev/errors/SC6127" },
1428
1456
  "feature-query-tenant-boundary": { code: "SC6114", docsUrl: "https://supacloud.dev/errors/SC6114" },
1429
1457
  "feature-job-tenant-boundary": { code: "SC6115", docsUrl: "https://supacloud.dev/errors/SC6115" },
1430
1458
  "feature-command-tenant-boundary": { code: "SC6116", docsUrl: "https://supacloud.dev/errors/SC6116" },
@@ -1433,6 +1461,11 @@ var init_validate = __esm(() => {
1433
1461
  "feature-job-mode": { code: "SC6119", docsUrl: "https://supacloud.dev/errors/SC6119" },
1434
1462
  "feature-job-contract": { code: "SC6120", docsUrl: "https://supacloud.dev/errors/SC6120" },
1435
1463
  "feature-job-context": { code: "SC6121", docsUrl: "https://supacloud.dev/errors/SC6121" },
1464
+ "feature-database-source-required": { code: "SC6122", docsUrl: "https://supacloud.dev/errors/SC6122" },
1465
+ "feature-database-source-invalid": { code: "SC6123", docsUrl: "https://supacloud.dev/errors/SC6123" },
1466
+ "feature-database-table-invalid": { code: "SC6124", docsUrl: "https://supacloud.dev/errors/SC6124" },
1467
+ "feature-database-row-type-invalid": { code: "SC6125", docsUrl: "https://supacloud.dev/errors/SC6125" },
1468
+ "feature-invalidation-tags-required": { code: "SC6126", docsUrl: "https://supacloud.dev/errors/SC6126" },
1436
1469
  "feature-route-unresolved": { code: "SC6106", docsUrl: "https://supacloud.dev/errors/SC6106" },
1437
1470
  "feature-route-drift": { code: "SC6107", docsUrl: "https://supacloud.dev/errors/SC6107" },
1438
1471
  "invalid-feature-spec": { code: "SC6108", docsUrl: "https://supacloud.dev/errors/SC6108" }
@@ -1513,6 +1546,7 @@ function buildContractManifest(graph, artifacts) {
1513
1546
  features.push({
1514
1547
  name: module.featureSpec.name,
1515
1548
  states: [...module.featureSpec.states],
1549
+ ...module.featureSpec.database === undefined ? {} : { database: module.featureSpec.database },
1516
1550
  ...module.featureSpec.tenantField === undefined ? {} : { tenantField: module.featureSpec.tenantField },
1517
1551
  transitions: module.featureSpec.transitions.map((transition) => {
1518
1552
  const job = transition.job === undefined ? undefined : (module.jobs ?? []).find((candidate) => candidate.className === transition.job || candidate.name === transition.job);
@@ -19572,6 +19606,10 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
19572
19606
  if (!ts7.isObjectLiteralExpression(input))
19573
19607
  return invalid();
19574
19608
  const name = stringLiteralProp(input, "name");
19609
+ const databaseExpr = getProp(input, "database");
19610
+ const database = databaseExpr && ts7.isObjectLiteralExpression(databaseExpr) ? parseFeatureDatabaseSource(databaseExpr) : undefined;
19611
+ if (databaseExpr !== undefined && database === undefined)
19612
+ return invalid();
19575
19613
  const tenantField = stringLiteralProp(input, "tenantField");
19576
19614
  const statesExpr = getProp(input, "states");
19577
19615
  const transitionObject = getProp(input, "transitions");
@@ -19631,12 +19669,29 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
19631
19669
  return {
19632
19670
  name,
19633
19671
  states,
19672
+ ...database === undefined ? {} : { database },
19634
19673
  ...tenantField === undefined ? {} : { tenantField },
19635
19674
  transitions,
19636
19675
  file: sourcePath(ctx.rootDir, input.getSourceFile().fileName),
19637
19676
  line: lineOf(input)
19638
19677
  };
19639
19678
  }
19679
+ function parseFeatureDatabaseSource(input) {
19680
+ if (input.properties.some((property) => !ts7.isPropertyAssignment(property)))
19681
+ return;
19682
+ const source = stringLiteralProp(input, "source");
19683
+ const table = stringLiteralProp(input, "table");
19684
+ const rowType = stringLiteralProp(input, "rowType");
19685
+ if (!source || !table || !rowType)
19686
+ return;
19687
+ if (source.startsWith("/") || source.includes("\\") || source.split("/").includes("..") || !/^[A-Za-z0-9._/-]+$/.test(source))
19688
+ return;
19689
+ if (!/^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(table))
19690
+ return;
19691
+ if (!/^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*$/.test(rowType))
19692
+ return;
19693
+ return { source, table, rowType };
19694
+ }
19640
19695
  function parseFeaturePersistence(input) {
19641
19696
  if (input.properties.some((property) => !ts7.isPropertyAssignment(property)))
19642
19697
  return;
@@ -24633,10 +24688,10 @@ import { readFileSync as readFileSync4 } from "node:fs";
24633
24688
  import { resolve as resolve17 } from "node:path";
24634
24689
 
24635
24690
  // src/migration-app-version.ts
24636
- var MIGRATION_APP_VERSION = "0.30.0";
24691
+ var MIGRATION_APP_VERSION = "0.31.1";
24637
24692
 
24638
24693
  // src/migration-elysia-version.ts
24639
- var MIGRATION_ELYSIA_VERSION = "0.35.0";
24694
+ var MIGRATION_ELYSIA_VERSION = "0.35.2";
24640
24695
 
24641
24696
  // src/migration-policy.ts
24642
24697
  var cachedCompilerVersion;
@@ -1 +1 @@
1
- export declare const MIGRATION_APP_VERSION = "0.30.0";
1
+ export declare const MIGRATION_APP_VERSION = "0.31.1";
@@ -1 +1 @@
1
- export declare const MIGRATION_ELYSIA_VERSION = "0.35.0";
1
+ export declare const MIGRATION_ELYSIA_VERSION = "0.35.2";
package/dist/types.d.ts CHANGED
@@ -372,9 +372,15 @@ export interface FeaturePersistenceNode {
372
372
  receipt: "required" | "none";
373
373
  reconciliation: "required" | "none";
374
374
  }
375
+ export interface FeatureDatabaseSourceNode {
376
+ source: string;
377
+ table: string;
378
+ rowType: string;
379
+ }
375
380
  export interface FeatureSpecNode {
376
381
  name: string;
377
382
  states: string[];
383
+ database?: FeatureDatabaseSourceNode;
378
384
  tenantField?: string;
379
385
  transitions: FeatureTransitionNode[];
380
386
  file?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/compiler",
3
- "version": "0.49.0",
3
+ "version": "0.50.1",
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",
@@ -73,7 +73,7 @@
73
73
  "@whatwg-node/promise-helpers": "2.0.0"
74
74
  },
75
75
  "devDependencies": {
76
- "@supabase/supabase-js": "2.117.3",
76
+ "@supabase/supabase-js": "2.118.0",
77
77
  "drizzle-orm": "1.0.0-rc.5-5935859",
78
78
  "@types/bun": "^1.4.3",
79
79
  "typescript": "^7.0.2"