@rebasepro/cli 0.20.0 → 0.20.1-canary.g4d882ca

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/bundle.d.ts CHANGED
@@ -398,6 +398,8 @@ export declare function foldStaticIntoBundle(options: {
398
398
  path: string;
399
399
  /** Serve `index.html` for unmatched paths under `path`. */
400
400
  spa: boolean;
401
+ /** Where this app mounts the Rebase CMS, if it does. */
402
+ cms?: string;
401
403
  }): {
402
404
  fileCount: number;
403
405
  dir: string;
@@ -412,6 +414,8 @@ export declare function buildStaticBundle(options: {
412
414
  path?: string;
413
415
  /** Serve `index.html` for unmatched paths. Default `true`. */
414
416
  spa?: boolean;
417
+ /** Where this app mounts the Rebase CMS, if it does. */
418
+ cms?: string;
415
419
  }): {
416
420
  outDir: string;
417
421
  manifest: RebaseBundleManifest;
@@ -6,6 +6,7 @@ export interface FoldableManifest {
6
6
  output?: string;
7
7
  path?: string;
8
8
  spa?: boolean;
9
+ cms?: string;
9
10
  }>;
10
11
  }
11
12
  export interface FoldOptions {
@@ -32,6 +33,8 @@ export interface FoldableApp {
32
33
  path: string;
33
34
  /** SPA fallback, defaulted to `true`. */
34
35
  spa: boolean;
36
+ /** Where this app mounts the Rebase CMS, if it does. */
37
+ cms?: string;
35
38
  }
36
39
  /**
37
40
  * Every static app in the manifest, in mount order.
package/dist/index.es.js CHANGED
@@ -1495,33 +1495,30 @@ function renderPreview(event, properties) {
1495
1495
  * CI must behave exactly as it does today, which means not asking and not
1496
1496
  * sending.
1497
1497
  */
1498
- async function promptForConsent(event, properties, options = {}) {
1498
+ async function promptForConsent(options = {}) {
1499
1499
  if (!shouldPrompt(process.env, options)) return false;
1500
1500
  const askedBefore = suppressionReason(process.env) === "declined";
1501
1501
  try {
1502
1502
  console.log("");
1503
1503
  console.log(chalk.bold("Help improve Rebase?"));
1504
1504
  console.log("");
1505
- console.log(chalk.gray(" Rebase is self-hosted, so we have no idea what works and what does not"));
1506
- console.log(chalk.gray(" unless you tell us. Sharing is entirely optional and off by default."));
1505
+ console.log(chalk.gray(" Rebase is self-hosted, so we only learn what works if you tell us."));
1506
+ console.log(chalk.gray(" Anonymous: random ids, the CLI version, your OS, and which template and"));
1507
+ console.log(chalk.gray(" package manager you used. Never project names, paths, schemas, URLs or"));
1508
+ console.log(chalk.gray(" error messages."));
1507
1509
  console.log("");
1508
- console.log(chalk.gray(" This is exactly what would be sent nothing more, ever:"));
1509
- console.log("");
1510
- console.log(renderPreview(event, properties).split("\n").map((line) => chalk.gray(" " + line)).join("\n"));
1511
- console.log("");
1512
- console.log(chalk.gray(" No project names, paths, schemas, URLs or error messages. Change your"));
1513
- console.log(chalk.gray(` mind any time with ${chalk.cyan("rebase telemetry disable")}.`));
1510
+ console.log(chalk.gray(` Print the exact payload with ${chalk.cyan("rebase telemetry show")}; change your mind`));
1511
+ console.log(chalk.gray(` any time with ${chalk.cyan("rebase telemetry disable")}.`));
1514
1512
  if (askedBefore) {
1515
1513
  console.log("");
1516
- console.log(chalk.gray(" You declined before, and that is still the answer unless you change it"));
1517
- console.log(chalk.gray(" here. Asked once per new project; never during ordinary work."));
1514
+ console.log(chalk.gray(" You declined before; that stands unless you change it here."));
1518
1515
  }
1519
1516
  console.log("");
1520
1517
  const { accepted } = await inquirer.prompt([{
1521
1518
  type: "confirm",
1522
1519
  name: "accepted",
1523
1520
  message: "Share anonymous usage data?",
1524
- default: false
1521
+ default: true
1525
1522
  }]);
1526
1523
  setConsent(Boolean(accepted));
1527
1524
  console.log(accepted ? chalk.green(" Thank you — sharing enabled.") : chalk.gray(" Nothing will be sent." + (options.reAskDeclined ? " You will be asked again the next time you scaffold a project." : " You will not be asked again.")));
@@ -2124,7 +2121,7 @@ async function createProject$1(options) {
2124
2121
  git: Boolean(options.git),
2125
2122
  duration: durationBucket(Date.now() - startedAt)
2126
2123
  };
2127
- if (await promptForConsent("cli.init", initProperties, { reAskDeclined: true })) await recordEvent("cli.init", initProperties, { projectRoot: options.targetDirectory });
2124
+ if (await promptForConsent({ reAskDeclined: true })) await recordEvent("cli.init", initProperties, { projectRoot: options.targetDirectory });
2128
2125
  }
2129
2126
  /**
2130
2127
  * Apply a template preset by replacing the default collection files.
@@ -4403,6 +4400,38 @@ function checkAppPath(value, fieldPath, issues) {
4403
4400
  }
4404
4401
  return value;
4405
4402
  }
4403
+ /**
4404
+ * Is `candidate` the path `parent`, or something beneath it?
4405
+ *
4406
+ * Segment-aware for the same reason `isForbiddenStaticPath` is: a plain
4407
+ * `startsWith` reads `/admin` as living under `/adm`.
4408
+ */
4409
+ function isUnderPath(candidate, parent) {
4410
+ if (parent === "/") return true;
4411
+ return candidate === parent || candidate.startsWith(`${parent}/`);
4412
+ }
4413
+ /**
4414
+ * Validate where an app says it mounts the Rebase CMS.
4415
+ *
4416
+ * The same shape as {@link checkAppPath} — it is a URL path and ends up in the
4417
+ * same places — plus one rule of its own: it has to be inside the app declaring
4418
+ * it. The app's SPA fallback is what answers that URL, so a `cms` outside its
4419
+ * `path` names an address this app will never serve. That is a link the console
4420
+ * would then offer to a 404, which is worse than the missing link it replaces.
4421
+ */
4422
+ function checkCmsPath(value, appPath, fieldPath, issues) {
4423
+ if (value === void 0) return void 0;
4424
+ const cms = checkAppPath(value, fieldPath, issues);
4425
+ if (cms === void 0) return void 0;
4426
+ if (!isUnderPath(cms, appPath)) {
4427
+ issues.push({
4428
+ path: fieldPath,
4429
+ message: `must be inside this app's path — it is at "${appPath}", so it cannot serve "${cms}". The CMS is a route of this app, not a separate deployment; if it really lives elsewhere, declare that app and put \`cms\` on it instead`
4430
+ });
4431
+ return;
4432
+ }
4433
+ return cms;
4434
+ }
4406
4435
  function isRecord(value) {
4407
4436
  return typeof value === "object" && value !== null && !Array.isArray(value);
4408
4437
  }
@@ -4465,7 +4494,8 @@ var KNOWN_APP_FIELDS = {
4465
4494
  "build",
4466
4495
  "output",
4467
4496
  "path",
4468
- "spa"
4497
+ "spa",
4498
+ "cms"
4469
4499
  ]
4470
4500
  };
4471
4501
  /**
@@ -4577,7 +4607,7 @@ function validateApp(name, raw, issues) {
4577
4607
  });
4578
4608
  return raw;
4579
4609
  }
4580
- case "static":
4610
+ case "static": {
4581
4611
  checkRelativePath(raw.root, `${base}.root`, issues, { required: true });
4582
4612
  checkRelativePath(raw.output, `${base}.output`, issues, { required: true });
4583
4613
  if (raw.build !== void 0 && typeof raw.build !== "string") issues.push({
@@ -4588,8 +4618,10 @@ function validateApp(name, raw, issues) {
4588
4618
  path: `${base}.spa`,
4589
4619
  message: "must be a boolean"
4590
4620
  });
4591
- checkAppPath(raw.path, `${base}.path`, issues);
4621
+ const appPath = checkAppPath(raw.path, `${base}.path`, issues);
4622
+ checkCmsPath(raw.cms, appPath ?? "/", `${base}.cms`, issues);
4592
4623
  return raw;
4624
+ }
4593
4625
  default: return;
4594
4626
  }
4595
4627
  }
@@ -4656,6 +4688,11 @@ function validateManifest(raw) {
4656
4688
  }
4657
4689
  byPath.set(at, name);
4658
4690
  }
4691
+ const withCms = Object.entries(apps).filter(([, app]) => app.type === "static" && typeof app.cms === "string");
4692
+ if (withCms.length > 1) for (const [name] of withCms.slice(1)) issues.push({
4693
+ path: `apps.${name}.cms`,
4694
+ message: `a project has one CMS — "${withCms[0][0]}" already declares one`
4695
+ });
4659
4696
  refuseStorageBlock(raw.storage, issues);
4660
4697
  let telemetry;
4661
4698
  if (raw.telemetry !== void 0) if (typeof raw.telemetry === "boolean") telemetry = raw.telemetry;
@@ -4838,6 +4875,30 @@ function findBackendApp(manifest) {
4838
4875
  };
4839
4876
  }
4840
4877
  /**
4878
+ * Where this project mounts the Rebase CMS, if it says.
4879
+ *
4880
+ * The CMS is a component inside a developer's own app, so its address is a
4881
+ * client-side route: no build artifact, no running server and no control plane
4882
+ * can observe it. {@link RebaseStaticAppConfig.cms} is the only place that fact
4883
+ * is ever written down, and this is the one reader of it — so that "the
4884
+ * project's CMS" means the same thing to `rebase dev`, `rebase apps list`, the
4885
+ * bundle it builds and the console that shows it.
4886
+ *
4887
+ * Returns the *serving* app alongside the path, because a caller with a base URL
4888
+ * needs to know which app answers there — and because the path alone cannot say
4889
+ * whether the CMS is the whole of an app or one route of it.
4890
+ */
4891
+ function cmsMountOf(manifest) {
4892
+ for (const [name, app] of Object.entries(manifest.apps)) {
4893
+ if (app.type !== "static" || typeof app.cms !== "string") continue;
4894
+ return {
4895
+ appName: name,
4896
+ app,
4897
+ path: app.cms
4898
+ };
4899
+ }
4900
+ }
4901
+ /**
4841
4902
  * The app a deploy targets: the one named, or the obvious one.
4842
4903
  *
4843
4904
  * A repository declares apps; a project owns them. So "which app" is a question
@@ -5634,14 +5695,21 @@ async function devCommand(rawArgs) {
5634
5695
  * a shape that has no such directory reads as a broken scaffold on the
5635
5696
  * very first run of the very command the headless quickstart names.
5636
5697
  */
5637
- const declaresStaticApp = (() => {
5698
+ const staticShape = (() => {
5638
5699
  try {
5639
5700
  const { manifest } = loadManifest(projectRoot);
5640
- return Object.values(manifest.apps ?? {}).some((app) => app.type === "static");
5701
+ return {
5702
+ declaresStaticApp: Object.values(manifest.apps ?? {}).some((app) => app.type === "static"),
5703
+ cmsPath: cmsMountOf(manifest)?.path
5704
+ };
5641
5705
  } catch {
5642
- return Boolean(frontendDir);
5706
+ return {
5707
+ declaresStaticApp: Boolean(frontendDir),
5708
+ cmsPath: void 0
5709
+ };
5643
5710
  }
5644
5711
  })();
5712
+ const declaresStaticApp = staticShape.declaresStaticApp;
5645
5713
  let frontendUrl = "";
5646
5714
  let backendUrl = "";
5647
5715
  let debounceSummary = null;
@@ -5681,6 +5749,7 @@ async function devCommand(rawArgs) {
5681
5749
  ["✦ Rebase API is ready!", ""],
5682
5750
  ["➜ API: ", api]
5683
5751
  ];
5752
+ if (declaresStaticApp && staticShape.cmsPath && staticShape.cmsPath !== "/") lines.push(["➜ CMS: ", `${stripAnsi(frontendUrl).replace(/\/$/, "")}${staticShape.cmsPath}`]);
5684
5753
  if (!declaresStaticApp) {
5685
5754
  if (swaggerPath) lines.push(["➜ Swagger: ", `${api}${swaggerPath}`]);
5686
5755
  else lines.push([" ", "(no tables served yet, so no data API and no docs)"]);
@@ -7797,7 +7866,7 @@ function vendorDependencies(options) {
7797
7866
  * in one image already, that is exactly what it had.
7798
7867
  */
7799
7868
  function foldStaticIntoBundle(options) {
7800
- const { bundleDir, assetsDir, appName, path: basePath, spa } = options;
7869
+ const { bundleDir, assetsDir, appName, path: basePath, spa, cms } = options;
7801
7870
  const manifestPath = path.join(bundleDir, "manifest.json");
7802
7871
  if (!fs.existsSync(manifestPath)) throw new Error(`No manifest at ${manifestPath} — build the backend bundle first.`);
7803
7872
  if (!fs.existsSync(assetsDir)) throw new Error(`No built assets at ${assetsDir}.`);
@@ -7822,7 +7891,9 @@ function foldStaticIntoBundle(options) {
7822
7891
  static: [...existing, {
7823
7892
  path: basePath,
7824
7893
  dir,
7825
- spa
7894
+ spa,
7895
+ name: appName,
7896
+ ...cms ? { cms } : {}
7826
7897
  }]
7827
7898
  };
7828
7899
  fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
@@ -7857,7 +7928,9 @@ function buildStaticBundle(options) {
7857
7928
  entry: { static: [{
7858
7929
  path: basePath,
7859
7930
  dir: "static",
7860
- spa: options.spa ?? true
7931
+ spa: options.spa ?? true,
7932
+ name: appName,
7933
+ ...options.cms ? { cms: options.cms } : {}
7861
7934
  }] },
7862
7935
  hooks: { native: false },
7863
7936
  deps: { declared: {} },
@@ -7989,7 +8062,8 @@ function foldableApps(manifest) {
7989
8062
  build: app.build,
7990
8063
  output: app.output,
7991
8064
  path: app.path ?? "/",
7992
- spa: app.spa ?? true
8065
+ spa: app.spa ?? true,
8066
+ cms: app.cms
7993
8067
  });
7994
8068
  }
7995
8069
  apps.sort((a, b) => b.path.length - a.path.length);
@@ -8109,7 +8183,8 @@ async function foldFrontendIntoBundle(options) {
8109
8183
  assetsDir,
8110
8184
  appName: app.name,
8111
8185
  path: app.path,
8112
- spa: app.spa
8186
+ spa: app.spa,
8187
+ cms: app.cms
8113
8188
  });
8114
8189
  outcomes.push({
8115
8190
  appName: app.name,
@@ -8821,7 +8896,8 @@ async function buildAssetApp(projectRoot, name, app, runtimeRange, outOverride)
8821
8896
  outDir: outOverride ? path.resolve(process.cwd(), outOverride) : path.join(projectRoot, `dist-bundle-${name}`),
8822
8897
  runtimeRange,
8823
8898
  path: basePath,
8824
- spa: asset.spa ?? true
8899
+ spa: asset.spa ?? true,
8900
+ cms: asset.cms
8825
8901
  });
8826
8902
  const rel = path.relative(projectRoot, result.outDir);
8827
8903
  console.log(chalk.green(` ✓ static bundle → ${rel}/`) + chalk.dim(` (${result.fileCount} file(s) → served at ${basePath})`));
@@ -9004,13 +9080,6 @@ async function ejectCommand(rawArgs = []) {
9004
9080
  const dryRun = Boolean(args["--dry-run"]);
9005
9081
  const force = Boolean(args["--force"]);
9006
9082
  const requested = positionals[0];
9007
- if (requested === "infra") {
9008
- console.error(chalk.red(" ✗ `rebase eject infra` has been removed."));
9009
- console.error(chalk.gray(" It wrote rebase.infra.json, which nothing ever read. Resources bind"));
9010
- console.error(chalk.gray(" from the environment on the <BASE>__<KEY> convention; declare them in"));
9011
- console.error(chalk.gray(" config/resources.ts and see `rebase resources` for the names."));
9012
- process.exit(1);
9013
- }
9014
9083
  let loaded;
9015
9084
  try {
9016
9085
  loaded = loadManifest(projectRoot);
@@ -11735,8 +11804,11 @@ function printPayload() {
11735
11804
  console.log("");
11736
11805
  console.log(` ${describeState()}`);
11737
11806
  console.log("");
11738
- console.log(chalk.gray(" Nothing is being sent, so there is no payload to show."));
11739
- console.log(chalk.gray(` Run ${chalk.cyan("rebase telemetry enable")} first if you want to inspect one.`));
11807
+ console.log(chalk.gray(" Nothing is being sent. This is what WOULD be sent if you said yes:"));
11808
+ console.log("");
11809
+ console.log(renderPreview("cli.dev", { first_run: false }).split("\n").map((l) => " " + l).join("\n"));
11810
+ console.log("");
11811
+ console.log(chalk.gray(` Start sharing with ${chalk.cyan("rebase telemetry enable")}.`));
11740
11812
  console.log("");
11741
11813
  return;
11742
11814
  }
@@ -11752,7 +11824,7 @@ function printPayload() {
11752
11824
  }
11753
11825
  function printHelp$2() {
11754
11826
  console.log(`
11755
- ${chalk.bold("rebase telemetry")} — anonymous usage sharing (opt-in, off by default)
11827
+ ${chalk.bold("rebase telemetry")} — anonymous usage sharing (asked once per project)
11756
11828
 
11757
11829
  ${chalk.bold("Commands")}
11758
11830
  ${chalk.blue("status")} Whether anything is being shared, and why ${chalk.gray("(default)")}
@@ -18894,7 +18966,7 @@ async function appsCommand(subcommand, rawArgs = []) {
18894
18966
  function describeApp(app) {
18895
18967
  switch (app.type) {
18896
18968
  case "backend": return app.runtime === "custom" ? `custom runtime — ${app.dockerfile ?? "Dockerfile"}` : `managed runtime, config: ${app.config ?? "config"}`;
18897
- case "static": return `${app.root} → ${app.output} @ ${app.path ?? "/"}`;
18969
+ case "static": return `${app.root} → ${app.output} @ ${app.path ?? "/"}` + (app.cms ? ` ${chalk.magenta(`CMS at ${app.cms}`)}` : "");
18898
18970
  default: return "";
18899
18971
  }
18900
18972
  }
@@ -19297,6 +19369,6 @@ function telemetryNotice() {
19297
19369
  return chalk.gray(`Usage sharing: ${sharing ? "on" : "off"} — ${chalk.cyan("rebase telemetry")} to inspect or change\n`);
19298
19370
  }
19299
19371
  //#endregion
19300
- export { CURRENT_RUNTIME_RANGE, DEFAULT_BUNDLE_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CRONS_DIR, DEFAULT_FUNCTIONS_DIR, DEFAULT_SCHEMA_FILE, ManifestError, VENDOR_SIZE_MAX_BYTES, VENDOR_SIZE_WARN_BYTES, VENDOR_TARGET_CPU, VENDOR_TARGET_OS, assessManagedCompatibility, buildBundle, buildStaticBundle, buildableApps, collectDeclaredDependencies, commentSpans, composeBundleManifest, detectDeclaredDepConflicts, detectFrameworkDepDrift, detectNativeDependencies, detectStorageAuthorize, entry, findBackendApp, findUnusedServerEntry, foldStaticIntoBundle, loadManifest, manifestExists, manifestPath, normalizeEsmSpecifiers, resolveBackendPaths, selectDeployApp, synthesizeManifest, validateManifest, vendorDependencies, writeManifest };
19372
+ export { CURRENT_RUNTIME_RANGE, DEFAULT_BUNDLE_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CRONS_DIR, DEFAULT_FUNCTIONS_DIR, DEFAULT_SCHEMA_FILE, ManifestError, VENDOR_SIZE_MAX_BYTES, VENDOR_SIZE_WARN_BYTES, VENDOR_TARGET_CPU, VENDOR_TARGET_OS, assessManagedCompatibility, buildBundle, buildStaticBundle, buildableApps, cmsMountOf, collectDeclaredDependencies, commentSpans, composeBundleManifest, detectDeclaredDepConflicts, detectFrameworkDepDrift, detectNativeDependencies, detectStorageAuthorize, entry, findBackendApp, findUnusedServerEntry, foldStaticIntoBundle, loadManifest, manifestExists, manifestPath, normalizeEsmSpecifiers, resolveBackendPaths, selectDeployApp, synthesizeManifest, validateManifest, vendorDependencies, writeManifest };
19301
19373
 
19302
19374
  //# sourceMappingURL=index.es.js.map