@rebasepro/cli 0.22.0 → 0.24.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/README.md +19 -3
- package/bin/rebase.js +1 -1
- package/dist/{branch-pointer-dBiClJ0p.js → branch-pointer-kk9F5FBO.js} +2 -2
- package/dist/{branch-pointer-dBiClJ0p.js.map → branch-pointer-kk9F5FBO.js.map} +1 -1
- package/dist/bundle.d.ts +16 -2
- package/dist/cli.d.ts +39 -0
- package/dist/commands/__test_support__/parser-specs.d.ts +13 -0
- package/dist/commands/agent-setup.d.ts +116 -0
- package/dist/commands/api-keys.d.ts +85 -22
- package/dist/commands/apps.d.ts +19 -0
- package/dist/commands/auth.d.ts +19 -0
- package/dist/commands/build.d.ts +13 -1
- package/dist/commands/cloud/auth.d.ts +4 -3
- package/dist/commands/cloud/bundle-deploy.d.ts +79 -5
- package/dist/commands/cloud/context.d.ts +87 -5
- package/dist/commands/cloud/cron.d.ts +53 -0
- package/dist/commands/cloud/db-connect.d.ts +15 -0
- package/dist/commands/cloud/debug.d.ts +134 -0
- package/dist/commands/cloud/deploy.d.ts +55 -2
- package/dist/commands/cloud/domains.d.ts +2 -2
- package/dist/commands/cloud/env.d.ts +14 -0
- package/dist/commands/cloud/index.d.ts +89 -12
- package/dist/commands/cloud/rebuild-source.d.ts +24 -2
- package/dist/commands/cloud/token-capabilities.d.ts +76 -0
- package/dist/commands/cloud/tokens.d.ts +23 -0
- package/dist/commands/db.d.ts +17 -1
- package/dist/commands/dev.d.ts +78 -7
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/generate_sdk.d.ts +3 -2
- package/dist/commands/init.d.ts +57 -14
- package/dist/commands/schema.d.ts +8 -0
- package/dist/commands/skills.d.ts +111 -5
- package/dist/commands/start.d.ts +29 -0
- package/dist/commands/telemetry.d.ts +10 -0
- package/dist/{daemon-DR9Tk0La.js → daemon-C8p32i-n.js} +5 -3
- package/dist/daemon-C8p32i-n.js.map +1 -0
- package/dist/dev-db/daemon.d.ts +10 -0
- package/dist/dev-db/prepare.d.ts +10 -0
- package/dist/dev-db/pull.d.ts +31 -2
- package/dist/dev-db/resolve.d.ts +2 -4
- package/dist/fold-static.d.ts +28 -3
- package/dist/index.es.js +13360 -9756
- package/dist/index.es.js.map +1 -1
- package/dist/manifest.d.ts +41 -1
- package/dist/package-manager-CXQevsE1.js +193 -0
- package/dist/package-manager-CXQevsE1.js.map +1 -0
- package/dist/{project-3WCbrrfW.js → project-DmaGLmH2.js} +4 -183
- package/dist/project-DmaGLmH2.js.map +1 -0
- package/dist/{pull-Bj0XnH5s.js → pull-Dywm5FWP.js} +41 -5
- package/dist/{pull-Bj0XnH5s.js.map → pull-Dywm5FWP.js.map} +1 -1
- package/dist/{resolve-Y56osuQH.js → resolve-BAeRUBhg.js} +2 -2
- package/dist/resolve-BAeRUBhg.js.map +1 -0
- package/dist/upgrade.d.ts +24 -3
- package/dist/utils/path-flags.d.ts +18 -0
- package/dist/utils/tool-stdio.d.ts +11 -0
- package/dist/version-DsgBmP22.js +58 -0
- package/dist/version-DsgBmP22.js.map +1 -0
- package/package.json +8 -8
- package/templates/eject/backend/src/index.ts +14 -1
- package/templates/overlays/baas/ai-instructions.md +1 -1
- package/templates/overlays/baas/config/storage.ts +5 -3
- package/templates/template/.cursorrules +1 -1
- package/templates/template/.env.example +10 -6
- package/templates/template/.github/copilot-instructions.md +1 -1
- package/templates/template/.mcp.json +2 -2
- package/templates/template/.windsurfrules +1 -1
- package/templates/template/AGENTS.md +1 -1
- package/templates/template/CLAUDE.md +1 -1
- package/templates/template/README.md +10 -11
- package/templates/template/ai-instructions.md +3 -3
- package/templates/template/backend/functions/hello.ts +8 -0
- package/templates/template/backend/package.json +1 -1
- package/templates/template/config/storage.ts +5 -3
- package/templates/template/docker-compose.yml +6 -6
- package/templates/template/gitignore +6 -1
- package/templates/template/package.json +4 -3
- package/templates/template/scripts/example.ts +4 -3
- package/dist/daemon-DR9Tk0La.js.map +0 -1
- package/dist/project-3WCbrrfW.js.map +0 -1
- package/dist/resolve-Y56osuQH.js.map +0 -1
|
@@ -42,7 +42,7 @@ function resolveDevDatabase(input = {}) {
|
|
|
42
42
|
url: fromEnvFile,
|
|
43
43
|
source: "env-file"
|
|
44
44
|
};
|
|
45
|
-
if (input.flagDocker
|
|
45
|
+
if (input.flagDocker) return {
|
|
46
46
|
kind: "docker",
|
|
47
47
|
source: "docker",
|
|
48
48
|
url: present(input.composeUrl)
|
|
@@ -71,4 +71,4 @@ function describeDevDatabase(database) {
|
|
|
71
71
|
//#endregion
|
|
72
72
|
export { resolveDevDatabase as n, resolve_exports as r, describeDevDatabase as t };
|
|
73
73
|
|
|
74
|
-
//# sourceMappingURL=resolve-
|
|
74
|
+
//# sourceMappingURL=resolve-BAeRUBhg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-BAeRUBhg.js","names":[],"sources":["../src/dev-db/resolve.ts"],"sourcesContent":["/**\n * Which database a command should talk to, decided in one place.\n *\n * Before this existed every command that needed Postgres read `DATABASE_URL`\n * for itself, which was fine while there was exactly one answer. Introducing a\n * managed database makes the question real: a project may have no\n * `DATABASE_URL` at all and still expect `rebase db push` to work, and a\n * project that *does* set one must never be quietly redirected somewhere else.\n *\n * So the rule is ordered and boring, and the order is the promise:\n *\n * 1. `--database-url <url>` — said on this command line, wins over everything\n * 2. `DATABASE_URL` in the shell environment\n * 3. the database branch this checkout is switched to\n * 4. `DATABASE_URL` in the project's `.env`\n * 5. `--docker`\n * 6. the managed PGlite database\n *\n * An explicit connection string always wins. That is the whole point of the\n * override: someone pointing Rebase at their own Postgres — a colleague's\n * staging box, a Neon branch, a container they manage — must get exactly that,\n * with no cleverness in between. The managed database is what fills the vacuum\n * when nobody has said anything, and it is the only case where the CLI picks.\n *\n * The branch at (3) is the one addition that is not an explicit connection\n * string, and it sits where it does deliberately. It has to outrank `.env` or\n * `rebase db branch switch` would silently do nothing on every project that\n * sets `DATABASE_URL` — which is every project not on the managed database.\n * It must not outrank (1) or (2), because a flag on this command line and a\n * variable in this shell are more immediate than a switch made yesterday.\n *\n * {@link resolveDevDatabase} is pure: inputs in, decision out, no filesystem\n * and no process. Reading `.env`, reading the branch pointer and starting a\n * daemon happen elsewhere, so the ordering above can be tested without any of\n * them.\n */\n\n/** Where the answer came from. Carried so diagnostics can name it. */\nexport type DevDatabaseSource =\n /** `--database-url` on the command line. */\n | \"flag\"\n /** `DATABASE_URL` in the shell environment. */\n | \"environment\"\n /** `DATABASE_URL` in the project's `.env`. */\n | \"env-file\"\n /** The branch this checkout is switched to, over the base connection. */\n | \"branch\"\n /** `--docker`. */\n | \"docker\"\n /** Nobody said anything, so the managed database fills in. */\n | \"managed\";\n\nexport type DevDatabase =\n | {\n kind: \"external\";\n /** The connection string, exactly as given. Never rewritten. */\n url: string;\n source: Extract<DevDatabaseSource, \"flag\" | \"environment\" | \"env-file\" | \"branch\">;\n /** The branch name, when this checkout is switched to one. */\n branch?: string;\n }\n | {\n kind: \"docker\";\n source: \"docker\";\n /**\n * The compose `db` service's connection string, derived by the caller.\n *\n * Null when the project has no compose file to derive one from, which\n * is a `--docker` that cannot be honoured rather than a fallback: the\n * caller says so instead of guessing at `localhost:5432`.\n */\n url: string | null;\n }\n | {\n kind: \"managed\";\n source: \"managed\";\n };\n\nexport interface ResolveDevDatabaseInput {\n /** `--database-url <url>`, if given. */\n flagUrl?: string | null;\n /** `--docker`, if given. */\n flagDocker?: boolean;\n /** The shell environment. Only `DATABASE_URL` is read. */\n env?: Record<string, string | undefined>;\n /** Parsed `.env` from the project root. Only `DATABASE_URL` is read. */\n envFile?: Record<string, string> | null;\n /**\n * The compose `db` service's connection string, when the project has one.\n *\n * Passed in rather than read here so this function stays pure. Only\n * consulted for the Docker case; an explicit `DATABASE_URL` still wins.\n */\n composeUrl?: string | null;\n /**\n * The branch this checkout is switched to, already resolved to a URL.\n *\n * Resolved by the caller rather than here so this stays pure: deriving it\n * needs the base connection string, which needs the `.env` this function is\n * handed rather than reads.\n */\n branch?: { name: string; url: string } | null;\n}\n\n/**\n * A value that is present but empty is treated as absent.\n *\n * `DATABASE_URL=` in a `.env` is what a developer writes when they mean \"not\n * this one\" — honouring it literally would hand an empty connection string to\n * libpq and produce an error about a missing host, which explains nothing.\n */\nfunction present(value: string | undefined | null): string | null {\n if (typeof value !== \"string\") return null;\n const trimmed = value.trim();\n\n return trimmed.length > 0 ? trimmed : null;\n}\n\nexport function resolveDevDatabase(input: ResolveDevDatabaseInput = {}): DevDatabase {\n const flagUrl = present(input.flagUrl);\n if (flagUrl) return { kind: \"external\", url: flagUrl, source: \"flag\" };\n\n const fromEnvironment = present(input.env?.DATABASE_URL);\n if (fromEnvironment) return { kind: \"external\", url: fromEnvironment, source: \"environment\" };\n\n // Above `.env`, below anything said explicitly — see the ordering note at\n // the top of this file.\n const fromBranch = present(input.branch?.url);\n if (fromBranch && input.branch) {\n return { kind: \"external\", url: fromBranch, source: \"branch\", branch: input.branch.name };\n }\n\n const fromEnvFile = present(input.envFile?.DATABASE_URL);\n if (fromEnvFile) return { kind: \"external\", url: fromEnvFile, source: \"env-file\" };\n\n // Only consulted once every explicit connection string is exhausted: asking\n // for Docker is a choice about *how to get* a database, not which one, so a\n // DATABASE_URL that already names one outranks it.\n if (input.flagDocker) {\n return { kind: \"docker\", source: \"docker\", url: present(input.composeUrl) };\n }\n\n return { kind: \"managed\", source: \"managed\" };\n}\n\n/** One line for the startup banner, naming both the database and why. */\nexport function describeDevDatabase(database: DevDatabase): string {\n switch (database.kind) {\n case \"external\":\n switch (database.source) {\n case \"flag\":\n return \"your database (--database-url)\";\n case \"environment\":\n return \"your database (DATABASE_URL in the environment)\";\n case \"env-file\":\n return \"your database (DATABASE_URL in .env)\";\n case \"branch\":\n return `branch \"${database.branch}\" (rebase db branch switch)`;\n }\n break;\n case \"docker\":\n return \"Postgres in Docker\";\n case \"managed\":\n return \"the managed development database (PGlite)\";\n }\n\n // Unreachable while the union is exhaustive; kept so a future variant fails\n // loudly in review rather than printing \"undefined\" to a user.\n throw new Error(`Unhandled dev database: ${JSON.stringify(database)}`);\n}\n"],"mappings":";;;;;;;;;;;;;AA+GA,SAAS,QAAQ,OAAiD;CAC9D,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,MAAM,UAAU,MAAM,KAAK;CAE3B,OAAO,QAAQ,SAAS,IAAI,UAAU;AAC1C;AAEA,SAAgB,mBAAmB,QAAiC,CAAC,GAAgB;CACjF,MAAM,UAAU,QAAQ,MAAM,OAAO;CACrC,IAAI,SAAS,OAAO;EAAE,MAAM;EAAY,KAAK;EAAS,QAAQ;CAAO;CAErE,MAAM,kBAAkB,QAAQ,MAAM,KAAK,YAAY;CACvD,IAAI,iBAAiB,OAAO;EAAE,MAAM;EAAY,KAAK;EAAiB,QAAQ;CAAc;CAI5F,MAAM,aAAa,QAAQ,MAAM,QAAQ,GAAG;CAC5C,IAAI,cAAc,MAAM,QACpB,OAAO;EAAE,MAAM;EAAY,KAAK;EAAY,QAAQ;EAAU,QAAQ,MAAM,OAAO;CAAK;CAG5F,MAAM,cAAc,QAAQ,MAAM,SAAS,YAAY;CACvD,IAAI,aAAa,OAAO;EAAE,MAAM;EAAY,KAAK;EAAa,QAAQ;CAAW;CAKjF,IAAI,MAAM,YACN,OAAO;EAAE,MAAM;EAAU,QAAQ;EAAU,KAAK,QAAQ,MAAM,UAAU;CAAE;CAG9E,OAAO;EAAE,MAAM;EAAW,QAAQ;CAAU;AAChD;;AAGA,SAAgB,oBAAoB,UAA+B;CAC/D,QAAQ,SAAS,MAAjB;EACI,KAAK;GACD,QAAQ,SAAS,QAAjB;IACI,KAAK,QACD,OAAO;IACX,KAAK,eACD,OAAO;IACX,KAAK,YACD,OAAO;IACX,KAAK,UACD,OAAO,WAAW,SAAS,OAAO;GAC1C;GACA;EACJ,KAAK,UACD,OAAO;EACX,KAAK,WACD,OAAO;CACf;CAIA,MAAM,IAAI,MAAM,2BAA2B,KAAK,UAAU,QAAQ,GAAG;AACzE"}
|
package/dist/upgrade.d.ts
CHANGED
|
@@ -25,6 +25,11 @@ export type SpecClass =
|
|
|
25
25
|
kind: "local";
|
|
26
26
|
protocol: "link:" | "file:" | "portal:";
|
|
27
27
|
}
|
|
28
|
+
/** A pnpm `catalog:` reference: the version is in pnpm-workspace.yaml's catalog, and moves there. */
|
|
29
|
+
| {
|
|
30
|
+
kind: "catalog";
|
|
31
|
+
catalog: string;
|
|
32
|
+
}
|
|
28
33
|
/** Anything else, with the reason it is left alone. */
|
|
29
34
|
| {
|
|
30
35
|
kind: "other";
|
|
@@ -53,13 +58,27 @@ export interface ProjectFiles {
|
|
|
53
58
|
packageJsons: string[];
|
|
54
59
|
workspaceYamls: string[];
|
|
55
60
|
}
|
|
56
|
-
/**
|
|
57
|
-
export
|
|
61
|
+
/** `git -C <cwd> …`, returning stdout. Throws when git is missing or refuses. */
|
|
62
|
+
export type GitRunner = (cwd: string, args: string[]) => string;
|
|
63
|
+
/**
|
|
64
|
+
* Every `package.json` and `pnpm-workspace.yaml` under the project root that
|
|
65
|
+
* belongs to the project.
|
|
66
|
+
*
|
|
67
|
+
* In a git repository that means what git lists: a gitignored build context,
|
|
68
|
+
* scratch copy or vendored package is not the project's, and rewriting it
|
|
69
|
+
* would change files nobody committed. The walk enters only directories that
|
|
70
|
+
* hold a listed file, so an ignored tree is not read at all. Outside a
|
|
71
|
+
* repository every directory is walked. {@link skipDirectory} applies either
|
|
72
|
+
* way.
|
|
73
|
+
*/
|
|
74
|
+
export declare function discoverProjectFiles(projectRoot: string, git?: GitRunner): ProjectFiles;
|
|
75
|
+
/** Where a catalog pin sits: `catalog`, or `catalogs.<name>` for a named one. */
|
|
76
|
+
export type CatalogField = "catalog" | `catalogs.${string}`;
|
|
58
77
|
export interface ChangedPin {
|
|
59
78
|
/** Relative to the project root, POSIX separators. */
|
|
60
79
|
file: string;
|
|
61
80
|
name: string;
|
|
62
|
-
field: PinField;
|
|
81
|
+
field: PinField | CatalogField;
|
|
63
82
|
from: string;
|
|
64
83
|
to: string;
|
|
65
84
|
}
|
|
@@ -97,6 +116,8 @@ export interface UpgradePlan {
|
|
|
97
116
|
absolute: string;
|
|
98
117
|
content: string;
|
|
99
118
|
}>;
|
|
119
|
+
/** Pins, overrides and catalog entries that were already on the target. */
|
|
120
|
+
unchanged: number;
|
|
100
121
|
}
|
|
101
122
|
export interface PlanOptions {
|
|
102
123
|
/** Remove `link:`/`file:` overrides of framework packages instead of reporting them. */
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** The rule, as every help page and error states it. */
|
|
2
|
+
export declare const COLLECTIONS_PATH_RULE = "relative paths are resolved from where you run the command";
|
|
3
|
+
/** The `--collections` line of a help page. */
|
|
4
|
+
export declare const COLLECTIONS_FLAG_HELP = "Collections directory (default: config/collections); relative paths are resolved from where you run the command";
|
|
5
|
+
/**
|
|
6
|
+
* The refusal for a `--collections` path that does not exist, or `null`.
|
|
7
|
+
*
|
|
8
|
+
* Checked by the CLI, in the reader's terms, before the driver is spawned: the
|
|
9
|
+
* driver's own check runs in `backend/` and can only describe the path it was
|
|
10
|
+
* handed. A generator pointed at a directory that is not there writes an empty
|
|
11
|
+
* schema, and a push of an empty schema drops every table — so nothing runs.
|
|
12
|
+
*
|
|
13
|
+
* Scripts written for the old rule (`--collections ../config/collections`,
|
|
14
|
+
* run from the root) land here, and the message says exactly what to change.
|
|
15
|
+
*/
|
|
16
|
+
export declare function missingCollectionsPath(args: readonly string[], cwd: string, backendDir: string): string[] | null;
|
|
17
|
+
/** Print {@link missingCollectionsPath}'s refusal and exit 1, or return. */
|
|
18
|
+
export declare function refuseMissingCollectionsPath(args: readonly string[], cwd: string, backendDir: string): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The stdio a build tool the CLI runs in the foreground gets: a static app's
|
|
3
|
+
* build command, `tsc`, `tar`.
|
|
4
|
+
*
|
|
5
|
+
* Inherited, so its output streams as it happens. With `quietStdout` its stdout
|
|
6
|
+
* goes to stderr instead, for a command whose own stdout carries a result:
|
|
7
|
+
* `rebase cloud deploy` in JSON mode — every piped run — owes stdout exactly one
|
|
8
|
+
* JSON value, and a `vite v6 building…` line in front of it is a result no
|
|
9
|
+
* parser can read. The tool's output still reaches the person watching.
|
|
10
|
+
*/
|
|
11
|
+
export declare function toolStdio(quietStdout: boolean | undefined): "inherit" | ["ignore", 2, "inherit"];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
//#region src/utils/version.ts
|
|
5
|
+
/**
|
|
6
|
+
* This CLI's own version, and the User-Agent built from it.
|
|
7
|
+
*
|
|
8
|
+
* Four call sites used to answer "what version am I?" and each answered it
|
|
9
|
+
* differently. `cli.ts` walked one directory up from `__dirname`. `init.ts`
|
|
10
|
+
* walked up looking for a folder literally named `cli`. `bundle.ts` had
|
|
11
|
+
* `resolveCliVersion`, which walked up at most five levels for a manifest whose
|
|
12
|
+
* `name` matched — the only one of the three that was actually correct, and the
|
|
13
|
+
* one the other two did not know existed. Every HTTP request to the control
|
|
14
|
+
* plane answered it not at all, which is the expensive gap: a control plane
|
|
15
|
+
* cannot refuse a CLI that is too old for its wire format if no request ever
|
|
16
|
+
* says which CLI is calling.
|
|
17
|
+
*
|
|
18
|
+
* One answer now, and it is `bundle.ts`'s: walk up for the manifest that names
|
|
19
|
+
* this package, rather than counting directories or matching a folder name.
|
|
20
|
+
* `dist/` is one level down in a published install and two in a source
|
|
21
|
+
* checkout, and a folder called `cli` is not guaranteed to be ours. Two
|
|
22
|
+
* differences from that original — `fileURLToPath` instead of `new
|
|
23
|
+
* URL().pathname`, which is what makes it survive a path containing a space,
|
|
24
|
+
* and no five-level ceiling.
|
|
25
|
+
*/
|
|
26
|
+
function readVersion() {
|
|
27
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
const root = path.parse(dir).root;
|
|
29
|
+
while (dir && dir !== root) {
|
|
30
|
+
const manifest = path.join(dir, "package.json");
|
|
31
|
+
if (fs.existsSync(manifest)) try {
|
|
32
|
+
const pkg = JSON.parse(fs.readFileSync(manifest, "utf-8"));
|
|
33
|
+
if (pkg.name === "@rebasepro/cli" && typeof pkg.version === "string") return pkg.version;
|
|
34
|
+
} catch {}
|
|
35
|
+
dir = path.dirname(dir);
|
|
36
|
+
}
|
|
37
|
+
return "unknown";
|
|
38
|
+
}
|
|
39
|
+
var cached;
|
|
40
|
+
/** The CLI's version, or `"unknown"` when it cannot be read. Memoized. */
|
|
41
|
+
function cliVersion() {
|
|
42
|
+
if (cached === void 0) cached = readVersion();
|
|
43
|
+
return cached;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* `rebase-cli/0.17.3` — sent on every control-plane request.
|
|
47
|
+
*
|
|
48
|
+
* The control plane needs it to answer `CLI_TOO_OLD` with a minimum version
|
|
49
|
+
* instead of failing somewhere further in with a shape error. A client that
|
|
50
|
+
* does not identify itself can only ever be refused generically.
|
|
51
|
+
*/
|
|
52
|
+
function cliUserAgent() {
|
|
53
|
+
return `rebase-cli/${cliVersion()}`;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { cliVersion as n, cliUserAgent as t };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=version-DsgBmP22.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-DsgBmP22.js","names":[],"sources":["../src/utils/version.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\n\n/**\n * This CLI's own version, and the User-Agent built from it.\n *\n * Four call sites used to answer \"what version am I?\" and each answered it\n * differently. `cli.ts` walked one directory up from `__dirname`. `init.ts`\n * walked up looking for a folder literally named `cli`. `bundle.ts` had\n * `resolveCliVersion`, which walked up at most five levels for a manifest whose\n * `name` matched — the only one of the three that was actually correct, and the\n * one the other two did not know existed. Every HTTP request to the control\n * plane answered it not at all, which is the expensive gap: a control plane\n * cannot refuse a CLI that is too old for its wire format if no request ever\n * says which CLI is calling.\n *\n * One answer now, and it is `bundle.ts`'s: walk up for the manifest that names\n * this package, rather than counting directories or matching a folder name.\n * `dist/` is one level down in a published install and two in a source\n * checkout, and a folder called `cli` is not guaranteed to be ours. Two\n * differences from that original — `fileURLToPath` instead of `new\n * URL().pathname`, which is what makes it survive a path containing a space,\n * and no five-level ceiling.\n */\nfunction readVersion(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n const root = path.parse(dir).root;\n while (dir && dir !== root) {\n const manifest = path.join(dir, \"package.json\");\n if (fs.existsSync(manifest)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(manifest, \"utf-8\"));\n if (pkg.name === \"@rebasepro/cli\" && typeof pkg.version === \"string\") return pkg.version;\n } catch {\n // A malformed manifest on the way up is not ours to complain\n // about; keep walking.\n }\n }\n dir = path.dirname(dir);\n }\n return \"unknown\";\n}\n\nlet cached: string | undefined;\n\n/** The CLI's version, or `\"unknown\"` when it cannot be read. Memoized. */\nexport function cliVersion(): string {\n if (cached === undefined) cached = readVersion();\n return cached;\n}\n\n/**\n * `rebase-cli/0.17.3` — sent on every control-plane request.\n *\n * The control plane needs it to answer `CLI_TOO_OLD` with a minimum version\n * instead of failing somewhere further in with a shape error. A client that\n * does not identify itself can only ever be refused generically.\n */\nexport function cliUserAgent(): string {\n return `rebase-cli/${cliVersion()}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAS,cAAsB;CAC3B,IAAI,MAAM,KAAK,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;CACrD,MAAM,OAAO,KAAK,MAAM,GAAG,CAAC,CAAC;CAC7B,OAAO,OAAO,QAAQ,MAAM;EACxB,MAAM,WAAW,KAAK,KAAK,KAAK,cAAc;EAC9C,IAAI,GAAG,WAAW,QAAQ,GACtB,IAAI;GACA,MAAM,MAAM,KAAK,MAAM,GAAG,aAAa,UAAU,OAAO,CAAC;GACzD,IAAI,IAAI,SAAS,oBAAoB,OAAO,IAAI,YAAY,UAAU,OAAO,IAAI;EACrF,QAAQ,CAGR;EAEJ,MAAM,KAAK,QAAQ,GAAG;CAC1B;CACA,OAAO;AACX;AAEA,IAAI;;AAGJ,SAAgB,aAAqB;CACjC,IAAI,WAAW,KAAA,GAAW,SAAS,YAAY;CAC/C,OAAO;AACX;;;;;;;;AASA,SAAgB,eAAuB;CACnC,OAAO,cAAc,WAAW;AACpC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Developer tools for Rebase projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"inquirer": "14.0.2",
|
|
44
44
|
"jiti": "^2.7.0",
|
|
45
45
|
"pg": "^8.22.0",
|
|
46
|
-
"@rebasepro/agent-skills": "0.
|
|
47
|
-
"@rebasepro/codegen": "0.
|
|
48
|
-
"@rebasepro/server
|
|
49
|
-
"@rebasepro/types": "0.
|
|
50
|
-
"@rebasepro/server": "0.
|
|
51
|
-
"@rebasepro/client": "0.
|
|
46
|
+
"@rebasepro/agent-skills": "0.24.0",
|
|
47
|
+
"@rebasepro/codegen": "0.24.0",
|
|
48
|
+
"@rebasepro/server": "0.24.0",
|
|
49
|
+
"@rebasepro/types": "0.24.0",
|
|
50
|
+
"@rebasepro/server-postgres": "0.24.0",
|
|
51
|
+
"@rebasepro/client": "0.24.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/node": "^26.1.2",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@types/ws": "^8.18.1",
|
|
57
57
|
"typescript": "^6.0.3",
|
|
58
58
|
"vite": "^8.1.5",
|
|
59
|
-
"vitest": "4.1.
|
|
59
|
+
"vitest": "4.1.11",
|
|
60
60
|
"ws": "^8.21.1"
|
|
61
61
|
},
|
|
62
62
|
"files": [
|
|
@@ -81,7 +81,20 @@ app.use("/*", cors({
|
|
|
81
81
|
if (!origin) return "*";
|
|
82
82
|
return isLocalhostOrigin(origin) ? origin : null;
|
|
83
83
|
},
|
|
84
|
-
credentials: true
|
|
84
|
+
credentials: true,
|
|
85
|
+
// A frontend on another origin reads only the response headers named here.
|
|
86
|
+
// Without `ETag` the SDK's `etagOf(row)` is always undefined there, and an
|
|
87
|
+
// `ifMatch` write silently goes out unconditional; without `Retry-After`
|
|
88
|
+
// and `X-Request-ID` a 429 or an error loses what it reports.
|
|
89
|
+
exposeHeaders: [
|
|
90
|
+
"ETag",
|
|
91
|
+
"Retry-After",
|
|
92
|
+
"X-Request-ID",
|
|
93
|
+
"X-RateLimit-Limit",
|
|
94
|
+
"X-RateLimit-Remaining",
|
|
95
|
+
"X-RateLimit-Reset",
|
|
96
|
+
"Preference-Applied"
|
|
97
|
+
]
|
|
85
98
|
}));
|
|
86
99
|
|
|
87
100
|
app.use("/*", secureHeaders());
|
|
@@ -12,7 +12,7 @@ This is a **headless** Rebase project: a REST API, auth, storage and realtime ov
|
|
|
12
12
|
| `rebase db url` | Print the connection string in use — it pipes straight into `psql` |
|
|
13
13
|
| `pnpm db:migrate` | Apply the migration files in `backend/drizzle/migrations`. Needs your own PostgreSQL, not the managed development database |
|
|
14
14
|
| `pnpm schema:introspect` | Existing tables → collection definitions in `config/collections/`. That directory ends headless mode; see rule 1 |
|
|
15
|
-
| `pnpm generate:sdk` | Regenerate the typed client from `config/collections/` — so in a headless project it has nothing to read until you introspect |
|
|
15
|
+
| `pnpm generate:sdk` | Regenerate the typed client from `config/collections/` — so in a headless project it has nothing to read until you introspect. Once there are collections, `pnpm dev` does this on start and on every save; the script is for CI and for when `pnpm dev` is not running |
|
|
16
16
|
| `pnpm build` then `pnpm start` | Build the deployable bundle, then run it |
|
|
17
17
|
| `pnpm skills:install` | Install the Rebase skills for your assistant |
|
|
18
18
|
| `pnpm example` | Run `scripts/example.ts` against the running backend — the SDK, end to end |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { StorageAuthorize } from "@rebasepro/types";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Who may do what to files in storage.
|
|
@@ -39,7 +39,7 @@ import { isPublicStoragePath, type StorageAuthorize } from "@rebasepro/types";
|
|
|
39
39
|
*
|
|
40
40
|
* ```ts
|
|
41
41
|
* export const storageAuthorize: StorageAuthorize = async ({ key, user, operation, data }) => {
|
|
42
|
-
* if (operation === "read" &&
|
|
42
|
+
* if (operation === "read" && key.startsWith("public/")) return true;
|
|
43
43
|
* if (!user) return false;
|
|
44
44
|
* const row = (await data?.collection("attachments").find({
|
|
45
45
|
* where: { storage_key: ["==", key] }, limit: 1
|
|
@@ -55,7 +55,9 @@ import { isPublicStoragePath, type StorageAuthorize } from "@rebasepro/types";
|
|
|
55
55
|
*/
|
|
56
56
|
export const storageAuthorize: StorageAuthorize = ({ key, user, operation }) => {
|
|
57
57
|
// The `public/` prefix is the framework's convention for world-readable objects.
|
|
58
|
-
|
|
58
|
+
// `key` is the canonical key the server serves, so a prefix test is exact:
|
|
59
|
+
// `default/public/x` is a private object in a folder named `default`.
|
|
60
|
+
if (operation === "read" && key.startsWith("public/")) {
|
|
59
61
|
return true;
|
|
60
62
|
}
|
|
61
63
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# Rebase AI Rules
|
|
2
2
|
Please refer to and follow the instructions defined in [ai-instructions.md](./ai-instructions.md).
|
|
3
|
-
|
|
3
|
+
The Rebase skills for this assistant live in `.cursor/rules/`. If they are not there yet, install them, with the Rebase MCP server: `rebase skills install --agent cursor --mcp`.
|
|
@@ -51,10 +51,12 @@ DATABASE_URL=postgresql://rebase_app:changeme@localhost:5432/rebase?options=-c%2
|
|
|
51
51
|
# DB_POOL_CONNECT_TIMEOUT=10000
|
|
52
52
|
|
|
53
53
|
# ── Server ────────────────────────────────────────────────────────────────────
|
|
54
|
-
# Used by `rebase start
|
|
54
|
+
# Used by `rebase start`. `rebase dev` IGNORES this and binds a
|
|
55
55
|
# port derived from the project path, so several projects can run at once —
|
|
56
56
|
# trust the URL `rebase dev` prints, or pin one with `rebase dev --port 3001`.
|
|
57
57
|
PORT=3001
|
|
58
|
+
# `rebase start` runs in this mode too, and warns that it is not a production
|
|
59
|
+
# server: set NODE_ENV=production (here or in the shell) for one.
|
|
58
60
|
NODE_ENV=development
|
|
59
61
|
# Allow connecting to localhost / 127.0.0.1 in production mode (for local testing of prod builds)
|
|
60
62
|
# ALLOW_LOCALHOST_IN_PRODUCTION=false
|
|
@@ -222,7 +224,7 @@ VITE_API_URL=
|
|
|
222
224
|
# BACKUP_DESTINATION=./backups # local path, or s3://bucket/prefix / gs://bucket/prefix
|
|
223
225
|
# BACKUP_RETENTION_DAYS=14 # delete backups older than N days (unset/0 ⇒ keep all)
|
|
224
226
|
# BACKUP_KEEP_MINIMUM=3 # always retain at least N most-recent backups
|
|
225
|
-
# PG_DUMP_PATH= # override pg_dump binary (
|
|
227
|
+
# PG_DUMP_PATH= # override pg_dump binary (server's major version or newer)
|
|
226
228
|
# PG_RESTORE_PATH= # override pg_restore binary
|
|
227
229
|
|
|
228
230
|
# ── Admin Service Key (optional) ──────────────────────────────────────────────
|
|
@@ -250,9 +252,11 @@ VITE_API_URL=
|
|
|
250
252
|
# unset. To upgrade, change this and restart — your bundle is untouched.
|
|
251
253
|
REBASE_VERSION=latest
|
|
252
254
|
|
|
253
|
-
#
|
|
254
|
-
# ensure create missing tables and
|
|
255
|
-
#
|
|
256
|
-
#
|
|
255
|
+
# Whether boot provisions the schema your collections describe.
|
|
256
|
+
# ensure create missing tables, columns and enum types, additively (the default)
|
|
257
|
+
# none leave the schema alone
|
|
258
|
+
# Any other value refuses to boot. Boot never runs migration files: the ones
|
|
259
|
+
# `rebase db generate` writes to `backend/drizzle/migrations` are applied with
|
|
260
|
+
# `rebase db migrate`.
|
|
257
261
|
# REBASE_MIGRATE_ON_BOOT=ensure
|
|
258
262
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# Rebase AI Rules
|
|
2
2
|
Please refer to and follow the instructions defined in [ai-instructions.md](../ai-instructions.md).
|
|
3
|
-
|
|
3
|
+
The Rebase skills for this assistant live in `.github/instructions/`. If they are not there yet, install them, with the Rebase MCP server: `rebase skills install --agent copilot --mcp`.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# Rebase AI Rules
|
|
2
2
|
Please refer to and follow the instructions defined in [ai-instructions.md](./ai-instructions.md).
|
|
3
|
-
|
|
3
|
+
The Rebase skills for this assistant live in `.windsurf/rules/`. If they are not there yet, install them, with the Rebase MCP server: `rebase skills install --agent windsurf --mcp`.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# Rebase AI Rules
|
|
2
2
|
Please refer to and follow the instructions defined in [ai-instructions.md](ai-instructions.md).
|
|
3
|
-
|
|
3
|
+
The Rebase skills for this assistant live in `.agents/skills/`. If they are not there yet, install them, with the Rebase MCP server: `rebase skills install --agent codex --mcp`.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# Rebase AI Rules
|
|
2
2
|
Please refer to and follow the instructions defined in [ai-instructions.md](./ai-instructions.md).
|
|
3
|
-
|
|
3
|
+
The Rebase skills for this assistant live in `.claude/skills/`. If they are not there yet, install them, with the Rebase MCP server: `rebase skills install --agent claude --mcp`.
|
|
@@ -33,9 +33,9 @@ pnpm install # or: npm install
|
|
|
33
33
|
pnpm dev # or: npm run dev
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
That is the whole first run. `rebase dev` generates the Drizzle schema
|
|
37
|
-
`config/collections`, starts the database, creates a table for
|
|
38
|
-
declared there, and serves the API and the admin panel.
|
|
36
|
+
That is the whole first run. `rebase dev` generates the Drizzle schema and the
|
|
37
|
+
SDK types from `config/collections`, starts the database, creates a table for
|
|
38
|
+
every collection declared there, and serves the API and the admin panel.
|
|
39
39
|
|
|
40
40
|
`rebase dev` prints the two URLs it actually bound. The first account you
|
|
41
41
|
register becomes the admin. `REBASE_ADMIN_EMAIL` and `REBASE_ADMIN_PASSWORD` in
|
|
@@ -45,8 +45,8 @@ is shut — see [Self-hosting](#self-hosting-with-docker).
|
|
|
45
45
|
Ports are **derived from this project's path**, not fixed at 3001/5173, so
|
|
46
46
|
several Rebase projects can run at once without colliding. That is why the URL
|
|
47
47
|
in your terminal is the one to trust — and why the `PORT` and `VITE_API_URL` in
|
|
48
|
-
`.env` are ignored by `rebase dev` (they apply to `rebase start`, the
|
|
49
|
-
|
|
48
|
+
`.env` are ignored by `rebase dev` (they apply to `rebase start`, which runs the
|
|
49
|
+
built bundle). Pin a port with `rebase dev --port 3001` if you need a stable one.
|
|
50
50
|
|
|
51
51
|
### Variant: your own PostgreSQL
|
|
52
52
|
|
|
@@ -61,10 +61,9 @@ database to compare against, and PGlite serves exactly one:
|
|
|
61
61
|
pnpm run db:push
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
Boot already creates missing tables and columns
|
|
65
|
-
what it deliberately leaves alone:
|
|
66
|
-
|
|
67
|
-
a removed field.
|
|
64
|
+
Boot already creates missing tables and columns, and their row-level security,
|
|
65
|
+
additively, so `db push` is for what it deliberately leaves alone: any change
|
|
66
|
+
that is not purely additive — a renamed column, a narrowed type, a removed field.
|
|
68
67
|
|
|
69
68
|
The `docker-compose.yml` in this project runs PostgreSQL in a container if you
|
|
70
69
|
would rather not install one:
|
|
@@ -163,8 +162,8 @@ compose database is a database of your own, so step 0 is the same one line.
|
|
|
163
162
|
pnpm run build # or: npm run build
|
|
164
163
|
|
|
165
164
|
# 2. Start the database. Boot creates the tables from your collections;
|
|
166
|
-
# `db:push` is for what it leaves alone —
|
|
167
|
-
#
|
|
165
|
+
# `db:push` is for what it leaves alone — any change that is not purely
|
|
166
|
+
# additive.
|
|
168
167
|
docker compose up -d db
|
|
169
168
|
pnpm run db:push # or: npm run db:push
|
|
170
169
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
| `pnpm schema:generate` then `pnpm db:push` | The same loop with `pnpm dev` not running, plus the changes boot leaves alone: collections → Drizzle schema → development database |
|
|
11
11
|
| `pnpm db:generate` then `pnpm db:migrate` | The production path — write the migration file, then apply it |
|
|
12
12
|
| `pnpm schema:introspect` | The other direction: existing tables → collection definitions |
|
|
13
|
-
| `pnpm generate:sdk` | Regenerate the typed client from the collections |
|
|
13
|
+
| `pnpm generate:sdk` | Regenerate the typed client in `generated/sdk/` from the collections. `pnpm dev` already does this on start and on every save; the script is for CI and for when `pnpm dev` is not running |
|
|
14
14
|
| `pnpm build` then `pnpm start` | Build the deployable bundle, then run it |
|
|
15
15
|
| `pnpm skills:install` | Install the Rebase skills for your assistant |
|
|
16
16
|
| `pnpm example` | Run `scripts/example.ts` against the running backend — the SDK, end to end |
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
|
|
30
30
|
## Core rules
|
|
31
31
|
|
|
32
|
-
1. **Schema-as-code**: define and edit collections in `config/collections/` with `defineCollection` from `@rebasepro/cms-types`,
|
|
33
|
-
2. **Applying a collection change**: while `pnpm dev` is running, saving a file in `config/collections/` is the whole step — it regenerates `backend/src/schema.generated.ts
|
|
32
|
+
1. **Schema-as-code**: define and edit collections in `config/collections/` with `defineCollection` from `@rebasepro/cms-types`, one collection per file, default-exported. Every file in that directory is loaded — by the backend, the admin panel and the SDK generator — whether or not `index.ts` lists it: the barrel is a sort order for the admin navigation (and holds `defaultSecurityRules`), not a registry. To remove a collection, delete its file. Never hand-edit generated schemas or Postgres tables.
|
|
33
|
+
2. **Applying a collection change**: while `pnpm dev` is running, saving a file in `config/collections/` is the whole step — it regenerates `backend/src/schema.generated.ts` and the SDK types in `generated/sdk/`, restarts the backend, and boot creates the tables and columns that are missing. With `pnpm dev` stopped, that is `pnpm schema:generate` and `pnpm generate:sdk`. `pnpm db:push` is only for what boot deliberately leaves alone — a renamed column, a narrowed type, a removed field — and it needs your own PostgreSQL, not the managed development database. In production the pair is `pnpm db:generate` then `pnpm db:migrate`.
|
|
34
34
|
3. **Use the SDK**: server-side that is `rebase.dataAsAdmin.<slug>` for work done as the service identity, or `getDriver(c)` inside a function when the read should run as the caller. The server client has no plain `data` accessor — it is omitted precisely so that the choice of identity is written down.
|
|
35
35
|
4. **Guard every custom route**: routes in `backend/functions/` are mounted **without** an auth requirement — webhook receivers need that — so each one is public until you guard it. Import `requireAuth` / `requireAdmin` from `@rebasepro/server/functions` and pass them in the route's own middleware slot (`app.post("/", requireAuth, handler)`), not via `app.use()`, which only covers routes declared below it. Reading `getUser(c)` is not a guard: an anonymous caller gets `undefined` and the handler still runs. See `backend/functions/hello.ts` for all three tiers.
|
|
36
36
|
5. **In `backend/functions/`, always import from `@rebasepro/server/functions`** — never from `@rebasepro/server`. Both work today; the subpath is the portable one, and it also gives you the typed context accessors (`getUser`, `getDriver`, `requireDriver`) instead of casting `c.get("user")`. The package root is for a server entrypoint, not for route handlers.
|
|
@@ -47,6 +47,14 @@ import {
|
|
|
47
47
|
* slot over `app.use("/*", requireAuth)`: `use()` only covers routes declared
|
|
48
48
|
* *below* it, so a route appended later above it is silently unprotected.
|
|
49
49
|
*
|
|
50
|
+
* An API key is a caller too. It reaches this file only if it holds the
|
|
51
|
+
* `functions:invoke` scope (or `functions:invoke:hello`), it passes
|
|
52
|
+
* `requireAuth`, and a service key created with `--roles admin` passes
|
|
53
|
+
* `requireAdmin`. To let a key do one thing here and not another, declare a
|
|
54
|
+
* scope under `auth.scopes` on the users collection and add
|
|
55
|
+
* `requireScope("reports:read")` to that route — every signed-in person holds
|
|
56
|
+
* every app scope, so it narrows keys, not people.
|
|
57
|
+
*
|
|
50
58
|
* `rebase.dataAsAdmin` gives you admin-level access to your data: it runs as
|
|
51
59
|
* `{ uid: "service", roles: ["admin"] }`, which is **admin-scoped, not an RLS
|
|
52
60
|
* bypass** — your policies are still evaluated, just against that identity. So
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "Rebase backend with PostgreSQL",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"build": "rebase schema generate
|
|
7
|
+
"build": "rebase schema generate && tsc && rebase normalize-imports dist"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@ariga/atlas": "^1.2.3",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { StorageAuthorize } from "@rebasepro/types";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Who may do what to files in storage.
|
|
@@ -37,7 +37,7 @@ import { isPublicStoragePath, type StorageAuthorize } from "@rebasepro/types";
|
|
|
37
37
|
*
|
|
38
38
|
* ```ts
|
|
39
39
|
* export const storageAuthorize: StorageAuthorize = async ({ key, user, operation, data }) => {
|
|
40
|
-
* if (operation === "read" &&
|
|
40
|
+
* if (operation === "read" && key.startsWith("public/")) return true;
|
|
41
41
|
* if (!user) return false;
|
|
42
42
|
*
|
|
43
43
|
* // Writes land under the caller's own prefix.
|
|
@@ -66,7 +66,9 @@ import { isPublicStoragePath, type StorageAuthorize } from "@rebasepro/types";
|
|
|
66
66
|
export const storageAuthorize: StorageAuthorize = ({ key, user, operation }) => {
|
|
67
67
|
// The `public/` prefix is the framework's convention for world-readable
|
|
68
68
|
// objects, and it is what signed download URLs for public assets rely on.
|
|
69
|
-
|
|
69
|
+
// `key` is the canonical key the server serves, so a prefix test is exact:
|
|
70
|
+
// `default/public/x` is a private object in a folder named `default`.
|
|
71
|
+
if (operation === "read" && key.startsWith("public/")) {
|
|
70
72
|
return true;
|
|
71
73
|
}
|
|
72
74
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
# docker compose up # boot creates the tables it is missing
|
|
16
16
|
#
|
|
17
17
|
# `rebase db push` is the separate step for what boot deliberately leaves
|
|
18
|
-
# alone:
|
|
18
|
+
# alone: any change that is not purely additive.
|
|
19
19
|
#
|
|
20
20
|
# One container then serves the API at /api and the admin at / — same origin, so
|
|
21
21
|
# there is no CORS to configure between them and no second web server.
|
|
@@ -132,12 +132,12 @@ services:
|
|
|
132
132
|
DISABLE_SELF_REGISTRATION: ${DISABLE_SELF_REGISTRATION:-true}
|
|
133
133
|
|
|
134
134
|
# `ensure` (the default) creates missing tables and columns at boot —
|
|
135
|
-
# your collections' as well as auth's —
|
|
136
|
-
# dropped, narrowed or rewritten,
|
|
137
|
-
# side effect of a container restart.
|
|
135
|
+
# your collections' as well as auth's — with their row-level security,
|
|
136
|
+
# and is additive only: nothing is dropped, narrowed or rewritten,
|
|
137
|
+
# because that must never happen as a side effect of a container restart.
|
|
138
138
|
#
|
|
139
|
-
# `rebase db push` is still what applies the rest:
|
|
140
|
-
#
|
|
139
|
+
# `rebase db push` is still what applies the rest: any change that is not
|
|
140
|
+
# purely additive.
|
|
141
141
|
# Set this to `none` to take a deployment out of provisioning entirely.
|
|
142
142
|
REBASE_MIGRATE_ON_BOOT: ${REBASE_MIGRATE_ON_BOOT:-ensure}
|
|
143
143
|
|
|
@@ -11,8 +11,13 @@ build/
|
|
|
11
11
|
!.env.example
|
|
12
12
|
|
|
13
13
|
# IDE
|
|
14
|
+
#
|
|
15
|
+
# `.vscode/*` rather than `.vscode/`: git cannot re-include a file inside an
|
|
16
|
+
# ignored directory, and `.vscode/mcp.json` is the Rebase MCP server
|
|
17
|
+
# `rebase init --agent copilot` registers for the whole team.
|
|
14
18
|
.idea/
|
|
15
|
-
.vscode
|
|
19
|
+
.vscode/*
|
|
20
|
+
!.vscode/mcp.json
|
|
16
21
|
*.swp
|
|
17
22
|
*.swo
|
|
18
23
|
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
"dev": "rebase dev",
|
|
14
14
|
"build": "rebase build",
|
|
15
15
|
"start": "rebase start",
|
|
16
|
-
"db:generate": "rebase db generate
|
|
16
|
+
"db:generate": "rebase db generate",
|
|
17
17
|
"db:migrate": "rebase db migrate",
|
|
18
18
|
"schema:introspect": "rebase schema introspect",
|
|
19
|
-
"db:push": "rebase db push
|
|
20
|
-
"schema:generate": "rebase schema generate
|
|
19
|
+
"db:push": "rebase db push",
|
|
20
|
+
"schema:generate": "rebase schema generate",
|
|
21
21
|
"generate:sdk": "rebase generate-sdk",
|
|
22
22
|
"skills:install": "rebase skills install",
|
|
23
23
|
"example": "tsx scripts/example.ts",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@rebasepro/cli": "workspace:*",
|
|
28
|
+
"@rebasepro/mcp": "workspace:*",
|
|
28
29
|
"@rebasepro/types": "workspace:*",
|
|
29
30
|
"tsx": "^4.20.6",
|
|
30
31
|
"typescript": "^6.0.3"
|
|
@@ -23,9 +23,10 @@ import fs from "node:fs";
|
|
|
23
23
|
import path from "node:path";
|
|
24
24
|
import * as dotenv from "dotenv";
|
|
25
25
|
import { createRebaseClient } from "@rebasepro/client";
|
|
26
|
-
// Optional: fully typed collections. `rebase
|
|
27
|
-
// ./generated/sdk — the dictionary is what
|
|
28
|
-
// property name, so a client built without it
|
|
26
|
+
// Optional: fully typed collections. `rebase dev` writes these under
|
|
27
|
+
// ./generated/sdk (`rebase generate-sdk` outside it) — the dictionary is what
|
|
28
|
+
// maps a hyphenated slug to the property name, so a client built without it
|
|
29
|
+
// 404s at runtime.
|
|
29
30
|
// import { collectionsDictionary, type Database } from "../generated/sdk/database.types";
|
|
30
31
|
|
|
31
32
|
// Load .env from project root (same file the backend uses)
|