@supacloud/compiler 0.49.0 → 0.50.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/dist/cli.js +44 -2
- package/dist/contract-manifest.d.ts +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +44 -2
- 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)) {
|
|
@@ -406,6 +421,7 @@ function generateFeatureSource(spec) {
|
|
|
406
421
|
const sourceSpec = {
|
|
407
422
|
name: spec.name,
|
|
408
423
|
states: spec.states,
|
|
424
|
+
...spec.database === undefined ? {} : { database: spec.database },
|
|
409
425
|
tenantField: spec.tenantField ?? "tenant_id",
|
|
410
426
|
transitions: Object.fromEntries(transitions.map((transition) => {
|
|
411
427
|
const { name, ...options } = transition;
|
|
@@ -1434,6 +1450,10 @@ var init_validate = __esm(() => {
|
|
|
1434
1450
|
"feature-job-mode": { code: "SC6119", docsUrl: "https://supacloud.dev/errors/SC6119" },
|
|
1435
1451
|
"feature-job-contract": { code: "SC6120", docsUrl: "https://supacloud.dev/errors/SC6120" },
|
|
1436
1452
|
"feature-job-context": { code: "SC6121", docsUrl: "https://supacloud.dev/errors/SC6121" },
|
|
1453
|
+
"feature-database-source-required": { code: "SC6122", docsUrl: "https://supacloud.dev/errors/SC6122" },
|
|
1454
|
+
"feature-database-source-invalid": { code: "SC6123", docsUrl: "https://supacloud.dev/errors/SC6123" },
|
|
1455
|
+
"feature-database-table-invalid": { code: "SC6124", docsUrl: "https://supacloud.dev/errors/SC6124" },
|
|
1456
|
+
"feature-database-row-type-invalid": { code: "SC6125", docsUrl: "https://supacloud.dev/errors/SC6125" },
|
|
1437
1457
|
"feature-route-unresolved": { code: "SC6106", docsUrl: "https://supacloud.dev/errors/SC6106" },
|
|
1438
1458
|
"feature-route-drift": { code: "SC6107", docsUrl: "https://supacloud.dev/errors/SC6107" },
|
|
1439
1459
|
"invalid-feature-spec": { code: "SC6108", docsUrl: "https://supacloud.dev/errors/SC6108" }
|
|
@@ -1514,6 +1534,7 @@ function buildContractManifest(graph, artifacts) {
|
|
|
1514
1534
|
features.push({
|
|
1515
1535
|
name: module.featureSpec.name,
|
|
1516
1536
|
states: [...module.featureSpec.states],
|
|
1537
|
+
...module.featureSpec.database === undefined ? {} : { database: module.featureSpec.database },
|
|
1517
1538
|
...module.featureSpec.tenantField === undefined ? {} : { tenantField: module.featureSpec.tenantField },
|
|
1518
1539
|
transitions: module.featureSpec.transitions.map((transition) => {
|
|
1519
1540
|
const job = transition.job === undefined ? undefined : (module.jobs ?? []).find((candidate) => candidate.className === transition.job || candidate.name === transition.job);
|
|
@@ -19613,6 +19634,10 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
|
|
|
19613
19634
|
if (!ts7.isObjectLiteralExpression(input))
|
|
19614
19635
|
return invalid();
|
|
19615
19636
|
const name = stringLiteralProp(input, "name");
|
|
19637
|
+
const databaseExpr = getProp(input, "database");
|
|
19638
|
+
const database = databaseExpr && ts7.isObjectLiteralExpression(databaseExpr) ? parseFeatureDatabaseSource(databaseExpr) : undefined;
|
|
19639
|
+
if (databaseExpr !== undefined && database === undefined)
|
|
19640
|
+
return invalid();
|
|
19616
19641
|
const tenantField = stringLiteralProp(input, "tenantField");
|
|
19617
19642
|
const statesExpr = getProp(input, "states");
|
|
19618
19643
|
const transitionObject = getProp(input, "transitions");
|
|
@@ -19672,12 +19697,29 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
|
|
|
19672
19697
|
return {
|
|
19673
19698
|
name,
|
|
19674
19699
|
states,
|
|
19700
|
+
...database === undefined ? {} : { database },
|
|
19675
19701
|
...tenantField === undefined ? {} : { tenantField },
|
|
19676
19702
|
transitions,
|
|
19677
19703
|
file: sourcePath(ctx.rootDir, input.getSourceFile().fileName),
|
|
19678
19704
|
line: lineOf(input)
|
|
19679
19705
|
};
|
|
19680
19706
|
}
|
|
19707
|
+
function parseFeatureDatabaseSource(input) {
|
|
19708
|
+
if (input.properties.some((property) => !ts7.isPropertyAssignment(property)))
|
|
19709
|
+
return;
|
|
19710
|
+
const source = stringLiteralProp(input, "source");
|
|
19711
|
+
const table = stringLiteralProp(input, "table");
|
|
19712
|
+
const rowType = stringLiteralProp(input, "rowType");
|
|
19713
|
+
if (!source || !table || !rowType)
|
|
19714
|
+
return;
|
|
19715
|
+
if (source.startsWith("/") || source.includes("\\") || source.split("/").includes("..") || !/^[A-Za-z0-9._/-]+$/.test(source))
|
|
19716
|
+
return;
|
|
19717
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(table))
|
|
19718
|
+
return;
|
|
19719
|
+
if (!/^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*$/.test(rowType))
|
|
19720
|
+
return;
|
|
19721
|
+
return { source, table, rowType };
|
|
19722
|
+
}
|
|
19681
19723
|
function parseFeaturePersistence(input) {
|
|
19682
19724
|
if (input.properties.some((property) => !ts7.isPropertyAssignment(property)))
|
|
19683
19725
|
return;
|
|
@@ -24951,10 +24993,10 @@ import { readFileSync as readFileSync4 } from "node:fs";
|
|
|
24951
24993
|
import { resolve as resolve18 } from "node:path";
|
|
24952
24994
|
|
|
24953
24995
|
// src/migration-app-version.ts
|
|
24954
|
-
var MIGRATION_APP_VERSION = "0.
|
|
24996
|
+
var MIGRATION_APP_VERSION = "0.31.0";
|
|
24955
24997
|
|
|
24956
24998
|
// src/migration-elysia-version.ts
|
|
24957
|
-
var MIGRATION_ELYSIA_VERSION = "0.35.
|
|
24999
|
+
var MIGRATION_ELYSIA_VERSION = "0.35.1";
|
|
24958
25000
|
|
|
24959
25001
|
// src/migration-policy.ts
|
|
24960
25002
|
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)) {
|
|
@@ -405,6 +420,7 @@ function generateFeatureSource(spec) {
|
|
|
405
420
|
const sourceSpec = {
|
|
406
421
|
name: spec.name,
|
|
407
422
|
states: spec.states,
|
|
423
|
+
...spec.database === undefined ? {} : { database: spec.database },
|
|
408
424
|
tenantField: spec.tenantField ?? "tenant_id",
|
|
409
425
|
transitions: Object.fromEntries(transitions.map((transition) => {
|
|
410
426
|
const { name, ...options } = transition;
|
|
@@ -1433,6 +1449,10 @@ var init_validate = __esm(() => {
|
|
|
1433
1449
|
"feature-job-mode": { code: "SC6119", docsUrl: "https://supacloud.dev/errors/SC6119" },
|
|
1434
1450
|
"feature-job-contract": { code: "SC6120", docsUrl: "https://supacloud.dev/errors/SC6120" },
|
|
1435
1451
|
"feature-job-context": { code: "SC6121", docsUrl: "https://supacloud.dev/errors/SC6121" },
|
|
1452
|
+
"feature-database-source-required": { code: "SC6122", docsUrl: "https://supacloud.dev/errors/SC6122" },
|
|
1453
|
+
"feature-database-source-invalid": { code: "SC6123", docsUrl: "https://supacloud.dev/errors/SC6123" },
|
|
1454
|
+
"feature-database-table-invalid": { code: "SC6124", docsUrl: "https://supacloud.dev/errors/SC6124" },
|
|
1455
|
+
"feature-database-row-type-invalid": { code: "SC6125", docsUrl: "https://supacloud.dev/errors/SC6125" },
|
|
1436
1456
|
"feature-route-unresolved": { code: "SC6106", docsUrl: "https://supacloud.dev/errors/SC6106" },
|
|
1437
1457
|
"feature-route-drift": { code: "SC6107", docsUrl: "https://supacloud.dev/errors/SC6107" },
|
|
1438
1458
|
"invalid-feature-spec": { code: "SC6108", docsUrl: "https://supacloud.dev/errors/SC6108" }
|
|
@@ -1513,6 +1533,7 @@ function buildContractManifest(graph, artifacts) {
|
|
|
1513
1533
|
features.push({
|
|
1514
1534
|
name: module.featureSpec.name,
|
|
1515
1535
|
states: [...module.featureSpec.states],
|
|
1536
|
+
...module.featureSpec.database === undefined ? {} : { database: module.featureSpec.database },
|
|
1516
1537
|
...module.featureSpec.tenantField === undefined ? {} : { tenantField: module.featureSpec.tenantField },
|
|
1517
1538
|
transitions: module.featureSpec.transitions.map((transition) => {
|
|
1518
1539
|
const job = transition.job === undefined ? undefined : (module.jobs ?? []).find((candidate) => candidate.className === transition.job || candidate.name === transition.job);
|
|
@@ -19572,6 +19593,10 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
|
|
|
19572
19593
|
if (!ts7.isObjectLiteralExpression(input))
|
|
19573
19594
|
return invalid();
|
|
19574
19595
|
const name = stringLiteralProp(input, "name");
|
|
19596
|
+
const databaseExpr = getProp(input, "database");
|
|
19597
|
+
const database = databaseExpr && ts7.isObjectLiteralExpression(databaseExpr) ? parseFeatureDatabaseSource(databaseExpr) : undefined;
|
|
19598
|
+
if (databaseExpr !== undefined && database === undefined)
|
|
19599
|
+
return invalid();
|
|
19575
19600
|
const tenantField = stringLiteralProp(input, "tenantField");
|
|
19576
19601
|
const statesExpr = getProp(input, "states");
|
|
19577
19602
|
const transitionObject = getProp(input, "transitions");
|
|
@@ -19631,12 +19656,29 @@ function parseFeatureSpec(input, ctx, seen = new Set) {
|
|
|
19631
19656
|
return {
|
|
19632
19657
|
name,
|
|
19633
19658
|
states,
|
|
19659
|
+
...database === undefined ? {} : { database },
|
|
19634
19660
|
...tenantField === undefined ? {} : { tenantField },
|
|
19635
19661
|
transitions,
|
|
19636
19662
|
file: sourcePath(ctx.rootDir, input.getSourceFile().fileName),
|
|
19637
19663
|
line: lineOf(input)
|
|
19638
19664
|
};
|
|
19639
19665
|
}
|
|
19666
|
+
function parseFeatureDatabaseSource(input) {
|
|
19667
|
+
if (input.properties.some((property) => !ts7.isPropertyAssignment(property)))
|
|
19668
|
+
return;
|
|
19669
|
+
const source = stringLiteralProp(input, "source");
|
|
19670
|
+
const table = stringLiteralProp(input, "table");
|
|
19671
|
+
const rowType = stringLiteralProp(input, "rowType");
|
|
19672
|
+
if (!source || !table || !rowType)
|
|
19673
|
+
return;
|
|
19674
|
+
if (source.startsWith("/") || source.includes("\\") || source.split("/").includes("..") || !/^[A-Za-z0-9._/-]+$/.test(source))
|
|
19675
|
+
return;
|
|
19676
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(table))
|
|
19677
|
+
return;
|
|
19678
|
+
if (!/^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*$/.test(rowType))
|
|
19679
|
+
return;
|
|
19680
|
+
return { source, table, rowType };
|
|
19681
|
+
}
|
|
19640
19682
|
function parseFeaturePersistence(input) {
|
|
19641
19683
|
if (input.properties.some((property) => !ts7.isPropertyAssignment(property)))
|
|
19642
19684
|
return;
|
|
@@ -24633,10 +24675,10 @@ import { readFileSync as readFileSync4 } from "node:fs";
|
|
|
24633
24675
|
import { resolve as resolve17 } from "node:path";
|
|
24634
24676
|
|
|
24635
24677
|
// src/migration-app-version.ts
|
|
24636
|
-
var MIGRATION_APP_VERSION = "0.
|
|
24678
|
+
var MIGRATION_APP_VERSION = "0.31.0";
|
|
24637
24679
|
|
|
24638
24680
|
// src/migration-elysia-version.ts
|
|
24639
|
-
var MIGRATION_ELYSIA_VERSION = "0.35.
|
|
24681
|
+
var MIGRATION_ELYSIA_VERSION = "0.35.1";
|
|
24640
24682
|
|
|
24641
24683
|
// src/migration-policy.ts
|
|
24642
24684
|
var cachedCompilerVersion;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MIGRATION_APP_VERSION = "0.
|
|
1
|
+
export declare const MIGRATION_APP_VERSION = "0.31.0";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MIGRATION_ELYSIA_VERSION = "0.35.
|
|
1
|
+
export declare const MIGRATION_ELYSIA_VERSION = "0.35.1";
|
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.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",
|
|
@@ -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"
|