@stardeck-customer-apps/compose 0.2.0 → 0.3.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.mjs CHANGED
@@ -2029,6 +2029,29 @@ var initialModuleCompositionSchema = z6.object({
2029
2029
  });
2030
2030
  var MODULE_SETUP_ATTEMPT_STALE_MS = 10 * 60 * 1e3;
2031
2031
 
2032
+ // ../../packages/lib/src/shared/compose-inputs.ts
2033
+ import { z as z7 } from "zod";
2034
+ var COMPOSE_INPUTS_PATH = "apps/web/stardeck.compose.json";
2035
+ var composeInputsSchema = z7.strictObject({
2036
+ connectedStores: z7.array(
2037
+ z7.strictObject({
2038
+ storeId: z7.string().min(1),
2039
+ slug: z7.string().min(1),
2040
+ // A row with an empty binding key must not fail a deploy: the rail
2041
+ // treats falsy as "no binding key", so normalise rather than reject.
2042
+ bindingKey: z7.string().nullish().transform((value) => value || null),
2043
+ accessLevel: z7.enum(["read", "write", "admin"])
2044
+ })
2045
+ ).default([]),
2046
+ installs: z7.record(
2047
+ z7.string(),
2048
+ z7.strictObject({
2049
+ installedVersion: z7.string().min(1),
2050
+ datastoreBindings: z7.record(z7.string(), z7.string()).nullish()
2051
+ })
2052
+ ).default({})
2053
+ });
2054
+
2032
2055
  // ../../packages/lib/src/shared/module-enablement.ts
2033
2056
  function isModuleEnabledByList(raw, name, kindOf) {
2034
2057
  if (!raw) return true;
@@ -3530,6 +3553,27 @@ function dirnamePosix(filePath) {
3530
3553
  return idx <= 0 ? "." : filePath.slice(0, idx);
3531
3554
  }
3532
3555
 
3556
+ // ../../packages/lib/src/server/module-rail/compose-inputs.ts
3557
+ async function buildComposeInputs(input) {
3558
+ const { db, projectId, deps } = input;
3559
+ const connectedStores = await deps.listDatabaseStoresForProject(db, projectId);
3560
+ const installRows = await Promise.all(
3561
+ input.moduleNames.map(async (moduleName) => ({
3562
+ moduleName,
3563
+ install: await deps.getModuleInstall(db, projectId, moduleName)
3564
+ }))
3565
+ );
3566
+ const installs = {};
3567
+ for (const { moduleName, install } of installRows) {
3568
+ if (!install) continue;
3569
+ installs[moduleName] = {
3570
+ installedVersion: install.installedVersion,
3571
+ datastoreBindings: install.datastoreBindings ?? null
3572
+ };
3573
+ }
3574
+ return composeInputsSchema.parse({ connectedStores, installs });
3575
+ }
3576
+
3533
3577
  // ../../packages/lib/src/shared/data-store-manifest.ts
3534
3578
  function dataStoreSlug(name) {
3535
3579
  const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
@@ -3726,162 +3770,162 @@ function rejectPseudoModuleEntries(entries, parentDir, label) {
3726
3770
  }
3727
3771
 
3728
3772
  // ../../packages/lib/src/shared/schema-ops.ts
3729
- import { z as z7 } from "zod";
3730
- var columnSpecSchema = z7.object({
3731
- name: z7.string().min(1).max(63),
3732
- pgType: z7.string().min(1),
3733
- nullable: z7.boolean(),
3773
+ import { z as z8 } from "zod";
3774
+ var columnSpecSchema = z8.object({
3775
+ name: z8.string().min(1).max(63),
3776
+ pgType: z8.string().min(1),
3777
+ nullable: z8.boolean(),
3734
3778
  /**
3735
3779
  * A SQL expression used as the column default, as a raw string (e.g. `'t'`,
3736
3780
  * `0`, `now()`, `gen_random_uuid()`). `null` or omitted means no default.
3737
3781
  * NOT a JS literal — must already be a valid SQL expression.
3738
3782
  */
3739
- default: z7.string().nullable().optional(),
3740
- fieldType: z7.string().optional(),
3741
- fieldConfig: z7.record(z7.string(), z7.unknown()).optional()
3783
+ default: z8.string().nullable().optional(),
3784
+ fieldType: z8.string().optional(),
3785
+ fieldConfig: z8.record(z8.string(), z8.unknown()).optional()
3742
3786
  });
3743
- var referentialActionSchema = z7.enum([
3787
+ var referentialActionSchema = z8.enum([
3744
3788
  "cascade",
3745
3789
  "set null",
3746
3790
  "set default",
3747
3791
  "restrict",
3748
3792
  "no action"
3749
3793
  ]);
3750
- var schemaOpSchema = z7.discriminatedUnion("type", [
3794
+ var schemaOpSchema = z8.discriminatedUnion("type", [
3751
3795
  // Tables
3752
- z7.object({
3753
- type: z7.literal("createTable"),
3754
- table: z7.string().min(1).max(63),
3755
- columns: z7.array(columnSpecSchema).min(1),
3756
- primaryKey: z7.array(z7.string()).optional(),
3757
- ifNotExists: z7.boolean().optional()
3796
+ z8.object({
3797
+ type: z8.literal("createTable"),
3798
+ table: z8.string().min(1).max(63),
3799
+ columns: z8.array(columnSpecSchema).min(1),
3800
+ primaryKey: z8.array(z8.string()).optional(),
3801
+ ifNotExists: z8.boolean().optional()
3758
3802
  }),
3759
- z7.object({
3760
- type: z7.literal("dropTable"),
3761
- table: z7.string().min(1).max(63),
3762
- cascade: z7.boolean().optional(),
3763
- ifExists: z7.boolean().optional()
3803
+ z8.object({
3804
+ type: z8.literal("dropTable"),
3805
+ table: z8.string().min(1).max(63),
3806
+ cascade: z8.boolean().optional(),
3807
+ ifExists: z8.boolean().optional()
3764
3808
  }),
3765
- z7.object({
3766
- type: z7.literal("renameTable"),
3767
- from: z7.string().min(1).max(63),
3768
- to: z7.string().min(1).max(63)
3809
+ z8.object({
3810
+ type: z8.literal("renameTable"),
3811
+ from: z8.string().min(1).max(63),
3812
+ to: z8.string().min(1).max(63)
3769
3813
  }),
3770
3814
  // Columns
3771
- z7.object({
3772
- type: z7.literal("addColumn"),
3773
- table: z7.string().min(1).max(63),
3815
+ z8.object({
3816
+ type: z8.literal("addColumn"),
3817
+ table: z8.string().min(1).max(63),
3774
3818
  column: columnSpecSchema,
3775
- ifNotExists: z7.boolean().optional()
3819
+ ifNotExists: z8.boolean().optional()
3776
3820
  }),
3777
- z7.object({
3778
- type: z7.literal("dropColumn"),
3779
- table: z7.string().min(1).max(63),
3780
- column: z7.string().min(1).max(63),
3781
- cascade: z7.boolean().optional(),
3782
- ifExists: z7.boolean().optional()
3821
+ z8.object({
3822
+ type: z8.literal("dropColumn"),
3823
+ table: z8.string().min(1).max(63),
3824
+ column: z8.string().min(1).max(63),
3825
+ cascade: z8.boolean().optional(),
3826
+ ifExists: z8.boolean().optional()
3783
3827
  }),
3784
- z7.object({
3785
- type: z7.literal("renameColumn"),
3786
- table: z7.string().min(1).max(63),
3787
- from: z7.string().min(1).max(63),
3788
- to: z7.string().min(1).max(63)
3828
+ z8.object({
3829
+ type: z8.literal("renameColumn"),
3830
+ table: z8.string().min(1).max(63),
3831
+ from: z8.string().min(1).max(63),
3832
+ to: z8.string().min(1).max(63)
3789
3833
  }),
3790
- z7.object({
3791
- type: z7.literal("alterColumnType"),
3792
- table: z7.string().min(1).max(63),
3793
- column: z7.string().min(1).max(63),
3794
- newType: z7.string().min(1),
3834
+ z8.object({
3835
+ type: z8.literal("alterColumnType"),
3836
+ table: z8.string().min(1).max(63),
3837
+ column: z8.string().min(1).max(63),
3838
+ newType: z8.string().min(1),
3795
3839
  /** Optional USING expression for potentially-lossy casts */
3796
- using: z7.string().optional()
3840
+ using: z8.string().optional()
3797
3841
  }),
3798
- z7.object({
3799
- type: z7.literal("alterColumnNullable"),
3800
- table: z7.string().min(1).max(63),
3801
- column: z7.string().min(1).max(63),
3802
- nullable: z7.boolean()
3842
+ z8.object({
3843
+ type: z8.literal("alterColumnNullable"),
3844
+ table: z8.string().min(1).max(63),
3845
+ column: z8.string().min(1).max(63),
3846
+ nullable: z8.boolean()
3803
3847
  }),
3804
- z7.object({
3805
- type: z7.literal("alterColumnDefault"),
3806
- table: z7.string().min(1).max(63),
3807
- column: z7.string().min(1).max(63),
3848
+ z8.object({
3849
+ type: z8.literal("alterColumnDefault"),
3850
+ table: z8.string().min(1).max(63),
3851
+ column: z8.string().min(1).max(63),
3808
3852
  /** null means drop the default; otherwise a SQL expression string. */
3809
- default: z7.string().nullable()
3853
+ default: z8.string().nullable()
3810
3854
  }),
3811
3855
  // Indexes
3812
- z7.object({
3813
- type: z7.literal("addIndex"),
3814
- table: z7.string().min(1).max(63),
3815
- name: z7.string().min(1).max(63),
3816
- columns: z7.array(z7.string().min(1)).min(1),
3817
- unique: z7.boolean().optional(),
3856
+ z8.object({
3857
+ type: z8.literal("addIndex"),
3858
+ table: z8.string().min(1).max(63),
3859
+ name: z8.string().min(1).max(63),
3860
+ columns: z8.array(z8.string().min(1)).min(1),
3861
+ unique: z8.boolean().optional(),
3818
3862
  /** Partial-index WHERE clause, as a raw SQL expression */
3819
- where: z7.string().optional(),
3820
- ifNotExists: z7.boolean().optional()
3863
+ where: z8.string().optional(),
3864
+ ifNotExists: z8.boolean().optional()
3821
3865
  }),
3822
- z7.object({
3823
- type: z7.literal("dropIndex"),
3824
- name: z7.string().min(1).max(63),
3825
- cascade: z7.boolean().optional(),
3826
- ifExists: z7.boolean().optional()
3866
+ z8.object({
3867
+ type: z8.literal("dropIndex"),
3868
+ name: z8.string().min(1).max(63),
3869
+ cascade: z8.boolean().optional(),
3870
+ ifExists: z8.boolean().optional()
3827
3871
  }),
3828
3872
  // Constraints
3829
- z7.object({
3830
- type: z7.literal("addForeignKey"),
3831
- table: z7.string().min(1).max(63),
3832
- name: z7.string().min(1).max(63),
3833
- columns: z7.array(z7.string().min(1)).min(1),
3834
- refTable: z7.string().min(1).max(63),
3835
- refColumns: z7.array(z7.string().min(1)).min(1),
3873
+ z8.object({
3874
+ type: z8.literal("addForeignKey"),
3875
+ table: z8.string().min(1).max(63),
3876
+ name: z8.string().min(1).max(63),
3877
+ columns: z8.array(z8.string().min(1)).min(1),
3878
+ refTable: z8.string().min(1).max(63),
3879
+ refColumns: z8.array(z8.string().min(1)).min(1),
3836
3880
  onDelete: referentialActionSchema.optional(),
3837
3881
  onUpdate: referentialActionSchema.optional()
3838
3882
  }),
3839
- z7.object({
3840
- type: z7.literal("addUniqueConstraint"),
3841
- table: z7.string().min(1).max(63),
3842
- name: z7.string().min(1).max(63),
3843
- columns: z7.array(z7.string().min(1)).min(1)
3883
+ z8.object({
3884
+ type: z8.literal("addUniqueConstraint"),
3885
+ table: z8.string().min(1).max(63),
3886
+ name: z8.string().min(1).max(63),
3887
+ columns: z8.array(z8.string().min(1)).min(1)
3844
3888
  }),
3845
- z7.object({
3846
- type: z7.literal("addCheckConstraint"),
3847
- table: z7.string().min(1).max(63),
3848
- name: z7.string().min(1).max(63),
3849
- expression: z7.string().min(1)
3889
+ z8.object({
3890
+ type: z8.literal("addCheckConstraint"),
3891
+ table: z8.string().min(1).max(63),
3892
+ name: z8.string().min(1).max(63),
3893
+ expression: z8.string().min(1)
3850
3894
  }),
3851
- z7.object({
3852
- type: z7.literal("dropConstraint"),
3853
- table: z7.string().min(1).max(63),
3854
- name: z7.string().min(1).max(63),
3855
- cascade: z7.boolean().optional(),
3856
- ifExists: z7.boolean().optional()
3895
+ z8.object({
3896
+ type: z8.literal("dropConstraint"),
3897
+ table: z8.string().min(1).max(63),
3898
+ name: z8.string().min(1).max(63),
3899
+ cascade: z8.boolean().optional(),
3900
+ ifExists: z8.boolean().optional()
3857
3901
  }),
3858
3902
  // Enum types
3859
- z7.object({
3860
- type: z7.literal("createEnum"),
3861
- name: z7.string().min(1).max(63),
3862
- values: z7.array(z7.string().min(1)).min(1)
3903
+ z8.object({
3904
+ type: z8.literal("createEnum"),
3905
+ name: z8.string().min(1).max(63),
3906
+ values: z8.array(z8.string().min(1)).min(1)
3863
3907
  }),
3864
- z7.object({
3865
- type: z7.literal("alterEnumAddValue"),
3866
- name: z7.string().min(1).max(63),
3867
- value: z7.string().min(1),
3908
+ z8.object({
3909
+ type: z8.literal("alterEnumAddValue"),
3910
+ name: z8.string().min(1).max(63),
3911
+ value: z8.string().min(1),
3868
3912
  /** Position the new value before an existing one (mutually exclusive with `after`) */
3869
- before: z7.string().optional(),
3913
+ before: z8.string().optional(),
3870
3914
  /** Position the new value after an existing one (mutually exclusive with `before`) */
3871
- after: z7.string().optional(),
3872
- ifNotExists: z7.boolean().optional()
3915
+ after: z8.string().optional(),
3916
+ ifNotExists: z8.boolean().optional()
3873
3917
  }),
3874
- z7.object({
3875
- type: z7.literal("dropEnum"),
3876
- name: z7.string().min(1).max(63),
3877
- cascade: z7.boolean().optional(),
3878
- ifExists: z7.boolean().optional()
3918
+ z8.object({
3919
+ type: z8.literal("dropEnum"),
3920
+ name: z8.string().min(1).max(63),
3921
+ cascade: z8.boolean().optional(),
3922
+ ifExists: z8.boolean().optional()
3879
3923
  }),
3880
3924
  // Extensions
3881
- z7.object({
3882
- type: z7.literal("createExtension"),
3883
- name: z7.string().min(1),
3884
- ifNotExists: z7.boolean().optional()
3925
+ z8.object({
3926
+ type: z8.literal("createExtension"),
3927
+ name: z8.string().min(1),
3928
+ ifNotExists: z8.boolean().optional()
3885
3929
  }),
3886
3930
  // Data operations
3887
3931
  /**
@@ -3889,26 +3933,26 @@ var schemaOpSchema = z7.discriminatedUnion("type", [
3889
3933
  * destructive — requires explicit confirm to replay on prod. The
3890
3934
  * `description` is what the agent/user sees at confirm time.
3891
3935
  */
3892
- z7.object({
3893
- type: z7.literal("backfill"),
3894
- description: z7.string().min(1),
3895
- sql: z7.string().min(1)
3936
+ z8.object({
3937
+ type: z8.literal("backfill"),
3938
+ description: z8.string().min(1),
3939
+ sql: z8.string().min(1)
3896
3940
  }),
3897
3941
  /**
3898
3942
  * Escape hatch for DDL the structured ops can't express. `destructive`
3899
3943
  * forces classification — use false only for genuinely additive-only SQL
3900
3944
  * (e.g. CREATE EXTENSION variants the structured op doesn't cover).
3901
3945
  */
3902
- z7.object({
3903
- type: z7.literal("rawSql"),
3904
- description: z7.string().min(1),
3905
- sql: z7.string().min(1),
3906
- destructive: z7.boolean()
3946
+ z8.object({
3947
+ type: z8.literal("rawSql"),
3948
+ description: z8.string().min(1),
3949
+ sql: z8.string().min(1),
3950
+ destructive: z8.boolean()
3907
3951
  })
3908
3952
  ]);
3909
3953
 
3910
3954
  // ../../packages/lib/src/server/module-rail/ops.ts
3911
- import { z as z8 } from "zod";
3955
+ import { z as z9 } from "zod";
3912
3956
 
3913
3957
  // ../../packages/lib/src/server/module-rail/reconcile.ts
3914
3958
  var SANDBOX_BATCH_SIZE = 200;
@@ -3949,8 +3993,8 @@ function countedCompositionContext(context) {
3949
3993
  }
3950
3994
  };
3951
3995
  }
3952
- async function listPresentModuleNames(context) {
3953
- const entries = await listImmediateEntries(context.sandbox, MODULES_SANDBOX_DIR, {
3996
+ async function listPresentModuleNames(sandbox) {
3997
+ const entries = await listImmediateEntries(sandbox, MODULES_SANDBOX_DIR, {
3954
3998
  optional: true,
3955
3999
  label: "modules"
3956
4000
  });
@@ -4154,24 +4198,24 @@ async function discoverModuleRouteEntries(context, moduleName) {
4154
4198
  }
4155
4199
  return pages.sort((a, b) => a.nextRelativePath.localeCompare(b.nextRelativePath));
4156
4200
  }
4157
- async function writeSandboxFileAtomic(context, path3, content) {
4201
+ async function writeSandboxFileAtomic(target, path3, content) {
4158
4202
  const dir = dirnamePosix(path3);
4159
- const tmp = `${path3}.tmp.${context.runId}`;
4203
+ const tmp = `${path3}.tmp.${target.runId}`;
4160
4204
  const b64 = Buffer.from(content, "utf8").toString("base64");
4161
4205
  const cmd = [
4162
4206
  `mkdir -p ${shellQuote(dir)}`,
4163
4207
  `printf '%s' ${shellQuote(b64)} | base64 -d > ${shellQuote(tmp)}`,
4164
4208
  `mv -f ${shellQuote(tmp)} ${shellQuote(path3)}`
4165
4209
  ].join(" && ");
4166
- const result = await context.sandbox.exec(cmd, { raiseOnError: false });
4210
+ const result = await target.sandbox.exec(cmd, { raiseOnError: false });
4167
4211
  if (result.exitCode !== 0) {
4168
- const cleanup = await context.sandbox.exec(`rm -f ${shellQuote(tmp)}`, {
4212
+ const cleanup = await target.sandbox.exec(`rm -f ${shellQuote(tmp)}`, {
4169
4213
  raiseOnError: false
4170
4214
  });
4171
4215
  if (cleanup.exitCode !== 0) {
4172
4216
  const cleanupDetail = typeof cleanup.error === "string" && cleanup.error.trim() || cleanup.output.trim() || `exit ${cleanup.exitCode}`;
4173
4217
  console.log(
4174
- `[ModuleRail] runId=${context.runId} composition artifacts failed to clean temp ${redactSecrets(tmp)}: ${redactSecrets(cleanupDetail)}`
4218
+ `[ModuleRail] runId=${target.runId} composition artifacts failed to clean temp ${redactSecrets(tmp)}: ${redactSecrets(cleanupDetail)}`
4175
4219
  );
4176
4220
  }
4177
4221
  const detail = typeof result.error === "string" && result.error.trim() || result.output.trim() || `exit ${result.exitCode}`;
@@ -4229,6 +4273,40 @@ async function deleteSandboxFile(context, path3) {
4229
4273
  );
4230
4274
  }
4231
4275
  }
4276
+ async function writeComposeInputs(target) {
4277
+ const ignored = await target.sandbox.exec(
4278
+ `git check-ignore -q ${shellQuote(COMPOSE_INPUTS_PATH)}`,
4279
+ { raiseOnError: false }
4280
+ );
4281
+ if (ignored.exitCode === 1) {
4282
+ console.log(
4283
+ `[ComposeInputs] project=${target.projectId} skipped: ${COMPOSE_INPUTS_PATH} is not ignored in this checkout`
4284
+ );
4285
+ return false;
4286
+ }
4287
+ if (ignored.exitCode !== 0) {
4288
+ const detail = typeof ignored.error === "string" && ignored.error.trim() || ignored.output.trim() || "(no output)";
4289
+ throw new Error(
4290
+ `[ComposeInputs] git check-ignore failed in this checkout (exit ${ignored.exitCode}): ${redactSecrets(detail)}`
4291
+ );
4292
+ }
4293
+ const moduleNames = await listPresentModuleNames(target.sandbox);
4294
+ const inputs = await buildComposeInputs({
4295
+ db: target.db,
4296
+ projectId: target.projectId,
4297
+ deps: target.deps,
4298
+ moduleNames
4299
+ });
4300
+ const content = `${JSON.stringify(inputs, null, 2)}
4301
+ `;
4302
+ const existing = await target.sandbox.fileExists(COMPOSE_INPUTS_PATH) ? await target.sandbox.readFile(COMPOSE_INPUTS_PATH) : null;
4303
+ const written = existing === null || existing.trimEnd() !== content.trimEnd();
4304
+ if (written) await writeSandboxFileAtomic(target, COMPOSE_INPUTS_PATH, content);
4305
+ console.log(
4306
+ `[ComposeInputs] project=${target.projectId} stores=${inputs.connectedStores.length} installs=${Object.keys(inputs.installs).length} written=${written}`
4307
+ );
4308
+ return written;
4309
+ }
4232
4310
  async function applyCompositionArtifactMutations(context, plan, existingFiles) {
4233
4311
  const appliedWrites = [];
4234
4312
  const appliedDeletes = [];
@@ -4864,7 +4942,7 @@ async function reconcileCompositionArtifacts(context, options = {}) {
4864
4942
  context = counted.context;
4865
4943
  const deps = context.deps;
4866
4944
  if (!deps) throw new Error("Module rail dependencies are required for composition artifacts");
4867
- const presentRaw = await listPresentModuleNames(context);
4945
+ const presentRaw = await listPresentModuleNames(context.sandbox);
4868
4946
  const presentNames = presentRaw.filter((name) => isValidModuleName(name)).sort((a, b) => a.localeCompare(b));
4869
4947
  const moduleFacts = [];
4870
4948
  const manifestsByName = {};
@@ -5084,6 +5162,15 @@ async function reconcileCompositionArtifacts(context, options = {}) {
5084
5162
  console.log(
5085
5163
  `[ModuleRail] runId=${context.runId} composition artifacts writes=${planned.plan.writes.length} deletes=${planned.plan.deletes.length} modules=${registry.modules.length} excluded=${excludedModules.length} changed=${changed} dryRun=${options.dryRun === true} sandboxExecs=${counted.counts.sandboxExecs} sandboxReads=${counted.counts.sandboxReads}`
5086
5164
  );
5165
+ if (!options.dryRun && !options.skipComposeInputs) {
5166
+ await writeComposeInputs({
5167
+ db: context.db,
5168
+ projectId: context.projectId,
5169
+ runId: context.runId,
5170
+ sandbox: context.sandbox,
5171
+ deps
5172
+ });
5173
+ }
5087
5174
  if (changed && !options.dryRun) {
5088
5175
  await applyCompositionArtifactMutations(context, planned.plan, existingFiles);
5089
5176
  }
@@ -5101,26 +5188,7 @@ var HOME_I18N_SUBSTRATE_DIR = `${APP_PACKAGE_DIR}/src/lib/i18n/substrate`;
5101
5188
  var HOME_I18N_MESSAGES_DIR = `${APP_PACKAGE_DIR}/src/lib/i18n/messages`;
5102
5189
 
5103
5190
  // src/index.ts
5104
- import { z as z9 } from "zod";
5105
5191
  var MODULES_DIR2 = MODULES_SANDBOX_DIR;
5106
- var COMPOSE_INPUTS_PATH = "apps/web/stardeck.compose.json";
5107
- var composeInputsSchema = z9.strictObject({
5108
- connectedStores: z9.array(
5109
- z9.strictObject({
5110
- storeId: z9.string().min(1),
5111
- slug: z9.string().min(1),
5112
- bindingKey: z9.string().min(1).nullish(),
5113
- accessLevel: z9.enum(["read", "write", "admin"])
5114
- })
5115
- ).default([]),
5116
- installs: z9.record(
5117
- z9.string(),
5118
- z9.strictObject({
5119
- installedVersion: z9.string().min(1),
5120
- datastoreBindings: z9.record(z9.string(), z9.string()).nullish()
5121
- })
5122
- ).default({})
5123
- });
5124
5192
  function readComposeInputs(cwd) {
5125
5193
  const file = path2.join(cwd, COMPOSE_INPUTS_PATH);
5126
5194
  if (!fs2.existsSync(file)) return { connectedStores: [], installs: {} };
@@ -5154,6 +5222,7 @@ function assertSupportedTypescript(versionMajorMinor) {
5154
5222
  }
5155
5223
  }
5156
5224
  var APP_DIR_PREFIX2 = "apps/web/src/app/";
5225
+ var APP_PACKAGE_JSON = "apps/web/package.json";
5157
5226
  var STUB_GITIGNORE_PATH = "apps/web/src/app/.gitignore";
5158
5227
  var STUB_GITIGNORE_HEADER = "# Generated by stardeck-compose \u2014 Module-rail stubs are build outputs; do not edit or commit them.";
5159
5228
  function escapeGitignore(pattern) {
@@ -5185,10 +5254,10 @@ function assertStubGitignoreOwned(cwd) {
5185
5254
  }
5186
5255
  }
5187
5256
  function assertAppRoot(cwd) {
5188
- const modulesPath = path2.join(cwd, MODULES_DIR2);
5189
- if (!fs2.existsSync(modulesPath)) {
5257
+ const appPath = path2.join(cwd, APP_PACKAGE_JSON);
5258
+ if (!fs2.existsSync(appPath)) {
5190
5259
  throw new Error(
5191
- `[compose] ${modulesPath} not found \u2014 run this from the repo root of a Stardeck app`
5260
+ `[compose] ${appPath} not found \u2014 run this from the repo root of a Stardeck app`
5192
5261
  );
5193
5262
  }
5194
5263
  }
@@ -5292,7 +5361,10 @@ async function compose(options) {
5292
5361
  assertNoAppLayerImporters(options.cwd, preview.excludedModules);
5293
5362
  }
5294
5363
  const result = await reconcileCompositionArtifacts(context, {
5295
- enabledModulesRaw: options.enabled
5364
+ enabledModulesRaw: options.enabled,
5365
+ // compose is the inputs file's reader: the deps above echo it back, so
5366
+ // letting the rail rewrite it would round-trip a fork's own input.
5367
+ skipComposeInputs: true
5296
5368
  });
5297
5369
  const gitignoreEntries = options.enabled ? null : writeStubGitignore(options.cwd, result.artifactPaths);
5298
5370
  let pruned = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stardeck-customer-apps/compose",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Regenerates a Stardeck app's Module-rail artifacts — the five 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",