@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/dist/index.js CHANGED
@@ -1149,16 +1149,16 @@ var require_range = __commonJS({
1149
1149
  };
1150
1150
  var replaceTilde = (comp, options) => {
1151
1151
  const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE];
1152
- const z10 = options.includePrerelease ? "-0" : "";
1152
+ const z11 = options.includePrerelease ? "-0" : "";
1153
1153
  return comp.replace(r, (_, M, m, p, pr) => {
1154
1154
  debug("tilde", comp, _, M, m, p, pr);
1155
1155
  let ret;
1156
1156
  if (isX(M)) {
1157
1157
  ret = "";
1158
1158
  } else if (isX(m)) {
1159
- ret = `>=${M}.0.0${z10} <${+M + 1}.0.0-0`;
1159
+ ret = `>=${M}.0.0${z11} <${+M + 1}.0.0-0`;
1160
1160
  } else if (isX(p)) {
1161
- ret = `>=${M}.${m}.0${z10} <${M}.${+m + 1}.0-0`;
1161
+ ret = `>=${M}.${m}.0${z11} <${M}.${+m + 1}.0-0`;
1162
1162
  } else if (pr) {
1163
1163
  debug("replaceTilde pr", pr);
1164
1164
  ret = `>=${M}.${m}.${p}-${pr} <${M}.${+m + 1}.0-0`;
@@ -1175,19 +1175,19 @@ var require_range = __commonJS({
1175
1175
  var replaceCaret = (comp, options) => {
1176
1176
  debug("caret", comp, options);
1177
1177
  const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET];
1178
- const z10 = options.includePrerelease ? "-0" : "";
1178
+ const z11 = options.includePrerelease ? "-0" : "";
1179
1179
  return comp.replace(r, (_, M, m, p, pr) => {
1180
1180
  debug("caret", comp, _, M, m, p, pr);
1181
1181
  let ret;
1182
1182
  if (isX(M)) {
1183
1183
  ret = "";
1184
1184
  } else if (isX(m)) {
1185
- ret = `>=${M}.0.0${z10} <${+M + 1}.0.0-0`;
1185
+ ret = `>=${M}.0.0${z11} <${+M + 1}.0.0-0`;
1186
1186
  } else if (isX(p)) {
1187
1187
  if (M === "0") {
1188
- ret = `>=${M}.${m}.0${z10} <${M}.${+m + 1}.0-0`;
1188
+ ret = `>=${M}.${m}.0${z11} <${M}.${+m + 1}.0-0`;
1189
1189
  } else {
1190
- ret = `>=${M}.${m}.0${z10} <${+M + 1}.0.0-0`;
1190
+ ret = `>=${M}.${m}.0${z11} <${+M + 1}.0.0-0`;
1191
1191
  }
1192
1192
  } else if (pr) {
1193
1193
  debug("replaceCaret pr", pr);
@@ -2097,6 +2097,7 @@ var JSON_SECRET_PAIR = new RegExp(
2097
2097
  "g"
2098
2098
  );
2099
2099
  var SECRET_QUOTE_OPENER = new RegExp(String.raw`\b${SECRET_NAME}\s*=\s*(['"])`, "g");
2100
+ var SHELL_QUOTE_CONTINUATION = String.raw`\''`;
2100
2101
  function redactSecrets(text) {
2101
2102
  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***");
2102
2103
  }
@@ -2388,10 +2389,12 @@ var modulePermissionClaimSchema = import_zod2.z.object({
2388
2389
  /** Human label for the deployment auth config row. */
2389
2390
  description: descriptionSchema,
2390
2391
  /**
2391
- * The default organization roles that hold this key when the platform
2392
- * first registers it on an app (a Blueprint fork, a Module install). Admin
2393
- * holds every key without being listed; External Viewer never holds one.
2394
- * Changing a role's grants afterwards is the organization's business.
2392
+ * The standard organization roles that hold this key. The platform sets them on every app
2393
+ * (a Blueprint fork, a Module install or uninstall, every Blueprint update), so this list is
2394
+ * the truth: a role added here gains the key, a role removed loses it, and nobody can edit a
2395
+ * standard role's grants on a Module key. Admin holds every key without being listed;
2396
+ * External Viewer never holds one. An organization that wants different access duplicates the
2397
+ * standard role and edits the copy.
2395
2398
  */
2396
2399
  roles: import_zod2.z.array(import_zod2.z.enum(MODULE_PERMISSION_DEFAULT_ROLES)).optional()
2397
2400
  }).strict();
@@ -4033,6 +4036,24 @@ function analyzeClientSafeEntryImports(sourceText, fileName) {
4033
4036
  return analyzeClientSafeEntryImportsWithTs(import_typescript3.default, sourceText, fileName);
4034
4037
  }
4035
4038
 
4039
+ // ../../packages/lib/src/shared/ownership-record.ts
4040
+ var import_zod7 = require("zod");
4041
+ var OWNERSHIP_RECORD_VERSION = 1;
4042
+ var moduleList = import_zod7.z.array(import_zod7.z.string().refine(isValidModuleName, "not a Module name"));
4043
+ var ownershipRecordSchema = import_zod7.z.object({
4044
+ version: import_zod7.z.literal(OWNERSHIP_RECORD_VERSION),
4045
+ /** False once the app stopped all Stardeck updates: then every file is the app's. */
4046
+ stardeckUpdates: import_zod7.z.boolean(),
4047
+ /** projects.ejected_modules: updates stopped for these Modules, so their folders are the app's. */
4048
+ updatesStoppedModules: moduleList,
4049
+ /** projects.ui_ejected_modules: Customize UI, so their screens are the app's. */
4050
+ customizedUiModules: moduleList,
4051
+ /** projects.external_modules: installed from another app, so the app owns the copy. */
4052
+ externalModules: moduleList,
4053
+ /** projects.removed_modules names: uninstalled on purpose. */
4054
+ uninstalledModules: moduleList
4055
+ });
4056
+
4036
4057
  // ../../packages/lib/src/shared/platform-owned-paths.ts
4037
4058
  var APP_WEB_PREFIX = "apps/web/";
4038
4059
  var BLUEPRINT_LINT_MARKER = `${APP_WEB_PREFIX}eslint-rules/module-boundaries.mjs`;
@@ -4837,6 +4858,9 @@ function enhancementImport(owner, peer) {
4837
4858
  function scopeLabel(scope) {
4838
4859
  return scope.kind === "root" ? "root" : `enhancement:${scope.peer}`;
4839
4860
  }
4861
+ function endpointMarkerOwnsStub(marker, stub) {
4862
+ return stub != null && marker?.kind === "endpoint" && marker.owner === stub.owner;
4863
+ }
4840
4864
  function formatEndpointMarker(owner, scope) {
4841
4865
  return `// ${MODULE_STUB_MARKER} owner=${owner} scope=${scopeLabel(scope)}`;
4842
4866
  }
@@ -5538,7 +5562,7 @@ function planCompositionArtifacts(input) {
5538
5562
  const legacy = parseLegacyApiAdapter(pagePath, content);
5539
5563
  const plannedRoute = plannedRouteByPath.get(pagePath);
5540
5564
  const plannedEndpoint = plannedEndpointByPath.get(pagePath);
5541
- const isExactPlannedMatch = plannedRoute != null && marker != null && marker.kind === "route" && marker.owner === plannedRoute.owner && marker.nextRelativePath === plannedRoute.nextRelativePath || plannedEndpoint != null && (marker != null && marker.kind === "endpoint" && marker.owner === plannedEndpoint.owner && scopeLabel(marker.scope) === scopeLabel(plannedEndpoint.scope) || legacy != null) || plannedRoute != null && legacyRouteAdapterMatchesStub(pagePath, content, plannedRoute);
5565
+ 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);
5542
5566
  if (isExactPlannedMatch) {
5543
5567
  continue;
5544
5568
  }
@@ -5681,9 +5705,7 @@ function planCompositionArtifacts(input) {
5681
5705
  }
5682
5706
  if (marker.kind === "endpoint") {
5683
5707
  const stub = endpointStubByPath.get(path4);
5684
- const ownerMatches = stub != null && marker.owner === stub.owner;
5685
- const scopeMatches = stub != null && scopeLabel(marker.scope) === scopeLabel(stub.scope);
5686
- if (!ownerMatches || !scopeMatches) {
5708
+ if (!endpointMarkerOwnsStub(marker, stub)) {
5687
5709
  return {
5688
5710
  ok: false,
5689
5711
  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) : "?"})`,
@@ -5986,14 +6008,14 @@ function rejectPseudoModuleEntries(entries, parentDir, label) {
5986
6008
  }
5987
6009
 
5988
6010
  // ../../packages/lib/src/shared/module-composition.ts
5989
- var import_zod7 = require("zod");
5990
- var creationSourceBlankSchema = import_zod7.z.object({
5991
- type: import_zod7.z.literal("blank")
6011
+ var import_zod8 = require("zod");
6012
+ var creationSourceBlankSchema = import_zod8.z.object({
6013
+ type: import_zod8.z.literal("blank")
5992
6014
  });
5993
- var creationSourceBlueprintSchema = import_zod7.z.object({
5994
- type: import_zod7.z.literal("blueprint"),
6015
+ var creationSourceBlueprintSchema = import_zod8.z.object({
6016
+ type: import_zod8.z.literal("blueprint"),
5995
6017
  /** Internal template/fork project id — keep template naming in identifiers. */
5996
- blueprintProjectId: import_zod7.z.string().uuid(),
6018
+ blueprintProjectId: import_zod8.z.string().uuid(),
5997
6019
  /**
5998
6020
  * `null`/absent means every feature Module: the platform stores that as the
5999
6021
  * explicit list of feature Modules in the published Blueprint version the fork
@@ -6001,192 +6023,197 @@ var creationSourceBlueprintSchema = import_zod7.z.object({
6001
6023
  * a custom app: no feature Module, Library Modules only (`resolvePlatformEnv`
6002
6024
  * emits it as a set value naming no Module).
6003
6025
  */
6004
- enabledModules: import_zod7.z.array(moduleNameSchema).max(100).nullable().optional()
6026
+ enabledModules: import_zod8.z.array(moduleNameSchema).max(100).nullable().optional(),
6027
+ /**
6028
+ * The kind of business (a preset id the published version defines). Its Modules are built
6029
+ * and `enabledModules` adds extras on top; for the general kind `enabledModules` is the pick.
6030
+ */
6031
+ businessKind: import_zod8.z.string().regex(/^[a-z][a-z0-9-]{0,39}$/).optional()
6005
6032
  });
6006
- var creationSourceSchema = import_zod7.z.discriminatedUnion("type", [
6033
+ var creationSourceSchema = import_zod8.z.discriminatedUnion("type", [
6007
6034
  creationSourceBlankSchema,
6008
6035
  creationSourceBlueprintSchema
6009
6036
  ]);
6010
- var moduleInstallHandoffSchema = import_zod7.z.object({
6011
- moduleName: import_zod7.z.string().min(1),
6012
- homeProjectId: import_zod7.z.string().uuid(),
6013
- installedVersion: import_zod7.z.string().min(1),
6014
- baselineSha: import_zod7.z.string().min(1),
6015
- mounts: import_zod7.z.array(
6016
- import_zod7.z.object({
6017
- group: import_zod7.z.string(),
6018
- segment: import_zod7.z.string()
6037
+ var moduleInstallHandoffSchema = import_zod8.z.object({
6038
+ moduleName: import_zod8.z.string().min(1),
6039
+ homeProjectId: import_zod8.z.string().uuid(),
6040
+ installedVersion: import_zod8.z.string().min(1),
6041
+ baselineSha: import_zod8.z.string().min(1),
6042
+ mounts: import_zod8.z.array(
6043
+ import_zod8.z.object({
6044
+ group: import_zod8.z.string(),
6045
+ segment: import_zod8.z.string()
6019
6046
  })
6020
6047
  ),
6021
- integration: import_zod7.z.array(import_zod7.z.string()),
6022
- workflows: import_zod7.z.array(import_zod7.z.string()),
6023
- prunedEnhancements: import_zod7.z.array(import_zod7.z.string()),
6024
- restoredEnhancements: import_zod7.z.array(import_zod7.z.string()).optional(),
6025
- permissions: import_zod7.z.array(
6026
- import_zod7.z.object({
6027
- key: import_zod7.z.string().min(1),
6028
- description: import_zod7.z.string().min(1)
6048
+ integration: import_zod8.z.array(import_zod8.z.string()),
6049
+ workflows: import_zod8.z.array(import_zod8.z.string()),
6050
+ prunedEnhancements: import_zod8.z.array(import_zod8.z.string()),
6051
+ restoredEnhancements: import_zod8.z.array(import_zod8.z.string()).optional(),
6052
+ permissions: import_zod8.z.array(
6053
+ import_zod8.z.object({
6054
+ key: import_zod8.z.string().min(1),
6055
+ description: import_zod8.z.string().min(1)
6029
6056
  })
6030
6057
  ).optional()
6031
6058
  });
6032
6059
 
6033
6060
  // ../../packages/lib/src/shared/schema-ops.ts
6034
- var import_zod8 = require("zod");
6035
- var columnSpecSchema = import_zod8.z.object({
6036
- name: import_zod8.z.string().min(1).max(63),
6037
- pgType: import_zod8.z.string().min(1),
6038
- nullable: import_zod8.z.boolean(),
6061
+ var import_zod9 = require("zod");
6062
+ var columnSpecSchema = import_zod9.z.object({
6063
+ name: import_zod9.z.string().min(1).max(63),
6064
+ pgType: import_zod9.z.string().min(1),
6065
+ nullable: import_zod9.z.boolean(),
6039
6066
  /**
6040
6067
  * A SQL expression used as the column default, as a raw string (e.g. `'t'`,
6041
6068
  * `0`, `now()`, `gen_random_uuid()`). `null` or omitted means no default.
6042
6069
  * NOT a JS literal — must already be a valid SQL expression.
6043
6070
  */
6044
- default: import_zod8.z.string().nullable().optional(),
6045
- fieldType: import_zod8.z.string().optional(),
6046
- fieldConfig: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.unknown()).optional()
6071
+ default: import_zod9.z.string().nullable().optional(),
6072
+ fieldType: import_zod9.z.string().optional(),
6073
+ fieldConfig: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.unknown()).optional()
6047
6074
  });
6048
- var referentialActionSchema = import_zod8.z.enum([
6075
+ var referentialActionSchema = import_zod9.z.enum([
6049
6076
  "cascade",
6050
6077
  "set null",
6051
6078
  "set default",
6052
6079
  "restrict",
6053
6080
  "no action"
6054
6081
  ]);
6055
- var schemaOpSchema = import_zod8.z.discriminatedUnion("type", [
6082
+ var schemaOpSchema = import_zod9.z.discriminatedUnion("type", [
6056
6083
  // Tables
6057
- import_zod8.z.object({
6058
- type: import_zod8.z.literal("createTable"),
6059
- table: import_zod8.z.string().min(1).max(63),
6060
- columns: import_zod8.z.array(columnSpecSchema).min(1),
6061
- primaryKey: import_zod8.z.array(import_zod8.z.string()).optional(),
6062
- ifNotExists: import_zod8.z.boolean().optional()
6084
+ import_zod9.z.object({
6085
+ type: import_zod9.z.literal("createTable"),
6086
+ table: import_zod9.z.string().min(1).max(63),
6087
+ columns: import_zod9.z.array(columnSpecSchema).min(1),
6088
+ primaryKey: import_zod9.z.array(import_zod9.z.string()).optional(),
6089
+ ifNotExists: import_zod9.z.boolean().optional()
6063
6090
  }),
6064
- import_zod8.z.object({
6065
- type: import_zod8.z.literal("dropTable"),
6066
- table: import_zod8.z.string().min(1).max(63),
6067
- cascade: import_zod8.z.boolean().optional(),
6068
- ifExists: import_zod8.z.boolean().optional()
6091
+ import_zod9.z.object({
6092
+ type: import_zod9.z.literal("dropTable"),
6093
+ table: import_zod9.z.string().min(1).max(63),
6094
+ cascade: import_zod9.z.boolean().optional(),
6095
+ ifExists: import_zod9.z.boolean().optional()
6069
6096
  }),
6070
- import_zod8.z.object({
6071
- type: import_zod8.z.literal("renameTable"),
6072
- from: import_zod8.z.string().min(1).max(63),
6073
- to: import_zod8.z.string().min(1).max(63)
6097
+ import_zod9.z.object({
6098
+ type: import_zod9.z.literal("renameTable"),
6099
+ from: import_zod9.z.string().min(1).max(63),
6100
+ to: import_zod9.z.string().min(1).max(63)
6074
6101
  }),
6075
6102
  // Columns
6076
- import_zod8.z.object({
6077
- type: import_zod8.z.literal("addColumn"),
6078
- table: import_zod8.z.string().min(1).max(63),
6103
+ import_zod9.z.object({
6104
+ type: import_zod9.z.literal("addColumn"),
6105
+ table: import_zod9.z.string().min(1).max(63),
6079
6106
  column: columnSpecSchema,
6080
- ifNotExists: import_zod8.z.boolean().optional()
6107
+ ifNotExists: import_zod9.z.boolean().optional()
6081
6108
  }),
6082
- import_zod8.z.object({
6083
- type: import_zod8.z.literal("dropColumn"),
6084
- table: import_zod8.z.string().min(1).max(63),
6085
- column: import_zod8.z.string().min(1).max(63),
6086
- cascade: import_zod8.z.boolean().optional(),
6087
- ifExists: import_zod8.z.boolean().optional()
6109
+ import_zod9.z.object({
6110
+ type: import_zod9.z.literal("dropColumn"),
6111
+ table: import_zod9.z.string().min(1).max(63),
6112
+ column: import_zod9.z.string().min(1).max(63),
6113
+ cascade: import_zod9.z.boolean().optional(),
6114
+ ifExists: import_zod9.z.boolean().optional()
6088
6115
  }),
6089
- import_zod8.z.object({
6090
- type: import_zod8.z.literal("renameColumn"),
6091
- table: import_zod8.z.string().min(1).max(63),
6092
- from: import_zod8.z.string().min(1).max(63),
6093
- to: import_zod8.z.string().min(1).max(63)
6116
+ import_zod9.z.object({
6117
+ type: import_zod9.z.literal("renameColumn"),
6118
+ table: import_zod9.z.string().min(1).max(63),
6119
+ from: import_zod9.z.string().min(1).max(63),
6120
+ to: import_zod9.z.string().min(1).max(63)
6094
6121
  }),
6095
- import_zod8.z.object({
6096
- type: import_zod8.z.literal("alterColumnType"),
6097
- table: import_zod8.z.string().min(1).max(63),
6098
- column: import_zod8.z.string().min(1).max(63),
6099
- newType: import_zod8.z.string().min(1),
6122
+ import_zod9.z.object({
6123
+ type: import_zod9.z.literal("alterColumnType"),
6124
+ table: import_zod9.z.string().min(1).max(63),
6125
+ column: import_zod9.z.string().min(1).max(63),
6126
+ newType: import_zod9.z.string().min(1),
6100
6127
  /** Optional USING expression for potentially-lossy casts */
6101
- using: import_zod8.z.string().optional()
6128
+ using: import_zod9.z.string().optional()
6102
6129
  }),
6103
- import_zod8.z.object({
6104
- type: import_zod8.z.literal("alterColumnNullable"),
6105
- table: import_zod8.z.string().min(1).max(63),
6106
- column: import_zod8.z.string().min(1).max(63),
6107
- nullable: import_zod8.z.boolean()
6130
+ import_zod9.z.object({
6131
+ type: import_zod9.z.literal("alterColumnNullable"),
6132
+ table: import_zod9.z.string().min(1).max(63),
6133
+ column: import_zod9.z.string().min(1).max(63),
6134
+ nullable: import_zod9.z.boolean()
6108
6135
  }),
6109
- import_zod8.z.object({
6110
- type: import_zod8.z.literal("alterColumnDefault"),
6111
- table: import_zod8.z.string().min(1).max(63),
6112
- column: import_zod8.z.string().min(1).max(63),
6136
+ import_zod9.z.object({
6137
+ type: import_zod9.z.literal("alterColumnDefault"),
6138
+ table: import_zod9.z.string().min(1).max(63),
6139
+ column: import_zod9.z.string().min(1).max(63),
6113
6140
  /** null means drop the default; otherwise a SQL expression string. */
6114
- default: import_zod8.z.string().nullable()
6141
+ default: import_zod9.z.string().nullable()
6115
6142
  }),
6116
6143
  // Indexes
6117
- import_zod8.z.object({
6118
- type: import_zod8.z.literal("addIndex"),
6119
- table: import_zod8.z.string().min(1).max(63),
6120
- name: import_zod8.z.string().min(1).max(63),
6121
- columns: import_zod8.z.array(import_zod8.z.string().min(1)).min(1),
6122
- unique: import_zod8.z.boolean().optional(),
6144
+ import_zod9.z.object({
6145
+ type: import_zod9.z.literal("addIndex"),
6146
+ table: import_zod9.z.string().min(1).max(63),
6147
+ name: import_zod9.z.string().min(1).max(63),
6148
+ columns: import_zod9.z.array(import_zod9.z.string().min(1)).min(1),
6149
+ unique: import_zod9.z.boolean().optional(),
6123
6150
  /** Partial-index WHERE clause, as a raw SQL expression */
6124
- where: import_zod8.z.string().optional(),
6125
- ifNotExists: import_zod8.z.boolean().optional()
6151
+ where: import_zod9.z.string().optional(),
6152
+ ifNotExists: import_zod9.z.boolean().optional()
6126
6153
  }),
6127
- import_zod8.z.object({
6128
- type: import_zod8.z.literal("dropIndex"),
6129
- name: import_zod8.z.string().min(1).max(63),
6130
- cascade: import_zod8.z.boolean().optional(),
6131
- ifExists: import_zod8.z.boolean().optional()
6154
+ import_zod9.z.object({
6155
+ type: import_zod9.z.literal("dropIndex"),
6156
+ name: import_zod9.z.string().min(1).max(63),
6157
+ cascade: import_zod9.z.boolean().optional(),
6158
+ ifExists: import_zod9.z.boolean().optional()
6132
6159
  }),
6133
6160
  // Constraints
6134
- import_zod8.z.object({
6135
- type: import_zod8.z.literal("addForeignKey"),
6136
- table: import_zod8.z.string().min(1).max(63),
6137
- name: import_zod8.z.string().min(1).max(63),
6138
- columns: import_zod8.z.array(import_zod8.z.string().min(1)).min(1),
6139
- refTable: import_zod8.z.string().min(1).max(63),
6140
- refColumns: import_zod8.z.array(import_zod8.z.string().min(1)).min(1),
6161
+ import_zod9.z.object({
6162
+ type: import_zod9.z.literal("addForeignKey"),
6163
+ table: import_zod9.z.string().min(1).max(63),
6164
+ name: import_zod9.z.string().min(1).max(63),
6165
+ columns: import_zod9.z.array(import_zod9.z.string().min(1)).min(1),
6166
+ refTable: import_zod9.z.string().min(1).max(63),
6167
+ refColumns: import_zod9.z.array(import_zod9.z.string().min(1)).min(1),
6141
6168
  onDelete: referentialActionSchema.optional(),
6142
6169
  onUpdate: referentialActionSchema.optional()
6143
6170
  }),
6144
- import_zod8.z.object({
6145
- type: import_zod8.z.literal("addUniqueConstraint"),
6146
- table: import_zod8.z.string().min(1).max(63),
6147
- name: import_zod8.z.string().min(1).max(63),
6148
- columns: import_zod8.z.array(import_zod8.z.string().min(1)).min(1)
6171
+ import_zod9.z.object({
6172
+ type: import_zod9.z.literal("addUniqueConstraint"),
6173
+ table: import_zod9.z.string().min(1).max(63),
6174
+ name: import_zod9.z.string().min(1).max(63),
6175
+ columns: import_zod9.z.array(import_zod9.z.string().min(1)).min(1)
6149
6176
  }),
6150
- import_zod8.z.object({
6151
- type: import_zod8.z.literal("addCheckConstraint"),
6152
- table: import_zod8.z.string().min(1).max(63),
6153
- name: import_zod8.z.string().min(1).max(63),
6154
- expression: import_zod8.z.string().min(1)
6177
+ import_zod9.z.object({
6178
+ type: import_zod9.z.literal("addCheckConstraint"),
6179
+ table: import_zod9.z.string().min(1).max(63),
6180
+ name: import_zod9.z.string().min(1).max(63),
6181
+ expression: import_zod9.z.string().min(1)
6155
6182
  }),
6156
- import_zod8.z.object({
6157
- type: import_zod8.z.literal("dropConstraint"),
6158
- table: import_zod8.z.string().min(1).max(63),
6159
- name: import_zod8.z.string().min(1).max(63),
6160
- cascade: import_zod8.z.boolean().optional(),
6161
- ifExists: import_zod8.z.boolean().optional()
6183
+ import_zod9.z.object({
6184
+ type: import_zod9.z.literal("dropConstraint"),
6185
+ table: import_zod9.z.string().min(1).max(63),
6186
+ name: import_zod9.z.string().min(1).max(63),
6187
+ cascade: import_zod9.z.boolean().optional(),
6188
+ ifExists: import_zod9.z.boolean().optional()
6162
6189
  }),
6163
6190
  // Enum types
6164
- import_zod8.z.object({
6165
- type: import_zod8.z.literal("createEnum"),
6166
- name: import_zod8.z.string().min(1).max(63),
6167
- values: import_zod8.z.array(import_zod8.z.string().min(1)).min(1)
6191
+ import_zod9.z.object({
6192
+ type: import_zod9.z.literal("createEnum"),
6193
+ name: import_zod9.z.string().min(1).max(63),
6194
+ values: import_zod9.z.array(import_zod9.z.string().min(1)).min(1)
6168
6195
  }),
6169
- import_zod8.z.object({
6170
- type: import_zod8.z.literal("alterEnumAddValue"),
6171
- name: import_zod8.z.string().min(1).max(63),
6172
- value: import_zod8.z.string().min(1),
6196
+ import_zod9.z.object({
6197
+ type: import_zod9.z.literal("alterEnumAddValue"),
6198
+ name: import_zod9.z.string().min(1).max(63),
6199
+ value: import_zod9.z.string().min(1),
6173
6200
  /** Position the new value before an existing one (mutually exclusive with `after`) */
6174
- before: import_zod8.z.string().optional(),
6201
+ before: import_zod9.z.string().optional(),
6175
6202
  /** Position the new value after an existing one (mutually exclusive with `before`) */
6176
- after: import_zod8.z.string().optional(),
6177
- ifNotExists: import_zod8.z.boolean().optional()
6203
+ after: import_zod9.z.string().optional(),
6204
+ ifNotExists: import_zod9.z.boolean().optional()
6178
6205
  }),
6179
- import_zod8.z.object({
6180
- type: import_zod8.z.literal("dropEnum"),
6181
- name: import_zod8.z.string().min(1).max(63),
6182
- cascade: import_zod8.z.boolean().optional(),
6183
- ifExists: import_zod8.z.boolean().optional()
6206
+ import_zod9.z.object({
6207
+ type: import_zod9.z.literal("dropEnum"),
6208
+ name: import_zod9.z.string().min(1).max(63),
6209
+ cascade: import_zod9.z.boolean().optional(),
6210
+ ifExists: import_zod9.z.boolean().optional()
6184
6211
  }),
6185
6212
  // Extensions
6186
- import_zod8.z.object({
6187
- type: import_zod8.z.literal("createExtension"),
6188
- name: import_zod8.z.string().min(1),
6189
- ifNotExists: import_zod8.z.boolean().optional()
6213
+ import_zod9.z.object({
6214
+ type: import_zod9.z.literal("createExtension"),
6215
+ name: import_zod9.z.string().min(1),
6216
+ ifNotExists: import_zod9.z.boolean().optional()
6190
6217
  }),
6191
6218
  // Data operations
6192
6219
  /**
@@ -6194,26 +6221,26 @@ var schemaOpSchema = import_zod8.z.discriminatedUnion("type", [
6194
6221
  * destructive — requires explicit confirm to replay on prod. The
6195
6222
  * `description` is what the agent/user sees at confirm time.
6196
6223
  */
6197
- import_zod8.z.object({
6198
- type: import_zod8.z.literal("backfill"),
6199
- description: import_zod8.z.string().min(1),
6200
- sql: import_zod8.z.string().min(1)
6224
+ import_zod9.z.object({
6225
+ type: import_zod9.z.literal("backfill"),
6226
+ description: import_zod9.z.string().min(1),
6227
+ sql: import_zod9.z.string().min(1)
6201
6228
  }),
6202
6229
  /**
6203
6230
  * Escape hatch for DDL the structured ops can't express. `destructive`
6204
6231
  * forces classification — use false only for genuinely additive-only SQL
6205
6232
  * (e.g. CREATE EXTENSION variants the structured op doesn't cover).
6206
6233
  */
6207
- import_zod8.z.object({
6208
- type: import_zod8.z.literal("rawSql"),
6209
- description: import_zod8.z.string().min(1),
6210
- sql: import_zod8.z.string().min(1),
6211
- destructive: import_zod8.z.boolean()
6234
+ import_zod9.z.object({
6235
+ type: import_zod9.z.literal("rawSql"),
6236
+ description: import_zod9.z.string().min(1),
6237
+ sql: import_zod9.z.string().min(1),
6238
+ destructive: import_zod9.z.boolean()
6212
6239
  })
6213
6240
  ]);
6214
6241
 
6215
6242
  // ../../packages/lib/src/server/module-rail/ops.ts
6216
- var import_zod9 = require("zod");
6243
+ var import_zod10 = require("zod");
6217
6244
 
6218
6245
  // ../../packages/lib/src/server/module-rail/reconcile.ts
6219
6246
  var SANDBOX_BATCH_SIZE = 200;
@@ -6326,39 +6353,24 @@ async function assertNoRootRoutesWhenMountsEmpty(context, moduleName) {
6326
6353
  );
6327
6354
  }
6328
6355
  }
6329
- async function assertNoEnhancementRoutes(context, moduleName) {
6330
- const enhancementsDir = `${MODULES_SANDBOX_DIR}/${moduleName}/enhancements`;
6331
- const enhancementEntries = await listImmediateEntries(context.sandbox, enhancementsDir, {
6332
- optional: true,
6333
- label: `enhancements for ${moduleName}`
6334
- });
6335
- for (const entry of enhancementEntries) {
6336
- if (entry.kind !== "dir") continue;
6337
- const sliceRoutes = `${enhancementsDir}/${entry.name}/routes`;
6338
- const sliceProbe = await context.sandbox.exec(
6339
- [
6340
- `p=${shellQuote(sliceRoutes)}`,
6341
- `if test -L "$p" || test -e "$p"; then exit 2; else exit 0; fi`
6342
- ].join("\n"),
6343
- { raiseOnError: false }
6344
- );
6345
- if (sliceProbe.exitCode === 2) {
6356
+ async function assertNoEnhancementRoutePaths(context, paths) {
6357
+ const kinds = await classifySandboxPathPresenceKindMany(context, paths, "enhancement-route-kind");
6358
+ for (const sliceRoutes of paths) {
6359
+ const kind = kinds.get(sliceRoutes);
6360
+ if (kind === "absent") continue;
6361
+ if (kind !== "unreadable" && kind !== void 0) {
6346
6362
  throw new Error(
6347
6363
  `[ModuleRail] composition artifacts: enhancement slice routes/ are forbidden at ${sliceRoutes}`
6348
6364
  );
6349
6365
  }
6350
- if (sliceProbe.exitCode !== 0) {
6351
- const detail = typeof sliceProbe.error === "string" && sliceProbe.error.trim() || sliceProbe.output.trim() || `exit ${sliceProbe.exitCode}`;
6352
- throw new Error(
6353
- `[ModuleRail] composition artifacts: cannot probe ${sliceRoutes}: ${redactSecrets(detail)}`
6354
- );
6355
- }
6366
+ throw new Error(
6367
+ `[ModuleRail] composition artifacts: cannot probe ${sliceRoutes}: entry-kind:${kind ?? "missing"}`
6368
+ );
6356
6369
  }
6357
6370
  }
6358
- async function discoverModuleRouteEntries(context, moduleName) {
6371
+ async function discoverRootRouteEntries(context, moduleName) {
6359
6372
  const modulePath = `${MODULES_SANDBOX_DIR}/${moduleName}`;
6360
6373
  const routesDir = `${modulePath}/routes`;
6361
- await assertNoEnhancementRoutes(context, moduleName);
6362
6374
  const quotedRoutes = shellQuote(routesDir);
6363
6375
  const listResult = await context.sandbox.exec(
6364
6376
  [
@@ -6812,7 +6824,8 @@ async function classifySandboxPathPresenceKindMany(context, paths, probeToken) {
6812
6824
  `# Leaf is missing. A missing intermediate parent means the path is simply`,
6813
6825
  `# absent (new nested writes). Only an existing-but-inaccessible parent`,
6814
6826
  `# is unreadable \u2014 never conflate ENOENT parents with EACCES.`,
6815
- `parent=$(dirname -- "$p")`,
6827
+ // Probe paths are nested repo-relative paths; do not spawn dirname per missing file.
6828
+ `parent=\${p%/*}`,
6816
6829
  `if test ! -e "$parent" && test ! -L "$parent"; then`,
6817
6830
  ` printf 'entry-kind:absent\\t%s\\n' "$p"`,
6818
6831
  `elif ls -ld -- "$parent" >/dev/null 2>&1; then`,
@@ -7357,14 +7370,21 @@ async function reconcileCompositionArtifacts(context, options = {}) {
7357
7370
  manifestsByName
7358
7371
  );
7359
7372
  const routeEntriesByOwner = {};
7373
+ await assertNoEnhancementRoutePaths(
7374
+ context,
7375
+ moduleRuntimeFacts.flatMap(
7376
+ ({ moduleName, onDiskEnhancementDirs }) => onDiskEnhancementDirs.map(
7377
+ (peer) => `${MODULES_SANDBOX_DIR}/${moduleName}/enhancements/${peer}/routes`
7378
+ )
7379
+ )
7380
+ );
7360
7381
  for (const moduleName of composedNames) {
7361
7382
  const manifest = manifestsByName[moduleName];
7362
- await assertNoEnhancementRoutes(context, moduleName);
7363
7383
  if (manifest.mounts.length === 0) {
7364
7384
  await assertNoRootRoutesWhenMountsEmpty(context, moduleName);
7365
7385
  routeEntriesByOwner[moduleName] = [];
7366
7386
  } else {
7367
- routeEntriesByOwner[moduleName] = await discoverModuleRouteEntries(context, moduleName);
7387
+ routeEntriesByOwner[moduleName] = await discoverRootRouteEntries(context, moduleName);
7368
7388
  }
7369
7389
  }
7370
7390
  const existingGeneratedPaths = await listExistingGeneratedStubPaths(context);