@rebasepro/server-core 0.0.1-canary.09e5ec5

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 (300) hide show
  1. package/LICENSE +6 -0
  2. package/README.md +40 -0
  3. package/build-errors.txt +52 -0
  4. package/coverage/clover.xml +3739 -0
  5. package/coverage/coverage-final.json +31 -0
  6. package/coverage/lcov-report/base.css +224 -0
  7. package/coverage/lcov-report/block-navigation.js +87 -0
  8. package/coverage/lcov-report/favicon.png +0 -0
  9. package/coverage/lcov-report/index.html +266 -0
  10. package/coverage/lcov-report/prettify.css +1 -0
  11. package/coverage/lcov-report/prettify.js +2 -0
  12. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  13. package/coverage/lcov-report/sorter.js +210 -0
  14. package/coverage/lcov-report/src/api/ast-schema-editor.ts.html +952 -0
  15. package/coverage/lcov-report/src/api/errors.ts.html +472 -0
  16. package/coverage/lcov-report/src/api/graphql/graphql-schema-generator.ts.html +1069 -0
  17. package/coverage/lcov-report/src/api/graphql/index.html +116 -0
  18. package/coverage/lcov-report/src/api/index.html +176 -0
  19. package/coverage/lcov-report/src/api/openapi-generator.ts.html +565 -0
  20. package/coverage/lcov-report/src/api/rest/api-generator.ts.html +994 -0
  21. package/coverage/lcov-report/src/api/rest/index.html +131 -0
  22. package/coverage/lcov-report/src/api/rest/query-parser.ts.html +550 -0
  23. package/coverage/lcov-report/src/api/schema-editor-routes.ts.html +202 -0
  24. package/coverage/lcov-report/src/api/server.ts.html +823 -0
  25. package/coverage/lcov-report/src/auth/admin-routes.ts.html +973 -0
  26. package/coverage/lcov-report/src/auth/index.html +176 -0
  27. package/coverage/lcov-report/src/auth/jwt.ts.html +574 -0
  28. package/coverage/lcov-report/src/auth/middleware.ts.html +745 -0
  29. package/coverage/lcov-report/src/auth/password.ts.html +310 -0
  30. package/coverage/lcov-report/src/auth/services.ts.html +2074 -0
  31. package/coverage/lcov-report/src/collections/index.html +116 -0
  32. package/coverage/lcov-report/src/collections/loader.ts.html +232 -0
  33. package/coverage/lcov-report/src/db/auth-schema.ts.html +523 -0
  34. package/coverage/lcov-report/src/db/data-transformer.ts.html +1753 -0
  35. package/coverage/lcov-report/src/db/entityService.ts.html +700 -0
  36. package/coverage/lcov-report/src/db/index.html +146 -0
  37. package/coverage/lcov-report/src/db/services/EntityFetchService.ts.html +4048 -0
  38. package/coverage/lcov-report/src/db/services/EntityPersistService.ts.html +883 -0
  39. package/coverage/lcov-report/src/db/services/RelationService.ts.html +3121 -0
  40. package/coverage/lcov-report/src/db/services/entity-helpers.ts.html +442 -0
  41. package/coverage/lcov-report/src/db/services/index.html +176 -0
  42. package/coverage/lcov-report/src/db/services/index.ts.html +124 -0
  43. package/coverage/lcov-report/src/generate-drizzle-schema-logic.ts.html +1960 -0
  44. package/coverage/lcov-report/src/index.html +116 -0
  45. package/coverage/lcov-report/src/services/driver-registry.ts.html +631 -0
  46. package/coverage/lcov-report/src/services/index.html +131 -0
  47. package/coverage/lcov-report/src/services/postgresDataDriver.ts.html +3025 -0
  48. package/coverage/lcov-report/src/storage/LocalStorageController.ts.html +1189 -0
  49. package/coverage/lcov-report/src/storage/S3StorageController.ts.html +970 -0
  50. package/coverage/lcov-report/src/storage/index.html +161 -0
  51. package/coverage/lcov-report/src/storage/storage-registry.ts.html +646 -0
  52. package/coverage/lcov-report/src/storage/types.ts.html +451 -0
  53. package/coverage/lcov-report/src/utils/drizzle-conditions.ts.html +3082 -0
  54. package/coverage/lcov-report/src/utils/index.html +116 -0
  55. package/coverage/lcov.info +7179 -0
  56. package/dist/common/src/collections/CollectionRegistry.d.ts +56 -0
  57. package/dist/common/src/collections/index.d.ts +1 -0
  58. package/dist/common/src/data/buildRebaseData.d.ts +14 -0
  59. package/dist/common/src/index.d.ts +3 -0
  60. package/dist/common/src/util/builders.d.ts +57 -0
  61. package/dist/common/src/util/callbacks.d.ts +6 -0
  62. package/dist/common/src/util/collections.d.ts +11 -0
  63. package/dist/common/src/util/common.d.ts +2 -0
  64. package/dist/common/src/util/conditions.d.ts +26 -0
  65. package/dist/common/src/util/entities.d.ts +58 -0
  66. package/dist/common/src/util/enums.d.ts +3 -0
  67. package/dist/common/src/util/index.d.ts +16 -0
  68. package/dist/common/src/util/navigation_from_path.d.ts +34 -0
  69. package/dist/common/src/util/navigation_utils.d.ts +20 -0
  70. package/dist/common/src/util/parent_references_from_path.d.ts +6 -0
  71. package/dist/common/src/util/paths.d.ts +14 -0
  72. package/dist/common/src/util/permissions.d.ts +5 -0
  73. package/dist/common/src/util/references.d.ts +2 -0
  74. package/dist/common/src/util/relations.d.ts +22 -0
  75. package/dist/common/src/util/resolutions.d.ts +72 -0
  76. package/dist/common/src/util/storage.d.ts +24 -0
  77. package/dist/index-DXVBFp5V.js +37 -0
  78. package/dist/index-DXVBFp5V.js.map +1 -0
  79. package/dist/index.es.js +49934 -0
  80. package/dist/index.es.js.map +1 -0
  81. package/dist/index.umd.js +49968 -0
  82. package/dist/index.umd.js.map +1 -0
  83. package/dist/server-core/src/api/ast-schema-editor.d.ts +21 -0
  84. package/dist/server-core/src/api/collections_for_test/callbacks_test_collection.d.ts +2 -0
  85. package/dist/server-core/src/api/errors.d.ts +35 -0
  86. package/dist/server-core/src/api/graphql/graphql-schema-generator.d.ts +35 -0
  87. package/dist/server-core/src/api/graphql/index.d.ts +1 -0
  88. package/dist/server-core/src/api/index.d.ts +9 -0
  89. package/dist/server-core/src/api/openapi-generator.d.ts +16 -0
  90. package/dist/server-core/src/api/rest/api-generator.d.ts +64 -0
  91. package/dist/server-core/src/api/rest/index.d.ts +1 -0
  92. package/dist/server-core/src/api/rest/query-parser.d.ts +9 -0
  93. package/dist/server-core/src/api/schema-editor-routes.d.ts +3 -0
  94. package/dist/server-core/src/api/server.d.ts +40 -0
  95. package/dist/server-core/src/api/types.d.ts +90 -0
  96. package/dist/server-core/src/auth/admin-routes.d.ts +16 -0
  97. package/dist/server-core/src/auth/apple-oauth.d.ts +30 -0
  98. package/dist/server-core/src/auth/bitbucket-oauth.d.ts +11 -0
  99. package/dist/server-core/src/auth/discord-oauth.d.ts +14 -0
  100. package/dist/server-core/src/auth/facebook-oauth.d.ts +14 -0
  101. package/dist/server-core/src/auth/github-oauth.d.ts +15 -0
  102. package/dist/server-core/src/auth/gitlab-oauth.d.ts +13 -0
  103. package/dist/server-core/src/auth/google-oauth.d.ts +14 -0
  104. package/dist/server-core/src/auth/index.d.ts +23 -0
  105. package/dist/server-core/src/auth/interfaces.d.ts +309 -0
  106. package/dist/server-core/src/auth/jwt.d.ts +43 -0
  107. package/dist/server-core/src/auth/linkedin-oauth.d.ts +18 -0
  108. package/dist/server-core/src/auth/microsoft-oauth.d.ts +16 -0
  109. package/dist/server-core/src/auth/middleware.d.ts +81 -0
  110. package/dist/server-core/src/auth/password.d.ts +22 -0
  111. package/dist/server-core/src/auth/rate-limiter.d.ts +31 -0
  112. package/dist/server-core/src/auth/routes.d.ts +27 -0
  113. package/dist/server-core/src/auth/slack-oauth.d.ts +12 -0
  114. package/dist/server-core/src/auth/spotify-oauth.d.ts +12 -0
  115. package/dist/server-core/src/auth/twitter-oauth.d.ts +18 -0
  116. package/dist/server-core/src/bootstrappers/index.d.ts +0 -0
  117. package/dist/server-core/src/collections/BackendCollectionRegistry.d.ts +13 -0
  118. package/dist/server-core/src/collections/loader.d.ts +5 -0
  119. package/dist/server-core/src/cron/cron-loader.d.ts +17 -0
  120. package/dist/server-core/src/cron/cron-routes.d.ts +14 -0
  121. package/dist/server-core/src/cron/cron-scheduler.d.ts +61 -0
  122. package/dist/server-core/src/cron/cron-store.d.ts +32 -0
  123. package/dist/server-core/src/cron/index.d.ts +6 -0
  124. package/dist/server-core/src/db/interfaces.d.ts +18 -0
  125. package/dist/server-core/src/email/index.d.ts +6 -0
  126. package/dist/server-core/src/email/smtp-email-service.d.ts +25 -0
  127. package/dist/server-core/src/email/templates.d.ts +42 -0
  128. package/dist/server-core/src/email/types.d.ts +107 -0
  129. package/dist/server-core/src/functions/function-loader.d.ts +17 -0
  130. package/dist/server-core/src/functions/function-routes.d.ts +10 -0
  131. package/dist/server-core/src/functions/index.d.ts +3 -0
  132. package/dist/server-core/src/history/history-routes.d.ts +23 -0
  133. package/dist/server-core/src/history/index.d.ts +1 -0
  134. package/dist/server-core/src/index.d.ts +29 -0
  135. package/dist/server-core/src/init.d.ts +159 -0
  136. package/dist/server-core/src/serve-spa.d.ts +30 -0
  137. package/dist/server-core/src/services/driver-registry.d.ts +78 -0
  138. package/dist/server-core/src/singleton.d.ts +35 -0
  139. package/dist/server-core/src/storage/LocalStorageController.d.ts +46 -0
  140. package/dist/server-core/src/storage/S3StorageController.d.ts +36 -0
  141. package/dist/server-core/src/storage/index.d.ts +25 -0
  142. package/dist/server-core/src/storage/routes.d.ts +38 -0
  143. package/dist/server-core/src/storage/storage-registry.d.ts +78 -0
  144. package/dist/server-core/src/storage/types.d.ts +103 -0
  145. package/dist/server-core/src/types/index.d.ts +11 -0
  146. package/dist/server-core/src/utils/dev-port.d.ts +35 -0
  147. package/dist/server-core/src/utils/logger.d.ts +31 -0
  148. package/dist/server-core/src/utils/logging.d.ts +9 -0
  149. package/dist/server-core/src/utils/request-logger.d.ts +19 -0
  150. package/dist/server-core/src/utils/sql.d.ts +27 -0
  151. package/dist/types/src/controllers/analytics_controller.d.ts +7 -0
  152. package/dist/types/src/controllers/auth.d.ts +119 -0
  153. package/dist/types/src/controllers/client.d.ts +170 -0
  154. package/dist/types/src/controllers/collection_registry.d.ts +45 -0
  155. package/dist/types/src/controllers/customization_controller.d.ts +60 -0
  156. package/dist/types/src/controllers/data.d.ts +168 -0
  157. package/dist/types/src/controllers/data_driver.d.ts +160 -0
  158. package/dist/types/src/controllers/database_admin.d.ts +11 -0
  159. package/dist/types/src/controllers/dialogs_controller.d.ts +36 -0
  160. package/dist/types/src/controllers/effective_role.d.ts +4 -0
  161. package/dist/types/src/controllers/email.d.ts +34 -0
  162. package/dist/types/src/controllers/index.d.ts +18 -0
  163. package/dist/types/src/controllers/local_config_persistence.d.ts +20 -0
  164. package/dist/types/src/controllers/navigation.d.ts +213 -0
  165. package/dist/types/src/controllers/registry.d.ts +54 -0
  166. package/dist/types/src/controllers/side_dialogs_controller.d.ts +67 -0
  167. package/dist/types/src/controllers/side_entity_controller.d.ts +90 -0
  168. package/dist/types/src/controllers/snackbar.d.ts +24 -0
  169. package/dist/types/src/controllers/storage.d.ts +171 -0
  170. package/dist/types/src/index.d.ts +4 -0
  171. package/dist/types/src/rebase_context.d.ts +105 -0
  172. package/dist/types/src/types/backend.d.ts +536 -0
  173. package/dist/types/src/types/builders.d.ts +15 -0
  174. package/dist/types/src/types/chips.d.ts +5 -0
  175. package/dist/types/src/types/collections.d.ts +856 -0
  176. package/dist/types/src/types/cron.d.ts +102 -0
  177. package/dist/types/src/types/data_source.d.ts +64 -0
  178. package/dist/types/src/types/entities.d.ts +145 -0
  179. package/dist/types/src/types/entity_actions.d.ts +98 -0
  180. package/dist/types/src/types/entity_callbacks.d.ts +173 -0
  181. package/dist/types/src/types/entity_link_builder.d.ts +7 -0
  182. package/dist/types/src/types/entity_overrides.d.ts +10 -0
  183. package/dist/types/src/types/entity_views.d.ts +61 -0
  184. package/dist/types/src/types/export_import.d.ts +21 -0
  185. package/dist/types/src/types/index.d.ts +23 -0
  186. package/dist/types/src/types/locales.d.ts +4 -0
  187. package/dist/types/src/types/modify_collections.d.ts +5 -0
  188. package/dist/types/src/types/plugins.d.ts +279 -0
  189. package/dist/types/src/types/properties.d.ts +1176 -0
  190. package/dist/types/src/types/property_config.d.ts +70 -0
  191. package/dist/types/src/types/relations.d.ts +336 -0
  192. package/dist/types/src/types/slots.d.ts +252 -0
  193. package/dist/types/src/types/translations.d.ts +870 -0
  194. package/dist/types/src/types/user_management_delegate.d.ts +121 -0
  195. package/dist/types/src/types/websockets.d.ts +78 -0
  196. package/dist/types/src/users/index.d.ts +2 -0
  197. package/dist/types/src/users/roles.d.ts +22 -0
  198. package/dist/types/src/users/user.d.ts +46 -0
  199. package/history_diff.log +385 -0
  200. package/jest.config.cjs +16 -0
  201. package/package.json +86 -0
  202. package/scratch.ts +9 -0
  203. package/src/api/ast-schema-editor.ts +289 -0
  204. package/src/api/collections_for_test/callbacks_test_collection.ts +60 -0
  205. package/src/api/errors.ts +179 -0
  206. package/src/api/graphql/graphql-schema-generator.ts +336 -0
  207. package/src/api/graphql/index.ts +2 -0
  208. package/src/api/index.ts +11 -0
  209. package/src/api/openapi-generator.ts +715 -0
  210. package/src/api/rest/api-generator.ts +472 -0
  211. package/src/api/rest/index.ts +2 -0
  212. package/src/api/rest/query-parser.ts +155 -0
  213. package/src/api/schema-editor-routes.ts +41 -0
  214. package/src/api/server.ts +248 -0
  215. package/src/api/types.ts +90 -0
  216. package/src/auth/admin-routes.ts +529 -0
  217. package/src/auth/apple-oauth.ts +130 -0
  218. package/src/auth/bitbucket-oauth.ts +82 -0
  219. package/src/auth/discord-oauth.ts +83 -0
  220. package/src/auth/facebook-oauth.ts +72 -0
  221. package/src/auth/github-oauth.ts +110 -0
  222. package/src/auth/gitlab-oauth.ts +70 -0
  223. package/src/auth/google-oauth.ts +48 -0
  224. package/src/auth/index.ts +34 -0
  225. package/src/auth/interfaces.ts +363 -0
  226. package/src/auth/jwt.ts +181 -0
  227. package/src/auth/linkedin-oauth.ts +81 -0
  228. package/src/auth/microsoft-oauth.ts +88 -0
  229. package/src/auth/middleware.ts +384 -0
  230. package/src/auth/password.ts +77 -0
  231. package/src/auth/rate-limiter.ts +129 -0
  232. package/src/auth/routes.ts +788 -0
  233. package/src/auth/slack-oauth.ts +71 -0
  234. package/src/auth/spotify-oauth.ts +67 -0
  235. package/src/auth/twitter-oauth.ts +120 -0
  236. package/src/bootstrappers/index.ts +1 -0
  237. package/src/collections/BackendCollectionRegistry.ts +20 -0
  238. package/src/collections/loader.ts +49 -0
  239. package/src/cron/cron-loader.ts +89 -0
  240. package/src/cron/cron-routes.test.ts +265 -0
  241. package/src/cron/cron-routes.ts +85 -0
  242. package/src/cron/cron-scheduler.test.ts +421 -0
  243. package/src/cron/cron-scheduler.ts +413 -0
  244. package/src/cron/cron-store.ts +163 -0
  245. package/src/cron/index.ts +6 -0
  246. package/src/db/interfaces.ts +60 -0
  247. package/src/email/index.ts +18 -0
  248. package/src/email/smtp-email-service.ts +91 -0
  249. package/src/email/templates.ts +388 -0
  250. package/src/email/types.ts +105 -0
  251. package/src/functions/function-loader.ts +119 -0
  252. package/src/functions/function-routes.ts +31 -0
  253. package/src/functions/index.ts +3 -0
  254. package/src/history/history-routes.ts +129 -0
  255. package/src/history/index.ts +2 -0
  256. package/src/index.ts +66 -0
  257. package/src/init.ts +727 -0
  258. package/src/serve-spa.ts +81 -0
  259. package/src/services/driver-registry.ts +182 -0
  260. package/src/singleton.test.ts +28 -0
  261. package/src/singleton.ts +70 -0
  262. package/src/storage/LocalStorageController.ts +365 -0
  263. package/src/storage/S3StorageController.ts +298 -0
  264. package/src/storage/index.ts +43 -0
  265. package/src/storage/routes.ts +264 -0
  266. package/src/storage/storage-registry.ts +187 -0
  267. package/src/storage/types.ts +134 -0
  268. package/src/types/index.ts +27 -0
  269. package/src/utils/dev-port.ts +176 -0
  270. package/src/utils/logger.ts +143 -0
  271. package/src/utils/logging.ts +38 -0
  272. package/src/utils/request-logger.ts +66 -0
  273. package/src/utils/sql.ts +38 -0
  274. package/test/admin-routes.test.ts +640 -0
  275. package/test/api-generator.test.ts +501 -0
  276. package/test/ast-schema-editor.test.ts +63 -0
  277. package/test/auth-middleware-hono.test.ts +556 -0
  278. package/test/auth-routes.test.ts +1047 -0
  279. package/test/driver-registry.test.ts +282 -0
  280. package/test/error-propagation.test.ts +226 -0
  281. package/test/errors-hono.test.ts +133 -0
  282. package/test/errors.test.ts +155 -0
  283. package/test/jwt-security.test.ts +182 -0
  284. package/test/jwt.test.ts +324 -0
  285. package/test/middleware.test.ts +300 -0
  286. package/test/password.test.ts +165 -0
  287. package/test/query-parser.test.ts +263 -0
  288. package/test/rate-limiter.test.ts +102 -0
  289. package/test/safe-compare.test.ts +66 -0
  290. package/test/singleton.test.ts +59 -0
  291. package/test/storage-local.test.ts +271 -0
  292. package/test/storage-registry.test.ts +282 -0
  293. package/test/storage-routes.test.ts +222 -0
  294. package/test/storage-s3.test.ts +304 -0
  295. package/test-ast.ts +28 -0
  296. package/test.ts +6 -0
  297. package/test_output.txt +1133 -0
  298. package/tsconfig.json +49 -0
  299. package/tsconfig.prod.json +20 -0
  300. package/vite.config.ts +80 -0
@@ -0,0 +1,81 @@
1
+ import { Hono } from "hono";
2
+ import { serveStatic } from "@hono/node-server/serve-static";
3
+ import * as path from "path";
4
+ import * as fs from "fs";
5
+
6
+ /**
7
+ * Configuration for serving a Single Page Application
8
+ */
9
+ export interface ServeSPAConfig {
10
+ /**
11
+ * Absolute path to the frontend build directory
12
+ * @example path.join(__dirname, "../../frontend/dist")
13
+ */
14
+ frontendPath: string;
15
+
16
+ /**
17
+ * Base path for API routes (default: "/api")
18
+ * Requests to this path will be passed through to API handlers
19
+ */
20
+ apiBasePath?: string;
21
+
22
+ /**
23
+ * Additional paths to exclude from SPA handling
24
+ * These paths will be passed through to other handlers
25
+ * @example ["/health", "/ws", "/metrics"]
26
+ */
27
+ excludePaths?: string[];
28
+
29
+ /**
30
+ * Index file to serve for SPA routes (default: "index.html")
31
+ */
32
+ indexFile?: string;
33
+ }
34
+
35
+ /**
36
+ * Serve a Single Page Application from an Hono app.
37
+ */
38
+ export function serveSPA<E extends import("hono").Env>(app: Hono<E>, config: ServeSPAConfig): void {
39
+ const {
40
+ frontendPath,
41
+ apiBasePath = "/api",
42
+ excludePaths = [],
43
+ indexFile = "index.html"
44
+ } = config;
45
+
46
+ // Validate frontend path exists
47
+ if (!fs.existsSync(frontendPath)) {
48
+ console.warn(`⚠️ Frontend build path does not exist: ${frontendPath}`);
49
+ console.warn(" SPA serving is disabled. Build your frontend first.");
50
+ return;
51
+ }
52
+
53
+ // Serve static files from frontend build
54
+ app.use("/*", serveStatic({
55
+ root: path.relative(process.cwd(), frontendPath)
56
+ }));
57
+
58
+ // Build list of paths to exclude from SPA handling
59
+ const allExcludePaths = [apiBasePath, ...excludePaths];
60
+
61
+ // SPA fallback - serve index.html for all non-excluded routes
62
+ app.get("*", async (c, next) => {
63
+ // Skip excluded paths (API, health checks, etc.)
64
+ if (allExcludePaths.some(p => c.req.path.startsWith(p))) {
65
+ return next();
66
+ }
67
+
68
+ const indexPath = path.join(frontendPath, indexFile);
69
+
70
+ if (!fs.existsSync(indexPath)) {
71
+ console.warn(`⚠️ Index file not found: ${indexPath}`);
72
+ return next();
73
+ }
74
+
75
+ const html = fs.readFileSync(indexPath, "utf-8");
76
+ return c.html(html);
77
+ });
78
+
79
+ console.log(`✅ SPA serving enabled from: ${frontendPath}`);
80
+ }
81
+
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Driver Registry
3
+ *
4
+ * Manages multiple driver delegates for Rebase backend.
5
+ * Allows different databases for different collections.
6
+ *
7
+ * Usage:
8
+ * - Single DB: Pass a single DataDriver → maps to "(default)"
9
+ * - Multiple DBs: Pass a map of { dbId: DataDriver }
10
+ * - Collections use `databaseId` property to specify which driver to use
11
+ * - Collections without `databaseId` fallback to "(default)"
12
+ */
13
+
14
+ import { DataDriver } from "@rebasepro/types";
15
+
16
+ /**
17
+ * The default driver identifier used when:
18
+ * - A single driver is provided (not a map)
19
+ * - A collection doesn't specify a databaseId
20
+ */
21
+ export const DEFAULT_DRIVER_ID = "(default)";
22
+
23
+ /**
24
+ * Registry for managing multiple driver delegates
25
+ */
26
+ export interface DriverRegistry {
27
+ /**
28
+ * Register a driver delegate with an ID
29
+ * @param id - Unique identifier for this driver (e.g., "analytics", "users")
30
+ * @param delegate - The DataDriver instance
31
+ */
32
+ register(id: string, delegate: DataDriver): void;
33
+
34
+ /**
35
+ * Get the default driver delegate (id = "(default)")
36
+ * @throws Error if no default driver is registered
37
+ */
38
+ getDefault(): DataDriver;
39
+
40
+ /**
41
+ * Get a driver delegate by ID
42
+ * @param id - Driver identifier, or undefined/null for default
43
+ * @returns The DataDriver, or undefined if not found
44
+ */
45
+ get(id: string | undefined | null): DataDriver | undefined;
46
+
47
+ /**
48
+ * Get a driver delegate by ID, with fallback to default
49
+ * @param id - Driver identifier, or undefined/null for default
50
+ * @returns The DataDriver (falls back to default if id not found)
51
+ * @throws Error if neither the specified nor default driver exists
52
+ */
53
+ getOrDefault(id: string | undefined | null): DataDriver;
54
+
55
+ /**
56
+ * Check if a driver with the given ID exists
57
+ */
58
+ has(id: string): boolean;
59
+
60
+ /**
61
+ * List all registered driver IDs
62
+ */
63
+ list(): string[];
64
+
65
+ /**
66
+ * Get the number of registered drivers
67
+ */
68
+ size(): number;
69
+ }
70
+
71
+ /**
72
+ * Default implementation of DriverRegistry
73
+ */
74
+ export class DefaultDriverRegistry implements DriverRegistry {
75
+ private delegates = new Map<string, DataDriver>();
76
+
77
+ /**
78
+ * Create a DriverRegistry from either a single delegate or a map
79
+ * @param input - Single DataDriver (maps to "(default)") or Record<string, DataDriver>
80
+ */
81
+ static create(
82
+ input: DataDriver | Record<string, DataDriver>
83
+ ): DefaultDriverRegistry {
84
+ const registry = new DefaultDriverRegistry();
85
+
86
+ if (isDataDriverDelegate(input)) {
87
+ // Single delegate → register as "(default)"
88
+ registry.register(DEFAULT_DRIVER_ID, input);
89
+ } else {
90
+ // Map of delegates → register each
91
+ for (const [id, delegate] of Object.entries(input)) {
92
+ registry.register(id, delegate);
93
+ }
94
+ // Ensure there's a default if not explicitly provided
95
+ if (!registry.has(DEFAULT_DRIVER_ID) && registry.size() > 0) {
96
+ // If no explicit "(default)", use the first one as default
97
+ const firstId = Object.keys(input)[0];
98
+ console.warn(
99
+ `[DriverRegistry] No "${DEFAULT_DRIVER_ID}" driver provided. ` +
100
+ `Using "${firstId}" as the default.`
101
+ );
102
+ registry.register(DEFAULT_DRIVER_ID, input[firstId]);
103
+ }
104
+ }
105
+
106
+ return registry;
107
+ }
108
+
109
+ register(id: string, delegate: DataDriver): void {
110
+ if (this.delegates.has(id)) {
111
+ console.warn(`[DriverRegistry] Overwriting driver with id "${id}"`);
112
+ }
113
+ this.delegates.set(id, delegate);
114
+ }
115
+
116
+ getDefault(): DataDriver {
117
+ const delegate = this.delegates.get(DEFAULT_DRIVER_ID);
118
+ if (!delegate) {
119
+ throw new Error(
120
+ "[DriverRegistry] No default driver registered. " +
121
+ `Register one with id "${DEFAULT_DRIVER_ID}" or pass a single DataDriver.`
122
+ );
123
+ }
124
+ return delegate;
125
+ }
126
+
127
+ get(id: string | undefined | null): DataDriver | undefined {
128
+ if (id === undefined || id === null) {
129
+ return this.delegates.get(DEFAULT_DRIVER_ID);
130
+ }
131
+ return this.delegates.get(id);
132
+ }
133
+
134
+ getOrDefault(id: string | undefined | null): DataDriver {
135
+ // If no ID specified, return default
136
+ if (id === undefined || id === null) {
137
+ return this.getDefault();
138
+ }
139
+
140
+ // Try to get by ID
141
+ const delegate = this.delegates.get(id);
142
+ if (delegate) {
143
+ return delegate;
144
+ }
145
+
146
+ // Fallback to default with warning
147
+ console.warn(
148
+ `[DriverRegistry] Driver "${id}" not found, falling back to "${DEFAULT_DRIVER_ID}"`
149
+ );
150
+ return this.getDefault();
151
+ }
152
+
153
+ has(id: string): boolean {
154
+ return this.delegates.has(id);
155
+ }
156
+
157
+ list(): string[] {
158
+ return Array.from(this.delegates.keys());
159
+ }
160
+
161
+ size(): number {
162
+ return this.delegates.size;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Type guard to check if an object is a DataDriver
168
+ */
169
+ function isDataDriverDelegate(obj: unknown): obj is DataDriver {
170
+ if (typeof obj !== "object" || obj === null) {
171
+ return false;
172
+ }
173
+ const delegate = obj as DataDriver;
174
+ // Check for required DataDriver properties
175
+ return (
176
+ typeof delegate.key === "string" &&
177
+ typeof delegate.fetchCollection === "function" &&
178
+ typeof delegate.fetchEntity === "function" &&
179
+ typeof delegate.saveEntity === "function" &&
180
+ typeof delegate.deleteEntity === "function"
181
+ );
182
+ }
@@ -0,0 +1,28 @@
1
+ import { rebase, _initRebase } from "./singleton";
2
+ import type { RebaseClient } from "@rebasepro/types";
3
+
4
+ describe("rebase singleton", () => {
5
+ beforeEach(() => {
6
+ // Reset the singleton before each test
7
+ // By calling _initRebase with null (cast to bypass type checking for the reset)
8
+ _initRebase(null as unknown as RebaseClient);
9
+ });
10
+
11
+ it("should throw an error if accessed before initialization", () => {
12
+ expect(() => rebase.data).toThrow(
13
+ "rebase.data: server not initialized yet. The singleton is available after Rebase starts — don't call it at import time."
14
+ );
15
+ });
16
+
17
+ it("should return the correctly initialized instance properties", () => {
18
+ const mockClient = {
19
+ data: { test: "mockData" },
20
+ auth: { test: "mockAuth" }
21
+ } as unknown as RebaseClient;
22
+
23
+ _initRebase(mockClient);
24
+
25
+ expect(rebase.data).toEqual({ test: "mockData" });
26
+ expect(rebase.auth).toEqual({ test: "mockAuth" });
27
+ });
28
+ });
@@ -0,0 +1,70 @@
1
+ import type { RebaseClient } from "@rebasepro/types";
2
+
3
+ let _instance: RebaseClient | null = null;
4
+
5
+ /**
6
+ * @internal Called once during server initialization to set the backing instance.
7
+ * This is invoked by `initializeRebaseBackend()` — never call it manually.
8
+ */
9
+ export function _initRebase(client: RebaseClient): void {
10
+ _instance = client;
11
+ }
12
+
13
+ /**
14
+ * @internal Allows overriding the underlying instance for unit testing.
15
+ * Throws an error if used in a non-test environment to prevent production abuse.
16
+ */
17
+ export function _setRebaseMock(mockInstance: Partial<RebaseClient>): void {
18
+ if (process.env.NODE_ENV !== "test") {
19
+ throw new Error("_setRebaseMock can only be called in a test environment (NODE_ENV=test).");
20
+ }
21
+ _instance = { ...(_instance || {} as RebaseClient),
22
+ ...mockInstance } as RebaseClient;
23
+ }
24
+
25
+ /**
26
+ * @internal Resets the singleton instance, useful for afterEach() in test suites.
27
+ */
28
+ export function _resetRebaseMock(): void {
29
+ if (process.env.NODE_ENV !== "test") {
30
+ throw new Error("_resetRebaseMock can only be called in a test environment.");
31
+ }
32
+ _instance = null;
33
+ }
34
+
35
+ /**
36
+ * The server-side Rebase singleton.
37
+ *
38
+ * Initialized automatically during server startup. Provides access to all
39
+ * app-scoped services: **data**, **auth**, **storage**, and **email**.
40
+ *
41
+ * `rebase.data` runs with **admin privileges** (no RLS). For user-scoped
42
+ * queries inside request handlers, continue using the handler's context
43
+ * or the RLS-scoped driver.
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * import { rebase } from "@rebasepro/server-core";
48
+ *
49
+ * // In a Hono handler, cron job, hook, or service file:
50
+ * await rebase.email?.send({ to: "admin@co.com", subject: "Alert", html: "<p>Hi</p>" });
51
+ * const jobs = await rebase.data.jobs.find({ limit: 10 });
52
+ * ```
53
+ */
54
+ export const rebase: RebaseClient = new Proxy({} as RebaseClient, {
55
+ get(_, prop) {
56
+ if (!_instance) {
57
+ throw new Error(
58
+ `rebase.${String(prop)}: server not initialized yet. ` +
59
+ "The singleton is available after Rebase starts — don't call it at import time."
60
+ );
61
+ }
62
+ return _instance[prop as keyof RebaseClient];
63
+ },
64
+ set(_, prop) {
65
+ throw new Error(
66
+ `Cannot set rebase.${String(prop)} directly. ` +
67
+ "The singleton is read-only. Use _initRebase() during server startup."
68
+ );
69
+ }
70
+ });