@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
package/src/api/types.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { EntityCollection, VectorSearchParams, LogicalCondition } from "@rebasepro/types";
|
|
2
|
-
import { AuthResult } from "../auth/middleware";
|
|
3
|
-
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
4
|
-
import { DataDriver } from "@rebasepro/types";
|
|
5
|
-
import type { ApiKeyMasked } from "../auth/api-keys/api-key-types";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Hono Environment Variables
|
|
9
|
-
* Passed to generic Hono<HonoEnv> to type `c.get()`
|
|
10
|
-
*/
|
|
11
|
-
export type HonoEnv = {
|
|
12
|
-
Variables: {
|
|
13
|
-
user?: AuthResult | { userId?: string, roles?: string[] };
|
|
14
|
-
driver?: DataDriver;
|
|
15
|
-
/** Set when the request is authenticated via a Service API Key. */
|
|
16
|
-
apiKey?: ApiKeyMasked;
|
|
17
|
-
/** Unique request correlation ID (generated or propagated from X-Request-ID header). */
|
|
18
|
-
requestId?: string;
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Configuration for API generation
|
|
24
|
-
*/
|
|
25
|
-
/**
|
|
26
|
-
* Configuration for API generation
|
|
27
|
-
*/
|
|
28
|
-
export interface ApiConfig {
|
|
29
|
-
collections?: EntityCollection[];
|
|
30
|
-
collectionsDir?: string;
|
|
31
|
-
/**
|
|
32
|
-
* Declared data sources. When provided, collections on a `direct`/`custom`
|
|
33
|
-
* transport are treated as client-only and no server routes are generated
|
|
34
|
-
* for them.
|
|
35
|
-
*/
|
|
36
|
-
dataSources?: import("@rebasepro/types").DataSourceDefinition[];
|
|
37
|
-
basePath?: string;
|
|
38
|
-
enableGraphQL?: boolean;
|
|
39
|
-
enableREST?: boolean;
|
|
40
|
-
cors?: {
|
|
41
|
-
origin?: string | string[] | boolean;
|
|
42
|
-
credentials?: boolean;
|
|
43
|
-
};
|
|
44
|
-
/** Whether auth is required for API endpoints (default: true) */
|
|
45
|
-
requireAuth?: boolean;
|
|
46
|
-
/** Optional custom validator for authentication */
|
|
47
|
-
authValidator?: (c: import("hono").Context<import("./types").HonoEnv>) => Promise<AuthResult>;
|
|
48
|
-
pagination?: {
|
|
49
|
-
defaultLimit: number;
|
|
50
|
-
maxLimit: number;
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Context passed to resolvers and handlers
|
|
56
|
-
*/
|
|
57
|
-
export interface ApiContext {
|
|
58
|
-
user?: AuthResult;
|
|
59
|
-
collections: Map<string, EntityCollection>;
|
|
60
|
-
db: NodePgDatabase; // Drizzle DB instance
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Standard API response format
|
|
65
|
-
*/
|
|
66
|
-
export interface ApiResponse<T = unknown> {
|
|
67
|
-
data?: T;
|
|
68
|
-
error?: {
|
|
69
|
-
message: string;
|
|
70
|
-
code?: string;
|
|
71
|
-
details?: unknown;
|
|
72
|
-
};
|
|
73
|
-
meta?: {
|
|
74
|
-
total?: number;
|
|
75
|
-
page?: number;
|
|
76
|
-
limit?: number;
|
|
77
|
-
hasMore?: boolean;
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Query options for API endpoints
|
|
83
|
-
*/
|
|
84
|
-
export interface QueryOptions {
|
|
85
|
-
limit?: number;
|
|
86
|
-
offset?: number;
|
|
87
|
-
where?: Record<string, unknown>;
|
|
88
|
-
logical?: LogicalCondition;
|
|
89
|
-
orderBy?: Array<{ field: string; direction: "asc" | "desc" }>;
|
|
90
|
-
include?: string[];
|
|
91
|
-
/** Columns to return in the response (field-level selection) */
|
|
92
|
-
fields?: string[];
|
|
93
|
-
/** Vector similarity search configuration */
|
|
94
|
-
vectorSearch?: VectorSearchParams;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Relation resolution configuration
|
|
99
|
-
*/
|
|
100
|
-
export interface RelationConfig {
|
|
101
|
-
relationName: string;
|
|
102
|
-
depth?: number;
|
|
103
|
-
include?: string[];
|
|
104
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Adapter Auth Middleware
|
|
3
|
-
*
|
|
4
|
-
* Creates a Hono middleware that delegates authentication to an `AuthAdapter`
|
|
5
|
-
* instead of hardcoded JWT verification. This is used when the user passes
|
|
6
|
-
* an `AuthAdapter` to `initializeRebaseBackend()`.
|
|
7
|
-
*
|
|
8
|
-
* The middleware:
|
|
9
|
-
* 1. Checks for API key tokens (`rk_` prefix) first — these are Rebase-level
|
|
10
|
-
* 2. Falls back to `adapter.verifyRequest(request)` to resolve the user
|
|
11
|
-
* 3. Scopes the DataDriver via `withAuth()` for RLS
|
|
12
|
-
* 4. Enforces auth (401) when `requireAuth` is true and no user is found
|
|
13
|
-
*
|
|
14
|
-
* The behavior is identical to `createAuthMiddleware()` — only the
|
|
15
|
-
* token verification strategy is pluggable.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import type { MiddlewareHandler, Context } from "hono";
|
|
19
|
-
import type { DataDriver, AuthAdapter } from "@rebasepro/types";
|
|
20
|
-
import type { HonoEnv } from "../api/types";
|
|
21
|
-
import type { ApiKeyStore } from "./api-keys/api-key-store";
|
|
22
|
-
import { scopeDataDriver } from "./rls-scope";
|
|
23
|
-
import { validateApiKey } from "./api-keys/api-key-middleware";
|
|
24
|
-
import { logger } from "../utils/logger";
|
|
25
|
-
|
|
26
|
-
export interface AdapterAuthMiddlewareOptions {
|
|
27
|
-
/** The auth adapter to delegate verification to. */
|
|
28
|
-
adapter: AuthAdapter;
|
|
29
|
-
/** The DataDriver to scope via withAuth() for RLS. */
|
|
30
|
-
driver: DataDriver;
|
|
31
|
-
/**
|
|
32
|
-
* Optional per-request driver resolver for multi-data-source backends.
|
|
33
|
-
* Returns the unscoped delegate to use for this request (e.g. Postgres vs
|
|
34
|
-
* Mongo). When omitted, `driver` is used for every request.
|
|
35
|
-
*/
|
|
36
|
-
resolveDriver?: (c: Context<HonoEnv>) => DataDriver;
|
|
37
|
-
/**
|
|
38
|
-
* If true, return 401 when no valid user is resolved.
|
|
39
|
-
* Defaults to `true` (secure by default).
|
|
40
|
-
*/
|
|
41
|
-
requireAuth?: boolean;
|
|
42
|
-
/** Optional API key store — when provided, `rk_` bearer tokens are accepted. */
|
|
43
|
-
apiKeyStore?: ApiKeyStore;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Create a Hono middleware that uses an `AuthAdapter` for request verification.
|
|
48
|
-
*/
|
|
49
|
-
export function createAdapterAuthMiddleware(options: AdapterAuthMiddlewareOptions): MiddlewareHandler<HonoEnv> {
|
|
50
|
-
const { adapter, driver: baseDriver, resolveDriver, requireAuth: enforceAuth = true, apiKeyStore } = options;
|
|
51
|
-
|
|
52
|
-
return async (c, next) => {
|
|
53
|
-
// Pick the per-request delegate (multi-data-source) before scoping.
|
|
54
|
-
const driver = resolveDriver ? resolveDriver(c) : baseDriver;
|
|
55
|
-
// ── API Key check (Rebase-level, independent of auth adapter) ────
|
|
56
|
-
if (apiKeyStore) {
|
|
57
|
-
const authHeader = c.req.header("authorization") || "";
|
|
58
|
-
const token = authHeader.startsWith("Bearer ") ? authHeader.slice(7) : "";
|
|
59
|
-
if (token.startsWith("rk_")) {
|
|
60
|
-
const result = await validateApiKey(c, token, { store: apiKeyStore,
|
|
61
|
-
driver });
|
|
62
|
-
if (result === true) return next();
|
|
63
|
-
return result;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
let authenticatedUser = null;
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
authenticatedUser = await adapter.verifyRequest(c.req.raw);
|
|
71
|
-
} catch (error) {
|
|
72
|
-
// adapter.verifyRequest() threw — reject the request (fail closed)
|
|
73
|
-
return c.json({ error: { message: "Unauthorized",
|
|
74
|
-
code: "UNAUTHORIZED" } }, 401);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (authenticatedUser) {
|
|
78
|
-
// Authenticated — set user context and scope driver
|
|
79
|
-
c.set("user", {
|
|
80
|
-
userId: authenticatedUser.uid,
|
|
81
|
-
email: authenticatedUser.email,
|
|
82
|
-
roles: authenticatedUser.roles
|
|
83
|
-
});
|
|
84
|
-
try {
|
|
85
|
-
c.set("driver", await scopeDataDriver(driver, {
|
|
86
|
-
uid: authenticatedUser.uid,
|
|
87
|
-
roles: authenticatedUser.roles
|
|
88
|
-
}));
|
|
89
|
-
} catch (error) {
|
|
90
|
-
logger.error("[AUTH-ADAPTER] RLS scoping failed for authenticated user", { error: error });
|
|
91
|
-
return c.json({ error: { message: "Internal authentication error",
|
|
92
|
-
code: "INTERNAL_ERROR" } }, 500);
|
|
93
|
-
}
|
|
94
|
-
} else {
|
|
95
|
-
// Not authenticated — scope as anon for RLS evaluation
|
|
96
|
-
try {
|
|
97
|
-
c.set("driver", await scopeDataDriver(driver, { uid: "anon",
|
|
98
|
-
roles: ["anon"] }));
|
|
99
|
-
} catch (error) {
|
|
100
|
-
logger.error("[AUTH-ADAPTER] Failed to create anon-scoped driver", { error: error });
|
|
101
|
-
return c.json({ error: { message: "Server configuration error",
|
|
102
|
-
code: "INTERNAL_ERROR" } }, 500);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Enforce auth if required
|
|
107
|
-
if (enforceAuth && !c.get("user")) {
|
|
108
|
-
return c.json({ error: { message: "Unauthorized: Authentication required",
|
|
109
|
-
code: "UNAUTHORIZED" } }, 401);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return next();
|
|
113
|
-
};
|
|
114
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Admin endpoint for listing all roles.
|
|
3
|
-
*
|
|
4
|
-
* Mounts: GET /roles
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { Hono } from "hono";
|
|
8
|
-
import { errorHandler } from "../api/errors";
|
|
9
|
-
import type { AuthRepository } from "./interfaces";
|
|
10
|
-
import { createRequireAuth, requireAdmin } from "./middleware";
|
|
11
|
-
import type { HonoEnv } from "../api/types";
|
|
12
|
-
|
|
13
|
-
export interface AdminRolesRouteConfig {
|
|
14
|
-
authRepo: AuthRepository;
|
|
15
|
-
serviceKey?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Create a standalone admin route for listing roles.
|
|
20
|
-
*
|
|
21
|
-
* Mounts: GET /roles
|
|
22
|
-
*/
|
|
23
|
-
export function createAdminRolesRoute(config: AdminRolesRouteConfig): Hono<HonoEnv> {
|
|
24
|
-
const router = new Hono<HonoEnv>();
|
|
25
|
-
const authRepo = config.authRepo;
|
|
26
|
-
|
|
27
|
-
router.onError(errorHandler);
|
|
28
|
-
router.use("/*", createRequireAuth({ serviceKey: config.serviceKey }));
|
|
29
|
-
|
|
30
|
-
router.get("/roles", requireAdmin, async (c) => {
|
|
31
|
-
const roles = await authRepo.listRoles();
|
|
32
|
-
return c.json({ roles });
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return router;
|
|
36
|
-
}
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Admin User Operations
|
|
3
|
-
*
|
|
4
|
-
* Shared utilities and orchestration for admin-initiated user management
|
|
5
|
-
* (user creation via REST API, password reset via admin panel).
|
|
6
|
-
*
|
|
7
|
-
* Hook resolution order:
|
|
8
|
-
* 1. Collection-level hook (`auth.onCreateUser` on the collection) — closest to the data
|
|
9
|
-
* 2. Backend-level hook (`AuthHooks.onAdminCreateUser`) — global override
|
|
10
|
-
* 3. Built-in default — framework fallback
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { randomBytes, createHash, randomInt } from "node:crypto";
|
|
14
|
-
import type { AuthRepository } from "./interfaces";
|
|
15
|
-
import type { EmailService, EmailConfig } from "../email";
|
|
16
|
-
import type { ResolvedAuthHooks } from "./auth-hooks";
|
|
17
|
-
import type { AuthCollectionConfig, AuthCollectionContext } from "@rebasepro/types";
|
|
18
|
-
import { getPasswordResetTemplate } from "../email/templates";
|
|
19
|
-
import { logger } from "../utils/logger";
|
|
20
|
-
|
|
21
|
-
// ─── Shared Crypto Utilities ────────────────────────────────────────────────
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Generate a cryptographically secure random password that meets strength requirements.
|
|
25
|
-
*
|
|
26
|
-
* 16 characters, guaranteed at least one uppercase, one lowercase, one digit.
|
|
27
|
-
* Ambiguous characters (0, O, 1, l, I) are excluded.
|
|
28
|
-
*/
|
|
29
|
-
export function generateSecurePassword(): string {
|
|
30
|
-
const upper = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
31
|
-
const lower = "abcdefghjkmnpqrstuvwxyz";
|
|
32
|
-
const digits = "23456789";
|
|
33
|
-
const all = upper + lower + digits;
|
|
34
|
-
|
|
35
|
-
const pick = (chars: string) => chars[randomInt(chars.length)];
|
|
36
|
-
const parts = [pick(upper), pick(lower), pick(digits)];
|
|
37
|
-
|
|
38
|
-
for (let i = parts.length; i < 16; i++) {
|
|
39
|
-
parts.push(pick(all));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Shuffle
|
|
43
|
-
for (let i = parts.length - 1; i > 0; i--) {
|
|
44
|
-
const j = randomInt(i + 1);
|
|
45
|
-
[parts[i], parts[j]] = [parts[j], parts[i]];
|
|
46
|
-
}
|
|
47
|
-
return parts.join("");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Generate a cryptographically secure random token (80 hex characters).
|
|
52
|
-
*/
|
|
53
|
-
export function generateSecureToken(): string {
|
|
54
|
-
return randomBytes(40).toString("hex");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Hash a token for database storage using SHA-256.
|
|
59
|
-
*/
|
|
60
|
-
export function hashToken(token: string): string {
|
|
61
|
-
return createHash("sha256").update(token).digest("hex");
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ─── Admin User Creation ────────────────────────────────────────────────────
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Context needed by admin user creation / password reset operations.
|
|
68
|
-
*/
|
|
69
|
-
export interface AdminUserContext {
|
|
70
|
-
authRepo: AuthRepository;
|
|
71
|
-
emailService?: EmailService;
|
|
72
|
-
emailConfig?: EmailConfig;
|
|
73
|
-
resolvedHooks: ResolvedAuthHooks;
|
|
74
|
-
/** The parsed auth config from the collection (if `auth` is an object, not just `true`). */
|
|
75
|
-
collectionAuthConfig?: AuthCollectionConfig;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Result of preparing user values for admin-initiated creation.
|
|
80
|
-
*/
|
|
81
|
-
export interface AdminUserPrepareResult {
|
|
82
|
-
/** Values ready for `driver.saveEntity()`. */
|
|
83
|
-
values: Record<string, unknown>;
|
|
84
|
-
/** The cleartext password (for returning to admin or sending via email). */
|
|
85
|
-
clearPassword?: string;
|
|
86
|
-
/** Whether the hook already handled the invitation email. */
|
|
87
|
-
hookHandledEmail: boolean;
|
|
88
|
-
/** Whether an invitation was sent (only relevant when hookHandledEmail is true). */
|
|
89
|
-
invitationSent: boolean;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Build the `AuthCollectionContext` facade from server internals.
|
|
94
|
-
*
|
|
95
|
-
* This is the simplified context exposed to collection-level auth hooks,
|
|
96
|
-
* keeping them decoupled from internal interfaces like `AuthRepository`.
|
|
97
|
-
*/
|
|
98
|
-
function buildCollectionContext(ctx: AdminUserContext): AuthCollectionContext {
|
|
99
|
-
const isEmailConfigured = !!(ctx.emailService && ctx.emailService.isConfigured());
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
hashPassword: (password: string) => ctx.resolvedHooks.hashPassword(password),
|
|
103
|
-
sendEmail: isEmailConfigured
|
|
104
|
-
? (options) => ctx.emailService!.send(options)
|
|
105
|
-
: undefined,
|
|
106
|
-
emailConfigured: isEmailConfigured,
|
|
107
|
-
appName: ctx.emailConfig?.appName || "Rebase",
|
|
108
|
-
resetPasswordUrl: ctx.emailConfig?.resetPasswordUrl || ""
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Prepare user values for an admin-initiated user creation.
|
|
114
|
-
*
|
|
115
|
-
* Resolution order:
|
|
116
|
-
* 1. Collection-level `auth.onCreateUser` — closest to the data
|
|
117
|
-
* 2. Backend-level `AuthHooks.onAdminCreateUser` — global override
|
|
118
|
-
* 3. Built-in default — generate password → hash → normalize email
|
|
119
|
-
*
|
|
120
|
-
* The caller is responsible for persisting (via `driver.saveEntity()`).
|
|
121
|
-
*/
|
|
122
|
-
export async function prepareAdminUserValues(
|
|
123
|
-
body: Record<string, unknown>,
|
|
124
|
-
ctx: AdminUserContext
|
|
125
|
-
): Promise<AdminUserPrepareResult> {
|
|
126
|
-
const { resolvedHooks, collectionAuthConfig } = ctx;
|
|
127
|
-
|
|
128
|
-
// 1. Collection-level hook (closest to the data)
|
|
129
|
-
if (collectionAuthConfig?.onCreateUser) {
|
|
130
|
-
const collectionCtx = buildCollectionContext(ctx);
|
|
131
|
-
const hookResult = await collectionAuthConfig.onCreateUser(body, collectionCtx);
|
|
132
|
-
return {
|
|
133
|
-
values: hookResult.values,
|
|
134
|
-
clearPassword: hookResult.temporaryPassword,
|
|
135
|
-
hookHandledEmail: true,
|
|
136
|
-
invitationSent: hookResult.invitationSent ?? false
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// 2. Backend-level hook (global override)
|
|
141
|
-
if (resolvedHooks.onAdminCreateUser) {
|
|
142
|
-
const hookResult = await resolvedHooks.onAdminCreateUser(body, {
|
|
143
|
-
authRepo: ctx.authRepo,
|
|
144
|
-
emailService: ctx.emailService,
|
|
145
|
-
emailConfig: ctx.emailConfig,
|
|
146
|
-
hashPassword: (password: string) => resolvedHooks.hashPassword(password)
|
|
147
|
-
});
|
|
148
|
-
return {
|
|
149
|
-
values: hookResult.values,
|
|
150
|
-
clearPassword: hookResult.temporaryPassword,
|
|
151
|
-
hookHandledEmail: true,
|
|
152
|
-
invitationSent: hookResult.invitationSent ?? false
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// 3. Built-in default
|
|
157
|
-
const password = body.password as string | undefined;
|
|
158
|
-
const clearPassword = password || generateSecurePassword();
|
|
159
|
-
const passwordHash = await resolvedHooks.hashPassword(clearPassword);
|
|
160
|
-
|
|
161
|
-
const values = { ...body };
|
|
162
|
-
values.passwordHash = passwordHash;
|
|
163
|
-
if (values.email) {
|
|
164
|
-
values.email = (values.email as string).toLowerCase();
|
|
165
|
-
}
|
|
166
|
-
values.emailVerified = true;
|
|
167
|
-
delete values.password;
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
values,
|
|
171
|
-
clearPassword: password ? undefined : clearPassword,
|
|
172
|
-
hookHandledEmail: false,
|
|
173
|
-
invitationSent: false
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Handle post-creation work for admin-created users.
|
|
179
|
-
*
|
|
180
|
-
* Sends an invitation email (password-reset link) if email is configured
|
|
181
|
-
* and no explicit password was provided. Falls back to returning the
|
|
182
|
-
* temporary password if email fails or is not configured.
|
|
183
|
-
*/
|
|
184
|
-
export async function finalizeAdminUserCreation(
|
|
185
|
-
entity: { id: string; values: Record<string, unknown> },
|
|
186
|
-
clearPassword: string | undefined,
|
|
187
|
-
ctx: AdminUserContext
|
|
188
|
-
): Promise<{
|
|
189
|
-
temporaryPassword?: string;
|
|
190
|
-
invitationSent: boolean;
|
|
191
|
-
}> {
|
|
192
|
-
// If an explicit password was provided (clearPassword is undefined), nothing to do
|
|
193
|
-
if (!clearPassword) {
|
|
194
|
-
return { invitationSent: false };
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const isEmailConfigured = !!(ctx.emailService && ctx.emailService.isConfigured());
|
|
198
|
-
|
|
199
|
-
if (isEmailConfigured) {
|
|
200
|
-
try {
|
|
201
|
-
const token = generateSecureToken();
|
|
202
|
-
const tokenHash = hashToken(token);
|
|
203
|
-
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
|
|
204
|
-
|
|
205
|
-
await ctx.authRepo.createPasswordResetToken(entity.id, tokenHash, expiresAt);
|
|
206
|
-
|
|
207
|
-
const baseUrl = ctx.emailConfig?.resetPasswordUrl || "";
|
|
208
|
-
const setPasswordUrl = `${baseUrl}/reset-password?token=${token}`;
|
|
209
|
-
|
|
210
|
-
const appName = ctx.emailConfig?.appName || "Rebase";
|
|
211
|
-
const templateFn = ctx.emailConfig?.templates?.passwordReset;
|
|
212
|
-
const emailContent = templateFn
|
|
213
|
-
? templateFn(setPasswordUrl, { email: entity.values.email as string,
|
|
214
|
-
displayName: entity.values.displayName as string })
|
|
215
|
-
: getPasswordResetTemplate(setPasswordUrl, { email: entity.values.email as string,
|
|
216
|
-
displayName: entity.values.displayName as string }, appName);
|
|
217
|
-
|
|
218
|
-
await ctx.emailService!.send({
|
|
219
|
-
to: entity.values.email as string,
|
|
220
|
-
subject: emailContent.subject,
|
|
221
|
-
html: emailContent.html,
|
|
222
|
-
text: emailContent.text
|
|
223
|
-
});
|
|
224
|
-
return { invitationSent: true };
|
|
225
|
-
} catch (emailError: unknown) {
|
|
226
|
-
logger.error("Failed to send reset email", { error: emailError instanceof Error ? emailError.message : emailError });
|
|
227
|
-
// Fall back to returning the temporary password
|
|
228
|
-
return { temporaryPassword: clearPassword,
|
|
229
|
-
invitationSent: false };
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// No email service — return the temporary password
|
|
234
|
-
return { temporaryPassword: clearPassword,
|
|
235
|
-
invitationSent: false };
|
|
236
|
-
}
|