@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 +58 -3
- package/dist/contract-manifest.d.ts +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +58 -3
- package/dist/migration-app-version.d.ts +1 -1
- package/dist/migration-elysia-version.d.ts +1 -1
- package/dist/types.d.ts +6 -0
- package/package.json +2 -2
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: "
|
|
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.
|
|
25009
|
+
var MIGRATION_APP_VERSION = "0.31.1";
|
|
24955
25010
|
|
|
24956
25011
|
// src/migration-elysia-version.ts
|
|
24957
|
-
var MIGRATION_ELYSIA_VERSION = "0.35.
|
|
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: "
|
|
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.
|
|
24691
|
+
var MIGRATION_APP_VERSION = "0.31.1";
|
|
24637
24692
|
|
|
24638
24693
|
// src/migration-elysia-version.ts
|
|
24639
|
-
var MIGRATION_ELYSIA_VERSION = "0.35.
|
|
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.
|
|
1
|
+
export declare const MIGRATION_APP_VERSION = "0.31.1";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MIGRATION_ELYSIA_VERSION = "0.35.
|
|
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.
|
|
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.
|
|
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"
|