@rebasepro/cli 0.24.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.
Files changed (156) hide show
  1. package/bin/rebase.js +3 -0
  2. package/dist/agent-setup-B31F00DC.js +324 -0
  3. package/dist/agent-setup-B31F00DC.js.map +1 -0
  4. package/dist/api-keys-Bl1I9q7M.js +525 -0
  5. package/dist/api-keys-Bl1I9q7M.js.map +1 -0
  6. package/dist/apps-CNgQJjg5.js +340 -0
  7. package/dist/apps-CNgQJjg5.js.map +1 -0
  8. package/dist/args-BnmsEXvu.js +109 -0
  9. package/dist/args-BnmsEXvu.js.map +1 -0
  10. package/dist/atlas-dev-database-D_LP_Woq.js +62 -0
  11. package/dist/atlas-dev-database-D_LP_Woq.js.map +1 -0
  12. package/dist/auth-aySHEF45.js +414 -0
  13. package/dist/auth-aySHEF45.js.map +1 -0
  14. package/dist/branch-pointer-DvSHBjjz.js +2 -0
  15. package/dist/build-DIHWIqO4.js +336 -0
  16. package/dist/build-DIHWIqO4.js.map +1 -0
  17. package/dist/bundle-CqURVN-K.js +1621 -0
  18. package/dist/bundle-CqURVN-K.js.map +1 -0
  19. package/dist/bundle.d.ts +6 -1
  20. package/dist/cli.d.ts +2 -2
  21. package/dist/cloud-DjByQlkW.js +9667 -0
  22. package/dist/cloud-DjByQlkW.js.map +1 -0
  23. package/dist/collection-drift-BKj_BoMq.js +106 -0
  24. package/dist/collection-drift-BKj_BoMq.js.map +1 -0
  25. package/dist/commands/api-keys.d.ts +2 -0
  26. package/dist/commands/console.d.ts +12 -0
  27. package/dist/commands/db.d.ts +64 -24
  28. package/dist/commands/dev.d.ts +103 -6
  29. package/dist/commands/generate_sdk.d.ts +26 -0
  30. package/dist/commands/init.d.ts +58 -0
  31. package/dist/commands/skills.d.ts +22 -7
  32. package/dist/commands/start.d.ts +15 -0
  33. package/dist/commands/storage.d.ts +46 -0
  34. package/dist/commands/upgrade.d.ts +1 -0
  35. package/dist/consent-ClRHmcxf.js +76 -0
  36. package/dist/consent-ClRHmcxf.js.map +1 -0
  37. package/dist/console-D6SJf8k_.js +102 -0
  38. package/dist/console-D6SJf8k_.js.map +1 -0
  39. package/dist/context-BqhRydBg.js +1234 -0
  40. package/dist/context-BqhRydBg.js.map +1 -0
  41. package/dist/{daemon-entry-LTFKtpHy.js → daemon-entry-Da-D3rmH.js} +3 -4
  42. package/dist/daemon-entry-Da-D3rmH.js.map +1 -0
  43. package/dist/daemon-pzsQwDHa.js +2 -0
  44. package/dist/db-B7RuNuaQ.js +1312 -0
  45. package/dist/db-B7RuNuaQ.js.map +1 -0
  46. package/dist/derive-Dl0z2OWi.js +484 -0
  47. package/dist/derive-Dl0z2OWi.js.map +1 -0
  48. package/dist/dev-CYr_WXan.js +1599 -0
  49. package/dist/dev-CYr_WXan.js.map +1 -0
  50. package/dist/dev-db/atlas-dev-database.d.ts +32 -0
  51. package/dist/dev-db/daemon-entry.d.ts +13 -0
  52. package/dist/dev-db/last-dev-database.d.ts +41 -0
  53. package/dist/dev-db/prepare.d.ts +19 -3
  54. package/dist/dev-db/pull.d.ts +90 -5
  55. package/dist/dev-db/resolve.d.ts +26 -2
  56. package/dist/dev-preflight-B-LYyBf1.js +2 -0
  57. package/dist/dev-server-DG8Tt-uf.js +96 -0
  58. package/dist/dev-server-DG8Tt-uf.js.map +1 -0
  59. package/dist/doctor-BP8cZ-7F.js +771 -0
  60. package/dist/doctor-BP8cZ-7F.js.map +1 -0
  61. package/dist/eject-DizdoecV.js +335 -0
  62. package/dist/eject-DizdoecV.js.map +1 -0
  63. package/dist/fold-static-BC9CYicw.js +201 -0
  64. package/dist/fold-static-BC9CYicw.js.map +1 -0
  65. package/dist/function-portability-BIvlvR9q.js +265 -0
  66. package/dist/function-portability-BIvlvR9q.js.map +1 -0
  67. package/dist/generate_sdk-BPqdJc3Q.js +489 -0
  68. package/dist/generate_sdk-BPqdJc3Q.js.map +1 -0
  69. package/dist/index.es.js +151 -24674
  70. package/dist/index.es.js.map +1 -1
  71. package/dist/init-Utstvh2Q.js +1149 -0
  72. package/dist/init-Utstvh2Q.js.map +1 -0
  73. package/dist/last-dev-database-B58g89uA.js +2 -0
  74. package/dist/manifest-DRp0UVTj.js +880 -0
  75. package/dist/manifest-DRp0UVTj.js.map +1 -0
  76. package/dist/manifest.d.ts +15 -3
  77. package/dist/normalize-imports-X0Tgze9y.js +107 -0
  78. package/dist/normalize-imports-X0Tgze9y.js.map +1 -0
  79. package/dist/{package-manager-CXQevsE1.js → package-manager-DSEOwTqM.js} +2 -2
  80. package/dist/{package-manager-CXQevsE1.js.map → package-manager-DSEOwTqM.js.map} +1 -1
  81. package/dist/path-flags-BFgG9V6y.js +91 -0
  82. package/dist/path-flags-BFgG9V6y.js.map +1 -0
  83. package/dist/precompress.d.ts +17 -0
  84. package/dist/prepare-CDN6lSpz.js +1236 -0
  85. package/dist/prepare-CDN6lSpz.js.map +1 -0
  86. package/dist/{project-DmaGLmH2.js → project-Wp2zoyeN.js} +33 -4
  87. package/dist/project-Wp2zoyeN.js.map +1 -0
  88. package/dist/pull-CrGYMEsy.js +458 -0
  89. package/dist/pull-CrGYMEsy.js.map +1 -0
  90. package/dist/resolve-B2O-wKKk.js +2 -0
  91. package/dist/resources-FD7AfZx8.js +183 -0
  92. package/dist/resources-FD7AfZx8.js.map +1 -0
  93. package/dist/schema-DMdr431S.js +125 -0
  94. package/dist/schema-DMdr431S.js.map +1 -0
  95. package/dist/skills-DTFibT1m.js +642 -0
  96. package/dist/skills-DTFibT1m.js.map +1 -0
  97. package/dist/start-DEa-hOBh.js +267 -0
  98. package/dist/start-DEa-hOBh.js.map +1 -0
  99. package/dist/{state-C59Elrnt.js → state-Do7ZJYkF.js} +49 -4
  100. package/dist/state-Do7ZJYkF.js.map +1 -0
  101. package/dist/status-DxnJTekv.js +352 -0
  102. package/dist/status-DxnJTekv.js.map +1 -0
  103. package/dist/storage-DyVq-f_F.js +303 -0
  104. package/dist/storage-DyVq-f_F.js.map +1 -0
  105. package/dist/telemetry/identity.d.ts +10 -1
  106. package/dist/telemetry-C8Uq8phb.js +129 -0
  107. package/dist/telemetry-C8Uq8phb.js.map +1 -0
  108. package/dist/telemetry-EMFRVRQi.js +351 -0
  109. package/dist/telemetry-EMFRVRQi.js.map +1 -0
  110. package/dist/unknown-command-DNwDcX3w.js +98 -0
  111. package/dist/unknown-command-DNwDcX3w.js.map +1 -0
  112. package/dist/upgrade-CtZtRkTE.js +1332 -0
  113. package/dist/upgrade-CtZtRkTE.js.map +1 -0
  114. package/dist/upgrade.d.ts +24 -3
  115. package/dist/utils/dev-preflight.d.ts +47 -5
  116. package/dist/utils/dev-server.d.ts +30 -0
  117. package/dist/utils/path-flags.d.ts +15 -2
  118. package/dist/utils/project.d.ts +16 -0
  119. package/dist/utils/temp-archive.d.ts +9 -0
  120. package/dist/{version-DsgBmP22.js → version-Buyyo1ut.js} +2 -2
  121. package/dist/{version-DsgBmP22.js.map → version-Buyyo1ut.js.map} +1 -1
  122. package/package.json +7 -7
  123. package/templates/eject/Dockerfile +4 -2
  124. package/templates/eject/backend/src/env.ts +1 -1
  125. package/templates/eject/backend/src/index.ts +29 -4
  126. package/templates/eject/docker-compose.custom.yml +8 -4
  127. package/templates/generated-schemas/blank.ts +40 -0
  128. package/templates/generated-schemas/blog.ts +127 -0
  129. package/templates/generated-schemas/ecommerce.ts +93 -0
  130. package/templates/overlays/baas/config/package.json +1 -0
  131. package/templates/overlays/baas/package.json +1 -0
  132. package/templates/template/.env.example +10 -4
  133. package/templates/template/README.md +11 -4
  134. package/templates/template/ai-instructions.md +3 -2
  135. package/templates/template/config/resources.ts +7 -6
  136. package/templates/template/docker-compose.yml +9 -3
  137. package/templates/template/frontend/vite.config.ts +13 -3
  138. package/templates/template/package.json +1 -0
  139. package/templates/template/scripts/example.ts +2 -1
  140. package/templates/template/tsconfig.json +25 -0
  141. package/dist/branch-pointer-kk9F5FBO.js +0 -111
  142. package/dist/branch-pointer-kk9F5FBO.js.map +0 -1
  143. package/dist/constraints-DKGbNfUW.js +0 -48
  144. package/dist/constraints-DKGbNfUW.js.map +0 -1
  145. package/dist/daemon-C8p32i-n.js +0 -357
  146. package/dist/daemon-C8p32i-n.js.map +0 -1
  147. package/dist/daemon-entry-LTFKtpHy.js.map +0 -1
  148. package/dist/dev-preflight-CNLl4rdo.js +0 -367
  149. package/dist/dev-preflight-CNLl4rdo.js.map +0 -1
  150. package/dist/project-DmaGLmH2.js.map +0 -1
  151. package/dist/pull-Dywm5FWP.js +0 -232
  152. package/dist/pull-Dywm5FWP.js.map +0 -1
  153. package/dist/resolve-BAeRUBhg.js +0 -74
  154. package/dist/resolve-BAeRUBhg.js.map +0 -1
  155. package/dist/state-C59Elrnt.js.map +0 -1
  156. package/templates/template/backend/src/schema.generated.ts +0 -13
@@ -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
+
@@ -16,6 +16,7 @@
16
16
  "@rebasepro/types": "workspace:*"
17
17
  },
18
18
  "devDependencies": {
19
+ "@types/node": "^22.19.4",
19
20
  "typescript": "^6.0.3"
20
21
  },
21
22
  "exports": {
@@ -22,6 +22,7 @@
22
22
  "devDependencies": {
23
23
  "@rebasepro/cli": "workspace:*",
24
24
  "@rebasepro/types": "workspace:*",
25
+ "@types/node": "^22.19.4",
25
26
  "tsx": "^4.20.6",
26
27
  "typescript": "^6.0.3"
27
28
  },
@@ -161,14 +161,20 @@ VITE_API_URL=
161
161
  # In production, "local" means NO file storage: uploads answer
162
162
  # 501 STORAGE_NOT_CONFIGURED instead of landing on a container filesystem that
163
163
  # is erased on the next redeploy. Configure a bucket below to switch it on, or
164
- # set FORCE_LOCAL_STORAGE=true if a durable volume really is mounted at
165
- # STORAGE_PATH (the generated docker-compose.yml does exactly that).
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.
166
168
  #
167
169
  # STORAGE_TYPE=local
168
170
 
169
171
  # --- Local filesystem (default — great for dev and single-server deployments) --
170
- # STORAGE_PATH=./uploads
171
- # FORCE_LOCAL_STORAGE=true # Only with a durable volume mounted at STORAGE_PATH
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
172
178
 
173
179
  # --- S3-compatible (AWS S3, Cloudflare R2, MinIO, Hetzner Object Storage, Backblaze B2) ---
174
180
  # STORAGE_TYPE=s3
@@ -40,7 +40,7 @@ every collection declared there, and serves the API and the admin panel.
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
42
42
  `.env` are ignored here and read by the production boot below, where that window
43
- is shut — see [Self-hosting](#self-hosting-with-docker).
43
+ is shut — see [Self-hosting](#self-hosting).
44
44
 
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
@@ -53,9 +53,10 @@ built bundle). Pin a port with `rebase dev --port 3001` if you need a stable one
53
53
  Uncomment `DATABASE_URL` in `.env` and run `pnpm dev` again. Nothing else
54
54
  changes. A `DATABASE_URL` that is already set is never touched.
55
55
 
56
- With your own database you also get the migration commands, which the managed
57
- one cannot offer — they plan changes with Atlas, which needs a second empty
58
- database to compare against, and PGlite serves exactly one:
56
+ The migration commands work on either database. They plan changes with Atlas,
57
+ which needs a second empty database to compare against: beside your own
58
+ database Rebase makes one, and on the managed one, which serves exactly one,
59
+ the command starts a throwaway in-memory PGlite:
59
60
 
60
61
  ```bash
61
62
  pnpm run db:push
@@ -81,12 +82,18 @@ docker compose up -d db
81
82
  │ └── src/ # Generated database schema
82
83
  ├── config/ # Shared collection definitions
83
84
  │ └── collections/ # Schema-as-Code TypeScript files
85
+ ├── scripts/ # Scripts that call the API, e.g. example.ts
84
86
  ├── rebase.json # Which apps this repository contains
85
87
  ├── docker-compose.yml # Self-hosting stack (Postgres + the Rebase runtime)
86
88
  ├── .env.example # Environment variable reference
89
+ ├── tsconfig.json # Typechecks scripts/ only
87
90
  └── package.json # Root workspace config
88
91
  ```
89
92
 
93
+ Each workspace typechecks on its own, with its own `tsconfig.json`:
94
+ `cd backend && npx tsc --noEmit`, and the same in `config/` and `frontend/`.
95
+ `tsc --noEmit` at the root checks `scripts/`.
96
+
90
97
  There is no Dockerfile, and that is deliberate: `rebase build` produces a
91
98
  **bundle** — your compiled collections, functions, crons and admin assets — and
92
99
  the published `rebasepro/server` image boots it. The artifact you self-host is
@@ -7,7 +7,8 @@
7
7
  | Command | What it does |
8
8
  |---|---|
9
9
  | `pnpm dev` | Backend, frontend and the managed development database, together |
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 |
10
+ | `pnpm schema:generate` then `pnpm generate:sdk` | The same loop with `pnpm dev` not running: collections → Drizzle schema and SDK types. The next boot creates what is missing |
11
+ | `pnpm db:push` | The changes boot leaves alone (a rename, a narrowed type, a removed field), on the managed development database as on your own PostgreSQL |
11
12
  | `pnpm db:generate` then `pnpm db:migrate` | The production path — write the migration file, then apply it |
12
13
  | `pnpm schema:introspect` | The other direction: existing tables → collection definitions |
13
14
  | `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 |
@@ -30,7 +31,7 @@
30
31
  ## Core rules
31
32
 
32
33
  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
+ 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 — on the managed development database as on your own PostgreSQL. In production the pair is `pnpm db:generate` then `pnpm db:migrate`.
34
35
  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
36
  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
37
  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.
@@ -43,12 +43,13 @@ export const main = database();
43
43
  * export const files = bucket({ engine: "s3" });
44
44
  * export const media = bucket("media", { engine: "s3" });
45
45
  *
46
- * One of them has to be the one an upload reaches when the property names no
47
- * `storageSource` — the default-keyed `bucket()` above, or a named bucket
48
- * marked `bucket("media", { engine: "s3", default: true })`. A project of named
49
- * buckets with no default refuses to boot rather than have one chosen for it:
50
- * that choice used to be made by declaration order, and it came out differently
51
- * in development and in production.
46
+ * An upload whose property names no `storageSource` goes to the default
47
+ * bucket, which keeps its own variables — `STORAGE_PATH` (else `./uploads`),
48
+ * `S3_BUCKET` / `GCS_BUCKET` — whatever you declare here, so adding
49
+ * `bucket("media")` never moves the files already there. To send those
50
+ * uploads to a named bucket instead, mark it:
51
+ * `bucket("media", { engine: "s3", default: true })`. Two buckets may not
52
+ * share a directory or a bucket; boot refuses if they would.
52
53
  *
53
54
  * Point a property at it by handle — the same name, spelled once:
54
55
  *
@@ -147,7 +147,13 @@ services:
147
147
  # container filesystem is destroyed on the next deploy and every uploaded
148
148
  # file goes with it. Switch to STORAGE_TYPE=s3 or gcs and drop both lines
149
149
  # if you move storage off-box.
150
- STORAGE_PATH: /uploads
150
+ #
151
+ # The volume is mounted at /storage, one level above STORAGE_PATH, because
152
+ # every bucket you declare in config/resources.ts gets a directory beside
153
+ # this one: bucket("media") is /storage/uploads__media. Mounted at
154
+ # /storage/uploads itself, the volume would hold the default bucket only,
155
+ # and every other bucket's files would go with the container.
156
+ STORAGE_PATH: /storage/uploads
151
157
  FORCE_LOCAL_STORAGE: "true"
152
158
  volumes:
153
159
  # Your built project. `rebase build` installs its declared dependencies
@@ -156,10 +162,10 @@ services:
156
162
  # that runs after it. Drop the `:ro` if you build with `--no-vendor`: the
157
163
  # runtime installs at every start instead, and needs to write here.
158
164
  - ./dist-bundle:/bundle:ro
159
- - uploads:/uploads
165
+ - storage:/storage
160
166
 
161
167
  volumes:
162
168
  postgres_data:
163
169
  driver: local
164
- uploads:
170
+ storage:
165
171
  driver: local
@@ -30,9 +30,9 @@ export default defineConfig({
30
30
  "@remix-run/router"
31
31
  ]
32
32
  },
33
- esbuild: {
34
- logOverride: { "this-is-undefined-in-esm": "silent" }
35
- },
33
+ // No `esbuild` block: Vite 8 transforms with oxc and ignores it, and
34
+ // having one made every `rebase dev` and build print "Both esbuild and oxc
35
+ // options were set".
36
36
  build: {
37
37
  minify: true,
38
38
  outDir: "./dist",
@@ -42,6 +42,8 @@ export default defineConfig({
42
42
  // successful JS transform, so the build fails at the very end.
43
43
  target: "es2022",
44
44
  sourcemap: true,
45
+ // The admin's own chunks are already code-split and the warning names only them, never this project's code.
46
+ chunkSizeWarningLimit: Infinity,
45
47
  rollupOptions: {
46
48
  output: {
47
49
  // These rules are copied in rather than taken from
@@ -75,6 +77,14 @@ export default defineConfig({
75
77
  // anchor a heavy one to the critical path.
76
78
  if (id.includes("commonjsHelpers") || id.includes("commonjs-dynamic-modules")) return "vendor-commonjs-helpers";
77
79
 
80
+ // Small libraries the entry needs, named before the heavy groups. A name
81
+ // takes the unassigned dependencies of its modules with it, so
82
+ // `prism-react-renderer` took `clsx` — which the kit imports statically — and
83
+ // the entry imported 85 kB of syntax highlighter for a 633-byte helper;
84
+ // React core landed in `vendor-dnd` the same way.
85
+ if (/[\\/]node_modules[\\/](react|scheduler|use-sync-external-store)[\\/]/.test(id)) return "vendor-react";
86
+ if (/[\\/]node_modules[\\/]clsx[\\/]/.test(id)) return "vendor-clsx";
87
+
78
88
  if (id.includes("exceljs")) return "vendor-exceljs";
79
89
  if (id.includes("prosemirror")) return "vendor-prosemirror";
80
90
  if (id.includes("monaco-editor") || id.includes("@monaco-editor")) return "vendor-monaco";
@@ -27,6 +27,7 @@
27
27
  "@rebasepro/cli": "workspace:*",
28
28
  "@rebasepro/mcp": "workspace:*",
29
29
  "@rebasepro/types": "workspace:*",
30
+ "@types/node": "^22.19.4",
30
31
  "tsx": "^4.20.6",
31
32
  "typescript": "^6.0.3"
32
33
  },
@@ -30,7 +30,8 @@ import { createRebaseClient } from "@rebasepro/client";
30
30
  // import { collectionsDictionary, type Database } from "../generated/sdk/database.types";
31
31
 
32
32
  // Load .env from project root (same file the backend uses)
33
- dotenv.config({ path: path.resolve(process.cwd(), ".env") });
33
+ // `quiet`: dotenv 17 otherwise prints its own advertisement banner.
34
+ dotenv.config({ path: path.resolve(process.cwd(), ".env"), quiet: true });
34
35
 
35
36
  // ─── Resolve Backend URL ─────────────────────────────────────────────
36
37
  let baseUrl = process.env.REBASE_URL;
@@ -0,0 +1,25 @@
1
+ {
2
+ // The project root's own program: `scripts/`, which no workspace compiles.
3
+ //
4
+ // frontend/, backend/ and config/ each typecheck on their own, with the
5
+ // tsconfig in that folder — `cd backend && tsc --noEmit` — and this file
6
+ // does not reach into them: it would compile their code under options that
7
+ // are not theirs. Without it, `tsc --noEmit` here printed tsc's help and
8
+ // exited 0, which reads as a passing check of nothing.
9
+ "compilerOptions": {
10
+ "target": "ES2022",
11
+ "module": "ESNext",
12
+ "moduleResolution": "bundler",
13
+ "strict": true,
14
+ "noEmit": true,
15
+ "esModuleInterop": true,
16
+ "allowSyntheticDefaultImports": true,
17
+ "skipLibCheck": true,
18
+ "forceConsistentCasingInFileNames": true,
19
+ "resolveJsonModule": true,
20
+ // Pinned, as every workspace's tsconfig is: unset, tsc sweeps every
21
+ // `node_modules/@types` it can reach, the pnpm virtual store included.
22
+ "types": ["node"]
23
+ },
24
+ "include": ["scripts/**/*"]
25
+ }