@rebasepro/server-core 0.0.1-canary.4d4fb3e
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/LICENSE +6 -0
- package/README.md +40 -0
- package/build-errors.txt +52 -0
- package/coverage/clover.xml +3739 -0
- package/coverage/coverage-final.json +31 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +266 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/api/ast-schema-editor.ts.html +952 -0
- package/coverage/lcov-report/src/api/errors.ts.html +472 -0
- package/coverage/lcov-report/src/api/graphql/graphql-schema-generator.ts.html +1069 -0
- package/coverage/lcov-report/src/api/graphql/index.html +116 -0
- package/coverage/lcov-report/src/api/index.html +176 -0
- package/coverage/lcov-report/src/api/openapi-generator.ts.html +565 -0
- package/coverage/lcov-report/src/api/rest/api-generator.ts.html +994 -0
- package/coverage/lcov-report/src/api/rest/index.html +131 -0
- package/coverage/lcov-report/src/api/rest/query-parser.ts.html +550 -0
- package/coverage/lcov-report/src/api/schema-editor-routes.ts.html +202 -0
- package/coverage/lcov-report/src/api/server.ts.html +823 -0
- package/coverage/lcov-report/src/auth/admin-routes.ts.html +973 -0
- package/coverage/lcov-report/src/auth/index.html +176 -0
- package/coverage/lcov-report/src/auth/jwt.ts.html +574 -0
- package/coverage/lcov-report/src/auth/middleware.ts.html +745 -0
- package/coverage/lcov-report/src/auth/password.ts.html +310 -0
- package/coverage/lcov-report/src/auth/services.ts.html +2074 -0
- package/coverage/lcov-report/src/collections/index.html +116 -0
- package/coverage/lcov-report/src/collections/loader.ts.html +232 -0
- package/coverage/lcov-report/src/db/auth-schema.ts.html +523 -0
- package/coverage/lcov-report/src/db/data-transformer.ts.html +1753 -0
- package/coverage/lcov-report/src/db/entityService.ts.html +700 -0
- package/coverage/lcov-report/src/db/index.html +146 -0
- package/coverage/lcov-report/src/db/services/EntityFetchService.ts.html +4048 -0
- package/coverage/lcov-report/src/db/services/EntityPersistService.ts.html +883 -0
- package/coverage/lcov-report/src/db/services/RelationService.ts.html +3121 -0
- package/coverage/lcov-report/src/db/services/entity-helpers.ts.html +442 -0
- package/coverage/lcov-report/src/db/services/index.html +176 -0
- package/coverage/lcov-report/src/db/services/index.ts.html +124 -0
- package/coverage/lcov-report/src/generate-drizzle-schema-logic.ts.html +1960 -0
- package/coverage/lcov-report/src/index.html +116 -0
- package/coverage/lcov-report/src/services/driver-registry.ts.html +631 -0
- package/coverage/lcov-report/src/services/index.html +131 -0
- package/coverage/lcov-report/src/services/postgresDataDriver.ts.html +3025 -0
- package/coverage/lcov-report/src/storage/LocalStorageController.ts.html +1189 -0
- package/coverage/lcov-report/src/storage/S3StorageController.ts.html +970 -0
- package/coverage/lcov-report/src/storage/index.html +161 -0
- package/coverage/lcov-report/src/storage/storage-registry.ts.html +646 -0
- package/coverage/lcov-report/src/storage/types.ts.html +451 -0
- package/coverage/lcov-report/src/utils/drizzle-conditions.ts.html +3082 -0
- package/coverage/lcov-report/src/utils/index.html +116 -0
- package/coverage/lcov.info +7179 -0
- package/dist/common/src/collections/CollectionRegistry.d.ts +48 -0
- package/dist/common/src/collections/index.d.ts +1 -0
- package/dist/common/src/data/buildRebaseData.d.ts +14 -0
- package/dist/common/src/index.d.ts +3 -0
- package/dist/common/src/util/builders.d.ts +57 -0
- package/dist/common/src/util/callbacks.d.ts +6 -0
- package/dist/common/src/util/collections.d.ts +11 -0
- package/dist/common/src/util/common.d.ts +2 -0
- package/dist/common/src/util/conditions.d.ts +26 -0
- package/dist/common/src/util/entities.d.ts +36 -0
- package/dist/common/src/util/enums.d.ts +3 -0
- package/dist/common/src/util/index.d.ts +16 -0
- package/dist/common/src/util/navigation_from_path.d.ts +34 -0
- package/dist/common/src/util/navigation_utils.d.ts +20 -0
- package/dist/common/src/util/parent_references_from_path.d.ts +6 -0
- package/dist/common/src/util/paths.d.ts +14 -0
- package/dist/common/src/util/permissions.d.ts +5 -0
- package/dist/common/src/util/references.d.ts +2 -0
- package/dist/common/src/util/relations.d.ts +12 -0
- package/dist/common/src/util/resolutions.d.ts +72 -0
- package/dist/common/src/util/storage.d.ts +24 -0
- package/dist/index-BeMqpmfQ.js +239 -0
- package/dist/index-BeMqpmfQ.js.map +1 -0
- package/dist/index-bl4J3lNb.js +55823 -0
- package/dist/index-bl4J3lNb.js.map +1 -0
- package/dist/index.es.js +58 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +56062 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/server-core/src/api/ast-schema-editor.d.ts +21 -0
- package/dist/server-core/src/api/collections_for_test/callbacks_test_collection.d.ts +2 -0
- package/dist/server-core/src/api/errors.d.ts +35 -0
- package/dist/server-core/src/api/graphql/graphql-schema-generator.d.ts +35 -0
- package/dist/server-core/src/api/graphql/index.d.ts +1 -0
- package/dist/server-core/src/api/index.d.ts +9 -0
- package/dist/server-core/src/api/openapi-generator.d.ts +2 -0
- package/dist/server-core/src/api/rest/api-generator.d.ts +64 -0
- package/dist/server-core/src/api/rest/index.d.ts +1 -0
- package/dist/server-core/src/api/rest/query-parser.d.ts +9 -0
- package/dist/server-core/src/api/schema-editor-routes.d.ts +3 -0
- package/dist/server-core/src/api/server.d.ts +40 -0
- package/dist/server-core/src/api/types.d.ts +90 -0
- package/dist/server-core/src/auth/admin-routes.d.ts +7 -0
- package/dist/server-core/src/auth/google-oauth.d.ts +20 -0
- package/dist/server-core/src/auth/index.d.ts +12 -0
- package/dist/server-core/src/auth/interfaces.d.ts +270 -0
- package/dist/server-core/src/auth/jwt.d.ts +42 -0
- package/dist/server-core/src/auth/middleware.d.ts +56 -0
- package/dist/server-core/src/auth/password.d.ts +22 -0
- package/dist/server-core/src/auth/rate-limiter.d.ts +31 -0
- package/dist/server-core/src/auth/routes.d.ts +17 -0
- package/dist/server-core/src/bootstrappers/index.d.ts +0 -0
- package/dist/server-core/src/collections/BackendCollectionRegistry.d.ts +13 -0
- package/dist/server-core/src/collections/loader.d.ts +5 -0
- package/dist/server-core/src/db/interfaces.d.ts +18 -0
- package/dist/server-core/src/email/index.d.ts +6 -0
- package/dist/server-core/src/email/smtp-email-service.d.ts +25 -0
- package/dist/server-core/src/email/templates.d.ts +33 -0
- package/dist/server-core/src/email/types.d.ts +110 -0
- package/dist/server-core/src/functions/function-loader.d.ts +17 -0
- package/dist/server-core/src/functions/function-routes.d.ts +10 -0
- package/dist/server-core/src/functions/index.d.ts +3 -0
- package/dist/server-core/src/history/history-routes.d.ts +23 -0
- package/dist/server-core/src/history/index.d.ts +1 -0
- package/dist/server-core/src/index.d.ts +24 -0
- package/dist/server-core/src/init.d.ts +49 -0
- package/dist/server-core/src/serve-spa.d.ts +30 -0
- package/dist/server-core/src/services/driver-registry.d.ts +78 -0
- package/dist/server-core/src/storage/LocalStorageController.d.ts +46 -0
- package/dist/server-core/src/storage/S3StorageController.d.ts +36 -0
- package/dist/server-core/src/storage/index.d.ts +18 -0
- package/dist/server-core/src/storage/routes.d.ts +38 -0
- package/dist/server-core/src/storage/storage-registry.d.ts +78 -0
- package/dist/server-core/src/storage/types.d.ts +91 -0
- package/dist/server-core/src/types/index.d.ts +11 -0
- package/dist/server-core/src/utils/logging.d.ts +9 -0
- package/dist/server-core/src/utils/sql.d.ts +27 -0
- package/dist/types/src/controllers/analytics_controller.d.ts +7 -0
- package/dist/types/src/controllers/auth.d.ts +117 -0
- package/dist/types/src/controllers/client.d.ts +58 -0
- package/dist/types/src/controllers/collection_registry.d.ts +44 -0
- package/dist/types/src/controllers/customization_controller.d.ts +54 -0
- package/dist/types/src/controllers/data.d.ts +141 -0
- package/dist/types/src/controllers/data_driver.d.ts +168 -0
- package/dist/types/src/controllers/database_admin.d.ts +11 -0
- package/dist/types/src/controllers/dialogs_controller.d.ts +36 -0
- package/dist/types/src/controllers/effective_role.d.ts +4 -0
- package/dist/types/src/controllers/index.d.ts +17 -0
- package/dist/types/src/controllers/local_config_persistence.d.ts +20 -0
- package/dist/types/src/controllers/navigation.d.ts +213 -0
- package/dist/types/src/controllers/registry.d.ts +51 -0
- package/dist/types/src/controllers/side_dialogs_controller.d.ts +67 -0
- package/dist/types/src/controllers/side_entity_controller.d.ts +89 -0
- package/dist/types/src/controllers/snackbar.d.ts +24 -0
- package/dist/types/src/controllers/storage.d.ts +173 -0
- package/dist/types/src/index.d.ts +4 -0
- package/dist/types/src/rebase_context.d.ts +101 -0
- package/dist/types/src/types/backend.d.ts +533 -0
- package/dist/types/src/types/builders.d.ts +14 -0
- package/dist/types/src/types/chips.d.ts +5 -0
- package/dist/types/src/types/collections.d.ts +812 -0
- package/dist/types/src/types/data_source.d.ts +64 -0
- package/dist/types/src/types/entities.d.ts +145 -0
- package/dist/types/src/types/entity_actions.d.ts +98 -0
- package/dist/types/src/types/entity_callbacks.d.ts +173 -0
- package/dist/types/src/types/entity_link_builder.d.ts +7 -0
- package/dist/types/src/types/entity_overrides.d.ts +9 -0
- package/dist/types/src/types/entity_views.d.ts +61 -0
- package/dist/types/src/types/export_import.d.ts +21 -0
- package/dist/types/src/types/index.d.ts +22 -0
- package/dist/types/src/types/locales.d.ts +4 -0
- package/dist/types/src/types/modify_collections.d.ts +5 -0
- package/dist/types/src/types/plugins.d.ts +225 -0
- package/dist/types/src/types/properties.d.ts +1091 -0
- package/dist/types/src/types/property_config.d.ts +70 -0
- package/dist/types/src/types/relations.d.ts +336 -0
- package/dist/types/src/types/slots.d.ts +228 -0
- package/dist/types/src/types/translations.d.ts +826 -0
- package/dist/types/src/types/user_management_delegate.d.ts +120 -0
- package/dist/types/src/types/websockets.d.ts +78 -0
- package/dist/types/src/users/index.d.ts +2 -0
- package/dist/types/src/users/roles.d.ts +22 -0
- package/dist/types/src/users/user.d.ts +46 -0
- package/history_diff.log +385 -0
- package/jest.config.cjs +16 -0
- package/package.json +86 -0
- package/scratch.ts +8 -0
- package/src/api/ast-schema-editor.ts +289 -0
- package/src/api/collections_for_test/callbacks_test_collection.ts +57 -0
- package/src/api/errors.ts +155 -0
- package/src/api/graphql/graphql-schema-generator.ts +334 -0
- package/src/api/graphql/index.ts +2 -0
- package/src/api/index.ts +11 -0
- package/src/api/openapi-generator.ts +160 -0
- package/src/api/rest/api-generator.ts +466 -0
- package/src/api/rest/index.ts +2 -0
- package/src/api/rest/query-parser.ts +155 -0
- package/src/api/schema-editor-routes.ts +39 -0
- package/src/api/server.ts +245 -0
- package/src/api/types.ts +90 -0
- package/src/auth/admin-routes.ts +488 -0
- package/src/auth/google-oauth.ts +60 -0
- package/src/auth/index.ts +21 -0
- package/src/auth/interfaces.ts +316 -0
- package/src/auth/jwt.ts +164 -0
- package/src/auth/middleware.ts +235 -0
- package/src/auth/password.ts +75 -0
- package/src/auth/rate-limiter.ts +129 -0
- package/src/auth/routes.ts +730 -0
- package/src/bootstrappers/index.ts +1 -0
- package/src/collections/BackendCollectionRegistry.ts +20 -0
- package/src/collections/loader.ts +49 -0
- package/src/db/interfaces.ts +60 -0
- package/src/email/index.ts +17 -0
- package/src/email/smtp-email-service.ts +88 -0
- package/src/email/templates.ts +301 -0
- package/src/email/types.ts +112 -0
- package/src/functions/function-loader.ts +91 -0
- package/src/functions/function-routes.ts +31 -0
- package/src/functions/index.ts +3 -0
- package/src/history/history-routes.ts +128 -0
- package/src/history/index.ts +2 -0
- package/src/index.ts +56 -0
- package/src/init.ts +309 -0
- package/src/serve-spa.ts +81 -0
- package/src/services/driver-registry.ts +182 -0
- package/src/storage/LocalStorageController.ts +368 -0
- package/src/storage/S3StorageController.ts +295 -0
- package/src/storage/index.ts +32 -0
- package/src/storage/routes.ts +247 -0
- package/src/storage/storage-registry.ts +187 -0
- package/src/storage/types.ts +122 -0
- package/src/types/index.ts +27 -0
- package/src/utils/logging.ts +35 -0
- package/src/utils/sql.ts +38 -0
- package/test/admin-routes.test.ts +591 -0
- package/test/api-generator.test.ts +458 -0
- package/test/ast-schema-editor.test.ts +61 -0
- package/test/auth-middleware-hono.test.ts +321 -0
- package/test/auth-routes.test.ts +868 -0
- package/test/driver-registry.test.ts +280 -0
- package/test/errors-hono.test.ts +133 -0
- package/test/errors.test.ts +150 -0
- package/test/jwt-security.test.ts +173 -0
- package/test/jwt.test.ts +311 -0
- package/test/middleware.test.ts +295 -0
- package/test/password.test.ts +165 -0
- package/test/query-parser.test.ts +258 -0
- package/test/rate-limiter.test.ts +102 -0
- package/test/storage-local.test.ts +278 -0
- package/test/storage-registry.test.ts +280 -0
- package/test/storage-routes.test.ts +218 -0
- package/test/storage-s3.test.ts +301 -0
- package/test-ast.ts +28 -0
- package/test_output.txt +1133 -0
- package/tsconfig.json +49 -0
- package/tsconfig.prod.json +20 -0
- package/vite.config.ts +78 -0
- package/vite.config.ts.timestamp-1775065397568-8a853255edf6e.mjs +46 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { pathToFileURL } from "url";
|
|
4
|
+
import { Hono } from "hono";
|
|
5
|
+
|
|
6
|
+
export interface LoadedFunction {
|
|
7
|
+
/** Endpoint name derived from filename (e.g., "send-invoice") */
|
|
8
|
+
name: string;
|
|
9
|
+
/** The Hono sub-app to mount */
|
|
10
|
+
app: Hono<import("hono").Env>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Auto-discover Hono route files from a directory.
|
|
15
|
+
*
|
|
16
|
+
* Each file should default-export a Hono app (or router).
|
|
17
|
+
* The filename (without extension) becomes the mount path:
|
|
18
|
+
* `functions/send-invoice.ts` → mounted at `/send-invoice`
|
|
19
|
+
*
|
|
20
|
+
* This mirrors how `loadCollectionsFromDirectory` works for collections.
|
|
21
|
+
*/
|
|
22
|
+
export async function loadFunctionsFromDirectory(
|
|
23
|
+
directory: string
|
|
24
|
+
): Promise<LoadedFunction[]> {
|
|
25
|
+
const functions: LoadedFunction[] = [];
|
|
26
|
+
|
|
27
|
+
if (!fs.existsSync(directory)) {
|
|
28
|
+
return functions;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const files = fs.readdirSync(directory);
|
|
32
|
+
for (const file of files) {
|
|
33
|
+
if (
|
|
34
|
+
(file.endsWith(".ts") || file.endsWith(".js")) &&
|
|
35
|
+
!file.includes(".test.") &&
|
|
36
|
+
!file.endsWith(".d.ts") &&
|
|
37
|
+
file !== "index.ts" &&
|
|
38
|
+
file !== "index.js"
|
|
39
|
+
) {
|
|
40
|
+
const filePath = path.join(directory, file);
|
|
41
|
+
try {
|
|
42
|
+
const fileUrl = pathToFileURL(filePath).href;
|
|
43
|
+
|
|
44
|
+
// Use new Function to compile dynamic import natively and bypass
|
|
45
|
+
// tsc converting import() to require() — same pattern as collection loader
|
|
46
|
+
const dynamicImport = new Function("url", "return import(url)");
|
|
47
|
+
const mod = await dynamicImport(fileUrl);
|
|
48
|
+
|
|
49
|
+
const exported = mod.default;
|
|
50
|
+
|
|
51
|
+
if (!exported) {
|
|
52
|
+
console.warn(
|
|
53
|
+
`[functions] ${file}: no default export. Skipping.`
|
|
54
|
+
);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Accept a Hono instance directly
|
|
59
|
+
if (exported instanceof Hono) {
|
|
60
|
+
const name = path.basename(file, path.extname(file));
|
|
61
|
+
functions.push({ name, app: exported });
|
|
62
|
+
console.log(`⚡ Loaded function route: ${name}`);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Also accept a factory function that returns a Hono instance
|
|
67
|
+
if (typeof exported === "function") {
|
|
68
|
+
const result = exported();
|
|
69
|
+
if (result instanceof Hono) {
|
|
70
|
+
const name = path.basename(file, path.extname(file));
|
|
71
|
+
functions.push({ name, app: result });
|
|
72
|
+
console.log(`⚡ Loaded function route: ${name}`);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.warn(
|
|
78
|
+
`[functions] ${file}: default export is not a Hono app or factory. Skipping.`
|
|
79
|
+
);
|
|
80
|
+
} catch (err: unknown) {
|
|
81
|
+
const message =
|
|
82
|
+
err instanceof Error ? err.message : String(err);
|
|
83
|
+
console.error(
|
|
84
|
+
`[functions] Failed to load ${file}: ${message}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return functions;
|
|
91
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { HonoEnv } from "../api/types";
|
|
3
|
+
import { LoadedFunction } from "./function-loader";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Mount all loaded function routes under a single Hono router.
|
|
7
|
+
*
|
|
8
|
+
* Each function is mounted at `/<function-name>`, preserving
|
|
9
|
+
* whatever HTTP methods and middleware the Hono sub-app defines.
|
|
10
|
+
*/
|
|
11
|
+
export function createFunctionRoutes(
|
|
12
|
+
functions: LoadedFunction[]
|
|
13
|
+
): Hono<HonoEnv> {
|
|
14
|
+
const router = new Hono<HonoEnv>();
|
|
15
|
+
|
|
16
|
+
// Listing endpoint: GET / → list available functions
|
|
17
|
+
router.get("/", (c) => {
|
|
18
|
+
return c.json({
|
|
19
|
+
functions: functions.map((fn) => ({
|
|
20
|
+
name: fn.name,
|
|
21
|
+
endpoint: `/functions/${fn.name}`,
|
|
22
|
+
})),
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
for (const fn of functions) {
|
|
27
|
+
router.route(`/${fn.name}`, fn.app);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return router;
|
|
31
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { HonoEnv } from "../api/types";
|
|
3
|
+
import { BackendCollectionRegistry } from "../collections/BackendCollectionRegistry";
|
|
4
|
+
import { ApiError } from "../api/errors";
|
|
5
|
+
import { DataDriver } from "@rebasepro/types";
|
|
6
|
+
/**
|
|
7
|
+
* Create Hono routes for entity history.
|
|
8
|
+
* Mounted at `{basePath}/data/:slug/:entityId/history`.
|
|
9
|
+
*/
|
|
10
|
+
export interface HistoryService {
|
|
11
|
+
fetchHistory(tableName: string, entityId: string, options: { limit: number, offset: number }): Promise<{ data: any[], total: number }>;
|
|
12
|
+
fetchHistoryEntry(historyId: string): Promise<any>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function createHistoryRoutes(params: {
|
|
16
|
+
historyService: HistoryService;
|
|
17
|
+
registry: BackendCollectionRegistry;
|
|
18
|
+
driver: DataDriver;
|
|
19
|
+
}): Hono<HonoEnv> {
|
|
20
|
+
const { historyService, registry, driver } = params;
|
|
21
|
+
const router = new Hono<HonoEnv>();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* GET /:slug/:entityId/history - List history entries for an entity
|
|
25
|
+
*
|
|
26
|
+
* Query params:
|
|
27
|
+
* limit (default 20)
|
|
28
|
+
* offset (default 0)
|
|
29
|
+
*/
|
|
30
|
+
router.get("/:slug/:entityId/history", async (c) => {
|
|
31
|
+
const slug = c.req.param("slug");
|
|
32
|
+
const entityId = c.req.param("entityId");
|
|
33
|
+
const parsedLimit = parseInt(c.req.query("limit") ?? "20", 10);
|
|
34
|
+
const parsedOffset = parseInt(c.req.query("offset") ?? "0", 10);
|
|
35
|
+
const limit = Number.isNaN(parsedLimit) ? 20 : parsedLimit;
|
|
36
|
+
const offset = Number.isNaN(parsedOffset) ? 0 : parsedOffset;
|
|
37
|
+
|
|
38
|
+
// Resolve the collection to get the actual table name
|
|
39
|
+
const collection = registry.getCollections().find(
|
|
40
|
+
col => col.slug === slug || false
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (!collection) {
|
|
44
|
+
throw ApiError.notFound(`Collection '${slug}' not found`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!collection.history) {
|
|
48
|
+
throw ApiError.badRequest(`History is not enabled for collection '${slug}'`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const tableName = collection.slug;
|
|
52
|
+
|
|
53
|
+
const result = await historyService.fetchHistory(tableName, entityId, {
|
|
54
|
+
limit: Math.min(limit, 100),
|
|
55
|
+
offset: Math.max(offset, 0)
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return c.json({
|
|
59
|
+
data: result.data,
|
|
60
|
+
meta: {
|
|
61
|
+
total: result.total,
|
|
62
|
+
limit,
|
|
63
|
+
offset,
|
|
64
|
+
hasMore: offset + result.data.length < result.total
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* POST /:slug/:entityId/history/:historyId/revert - Revert entity to a historical version
|
|
71
|
+
*
|
|
72
|
+
* This goes through the normal save path, so it creates its own history entry.
|
|
73
|
+
*/
|
|
74
|
+
router.post("/:slug/:entityId/history/:historyId/revert", async (c) => {
|
|
75
|
+
const slug = c.req.param("slug");
|
|
76
|
+
const entityId = c.req.param("entityId");
|
|
77
|
+
const historyId = c.req.param("historyId");
|
|
78
|
+
|
|
79
|
+
const collection = registry.getCollections().find(
|
|
80
|
+
col => col.slug === slug || false
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
if (!collection) {
|
|
84
|
+
throw ApiError.notFound(`Collection '${slug}' not found`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!collection.history) {
|
|
88
|
+
throw ApiError.badRequest(`History is not enabled for collection '${slug}'`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Fetch the history entry
|
|
92
|
+
const historyEntry = await historyService.fetchHistoryEntry(historyId);
|
|
93
|
+
|
|
94
|
+
if (!historyEntry) {
|
|
95
|
+
throw ApiError.notFound(`History entry '${historyId}' not found`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Verify the history entry belongs to this entity (prevent cross-entity revert)
|
|
99
|
+
const tableName = collection.slug;
|
|
100
|
+
if (historyEntry.entity_id !== String(entityId) || historyEntry.table_name !== tableName) {
|
|
101
|
+
throw ApiError.badRequest("History entry does not belong to this entity");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!historyEntry.values) {
|
|
105
|
+
throw ApiError.badRequest("Cannot revert: history entry has no stored values");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Revert by saving through the normal driver path — this will
|
|
109
|
+
// itself create another history entry, giving a full audit trail.
|
|
110
|
+
const authDriver = c.get("driver") || driver;
|
|
111
|
+
const path = collection.slug;
|
|
112
|
+
|
|
113
|
+
const savedEntity = await authDriver.saveEntity({
|
|
114
|
+
path,
|
|
115
|
+
entityId: String(entityId),
|
|
116
|
+
values: historyEntry.values,
|
|
117
|
+
collection,
|
|
118
|
+
status: "existing"
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return c.json({
|
|
122
|
+
data: savedEntity,
|
|
123
|
+
meta: { reverted_from: historyId }
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return router;
|
|
128
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rebasepro/server-core
|
|
3
|
+
*
|
|
4
|
+
* Database-Agnostic Backend Core for Rebase.
|
|
5
|
+
* This package provides the core backend services, generic driver routing,
|
|
6
|
+
* and API layers. Database implementations (e.g., PostgreSQL) are provided
|
|
7
|
+
* by specialized driver packages like `@rebasepro/server-postgresql`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// Abstract Interfaces (for database abstraction)
|
|
12
|
+
// =============================================================================
|
|
13
|
+
export * from "./db/interfaces";
|
|
14
|
+
export * from "./auth/interfaces";
|
|
15
|
+
|
|
16
|
+
// Core functionality
|
|
17
|
+
export * from "./init";
|
|
18
|
+
|
|
19
|
+
// Services
|
|
20
|
+
export * from "./services/driver-registry";
|
|
21
|
+
|
|
22
|
+
// API types (HonoEnv, ApiConfig, etc.)
|
|
23
|
+
export * from "./api/types";
|
|
24
|
+
|
|
25
|
+
// API Generation
|
|
26
|
+
export * from "./api";
|
|
27
|
+
|
|
28
|
+
// Types
|
|
29
|
+
export * from "./types";
|
|
30
|
+
export * from "./types/index";
|
|
31
|
+
|
|
32
|
+
// Auth module
|
|
33
|
+
export * from "./auth";
|
|
34
|
+
|
|
35
|
+
// Email module
|
|
36
|
+
export * from "./email";
|
|
37
|
+
|
|
38
|
+
// Storage module
|
|
39
|
+
export * from "./storage";
|
|
40
|
+
|
|
41
|
+
export * from "./utils/logging";
|
|
42
|
+
export * from "./utils/sql";
|
|
43
|
+
|
|
44
|
+
// Entity history
|
|
45
|
+
export * from "./history";
|
|
46
|
+
|
|
47
|
+
// Custom Functions (auto-discovered Hono routes)
|
|
48
|
+
export * from "./functions";
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
// SPA serving helper
|
|
53
|
+
export * from "./serve-spa";
|
|
54
|
+
|
|
55
|
+
// Backend bootstrappers (pluggable driver initialization)
|
|
56
|
+
|
package/src/init.ts
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { DataDriver, EntityCollection, BackendBootstrapper, BootstrappedAuth, RealtimeProvider } from "@rebasepro/types";
|
|
2
|
+
import { BackendCollectionRegistry } from "./collections/BackendCollectionRegistry";
|
|
3
|
+
import { loadCollectionsFromDirectory } from "./collections/loader";
|
|
4
|
+
import { DriverRegistry, DEFAULT_DRIVER_ID, DefaultDriverRegistry } from "./services/driver-registry";
|
|
5
|
+
import { Server } from "http";
|
|
6
|
+
|
|
7
|
+
import { RestApiGenerator } from "./api/rest/api-generator";
|
|
8
|
+
import { createAuthMiddleware } from "./auth/middleware";
|
|
9
|
+
import { errorHandler } from "./api/errors";
|
|
10
|
+
import { Hono } from "hono";
|
|
11
|
+
import { HonoEnv } from "./api/types";
|
|
12
|
+
import { configureLogLevel } from "./utils/logging";
|
|
13
|
+
import { createAdminRoutes, createAuthRoutes, requireAuth, requireAdmin, configureJwt } from "./auth";
|
|
14
|
+
import { createStorageController, createStorageRoutes, DEFAULT_STORAGE_ID, DefaultStorageRegistry, BackendStorageConfig, StorageController, StorageRegistry } from "./storage";
|
|
15
|
+
import { createHistoryRoutes } from "./history";
|
|
16
|
+
import { EmailConfig } from "./email";
|
|
17
|
+
|
|
18
|
+
export interface RebaseAuthConfig {
|
|
19
|
+
jwtSecret?: string;
|
|
20
|
+
accessExpiresIn?: string;
|
|
21
|
+
refreshExpiresIn?: string;
|
|
22
|
+
requireAuth?: boolean;
|
|
23
|
+
allowRegistration?: boolean;
|
|
24
|
+
email?: EmailConfig;
|
|
25
|
+
google?: { clientId: string };
|
|
26
|
+
defaultRole?: string;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface RebaseBackendConfig {
|
|
31
|
+
collections?: EntityCollection[];
|
|
32
|
+
collectionsDir?: string;
|
|
33
|
+
server: Server;
|
|
34
|
+
app: Hono<HonoEnv>;
|
|
35
|
+
basePath?: string;
|
|
36
|
+
bootstrappers: BackendBootstrapper[];
|
|
37
|
+
logging?: {
|
|
38
|
+
level?: "error" | "warn" | "info" | "debug";
|
|
39
|
+
};
|
|
40
|
+
auth?: RebaseAuthConfig;
|
|
41
|
+
storage?: BackendStorageConfig | Record<string, BackendStorageConfig>;
|
|
42
|
+
history?: unknown;
|
|
43
|
+
enableSwagger?: boolean;
|
|
44
|
+
functionsDir?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface RebaseBackendInstance {
|
|
48
|
+
driverRegistry: DriverRegistry;
|
|
49
|
+
driver: DataDriver;
|
|
50
|
+
realtimeServices: Record<string, RealtimeProvider>;
|
|
51
|
+
realtimeService: RealtimeProvider;
|
|
52
|
+
auth?: BootstrappedAuth;
|
|
53
|
+
history?: unknown;
|
|
54
|
+
storageRegistry?: StorageRegistry;
|
|
55
|
+
storageController?: StorageController;
|
|
56
|
+
collectionRegistry: BackendCollectionRegistry;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function initializeRebaseBackend(config: RebaseBackendConfig): Promise<RebaseBackendInstance> {
|
|
60
|
+
try {
|
|
61
|
+
return await _initializeRebaseBackend(config);
|
|
62
|
+
} catch (error: unknown) {
|
|
63
|
+
console.error("❌ Critical error during Rebase Backend initialization:", error);
|
|
64
|
+
|
|
65
|
+
const basePath = config.basePath || "/api";
|
|
66
|
+
config.app.use(`${basePath}/*`, async (c) => {
|
|
67
|
+
return c.json({
|
|
68
|
+
error: {
|
|
69
|
+
message: "Backend initialization failed. Please check the backend server logs.",
|
|
70
|
+
code: "backend-init-failed"
|
|
71
|
+
}
|
|
72
|
+
}, 503);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
__failed: true,
|
|
77
|
+
driverRegistry: DefaultDriverRegistry.create({}),
|
|
78
|
+
driver: {} as unknown as DataDriver,
|
|
79
|
+
realtimeServices: {},
|
|
80
|
+
realtimeService: {} as unknown as RealtimeProvider,
|
|
81
|
+
} as unknown as RebaseBackendInstance;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function _initializeRebaseBackend(config: RebaseBackendConfig): Promise<RebaseBackendInstance> {
|
|
86
|
+
if (config.logging?.level) {
|
|
87
|
+
configureLogLevel(config.logging.level);
|
|
88
|
+
} else {
|
|
89
|
+
configureLogLevel();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log("🔥 Initializing Rebase Backend (Bootstrapper Protocol V2)");
|
|
93
|
+
|
|
94
|
+
const collectionRegistry = new BackendCollectionRegistry();
|
|
95
|
+
let activeCollections = config.collections || [];
|
|
96
|
+
if (config.collectionsDir && activeCollections.length === 0) {
|
|
97
|
+
activeCollections = await loadCollectionsFromDirectory(config.collectionsDir);
|
|
98
|
+
console.log(`📁 Auto-discovered ${activeCollections.length} collections from ${config.collectionsDir}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const realtimeServices: Record<string, RealtimeProvider> = {};
|
|
102
|
+
const delegates: Record<string, DataDriver> = {};
|
|
103
|
+
const bootstrappers = config.bootstrappers || [];
|
|
104
|
+
|
|
105
|
+
if (bootstrappers.length === 0) {
|
|
106
|
+
throw new Error("No bootstrappers provided. Cannot initialize database drivers.");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let defaultDriverId = DEFAULT_DRIVER_ID;
|
|
110
|
+
|
|
111
|
+
let defaultDriverResult: import("@rebasepro/types").InitializedDriver | undefined = undefined;
|
|
112
|
+
|
|
113
|
+
// 1. Initialize all drivers
|
|
114
|
+
for (const bootstrapper of bootstrappers) {
|
|
115
|
+
const b = bootstrapper as BackendBootstrapper & { id?: string; isDefault?: boolean };
|
|
116
|
+
console.log(`📦 Running bootstrapper for driver: "${b.id || bootstrapper.type}"`);
|
|
117
|
+
if (b.isDefault) {
|
|
118
|
+
defaultDriverId = b.id || bootstrapper.type;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const driverResult = await bootstrapper.initializeDriver({ collections: activeCollections, collectionRegistry });
|
|
122
|
+
delegates[b.id || bootstrapper.type] = driverResult.driver;
|
|
123
|
+
|
|
124
|
+
if ((b.id || bootstrapper.type) === defaultDriverId || !defaultDriverResult) {
|
|
125
|
+
defaultDriverResult = driverResult;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (bootstrapper.initializeRealtime) {
|
|
129
|
+
const realtime = await bootstrapper.initializeRealtime({}, driverResult);
|
|
130
|
+
realtimeServices[b.id || bootstrapper.type] = realtime as RealtimeProvider;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const driverRegistry = DefaultDriverRegistry.create(delegates);
|
|
135
|
+
activeCollections.forEach(collection => collectionRegistry.register(collection));
|
|
136
|
+
|
|
137
|
+
const defaultDriver = driverRegistry.getOrDefault(defaultDriverId);
|
|
138
|
+
if (!defaultDriver || !defaultDriverResult) {
|
|
139
|
+
throw new Error("Default driver not initialized by bootstrappers");
|
|
140
|
+
}
|
|
141
|
+
const defaultBootstrapper = bootstrappers.find(b => (b as BackendBootstrapper & { id?: string }).id === defaultDriverId || b.type === defaultDriverId) || bootstrappers[0];
|
|
142
|
+
const defaultRealtimeService = defaultDriverResult.realtimeProvider;
|
|
143
|
+
|
|
144
|
+
// 2. Initialize Auth & History via the default driver's bootstrapper
|
|
145
|
+
let authConfigResult: BootstrappedAuth | undefined = undefined;
|
|
146
|
+
if (config.auth) {
|
|
147
|
+
// Secure JWT setup proactively within core package memory to eliminate dual-package hazards
|
|
148
|
+
const safeAuthConfig = config.auth;
|
|
149
|
+
if (safeAuthConfig.jwtSecret) {
|
|
150
|
+
configureJwt({
|
|
151
|
+
secret: safeAuthConfig.jwtSecret,
|
|
152
|
+
accessExpiresIn: safeAuthConfig.accessExpiresIn || "1h",
|
|
153
|
+
refreshExpiresIn: safeAuthConfig.refreshExpiresIn || "30d"
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (defaultBootstrapper.initializeAuth) {
|
|
158
|
+
console.log("🔐 Bootstrapping authentication via driver protocol...");
|
|
159
|
+
authConfigResult = await defaultBootstrapper.initializeAuth(config.auth, defaultDriverResult);
|
|
160
|
+
console.log("✅ Authentication initialized");
|
|
161
|
+
} else {
|
|
162
|
+
console.warn("⚠️ Auth requested but default bootstrapper does not support initializeAuth");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let historyConfigResult: Record<string, unknown> | undefined = undefined;
|
|
167
|
+
if (config.history) {
|
|
168
|
+
if (defaultBootstrapper.initializeHistory) {
|
|
169
|
+
console.log("📜 Bootstrapping entity history via driver protocol...");
|
|
170
|
+
historyConfigResult = await defaultBootstrapper.initializeHistory(config.history, defaultDriverResult);
|
|
171
|
+
console.log("✅ Entity history initialized");
|
|
172
|
+
} else {
|
|
173
|
+
console.warn("⚠️ History requested but default bootstrapper does not support initializeHistory");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 3. Initialize Storage
|
|
178
|
+
let storageRegistry: StorageRegistry | undefined;
|
|
179
|
+
let storageController: StorageController | undefined;
|
|
180
|
+
|
|
181
|
+
if (config.storage) {
|
|
182
|
+
console.log("📁 Configuring storage...");
|
|
183
|
+
const controllers: Record<string, StorageController> = {};
|
|
184
|
+
|
|
185
|
+
if (typeof config.storage === "object" && "type" in config.storage) {
|
|
186
|
+
const controller = createStorageController(config.storage as BackendStorageConfig);
|
|
187
|
+
controllers[DEFAULT_STORAGE_ID] = controller;
|
|
188
|
+
} else {
|
|
189
|
+
for (const [storageId, storageConfig] of Object.entries(config.storage as Record<string, BackendStorageConfig>)) {
|
|
190
|
+
controllers[storageId] = createStorageController(storageConfig);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (Object.keys(controllers).length > 0) {
|
|
195
|
+
storageRegistry = DefaultStorageRegistry.create(controllers);
|
|
196
|
+
storageController = storageRegistry.getDefault();
|
|
197
|
+
console.log(`✅ Initialized ${Object.keys(controllers).length} storage backend(s)`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const basePath = config.basePath || "/api";
|
|
202
|
+
|
|
203
|
+
// 4. Mount API Routes
|
|
204
|
+
if (config.auth && authConfigResult) {
|
|
205
|
+
const authRoutes = createAuthRoutes({
|
|
206
|
+
authRepo: authConfigResult.authRepository as import("./auth/interfaces").AuthRepository ?? authConfigResult.userService as import("./auth/interfaces").AuthRepository,
|
|
207
|
+
emailService: authConfigResult.emailService as import("./email").EmailService,
|
|
208
|
+
emailConfig: config.auth.email,
|
|
209
|
+
allowRegistration: config.auth.allowRegistration ?? false,
|
|
210
|
+
defaultRole: config.auth.defaultRole
|
|
211
|
+
});
|
|
212
|
+
config.app.route(`${basePath}/auth`, authRoutes);
|
|
213
|
+
|
|
214
|
+
const adminRoutes = createAdminRoutes({
|
|
215
|
+
authRepo: authConfigResult.authRepository as import("./auth/interfaces").AuthRepository ?? authConfigResult.userService as import("./auth/interfaces").AuthRepository,
|
|
216
|
+
emailService: authConfigResult.emailService as import("./email").EmailService,
|
|
217
|
+
emailConfig: config.auth.email,
|
|
218
|
+
});
|
|
219
|
+
config.app.route(`${basePath}/admin`, adminRoutes);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (config.collectionsDir) {
|
|
223
|
+
if (process.env.NODE_ENV !== "production") {
|
|
224
|
+
const { createSchemaEditorRoutes } = await import("./api/schema-editor-routes");
|
|
225
|
+
const schemaEditorRoutes = createSchemaEditorRoutes(config.collectionsDir);
|
|
226
|
+
|
|
227
|
+
if (config.auth?.requireAuth !== false && !!config.auth?.jwtSecret) {
|
|
228
|
+
schemaEditorRoutes.use("/*", requireAuth, requireAdmin);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
config.app.route(`${basePath}/schema-editor`, schemaEditorRoutes);
|
|
232
|
+
console.log(`✅ Schema Editor mounted at ${basePath}/schema-editor`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (storageController) {
|
|
237
|
+
const storageRoutes = createStorageRoutes({
|
|
238
|
+
controller: storageController,
|
|
239
|
+
requireAuth: config.auth?.requireAuth ?? true
|
|
240
|
+
});
|
|
241
|
+
config.app.route(`${basePath}/storage`, storageRoutes);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (activeCollections.length > 0) {
|
|
245
|
+
const dataRouter = new Hono<HonoEnv>();
|
|
246
|
+
|
|
247
|
+
dataRouter.use("/*", createAuthMiddleware({
|
|
248
|
+
driver: defaultDriver,
|
|
249
|
+
requireAuth: false // true BaaS — delegate completely to Postgres RLS
|
|
250
|
+
}));
|
|
251
|
+
|
|
252
|
+
// Mount history routes BEFORE the REST API subcollection catch-all so
|
|
253
|
+
// that /:slug/:entityId/history is matched by the dedicated handler first.
|
|
254
|
+
if (historyConfigResult && historyConfigResult.historyService) {
|
|
255
|
+
const historyRoutes = createHistoryRoutes({
|
|
256
|
+
historyService: historyConfigResult.historyService as import("./history/history-routes").HistoryService,
|
|
257
|
+
registry: collectionRegistry,
|
|
258
|
+
driver: defaultDriver
|
|
259
|
+
});
|
|
260
|
+
dataRouter.route("/", historyRoutes);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const restGenerator = new RestApiGenerator(activeCollections, defaultDriver);
|
|
264
|
+
dataRouter.route("/", restGenerator.generateRoutes());
|
|
265
|
+
|
|
266
|
+
config.app.route(`${basePath}/data`, dataRouter);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// 5. Mount Custom Functions
|
|
270
|
+
if (config.functionsDir) {
|
|
271
|
+
const { loadFunctionsFromDirectory } = await import("./functions/function-loader");
|
|
272
|
+
const { createFunctionRoutes } = await import("./functions/function-routes");
|
|
273
|
+
|
|
274
|
+
const loadedFunctions = await loadFunctionsFromDirectory(config.functionsDir);
|
|
275
|
+
|
|
276
|
+
if (loadedFunctions.length > 0) {
|
|
277
|
+
const functionsRouter = new Hono<HonoEnv>();
|
|
278
|
+
|
|
279
|
+
// Apply auth middleware — delegates to RLS, per-route auth is up to the function
|
|
280
|
+
functionsRouter.use("/*", createAuthMiddleware({
|
|
281
|
+
driver: defaultDriver,
|
|
282
|
+
requireAuth: false
|
|
283
|
+
}));
|
|
284
|
+
|
|
285
|
+
const fnRoutes = createFunctionRoutes(loadedFunctions);
|
|
286
|
+
functionsRouter.route("/", fnRoutes);
|
|
287
|
+
config.app.route(`${basePath}/functions`, functionsRouter);
|
|
288
|
+
console.log(`⚡ Mounted ${loadedFunctions.length} custom function(s) at ${basePath}/functions`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if ((defaultBootstrapper as BackendBootstrapper & { initializeWebsockets?: (...args: unknown[]) => unknown }).initializeWebsockets) {
|
|
293
|
+
await (defaultBootstrapper as BackendBootstrapper & { initializeWebsockets: (...args: unknown[]) => unknown }).initializeWebsockets(config.server, defaultRealtimeService, defaultDriver, config.auth);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
console.log("✅ Rebase Backend Initialized");
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
driverRegistry,
|
|
300
|
+
driver: defaultDriver,
|
|
301
|
+
realtimeServices,
|
|
302
|
+
realtimeService: defaultRealtimeService as RealtimeProvider,
|
|
303
|
+
auth: authConfigResult,
|
|
304
|
+
history: historyConfigResult,
|
|
305
|
+
storageRegistry,
|
|
306
|
+
storageController,
|
|
307
|
+
collectionRegistry
|
|
308
|
+
};
|
|
309
|
+
}
|