create-bw-app 0.27.3 → 0.27.4

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-bw-app",
3
3
  "private": false,
4
- "version": "0.27.3",
4
+ "version": "0.27.4",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "create-bw-app": "bin/create-bw-app.mjs",
package/src/add.mjs CHANGED
@@ -6,7 +6,7 @@ import { SELECTABLE_MODULES } from "./constants.mjs";
6
6
  import { TEMPLATE_ROOT, createDbInstallPlan, createManagedPlatformFiles, getDbModuleRegistry, getVersionMap, pathExists, readJsonIfPresent } from "./generator.mjs";
7
7
  import { collectScaffoldFiles, findWorkspaceRoot, loadModuleCatalog, MODULE_PACKAGES, readAppManifest, resolveModuleClosure, satisfiesVersion, writeAppManifest } from "./app-manifest.mjs";
8
8
  import { assertNoUntrackedScaffoldWrites, scaffoldDrift } from "./scaffold.mjs";
9
- import { applyMigrationWrites, planMigrationAppends } from "./migrations.mjs";
9
+ import { assertMigrationMutationTargets, applyMigrationWrites, planMigrationAppends } from "./migrations.mjs";
10
10
 
11
11
  const HELP = `Usage: bw add <moduleKey> [options]\n\nOptions:\n --target-dir <path> App directory (defaults to cwd)\n --workspace-root <path> BrightWeb workspace root\n --dry-run Print the install plan without writing\n --help Show this help`;
12
12
 
@@ -109,7 +109,8 @@ export async function addBrightwebModule(moduleKey, argvOptions = {}, runtimeOpt
109
109
  }
110
110
  }
111
111
 
112
- await assertMutationTargets(targetDir, ["package.json", ".brightweb/app-manifest.json", ...Object.keys(managedWrites), ...overlayFiles, ...migrationPlan.writes.map((write) => path.relative(targetDir, write.targetPath))]);
112
+ await assertMutationTargets(targetDir, ["package.json", ".brightweb/app-manifest.json", ...Object.keys(managedWrites), ...overlayFiles]);
113
+ await assertMigrationMutationTargets(targetDir, migrationPlan.writes);
113
114
 
114
115
  const summary = [
115
116
  "bw add",
package/src/constants.mjs CHANGED
@@ -187,14 +187,14 @@ export const PLATFORM_STARTER_FILES = [
187
187
  ];
188
188
 
189
189
  export const APP_DEPENDENCY_DEFAULTS = {
190
- "@brightweblabs/app-shell": "^0.16.3",
190
+ "@brightweblabs/app-shell": "^0.16.4",
191
191
  "@brightweblabs/core-auth": "^0.12.2",
192
192
  "@brightweblabs/infra": "^0.7.0",
193
- "@brightweblabs/module-admin": "^0.9.7",
194
- "@brightweblabs/module-crm": "^0.18.4",
195
- "@brightweblabs/module-marketing": "^0.5.2",
196
- "@brightweblabs/module-orgs": "^0.7.3",
197
- "@brightweblabs/module-projects": "^0.19.3",
193
+ "@brightweblabs/module-admin": "^0.9.8",
194
+ "@brightweblabs/module-crm": "^0.18.5",
195
+ "@brightweblabs/module-marketing": "^0.5.3",
196
+ "@brightweblabs/module-orgs": "^0.7.4",
197
+ "@brightweblabs/module-projects": "^0.19.4",
198
198
  "@brightweblabs/theme": "^0.8.4",
199
199
  "@brightweblabs/ui": "^1.5.6",
200
200
  "geist": "1.7.2",
@@ -1,4 +1,5 @@
1
1
  import semver from "semver";
2
+ import { assertMutationTargets } from "./mutation-paths.mjs";
2
3
  import fs from "node:fs/promises";
3
4
  import path from "node:path";
4
5
  import { createHash } from "node:crypto";
@@ -16,6 +17,33 @@ export async function findAppMigrationsDirectory(targetDir) {
16
17
  }
17
18
  }
18
19
 
20
+ // Database migrations may belong to the containing consumer workspace, while
21
+ // app files remain bounded to the app itself. Never realpath the migration
22
+ // directory: that would hide links below the legitimate workspace boundary.
23
+ export async function assertMigrationMutationTargets(targetDir, writes) {
24
+ if (writes.length === 0) return;
25
+ const appRoot = await fs.realpath(path.resolve(targetDir));
26
+ let boundary = appRoot;
27
+ let current = appRoot;
28
+ while (true) {
29
+ if (await pathExists(path.join(current, "pnpm-workspace.yaml"))
30
+ || await pathExists(path.join(current, ".git"))) {
31
+ boundary = current;
32
+ break;
33
+ }
34
+ const parent = path.dirname(current);
35
+ if (parent === current) break;
36
+ current = parent;
37
+ }
38
+ const migrationsDir = await findAppMigrationsDirectory(appRoot);
39
+ for (const write of writes) {
40
+ if (path.dirname(write.targetPath) !== migrationsDir) {
41
+ throw new Error("Migration write must target the app's discovered migrations directory.");
42
+ }
43
+ }
44
+ await assertMutationTargets(boundary, writes.map((write) => path.relative(boundary, write.targetPath)));
45
+ }
46
+
19
47
  export async function getModuleMigrations(moduleKey, catalogEntry = {}) {
20
48
  const candidates = [];
21
49
  const configuredPath = catalogEntry.manifest?.database?.migrations;
package/src/upgrade.mjs CHANGED
@@ -4,7 +4,7 @@ import path from "node:path";
4
4
  import { stdout as output } from "node:process";
5
5
  import { hashFile, findWorkspaceRoot, loadModuleCatalog, readAppManifest, writeAppManifest, cleanVersion } from "./app-manifest.mjs";
6
6
  import { pathExists, runInstall } from "./generator.mjs";
7
- import { applyMigrationWrites, getModuleMigrations, planMigrationAppends } from "./migrations.mjs";
7
+ import { assertMigrationMutationTargets, applyMigrationWrites, getModuleMigrations, planMigrationAppends } from "./migrations.mjs";
8
8
  import { buildBrightwebAppUpdatePlan } from "./update.mjs";
9
9
  import { resolveSafeRelativePath } from "./safe-path.mjs";
10
10
  import { scaffoldDrift } from "./scaffold.mjs";
@@ -102,7 +102,8 @@ export async function upgradeBrightwebApp(moduleKey, argvOptions = {}, runtimeOp
102
102
  migrationCursor: appManifest.migrationCursor,
103
103
  migrationUpperBounds,
104
104
  });
105
- await assertMutationTargets(targetDir, [".brightweb/app-manifest.json", ...plan.fileWrites.map((write) => write.relativePath), ...plan.fileDeletes.map((entry) => entry.relativePath), ...migrationPlan.writes.map((write) => path.relative(targetDir, write.targetPath))]);
105
+ await assertMutationTargets(targetDir, [".brightweb/app-manifest.json", ...plan.fileWrites.map((write) => write.relativePath), ...plan.fileDeletes.map((entry) => entry.relativePath)]);
106
+ await assertMigrationMutationTargets(targetDir, migrationPlan.writes);
106
107
  output.write(`bw upgrade\nPackages to update: ${plan.packageUpdates.length}\nManaged files to write: ${plan.fileWrites.length}\nObsolete managed files to remove: ${plan.fileDeletes.length}\nMigrations to append: ${migrationPlan.appends.length}\n`);
107
108
  if (throughMigration) output.write(`Migration cutoff: ${moduleKey} through ${throughMigration}\n`);
108
109
  for (const boundary of safetyBoundaries) {