@rebasepro/cli 0.10.1-canary.6f89f77 → 0.10.1-canary.7801eed

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 (36) hide show
  1. package/dist/bundle.d.ts +167 -0
  2. package/dist/commands/apps.d.ts +1 -0
  3. package/dist/commands/build.d.ts +1 -1
  4. package/dist/commands/cloud/bundle-deploy.d.ts +53 -0
  5. package/dist/commands/cloud/context.d.ts +18 -0
  6. package/dist/commands/cloud/deploy.d.ts +48 -0
  7. package/dist/commands/generate_sdk.d.ts +25 -0
  8. package/dist/commands/start.d.ts +1 -1
  9. package/dist/fold-static.d.ts +46 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.es.js +2403 -37
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/manifest.d.ts +83 -0
  14. package/dist/utils/project.d.ts +11 -3
  15. package/package.json +8 -7
  16. package/runtime/dev-server.mjs +43 -0
  17. package/templates/overlays/baas/backend/src/index.ts +7 -0
  18. package/templates/overlays/baas/backend/src/storage.ts +71 -0
  19. package/templates/overlays/baas/rebase.json +14 -0
  20. package/templates/template/.env.example +5 -0
  21. package/templates/template/README.md +8 -3
  22. package/templates/template/backend/src/index.ts +7 -0
  23. package/templates/template/config/admin.d.ts +9 -0
  24. package/templates/template/config/collections/authors.ts +12 -10
  25. package/templates/template/config/collections/posts.ts +17 -13
  26. package/templates/template/config/collections/presets/ecommerce/categories.ts +8 -6
  27. package/templates/template/config/collections/presets/ecommerce/orders.ts +33 -21
  28. package/templates/template/config/collections/presets/ecommerce/products.ts +27 -18
  29. package/templates/template/config/collections/tags.ts +6 -4
  30. package/templates/template/config/collections/users.ts +35 -30
  31. package/templates/template/config/frontend-assets.d.ts +17 -0
  32. package/templates/template/config/index.ts +6 -0
  33. package/templates/template/config/package.json +26 -25
  34. package/templates/template/config/storage.ts +88 -0
  35. package/templates/template/gitignore +4 -0
  36. package/templates/template/rebase.json +20 -0
@@ -0,0 +1,167 @@
1
+ import { type NativeDependency, type RebaseBundleManifest, type RebaseBackendAppConfig } from "@rebasepro/types";
2
+ export declare const DEFAULT_BUNDLE_DIR = "dist-bundle";
3
+ export interface BuildBundleOptions {
4
+ projectRoot: string;
5
+ appName: string;
6
+ app: RebaseBackendAppConfig;
7
+ /** Output directory, absolute or relative to the project root. */
8
+ outDir?: string;
9
+ /** Runtime range from the manifest, recorded for compatibility checks. */
10
+ runtimeRange: string;
11
+ /** Skip type checking. Faster, and strictly worse — for iteration only. */
12
+ skipTypeCheck?: boolean;
13
+ /** Skip regenerating the Drizzle schema from the collections. */
14
+ skipSchema?: boolean;
15
+ /** Emit progress. */
16
+ log?: (message: string) => void;
17
+ }
18
+ export interface BuildBundleResult {
19
+ outDir: string;
20
+ manifest: RebaseBundleManifest;
21
+ collectionCount: number;
22
+ }
23
+ /**
24
+ * Whether the compiled config package exports a `storageAuthorize` hook.
25
+ *
26
+ * Recorded in the manifest so a host can refuse a deploy that would enable file
27
+ * storage with no access model, rather than let the runtime's boot guard turn it
28
+ * into a crash loop the developer cannot read.
29
+ *
30
+ * Read from the *compiled* index, deliberately: that is the exact module the
31
+ * runtime imports and reads the export off, so this cannot disagree with what
32
+ * actually happens at boot. It is a textual check rather than an import because
33
+ * a freshly built bundle cannot resolve its own dependencies until it is
34
+ * deployed — the same reason schema hashing reads source.
35
+ *
36
+ * Errs toward `false`: a missed detection costs a deploy rejection whose message
37
+ * says exactly how to proceed, while a false positive would hand back the crash
38
+ * loop this exists to prevent.
39
+ */
40
+ export declare function detectStorageAuthorize(compiledConfigDir: string): boolean;
41
+ /**
42
+ * Detect native code in the dependency closure.
43
+ *
44
+ * Walks declared runtime dependencies breadth-first through `node_modules`,
45
+ * flagging anything with a `binding.gyp`, a prebuilt `.node` binary, or an
46
+ * install script that builds one. The managed runtime cannot run these: a
47
+ * binary compiled for one image will not load in another, and finding that out
48
+ * at deploy time is far better than in a crash loop.
49
+ *
50
+ * The walk is bounded. A dependency graph can be enormous, and this is a
51
+ * heuristic gate whose false negatives are caught at deploy time anyway.
52
+ */
53
+ export declare function detectNativeDependencies(projectRoot: string, declared: Record<string, string>, limit?: number): NativeDependency[];
54
+ /**
55
+ * Collect the runtime dependencies a bundle needs installed beside it.
56
+ *
57
+ * Packages the runtime image already provides are excluded — reinstalling a
58
+ * second copy of the server next to the one running the process is at best
59
+ * wasted space and at worst a version conflict. Workspace packages are excluded
60
+ * too: they are not on the registry the runtime installs from, and the project's
61
+ * own config package already travels inside the bundle.
62
+ */
63
+ export declare function collectDeclaredDependencies(projectRoot: string): Record<string, string>;
64
+ /**
65
+ * Rewrite relative import specifiers in emitted JavaScript so Node can resolve them.
66
+ *
67
+ * TypeScript deliberately does not touch specifiers: `moduleResolution: "bundler"`
68
+ * lets a project write `from "./posts"` or `from "./collections"`, and TypeScript
69
+ * emits them unchanged on the assumption that a bundler will finish the job.
70
+ * Nothing bundles a Rebase bundle — the runtime imports these files directly with
71
+ * Node's ESM loader, which requires a full path with an extension and refuses
72
+ * directory imports outright.
73
+ *
74
+ * Without this, adopting the bundle would mean asking every project written in
75
+ * the (extremely common) extensionless style to rewrite all of its imports. The
76
+ * rewrite is mechanical and verifiable: only relative specifiers are touched, and
77
+ * only when the target file actually exists on disk.
78
+ */
79
+ export declare function normalizeEsmSpecifiers(outDir: string): {
80
+ rewritten: number;
81
+ unresolved: string[];
82
+ };
83
+ /**
84
+ * A hand-written server entrypoint that a bundle does not use.
85
+ *
86
+ * `rebase dev` runs `backend/src/index.ts` whenever a project has one, so for
87
+ * the whole of local development that file *is* the server and every route
88
+ * written in it works. A bundle has no entrypoint of its own: the runtime boots
89
+ * the bundle and mounts what the manifest points at — the config package,
90
+ * functions, crons and the schema. The file is not compiled, not shipped, and
91
+ * never imported.
92
+ *
93
+ * Nothing said so. A project with custom routes in its entrypoint built clean,
94
+ * deployed green, and answered 404 on every one of them, with the file still
95
+ * sitting in the repository looking exactly like the server.
96
+ *
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.
102
+ */
103
+ export declare function findUnusedServerEntry(projectRoot: string, functionsDir: string): string | undefined;
104
+ /**
105
+ * Compile and assemble a bundle.
106
+ */
107
+ export declare function buildBundle(options: BuildBundleOptions): Promise<BuildBundleResult>;
108
+ /**
109
+ * Package a built static app (a `static` or bundled-`admin` app) into a bundle.
110
+ *
111
+ * A static bundle is the counterpart to a backend bundle: the same shape, the
112
+ * same runtime image runs it, but its manifest says `mode: "static"` and it
113
+ * carries only the built assets under `static/`. That is what lets a frontend or
114
+ * admin app be its own deployable, scalable unit rather than something baked into
115
+ * the backend container.
116
+ *
117
+ * `assetsDir` is the app's built output (e.g. `frontend/dist`), already produced
118
+ * by its own build command. This copies it into the bundle and writes the
119
+ * manifest — no compilation, no dependency closure (a static bundle installs
120
+ * nothing at boot).
121
+ */
122
+ /**
123
+ * Fold a built static app into a backend bundle, so one runtime serves both.
124
+ *
125
+ * ## Why this exists
126
+ *
127
+ * A managed tenant runs one pod, and `bootFromBundle` on the backend path already
128
+ * knows how to serve a SPA — it looks for `entry.static` and mounts `serveSPA`
129
+ * last, behind `REBASE_SERVE_STATIC`. What was missing was anything putting the
130
+ * assets there.
131
+ *
132
+ * The consequence was not subtle. A project whose custom image served its website
133
+ * at `/` and its API at `/api` — the shape the scaffolded template produces — lost
134
+ * the website the moment it moved to the managed runtime: the API answered
135
+ * perfectly and every page 404'd. Managed could not be a drop-in replacement for
136
+ * custom while the frontend simply vanished.
137
+ *
138
+ * Folding restores parity with the container it replaces, which is the only
139
+ * honest baseline. It is deliberately the FIRST implementation and not the last:
140
+ * a static app on its own bucket behind a CDN is better for cache behaviour and
141
+ * lets the frontend deploy independently. But that needs infrastructure that does
142
+ * not exist yet, and "your site is gone" is not an acceptable state to leave a
143
+ * project in while it gets built.
144
+ *
145
+ * The trade it makes, stated plainly: frontend and backend now deploy together
146
+ * and the bundle carries the built assets. For a project that was shipping both
147
+ * in one image already, that is exactly what it had.
148
+ */
149
+ export declare function foldStaticIntoBundle(options: {
150
+ /** The backend bundle directory, already written. */
151
+ bundleDir: string;
152
+ /** Directory of built frontend assets (the static app's `output`). */
153
+ assetsDir: string;
154
+ }): {
155
+ fileCount: number;
156
+ };
157
+ export declare function buildStaticBundle(options: {
158
+ projectRoot: string;
159
+ appName: string;
160
+ assetsDir: string;
161
+ outDir: string;
162
+ runtimeRange: string;
163
+ }): {
164
+ outDir: string;
165
+ manifest: RebaseBundleManifest;
166
+ fileCount: number;
167
+ };
@@ -0,0 +1 @@
1
+ export declare function appsCommand(subcommand: string | undefined, rawArgs?: string[]): Promise<void>;
@@ -1 +1 @@
1
- export declare function buildCommand(): Promise<void>;
1
+ export declare function buildCommand(rawArgs?: string[]): Promise<void>;
@@ -0,0 +1,53 @@
1
+ import type { RebaseBundleManifest } from "@rebasepro/types";
2
+ /** Read and shallow-validate a built bundle's manifest. */
3
+ export declare function readBundleManifest(bundleDir: string): RebaseBundleManifest;
4
+ /**
5
+ * Tar a built bundle into a gzipped archive.
6
+ *
7
+ * `node_modules` is excluded on purpose: the bundle ships a `package.json`, and
8
+ * the managed runtime installs the declared dependencies at boot. Uploading an
9
+ * installed `node_modules` would bloat the archive and could carry a
10
+ * platform-specific build that will not run on the runtime image.
11
+ */
12
+ export declare function packBundle(bundleDir: string, outPath: string): Promise<void>;
13
+ /**
14
+ * Assemble the deploy-trigger body for a bundle deploy.
15
+ *
16
+ * The manifest travels with the trigger so the control plane can validate intake
17
+ * without unpacking the uploaded archive first — a rejection (native deps, no
18
+ * matching runtime) is then a fast, cheap answer.
19
+ */
20
+ export declare function bundleDeployBody(input: {
21
+ projectId: string;
22
+ bundleId: string;
23
+ manifest: RebaseBundleManifest;
24
+ app?: string;
25
+ message?: string;
26
+ /**
27
+ * Every app this repository declares in `rebase.json`, so the platform can
28
+ * register the whole set rather than only the one being deployed.
29
+ */
30
+ declaredApps?: DeclaredApp[];
31
+ }): Record<string, unknown>;
32
+ /** An app as `rebase.json` declares it, reduced to what the registry stores. */
33
+ export interface DeclaredApp {
34
+ name: string;
35
+ type: string;
36
+ }
37
+ /**
38
+ * The apps a project manifest declares.
39
+ *
40
+ * A deploy only ever ships ONE app's bundle, so the trigger alone could never
41
+ * tell the platform that the repository also contains a web frontend and an
42
+ * admin panel — and the Apps page, whose whole job is to show the set, listed a
43
+ * single entry called "backend". Sending the declared set fixes that without
44
+ * pretending the others are deployed: the platform registers them, and their
45
+ * status says what is actually true.
46
+ */
47
+ export declare function declaredAppsFrom(manifest: {
48
+ apps?: Record<string, {
49
+ type?: string;
50
+ }>;
51
+ } | null | undefined): DeclaredApp[];
52
+ /** Upload a bundle archive; returns the control-plane bundle id. */
53
+ export declare function uploadBundle(url: string, token: string, projectId: string, tarPath: string): Promise<string>;
@@ -62,6 +62,24 @@ export interface ProjectLink {
62
62
  slug?: string;
63
63
  projectName?: string;
64
64
  orgId?: string;
65
+ /**
66
+ * Base URL of the project's own API.
67
+ *
68
+ * For a cloud project this is a convenience derived from the subdomain. For
69
+ * a **self-hosted** project it is the entire link: there is no control plane
70
+ * to look anything up in, so `projectId` is empty and this is what commands
71
+ * resolve against.
72
+ *
73
+ * Keeping both kinds of link in one file is deliberate. A second link file
74
+ * for self-hosting would fork every command that reads one, and the tooling
75
+ * would drift into being cloud-only by accident.
76
+ */
77
+ apiUrl?: string;
78
+ /**
79
+ * How this checkout is linked. Absent means `cloud` — which is every link
80
+ * written before this field existed.
81
+ */
82
+ mode?: "cloud" | "direct";
65
83
  }
66
84
  export declare function readLink(cwd?: string): ProjectLink | null;
67
85
  export declare function writeLink(link: ProjectLink, cwd?: string): void;
@@ -1,2 +1,50 @@
1
+ /** A project row, reduced to what says how it deploys (camel or snake columns). */
2
+ export interface DeployProjectRow {
3
+ runtimeMode?: string;
4
+ runtime_mode?: string;
5
+ gitRepoUrl?: string;
6
+ git_repo_url?: string;
7
+ gitBranch?: string;
8
+ git_branch?: string;
9
+ }
10
+ /** A deployment row, reduced to what says what it was built from. */
11
+ export interface DeploySourceRow {
12
+ id?: string | number;
13
+ status?: string;
14
+ createdAt?: string | Date;
15
+ created_at?: string | Date;
16
+ sourceRef?: string;
17
+ source_ref?: string;
18
+ bundleId?: string;
19
+ bundle_id?: string;
20
+ }
21
+ export interface BareDeployPlan {
22
+ /**
23
+ * Whether the project runs the platform runtime — in which case any source
24
+ * build here ejects it back onto a container image.
25
+ */
26
+ managed: boolean;
27
+ /**
28
+ * `git` — the control plane will clone the configured repository.
29
+ * `snapshot` — it will rebuild the newest uploaded source archive.
30
+ * `none` — it holds neither, and will refuse.
31
+ */
32
+ source: "git" | "snapshot" | "none";
33
+ /** Lines describing the build, printed before it is triggered. */
34
+ lines: string[];
35
+ }
36
+ /** Rough age of a timestamp, for "…uploaded 6d ago". Undefined if unreadable. */
37
+ export declare function timeAgo(value: string | Date | undefined, now: Date): string | undefined;
38
+ /**
39
+ * Whether this project runs on the managed runtime.
40
+ *
41
+ * `runtimeMode` on the project row is the authority — the control plane writes
42
+ * it. The bundle-id fallback covers a control plane that does not return the
43
+ * field: a successful deploy that served a bundle only happens on the managed
44
+ * path.
45
+ */
46
+ export declare function isManagedProject(project: DeployProjectRow | undefined, latest: DeploySourceRow | undefined): boolean;
47
+ /** What a `deploy` with nothing attached will build, in the words to print. */
48
+ export declare function planBareDeploy(project: DeployProjectRow | undefined, latest: DeploySourceRow | undefined, now: Date): BareDeployPlan;
1
49
  export declare function deployCommand(rawArgs: string[], projectRef: string): Promise<void>;
2
50
  export declare function logsCommand(rawArgs: string[], projectRef: string): Promise<void>;
@@ -10,7 +10,32 @@ interface GenerateSDKArgs {
10
10
  collectionsDir: string;
11
11
  output: string;
12
12
  cwd: string;
13
+ /**
14
+ * Where to read the schema from instead of local source.
15
+ *
16
+ * `link` uses this checkout's linked project; anything else is treated as
17
+ * the base URL of a Rebase backend. This is what lets a repository that
18
+ * contains no collections — a separate frontend, a second web app — generate
19
+ * a typed client from the project it talks to.
20
+ */
21
+ from?: string;
22
+ /** Bearer token for the contract endpoint. Falls back to REBASE_SERVICE_KEY. */
23
+ token?: string;
24
+ help?: boolean;
13
25
  }
26
+ /**
27
+ * The base URL to show in the printed usage example.
28
+ *
29
+ * `rebase dev` binds a port derived from the project path, not 3001, and writes
30
+ * the one it actually got to `.rebase/state.json`. Printing a hardcoded
31
+ * `localhost:3001` sent people to a port nothing was listening on — or, with
32
+ * several projects on one machine, to a different project's backend. Prefer the
33
+ * port this project last ran on; fall back to the literal only when the project
34
+ * has never been started.
35
+ */
36
+ export declare function resolveExampleBaseUrl(cwd: string): string;
37
+ /** Whether a slug can be written as `rebase.data.<slug>` rather than a lookup. */
38
+ export declare function isIdentifierLike(slug: string): boolean;
14
39
  /**
15
40
  * Main entry point for the generate-sdk command.
16
41
  */
@@ -1 +1 @@
1
- export declare function startCommand(): Promise<void>;
1
+ export declare function startCommand(rawArgs?: string[]): Promise<void>;
@@ -0,0 +1,46 @@
1
+ /** The apps section of a project manifest, as much of it as folding needs. */
2
+ export interface FoldableManifest {
3
+ apps?: Record<string, {
4
+ type?: string;
5
+ build?: string;
6
+ output?: string;
7
+ }>;
8
+ }
9
+ export interface FoldOptions {
10
+ projectRoot: string;
11
+ manifest: FoldableManifest;
12
+ /** The backend bundle directory, already written. */
13
+ bundleDir: string;
14
+ /** Skip running the app's own build command; fold what is already built. */
15
+ skipBuild?: boolean;
16
+ log?: (message: string) => void;
17
+ }
18
+ export interface FoldOutcome {
19
+ appName: string;
20
+ fileCount: number;
21
+ }
22
+ /**
23
+ * Which static app, if any, should be served by the backend.
24
+ *
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.
29
+ */
30
+ export declare function selectFoldableApp(manifest: FoldableManifest): {
31
+ app?: {
32
+ name: string;
33
+ build?: string;
34
+ output?: string;
35
+ };
36
+ /** Why nothing will be folded, when that is the answer. */
37
+ reason?: string;
38
+ };
39
+ /**
40
+ * Build the project's frontend and fold it into the backend bundle.
41
+ *
42
+ * Throws rather than exiting, so the caller decides whether a missing frontend
43
+ * should fail its command — a `build` may reasonably want to stop, and so should
44
+ * a deploy, but that is not this function's call to make.
45
+ */
46
+ export declare function foldFrontendIntoBundle(options: FoldOptions): Promise<FoldOutcome | null>;
package/dist/index.d.ts CHANGED
@@ -9,5 +9,8 @@ export * from "./commands/auth";
9
9
  export * from "./commands/doctor";
10
10
  export * from "./commands/generate_sdk";
11
11
  export * from "./commands/cloud";
12
+ export * from "./commands/apps";
12
13
  export * from "./utils/project";
13
14
  export * from "./utils/package-manager";
15
+ export * from "./manifest";
16
+ export * from "./bundle";