@rebasepro/cli 0.11.1-canary.gfd39654 → 0.12.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.
Files changed (37) hide show
  1. package/bin/rebase.js +21 -0
  2. package/dist/bundle.d.ts +24 -7
  3. package/dist/commands/eject.d.ts +1 -0
  4. package/dist/commands/init.d.ts +19 -15
  5. package/dist/fold-static.d.ts +41 -15
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.es.js +894 -246
  8. package/dist/index.es.js.map +1 -1
  9. package/dist/manifest.d.ts +27 -8
  10. package/package.json +7 -7
  11. package/runtime/dev-server.mjs +0 -1
  12. package/templates/{template/backend → eject}/Dockerfile +16 -4
  13. package/templates/{template → eject}/backend/src/env.ts +0 -1
  14. package/templates/{template → eject}/backend/src/index.ts +41 -27
  15. package/templates/eject/docker-compose.custom.yml +71 -0
  16. package/templates/overlays/baas/backend/package.json +1 -4
  17. package/templates/overlays/baas/backend/tsconfig.json +8 -2
  18. package/templates/overlays/baas/config/index.ts +15 -0
  19. package/templates/overlays/baas/config/package.json +28 -0
  20. package/templates/overlays/baas/package.json +2 -1
  21. package/templates/overlays/baas/pnpm-workspace.yaml +1 -0
  22. package/templates/overlays/baas/rebase.json +2 -6
  23. package/templates/template/.env.example +15 -0
  24. package/templates/template/README.md +56 -22
  25. package/templates/template/ai-instructions.md +1 -0
  26. package/templates/template/backend/functions/hello.ts +45 -14
  27. package/templates/template/backend/package.json +1 -4
  28. package/templates/template/backend/tsconfig.json +23 -2
  29. package/templates/template/config/tsconfig.json +16 -1
  30. package/templates/template/docker-compose.yml +62 -38
  31. package/templates/template/frontend/src/main.tsx +8 -1
  32. package/templates/template/frontend/vite.config.ts +5 -0
  33. package/templates/template/rebase.json +5 -8
  34. package/templates/overlays/baas/backend/src/index.ts +0 -216
  35. package/templates/template/frontend/Dockerfile +0 -52
  36. package/templates/template/frontend/nginx.conf +0 -40
  37. /package/templates/overlays/baas/{backend/src → config}/storage.ts +0 -0
package/bin/rebase.js CHANGED
@@ -65,6 +65,27 @@ try {
65
65
  /* ignore */
66
66
  }
67
67
 
68
+ /**
69
+ * `dist/` is gitignored, so in a fresh clone it does not exist until someone
70
+ * runs a build — and `rebase` is reached long before that: CONTRIBUTING's
71
+ * getting-started steps call `db push` and `dev` through it. Importing a
72
+ * missing module raises a bare ERR_MODULE_NOT_FOUND stack trace naming an
73
+ * internal path, which reads as a broken repository rather than a missing step.
74
+ *
75
+ * stderr, like the staleness warning above, so `--json` output stays parseable.
76
+ */
77
+ if (!existsSync(distEntry)) {
78
+ const dev = existsSync(srcDir);
79
+ process.stderr.write(
80
+ `\x1b[31m✗ rebase CLI: not built yet — ${distEntry} is missing.\x1b[0m\n` +
81
+ (dev
82
+ ? " Build it with: pnpm --filter @rebasepro/cli build\n" +
83
+ " (or `pnpm build` from the repo root to build every package)\n"
84
+ : " This install looks incomplete; try reinstalling @rebasepro/cli.\n")
85
+ );
86
+ process.exit(1);
87
+ }
88
+
68
89
  const { entry } = await import("../dist/index.es.js");
69
90
 
70
91
  entry(process.argv);
package/dist/bundle.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type NativeDependency, type RebaseBundleManifest, type RebaseBackendAppConfig } from "@rebasepro/types";
1
+ import { type DeclaredStorageSources, type NativeDependency, type RebaseBundleManifest, type RebaseBackendAppConfig } from "@rebasepro/types";
2
2
  export declare const DEFAULT_BUNDLE_DIR = "dist-bundle";
3
3
  export interface BuildBundleOptions {
4
4
  projectRoot: string;
@@ -8,6 +8,13 @@ export interface BuildBundleOptions {
8
8
  outDir?: string;
9
9
  /** Runtime range from the manifest, recorded for compatibility checks. */
10
10
  runtimeRange: string;
11
+ /**
12
+ * The `storage` block of `rebase.json` — which buckets this project uses.
13
+ *
14
+ * Passed in rather than re-read here so `rebase.json` is parsed and validated
15
+ * once, by the command that owns it.
16
+ */
17
+ storage?: DeclaredStorageSources;
11
18
  /** Skip type checking. Faster, and strictly worse — for iteration only. */
12
19
  skipTypeCheck?: boolean;
13
20
  /** Skip regenerating the Drizzle schema from the collections. */
@@ -37,7 +44,7 @@ export interface BuildBundleResult {
37
44
  * says exactly how to proceed, while a false positive would hand back the crash
38
45
  * loop this exists to prevent.
39
46
  */
40
- export declare function detectStorageAuthorize(compiledConfigDir: string): boolean;
47
+ export declare function detectStorageAuthorize(compiledConfigDir: string, depth?: number): boolean;
41
48
  /**
42
49
  * Detect native code in the dependency closure.
43
50
  *
@@ -94,11 +101,10 @@ export declare function normalizeEsmSpecifiers(outDir: string): {
94
101
  * deployed green, and answered 404 on every one of them, with the file still
95
102
  * sitting in the repository looking exactly like the server.
96
103
  *
97
- * A project that means to keep its own entrypoint declares the app as
98
- * `"type": "custom"`, which builds the repository's Dockerfile instead which
99
- * is what {@link synthesizeManifest} already infers for a manifest-less repo
100
- * carrying one. The warning names that route rather than implying the file is
101
- * a mistake.
104
+ * A project that means to keep its own entrypoint runs `rebase eject`, which
105
+ * writes the entrypoint, a Dockerfile and a compose file together and flips the
106
+ * backend to `runtime: "custom"`. The warning names that route rather than
107
+ * implying the file is a mistake.
102
108
  */
103
109
  export declare function findUnusedServerEntry(projectRoot: string, functionsDir: string): string | undefined;
104
110
  /**
@@ -151,8 +157,15 @@ export declare function foldStaticIntoBundle(options: {
151
157
  bundleDir: string;
152
158
  /** Directory of built frontend assets (the static app's `output`). */
153
159
  assetsDir: string;
160
+ /** The app's name in `rebase.json`. Names its directory inside the bundle. */
161
+ appName: string;
162
+ /** Public base path this app is served under. */
163
+ path: string;
164
+ /** Serve `index.html` for unmatched paths under `path`. */
165
+ spa: boolean;
154
166
  }): {
155
167
  fileCount: number;
168
+ dir: string;
156
169
  };
157
170
  export declare function buildStaticBundle(options: {
158
171
  projectRoot: string;
@@ -160,6 +173,10 @@ export declare function buildStaticBundle(options: {
160
173
  assetsDir: string;
161
174
  outDir: string;
162
175
  runtimeRange: string;
176
+ /** Public base path. Default `/` — a standalone bundle owns its origin. */
177
+ path?: string;
178
+ /** Serve `index.html` for unmatched paths. Default `true`. */
179
+ spa?: boolean;
163
180
  }): {
164
181
  outDir: string;
165
182
  manifest: RebaseBundleManifest;
@@ -0,0 +1 @@
1
+ export declare function ejectCommand(rawArgs?: string[]): Promise<void>;
@@ -1,19 +1,23 @@
1
1
  import type { PackageManager, PMCommands } from "../utils/package-manager";
2
- /** Returns an error message, or null when the name is a valid package name. */
3
- export declare function validateProjectName(name: string): string | null;
4
- export type TemplatePreset = "blog" | "ecommerce" | "blank";
5
2
  /**
6
- * How much of Rebase to scaffold.
3
+ * Every scaffolded file that carries a `{{PLACEHOLDER}}`.
7
4
  *
8
- * `cms` is the full triad (config + backend + frontend). `baas` is the backend
9
- * alone, serving the database over REST with no collection files and no UI.
10
- */
11
- /**
12
- * `cms` scaffolds BaaS + the admin UI; `baas` scaffolds the API alone. The
13
- * values match `RebaseBackendConfig.mode`, which is what the generated backend
14
- * sets the labels below are what users actually read.
5
+ * Exported because it is the single source of truth: `init.test.ts` reads it and
6
+ * asserts that every template file containing `{{` appears here. It used to be a
7
+ * local, with the test harness keeping a *second* copy — so the two drifted, and
8
+ * a test built on the copy could not observe the production list at all.
9
+ *
10
+ * The drift shipped: `docker-compose.yml` arrived with the self-host work
11
+ * (26fd5259c) and was added to neither, so every scaffolded project got a literal
12
+ * `name: {{PROJECT_NAME}}`. In YAML `{{...}}` is a map, not a string, so the
13
+ * documented `docker compose up` path failed on the file before doing anything:
14
+ *
15
+ * yaml: unmarshal errors: line 28: cannot unmarshal !!map into string
15
16
  */
16
- export type TemplateFlavor = "cms" | "baas";
17
+ export declare const TEMPLATE_PLACEHOLDER_FILES: string[];
18
+ /** Returns an error message, or null when the name is a valid package name. */
19
+ export declare function validateProjectName(name: string): string | null;
20
+ export type TemplatePreset = "blog" | "ecommerce" | "blank";
17
21
  export interface InitOptions {
18
22
  projectName: string;
19
23
  git: boolean;
@@ -26,8 +30,8 @@ export interface InitOptions {
26
30
  preset: TemplatePreset;
27
31
  /** Whether `preset` came from an explicit --template rather than the default. */
28
32
  explicitPreset?: boolean;
29
- /** Which parts of Rebase to scaffold. */
30
- flavor: TemplateFlavor;
33
+ /** Scaffold the backend alone, with no admin panel and no collections. */
34
+ headless: boolean;
31
35
  /** Detected package manager (pnpm or npm). */
32
36
  pm: PackageManager;
33
37
  /** Command helpers for the detected PM. */
@@ -42,7 +46,7 @@ export interface InitOptions {
42
46
  export interface BuildQuestionsParams {
43
47
  nameArg?: string;
44
48
  templateArg?: TemplatePreset;
45
- flavorArg?: TemplateFlavor;
49
+ headlessArg?: boolean;
46
50
  hasGitFlag: boolean;
47
51
  hasInstallFlag: boolean;
48
52
  pm: PackageManager;
@@ -4,6 +4,8 @@ export interface FoldableManifest {
4
4
  type?: string;
5
5
  build?: string;
6
6
  output?: string;
7
+ path?: string;
8
+ spa?: boolean;
7
9
  }>;
8
10
  }
9
11
  export interface FoldOptions {
@@ -11,36 +13,60 @@ export interface FoldOptions {
11
13
  manifest: FoldableManifest;
12
14
  /** The backend bundle directory, already written. */
13
15
  bundleDir: string;
14
- /** Skip running the app's own build command; fold what is already built. */
16
+ /** Skip running each app's own build command; fold what is already built. */
15
17
  skipBuild?: boolean;
16
18
  log?: (message: string) => void;
17
19
  }
18
20
  export interface FoldOutcome {
19
21
  appName: string;
20
22
  fileCount: number;
23
+ /** Public base path this app was folded in at. */
24
+ path: string;
25
+ }
26
+ /** A static app as folding sees it, with the manifest's defaults applied. */
27
+ export interface FoldableApp {
28
+ name: string;
29
+ build?: string;
30
+ output?: string;
31
+ /** Public base path, defaulted to `/`. */
32
+ path: string;
33
+ /** SPA fallback, defaulted to `true`. */
34
+ spa: boolean;
21
35
  }
22
36
  /**
23
- * Which static app, if any, should be served by the backend.
37
+ * Every static app in the manifest, in mount order.
24
38
  *
25
- * Exactly one `static` app is folded. With several, folding would have to choose,
26
- * and silently picking one of two websites is worse than doing nothing — so it
27
- * declines and names what it saw. Pure, so the decision is testable without a
28
- * filesystem.
39
+ * Longest path first, so the `/`-rooted app is registered last its catch-all
40
+ * would otherwise claim its siblings' URLs. Pure, so the ordering is testable
41
+ * without a filesystem.
29
42
  */
30
- export declare function selectFoldableApp(manifest: FoldableManifest): {
31
- app?: {
43
+ export declare function foldableApps(manifest: FoldableManifest): {
44
+ apps: FoldableApp[];
45
+ /** Apps that cannot be folded, and why. */
46
+ skipped: {
32
47
  name: string;
33
- build?: string;
34
- output?: string;
35
- };
36
- /** Why nothing will be folded, when that is the answer. */
37
- reason?: string;
48
+ reason: string;
49
+ }[];
38
50
  };
39
51
  /**
40
- * Build the project's frontend and fold it into the backend bundle.
52
+ * Assert a built app's assets are actually rooted at the path it is served from.
53
+ *
54
+ * An app mounted at `/admin` but built with Vite's default `base: "/"` emits
55
+ * `<script src="/assets/index-a1b2.js">`. The server serves `index.html` fine
56
+ * and 404s every asset: a blank page, no server error, nothing in the logs. It
57
+ * is the single most expensive silent failure in this design, so it is a build
58
+ * error rather than a runtime surprise.
59
+ *
60
+ * Only `<script src>` and `<link href>` are inspected — those are what a bundler
61
+ * rewrites through `base`. Author-written anchors and canonical URLs are not
62
+ * evidence of a misbuild.
63
+ */
64
+ export declare function assertBuiltForPath(indexHtml: string, basePath: string, appName: string): void;
65
+ /**
66
+ * Build the project's static apps and fold them into the backend bundle.
41
67
  *
42
68
  * Throws rather than exiting, so the caller decides whether a missing frontend
43
69
  * should fail its command — a `build` may reasonably want to stop, and so should
44
70
  * a deploy, but that is not this function's call to make.
45
71
  */
46
- export declare function foldFrontendIntoBundle(options: FoldOptions): Promise<FoldOutcome | null>;
72
+ export declare function foldFrontendIntoBundle(options: FoldOptions): Promise<FoldOutcome[]>;
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export * from "./commands/schema";
4
4
  export * from "./commands/db";
5
5
  export * from "./commands/dev";
6
6
  export * from "./commands/build";
7
+ export * from "./commands/eject";
7
8
  export * from "./commands/start";
8
9
  export * from "./commands/auth";
9
10
  export * from "./commands/doctor";