@stardeck-customer-apps/compose 0.14.0 → 0.15.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/SKILL.md +16 -0
- package/dist/cli.js +742 -452
- package/dist/index.js +210 -190
- package/dist/index.mjs +210 -190
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1143,16 +1143,16 @@ var require_range = __commonJS({
|
|
|
1143
1143
|
};
|
|
1144
1144
|
var replaceTilde = (comp, options) => {
|
|
1145
1145
|
const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE];
|
|
1146
|
-
const
|
|
1146
|
+
const z11 = options.includePrerelease ? "-0" : "";
|
|
1147
1147
|
return comp.replace(r, (_, M, m, p, pr) => {
|
|
1148
1148
|
debug("tilde", comp, _, M, m, p, pr);
|
|
1149
1149
|
let ret;
|
|
1150
1150
|
if (isX(M)) {
|
|
1151
1151
|
ret = "";
|
|
1152
1152
|
} else if (isX(m)) {
|
|
1153
|
-
ret = `>=${M}.0.0${
|
|
1153
|
+
ret = `>=${M}.0.0${z11} <${+M + 1}.0.0-0`;
|
|
1154
1154
|
} else if (isX(p)) {
|
|
1155
|
-
ret = `>=${M}.${m}.0${
|
|
1155
|
+
ret = `>=${M}.${m}.0${z11} <${M}.${+m + 1}.0-0`;
|
|
1156
1156
|
} else if (pr) {
|
|
1157
1157
|
debug("replaceTilde pr", pr);
|
|
1158
1158
|
ret = `>=${M}.${m}.${p}-${pr} <${M}.${+m + 1}.0-0`;
|
|
@@ -1169,19 +1169,19 @@ var require_range = __commonJS({
|
|
|
1169
1169
|
var replaceCaret = (comp, options) => {
|
|
1170
1170
|
debug("caret", comp, options);
|
|
1171
1171
|
const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET];
|
|
1172
|
-
const
|
|
1172
|
+
const z11 = options.includePrerelease ? "-0" : "";
|
|
1173
1173
|
return comp.replace(r, (_, M, m, p, pr) => {
|
|
1174
1174
|
debug("caret", comp, _, M, m, p, pr);
|
|
1175
1175
|
let ret;
|
|
1176
1176
|
if (isX(M)) {
|
|
1177
1177
|
ret = "";
|
|
1178
1178
|
} else if (isX(m)) {
|
|
1179
|
-
ret = `>=${M}.0.0${
|
|
1179
|
+
ret = `>=${M}.0.0${z11} <${+M + 1}.0.0-0`;
|
|
1180
1180
|
} else if (isX(p)) {
|
|
1181
1181
|
if (M === "0") {
|
|
1182
|
-
ret = `>=${M}.${m}.0${
|
|
1182
|
+
ret = `>=${M}.${m}.0${z11} <${M}.${+m + 1}.0-0`;
|
|
1183
1183
|
} else {
|
|
1184
|
-
ret = `>=${M}.${m}.0${
|
|
1184
|
+
ret = `>=${M}.${m}.0${z11} <${+M + 1}.0.0-0`;
|
|
1185
1185
|
}
|
|
1186
1186
|
} else if (pr) {
|
|
1187
1187
|
debug("replaceCaret pr", pr);
|
|
@@ -2078,6 +2078,7 @@ var JSON_SECRET_PAIR = new RegExp(
|
|
|
2078
2078
|
"g"
|
|
2079
2079
|
);
|
|
2080
2080
|
var SECRET_QUOTE_OPENER = new RegExp(String.raw`\b${SECRET_NAME}\s*=\s*(['"])`, "g");
|
|
2081
|
+
var SHELL_QUOTE_CONTINUATION = String.raw`\''`;
|
|
2081
2082
|
function redactSecrets(text) {
|
|
2082
2083
|
return text.replace(/x-access-token:[^@\s]+@/g, "x-access-token:***@").replace(/https:\/\/(?!x-access-token:)[^/\s:@]+:[^/\s@]+@/gi, "https://***:***@").replace(/\b(gh[pousr]_)[A-Za-z0-9]+/g, "$1***").replace(/\b(github_pat_)[A-Za-z0-9_]+/g, "$1***").replace(/\b(postgres(?:ql)?:\/\/)([^:\s/@]+):([^@\s/]+)@/gi, "$1$2:***@").replace(/\b(npm_[A-Za-z0-9]+)/g, "npm_***").replace(/(_authToken=)([^\s&]+)/gi, "$1***").replace(SECRET_ASSIGNMENT, "$1=***").replace(JSON_SECRET_PAIR, '"$1"$2"***"').replace(/\b(Authorization:\s*(?:Bearer|Basic)\s+)\S+/gi, "$1***");
|
|
2083
2084
|
}
|
|
@@ -2369,10 +2370,12 @@ var modulePermissionClaimSchema = z2.object({
|
|
|
2369
2370
|
/** Human label for the deployment auth config row. */
|
|
2370
2371
|
description: descriptionSchema,
|
|
2371
2372
|
/**
|
|
2372
|
-
* The
|
|
2373
|
-
*
|
|
2374
|
-
*
|
|
2375
|
-
*
|
|
2373
|
+
* The standard organization roles that hold this key. The platform sets them on every app
|
|
2374
|
+
* (a Blueprint fork, a Module install or uninstall, every Blueprint update), so this list is
|
|
2375
|
+
* the truth: a role added here gains the key, a role removed loses it, and nobody can edit a
|
|
2376
|
+
* standard role's grants on a Module key. Admin holds every key without being listed;
|
|
2377
|
+
* External Viewer never holds one. An organization that wants different access duplicates the
|
|
2378
|
+
* standard role and edits the copy.
|
|
2376
2379
|
*/
|
|
2377
2380
|
roles: z2.array(z2.enum(MODULE_PERMISSION_DEFAULT_ROLES)).optional()
|
|
2378
2381
|
}).strict();
|
|
@@ -4014,6 +4017,24 @@ function analyzeClientSafeEntryImports(sourceText, fileName) {
|
|
|
4014
4017
|
return analyzeClientSafeEntryImportsWithTs(ts3, sourceText, fileName);
|
|
4015
4018
|
}
|
|
4016
4019
|
|
|
4020
|
+
// ../../packages/lib/src/shared/ownership-record.ts
|
|
4021
|
+
import { z as z7 } from "zod";
|
|
4022
|
+
var OWNERSHIP_RECORD_VERSION = 1;
|
|
4023
|
+
var moduleList = z7.array(z7.string().refine(isValidModuleName, "not a Module name"));
|
|
4024
|
+
var ownershipRecordSchema = z7.object({
|
|
4025
|
+
version: z7.literal(OWNERSHIP_RECORD_VERSION),
|
|
4026
|
+
/** False once the app stopped all Stardeck updates: then every file is the app's. */
|
|
4027
|
+
stardeckUpdates: z7.boolean(),
|
|
4028
|
+
/** projects.ejected_modules: updates stopped for these Modules, so their folders are the app's. */
|
|
4029
|
+
updatesStoppedModules: moduleList,
|
|
4030
|
+
/** projects.ui_ejected_modules: Customize UI, so their screens are the app's. */
|
|
4031
|
+
customizedUiModules: moduleList,
|
|
4032
|
+
/** projects.external_modules: installed from another app, so the app owns the copy. */
|
|
4033
|
+
externalModules: moduleList,
|
|
4034
|
+
/** projects.removed_modules names: uninstalled on purpose. */
|
|
4035
|
+
uninstalledModules: moduleList
|
|
4036
|
+
});
|
|
4037
|
+
|
|
4017
4038
|
// ../../packages/lib/src/shared/platform-owned-paths.ts
|
|
4018
4039
|
var APP_WEB_PREFIX = "apps/web/";
|
|
4019
4040
|
var BLUEPRINT_LINT_MARKER = `${APP_WEB_PREFIX}eslint-rules/module-boundaries.mjs`;
|
|
@@ -4818,6 +4839,9 @@ function enhancementImport(owner, peer) {
|
|
|
4818
4839
|
function scopeLabel(scope) {
|
|
4819
4840
|
return scope.kind === "root" ? "root" : `enhancement:${scope.peer}`;
|
|
4820
4841
|
}
|
|
4842
|
+
function endpointMarkerOwnsStub(marker, stub) {
|
|
4843
|
+
return stub != null && marker?.kind === "endpoint" && marker.owner === stub.owner;
|
|
4844
|
+
}
|
|
4821
4845
|
function formatEndpointMarker(owner, scope) {
|
|
4822
4846
|
return `// ${MODULE_STUB_MARKER} owner=${owner} scope=${scopeLabel(scope)}`;
|
|
4823
4847
|
}
|
|
@@ -5519,7 +5543,7 @@ function planCompositionArtifacts(input) {
|
|
|
5519
5543
|
const legacy = parseLegacyApiAdapter(pagePath, content);
|
|
5520
5544
|
const plannedRoute = plannedRouteByPath.get(pagePath);
|
|
5521
5545
|
const plannedEndpoint = plannedEndpointByPath.get(pagePath);
|
|
5522
|
-
const isExactPlannedMatch = plannedRoute != null && marker != null && marker.kind === "route" && marker.owner === plannedRoute.owner && marker.nextRelativePath === plannedRoute.nextRelativePath || plannedEndpoint != null && (
|
|
5546
|
+
const isExactPlannedMatch = plannedRoute != null && marker != null && marker.kind === "route" && marker.owner === plannedRoute.owner && marker.nextRelativePath === plannedRoute.nextRelativePath || plannedEndpoint != null && (endpointMarkerOwnsStub(marker, plannedEndpoint) || legacy != null) || plannedRoute != null && legacyRouteAdapterMatchesStub(pagePath, content, plannedRoute);
|
|
5523
5547
|
if (isExactPlannedMatch) {
|
|
5524
5548
|
continue;
|
|
5525
5549
|
}
|
|
@@ -5662,9 +5686,7 @@ function planCompositionArtifacts(input) {
|
|
|
5662
5686
|
}
|
|
5663
5687
|
if (marker.kind === "endpoint") {
|
|
5664
5688
|
const stub = endpointStubByPath.get(path4);
|
|
5665
|
-
|
|
5666
|
-
const scopeMatches = stub != null && scopeLabel(marker.scope) === scopeLabel(stub.scope);
|
|
5667
|
-
if (!ownerMatches || !scopeMatches) {
|
|
5689
|
+
if (!endpointMarkerOwnsStub(marker, stub)) {
|
|
5668
5690
|
return {
|
|
5669
5691
|
ok: false,
|
|
5670
5692
|
error: `[ModuleRail] composition artifacts: refusing to overwrite incongruent marker ownership at ${path4} (existing owner=${marker.owner} scope=${scopeLabel(marker.scope)} vs planned owner=${stub?.owner ?? "?"} scope=${stub ? scopeLabel(stub.scope) : "?"})`,
|
|
@@ -5967,14 +5989,14 @@ function rejectPseudoModuleEntries(entries, parentDir, label) {
|
|
|
5967
5989
|
}
|
|
5968
5990
|
|
|
5969
5991
|
// ../../packages/lib/src/shared/module-composition.ts
|
|
5970
|
-
import { z as
|
|
5971
|
-
var creationSourceBlankSchema =
|
|
5972
|
-
type:
|
|
5992
|
+
import { z as z8 } from "zod";
|
|
5993
|
+
var creationSourceBlankSchema = z8.object({
|
|
5994
|
+
type: z8.literal("blank")
|
|
5973
5995
|
});
|
|
5974
|
-
var creationSourceBlueprintSchema =
|
|
5975
|
-
type:
|
|
5996
|
+
var creationSourceBlueprintSchema = z8.object({
|
|
5997
|
+
type: z8.literal("blueprint"),
|
|
5976
5998
|
/** Internal template/fork project id — keep template naming in identifiers. */
|
|
5977
|
-
blueprintProjectId:
|
|
5999
|
+
blueprintProjectId: z8.string().uuid(),
|
|
5978
6000
|
/**
|
|
5979
6001
|
* `null`/absent means every feature Module: the platform stores that as the
|
|
5980
6002
|
* explicit list of feature Modules in the published Blueprint version the fork
|
|
@@ -5982,192 +6004,197 @@ var creationSourceBlueprintSchema = z7.object({
|
|
|
5982
6004
|
* a custom app: no feature Module, Library Modules only (`resolvePlatformEnv`
|
|
5983
6005
|
* emits it as a set value naming no Module).
|
|
5984
6006
|
*/
|
|
5985
|
-
enabledModules:
|
|
6007
|
+
enabledModules: z8.array(moduleNameSchema).max(100).nullable().optional(),
|
|
6008
|
+
/**
|
|
6009
|
+
* The kind of business (a preset id the published version defines). Its Modules are built
|
|
6010
|
+
* and `enabledModules` adds extras on top; for the general kind `enabledModules` is the pick.
|
|
6011
|
+
*/
|
|
6012
|
+
businessKind: z8.string().regex(/^[a-z][a-z0-9-]{0,39}$/).optional()
|
|
5986
6013
|
});
|
|
5987
|
-
var creationSourceSchema =
|
|
6014
|
+
var creationSourceSchema = z8.discriminatedUnion("type", [
|
|
5988
6015
|
creationSourceBlankSchema,
|
|
5989
6016
|
creationSourceBlueprintSchema
|
|
5990
6017
|
]);
|
|
5991
|
-
var moduleInstallHandoffSchema =
|
|
5992
|
-
moduleName:
|
|
5993
|
-
homeProjectId:
|
|
5994
|
-
installedVersion:
|
|
5995
|
-
baselineSha:
|
|
5996
|
-
mounts:
|
|
5997
|
-
|
|
5998
|
-
group:
|
|
5999
|
-
segment:
|
|
6018
|
+
var moduleInstallHandoffSchema = z8.object({
|
|
6019
|
+
moduleName: z8.string().min(1),
|
|
6020
|
+
homeProjectId: z8.string().uuid(),
|
|
6021
|
+
installedVersion: z8.string().min(1),
|
|
6022
|
+
baselineSha: z8.string().min(1),
|
|
6023
|
+
mounts: z8.array(
|
|
6024
|
+
z8.object({
|
|
6025
|
+
group: z8.string(),
|
|
6026
|
+
segment: z8.string()
|
|
6000
6027
|
})
|
|
6001
6028
|
),
|
|
6002
|
-
integration:
|
|
6003
|
-
workflows:
|
|
6004
|
-
prunedEnhancements:
|
|
6005
|
-
restoredEnhancements:
|
|
6006
|
-
permissions:
|
|
6007
|
-
|
|
6008
|
-
key:
|
|
6009
|
-
description:
|
|
6029
|
+
integration: z8.array(z8.string()),
|
|
6030
|
+
workflows: z8.array(z8.string()),
|
|
6031
|
+
prunedEnhancements: z8.array(z8.string()),
|
|
6032
|
+
restoredEnhancements: z8.array(z8.string()).optional(),
|
|
6033
|
+
permissions: z8.array(
|
|
6034
|
+
z8.object({
|
|
6035
|
+
key: z8.string().min(1),
|
|
6036
|
+
description: z8.string().min(1)
|
|
6010
6037
|
})
|
|
6011
6038
|
).optional()
|
|
6012
6039
|
});
|
|
6013
6040
|
|
|
6014
6041
|
// ../../packages/lib/src/shared/schema-ops.ts
|
|
6015
|
-
import { z as
|
|
6016
|
-
var columnSpecSchema =
|
|
6017
|
-
name:
|
|
6018
|
-
pgType:
|
|
6019
|
-
nullable:
|
|
6042
|
+
import { z as z9 } from "zod";
|
|
6043
|
+
var columnSpecSchema = z9.object({
|
|
6044
|
+
name: z9.string().min(1).max(63),
|
|
6045
|
+
pgType: z9.string().min(1),
|
|
6046
|
+
nullable: z9.boolean(),
|
|
6020
6047
|
/**
|
|
6021
6048
|
* A SQL expression used as the column default, as a raw string (e.g. `'t'`,
|
|
6022
6049
|
* `0`, `now()`, `gen_random_uuid()`). `null` or omitted means no default.
|
|
6023
6050
|
* NOT a JS literal — must already be a valid SQL expression.
|
|
6024
6051
|
*/
|
|
6025
|
-
default:
|
|
6026
|
-
fieldType:
|
|
6027
|
-
fieldConfig:
|
|
6052
|
+
default: z9.string().nullable().optional(),
|
|
6053
|
+
fieldType: z9.string().optional(),
|
|
6054
|
+
fieldConfig: z9.record(z9.string(), z9.unknown()).optional()
|
|
6028
6055
|
});
|
|
6029
|
-
var referentialActionSchema =
|
|
6056
|
+
var referentialActionSchema = z9.enum([
|
|
6030
6057
|
"cascade",
|
|
6031
6058
|
"set null",
|
|
6032
6059
|
"set default",
|
|
6033
6060
|
"restrict",
|
|
6034
6061
|
"no action"
|
|
6035
6062
|
]);
|
|
6036
|
-
var schemaOpSchema =
|
|
6063
|
+
var schemaOpSchema = z9.discriminatedUnion("type", [
|
|
6037
6064
|
// Tables
|
|
6038
|
-
|
|
6039
|
-
type:
|
|
6040
|
-
table:
|
|
6041
|
-
columns:
|
|
6042
|
-
primaryKey:
|
|
6043
|
-
ifNotExists:
|
|
6065
|
+
z9.object({
|
|
6066
|
+
type: z9.literal("createTable"),
|
|
6067
|
+
table: z9.string().min(1).max(63),
|
|
6068
|
+
columns: z9.array(columnSpecSchema).min(1),
|
|
6069
|
+
primaryKey: z9.array(z9.string()).optional(),
|
|
6070
|
+
ifNotExists: z9.boolean().optional()
|
|
6044
6071
|
}),
|
|
6045
|
-
|
|
6046
|
-
type:
|
|
6047
|
-
table:
|
|
6048
|
-
cascade:
|
|
6049
|
-
ifExists:
|
|
6072
|
+
z9.object({
|
|
6073
|
+
type: z9.literal("dropTable"),
|
|
6074
|
+
table: z9.string().min(1).max(63),
|
|
6075
|
+
cascade: z9.boolean().optional(),
|
|
6076
|
+
ifExists: z9.boolean().optional()
|
|
6050
6077
|
}),
|
|
6051
|
-
|
|
6052
|
-
type:
|
|
6053
|
-
from:
|
|
6054
|
-
to:
|
|
6078
|
+
z9.object({
|
|
6079
|
+
type: z9.literal("renameTable"),
|
|
6080
|
+
from: z9.string().min(1).max(63),
|
|
6081
|
+
to: z9.string().min(1).max(63)
|
|
6055
6082
|
}),
|
|
6056
6083
|
// Columns
|
|
6057
|
-
|
|
6058
|
-
type:
|
|
6059
|
-
table:
|
|
6084
|
+
z9.object({
|
|
6085
|
+
type: z9.literal("addColumn"),
|
|
6086
|
+
table: z9.string().min(1).max(63),
|
|
6060
6087
|
column: columnSpecSchema,
|
|
6061
|
-
ifNotExists:
|
|
6088
|
+
ifNotExists: z9.boolean().optional()
|
|
6062
6089
|
}),
|
|
6063
|
-
|
|
6064
|
-
type:
|
|
6065
|
-
table:
|
|
6066
|
-
column:
|
|
6067
|
-
cascade:
|
|
6068
|
-
ifExists:
|
|
6090
|
+
z9.object({
|
|
6091
|
+
type: z9.literal("dropColumn"),
|
|
6092
|
+
table: z9.string().min(1).max(63),
|
|
6093
|
+
column: z9.string().min(1).max(63),
|
|
6094
|
+
cascade: z9.boolean().optional(),
|
|
6095
|
+
ifExists: z9.boolean().optional()
|
|
6069
6096
|
}),
|
|
6070
|
-
|
|
6071
|
-
type:
|
|
6072
|
-
table:
|
|
6073
|
-
from:
|
|
6074
|
-
to:
|
|
6097
|
+
z9.object({
|
|
6098
|
+
type: z9.literal("renameColumn"),
|
|
6099
|
+
table: z9.string().min(1).max(63),
|
|
6100
|
+
from: z9.string().min(1).max(63),
|
|
6101
|
+
to: z9.string().min(1).max(63)
|
|
6075
6102
|
}),
|
|
6076
|
-
|
|
6077
|
-
type:
|
|
6078
|
-
table:
|
|
6079
|
-
column:
|
|
6080
|
-
newType:
|
|
6103
|
+
z9.object({
|
|
6104
|
+
type: z9.literal("alterColumnType"),
|
|
6105
|
+
table: z9.string().min(1).max(63),
|
|
6106
|
+
column: z9.string().min(1).max(63),
|
|
6107
|
+
newType: z9.string().min(1),
|
|
6081
6108
|
/** Optional USING expression for potentially-lossy casts */
|
|
6082
|
-
using:
|
|
6109
|
+
using: z9.string().optional()
|
|
6083
6110
|
}),
|
|
6084
|
-
|
|
6085
|
-
type:
|
|
6086
|
-
table:
|
|
6087
|
-
column:
|
|
6088
|
-
nullable:
|
|
6111
|
+
z9.object({
|
|
6112
|
+
type: z9.literal("alterColumnNullable"),
|
|
6113
|
+
table: z9.string().min(1).max(63),
|
|
6114
|
+
column: z9.string().min(1).max(63),
|
|
6115
|
+
nullable: z9.boolean()
|
|
6089
6116
|
}),
|
|
6090
|
-
|
|
6091
|
-
type:
|
|
6092
|
-
table:
|
|
6093
|
-
column:
|
|
6117
|
+
z9.object({
|
|
6118
|
+
type: z9.literal("alterColumnDefault"),
|
|
6119
|
+
table: z9.string().min(1).max(63),
|
|
6120
|
+
column: z9.string().min(1).max(63),
|
|
6094
6121
|
/** null means drop the default; otherwise a SQL expression string. */
|
|
6095
|
-
default:
|
|
6122
|
+
default: z9.string().nullable()
|
|
6096
6123
|
}),
|
|
6097
6124
|
// Indexes
|
|
6098
|
-
|
|
6099
|
-
type:
|
|
6100
|
-
table:
|
|
6101
|
-
name:
|
|
6102
|
-
columns:
|
|
6103
|
-
unique:
|
|
6125
|
+
z9.object({
|
|
6126
|
+
type: z9.literal("addIndex"),
|
|
6127
|
+
table: z9.string().min(1).max(63),
|
|
6128
|
+
name: z9.string().min(1).max(63),
|
|
6129
|
+
columns: z9.array(z9.string().min(1)).min(1),
|
|
6130
|
+
unique: z9.boolean().optional(),
|
|
6104
6131
|
/** Partial-index WHERE clause, as a raw SQL expression */
|
|
6105
|
-
where:
|
|
6106
|
-
ifNotExists:
|
|
6132
|
+
where: z9.string().optional(),
|
|
6133
|
+
ifNotExists: z9.boolean().optional()
|
|
6107
6134
|
}),
|
|
6108
|
-
|
|
6109
|
-
type:
|
|
6110
|
-
name:
|
|
6111
|
-
cascade:
|
|
6112
|
-
ifExists:
|
|
6135
|
+
z9.object({
|
|
6136
|
+
type: z9.literal("dropIndex"),
|
|
6137
|
+
name: z9.string().min(1).max(63),
|
|
6138
|
+
cascade: z9.boolean().optional(),
|
|
6139
|
+
ifExists: z9.boolean().optional()
|
|
6113
6140
|
}),
|
|
6114
6141
|
// Constraints
|
|
6115
|
-
|
|
6116
|
-
type:
|
|
6117
|
-
table:
|
|
6118
|
-
name:
|
|
6119
|
-
columns:
|
|
6120
|
-
refTable:
|
|
6121
|
-
refColumns:
|
|
6142
|
+
z9.object({
|
|
6143
|
+
type: z9.literal("addForeignKey"),
|
|
6144
|
+
table: z9.string().min(1).max(63),
|
|
6145
|
+
name: z9.string().min(1).max(63),
|
|
6146
|
+
columns: z9.array(z9.string().min(1)).min(1),
|
|
6147
|
+
refTable: z9.string().min(1).max(63),
|
|
6148
|
+
refColumns: z9.array(z9.string().min(1)).min(1),
|
|
6122
6149
|
onDelete: referentialActionSchema.optional(),
|
|
6123
6150
|
onUpdate: referentialActionSchema.optional()
|
|
6124
6151
|
}),
|
|
6125
|
-
|
|
6126
|
-
type:
|
|
6127
|
-
table:
|
|
6128
|
-
name:
|
|
6129
|
-
columns:
|
|
6152
|
+
z9.object({
|
|
6153
|
+
type: z9.literal("addUniqueConstraint"),
|
|
6154
|
+
table: z9.string().min(1).max(63),
|
|
6155
|
+
name: z9.string().min(1).max(63),
|
|
6156
|
+
columns: z9.array(z9.string().min(1)).min(1)
|
|
6130
6157
|
}),
|
|
6131
|
-
|
|
6132
|
-
type:
|
|
6133
|
-
table:
|
|
6134
|
-
name:
|
|
6135
|
-
expression:
|
|
6158
|
+
z9.object({
|
|
6159
|
+
type: z9.literal("addCheckConstraint"),
|
|
6160
|
+
table: z9.string().min(1).max(63),
|
|
6161
|
+
name: z9.string().min(1).max(63),
|
|
6162
|
+
expression: z9.string().min(1)
|
|
6136
6163
|
}),
|
|
6137
|
-
|
|
6138
|
-
type:
|
|
6139
|
-
table:
|
|
6140
|
-
name:
|
|
6141
|
-
cascade:
|
|
6142
|
-
ifExists:
|
|
6164
|
+
z9.object({
|
|
6165
|
+
type: z9.literal("dropConstraint"),
|
|
6166
|
+
table: z9.string().min(1).max(63),
|
|
6167
|
+
name: z9.string().min(1).max(63),
|
|
6168
|
+
cascade: z9.boolean().optional(),
|
|
6169
|
+
ifExists: z9.boolean().optional()
|
|
6143
6170
|
}),
|
|
6144
6171
|
// Enum types
|
|
6145
|
-
|
|
6146
|
-
type:
|
|
6147
|
-
name:
|
|
6148
|
-
values:
|
|
6172
|
+
z9.object({
|
|
6173
|
+
type: z9.literal("createEnum"),
|
|
6174
|
+
name: z9.string().min(1).max(63),
|
|
6175
|
+
values: z9.array(z9.string().min(1)).min(1)
|
|
6149
6176
|
}),
|
|
6150
|
-
|
|
6151
|
-
type:
|
|
6152
|
-
name:
|
|
6153
|
-
value:
|
|
6177
|
+
z9.object({
|
|
6178
|
+
type: z9.literal("alterEnumAddValue"),
|
|
6179
|
+
name: z9.string().min(1).max(63),
|
|
6180
|
+
value: z9.string().min(1),
|
|
6154
6181
|
/** Position the new value before an existing one (mutually exclusive with `after`) */
|
|
6155
|
-
before:
|
|
6182
|
+
before: z9.string().optional(),
|
|
6156
6183
|
/** Position the new value after an existing one (mutually exclusive with `before`) */
|
|
6157
|
-
after:
|
|
6158
|
-
ifNotExists:
|
|
6184
|
+
after: z9.string().optional(),
|
|
6185
|
+
ifNotExists: z9.boolean().optional()
|
|
6159
6186
|
}),
|
|
6160
|
-
|
|
6161
|
-
type:
|
|
6162
|
-
name:
|
|
6163
|
-
cascade:
|
|
6164
|
-
ifExists:
|
|
6187
|
+
z9.object({
|
|
6188
|
+
type: z9.literal("dropEnum"),
|
|
6189
|
+
name: z9.string().min(1).max(63),
|
|
6190
|
+
cascade: z9.boolean().optional(),
|
|
6191
|
+
ifExists: z9.boolean().optional()
|
|
6165
6192
|
}),
|
|
6166
6193
|
// Extensions
|
|
6167
|
-
|
|
6168
|
-
type:
|
|
6169
|
-
name:
|
|
6170
|
-
ifNotExists:
|
|
6194
|
+
z9.object({
|
|
6195
|
+
type: z9.literal("createExtension"),
|
|
6196
|
+
name: z9.string().min(1),
|
|
6197
|
+
ifNotExists: z9.boolean().optional()
|
|
6171
6198
|
}),
|
|
6172
6199
|
// Data operations
|
|
6173
6200
|
/**
|
|
@@ -6175,26 +6202,26 @@ var schemaOpSchema = z8.discriminatedUnion("type", [
|
|
|
6175
6202
|
* destructive — requires explicit confirm to replay on prod. The
|
|
6176
6203
|
* `description` is what the agent/user sees at confirm time.
|
|
6177
6204
|
*/
|
|
6178
|
-
|
|
6179
|
-
type:
|
|
6180
|
-
description:
|
|
6181
|
-
sql:
|
|
6205
|
+
z9.object({
|
|
6206
|
+
type: z9.literal("backfill"),
|
|
6207
|
+
description: z9.string().min(1),
|
|
6208
|
+
sql: z9.string().min(1)
|
|
6182
6209
|
}),
|
|
6183
6210
|
/**
|
|
6184
6211
|
* Escape hatch for DDL the structured ops can't express. `destructive`
|
|
6185
6212
|
* forces classification — use false only for genuinely additive-only SQL
|
|
6186
6213
|
* (e.g. CREATE EXTENSION variants the structured op doesn't cover).
|
|
6187
6214
|
*/
|
|
6188
|
-
|
|
6189
|
-
type:
|
|
6190
|
-
description:
|
|
6191
|
-
sql:
|
|
6192
|
-
destructive:
|
|
6215
|
+
z9.object({
|
|
6216
|
+
type: z9.literal("rawSql"),
|
|
6217
|
+
description: z9.string().min(1),
|
|
6218
|
+
sql: z9.string().min(1),
|
|
6219
|
+
destructive: z9.boolean()
|
|
6193
6220
|
})
|
|
6194
6221
|
]);
|
|
6195
6222
|
|
|
6196
6223
|
// ../../packages/lib/src/server/module-rail/ops.ts
|
|
6197
|
-
import { z as
|
|
6224
|
+
import { z as z10 } from "zod";
|
|
6198
6225
|
|
|
6199
6226
|
// ../../packages/lib/src/server/module-rail/reconcile.ts
|
|
6200
6227
|
var SANDBOX_BATCH_SIZE = 200;
|
|
@@ -6307,39 +6334,24 @@ async function assertNoRootRoutesWhenMountsEmpty(context, moduleName) {
|
|
|
6307
6334
|
);
|
|
6308
6335
|
}
|
|
6309
6336
|
}
|
|
6310
|
-
async function
|
|
6311
|
-
const
|
|
6312
|
-
const
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
for (const entry of enhancementEntries) {
|
|
6317
|
-
if (entry.kind !== "dir") continue;
|
|
6318
|
-
const sliceRoutes = `${enhancementsDir}/${entry.name}/routes`;
|
|
6319
|
-
const sliceProbe = await context.sandbox.exec(
|
|
6320
|
-
[
|
|
6321
|
-
`p=${shellQuote(sliceRoutes)}`,
|
|
6322
|
-
`if test -L "$p" || test -e "$p"; then exit 2; else exit 0; fi`
|
|
6323
|
-
].join("\n"),
|
|
6324
|
-
{ raiseOnError: false }
|
|
6325
|
-
);
|
|
6326
|
-
if (sliceProbe.exitCode === 2) {
|
|
6337
|
+
async function assertNoEnhancementRoutePaths(context, paths) {
|
|
6338
|
+
const kinds = await classifySandboxPathPresenceKindMany(context, paths, "enhancement-route-kind");
|
|
6339
|
+
for (const sliceRoutes of paths) {
|
|
6340
|
+
const kind = kinds.get(sliceRoutes);
|
|
6341
|
+
if (kind === "absent") continue;
|
|
6342
|
+
if (kind !== "unreadable" && kind !== void 0) {
|
|
6327
6343
|
throw new Error(
|
|
6328
6344
|
`[ModuleRail] composition artifacts: enhancement slice routes/ are forbidden at ${sliceRoutes}`
|
|
6329
6345
|
);
|
|
6330
6346
|
}
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
`[ModuleRail] composition artifacts: cannot probe ${sliceRoutes}: ${redactSecrets(detail)}`
|
|
6335
|
-
);
|
|
6336
|
-
}
|
|
6347
|
+
throw new Error(
|
|
6348
|
+
`[ModuleRail] composition artifacts: cannot probe ${sliceRoutes}: entry-kind:${kind ?? "missing"}`
|
|
6349
|
+
);
|
|
6337
6350
|
}
|
|
6338
6351
|
}
|
|
6339
|
-
async function
|
|
6352
|
+
async function discoverRootRouteEntries(context, moduleName) {
|
|
6340
6353
|
const modulePath = `${MODULES_SANDBOX_DIR}/${moduleName}`;
|
|
6341
6354
|
const routesDir = `${modulePath}/routes`;
|
|
6342
|
-
await assertNoEnhancementRoutes(context, moduleName);
|
|
6343
6355
|
const quotedRoutes = shellQuote(routesDir);
|
|
6344
6356
|
const listResult = await context.sandbox.exec(
|
|
6345
6357
|
[
|
|
@@ -6793,7 +6805,8 @@ async function classifySandboxPathPresenceKindMany(context, paths, probeToken) {
|
|
|
6793
6805
|
`# Leaf is missing. A missing intermediate parent means the path is simply`,
|
|
6794
6806
|
`# absent (new nested writes). Only an existing-but-inaccessible parent`,
|
|
6795
6807
|
`# is unreadable \u2014 never conflate ENOENT parents with EACCES.`,
|
|
6796
|
-
|
|
6808
|
+
// Probe paths are nested repo-relative paths; do not spawn dirname per missing file.
|
|
6809
|
+
`parent=\${p%/*}`,
|
|
6797
6810
|
`if test ! -e "$parent" && test ! -L "$parent"; then`,
|
|
6798
6811
|
` printf 'entry-kind:absent\\t%s\\n' "$p"`,
|
|
6799
6812
|
`elif ls -ld -- "$parent" >/dev/null 2>&1; then`,
|
|
@@ -7338,14 +7351,21 @@ async function reconcileCompositionArtifacts(context, options = {}) {
|
|
|
7338
7351
|
manifestsByName
|
|
7339
7352
|
);
|
|
7340
7353
|
const routeEntriesByOwner = {};
|
|
7354
|
+
await assertNoEnhancementRoutePaths(
|
|
7355
|
+
context,
|
|
7356
|
+
moduleRuntimeFacts.flatMap(
|
|
7357
|
+
({ moduleName, onDiskEnhancementDirs }) => onDiskEnhancementDirs.map(
|
|
7358
|
+
(peer) => `${MODULES_SANDBOX_DIR}/${moduleName}/enhancements/${peer}/routes`
|
|
7359
|
+
)
|
|
7360
|
+
)
|
|
7361
|
+
);
|
|
7341
7362
|
for (const moduleName of composedNames) {
|
|
7342
7363
|
const manifest = manifestsByName[moduleName];
|
|
7343
|
-
await assertNoEnhancementRoutes(context, moduleName);
|
|
7344
7364
|
if (manifest.mounts.length === 0) {
|
|
7345
7365
|
await assertNoRootRoutesWhenMountsEmpty(context, moduleName);
|
|
7346
7366
|
routeEntriesByOwner[moduleName] = [];
|
|
7347
7367
|
} else {
|
|
7348
|
-
routeEntriesByOwner[moduleName] = await
|
|
7368
|
+
routeEntriesByOwner[moduleName] = await discoverRootRouteEntries(context, moduleName);
|
|
7349
7369
|
}
|
|
7350
7370
|
}
|
|
7351
7371
|
const existingGeneratedPaths = await listExistingGeneratedStubPaths(context);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stardeck-customer-apps/compose",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Regenerates a Stardeck app's Module-rail artifacts — the six src/*.gen.ts registries and every route/endpoint stub — from src/modules/*/module.json",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"build": "rm -rf dist && tsup",
|
|
35
35
|
"dev": "tsup --watch",
|
|
36
36
|
"format": "prettier --write . && oxlint . --fix",
|
|
37
|
-
"typecheck": "
|
|
37
|
+
"typecheck": "node ../../scripts/typecheck.mjs -p tsconfig.test.json",
|
|
38
38
|
"lint": "oxlint src/",
|
|
39
39
|
"test": "vitest run",
|
|
40
40
|
"test:watch": "vitest"
|