@rebasepro/server-core 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/dist/{server-core/src/api → api}/errors.d.ts +5 -2
  2. package/dist/{server-core/src/api → api}/rest/api-generator.d.ts +8 -2
  3. package/dist/{server-core/src/api → api}/types.d.ts +2 -0
  4. package/dist/auth/admin-user-ops.d.ts +79 -0
  5. package/dist/{server-core/src/auth → auth}/api-keys/index.d.ts +2 -2
  6. package/dist/{server-core/src/auth → auth}/auth-hooks.d.ts +37 -9
  7. package/dist/{server-core/src/auth → auth}/builtin-auth-adapter.d.ts +4 -4
  8. package/dist/{server-core/src/auth → auth}/index.d.ts +5 -2
  9. package/dist/auth/mfa-routes.d.ts +6 -0
  10. package/dist/auth/reset-password-admin.d.ts +29 -0
  11. package/dist/auth/session-routes.d.ts +25 -0
  12. package/dist/backend-CIxN4FVm.js +15 -0
  13. package/dist/backend-CIxN4FVm.js.map +1 -0
  14. package/dist/chunk-Dze3rakg.js +42 -0
  15. package/dist/{server-core/src/cron → cron}/cron-scheduler.d.ts +1 -1
  16. package/dist/dist-CZKP-Xz4.js +832 -0
  17. package/dist/dist-CZKP-Xz4.js.map +1 -0
  18. package/dist/env.d.ts +102 -0
  19. package/dist/from-VbwD7xRf.js +3849 -0
  20. package/dist/from-VbwD7xRf.js.map +1 -0
  21. package/dist/{server-core/src/index.d.ts → index.d.ts} +1 -0
  22. package/dist/index.es.js +60867 -50462
  23. package/dist/index.es.js.map +1 -1
  24. package/dist/index.umd.js +73151 -51298
  25. package/dist/index.umd.js.map +1 -1
  26. package/dist/init/docs.d.ts +4 -0
  27. package/dist/init/health.d.ts +2 -0
  28. package/dist/init/middlewares.d.ts +10 -0
  29. package/dist/init/shutdown.d.ts +11 -0
  30. package/dist/init/storage.d.ts +5 -0
  31. package/dist/{server-core/src/init.d.ts → init.d.ts} +4 -4
  32. package/dist/jwt-DHcQRGC3.js +4168 -0
  33. package/dist/jwt-DHcQRGC3.js.map +1 -0
  34. package/dist/logger-BYU66ENZ.js +94 -0
  35. package/dist/logger-BYU66ENZ.js.map +1 -0
  36. package/dist/ms-BeBSuOXN.js +125 -0
  37. package/dist/ms-BeBSuOXN.js.map +1 -0
  38. package/dist/multipart-parser-CedBDOeC.js +299 -0
  39. package/dist/multipart-parser-CedBDOeC.js.map +1 -0
  40. package/dist/src-COaj0G3P.js +1182 -0
  41. package/dist/src-COaj0G3P.js.map +1 -0
  42. package/dist/{server-core/src/storage → storage}/image-transform.d.ts +3 -1
  43. package/dist/utils/request-id.d.ts +4 -0
  44. package/package.json +29 -29
  45. package/src/api/collections_for_test/callbacks_test_collection.ts +7 -6
  46. package/src/api/errors.ts +75 -19
  47. package/src/api/graphql/graphql-schema-generator.ts +15 -10
  48. package/src/api/logs-routes.ts +5 -2
  49. package/src/api/rest/api-generator-count.test.ts +21 -10
  50. package/src/api/rest/api-generator.ts +83 -24
  51. package/src/api/rest/query-parser.ts +18 -12
  52. package/src/api/server.ts +12 -1
  53. package/src/api/types.ts +2 -0
  54. package/src/auth/adapter-middleware.ts +17 -10
  55. package/src/auth/admin-user-ops.ts +236 -0
  56. package/src/auth/api-keys/api-key-middleware.ts +15 -9
  57. package/src/auth/api-keys/api-key-permission-guard.ts +1 -1
  58. package/src/auth/api-keys/api-key-routes.ts +3 -3
  59. package/src/auth/api-keys/api-key-store.ts +14 -8
  60. package/src/auth/api-keys/index.ts +2 -2
  61. package/src/auth/apple-oauth.ts +4 -3
  62. package/src/auth/auth-hooks.ts +50 -10
  63. package/src/auth/bitbucket-oauth.ts +5 -4
  64. package/src/auth/builtin-auth-adapter.ts +60 -39
  65. package/src/auth/custom-auth-adapter.ts +4 -5
  66. package/src/auth/discord-oauth.ts +5 -4
  67. package/src/auth/facebook-oauth.ts +5 -4
  68. package/src/auth/github-oauth.ts +6 -5
  69. package/src/auth/gitlab-oauth.ts +5 -4
  70. package/src/auth/google-oauth.ts +2 -1
  71. package/src/auth/index.ts +6 -2
  72. package/src/auth/jwt.ts +5 -4
  73. package/src/auth/linkedin-oauth.ts +4 -3
  74. package/src/auth/mfa-routes.ts +299 -0
  75. package/src/auth/mfa.ts +2 -1
  76. package/src/auth/microsoft-oauth.ts +5 -4
  77. package/src/auth/middleware.ts +5 -4
  78. package/src/auth/rate-limiter.ts +1 -1
  79. package/src/auth/reset-password-admin.ts +144 -0
  80. package/src/auth/rls-scope.ts +1 -1
  81. package/src/auth/routes.ts +52 -596
  82. package/src/auth/session-routes.ts +341 -0
  83. package/src/auth/slack-oauth.ts +6 -5
  84. package/src/auth/spotify-oauth.ts +5 -4
  85. package/src/auth/twitter-oauth.ts +4 -3
  86. package/src/collections/loader.ts +5 -4
  87. package/src/cron/cron-scheduler.test.ts +23 -11
  88. package/src/cron/cron-scheduler.ts +14 -8
  89. package/src/cron/cron-store.ts +1 -1
  90. package/src/email/smtp-email-service.ts +3 -2
  91. package/src/env.ts +11 -10
  92. package/src/index.ts +1 -0
  93. package/src/init/docs.ts +47 -0
  94. package/src/init/health.ts +37 -0
  95. package/src/init/middlewares.ts +61 -0
  96. package/src/init/shutdown.ts +56 -0
  97. package/src/init/storage.ts +57 -0
  98. package/src/init.ts +85 -279
  99. package/src/serve-spa.ts +12 -5
  100. package/src/services/driver-registry.ts +4 -3
  101. package/src/storage/S3StorageController.ts +1 -2
  102. package/src/storage/image-transform.ts +25 -10
  103. package/src/storage/routes.ts +30 -11
  104. package/src/storage/storage-registry.ts +4 -3
  105. package/src/storage/tus-handler.ts +12 -12
  106. package/src/utils/request-id.ts +40 -0
  107. package/src/utils/request-logger.ts +6 -0
  108. package/test/api-generator.test.ts +90 -2
  109. package/test/api-key-permission-guard.test.ts +24 -12
  110. package/test/auth-routes.test.ts +5 -3
  111. package/test/backend-hooks-data.test.ts +99 -30
  112. package/test/custom-auth-adapter.test.ts +16 -15
  113. package/test/email-templates.test.ts +10 -5
  114. package/test/env.test.ts +10 -10
  115. package/test/function-loader.test.ts +7 -4
  116. package/test/graphql-schema-generator.test.ts +554 -0
  117. package/test/jwt-security.test.ts +1 -1
  118. package/test/query-parser.test.ts +0 -1
  119. package/test/reset-password-admin.test.ts +113 -0
  120. package/test/singleton.test.ts +5 -5
  121. package/test/smtp-email-service.test.ts +21 -21
  122. package/test/webhook-service.test.ts +22 -11
  123. package/tsconfig.json +2 -0
  124. package/tsconfig.prod.json +3 -0
  125. package/vite.config.ts +5 -5
  126. package/dist/common/src/collections/CollectionRegistry.d.ts +0 -56
  127. package/dist/common/src/collections/default-collections.d.ts +0 -9
  128. package/dist/common/src/collections/index.d.ts +0 -2
  129. package/dist/common/src/data/buildRebaseData.d.ts +0 -14
  130. package/dist/common/src/data/query_builder.d.ts +0 -55
  131. package/dist/common/src/index.d.ts +0 -4
  132. package/dist/common/src/util/builders.d.ts +0 -57
  133. package/dist/common/src/util/callbacks.d.ts +0 -6
  134. package/dist/common/src/util/collections.d.ts +0 -11
  135. package/dist/common/src/util/common.d.ts +0 -2
  136. package/dist/common/src/util/conditions.d.ts +0 -26
  137. package/dist/common/src/util/entities.d.ts +0 -58
  138. package/dist/common/src/util/enums.d.ts +0 -3
  139. package/dist/common/src/util/index.d.ts +0 -16
  140. package/dist/common/src/util/navigation_from_path.d.ts +0 -34
  141. package/dist/common/src/util/navigation_utils.d.ts +0 -20
  142. package/dist/common/src/util/parent_references_from_path.d.ts +0 -6
  143. package/dist/common/src/util/paths.d.ts +0 -14
  144. package/dist/common/src/util/permissions.d.ts +0 -14
  145. package/dist/common/src/util/references.d.ts +0 -2
  146. package/dist/common/src/util/relations.d.ts +0 -22
  147. package/dist/common/src/util/resolutions.d.ts +0 -72
  148. package/dist/common/src/util/storage.d.ts +0 -24
  149. package/dist/index-Cr1D21av.js +0 -49
  150. package/dist/index-Cr1D21av.js.map +0 -1
  151. package/dist/server-core/src/auth/admin-routes.d.ts +0 -27
  152. package/dist/server-core/src/env.d.ts +0 -137
  153. package/dist/types/src/controllers/analytics_controller.d.ts +0 -7
  154. package/dist/types/src/controllers/auth.d.ts +0 -104
  155. package/dist/types/src/controllers/client.d.ts +0 -168
  156. package/dist/types/src/controllers/collection_registry.d.ts +0 -46
  157. package/dist/types/src/controllers/customization_controller.d.ts +0 -60
  158. package/dist/types/src/controllers/data.d.ts +0 -207
  159. package/dist/types/src/controllers/data_driver.d.ts +0 -218
  160. package/dist/types/src/controllers/database_admin.d.ts +0 -11
  161. package/dist/types/src/controllers/dialogs_controller.d.ts +0 -36
  162. package/dist/types/src/controllers/effective_role.d.ts +0 -4
  163. package/dist/types/src/controllers/email.d.ts +0 -36
  164. package/dist/types/src/controllers/index.d.ts +0 -18
  165. package/dist/types/src/controllers/local_config_persistence.d.ts +0 -20
  166. package/dist/types/src/controllers/navigation.d.ts +0 -225
  167. package/dist/types/src/controllers/registry.d.ts +0 -63
  168. package/dist/types/src/controllers/side_dialogs_controller.d.ts +0 -67
  169. package/dist/types/src/controllers/side_entity_controller.d.ts +0 -97
  170. package/dist/types/src/controllers/snackbar.d.ts +0 -24
  171. package/dist/types/src/controllers/storage.d.ts +0 -171
  172. package/dist/types/src/index.d.ts +0 -4
  173. package/dist/types/src/rebase_context.d.ts +0 -122
  174. package/dist/types/src/types/auth_adapter.d.ts +0 -301
  175. package/dist/types/src/types/backend.d.ts +0 -571
  176. package/dist/types/src/types/backend_hooks.d.ts +0 -172
  177. package/dist/types/src/types/builders.d.ts +0 -15
  178. package/dist/types/src/types/chips.d.ts +0 -5
  179. package/dist/types/src/types/collections.d.ts +0 -961
  180. package/dist/types/src/types/component_ref.d.ts +0 -47
  181. package/dist/types/src/types/cron.d.ts +0 -102
  182. package/dist/types/src/types/data_source.d.ts +0 -64
  183. package/dist/types/src/types/database_adapter.d.ts +0 -94
  184. package/dist/types/src/types/entities.d.ts +0 -145
  185. package/dist/types/src/types/entity_actions.d.ts +0 -104
  186. package/dist/types/src/types/entity_callbacks.d.ts +0 -173
  187. package/dist/types/src/types/entity_link_builder.d.ts +0 -7
  188. package/dist/types/src/types/entity_overrides.d.ts +0 -10
  189. package/dist/types/src/types/entity_views.d.ts +0 -87
  190. package/dist/types/src/types/export_import.d.ts +0 -21
  191. package/dist/types/src/types/formex.d.ts +0 -40
  192. package/dist/types/src/types/index.d.ts +0 -28
  193. package/dist/types/src/types/locales.d.ts +0 -4
  194. package/dist/types/src/types/modify_collections.d.ts +0 -5
  195. package/dist/types/src/types/plugins.d.ts +0 -282
  196. package/dist/types/src/types/properties.d.ts +0 -1173
  197. package/dist/types/src/types/property_config.d.ts +0 -74
  198. package/dist/types/src/types/relations.d.ts +0 -336
  199. package/dist/types/src/types/slots.d.ts +0 -262
  200. package/dist/types/src/types/translations.d.ts +0 -900
  201. package/dist/types/src/types/user_management_delegate.d.ts +0 -86
  202. package/dist/types/src/types/websockets.d.ts +0 -78
  203. package/dist/types/src/users/index.d.ts +0 -1
  204. package/dist/types/src/users/user.d.ts +0 -50
  205. package/src/auth/admin-routes.ts +0 -534
  206. package/test/admin-routes.test.ts +0 -544
  207. package/test/backend-hooks-admin.test.ts +0 -388
  208. /package/dist/{server-core/src/api → api}/ast-schema-editor.d.ts +0 -0
  209. /package/dist/{server-core/src/api → api}/collections_for_test/callbacks_test_collection.d.ts +0 -0
  210. /package/dist/{server-core/src/api → api}/graphql/graphql-schema-generator.d.ts +0 -0
  211. /package/dist/{server-core/src/api → api}/graphql/index.d.ts +0 -0
  212. /package/dist/{server-core/src/api → api}/index.d.ts +0 -0
  213. /package/dist/{server-core/src/api → api}/logs-routes.d.ts +0 -0
  214. /package/dist/{server-core/src/api → api}/openapi-generator.d.ts +0 -0
  215. /package/dist/{server-core/src/api → api}/rest/index.d.ts +0 -0
  216. /package/dist/{server-core/src/api → api}/rest/query-parser.d.ts +0 -0
  217. /package/dist/{server-core/src/api → api}/schema-editor-routes.d.ts +0 -0
  218. /package/dist/{server-core/src/api → api}/server.d.ts +0 -0
  219. /package/dist/{server-core/src/auth → auth}/adapter-middleware.d.ts +0 -0
  220. /package/dist/{server-core/src/auth → auth}/api-keys/api-key-middleware.d.ts +0 -0
  221. /package/dist/{server-core/src/auth → auth}/api-keys/api-key-permission-guard.d.ts +0 -0
  222. /package/dist/{server-core/src/auth → auth}/api-keys/api-key-routes.d.ts +0 -0
  223. /package/dist/{server-core/src/auth → auth}/api-keys/api-key-store.d.ts +0 -0
  224. /package/dist/{server-core/src/auth → auth}/api-keys/api-key-types.d.ts +0 -0
  225. /package/dist/{server-core/src/auth → auth}/apple-oauth.d.ts +0 -0
  226. /package/dist/{server-core/src/auth → auth}/bitbucket-oauth.d.ts +0 -0
  227. /package/dist/{server-core/src/auth → auth}/crypto-utils.d.ts +0 -0
  228. /package/dist/{server-core/src/auth → auth}/custom-auth-adapter.d.ts +0 -0
  229. /package/dist/{server-core/src/auth → auth}/discord-oauth.d.ts +0 -0
  230. /package/dist/{server-core/src/auth → auth}/facebook-oauth.d.ts +0 -0
  231. /package/dist/{server-core/src/auth → auth}/github-oauth.d.ts +0 -0
  232. /package/dist/{server-core/src/auth → auth}/gitlab-oauth.d.ts +0 -0
  233. /package/dist/{server-core/src/auth → auth}/google-oauth.d.ts +0 -0
  234. /package/dist/{server-core/src/auth → auth}/interfaces.d.ts +0 -0
  235. /package/dist/{server-core/src/auth → auth}/jwt.d.ts +0 -0
  236. /package/dist/{server-core/src/auth → auth}/linkedin-oauth.d.ts +0 -0
  237. /package/dist/{server-core/src/auth → auth}/mfa.d.ts +0 -0
  238. /package/dist/{server-core/src/auth → auth}/microsoft-oauth.d.ts +0 -0
  239. /package/dist/{server-core/src/auth → auth}/middleware.d.ts +0 -0
  240. /package/dist/{server-core/src/auth → auth}/password.d.ts +0 -0
  241. /package/dist/{server-core/src/auth → auth}/rate-limiter.d.ts +0 -0
  242. /package/dist/{server-core/src/auth → auth}/rls-scope.d.ts +0 -0
  243. /package/dist/{server-core/src/auth → auth}/routes.d.ts +0 -0
  244. /package/dist/{server-core/src/auth → auth}/slack-oauth.d.ts +0 -0
  245. /package/dist/{server-core/src/auth → auth}/spotify-oauth.d.ts +0 -0
  246. /package/dist/{server-core/src/auth → auth}/twitter-oauth.d.ts +0 -0
  247. /package/dist/{server-core/src/collections → collections}/BackendCollectionRegistry.d.ts +0 -0
  248. /package/dist/{server-core/src/collections → collections}/loader.d.ts +0 -0
  249. /package/dist/{server-core/src/cron → cron}/cron-loader.d.ts +0 -0
  250. /package/dist/{server-core/src/cron → cron}/cron-routes.d.ts +0 -0
  251. /package/dist/{server-core/src/cron → cron}/cron-store.d.ts +0 -0
  252. /package/dist/{server-core/src/cron → cron}/index.d.ts +0 -0
  253. /package/dist/{server-core/src/db → db}/interfaces.d.ts +0 -0
  254. /package/dist/{server-core/src/email → email}/index.d.ts +0 -0
  255. /package/dist/{server-core/src/email → email}/smtp-email-service.d.ts +0 -0
  256. /package/dist/{server-core/src/email → email}/templates.d.ts +0 -0
  257. /package/dist/{server-core/src/email → email}/types.d.ts +0 -0
  258. /package/dist/{server-core/src/functions → functions}/function-loader.d.ts +0 -0
  259. /package/dist/{server-core/src/functions → functions}/function-routes.d.ts +0 -0
  260. /package/dist/{server-core/src/functions → functions}/index.d.ts +0 -0
  261. /package/dist/{server-core/src/history → history}/history-routes.d.ts +0 -0
  262. /package/dist/{server-core/src/history → history}/index.d.ts +0 -0
  263. /package/dist/{server-core/src/serve-spa.d.ts → serve-spa.d.ts} +0 -0
  264. /package/dist/{server-core/src/services → services}/driver-registry.d.ts +0 -0
  265. /package/dist/{server-core/src/services → services}/webhook-service.d.ts +0 -0
  266. /package/dist/{server-core/src/singleton.d.ts → singleton.d.ts} +0 -0
  267. /package/dist/{server-core/src/storage → storage}/LocalStorageController.d.ts +0 -0
  268. /package/dist/{server-core/src/storage → storage}/S3StorageController.d.ts +0 -0
  269. /package/dist/{server-core/src/storage → storage}/index.d.ts +0 -0
  270. /package/dist/{server-core/src/storage → storage}/routes.d.ts +0 -0
  271. /package/dist/{server-core/src/storage → storage}/storage-registry.d.ts +0 -0
  272. /package/dist/{server-core/src/storage → storage}/tus-handler.d.ts +0 -0
  273. /package/dist/{server-core/src/storage → storage}/types.d.ts +0 -0
  274. /package/dist/{server-core/src/types → types}/index.d.ts +0 -0
  275. /package/dist/{server-core/src/utils → utils}/dev-port.d.ts +0 -0
  276. /package/dist/{server-core/src/utils → utils}/logger.d.ts +0 -0
  277. /package/dist/{server-core/src/utils → utils}/logging.d.ts +0 -0
  278. /package/dist/{server-core/src/utils → utils}/request-logger.d.ts +0 -0
  279. /package/dist/{server-core/src/utils → utils}/sql.d.ts +0 -0
@@ -1,5 +1,6 @@
1
1
  import { createTransport, Transporter } from "nodemailer";
2
2
  import { EmailService, EmailSendOptions, EmailConfig } from "./types";
3
+ import { logger } from "../utils/logger";
3
4
 
4
5
  /**
5
6
  * Safely parse a hostname from a URL string
@@ -90,7 +91,7 @@ export class SMTPEmailService implements EmailService {
90
91
  });
91
92
  } catch (error: unknown) {
92
93
  const message = error instanceof Error ? error.message : String(error);
93
- console.error("Failed to send email:", message);
94
+ logger.error("Failed to send email", { detail: message });
94
95
  throw new Error(`Failed to send email: ${message}`);
95
96
  }
96
97
  }
@@ -108,7 +109,7 @@ export class SMTPEmailService implements EmailService {
108
109
  return true;
109
110
  } catch (error: unknown) {
110
111
  const message = error instanceof Error ? error.message : String(error);
111
- console.error("SMTP connection verification failed:", message);
112
+ logger.error("SMTP connection verification failed", { detail: message });
112
113
  return false;
113
114
  }
114
115
  }
package/src/env.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import * as crypto from "crypto";
3
+ import { logger } from "./utils/logger";
3
4
 
4
5
  /**
5
6
  * Generate a cryptographically secure random secret (hex-encoded).
@@ -112,7 +113,7 @@ const rebaseEnvSchema = z.object({
112
113
  S3_ACCESS_KEY_ID: z.string().optional(),
113
114
  S3_SECRET_ACCESS_KEY: z.string().optional(),
114
115
  S3_ENDPOINT: z.string().url().optional(),
115
- S3_FORCE_PATH_STYLE: optionalBoolString,
116
+ S3_FORCE_PATH_STYLE: optionalBoolString
116
117
  });
117
118
 
118
119
  /** Inferred type of the validated environment. */
@@ -157,8 +158,8 @@ export type RebaseEnv = z.infer<typeof rebaseEnvSchema>;
157
158
  * ```
158
159
  */
159
160
  export function loadEnv(): RebaseEnv;
160
- export function loadEnv<E extends z.AnyZodObject>(options: { extend: E }): RebaseEnv & z.infer<E>;
161
- export function loadEnv(options?: { extend?: z.AnyZodObject }): Record<string, unknown> {
161
+ export function loadEnv<E extends z.ZodObject<z.ZodRawShape>>(options: { extend: E }): RebaseEnv & z.infer<E>;
162
+ export function loadEnv(options?: { extend?: z.ZodObject<z.ZodRawShape> }): Record<string, unknown> {
162
163
  // Auto-generate dev secrets before validation so the Zod schema sees valid values.
163
164
  const isProduction = process.env.NODE_ENV === "production";
164
165
  const autoGeneratedSecrets: string[] = [];
@@ -186,15 +187,15 @@ export function loadEnv(options?: { extend?: z.AnyZodObject }): Record<string, u
186
187
  ctx.addIssue({
187
188
  code: z.ZodIssueCode.custom,
188
189
  message: "CORS_ORIGINS or FRONTEND_URL must be set in production to secure the API.",
189
- path: ["CORS_ORIGINS"],
190
+ path: ["CORS_ORIGINS"]
190
191
  });
191
192
  }
192
193
  if (d.NODE_ENV === "production" && autoGeneratedSecrets.length > 0) {
193
194
  ctx.addIssue({
194
195
  code: z.ZodIssueCode.custom,
195
196
  message: `${autoGeneratedSecrets.join(", ")} must be explicitly set in production. ` +
196
- `Do not rely on auto-generated secrets outside development.`,
197
- path: [autoGeneratedSecrets[0]],
197
+ "Do not rely on auto-generated secrets outside development.",
198
+ path: [autoGeneratedSecrets[0]]
198
199
  });
199
200
  }
200
201
  if (d.NODE_ENV === "production" && !d.ALLOW_LOCALHOST_IN_PRODUCTION) {
@@ -204,7 +205,7 @@ export function loadEnv(options?: { extend?: z.AnyZodObject }): Record<string, u
204
205
  ctx.addIssue({
205
206
  code: z.ZodIssueCode.custom,
206
207
  message: `Environment variable ${key} contains a local/loopback URL or host "${value}". Deployed instances must not connect to localhost.`,
207
- path: [key],
208
+ path: [key]
208
209
  });
209
210
  }
210
211
  }
@@ -215,10 +216,10 @@ export function loadEnv(options?: { extend?: z.AnyZodObject }): Record<string, u
215
216
 
216
217
  // Warn after successful parse so the server still starts in dev.
217
218
  if (autoGeneratedSecrets.length > 0) {
218
- console.warn(
219
+ logger.warn(
219
220
  `⚠️ Auto-generated secrets for: ${autoGeneratedSecrets.join(", ")}. ` +
220
- `These are ephemeral — existing tokens will be invalidated on restart. ` +
221
- `Set them explicitly in .env for persistent sessions.`,
221
+ "These are ephemeral — existing tokens will be invalidated on restart. " +
222
+ "Set them explicitly in .env for persistent sessions."
222
223
  );
223
224
  }
224
225
 
package/src/index.ts CHANGED
@@ -44,6 +44,7 @@ export * from "./storage";
44
44
  export * from "./utils/logging";
45
45
  export * from "./utils/logger";
46
46
  export * from "./utils/request-logger";
47
+ export * from "./utils/request-id";
47
48
  export * from "./utils/sql";
48
49
 
49
50
  // Entity history
@@ -0,0 +1,47 @@
1
+ import { Hono } from "hono";
2
+ import { EntityCollection } from "@rebasepro/types";
3
+ import { HonoEnv } from "../api/types";
4
+ import { logger } from "../utils/logger";
5
+
6
+ export async function mountOpenApiDocs(
7
+ app: Hono<HonoEnv>,
8
+ basePath: string,
9
+ enableSwagger: boolean | undefined,
10
+ activeCollections: EntityCollection[],
11
+ requireAuth: boolean
12
+ ): Promise<void> {
13
+ if (enableSwagger === false || activeCollections.length === 0) {
14
+ return;
15
+ }
16
+
17
+ const { generateOpenApiSpec } = await import("../api/openapi-generator");
18
+
19
+ app.get(`${basePath}/docs`, (c) => {
20
+ const spec = generateOpenApiSpec(activeCollections, {
21
+ basePath,
22
+ requireAuth
23
+ });
24
+ return c.json(spec);
25
+ });
26
+
27
+ if (process.env.NODE_ENV !== "production") {
28
+ app.get(`${basePath}/swagger`, (c) => {
29
+ return c.html(`<!DOCTYPE html>
30
+ <html>
31
+ <head>
32
+ <title>Rebase API Documentation</title>
33
+ <meta charset="utf-8"/>
34
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
35
+ <link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css"/>
36
+ <style>body{margin:0;padding:0;}</style>
37
+ </head>
38
+ <body>
39
+ <div id="swagger-ui"></div>
40
+ <script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
41
+ <script>SwaggerUIBundle({ url: '${basePath}/docs', dom_id: '#swagger-ui' });</script>
42
+ </body>
43
+ </html>`);
44
+ });
45
+ logger.info("Swagger UI available", { path: `${basePath}/swagger` });
46
+ }
47
+ }
@@ -0,0 +1,37 @@
1
+ import { DataDriver, HealthCheckResult, isSQLAdmin } from "@rebasepro/types";
2
+ import { logger } from "../utils/logger";
3
+
4
+ export function createHealthCheck(defaultDriver: DataDriver): () => Promise<HealthCheckResult> {
5
+ return async (): Promise<HealthCheckResult> => {
6
+ const start = performance.now();
7
+ try {
8
+ const admin = defaultDriver.admin;
9
+ if (isSQLAdmin(admin)) {
10
+ await admin.executeSql("SELECT 1");
11
+ } else {
12
+ await defaultDriver.fetchCollection({
13
+ path: "__health_check_nonexistent__",
14
+ limit: 1
15
+ });
16
+ }
17
+ const latencyMs = Math.round(performance.now() - start);
18
+ return {
19
+ healthy: true,
20
+ latencyMs
21
+ };
22
+ } catch (error: unknown) {
23
+ const latencyMs = Math.round(performance.now() - start);
24
+ logger.error("Health check failed", {
25
+ error: error instanceof Error ? error : new Error(String(error)),
26
+ latencyMs
27
+ });
28
+ return {
29
+ healthy: false,
30
+ latencyMs,
31
+ details: {
32
+ error: error instanceof Error ? error.message : String(error)
33
+ }
34
+ };
35
+ }
36
+ };
37
+ }
@@ -0,0 +1,61 @@
1
+ import { Hono } from "hono";
2
+ import { bodyLimit } from "hono/body-limit";
3
+ import { csrf } from "hono/csrf";
4
+ import { HonoEnv } from "../api/types";
5
+ import { requestId } from "../utils/request-id";
6
+ import { requestLogger } from "../utils/request-logger";
7
+ import { logger } from "../utils/logger";
8
+
9
+ interface MiddlewareConfig {
10
+ maxBodySize?: number;
11
+ csrf?: {
12
+ origin: string | string[] | ((origin: string) => boolean);
13
+ };
14
+ }
15
+
16
+ export function configureMiddlewares(
17
+ app: Hono<HonoEnv>,
18
+ basePath: string,
19
+ isProduction: boolean,
20
+ config: MiddlewareConfig
21
+ ): void {
22
+ // Request ID (correlation)
23
+ app.use(`${basePath}/*`, requestId());
24
+
25
+ // Request Body Size Limit
26
+ const maxBodySize = config.maxBodySize ?? 10 * 1024 * 1024; // 10MB default
27
+ if (maxBodySize > 0) {
28
+ app.use(`${basePath}/*`, bodyLimit({
29
+ maxSize: maxBodySize,
30
+ onError: (c) => {
31
+ return c.json({
32
+ error: {
33
+ message: `Request body too large. Maximum size is ${Math.round(maxBodySize / 1024 / 1024)}MB.`,
34
+ code: "PAYLOAD_TOO_LARGE"
35
+ }
36
+ }, 413);
37
+ }
38
+ }));
39
+ logger.info("Request body limit configured", { maxSizeMB: Math.round(maxBodySize / 1024 / 1024) });
40
+ }
41
+
42
+ // CSRF Protection (opt-in)
43
+ if (config.csrf?.origin) {
44
+ app.use(`${basePath}/*`, csrf({
45
+ origin: config.csrf.origin
46
+ }));
47
+ logger.info("CSRF protection enabled");
48
+ }
49
+
50
+ // CORS Warning
51
+ if (!isProduction && !process.env.CORS_ORIGINS && !process.env.FRONTEND_URL) {
52
+ logger.warn(
53
+ "No CORS configuration detected (CORS_ORIGINS / FRONTEND_URL not set). " +
54
+ "The API will accept requests from any origin. " +
55
+ "Set CORS_ORIGINS in your .env file to restrict access."
56
+ );
57
+ }
58
+
59
+ // Request Logging
60
+ app.use(`${basePath}/*`, requestLogger());
61
+ }
@@ -0,0 +1,56 @@
1
+ import { Server } from "http";
2
+ import { RealtimeProvider } from "@rebasepro/types";
3
+ import { logger } from "../utils/logger";
4
+
5
+ interface ShutdownConfig {
6
+ server: Server;
7
+ cronScheduler?: { stop(): void };
8
+ realtimeServices: Record<string, RealtimeProvider>;
9
+ }
10
+
11
+ export function createShutdown(config: ShutdownConfig): (timeoutMs?: number) => Promise<void> {
12
+ return (timeoutMs = 15_000): Promise<void> => {
13
+ return new Promise<void>((resolve) => {
14
+ (async () => {
15
+ logger.info("Shutting down Rebase Backend...");
16
+
17
+ // 1. Stop cron scheduler
18
+ if (config.cronScheduler) {
19
+ config.cronScheduler.stop();
20
+ logger.info("Cron scheduler stopped");
21
+ }
22
+
23
+ // 2. Tear down realtime services (LISTEN clients, debounce timers,
24
+ // subscriptions). Must happen BEFORE pool.end() so that pending
25
+ // timer callbacks don't fire against a closed pool.
26
+ for (const [key, rt] of Object.entries(config.realtimeServices)) {
27
+ try {
28
+ if (typeof rt.destroy === "function") {
29
+ await rt.destroy();
30
+ logger.info(`Realtime service "${key}" destroyed`);
31
+ } else if (typeof rt.stopListening === "function") {
32
+ await rt.stopListening();
33
+ logger.info(`Realtime service "${key}" LISTEN client stopped`);
34
+ }
35
+ } catch (err) {
36
+ logger.warn(`Error destroying realtime service "${key}":`, { error: err });
37
+ }
38
+ }
39
+
40
+ // 3. Close the HTTP server (stop accepting, drain in-flight)
41
+ config.server.close(() => {
42
+ logger.info("HTTP server closed");
43
+ resolve();
44
+ });
45
+
46
+ // 4. Force-resolve after timeout (unless disabled with 0)
47
+ if (timeoutMs > 0) {
48
+ setTimeout(() => {
49
+ logger.warn(`Forced shutdown after ${timeoutMs / 1000}s timeout`);
50
+ resolve();
51
+ }, timeoutMs).unref();
52
+ }
53
+ })();
54
+ });
55
+ };
56
+ }
@@ -0,0 +1,57 @@
1
+ import {
2
+ BackendStorageConfig,
3
+ createStorageController,
4
+ DEFAULT_STORAGE_ID,
5
+ DefaultStorageRegistry,
6
+ StorageController,
7
+ StorageRegistry
8
+ } from "../storage";
9
+ import { logger } from "../utils/logger";
10
+
11
+ export function initializeStorage(
12
+ storageConfig: BackendStorageConfig | StorageController | Record<string, BackendStorageConfig | StorageController> | undefined,
13
+ isProduction: boolean
14
+ ): { storageRegistry?: StorageRegistry; storageController?: StorageController } {
15
+ if (!storageConfig) return {};
16
+
17
+ logger.info("Configuring storage");
18
+ const controllers: Record<string, StorageController> = {};
19
+
20
+ const toController = (entry: BackendStorageConfig | StorageController, label: string): StorageController => {
21
+ if (typeof (entry as StorageController).putObject === "function") {
22
+ return entry as StorageController;
23
+ }
24
+ const conf = entry as BackendStorageConfig;
25
+ if (isProduction && conf.type === "local") {
26
+ logger.warn(`Storage backend "${label}" uses local filesystem in production. ` +
27
+ "Files will be lost on container restart. " +
28
+ "Configure S3-compatible storage or a custom StorageController.");
29
+ }
30
+ return createStorageController(conf);
31
+ };
32
+
33
+ if (
34
+ typeof storageConfig === "object" &&
35
+ ("type" in storageConfig || typeof (storageConfig as StorageController).putObject === "function")
36
+ ) {
37
+ controllers[DEFAULT_STORAGE_ID] = toController(
38
+ storageConfig as BackendStorageConfig | StorageController,
39
+ DEFAULT_STORAGE_ID
40
+ );
41
+ } else {
42
+ for (const [storageId, entry] of Object.entries(
43
+ storageConfig as Record<string, BackendStorageConfig | StorageController>
44
+ )) {
45
+ controllers[storageId] = toController(entry, storageId);
46
+ }
47
+ }
48
+
49
+ if (Object.keys(controllers).length > 0) {
50
+ const storageRegistry = DefaultStorageRegistry.create(controllers);
51
+ const storageController = storageRegistry.getDefault();
52
+ logger.info("Initialized storage backends", { count: Object.keys(controllers).length });
53
+ return { storageRegistry, storageController };
54
+ }
55
+
56
+ return {};
57
+ }