@rebasepro/cli 0.23.0 → 0.24.1-canary.g19596ef
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 +4 -1
- package/dist/agent-setup-B31F00DC.js +324 -0
- package/dist/agent-setup-B31F00DC.js.map +1 -0
- package/dist/api-keys-Bl1I9q7M.js +525 -0
- package/dist/api-keys-Bl1I9q7M.js.map +1 -0
- package/dist/apps-CNgQJjg5.js +340 -0
- package/dist/apps-CNgQJjg5.js.map +1 -0
- package/dist/args-BnmsEXvu.js +109 -0
- package/dist/args-BnmsEXvu.js.map +1 -0
- package/dist/atlas-dev-database-D_LP_Woq.js +62 -0
- package/dist/atlas-dev-database-D_LP_Woq.js.map +1 -0
- package/dist/auth-aySHEF45.js +414 -0
- package/dist/auth-aySHEF45.js.map +1 -0
- package/dist/branch-pointer-DvSHBjjz.js +2 -0
- package/dist/build-DIHWIqO4.js +336 -0
- package/dist/build-DIHWIqO4.js.map +1 -0
- package/dist/bundle-CqURVN-K.js +1621 -0
- package/dist/bundle-CqURVN-K.js.map +1 -0
- package/dist/bundle.d.ts +12 -3
- package/dist/cli.d.ts +23 -2
- package/dist/cloud-DjByQlkW.js +9667 -0
- package/dist/cloud-DjByQlkW.js.map +1 -0
- package/dist/collection-drift-BKj_BoMq.js +106 -0
- package/dist/collection-drift-BKj_BoMq.js.map +1 -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 +86 -23
- package/dist/commands/apps.d.ts +17 -0
- package/dist/commands/auth.d.ts +7 -0
- package/dist/commands/build.d.ts +5 -1
- package/dist/commands/cloud/auth.d.ts +4 -3
- package/dist/commands/cloud/bundle-deploy.d.ts +45 -0
- package/dist/commands/cloud/context.d.ts +44 -5
- package/dist/commands/cloud/cron.d.ts +53 -0
- package/dist/commands/cloud/debug.d.ts +134 -0
- package/dist/commands/cloud/index.d.ts +89 -12
- package/dist/commands/cloud/token-capabilities.d.ts +76 -0
- package/dist/commands/cloud/tokens.d.ts +23 -0
- package/dist/commands/console.d.ts +12 -0
- package/dist/commands/db.d.ts +79 -25
- package/dist/commands/dev.d.ts +181 -13
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/generate_sdk.d.ts +29 -2
- package/dist/commands/init.d.ts +115 -14
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/skills.d.ts +126 -7
- package/dist/commands/start.d.ts +44 -0
- package/dist/commands/storage.d.ts +46 -0
- package/dist/commands/upgrade.d.ts +1 -0
- package/dist/consent-ClRHmcxf.js +76 -0
- package/dist/consent-ClRHmcxf.js.map +1 -0
- package/dist/console-D6SJf8k_.js +102 -0
- package/dist/console-D6SJf8k_.js.map +1 -0
- package/dist/context-BqhRydBg.js +1234 -0
- package/dist/context-BqhRydBg.js.map +1 -0
- package/dist/{daemon-entry-LTFKtpHy.js → daemon-entry-Da-D3rmH.js} +3 -4
- package/dist/daemon-entry-Da-D3rmH.js.map +1 -0
- package/dist/daemon-pzsQwDHa.js +2 -0
- package/dist/db-B7RuNuaQ.js +1312 -0
- package/dist/db-B7RuNuaQ.js.map +1 -0
- package/dist/derive-Dl0z2OWi.js +484 -0
- package/dist/derive-Dl0z2OWi.js.map +1 -0
- package/dist/dev-CYr_WXan.js +1599 -0
- package/dist/dev-CYr_WXan.js.map +1 -0
- package/dist/dev-db/atlas-dev-database.d.ts +32 -0
- package/dist/dev-db/daemon-entry.d.ts +13 -0
- package/dist/dev-db/daemon.d.ts +10 -0
- package/dist/dev-db/last-dev-database.d.ts +41 -0
- package/dist/dev-db/prepare.d.ts +29 -3
- package/dist/dev-db/pull.d.ts +90 -5
- package/dist/dev-db/resolve.d.ts +26 -2
- package/dist/dev-preflight-B-LYyBf1.js +2 -0
- package/dist/dev-server-DG8Tt-uf.js +96 -0
- package/dist/dev-server-DG8Tt-uf.js.map +1 -0
- package/dist/doctor-BP8cZ-7F.js +771 -0
- package/dist/doctor-BP8cZ-7F.js.map +1 -0
- package/dist/eject-DizdoecV.js +335 -0
- package/dist/eject-DizdoecV.js.map +1 -0
- package/dist/fold-static-BC9CYicw.js +201 -0
- package/dist/fold-static-BC9CYicw.js.map +1 -0
- package/dist/fold-static.d.ts +26 -3
- package/dist/function-portability-BIvlvR9q.js +265 -0
- package/dist/function-portability-BIvlvR9q.js.map +1 -0
- package/dist/generate_sdk-BPqdJc3Q.js +489 -0
- package/dist/generate_sdk-BPqdJc3Q.js.map +1 -0
- package/dist/index.es.js +199 -22095
- package/dist/index.es.js.map +1 -1
- package/dist/init-Utstvh2Q.js +1149 -0
- package/dist/init-Utstvh2Q.js.map +1 -0
- package/dist/last-dev-database-B58g89uA.js +2 -0
- package/dist/manifest-DRp0UVTj.js +880 -0
- package/dist/manifest-DRp0UVTj.js.map +1 -0
- package/dist/manifest.d.ts +56 -4
- package/dist/normalize-imports-X0Tgze9y.js +107 -0
- package/dist/normalize-imports-X0Tgze9y.js.map +1 -0
- package/dist/package-manager-DSEOwTqM.js +193 -0
- package/dist/package-manager-DSEOwTqM.js.map +1 -0
- package/dist/path-flags-BFgG9V6y.js +91 -0
- package/dist/path-flags-BFgG9V6y.js.map +1 -0
- package/dist/precompress.d.ts +17 -0
- package/dist/prepare-CDN6lSpz.js +1236 -0
- package/dist/prepare-CDN6lSpz.js.map +1 -0
- package/dist/{project-3WCbrrfW.js → project-Wp2zoyeN.js} +34 -184
- package/dist/project-Wp2zoyeN.js.map +1 -0
- package/dist/pull-CrGYMEsy.js +458 -0
- package/dist/pull-CrGYMEsy.js.map +1 -0
- package/dist/resolve-B2O-wKKk.js +2 -0
- package/dist/resources-FD7AfZx8.js +183 -0
- package/dist/resources-FD7AfZx8.js.map +1 -0
- package/dist/schema-DMdr431S.js +125 -0
- package/dist/schema-DMdr431S.js.map +1 -0
- package/dist/skills-DTFibT1m.js +642 -0
- package/dist/skills-DTFibT1m.js.map +1 -0
- package/dist/start-DEa-hOBh.js +267 -0
- package/dist/start-DEa-hOBh.js.map +1 -0
- package/dist/{state-C59Elrnt.js → state-Do7ZJYkF.js} +49 -4
- package/dist/state-Do7ZJYkF.js.map +1 -0
- package/dist/status-DxnJTekv.js +352 -0
- package/dist/status-DxnJTekv.js.map +1 -0
- package/dist/storage-DyVq-f_F.js +303 -0
- package/dist/storage-DyVq-f_F.js.map +1 -0
- package/dist/telemetry/identity.d.ts +10 -1
- package/dist/telemetry-C8Uq8phb.js +129 -0
- package/dist/telemetry-C8Uq8phb.js.map +1 -0
- package/dist/telemetry-EMFRVRQi.js +351 -0
- package/dist/telemetry-EMFRVRQi.js.map +1 -0
- package/dist/unknown-command-DNwDcX3w.js +98 -0
- package/dist/unknown-command-DNwDcX3w.js.map +1 -0
- package/dist/upgrade-CtZtRkTE.js +1332 -0
- package/dist/upgrade-CtZtRkTE.js.map +1 -0
- package/dist/upgrade.d.ts +38 -5
- package/dist/utils/dev-preflight.d.ts +47 -5
- package/dist/utils/dev-server.d.ts +30 -0
- package/dist/utils/path-flags.d.ts +31 -0
- package/dist/utils/project.d.ts +16 -0
- package/dist/utils/temp-archive.d.ts +9 -0
- package/dist/version-Buyyo1ut.js +58 -0
- package/dist/version-Buyyo1ut.js.map +1 -0
- package/package.json +7 -7
- package/templates/eject/Dockerfile +4 -2
- package/templates/eject/backend/src/env.ts +1 -1
- package/templates/eject/backend/src/index.ts +42 -4
- package/templates/eject/docker-compose.custom.yml +8 -4
- package/templates/generated-schemas/blank.ts +40 -0
- package/templates/generated-schemas/blog.ts +127 -0
- package/templates/generated-schemas/ecommerce.ts +93 -0
- package/templates/overlays/baas/ai-instructions.md +1 -1
- package/templates/overlays/baas/config/package.json +1 -0
- package/templates/overlays/baas/config/storage.ts +5 -3
- package/templates/overlays/baas/package.json +1 -0
- package/templates/template/.cursorrules +1 -1
- package/templates/template/.env.example +20 -10
- 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 +21 -15
- package/templates/template/ai-instructions.md +5 -4
- package/templates/template/backend/functions/hello.ts +8 -0
- package/templates/template/backend/package.json +1 -1
- package/templates/template/config/resources.ts +7 -6
- package/templates/template/config/storage.ts +5 -3
- package/templates/template/docker-compose.yml +15 -9
- package/templates/template/frontend/vite.config.ts +13 -3
- package/templates/template/gitignore +6 -1
- package/templates/template/package.json +5 -3
- package/templates/template/scripts/example.ts +6 -4
- package/templates/template/tsconfig.json +25 -0
- package/dist/branch-pointer-dBiClJ0p.js +0 -111
- package/dist/branch-pointer-dBiClJ0p.js.map +0 -1
- package/dist/constraints-DKGbNfUW.js +0 -48
- package/dist/constraints-DKGbNfUW.js.map +0 -1
- package/dist/daemon-DR9Tk0La.js +0 -355
- package/dist/daemon-DR9Tk0La.js.map +0 -1
- package/dist/daemon-entry-LTFKtpHy.js.map +0 -1
- package/dist/dev-preflight-CNLl4rdo.js +0 -367
- package/dist/dev-preflight-CNLl4rdo.js.map +0 -1
- package/dist/project-3WCbrrfW.js.map +0 -1
- package/dist/pull-Dywm5FWP.js +0 -232
- package/dist/pull-Dywm5FWP.js.map +0 -1
- package/dist/resolve-BAeRUBhg.js +0 -74
- package/dist/resolve-BAeRUBhg.js.map +0 -1
- package/dist/state-C59Elrnt.js.map +0 -1
- package/templates/template/backend/src/schema.generated.ts +0 -13
|
@@ -36,6 +36,22 @@ import usersCollection from "../../config/collections/users";
|
|
|
36
36
|
const __filename = fileURLToPath(import.meta.url);
|
|
37
37
|
const __dirname = path.dirname(__filename);
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* The project root: the nearest directory holding `rebase.json`.
|
|
41
|
+
*
|
|
42
|
+
* Walked up to rather than counted, because this file runs from two depths —
|
|
43
|
+
* `backend/src` under `rebase dev`, `backend/dist/backend/src` compiled — and
|
|
44
|
+
* a fixed `../..` from the compiled file is `backend/dist`, where local uploads
|
|
45
|
+
* then landed and the next build wiped them.
|
|
46
|
+
*/
|
|
47
|
+
function findProjectRoot(from: string): string {
|
|
48
|
+
for (let dir = from; ; dir = path.dirname(dir)) {
|
|
49
|
+
if (fs.existsSync(path.join(dir, "rebase.json"))) return dir;
|
|
50
|
+
if (path.dirname(dir) === dir) return path.resolve(from, "../..");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const projectRoot = findProjectRoot(__dirname);
|
|
54
|
+
|
|
39
55
|
// Which databases and buckets this project has, read from the declarations in
|
|
40
56
|
// `config/resources.ts`. One declaration site, so this process, the platform
|
|
41
57
|
// and the frontend all read the same list. A project that declares none gets
|
|
@@ -81,7 +97,24 @@ app.use("/*", cors({
|
|
|
81
97
|
if (!origin) return "*";
|
|
82
98
|
return isLocalhostOrigin(origin) ? origin : null;
|
|
83
99
|
},
|
|
84
|
-
credentials: true
|
|
100
|
+
credentials: true,
|
|
101
|
+
// A frontend on another origin reads only the response headers named here.
|
|
102
|
+
// Without `ETag` the SDK's `etagOf(row)` is always undefined there, and an
|
|
103
|
+
// `ifMatch` write silently goes out unconditional; without `Retry-After`
|
|
104
|
+
// and `X-Request-ID` a 429 or an error loses what it reports.
|
|
105
|
+
exposeHeaders: [
|
|
106
|
+
"ETag",
|
|
107
|
+
"Retry-After",
|
|
108
|
+
"X-Request-ID",
|
|
109
|
+
"X-RateLimit-Limit",
|
|
110
|
+
"X-RateLimit-Remaining",
|
|
111
|
+
"X-RateLimit-Reset",
|
|
112
|
+
"Preference-Applied",
|
|
113
|
+
// A resumable upload: where it lives, how far it got, what was stored.
|
|
114
|
+
"Location",
|
|
115
|
+
"Upload-Offset",
|
|
116
|
+
"Rebase-Upload-Result"
|
|
117
|
+
]
|
|
85
118
|
}));
|
|
86
119
|
|
|
87
120
|
app.use("/*", secureHeaders());
|
|
@@ -106,7 +139,11 @@ const resolvedDataSources = resolveDataSources(process.env, dataSources);
|
|
|
106
139
|
async function startServer() {
|
|
107
140
|
const jwtSecret = env.JWT_SECRET;
|
|
108
141
|
const PORT = env.PORT;
|
|
109
|
-
|
|
142
|
+
// 64 KB of request line plus headers, as the Rebase runtime takes, not
|
|
143
|
+
// Node's 16 KB: a vector search's embedding travels in `?vector=`, and
|
|
144
|
+
// 768 dimensions of it are already 17 KB of URL. (The SDK sends a vector
|
|
145
|
+
// search in a POST body; this is for a URL built by hand.)
|
|
146
|
+
const server = createServer({ maxHeaderSize: 64 * 1024 }, getRequestListener(app.fetch));
|
|
110
147
|
|
|
111
148
|
// `backend/crons` holds the scheduled jobs — nightly backups among them.
|
|
112
149
|
// Passed only when the directory exists, because a configured `cronsDir`
|
|
@@ -204,7 +241,9 @@ pass: env.SMTP_PASS! }
|
|
|
204
241
|
storage: resolveStorageSources(
|
|
205
242
|
process.env,
|
|
206
243
|
storageSources,
|
|
207
|
-
|
|
244
|
+
// `<project>/uploads`, from source and compiled alike — where
|
|
245
|
+
// `rebase dev` keeps them too. `STORAGE_PATH` overrides it.
|
|
246
|
+
path.join(projectRoot, "uploads")
|
|
208
247
|
),
|
|
209
248
|
// Storage is not under row-level security, so this hook IS its access
|
|
210
249
|
// model — the server refuses to boot in production without one, because
|
|
@@ -278,7 +317,6 @@ pass: env.SMTP_PASS! }
|
|
|
278
317
|
|
|
279
318
|
if (!isProduction) {
|
|
280
319
|
// Dev mode: retry the next port if the current one is in use
|
|
281
|
-
const projectRoot = path.resolve(__dirname, "../..");
|
|
282
320
|
const actualPort = await listenWithPortRetry(server, PORT, { portFileDir: projectRoot, serviceKey: env.REBASE_SERVICE_KEY });
|
|
283
321
|
|
|
284
322
|
// Clean up port file on exit
|
|
@@ -63,17 +63,21 @@ services:
|
|
|
63
63
|
# served from.
|
|
64
64
|
# {{/frontend}}
|
|
65
65
|
CORS_ORIGINS: ${CORS_ORIGINS:?set CORS_ORIGINS to the origin you browse to}
|
|
66
|
-
# A durable named volume, which is the case this flag acknowledges.
|
|
67
|
-
STORAGE_PATH
|
|
66
|
+
# A durable named volume, which is the case this flag acknowledges. It is
|
|
67
|
+
# mounted at /storage, one level above STORAGE_PATH, because every bucket
|
|
68
|
+
# declared in config/resources.ts gets a directory beside this one —
|
|
69
|
+
# bucket("media") is /storage/uploads__media — and all of them belong on
|
|
70
|
+
# the volume. The Dockerfile creates /storage for the `rebase` user.
|
|
71
|
+
STORAGE_PATH: /storage/uploads
|
|
68
72
|
FORCE_LOCAL_STORAGE: "true"
|
|
69
73
|
depends_on:
|
|
70
74
|
db:
|
|
71
75
|
condition: service_healthy
|
|
72
76
|
volumes:
|
|
73
|
-
-
|
|
77
|
+
- storage:/storage
|
|
74
78
|
|
|
75
79
|
volumes:
|
|
76
80
|
postgres_data:
|
|
77
81
|
driver: local
|
|
78
|
-
|
|
82
|
+
storage:
|
|
79
83
|
driver: local
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// This file is auto-generated by the Rebase Drizzle generator. Do not edit manually.
|
|
2
|
+
|
|
3
|
+
import { boolean, jsonb, pgPolicy, pgSchema, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
4
|
+
import { relations as drizzleRelations, sql } from 'drizzle-orm';
|
|
5
|
+
|
|
6
|
+
export const rebaseSchema = pgSchema("rebase");
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export const users = rebaseSchema.table("users", {
|
|
10
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
11
|
+
email: text("email").unique().notNull(),
|
|
12
|
+
displayName: text("display_name"),
|
|
13
|
+
photoURL: text("photo_url"),
|
|
14
|
+
roles: text("roles").array(),
|
|
15
|
+
passwordHash: text("password_hash"),
|
|
16
|
+
emailVerified: boolean("email_verified").default(sql`FALSE`),
|
|
17
|
+
emailVerificationToken: text("email_verification_token"),
|
|
18
|
+
emailVerificationSentAt: timestamp("email_verification_sent_at", { withTimezone: true, mode: 'string' }),
|
|
19
|
+
metadata: jsonb("metadata").default(sql`'{}'::jsonb`),
|
|
20
|
+
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`now()`),
|
|
21
|
+
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).default(sql`now()`)
|
|
22
|
+
}, (table) => ([
|
|
23
|
+
pgPolicy("users_select_5f32f06", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
24
|
+
pgPolicy("users_insert_3561e70_0", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
25
|
+
pgPolicy("users_update_3561e70_1", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])`, withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
26
|
+
pgPolicy("users_delete_3561e70_2", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
27
|
+
pgPolicy("users_default_admin_read", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
28
|
+
pgPolicy("users_default_admin_write_insert", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
29
|
+
pgPolicy("users_default_admin_write_update", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
30
|
+
pgPolicy("users_default_admin_write_delete", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
31
|
+
pgPolicy("users_default_self_read", { as: "permissive", for: "select", to: ["public"], using: sql`(id)::text = (SELECT rebase.uid())` }),
|
|
32
|
+
pgPolicy("users_require_admin_write_insert", { as: "restrictive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
33
|
+
pgPolicy("users_require_admin_write_update", { as: "restrictive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
34
|
+
pgPolicy("users_require_admin_write_delete", { as: "restrictive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
35
|
+
])).enableRLS();
|
|
36
|
+
|
|
37
|
+
export const tables = { users };
|
|
38
|
+
export const enums = { };
|
|
39
|
+
export const relations = { };
|
|
40
|
+
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// This file is auto-generated by the Rebase Drizzle generator. Do not edit manually.
|
|
2
|
+
|
|
3
|
+
import { type AnyPgColumn, boolean, index, integer, jsonb, pgEnum, pgPolicy, pgSchema, pgTable, primaryKey, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
4
|
+
import { relations as drizzleRelations, sql } from 'drizzle-orm';
|
|
5
|
+
|
|
6
|
+
export const rebaseSchema = pgSchema("rebase");
|
|
7
|
+
|
|
8
|
+
export const postsStatus = pgEnum("posts_status", ["draft", "review", "published"]);
|
|
9
|
+
|
|
10
|
+
export const authors = pgTable("authors", {
|
|
11
|
+
id: integer("id").generatedByDefaultAsIdentity().primaryKey(),
|
|
12
|
+
name: text("name").notNull(),
|
|
13
|
+
email: text("email").notNull(),
|
|
14
|
+
picture: text("picture")
|
|
15
|
+
}, (table) => ([
|
|
16
|
+
pgPolicy("authors_select_841c287", { as: "permissive", for: "select", to: ["public"], using: sql`true` }),
|
|
17
|
+
pgPolicy("authors_insert_3561e70_0", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
18
|
+
pgPolicy("authors_update_3561e70_1", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])`, withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
19
|
+
pgPolicy("authors_delete_3561e70_2", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
20
|
+
pgPolicy("authors_default_admin_read", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
21
|
+
pgPolicy("authors_default_admin_write_insert", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
22
|
+
pgPolicy("authors_default_admin_write_update", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
23
|
+
pgPolicy("authors_default_admin_write_delete", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
24
|
+
])).enableRLS();
|
|
25
|
+
|
|
26
|
+
export const posts = pgTable("posts", {
|
|
27
|
+
id: integer("id").generatedByDefaultAsIdentity().primaryKey(),
|
|
28
|
+
title: text("title").notNull(),
|
|
29
|
+
content: text("content"),
|
|
30
|
+
status: postsStatus("status"),
|
|
31
|
+
authorId: integer("author_id").references((): AnyPgColumn => authors.id, { onDelete: "set null" })
|
|
32
|
+
}, (table) => ([
|
|
33
|
+
index("posts_author_id_ix_00ad191").on(table.authorId.asc().nullsLast()),
|
|
34
|
+
pgPolicy("posts_select_841c287", { as: "permissive", for: "select", to: ["public"], using: sql`true` }),
|
|
35
|
+
pgPolicy("posts_insert_3561e70_0", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
36
|
+
pgPolicy("posts_update_3561e70_1", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])`, withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
37
|
+
pgPolicy("posts_delete_3561e70_2", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
38
|
+
pgPolicy("posts_default_admin_read", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
39
|
+
pgPolicy("posts_default_admin_write_insert", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
40
|
+
pgPolicy("posts_default_admin_write_update", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
41
|
+
pgPolicy("posts_default_admin_write_delete", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
42
|
+
])).enableRLS();
|
|
43
|
+
|
|
44
|
+
export const postsTags = pgTable("posts_tags", {
|
|
45
|
+
post_id: integer("post_id").notNull().references((): AnyPgColumn => posts.id, { onDelete: "cascade" }),
|
|
46
|
+
tag_id: integer("tag_id").notNull().references((): AnyPgColumn => tags.id, { onDelete: "cascade" }),
|
|
47
|
+
}, (table) => ([
|
|
48
|
+
primaryKey({ columns: [table.post_id, table.tag_id] }),
|
|
49
|
+
index("posts_tags_tag_id_ix_d4456f1").on(table.tag_id.asc().nullsLast()),
|
|
50
|
+
pgPolicy("posts_tags_default_admin_read", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
51
|
+
pgPolicy("posts_tags_default_admin_write_insert", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
52
|
+
pgPolicy("posts_tags_default_admin_write_update", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
53
|
+
pgPolicy("posts_tags_default_admin_write_delete", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
54
|
+
pgPolicy("posts_tags_default_edge_read", { as: "permissive", for: "select", to: ["public"], using: sql`(EXISTS (SELECT 1 FROM "public"."posts" "_ex0" WHERE "_ex0".id = "public"."posts_tags".post_id)) AND (EXISTS (SELECT 1 FROM "public"."tags" "_ex1" WHERE "_ex1".id = "public"."posts_tags".tag_id))` }),
|
|
55
|
+
pgPolicy("posts_tags_default_edge_write_insert", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`EXISTS (SELECT 1 FROM "public"."posts" "_ex0" WHERE ("_ex0".id = "public"."posts_tags".post_id) AND ((SELECT (string_to_array(rebase.roles(), ',') && ARRAY['admin']))))` }),
|
|
56
|
+
pgPolicy("posts_tags_default_edge_write_update", { as: "permissive", for: "update", to: ["public"], using: sql`EXISTS (SELECT 1 FROM "public"."posts" "_ex0" WHERE ("_ex0".id = "public"."posts_tags".post_id) AND ((SELECT (string_to_array(rebase.roles(), ',') && ARRAY['admin']))))`, withCheck: sql`EXISTS (SELECT 1 FROM "public"."posts" "_ex0" WHERE ("_ex0".id = "public"."posts_tags".post_id) AND ((SELECT (string_to_array(rebase.roles(), ',') && ARRAY['admin']))))` }),
|
|
57
|
+
pgPolicy("posts_tags_default_edge_write_delete", { as: "permissive", for: "delete", to: ["public"], using: sql`EXISTS (SELECT 1 FROM "public"."posts" "_ex0" WHERE ("_ex0".id = "public"."posts_tags".post_id) AND ((SELECT (string_to_array(rebase.roles(), ',') && ARRAY['admin']))))` }),
|
|
58
|
+
])).enableRLS();
|
|
59
|
+
|
|
60
|
+
export const tags = pgTable("tags", {
|
|
61
|
+
id: integer("id").generatedByDefaultAsIdentity().primaryKey(),
|
|
62
|
+
name: text("name").notNull()
|
|
63
|
+
}, (table) => ([
|
|
64
|
+
pgPolicy("tags_select_841c287", { as: "permissive", for: "select", to: ["public"], using: sql`true` }),
|
|
65
|
+
pgPolicy("tags_insert_3561e70_0", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
66
|
+
pgPolicy("tags_update_3561e70_1", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])`, withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
67
|
+
pgPolicy("tags_delete_3561e70_2", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
68
|
+
pgPolicy("tags_default_admin_read", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
69
|
+
pgPolicy("tags_default_admin_write_insert", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
70
|
+
pgPolicy("tags_default_admin_write_update", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
71
|
+
pgPolicy("tags_default_admin_write_delete", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
72
|
+
])).enableRLS();
|
|
73
|
+
|
|
74
|
+
export const users = rebaseSchema.table("users", {
|
|
75
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
76
|
+
email: text("email").unique().notNull(),
|
|
77
|
+
displayName: text("display_name"),
|
|
78
|
+
photoURL: text("photo_url"),
|
|
79
|
+
roles: text("roles").array(),
|
|
80
|
+
passwordHash: text("password_hash"),
|
|
81
|
+
emailVerified: boolean("email_verified").default(sql`FALSE`),
|
|
82
|
+
emailVerificationToken: text("email_verification_token"),
|
|
83
|
+
emailVerificationSentAt: timestamp("email_verification_sent_at", { withTimezone: true, mode: 'string' }),
|
|
84
|
+
metadata: jsonb("metadata").default(sql`'{}'::jsonb`),
|
|
85
|
+
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`now()`),
|
|
86
|
+
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).default(sql`now()`)
|
|
87
|
+
}, (table) => ([
|
|
88
|
+
pgPolicy("users_select_5f32f06", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
89
|
+
pgPolicy("users_insert_3561e70_0", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
90
|
+
pgPolicy("users_update_3561e70_1", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])`, withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
91
|
+
pgPolicy("users_delete_3561e70_2", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
92
|
+
pgPolicy("users_default_admin_read", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
93
|
+
pgPolicy("users_default_admin_write_insert", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
94
|
+
pgPolicy("users_default_admin_write_update", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
95
|
+
pgPolicy("users_default_admin_write_delete", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
96
|
+
pgPolicy("users_default_self_read", { as: "permissive", for: "select", to: ["public"], using: sql`(id)::text = (SELECT rebase.uid())` }),
|
|
97
|
+
pgPolicy("users_require_admin_write_insert", { as: "restrictive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
98
|
+
pgPolicy("users_require_admin_write_update", { as: "restrictive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
99
|
+
pgPolicy("users_require_admin_write_delete", { as: "restrictive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
100
|
+
])).enableRLS();
|
|
101
|
+
|
|
102
|
+
export const postsRelations = drizzleRelations(posts, ({ one, many }) => ({
|
|
103
|
+
"author": one(authors, {
|
|
104
|
+
fields: [posts.authorId],
|
|
105
|
+
references: [authors.id],
|
|
106
|
+
relationName: "posts_authorId"
|
|
107
|
+
}),
|
|
108
|
+
"tags": many(postsTags, { relationName: "tags" })
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
export const postsTagsRelations = drizzleRelations(postsTags, ({ one, many }) => ({
|
|
112
|
+
"post_id": one(posts, {
|
|
113
|
+
fields: [postsTags.post_id],
|
|
114
|
+
references: [posts.id],
|
|
115
|
+
relationName: "tags"
|
|
116
|
+
}),
|
|
117
|
+
"tag_id": one(tags, {
|
|
118
|
+
fields: [postsTags.tag_id],
|
|
119
|
+
references: [tags.id],
|
|
120
|
+
relationName: "posts_tags_tag_id"
|
|
121
|
+
})
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
export const tables = { authors, posts, postsTags, tags, users };
|
|
125
|
+
export const enums = { postsStatus };
|
|
126
|
+
export const relations = { postsRelations, postsTagsRelations };
|
|
127
|
+
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// This file is auto-generated by the Rebase Drizzle generator. Do not edit manually.
|
|
2
|
+
|
|
3
|
+
import { type AnyPgColumn, boolean, index, integer, jsonb, numeric, pgEnum, pgPolicy, pgSchema, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
4
|
+
import { relations as drizzleRelations, sql } from 'drizzle-orm';
|
|
5
|
+
|
|
6
|
+
export const rebaseSchema = pgSchema("rebase");
|
|
7
|
+
|
|
8
|
+
export const ordersStatus = pgEnum("orders_status", ["pending", "processing", "shipped", "delivered", "cancelled"]);
|
|
9
|
+
export const productsStatus = pgEnum("products_status", ["draft", "active", "archived"]);
|
|
10
|
+
|
|
11
|
+
export const categories = pgTable("categories", {
|
|
12
|
+
id: integer("id").generatedByDefaultAsIdentity().primaryKey(),
|
|
13
|
+
name: text("name").notNull(),
|
|
14
|
+
slug: text("slug").notNull(),
|
|
15
|
+
description: text("description"),
|
|
16
|
+
icon: text("icon")
|
|
17
|
+
}, (table) => ([
|
|
18
|
+
pgPolicy("categories_default_admin_read", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
19
|
+
pgPolicy("categories_default_admin_write_insert", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
20
|
+
pgPolicy("categories_default_admin_write_update", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
21
|
+
pgPolicy("categories_default_admin_write_delete", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
22
|
+
])).enableRLS();
|
|
23
|
+
|
|
24
|
+
export const orders = pgTable("orders", {
|
|
25
|
+
id: integer("id").generatedByDefaultAsIdentity().primaryKey(),
|
|
26
|
+
customerEmail: text("customer_email").notNull(),
|
|
27
|
+
status: ordersStatus("status"),
|
|
28
|
+
total: numeric("total").notNull(),
|
|
29
|
+
notes: text("notes"),
|
|
30
|
+
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`now()`)
|
|
31
|
+
}, (table) => ([
|
|
32
|
+
pgPolicy("orders_default_admin_read", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
33
|
+
pgPolicy("orders_default_admin_write_insert", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
34
|
+
pgPolicy("orders_default_admin_write_update", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
35
|
+
pgPolicy("orders_default_admin_write_delete", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
36
|
+
])).enableRLS();
|
|
37
|
+
|
|
38
|
+
export const products = pgTable("products", {
|
|
39
|
+
id: integer("id").generatedByDefaultAsIdentity().primaryKey(),
|
|
40
|
+
name: text("name").notNull(),
|
|
41
|
+
description: text("description"),
|
|
42
|
+
price: numeric("price").notNull(),
|
|
43
|
+
image: text("image"),
|
|
44
|
+
status: productsStatus("status"),
|
|
45
|
+
categoryId: integer("category_id").references((): AnyPgColumn => categories.id, { onDelete: "set null" })
|
|
46
|
+
}, (table) => ([
|
|
47
|
+
index("products_category_id_ix_066548f").on(table.categoryId.asc().nullsLast()),
|
|
48
|
+
pgPolicy("products_default_admin_read", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
49
|
+
pgPolicy("products_default_admin_write_insert", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
50
|
+
pgPolicy("products_default_admin_write_update", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
51
|
+
pgPolicy("products_default_admin_write_delete", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
52
|
+
])).enableRLS();
|
|
53
|
+
|
|
54
|
+
export const users = rebaseSchema.table("users", {
|
|
55
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
56
|
+
email: text("email").unique().notNull(),
|
|
57
|
+
displayName: text("display_name"),
|
|
58
|
+
photoURL: text("photo_url"),
|
|
59
|
+
roles: text("roles").array(),
|
|
60
|
+
passwordHash: text("password_hash"),
|
|
61
|
+
emailVerified: boolean("email_verified").default(sql`FALSE`),
|
|
62
|
+
emailVerificationToken: text("email_verification_token"),
|
|
63
|
+
emailVerificationSentAt: timestamp("email_verification_sent_at", { withTimezone: true, mode: 'string' }),
|
|
64
|
+
metadata: jsonb("metadata").default(sql`'{}'::jsonb`),
|
|
65
|
+
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`now()`),
|
|
66
|
+
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).default(sql`now()`)
|
|
67
|
+
}, (table) => ([
|
|
68
|
+
pgPolicy("users_select_5f32f06", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
69
|
+
pgPolicy("users_insert_3561e70_0", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
70
|
+
pgPolicy("users_update_3561e70_1", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])`, withCheck: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
71
|
+
pgPolicy("users_delete_3561e70_2", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT string_to_array(rebase.roles(), ',') && ARRAY['admin'])` }),
|
|
72
|
+
pgPolicy("users_default_admin_read", { as: "permissive", for: "select", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
73
|
+
pgPolicy("users_default_admin_write_insert", { as: "permissive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
74
|
+
pgPolicy("users_default_admin_write_update", { as: "permissive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
75
|
+
pgPolicy("users_default_admin_write_delete", { as: "permissive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
76
|
+
pgPolicy("users_default_self_read", { as: "permissive", for: "select", to: ["public"], using: sql`(id)::text = (SELECT rebase.uid())` }),
|
|
77
|
+
pgPolicy("users_require_admin_write_insert", { as: "restrictive", for: "insert", to: ["public"], withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
78
|
+
pgPolicy("users_require_admin_write_update", { as: "restrictive", for: "update", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))`, withCheck: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
79
|
+
pgPolicy("users_require_admin_write_delete", { as: "restrictive", for: "delete", to: ["public"], using: sql`(SELECT (rebase.uid() IS NULL) OR (string_to_array(rebase.roles(), ',') && ARRAY['admin']))` }),
|
|
80
|
+
])).enableRLS();
|
|
81
|
+
|
|
82
|
+
export const productsRelations = drizzleRelations(products, ({ one, many }) => ({
|
|
83
|
+
"category": one(categories, {
|
|
84
|
+
fields: [products.categoryId],
|
|
85
|
+
references: [categories.id],
|
|
86
|
+
relationName: "products_categoryId"
|
|
87
|
+
})
|
|
88
|
+
}));
|
|
89
|
+
|
|
90
|
+
export const tables = { categories, orders, products, users };
|
|
91
|
+
export const enums = { ordersStatus, productsStatus };
|
|
92
|
+
export const relations = { productsRelations };
|
|
93
|
+
|
|
@@ -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
|
|
@@ -159,14 +161,20 @@ VITE_API_URL=
|
|
|
159
161
|
# In production, "local" means NO file storage: uploads answer
|
|
160
162
|
# 501 STORAGE_NOT_CONFIGURED instead of landing on a container filesystem that
|
|
161
163
|
# is erased on the next redeploy. Configure a bucket below to switch it on, or
|
|
162
|
-
# set FORCE_LOCAL_STORAGE=true if a durable volume really
|
|
163
|
-
#
|
|
164
|
+
# set FORCE_LOCAL_STORAGE=true if a durable volume really holds STORAGE_PATH
|
|
165
|
+
# (the generated docker-compose.yml does exactly that). Mount it on the parent
|
|
166
|
+
# of STORAGE_PATH: a named local bucket keeps its files beside it, in
|
|
167
|
+
# <STORAGE_PATH>__<key>, and those belong on the volume too.
|
|
164
168
|
#
|
|
165
169
|
# STORAGE_TYPE=local
|
|
166
170
|
|
|
167
171
|
# --- Local filesystem (default — great for dev and single-server deployments) --
|
|
168
|
-
#
|
|
169
|
-
#
|
|
172
|
+
# Unset, files land in <project>/uploads, under `rebase dev` and in the server
|
|
173
|
+
# `rebase eject` writes alike. A relative path is read from the directory the
|
|
174
|
+
# server runs in: the project root under `rebase dev`, backend/ after
|
|
175
|
+
# `rebase eject`. So ./uploads names two places, and an absolute path one.
|
|
176
|
+
# STORAGE_PATH=/absolute/path/to/uploads
|
|
177
|
+
# FORCE_LOCAL_STORAGE=true # Only with a durable volume holding STORAGE_PATH
|
|
170
178
|
|
|
171
179
|
# --- S3-compatible (AWS S3, Cloudflare R2, MinIO, Hetzner Object Storage, Backblaze B2) ---
|
|
172
180
|
# STORAGE_TYPE=s3
|
|
@@ -222,7 +230,7 @@ VITE_API_URL=
|
|
|
222
230
|
# BACKUP_DESTINATION=./backups # local path, or s3://bucket/prefix / gs://bucket/prefix
|
|
223
231
|
# BACKUP_RETENTION_DAYS=14 # delete backups older than N days (unset/0 ⇒ keep all)
|
|
224
232
|
# BACKUP_KEEP_MINIMUM=3 # always retain at least N most-recent backups
|
|
225
|
-
# PG_DUMP_PATH= # override pg_dump binary (
|
|
233
|
+
# PG_DUMP_PATH= # override pg_dump binary (server's major version or newer)
|
|
226
234
|
# PG_RESTORE_PATH= # override pg_restore binary
|
|
227
235
|
|
|
228
236
|
# ── Admin Service Key (optional) ──────────────────────────────────────────────
|
|
@@ -250,9 +258,11 @@ VITE_API_URL=
|
|
|
250
258
|
# unset. To upgrade, change this and restart — your bundle is untouched.
|
|
251
259
|
REBASE_VERSION=latest
|
|
252
260
|
|
|
253
|
-
#
|
|
254
|
-
# ensure create missing tables and
|
|
255
|
-
#
|
|
256
|
-
#
|
|
261
|
+
# Whether boot provisions the schema your collections describe.
|
|
262
|
+
# ensure create missing tables, columns and enum types, additively (the default)
|
|
263
|
+
# none leave the schema alone
|
|
264
|
+
# Any other value refuses to boot. Boot never runs migration files: the ones
|
|
265
|
+
# `rebase db generate` writes to `backend/drizzle/migrations` are applied with
|
|
266
|
+
# `rebase db migrate`.
|
|
257
267
|
# REBASE_MIGRATE_ON_BOOT=ensure
|
|
258
268
|
|
|
@@ -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`.
|