@rebasepro/server-core 0.7.0 → 0.9.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.
- package/README.md +2 -2
- package/dist/api/ast-schema-editor.d.ts +21 -0
- package/dist/api/collections_for_test/callbacks_test_collection.d.ts +2 -0
- package/dist/api/errors.d.ts +53 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/logs-routes.d.ts +37 -0
- package/dist/api/openapi-generator.d.ts +16 -0
- package/dist/api/rest/api-generator.d.ts +68 -0
- package/{src/api/rest/index.ts → dist/api/rest/index.d.ts} +0 -1
- package/dist/api/rest/query-parser.d.ts +6 -0
- package/dist/api/schema-editor-routes.d.ts +3 -0
- package/dist/api/types.d.ts +56 -0
- package/dist/auth/adapter-middleware.d.ts +43 -0
- package/dist/auth/admin-roles-route.d.ts +18 -0
- package/dist/auth/admin-user-ops.d.ts +79 -0
- package/dist/auth/admin-users-route.d.ts +28 -0
- package/dist/auth/api-keys/api-key-middleware.d.ts +39 -0
- package/{src/auth/api-keys/api-key-permission-guard.ts → dist/auth/api-keys/api-key-permission-guard.d.ts} +2 -34
- package/dist/auth/api-keys/api-key-routes.d.ts +20 -0
- package/dist/auth/api-keys/api-key-store.d.ts +35 -0
- package/{src/auth/api-keys/api-key-types.ts → dist/auth/api-keys/api-key-types.d.ts} +0 -6
- package/{src/auth/api-keys/index.ts → dist/auth/api-keys/index.d.ts} +2 -22
- package/dist/auth/apple-oauth.d.ts +30 -0
- package/{src/auth/auth-hooks.ts → dist/auth/auth-hooks.d.ts} +15 -73
- package/dist/auth/bitbucket-oauth.d.ts +11 -0
- package/dist/auth/builtin-auth-adapter.d.ts +55 -0
- package/dist/auth/cookie-utils.d.ts +32 -0
- package/{src/auth/crypto-utils.ts → dist/auth/crypto-utils.d.ts} +1 -16
- package/dist/auth/custom-auth-adapter.d.ts +39 -0
- package/dist/auth/discord-oauth.d.ts +14 -0
- package/dist/auth/facebook-oauth.d.ts +14 -0
- package/dist/auth/github-oauth.d.ts +15 -0
- package/dist/auth/gitlab-oauth.d.ts +13 -0
- package/dist/auth/google-oauth.d.ts +47 -0
- package/{src/auth/index.ts → dist/auth/index.d.ts} +4 -22
- package/{src/auth/interfaces.ts → dist/auth/interfaces.d.ts} +20 -89
- package/dist/auth/jwt.d.ts +67 -0
- package/dist/auth/linkedin-oauth.d.ts +18 -0
- package/dist/auth/magic-link-routes.d.ts +32 -0
- package/dist/auth/mfa-crypto.d.ts +23 -0
- package/dist/auth/mfa-routes.d.ts +7 -0
- package/dist/auth/mfa.d.ts +49 -0
- package/dist/auth/microsoft-oauth.d.ts +16 -0
- package/dist/auth/middleware.d.ts +158 -0
- package/dist/auth/password.d.ts +22 -0
- package/dist/auth/rate-limiter.d.ts +50 -0
- package/dist/auth/reset-password-admin.d.ts +29 -0
- package/dist/auth/rls-scope.d.ts +31 -0
- package/dist/auth/routes.d.ts +66 -0
- package/dist/auth/session-routes.d.ts +29 -0
- package/dist/auth/slack-oauth.d.ts +12 -0
- package/dist/auth/spotify-oauth.d.ts +12 -0
- package/dist/auth/twitter-oauth.d.ts +18 -0
- package/dist/collections/BackendCollectionRegistry.d.ts +13 -0
- package/dist/collections/loader.d.ts +5 -0
- package/dist/cron/cron-loader.d.ts +18 -0
- package/dist/cron/cron-routes.d.ts +14 -0
- package/dist/cron/cron-scheduler.d.ts +106 -0
- package/dist/cron/cron-store.d.ts +32 -0
- package/dist/cron/define-cron.d.ts +28 -0
- package/{src/cron/index.ts → dist/cron/index.d.ts} +1 -0
- package/dist/db/interfaces.d.ts +18 -0
- package/dist/dynamic-import-Dvh-K5fl.js +22 -0
- package/dist/dynamic-import-Dvh-K5fl.js.map +1 -0
- package/dist/email/index.d.ts +6 -0
- package/dist/email/smtp-email-service.d.ts +30 -0
- package/dist/email/templates.d.ts +50 -0
- package/{src/email/types.ts → dist/email/types.d.ts} +40 -36
- package/dist/env.d.ts +102 -0
- package/dist/functions/define-function.d.ts +55 -0
- package/dist/functions/function-loader.d.ts +18 -0
- package/dist/functions/function-routes.d.ts +10 -0
- package/{src/functions/index.ts → dist/functions/index.d.ts} +2 -0
- package/dist/history/history-routes.d.ts +23 -0
- package/{src/history/index.ts → dist/history/index.d.ts} +0 -1
- package/dist/index.d.ts +35 -0
- package/dist/index.es.js +18184 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +48629 -0
- package/dist/index.umd.js.map +1 -0
- 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 +65 -0
- package/dist/init/storage.d.ts +5 -0
- package/dist/init.d.ts +344 -0
- package/dist/jwt-BwIn8xmk.js +4200 -0
- package/dist/jwt-BwIn8xmk.js.map +1 -0
- package/dist/logger-BYU66ENZ.js +94 -0
- package/dist/logger-BYU66ENZ.js.map +1 -0
- package/dist/ms-DnYXB-Wd.js +162 -0
- package/dist/ms-DnYXB-Wd.js.map +1 -0
- package/dist/openapi-generator-Z9oYWLf_.js +586 -0
- package/dist/openapi-generator-Z9oYWLf_.js.map +1 -0
- package/dist/schema-editor-routes-D3ef8zu1.js +219 -0
- package/dist/schema-editor-routes-D3ef8zu1.js.map +1 -0
- package/dist/serve-spa.d.ts +36 -0
- package/dist/services/driver-registry.d.ts +78 -0
- package/dist/services/routed-realtime-service.d.ts +43 -0
- package/dist/services/webhook-service.d.ts +29 -0
- package/dist/singleton.d.ts +51 -0
- package/dist/src-B4OLmNVa.js +437 -0
- package/dist/src-B4OLmNVa.js.map +1 -0
- package/dist/src-B5WkP1Rv.js +24778 -0
- package/dist/src-B5WkP1Rv.js.map +1 -0
- package/dist/storage/GCSStorageController.d.ts +43 -0
- package/dist/storage/LocalStorageController.d.ts +46 -0
- package/dist/storage/S3StorageController.d.ts +40 -0
- package/dist/storage/image-transform.d.ts +50 -0
- package/{src/storage/index.ts → dist/storage/index.d.ts} +6 -21
- package/dist/storage/routes.d.ts +70 -0
- package/dist/storage/storage-registry.d.ts +78 -0
- package/dist/storage/tus-handler.d.ts +53 -0
- package/{src/storage/types.ts → dist/storage/types.d.ts} +32 -38
- package/dist/types/index.d.ts +11 -0
- package/dist/utils/dev-port.d.ts +45 -0
- package/dist/utils/dynamic-import.d.ts +25 -0
- package/dist/utils/logger.d.ts +31 -0
- package/dist/utils/logging.d.ts +9 -0
- package/dist/utils/request-id.d.ts +4 -0
- package/dist/utils/request-logger.d.ts +19 -0
- package/{src/utils/sql.ts → dist/utils/sql.d.ts} +5 -16
- package/package.json +49 -22
- package/coverage/clover.xml +0 -3739
- package/coverage/coverage-final.json +0 -31
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -266
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov-report/src/api/ast-schema-editor.ts.html +0 -952
- package/coverage/lcov-report/src/api/errors.ts.html +0 -472
- package/coverage/lcov-report/src/api/graphql/graphql-schema-generator.ts.html +0 -1069
- package/coverage/lcov-report/src/api/graphql/index.html +0 -116
- package/coverage/lcov-report/src/api/index.html +0 -176
- package/coverage/lcov-report/src/api/openapi-generator.ts.html +0 -565
- package/coverage/lcov-report/src/api/rest/api-generator.ts.html +0 -994
- package/coverage/lcov-report/src/api/rest/index.html +0 -131
- package/coverage/lcov-report/src/api/rest/query-parser.ts.html +0 -550
- package/coverage/lcov-report/src/api/schema-editor-routes.ts.html +0 -202
- package/coverage/lcov-report/src/api/server.ts.html +0 -823
- package/coverage/lcov-report/src/auth/admin-routes.ts.html +0 -973
- package/coverage/lcov-report/src/auth/index.html +0 -176
- package/coverage/lcov-report/src/auth/jwt.ts.html +0 -574
- package/coverage/lcov-report/src/auth/middleware.ts.html +0 -745
- package/coverage/lcov-report/src/auth/password.ts.html +0 -310
- package/coverage/lcov-report/src/auth/services.ts.html +0 -2074
- package/coverage/lcov-report/src/collections/index.html +0 -116
- package/coverage/lcov-report/src/collections/loader.ts.html +0 -232
- package/coverage/lcov-report/src/db/auth-schema.ts.html +0 -523
- package/coverage/lcov-report/src/db/data-transformer.ts.html +0 -1753
- package/coverage/lcov-report/src/db/entityService.ts.html +0 -700
- package/coverage/lcov-report/src/db/index.html +0 -146
- package/coverage/lcov-report/src/db/services/EntityFetchService.ts.html +0 -4048
- package/coverage/lcov-report/src/db/services/EntityPersistService.ts.html +0 -883
- package/coverage/lcov-report/src/db/services/RelationService.ts.html +0 -3121
- package/coverage/lcov-report/src/db/services/entity-helpers.ts.html +0 -442
- package/coverage/lcov-report/src/db/services/index.html +0 -176
- package/coverage/lcov-report/src/db/services/index.ts.html +0 -124
- package/coverage/lcov-report/src/generate-drizzle-schema-logic.ts.html +0 -1960
- package/coverage/lcov-report/src/index.html +0 -116
- package/coverage/lcov-report/src/services/driver-registry.ts.html +0 -631
- package/coverage/lcov-report/src/services/index.html +0 -131
- package/coverage/lcov-report/src/services/postgresDataDriver.ts.html +0 -3025
- package/coverage/lcov-report/src/storage/LocalStorageController.ts.html +0 -1189
- package/coverage/lcov-report/src/storage/S3StorageController.ts.html +0 -970
- package/coverage/lcov-report/src/storage/index.html +0 -161
- package/coverage/lcov-report/src/storage/storage-registry.ts.html +0 -646
- package/coverage/lcov-report/src/storage/types.ts.html +0 -451
- package/coverage/lcov-report/src/utils/drizzle-conditions.ts.html +0 -3082
- package/coverage/lcov-report/src/utils/index.html +0 -116
- package/coverage/lcov.info +0 -7179
- package/jest.config.cjs +0 -19
- package/src/api/ast-schema-editor.ts +0 -289
- package/src/api/collections_for_test/callbacks_test_collection.ts +0 -61
- package/src/api/errors.ts +0 -278
- package/src/api/graphql/graphql-schema-generator.ts +0 -383
- package/src/api/graphql/index.ts +0 -2
- package/src/api/index.ts +0 -11
- package/src/api/logs-routes.ts +0 -132
- package/src/api/openapi-generator.ts +0 -727
- package/src/api/rest/api-generator-count.test.ts +0 -126
- package/src/api/rest/api-generator.ts +0 -747
- package/src/api/rest/query-parser.ts +0 -300
- package/src/api/schema-editor-routes.ts +0 -41
- package/src/api/server.ts +0 -271
- package/src/api/types.ts +0 -104
- package/src/auth/adapter-middleware.ts +0 -114
- package/src/auth/admin-roles-route.ts +0 -36
- package/src/auth/admin-user-ops.ts +0 -236
- package/src/auth/admin-users-route.ts +0 -302
- package/src/auth/api-keys/api-key-middleware.ts +0 -133
- package/src/auth/api-keys/api-key-routes.ts +0 -193
- package/src/auth/api-keys/api-key-store.ts +0 -340
- package/src/auth/apple-oauth.ts +0 -122
- package/src/auth/bitbucket-oauth.ts +0 -84
- package/src/auth/builtin-auth-adapter.ts +0 -380
- package/src/auth/custom-auth-adapter.ts +0 -86
- package/src/auth/discord-oauth.ts +0 -85
- package/src/auth/facebook-oauth.ts +0 -74
- package/src/auth/github-oauth.ts +0 -112
- package/src/auth/gitlab-oauth.ts +0 -72
- package/src/auth/google-oauth.ts +0 -223
- package/src/auth/jwt.ts +0 -208
- package/src/auth/linkedin-oauth.ts +0 -83
- package/src/auth/magic-link-routes.ts +0 -167
- package/src/auth/mfa-crypto.ts +0 -91
- package/src/auth/mfa-routes.ts +0 -323
- package/src/auth/mfa.ts +0 -161
- package/src/auth/microsoft-oauth.ts +0 -90
- package/src/auth/middleware.ts +0 -369
- package/src/auth/password.ts +0 -77
- package/src/auth/rate-limiter.ts +0 -225
- package/src/auth/reset-password-admin.ts +0 -160
- package/src/auth/rls-scope.ts +0 -58
- package/src/auth/routes.ts +0 -802
- package/src/auth/session-routes.ts +0 -353
- package/src/auth/slack-oauth.ts +0 -73
- package/src/auth/spotify-oauth.ts +0 -69
- package/src/auth/twitter-oauth.ts +0 -128
- package/src/collections/BackendCollectionRegistry.ts +0 -20
- package/src/collections/loader.ts +0 -50
- package/src/cron/cron-loader.ts +0 -84
- package/src/cron/cron-routes.test.ts +0 -265
- package/src/cron/cron-routes.ts +0 -85
- package/src/cron/cron-scheduler.test.ts +0 -559
- package/src/cron/cron-scheduler.ts +0 -581
- package/src/cron/cron-store.ts +0 -166
- package/src/db/interfaces.ts +0 -60
- package/src/email/index.ts +0 -19
- package/src/email/smtp-email-service.ts +0 -123
- package/src/email/templates.ts +0 -470
- package/src/env.ts +0 -227
- package/src/functions/function-loader.ts +0 -116
- package/src/functions/function-routes.ts +0 -31
- package/src/history/history-routes.ts +0 -129
- package/src/index.ts +0 -70
- package/src/init/docs.ts +0 -47
- package/src/init/health.ts +0 -37
- package/src/init/middlewares.ts +0 -61
- package/src/init/shutdown.ts +0 -56
- package/src/init/storage.ts +0 -57
- package/src/init.ts +0 -1041
- package/src/serve-spa.ts +0 -89
- package/src/services/driver-registry.ts +0 -183
- package/src/services/routed-realtime-service.ts +0 -113
- package/src/services/webhook-service.ts +0 -155
- package/src/singleton.ts +0 -70
- package/src/storage/LocalStorageController.ts +0 -389
- package/src/storage/S3StorageController.ts +0 -300
- package/src/storage/image-transform.ts +0 -218
- package/src/storage/routes.ts +0 -368
- package/src/storage/storage-registry.ts +0 -188
- package/src/storage/tus-handler.ts +0 -315
- package/src/types/index.ts +0 -27
- package/src/utils/dev-port.ts +0 -196
- package/src/utils/logger.ts +0 -143
- package/src/utils/logging.ts +0 -40
- package/src/utils/request-id.ts +0 -40
- package/src/utils/request-logger.ts +0 -72
- package/test/api-generator.test.ts +0 -588
- package/test/api-key-permission-guard.test.ts +0 -144
- package/test/ast-schema-editor.test.ts +0 -89
- package/test/auth-middleware-hono.test.ts +0 -556
- package/test/auth-routes.test.ts +0 -1098
- package/test/backend-hooks-data.test.ts +0 -477
- package/test/custom-auth-adapter.test.ts +0 -189
- package/test/driver-registry.test.ts +0 -282
- package/test/email-templates.test.ts +0 -174
- package/test/env.test.ts +0 -128
- package/test/error-propagation.test.ts +0 -226
- package/test/errors-hono.test.ts +0 -133
- package/test/errors.test.ts +0 -155
- package/test/function-loader.test.ts +0 -127
- package/test/graphql-schema-generator.test.ts +0 -554
- package/test/jwt-security.test.ts +0 -182
- package/test/jwt.test.ts +0 -326
- package/test/mfa.test.ts +0 -197
- package/test/middleware.test.ts +0 -305
- package/test/multi-datasource-routing.test.ts +0 -113
- package/test/password.test.ts +0 -165
- package/test/query-parser.test.ts +0 -233
- package/test/rate-limiter.test.ts +0 -102
- package/test/reset-password-admin.test.ts +0 -113
- package/test/routed-realtime-service.test.ts +0 -86
- package/test/safe-compare.test.ts +0 -66
- package/test/singleton.test.ts +0 -59
- package/test/smtp-email-service.test.ts +0 -169
- package/test/storage-local.test.ts +0 -271
- package/test/storage-registry.test.ts +0 -282
- package/test/storage-routes.test.ts +0 -222
- package/test/storage-s3.test.ts +0 -304
- package/test/transform-auth-response.test.ts +0 -305
- package/test/webhook-service.test.ts +0 -260
- package/tsconfig.json +0 -54
- package/tsconfig.prod.json +0 -23
- package/vite.config.ts +0 -86
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
import type { VectorSearchParams, LogicalCondition, FilterCondition } from "@rebasepro/types";
|
|
2
|
-
import { QueryOptions } from "../types";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Map PostgREST-style operators to Rebase WhereFilterOp
|
|
6
|
-
*/
|
|
7
|
-
export function mapOperator(op: string): string | null {
|
|
8
|
-
switch (op) {
|
|
9
|
-
case "eq": return "==";
|
|
10
|
-
case "neq": return "!=";
|
|
11
|
-
case "gt": return ">";
|
|
12
|
-
case "gte": return ">=";
|
|
13
|
-
case "lt": return "<";
|
|
14
|
-
case "lte": return "<=";
|
|
15
|
-
case "in": return "in";
|
|
16
|
-
case "nin": return "not-in";
|
|
17
|
-
case "cs": return "array-contains";
|
|
18
|
-
case "csa": return "array-contains-any";
|
|
19
|
-
default: return null;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function getLastValue(val: unknown): unknown {
|
|
24
|
-
if (Array.isArray(val)) {
|
|
25
|
-
return val[val.length - 1];
|
|
26
|
-
}
|
|
27
|
-
return val;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function parseLogicalString(str: string): FilterCondition | LogicalCondition {
|
|
31
|
-
str = str.trim();
|
|
32
|
-
if (str.startsWith("or(") && str.endsWith(")")) {
|
|
33
|
-
const inner = str.slice(3, -1);
|
|
34
|
-
return { type: "or",
|
|
35
|
-
conditions: parseLogicalList(inner) };
|
|
36
|
-
}
|
|
37
|
-
if (str.startsWith("and(") && str.endsWith(")")) {
|
|
38
|
-
const inner = str.slice(4, -1);
|
|
39
|
-
return { type: "and",
|
|
40
|
-
conditions: parseLogicalList(inner) };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// It's a leaf condition: field.op.val
|
|
44
|
-
const firstDot = str.indexOf(".");
|
|
45
|
-
if (firstDot === -1) {
|
|
46
|
-
return { column: str,
|
|
47
|
-
operator: "==",
|
|
48
|
-
value: true };
|
|
49
|
-
}
|
|
50
|
-
const field = str.substring(0, firstDot);
|
|
51
|
-
const rest = str.substring(firstDot + 1);
|
|
52
|
-
const secondDot = rest.indexOf(".");
|
|
53
|
-
let op = "eq";
|
|
54
|
-
let valStr = rest;
|
|
55
|
-
if (secondDot !== -1) {
|
|
56
|
-
op = rest.substring(0, secondDot);
|
|
57
|
-
valStr = rest.substring(secondDot + 1);
|
|
58
|
-
} else {
|
|
59
|
-
op = "eq";
|
|
60
|
-
valStr = rest;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const rebaseOp = (mapOperator(op) || "==") as FilterCondition["operator"];
|
|
64
|
-
let parsedVal: unknown = valStr;
|
|
65
|
-
if (valStr === "true") parsedVal = true;
|
|
66
|
-
else if (valStr === "false") parsedVal = false;
|
|
67
|
-
else if (valStr === "null") parsedVal = null;
|
|
68
|
-
else if (!isNaN(Number(valStr)) && valStr.trim() !== "") parsedVal = Number(valStr);
|
|
69
|
-
else if (valStr.startsWith("(")) {
|
|
70
|
-
const arrayContent = valStr.endsWith(")") ? valStr.slice(1, -1) : valStr.slice(1);
|
|
71
|
-
parsedVal = arrayContent.split(",").map(v => {
|
|
72
|
-
const trimmed = v.trim();
|
|
73
|
-
if (!isNaN(Number(trimmed)) && trimmed !== "") return Number(trimmed);
|
|
74
|
-
if (trimmed === "true") return true;
|
|
75
|
-
if (trimmed === "false") return false;
|
|
76
|
-
if (trimmed === "null") return null;
|
|
77
|
-
return trimmed;
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return { column: field,
|
|
82
|
-
operator: rebaseOp,
|
|
83
|
-
value: parsedVal };
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function parseLogicalList(str: string): (FilterCondition | LogicalCondition)[] {
|
|
87
|
-
const list: (FilterCondition | LogicalCondition)[] = [];
|
|
88
|
-
let depth = 0;
|
|
89
|
-
let current = "";
|
|
90
|
-
|
|
91
|
-
for (let i = 0; i < str.length; i++) {
|
|
92
|
-
const char = str[i];
|
|
93
|
-
if (char === "(") depth++;
|
|
94
|
-
if (char === ")") depth--;
|
|
95
|
-
|
|
96
|
-
if (char === "," && depth === 0) {
|
|
97
|
-
list.push(parseLogicalString(current));
|
|
98
|
-
current = "";
|
|
99
|
-
} else {
|
|
100
|
-
current += char;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
if (current) {
|
|
104
|
-
list.push(parseLogicalString(current));
|
|
105
|
-
}
|
|
106
|
-
return list;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Parse query parameters into QueryOptions
|
|
111
|
-
*/
|
|
112
|
-
export function parseQueryOptions(query: Record<string, unknown>): QueryOptions {
|
|
113
|
-
const options: QueryOptions = {};
|
|
114
|
-
|
|
115
|
-
// Pagination
|
|
116
|
-
const limitVal = getLastValue(query.limit);
|
|
117
|
-
if (limitVal) options.limit = parseInt(String(limitVal));
|
|
118
|
-
|
|
119
|
-
const offsetVal = getLastValue(query.offset);
|
|
120
|
-
if (offsetVal) options.offset = parseInt(String(offsetVal));
|
|
121
|
-
|
|
122
|
-
const pageVal = getLastValue(query.page);
|
|
123
|
-
if (pageVal) {
|
|
124
|
-
const page = parseInt(String(pageVal));
|
|
125
|
-
const limit = options.limit || 20;
|
|
126
|
-
options.offset = (page - 1) * limit;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Filtering
|
|
130
|
-
options.where = {};
|
|
131
|
-
|
|
132
|
-
// Handle logical conditions
|
|
133
|
-
const orVal = getLastValue(query.or);
|
|
134
|
-
const andVal = getLastValue(query.and);
|
|
135
|
-
if (orVal) {
|
|
136
|
-
let orStr = String(orVal).trim();
|
|
137
|
-
if (orStr.startsWith("(") && orStr.endsWith(")")) {
|
|
138
|
-
orStr = orStr.slice(1, -1);
|
|
139
|
-
}
|
|
140
|
-
options.logical = {
|
|
141
|
-
type: "or",
|
|
142
|
-
conditions: parseLogicalList(orStr)
|
|
143
|
-
};
|
|
144
|
-
} else if (andVal) {
|
|
145
|
-
let andStr = String(andVal).trim();
|
|
146
|
-
if (andStr.startsWith("(") && andStr.endsWith(")")) {
|
|
147
|
-
andStr = andStr.slice(1, -1);
|
|
148
|
-
}
|
|
149
|
-
options.logical = {
|
|
150
|
-
type: "and",
|
|
151
|
-
conditions: parseLogicalList(andStr)
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// PostgREST-style filtering: ?field=op.value
|
|
156
|
-
const reservedQueryKeys = ["limit", "offset", "page", "orderBy", "include", "fields", "searchString", "vector_search", "vector", "vector_distance", "vector_threshold", "or", "and"];
|
|
157
|
-
for (const [key, rawValue] of Object.entries(query)) {
|
|
158
|
-
if (reservedQueryKeys.includes(key)) continue;
|
|
159
|
-
|
|
160
|
-
const rawValues = Array.isArray(rawValue) ? rawValue : [rawValue];
|
|
161
|
-
const conditions: [string, unknown][] = [];
|
|
162
|
-
|
|
163
|
-
for (const value of rawValues) {
|
|
164
|
-
if (typeof value === "string") {
|
|
165
|
-
const parts = value.split(".");
|
|
166
|
-
if (parts.length >= 2) {
|
|
167
|
-
const op = parts[0];
|
|
168
|
-
const val = parts.slice(1).join(".");
|
|
169
|
-
const rebaseOp = mapOperator(op);
|
|
170
|
-
|
|
171
|
-
if (rebaseOp) {
|
|
172
|
-
let parsedVal: string | number | boolean | null | (string | number | boolean | null)[] = val;
|
|
173
|
-
// Attempt to parse primitive types or arrays
|
|
174
|
-
if (val === "true") parsedVal = true;
|
|
175
|
-
else if (val === "false") parsedVal = false;
|
|
176
|
-
else if (val === "null") parsedVal = null;
|
|
177
|
-
else if (!isNaN(Number(val)) && val.trim() !== "") parsedVal = Number(val);
|
|
178
|
-
else if (val.startsWith("(")) {
|
|
179
|
-
// Array for 'in' or 'not-in' ops (e.g. (1,2,3) or (a,b,c))
|
|
180
|
-
const arrayContent = val.endsWith(")") ? val.slice(1, -1) : val.slice(1);
|
|
181
|
-
parsedVal = arrayContent.split(",").map(v => {
|
|
182
|
-
const trimmed = v.trim();
|
|
183
|
-
if (!isNaN(Number(trimmed)) && trimmed !== "") return Number(trimmed);
|
|
184
|
-
if (trimmed === "true") return true;
|
|
185
|
-
if (trimmed === "false") return false;
|
|
186
|
-
if (trimmed === "null") return null;
|
|
187
|
-
return trimmed;
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
conditions.push([rebaseOp, parsedVal]);
|
|
192
|
-
} else {
|
|
193
|
-
// Fallback: assume implicit eq if the dot wasn't an operator (e.g. email or float)
|
|
194
|
-
let parsedVal: string | number | boolean | null = value;
|
|
195
|
-
if (!isNaN(Number(value)) && value.trim() !== "") parsedVal = Number(value);
|
|
196
|
-
conditions.push(["==", parsedVal]);
|
|
197
|
-
}
|
|
198
|
-
} else {
|
|
199
|
-
// Implicit eq
|
|
200
|
-
let parsedVal: string | number | boolean | null = value;
|
|
201
|
-
if (value === "true") parsedVal = true;
|
|
202
|
-
else if (value === "false") parsedVal = false;
|
|
203
|
-
else if (value === "null") parsedVal = null;
|
|
204
|
-
else if (!isNaN(Number(value)) && value.trim() !== "") parsedVal = Number(value);
|
|
205
|
-
|
|
206
|
-
conditions.push(["==", parsedVal]);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (conditions.length > 0) {
|
|
212
|
-
options.where[key] = conditions.length === 1 ? conditions[0] : conditions;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (Object.keys(options.where).length === 0) {
|
|
217
|
-
delete options.where;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Sorting
|
|
221
|
-
const orderByVal = getLastValue(query.orderBy);
|
|
222
|
-
if (orderByVal) {
|
|
223
|
-
try {
|
|
224
|
-
options.orderBy = typeof orderByVal === "string"
|
|
225
|
-
? JSON.parse(orderByVal)
|
|
226
|
-
: orderByVal;
|
|
227
|
-
} catch {
|
|
228
|
-
// Try simple format: "field:direction"
|
|
229
|
-
if (typeof orderByVal === "string") {
|
|
230
|
-
const [field, direction] = orderByVal.split(":");
|
|
231
|
-
const dir = (direction === "desc" ? "desc" : "asc") as "asc" | "desc";
|
|
232
|
-
options.orderBy = [
|
|
233
|
-
{
|
|
234
|
-
field,
|
|
235
|
-
direction: dir
|
|
236
|
-
}
|
|
237
|
-
];
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Relation includes
|
|
243
|
-
const includeVal = getLastValue(query.include);
|
|
244
|
-
if (includeVal) {
|
|
245
|
-
const includeStr = String(includeVal).trim();
|
|
246
|
-
if (includeStr === "*") {
|
|
247
|
-
options.include = ["*"];
|
|
248
|
-
} else {
|
|
249
|
-
options.include = includeStr.split(",").map(s => s.trim()).filter(Boolean);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Field selection
|
|
254
|
-
const fieldsVal = getLastValue(query.fields);
|
|
255
|
-
if (fieldsVal) {
|
|
256
|
-
const fieldsStr = String(fieldsVal).trim();
|
|
257
|
-
options.fields = fieldsStr.split(",").map(s => s.trim()).filter(Boolean);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Vector similarity search
|
|
261
|
-
const vectorSearchVal = getLastValue(query.vector_search);
|
|
262
|
-
const vectorVal = getLastValue(query.vector);
|
|
263
|
-
if (vectorSearchVal && vectorVal) {
|
|
264
|
-
const vectorStr = String(vectorVal);
|
|
265
|
-
let queryVector: number[];
|
|
266
|
-
try {
|
|
267
|
-
queryVector = JSON.parse(vectorStr) as number[];
|
|
268
|
-
if (!Array.isArray(queryVector) || !queryVector.every(v => typeof v === "number")) {
|
|
269
|
-
throw new Error("Expected array of numbers");
|
|
270
|
-
}
|
|
271
|
-
} catch {
|
|
272
|
-
throw new Error("Invalid vector format. Expected JSON array of numbers, e.g. [0.1,0.2,0.3]");
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const distanceParamVal = getLastValue(query.vector_distance);
|
|
276
|
-
const distanceParam = distanceParamVal ? String(distanceParamVal) : "cosine";
|
|
277
|
-
if (distanceParam !== "cosine" && distanceParam !== "l2" && distanceParam !== "inner_product") {
|
|
278
|
-
throw new Error(`Invalid vector_distance: ${distanceParam}. Expected: cosine, l2, or inner_product`);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const vectorSearch: VectorSearchParams = {
|
|
282
|
-
property: String(vectorSearchVal),
|
|
283
|
-
vector: queryVector,
|
|
284
|
-
distance: distanceParam
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
const thresholdVal = getLastValue(query.vector_threshold);
|
|
288
|
-
if (thresholdVal) {
|
|
289
|
-
const threshold = parseFloat(String(thresholdVal));
|
|
290
|
-
if (isNaN(threshold)) {
|
|
291
|
-
throw new Error("Invalid vector_threshold. Expected a number.");
|
|
292
|
-
}
|
|
293
|
-
vectorSearch.threshold = threshold;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
options.vectorSearch = vectorSearch;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
return options;
|
|
300
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { Hono } from "hono";
|
|
2
|
-
import { AstSchemaEditor } from "./ast-schema-editor";
|
|
3
|
-
import { errorHandler } from "./errors";
|
|
4
|
-
import { HonoEnv } from "./types";
|
|
5
|
-
|
|
6
|
-
export function createSchemaEditorRoutes(collectionsDir: string): Hono<HonoEnv> {
|
|
7
|
-
const router = new Hono<HonoEnv>();
|
|
8
|
-
router.onError(errorHandler);
|
|
9
|
-
const editor = new AstSchemaEditor(collectionsDir);
|
|
10
|
-
|
|
11
|
-
router.post("/property/save", async (c) => {
|
|
12
|
-
const body = await c.req.json();
|
|
13
|
-
const { collectionId, propertyKey, propertyConfig } = body;
|
|
14
|
-
await editor.saveProperty(collectionId, propertyKey, propertyConfig);
|
|
15
|
-
return c.json({ success: true });
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
router.post("/property/delete", async (c) => {
|
|
19
|
-
const body = await c.req.json();
|
|
20
|
-
const { collectionId, propertyKey } = body;
|
|
21
|
-
await editor.deleteProperty(collectionId, propertyKey);
|
|
22
|
-
return c.json({ success: true });
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
router.post("/collection/save", async (c) => {
|
|
26
|
-
const body = await c.req.json();
|
|
27
|
-
const { collectionId, collectionData } = body;
|
|
28
|
-
await editor.saveCollection(collectionId, collectionData);
|
|
29
|
-
return c.json({ success: true });
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
router.post("/collection/delete", async (c) => {
|
|
33
|
-
const body = await c.req.json();
|
|
34
|
-
const { collectionId } = body;
|
|
35
|
-
await editor.deleteCollection(collectionId);
|
|
36
|
-
return c.json({ success: true });
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
return router;
|
|
40
|
-
}
|
|
41
|
-
|
package/src/api/server.ts
DELETED
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
import { Hono } from "hono";
|
|
2
|
-
import { cors } from "hono/cors";
|
|
3
|
-
import { secureHeaders } from "hono/secure-headers";
|
|
4
|
-
import { graphqlServer } from "@hono/graphql-server";
|
|
5
|
-
import { serve } from "@hono/node-server";
|
|
6
|
-
import { GraphQLSchemaGenerator } from "./graphql/graphql-schema-generator";
|
|
7
|
-
import { RestApiGenerator } from "./rest/api-generator";
|
|
8
|
-
import { DataDriver, EntityCollection, Relation } from "@rebasepro/types";
|
|
9
|
-
import { createDataSourceRegistry, resolveDataSource } from "@rebasepro/common";
|
|
10
|
-
import { ApiConfig, HonoEnv } from "./types";
|
|
11
|
-
import { loadCollectionsFromDirectory } from "../collections/loader";
|
|
12
|
-
import { createSchemaEditorRoutes } from "./schema-editor-routes";
|
|
13
|
-
import { createAuthMiddleware, requireAuth, requireAdmin } from "../auth/middleware";
|
|
14
|
-
import { errorHandler } from "./errors";
|
|
15
|
-
import { generateOpenApiSpec } from "./openapi-generator";
|
|
16
|
-
import { requestId } from "../utils/request-id";
|
|
17
|
-
import { logger } from "../utils/logger";
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Simplified API server that leverages existing Rebase infrastructure
|
|
21
|
-
* Can be used standalone or mounted on existing Hono app
|
|
22
|
-
*/
|
|
23
|
-
export class RebaseApiServer {
|
|
24
|
-
private app: Hono<HonoEnv>;
|
|
25
|
-
private router: Hono<HonoEnv>;
|
|
26
|
-
private config: ApiConfig;
|
|
27
|
-
private driver: DataDriver;
|
|
28
|
-
|
|
29
|
-
private constructor(config: ApiConfig & { driver: DataDriver }) {
|
|
30
|
-
this.config = {
|
|
31
|
-
basePath: "/api",
|
|
32
|
-
enableGraphQL: true,
|
|
33
|
-
enableREST: true,
|
|
34
|
-
pagination: {
|
|
35
|
-
defaultLimit: 20,
|
|
36
|
-
maxLimit: 100
|
|
37
|
-
},
|
|
38
|
-
...config
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
this.driver = config.driver;
|
|
42
|
-
|
|
43
|
-
this.app = new Hono<HonoEnv>();
|
|
44
|
-
this.router = new Hono<HonoEnv>();
|
|
45
|
-
|
|
46
|
-
this.setupMiddleware();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Factory method to create an asynchronously initialized ApiServer instance
|
|
51
|
-
*/
|
|
52
|
-
public static async create(config: ApiConfig & { driver: DataDriver }): Promise<RebaseApiServer> {
|
|
53
|
-
if (config.collectionsDir && (!config.collections || config.collections.length === 0)) {
|
|
54
|
-
config.collections = await loadCollectionsFromDirectory(config.collectionsDir);
|
|
55
|
-
} else if (!config.collections) {
|
|
56
|
-
config.collections = [];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const server = new RebaseApiServer(config);
|
|
60
|
-
server.setupRoutes();
|
|
61
|
-
// Since we mount routes directly to router, we can let consumer attach it
|
|
62
|
-
server.app.route("/", server.router);
|
|
63
|
-
|
|
64
|
-
// Hono global error handler on the root app
|
|
65
|
-
server.app.onError(errorHandler);
|
|
66
|
-
server.router.onError(errorHandler);
|
|
67
|
-
|
|
68
|
-
return server;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Setup Hono middleware
|
|
73
|
-
*/
|
|
74
|
-
private setupMiddleware(): void {
|
|
75
|
-
// Request ID — must be first so all downstream middleware can access it
|
|
76
|
-
this.router.use("/*", requestId());
|
|
77
|
-
|
|
78
|
-
// Security headers — use same-origin-allow-popups for COOP so that
|
|
79
|
-
// OAuth popup flows (Google, etc.) can postMessage back to the opener.
|
|
80
|
-
this.router.use("/*", secureHeaders({
|
|
81
|
-
crossOriginOpenerPolicy: "same-origin-allow-popups"
|
|
82
|
-
}));
|
|
83
|
-
|
|
84
|
-
// CORS — only applied if explicitly configured via `cors` option.
|
|
85
|
-
// If omitted, the user is expected to configure CORS on their own
|
|
86
|
-
// Hono app before mounting the API (recommended approach).
|
|
87
|
-
if (this.config.cors) {
|
|
88
|
-
const origin = this.config.cors.origin;
|
|
89
|
-
this.router.use("/*", cors({
|
|
90
|
-
origin: typeof origin === "boolean"
|
|
91
|
-
? (origin ? ((o: string) => o) : "")
|
|
92
|
-
: (origin ?? "*"),
|
|
93
|
-
credentials: this.config.cors.credentials ?? false
|
|
94
|
-
}));
|
|
95
|
-
} else if (process.env.NODE_ENV !== "production") {
|
|
96
|
-
logger.warn(
|
|
97
|
-
"⚠️ [RebaseApiServer] No CORS configuration provided. " +
|
|
98
|
-
"The API will accept requests from any origin. " +
|
|
99
|
-
"Pass a `cors` option or configure CORS on your Hono app."
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Auth middleware
|
|
104
|
-
this.router.use("/*", createAuthMiddleware({
|
|
105
|
-
driver: this.driver,
|
|
106
|
-
requireAuth: this.config.requireAuth ?? true,
|
|
107
|
-
validator: this.config.authValidator
|
|
108
|
-
}));
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Setup API routes using existing services
|
|
113
|
-
*/
|
|
114
|
-
private setupRoutes(): void {
|
|
115
|
-
const basePath = this.config.basePath!;
|
|
116
|
-
|
|
117
|
-
// Health check
|
|
118
|
-
this.router.get(`${basePath}/health`, (c) => {
|
|
119
|
-
return c.json({
|
|
120
|
-
status: "healthy",
|
|
121
|
-
timestamp: new Date().toISOString(),
|
|
122
|
-
collections: this.config.collections?.map((col: EntityCollection) => col.slug) || [],
|
|
123
|
-
driver: this.driver.key
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// Collections metadata endpoint
|
|
128
|
-
this.router.get(`${basePath}/collections`, (c) => {
|
|
129
|
-
const collectionsMetadata = (this.config.collections || []).map((col: EntityCollection) => ({
|
|
130
|
-
slug: col.slug,
|
|
131
|
-
name: col.name,
|
|
132
|
-
singularName: col.singularName,
|
|
133
|
-
description: col.description,
|
|
134
|
-
properties: Object.keys(col.properties),
|
|
135
|
-
relations: col.relations?.map((r: Relation) => ({
|
|
136
|
-
relationName: r.relationName,
|
|
137
|
-
target: typeof r.target === "function" ? r.target().slug : r.target,
|
|
138
|
-
cardinality: r.cardinality,
|
|
139
|
-
direction: r.direction
|
|
140
|
-
})) || []
|
|
141
|
-
}));
|
|
142
|
-
|
|
143
|
-
return c.json({ data: collectionsMetadata });
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
// Server data routes are only generated for server-transport
|
|
147
|
-
// collections; direct/custom sources are client-only.
|
|
148
|
-
const dataSourceRegistry = createDataSourceRegistry(this.config.dataSources);
|
|
149
|
-
const serverCollections = (this.config.collections || []).filter(
|
|
150
|
-
(collection) => resolveDataSource(collection, dataSourceRegistry).transport === "server"
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
// GraphQL endpoint
|
|
154
|
-
if (this.config.enableGraphQL) {
|
|
155
|
-
const schemaGenerator = new GraphQLSchemaGenerator(serverCollections, this.driver);
|
|
156
|
-
const schema = schemaGenerator.generateSchema();
|
|
157
|
-
|
|
158
|
-
// Context is automatically passed to resolvers via contextValue containing Hono's 'c'
|
|
159
|
-
this.router.use(`${basePath}/graphql`, graphqlServer({
|
|
160
|
-
schema
|
|
161
|
-
}));
|
|
162
|
-
|
|
163
|
-
// Lightweight GraphiQL IDE
|
|
164
|
-
if (process.env.NODE_ENV !== "production") {
|
|
165
|
-
this.router.get(`${basePath}/graphiql`, (c) => {
|
|
166
|
-
return c.html(`<!DOCTYPE html>
|
|
167
|
-
<html>
|
|
168
|
-
<head>
|
|
169
|
-
<meta charset=utf-8/>
|
|
170
|
-
<title>Rebase GraphiQL</title>
|
|
171
|
-
<link rel="stylesheet" href="https://unpkg.com/graphiql/graphiql.min.css" />
|
|
172
|
-
<style>body,html,#graphiql{height:100%;margin:0;width:100%;}</style>
|
|
173
|
-
</head>
|
|
174
|
-
<body>
|
|
175
|
-
<div id="graphiql">Loading...</div>
|
|
176
|
-
<script crossorigin src="https://unpkg.com/react/umd/react.production.min.js"></script>
|
|
177
|
-
<script crossorigin src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
|
|
178
|
-
<script src="https://unpkg.com/graphiql/graphiql.min.js"></script>
|
|
179
|
-
<script>
|
|
180
|
-
const fetcher = GraphiQL.createFetcher({ url: '${basePath}/graphql' });
|
|
181
|
-
ReactDOM.render(
|
|
182
|
-
React.createElement(GraphiQL, { fetcher }),
|
|
183
|
-
document.getElementById('graphiql'),
|
|
184
|
-
);
|
|
185
|
-
</script>
|
|
186
|
-
</body>
|
|
187
|
-
</html>`);
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (this.config.enableREST) {
|
|
193
|
-
const restGenerator = new RestApiGenerator(serverCollections, this.driver);
|
|
194
|
-
const restRoutes = restGenerator.generateRoutes();
|
|
195
|
-
this.router.route(basePath, restRoutes);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Schema Editor endpoints
|
|
199
|
-
if (this.config.collectionsDir) {
|
|
200
|
-
if (process.env.NODE_ENV === "production") {
|
|
201
|
-
logger.warn("[RebaseApiServer] Schema Editor is disabled in production environments for security.");
|
|
202
|
-
} else {
|
|
203
|
-
// Auth middlewares applied to schema-editor via the router prefix
|
|
204
|
-
// MUST be declared before .route() so they execute first
|
|
205
|
-
this.router.use(`${basePath}/schema-editor/*`, requireAuth, requireAdmin);
|
|
206
|
-
const schemaEditorRoutes = createSchemaEditorRoutes(this.config.collectionsDir);
|
|
207
|
-
this.router.route(`${basePath}/schema-editor`, schemaEditorRoutes);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// OpenAPI endpoint
|
|
212
|
-
this.router.get(`${basePath}/docs`, (c) => {
|
|
213
|
-
const openApiSpec = generateOpenApiSpec(this.config.collections || [], {
|
|
214
|
-
basePath: this.config.basePath,
|
|
215
|
-
requireAuth: this.config.requireAuth ?? true
|
|
216
|
-
});
|
|
217
|
-
return c.json(openApiSpec);
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
// Simple Swagger UI
|
|
221
|
-
if (process.env.NODE_ENV !== "production") {
|
|
222
|
-
this.router.get(`${basePath}/swagger`, (c) => {
|
|
223
|
-
return c.html(`
|
|
224
|
-
<!DOCTYPE html>
|
|
225
|
-
<html>
|
|
226
|
-
<head>
|
|
227
|
-
<title>Rebase API Documentation</title>
|
|
228
|
-
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@4.15.5/swagger-ui.css" />
|
|
229
|
-
</head>
|
|
230
|
-
<body>
|
|
231
|
-
<div id="swagger-ui"></div>
|
|
232
|
-
<script src="https://unpkg.com/swagger-ui-dist@4.15.5/swagger-ui-bundle.js"></script>
|
|
233
|
-
<script>
|
|
234
|
-
SwaggerUIBundle({
|
|
235
|
-
url: '${basePath}/docs',
|
|
236
|
-
dom_id: '#swagger-ui'
|
|
237
|
-
});
|
|
238
|
-
</script>
|
|
239
|
-
</body>
|
|
240
|
-
</html>
|
|
241
|
-
`);
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Get the Hono router with all API routes
|
|
248
|
-
*/
|
|
249
|
-
getRouter(): Hono<HonoEnv> {
|
|
250
|
-
return this.router;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Get the standalone Hono app
|
|
255
|
-
*/
|
|
256
|
-
getApp(): Hono<HonoEnv> {
|
|
257
|
-
return this.app;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Start the server (standalone mode) via @hono/node-server
|
|
262
|
-
*/
|
|
263
|
-
listen(port = 3000, callback?: () => void): void {
|
|
264
|
-
serve({
|
|
265
|
-
fetch: this.app.fetch,
|
|
266
|
-
port
|
|
267
|
-
}, () => {
|
|
268
|
-
if (callback) callback();
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
}
|