@rebasepro/server-core 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{server-core/src/api → api}/errors.d.ts +5 -2
- package/dist/{server-core/src/api → api}/rest/api-generator.d.ts +8 -2
- package/dist/{server-core/src/api → api}/types.d.ts +2 -0
- package/dist/auth/admin-user-ops.d.ts +79 -0
- package/dist/{server-core/src/auth → auth}/api-keys/index.d.ts +2 -2
- package/dist/{server-core/src/auth → auth}/auth-hooks.d.ts +37 -9
- package/dist/{server-core/src/auth → auth}/builtin-auth-adapter.d.ts +4 -4
- package/dist/{server-core/src/auth → auth}/index.d.ts +5 -2
- package/dist/auth/mfa-routes.d.ts +6 -0
- package/dist/auth/reset-password-admin.d.ts +29 -0
- package/dist/auth/session-routes.d.ts +25 -0
- package/dist/backend-CIxN4FVm.js +15 -0
- package/dist/backend-CIxN4FVm.js.map +1 -0
- package/dist/chunk-Dze3rakg.js +42 -0
- package/dist/{server-core/src/cron → cron}/cron-scheduler.d.ts +1 -1
- package/dist/dist-CZKP-Xz4.js +832 -0
- package/dist/dist-CZKP-Xz4.js.map +1 -0
- package/dist/env.d.ts +102 -0
- package/dist/from-VbwD7xRf.js +3849 -0
- package/dist/from-VbwD7xRf.js.map +1 -0
- package/dist/{server-core/src/index.d.ts → index.d.ts} +1 -0
- package/dist/index.es.js +60872 -50462
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +73156 -51298
- package/dist/index.umd.js.map +1 -1
- package/dist/init/docs.d.ts +4 -0
- package/dist/init/health.d.ts +2 -0
- package/dist/init/middlewares.d.ts +10 -0
- package/dist/init/shutdown.d.ts +11 -0
- package/dist/init/storage.d.ts +5 -0
- package/dist/{server-core/src/init.d.ts → init.d.ts} +4 -4
- package/dist/jwt-DHcQRGC3.js +4168 -0
- package/dist/jwt-DHcQRGC3.js.map +1 -0
- package/dist/logger-BYU66ENZ.js +94 -0
- package/dist/logger-BYU66ENZ.js.map +1 -0
- package/dist/ms-BeBSuOXN.js +125 -0
- package/dist/ms-BeBSuOXN.js.map +1 -0
- package/dist/multipart-parser-CedBDOeC.js +299 -0
- package/dist/multipart-parser-CedBDOeC.js.map +1 -0
- package/dist/src-COaj0G3P.js +1182 -0
- package/dist/src-COaj0G3P.js.map +1 -0
- package/dist/{server-core/src/storage → storage}/image-transform.d.ts +3 -1
- package/dist/utils/request-id.d.ts +4 -0
- package/package.json +29 -29
- package/src/api/collections_for_test/callbacks_test_collection.ts +7 -6
- package/src/api/errors.ts +75 -19
- package/src/api/graphql/graphql-schema-generator.ts +15 -10
- package/src/api/logs-routes.ts +5 -2
- package/src/api/rest/api-generator-count.test.ts +21 -10
- package/src/api/rest/api-generator.ts +102 -26
- package/src/api/rest/query-parser.ts +18 -12
- package/src/api/server.ts +12 -1
- package/src/api/types.ts +2 -0
- package/src/auth/adapter-middleware.ts +17 -10
- package/src/auth/admin-user-ops.ts +236 -0
- package/src/auth/api-keys/api-key-middleware.ts +15 -9
- package/src/auth/api-keys/api-key-permission-guard.ts +1 -1
- package/src/auth/api-keys/api-key-routes.ts +3 -3
- package/src/auth/api-keys/api-key-store.ts +14 -8
- package/src/auth/api-keys/index.ts +2 -2
- package/src/auth/apple-oauth.ts +4 -3
- package/src/auth/auth-hooks.ts +50 -10
- package/src/auth/bitbucket-oauth.ts +5 -4
- package/src/auth/builtin-auth-adapter.ts +60 -39
- package/src/auth/custom-auth-adapter.ts +4 -5
- package/src/auth/discord-oauth.ts +5 -4
- package/src/auth/facebook-oauth.ts +5 -4
- package/src/auth/github-oauth.ts +6 -5
- package/src/auth/gitlab-oauth.ts +5 -4
- package/src/auth/google-oauth.ts +2 -1
- package/src/auth/index.ts +6 -2
- package/src/auth/jwt.ts +5 -4
- package/src/auth/linkedin-oauth.ts +4 -3
- package/src/auth/mfa-routes.ts +299 -0
- package/src/auth/mfa.ts +2 -1
- package/src/auth/microsoft-oauth.ts +5 -4
- package/src/auth/middleware.ts +5 -4
- package/src/auth/rate-limiter.ts +1 -1
- package/src/auth/reset-password-admin.ts +144 -0
- package/src/auth/rls-scope.ts +1 -1
- package/src/auth/routes.ts +52 -596
- package/src/auth/session-routes.ts +341 -0
- package/src/auth/slack-oauth.ts +6 -5
- package/src/auth/spotify-oauth.ts +5 -4
- package/src/auth/twitter-oauth.ts +4 -3
- package/src/collections/loader.ts +5 -4
- package/src/cron/cron-scheduler.test.ts +23 -11
- package/src/cron/cron-scheduler.ts +14 -8
- package/src/cron/cron-store.ts +1 -1
- package/src/email/smtp-email-service.ts +3 -2
- package/src/env.ts +11 -10
- package/src/index.ts +1 -0
- package/src/init/docs.ts +47 -0
- package/src/init/health.ts +37 -0
- package/src/init/middlewares.ts +61 -0
- package/src/init/shutdown.ts +56 -0
- package/src/init/storage.ts +57 -0
- package/src/init.ts +85 -279
- package/src/serve-spa.ts +12 -5
- package/src/services/driver-registry.ts +4 -3
- package/src/storage/S3StorageController.ts +1 -2
- package/src/storage/image-transform.ts +25 -10
- package/src/storage/routes.ts +34 -11
- package/src/storage/storage-registry.ts +4 -3
- package/src/storage/tus-handler.ts +12 -12
- package/src/utils/request-id.ts +40 -0
- package/src/utils/request-logger.ts +6 -0
- package/test/api-generator.test.ts +90 -2
- package/test/api-key-permission-guard.test.ts +24 -12
- package/test/auth-routes.test.ts +5 -3
- package/test/backend-hooks-data.test.ts +99 -30
- package/test/custom-auth-adapter.test.ts +16 -15
- package/test/email-templates.test.ts +10 -5
- package/test/env.test.ts +10 -10
- package/test/function-loader.test.ts +7 -4
- package/test/graphql-schema-generator.test.ts +554 -0
- package/test/jwt-security.test.ts +1 -1
- package/test/query-parser.test.ts +0 -1
- package/test/reset-password-admin.test.ts +113 -0
- package/test/singleton.test.ts +5 -5
- package/test/smtp-email-service.test.ts +21 -21
- package/test/webhook-service.test.ts +22 -11
- package/tsconfig.json +2 -0
- package/tsconfig.prod.json +3 -0
- package/vite.config.ts +10 -5
- package/dist/common/src/collections/CollectionRegistry.d.ts +0 -56
- package/dist/common/src/collections/default-collections.d.ts +0 -9
- package/dist/common/src/collections/index.d.ts +0 -2
- package/dist/common/src/data/buildRebaseData.d.ts +0 -14
- package/dist/common/src/data/query_builder.d.ts +0 -55
- package/dist/common/src/index.d.ts +0 -4
- package/dist/common/src/util/builders.d.ts +0 -57
- package/dist/common/src/util/callbacks.d.ts +0 -6
- package/dist/common/src/util/collections.d.ts +0 -11
- package/dist/common/src/util/common.d.ts +0 -2
- package/dist/common/src/util/conditions.d.ts +0 -26
- package/dist/common/src/util/entities.d.ts +0 -58
- package/dist/common/src/util/enums.d.ts +0 -3
- package/dist/common/src/util/index.d.ts +0 -16
- package/dist/common/src/util/navigation_from_path.d.ts +0 -34
- package/dist/common/src/util/navigation_utils.d.ts +0 -20
- package/dist/common/src/util/parent_references_from_path.d.ts +0 -6
- package/dist/common/src/util/paths.d.ts +0 -14
- package/dist/common/src/util/permissions.d.ts +0 -14
- package/dist/common/src/util/references.d.ts +0 -2
- package/dist/common/src/util/relations.d.ts +0 -22
- package/dist/common/src/util/resolutions.d.ts +0 -72
- package/dist/common/src/util/storage.d.ts +0 -24
- package/dist/index-Cr1D21av.js +0 -49
- package/dist/index-Cr1D21av.js.map +0 -1
- package/dist/server-core/src/auth/admin-routes.d.ts +0 -27
- package/dist/server-core/src/env.d.ts +0 -137
- package/dist/types/src/controllers/analytics_controller.d.ts +0 -7
- package/dist/types/src/controllers/auth.d.ts +0 -104
- package/dist/types/src/controllers/client.d.ts +0 -168
- package/dist/types/src/controllers/collection_registry.d.ts +0 -46
- package/dist/types/src/controllers/customization_controller.d.ts +0 -60
- package/dist/types/src/controllers/data.d.ts +0 -207
- package/dist/types/src/controllers/data_driver.d.ts +0 -218
- package/dist/types/src/controllers/database_admin.d.ts +0 -11
- package/dist/types/src/controllers/dialogs_controller.d.ts +0 -36
- package/dist/types/src/controllers/effective_role.d.ts +0 -4
- package/dist/types/src/controllers/email.d.ts +0 -36
- package/dist/types/src/controllers/index.d.ts +0 -18
- package/dist/types/src/controllers/local_config_persistence.d.ts +0 -20
- package/dist/types/src/controllers/navigation.d.ts +0 -225
- package/dist/types/src/controllers/registry.d.ts +0 -63
- package/dist/types/src/controllers/side_dialogs_controller.d.ts +0 -67
- package/dist/types/src/controllers/side_entity_controller.d.ts +0 -97
- package/dist/types/src/controllers/snackbar.d.ts +0 -24
- package/dist/types/src/controllers/storage.d.ts +0 -171
- package/dist/types/src/index.d.ts +0 -4
- package/dist/types/src/rebase_context.d.ts +0 -122
- package/dist/types/src/types/auth_adapter.d.ts +0 -301
- package/dist/types/src/types/backend.d.ts +0 -571
- package/dist/types/src/types/backend_hooks.d.ts +0 -172
- package/dist/types/src/types/builders.d.ts +0 -15
- package/dist/types/src/types/chips.d.ts +0 -5
- package/dist/types/src/types/collections.d.ts +0 -961
- package/dist/types/src/types/component_ref.d.ts +0 -47
- package/dist/types/src/types/cron.d.ts +0 -102
- package/dist/types/src/types/data_source.d.ts +0 -64
- package/dist/types/src/types/database_adapter.d.ts +0 -94
- package/dist/types/src/types/entities.d.ts +0 -145
- package/dist/types/src/types/entity_actions.d.ts +0 -104
- package/dist/types/src/types/entity_callbacks.d.ts +0 -173
- package/dist/types/src/types/entity_link_builder.d.ts +0 -7
- package/dist/types/src/types/entity_overrides.d.ts +0 -10
- package/dist/types/src/types/entity_views.d.ts +0 -87
- package/dist/types/src/types/export_import.d.ts +0 -21
- package/dist/types/src/types/formex.d.ts +0 -40
- package/dist/types/src/types/index.d.ts +0 -28
- package/dist/types/src/types/locales.d.ts +0 -4
- package/dist/types/src/types/modify_collections.d.ts +0 -5
- package/dist/types/src/types/plugins.d.ts +0 -282
- package/dist/types/src/types/properties.d.ts +0 -1173
- package/dist/types/src/types/property_config.d.ts +0 -74
- package/dist/types/src/types/relations.d.ts +0 -336
- package/dist/types/src/types/slots.d.ts +0 -262
- package/dist/types/src/types/translations.d.ts +0 -900
- package/dist/types/src/types/user_management_delegate.d.ts +0 -86
- package/dist/types/src/types/websockets.d.ts +0 -78
- package/dist/types/src/users/index.d.ts +0 -1
- package/dist/types/src/users/user.d.ts +0 -50
- package/src/auth/admin-routes.ts +0 -534
- package/test/admin-routes.test.ts +0 -544
- package/test/backend-hooks-admin.test.ts +0 -388
- /package/dist/{server-core/src/api → api}/ast-schema-editor.d.ts +0 -0
- /package/dist/{server-core/src/api → api}/collections_for_test/callbacks_test_collection.d.ts +0 -0
- /package/dist/{server-core/src/api → api}/graphql/graphql-schema-generator.d.ts +0 -0
- /package/dist/{server-core/src/api → api}/graphql/index.d.ts +0 -0
- /package/dist/{server-core/src/api → api}/index.d.ts +0 -0
- /package/dist/{server-core/src/api → api}/logs-routes.d.ts +0 -0
- /package/dist/{server-core/src/api → api}/openapi-generator.d.ts +0 -0
- /package/dist/{server-core/src/api → api}/rest/index.d.ts +0 -0
- /package/dist/{server-core/src/api → api}/rest/query-parser.d.ts +0 -0
- /package/dist/{server-core/src/api → api}/schema-editor-routes.d.ts +0 -0
- /package/dist/{server-core/src/api → api}/server.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/adapter-middleware.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/api-keys/api-key-middleware.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/api-keys/api-key-permission-guard.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/api-keys/api-key-routes.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/api-keys/api-key-store.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/api-keys/api-key-types.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/apple-oauth.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/bitbucket-oauth.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/crypto-utils.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/custom-auth-adapter.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/discord-oauth.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/facebook-oauth.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/github-oauth.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/gitlab-oauth.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/google-oauth.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/interfaces.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/jwt.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/linkedin-oauth.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/mfa.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/microsoft-oauth.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/middleware.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/password.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/rate-limiter.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/rls-scope.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/routes.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/slack-oauth.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/spotify-oauth.d.ts +0 -0
- /package/dist/{server-core/src/auth → auth}/twitter-oauth.d.ts +0 -0
- /package/dist/{server-core/src/collections → collections}/BackendCollectionRegistry.d.ts +0 -0
- /package/dist/{server-core/src/collections → collections}/loader.d.ts +0 -0
- /package/dist/{server-core/src/cron → cron}/cron-loader.d.ts +0 -0
- /package/dist/{server-core/src/cron → cron}/cron-routes.d.ts +0 -0
- /package/dist/{server-core/src/cron → cron}/cron-store.d.ts +0 -0
- /package/dist/{server-core/src/cron → cron}/index.d.ts +0 -0
- /package/dist/{server-core/src/db → db}/interfaces.d.ts +0 -0
- /package/dist/{server-core/src/email → email}/index.d.ts +0 -0
- /package/dist/{server-core/src/email → email}/smtp-email-service.d.ts +0 -0
- /package/dist/{server-core/src/email → email}/templates.d.ts +0 -0
- /package/dist/{server-core/src/email → email}/types.d.ts +0 -0
- /package/dist/{server-core/src/functions → functions}/function-loader.d.ts +0 -0
- /package/dist/{server-core/src/functions → functions}/function-routes.d.ts +0 -0
- /package/dist/{server-core/src/functions → functions}/index.d.ts +0 -0
- /package/dist/{server-core/src/history → history}/history-routes.d.ts +0 -0
- /package/dist/{server-core/src/history → history}/index.d.ts +0 -0
- /package/dist/{server-core/src/serve-spa.d.ts → serve-spa.d.ts} +0 -0
- /package/dist/{server-core/src/services → services}/driver-registry.d.ts +0 -0
- /package/dist/{server-core/src/services → services}/webhook-service.d.ts +0 -0
- /package/dist/{server-core/src/singleton.d.ts → singleton.d.ts} +0 -0
- /package/dist/{server-core/src/storage → storage}/LocalStorageController.d.ts +0 -0
- /package/dist/{server-core/src/storage → storage}/S3StorageController.d.ts +0 -0
- /package/dist/{server-core/src/storage → storage}/index.d.ts +0 -0
- /package/dist/{server-core/src/storage → storage}/routes.d.ts +0 -0
- /package/dist/{server-core/src/storage → storage}/storage-registry.d.ts +0 -0
- /package/dist/{server-core/src/storage → storage}/tus-handler.d.ts +0 -0
- /package/dist/{server-core/src/storage → storage}/types.d.ts +0 -0
- /package/dist/{server-core/src/types → types}/index.d.ts +0 -0
- /package/dist/{server-core/src/utils → utils}/dev-port.d.ts +0 -0
- /package/dist/{server-core/src/utils → utils}/logger.d.ts +0 -0
- /package/dist/{server-core/src/utils → utils}/logging.d.ts +0 -0
- /package/dist/{server-core/src/utils → utils}/request-logger.d.ts +0 -0
- /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
|
-
|
|
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
|
-
|
|
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.
|
|
161
|
-
export function loadEnv(options?: { extend?: z.
|
|
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
|
-
|
|
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
|
-
|
|
219
|
+
logger.warn(
|
|
219
220
|
`⚠️ Auto-generated secrets for: ${autoGeneratedSecrets.join(", ")}. ` +
|
|
220
|
-
|
|
221
|
-
|
|
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
package/src/init/docs.ts
ADDED
|
@@ -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
|
+
}
|