@rebasepro/server-core 0.7.0 → 0.8.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/build-errors.txt +52 -0
- 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/graphql/graphql-schema-generator.d.ts +44 -0
- package/dist/api/graphql/index.d.ts +1 -0
- package/dist/api/index.d.ts +9 -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 +76 -0
- package/dist/api/rest/index.d.ts +1 -0
- package/dist/api/rest/query-parser.d.ts +8 -0
- package/dist/api/schema-editor-routes.d.ts +3 -0
- package/dist/api/server.d.ts +40 -0
- package/dist/api/types.d.ts +104 -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/dist/auth/api-keys/api-key-permission-guard.d.ts +32 -0
- 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/dist/auth/api-keys/api-key-types.d.ts +96 -0
- package/dist/auth/api-keys/index.d.ts +17 -0
- package/dist/auth/apple-oauth.d.ts +30 -0
- package/dist/auth/auth-hooks.d.ts +242 -0
- package/dist/auth/bitbucket-oauth.d.ts +11 -0
- package/dist/auth/builtin-auth-adapter.d.ts +51 -0
- package/dist/auth/crypto-utils.d.ts +16 -0
- 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/dist/auth/index.d.ts +37 -0
- package/dist/auth/interfaces.d.ts +431 -0
- package/dist/auth/jwt.d.ts +55 -0
- package/dist/auth/linkedin-oauth.d.ts +18 -0
- package/dist/auth/magic-link-routes.d.ts +30 -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 +113 -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 +35 -0
- package/dist/auth/session-routes.d.ts +27 -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/backend-CIxN4FVm.js +15 -0
- package/dist/backend-CIxN4FVm.js.map +1 -0
- package/dist/base64-js-C_frYBkI.js +1687 -0
- package/dist/base64-js-C_frYBkI.js.map +1 -0
- package/dist/chunk-Dze3rakg.js +42 -0
- package/dist/collections/BackendCollectionRegistry.d.ts +13 -0
- package/dist/collections/loader.d.ts +5 -0
- package/dist/cron/cron-loader.d.ts +17 -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/index.d.ts +6 -0
- package/dist/db/interfaces.d.ts +18 -0
- package/dist/dist-DMO-zF6D.js +832 -0
- package/dist/dist-DMO-zF6D.js.map +1 -0
- package/dist/email/index.d.ts +6 -0
- package/dist/email/smtp-email-service.d.ts +25 -0
- package/dist/email/templates.d.ts +50 -0
- package/dist/email/types.d.ts +126 -0
- package/dist/env.d.ts +102 -0
- package/dist/from-VbwD7xRf.js +3849 -0
- package/dist/from-VbwD7xRf.js.map +1 -0
- package/dist/functions/define-function.d.ts +50 -0
- package/dist/functions/function-loader.d.ts +17 -0
- package/dist/functions/function-routes.d.ts +10 -0
- package/dist/functions/index.d.ts +5 -0
- package/dist/history/history-routes.d.ts +23 -0
- package/dist/history/index.d.ts +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.es.js +61322 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +103633 -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 +11 -0
- package/dist/init/storage.d.ts +5 -0
- package/dist/init.d.ts +314 -0
- package/dist/jws-BqRRaK11.js +616 -0
- package/dist/jws-BqRRaK11.js.map +1 -0
- package/dist/jwt-BETC8a1J.js +3560 -0
- package/dist/jwt-BETC8a1J.js.map +1 -0
- package/dist/logger-BYU66ENZ.js +94 -0
- package/dist/logger-BYU66ENZ.js.map +1 -0
- package/dist/ms-BeBSuOXN.js +125 -0
- package/dist/ms-BeBSuOXN.js.map +1 -0
- package/dist/multipart-parser-CedBDOeC.js +299 -0
- package/dist/multipart-parser-CedBDOeC.js.map +1 -0
- package/dist/serve-spa.d.ts +30 -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 +35 -0
- package/dist/src-CB2PIpBe.js +1182 -0
- package/dist/src-CB2PIpBe.js.map +1 -0
- package/dist/src-DjzOT1kG.js +29746 -0
- package/dist/src-DjzOT1kG.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 +36 -0
- package/dist/storage/image-transform.d.ts +50 -0
- package/dist/storage/index.d.ts +31 -0
- 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/dist/storage/types.d.ts +128 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/utils/dev-port.d.ts +37 -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/dist/utils/sql.d.ts +27 -0
- package/package.json +22 -14
- package/src/api/graphql/graphql-schema-generator.ts +5 -5
- package/src/api/openapi-generator.ts +2 -2
- package/src/api/rest/api-generator.ts +44 -123
- package/src/api/rest/query-parser.ts +6 -23
- package/src/api/types.ts +2 -2
- package/src/auth/auth-hooks.ts +1 -1
- package/src/auth/builtin-auth-adapter.ts +1 -2
- package/src/auth/interfaces.ts +11 -2
- package/src/auth/middleware.ts +4 -4
- package/src/auth/routes.ts +1 -2
- package/src/functions/define-function.ts +59 -0
- package/src/functions/function-loader.ts +16 -0
- package/src/functions/index.ts +2 -0
- package/src/index.ts +70 -37
- package/src/init.ts +78 -21
- package/src/storage/GCSStorageController.ts +334 -0
- package/src/storage/index.ts +9 -3
- package/src/storage/routes.ts +191 -23
- package/src/storage/tus-handler.ts +16 -4
- package/src/storage/types.ts +25 -3
- package/test/api-generator.test.ts +1 -1
- package/test/auth-config-types.test.ts +40 -0
- package/test/define-function.test.ts +45 -0
- package/test/storage-routes.test.ts +160 -0
- package/test/backend-hooks-data.test.ts +0 -477
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { OAuthProvider } from "./interfaces";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a GitHub OAuth Provider integration.
|
|
4
|
+
*
|
|
5
|
+
* Flow: Frontend receives an authorization `code` via the GitHub OAuth redirect.
|
|
6
|
+
* This provider exchanges the code for an access token, then fetches the user's
|
|
7
|
+
* profile and primary email from the GitHub API.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createGitHubProvider(config: {
|
|
10
|
+
clientId: string;
|
|
11
|
+
clientSecret: string;
|
|
12
|
+
}): OAuthProvider<{
|
|
13
|
+
code: string;
|
|
14
|
+
redirectUri: string;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { OAuthProvider } from "./interfaces";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a GitLab OAuth Provider integration.
|
|
4
|
+
* Works with both GitLab.com and self-hosted instances.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createGitLabProvider(config: {
|
|
7
|
+
clientId: string;
|
|
8
|
+
clientSecret: string;
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
}): OAuthProvider<{
|
|
11
|
+
code: string;
|
|
12
|
+
redirectUri: string;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { OAuthProvider } from "./interfaces";
|
|
2
|
+
export interface GoogleUserInfo {
|
|
3
|
+
googleId: string;
|
|
4
|
+
email: string;
|
|
5
|
+
displayName: string | null;
|
|
6
|
+
photoUrl: string | null;
|
|
7
|
+
emailVerified: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface GoogleProviderConfig {
|
|
10
|
+
clientId: string;
|
|
11
|
+
/**
|
|
12
|
+
* The OAuth 2.0 client secret from Google Cloud Console.
|
|
13
|
+
*
|
|
14
|
+
* Required for the **authorization code flow** (Path 3), where the
|
|
15
|
+
* frontend sends an authorization `code` and the backend exchanges it
|
|
16
|
+
* server-side for tokens. This is the most secure flow because tokens
|
|
17
|
+
* never touch the browser.
|
|
18
|
+
*
|
|
19
|
+
* When omitted, only ID-token and access-token verification are available
|
|
20
|
+
* (Paths 1 & 2), which rely on the frontend obtaining tokens directly.
|
|
21
|
+
*/
|
|
22
|
+
clientSecret?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Creates a Google OAuth Provider integration.
|
|
26
|
+
*
|
|
27
|
+
* Supports three verification paths:
|
|
28
|
+
*
|
|
29
|
+
* **Path 1 – ID Token** (One Tap / Sign In With Google button):
|
|
30
|
+
* Frontend sends `idToken`. Backend verifies cryptographically using
|
|
31
|
+
* Google's public keys. No secret required.
|
|
32
|
+
*
|
|
33
|
+
* **Path 2 – Access Token** (popup via `initTokenClient`):
|
|
34
|
+
* Frontend sends `accessToken`. Backend validates by calling Google's
|
|
35
|
+
* userinfo endpoint. No secret required.
|
|
36
|
+
*
|
|
37
|
+
* **Path 3 – Authorization Code** (most secure, requires `clientSecret`):
|
|
38
|
+
* Frontend sends `code` + `redirectUri`. Backend exchanges the code
|
|
39
|
+
* server-side for an ID token using `clientId` + `clientSecret`, then
|
|
40
|
+
* verifies the ID token. Tokens never touch the browser.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createGoogleProvider(config: GoogleProviderConfig | string): OAuthProvider<{
|
|
43
|
+
idToken?: string;
|
|
44
|
+
accessToken?: string;
|
|
45
|
+
code?: string;
|
|
46
|
+
redirectUri?: string;
|
|
47
|
+
}>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export * from "./interfaces";
|
|
2
|
+
export { configureJwt, generateAccessToken, verifyAccessToken, generateRefreshToken, hashRefreshToken, getRefreshTokenExpiry, getAccessTokenExpiry } from "./jwt";
|
|
3
|
+
export type { JwtConfig, AccessTokenPayload } from "./jwt";
|
|
4
|
+
export { hashPassword, verifyPassword, validatePasswordStrength } from "./password";
|
|
5
|
+
export type { PasswordValidationResult } from "./password";
|
|
6
|
+
export type { AuthHooks, AuthMethod, ResolvedAuthHooks } from "./auth-hooks";
|
|
7
|
+
export { resolveAuthHooks } from "./auth-hooks";
|
|
8
|
+
export { generateSecurePassword, generateSecureToken, hashToken, prepareAdminUserValues, finalizeAdminUserCreation } from "./admin-user-ops";
|
|
9
|
+
export type { AdminUserContext, AdminUserPrepareResult } from "./admin-user-ops";
|
|
10
|
+
export { createGoogleProvider } from "./google-oauth";
|
|
11
|
+
export type { GoogleProviderConfig } from "./google-oauth";
|
|
12
|
+
export { createLinkedinProvider } from "./linkedin-oauth";
|
|
13
|
+
export { createGitHubProvider } from "./github-oauth";
|
|
14
|
+
export { createMicrosoftProvider } from "./microsoft-oauth";
|
|
15
|
+
export { createAppleProvider } from "./apple-oauth";
|
|
16
|
+
export { createFacebookProvider } from "./facebook-oauth";
|
|
17
|
+
export { createTwitterProvider } from "./twitter-oauth";
|
|
18
|
+
export { createDiscordProvider } from "./discord-oauth";
|
|
19
|
+
export { createGitLabProvider } from "./gitlab-oauth";
|
|
20
|
+
export { createBitbucketProvider } from "./bitbucket-oauth";
|
|
21
|
+
export { createSlackProvider } from "./slack-oauth";
|
|
22
|
+
export { createSpotifyProvider } from "./spotify-oauth";
|
|
23
|
+
export { requireAuth, requireAdmin, optionalAuth, extractUserFromToken, createAuthMiddleware } from "./middleware";
|
|
24
|
+
export type { AuthMiddlewareOptions, AuthResult } from "./middleware";
|
|
25
|
+
export { createAuthRoutes } from "./routes";
|
|
26
|
+
export type { AuthModuleConfig } from "./routes";
|
|
27
|
+
export { mountMagicLinkRoutes } from "./magic-link-routes";
|
|
28
|
+
export { createResetPasswordRoute } from "./reset-password-admin";
|
|
29
|
+
export type { ResetPasswordRouteConfig } from "./reset-password-admin";
|
|
30
|
+
export { createRateLimiter, defaultAuthLimiter, strictAuthLimiter, createApiKeyRateLimiter, apiKeyKeyGenerator } from "./rate-limiter";
|
|
31
|
+
export { createApiKeyStore, createApiKeyRoutes, isApiKeyToken, validateApiKey, httpMethodToOperation, isOperationAllowed } from "./api-keys";
|
|
32
|
+
export type { ApiKey, ApiKeyMasked, ApiKeyPermission, ApiKeyWithSecret, CreateApiKeyRequest, UpdateApiKeyRequest, ApiKeyStore, ApiKeyOperation } from "./api-keys";
|
|
33
|
+
export { createBuiltinAuthAdapter } from "./builtin-auth-adapter";
|
|
34
|
+
export type { BuiltinAuthAdapterConfig } from "./builtin-auth-adapter";
|
|
35
|
+
export { createCustomAuthAdapter } from "./custom-auth-adapter";
|
|
36
|
+
export { createAdapterAuthMiddleware } from "./adapter-middleware";
|
|
37
|
+
export type { AdapterAuthMiddlewareOptions } from "./adapter-middleware";
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Authentication Abstraction Interfaces
|
|
4
|
+
*
|
|
5
|
+
* These interfaces define the contracts for authentication-related operations.
|
|
6
|
+
* Implementations can use different databases (PostgreSQL, MongoDB, etc.) to
|
|
7
|
+
* store user, role, and token data.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* User data structure
|
|
11
|
+
*/
|
|
12
|
+
export interface UserData {
|
|
13
|
+
id: string;
|
|
14
|
+
email: string;
|
|
15
|
+
passwordHash?: string | null;
|
|
16
|
+
displayName?: string | null;
|
|
17
|
+
photoUrl?: string | null;
|
|
18
|
+
emailVerified: boolean;
|
|
19
|
+
emailVerificationToken?: string | null;
|
|
20
|
+
emailVerificationSentAt?: Date | null;
|
|
21
|
+
isAnonymous?: boolean;
|
|
22
|
+
metadata?: Record<string, unknown>;
|
|
23
|
+
createdAt: Date;
|
|
24
|
+
updatedAt: Date;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Data for creating a new user
|
|
28
|
+
*/
|
|
29
|
+
export interface CreateUserData {
|
|
30
|
+
email: string;
|
|
31
|
+
passwordHash?: string;
|
|
32
|
+
displayName?: string;
|
|
33
|
+
photoUrl?: string;
|
|
34
|
+
emailVerified?: boolean;
|
|
35
|
+
isAnonymous?: boolean;
|
|
36
|
+
metadata?: Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* User Identity Data (OAuth accounts linked to user)
|
|
40
|
+
*/
|
|
41
|
+
export interface UserIdentityData {
|
|
42
|
+
id: string;
|
|
43
|
+
userId: string;
|
|
44
|
+
provider: string;
|
|
45
|
+
providerId: string;
|
|
46
|
+
profileData?: Record<string, unknown> | null;
|
|
47
|
+
createdAt: Date;
|
|
48
|
+
updatedAt: Date;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Standardized profile data returned by an OAuth provider verification payload
|
|
52
|
+
*/
|
|
53
|
+
export interface OAuthProviderProfile {
|
|
54
|
+
providerId: string;
|
|
55
|
+
email: string;
|
|
56
|
+
displayName?: string | null;
|
|
57
|
+
photoUrl?: string | null;
|
|
58
|
+
/** Whether the OAuth provider has verified the user's email address */
|
|
59
|
+
emailVerified?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Pluggable OAuth Provider integration strategy
|
|
63
|
+
*/
|
|
64
|
+
export interface OAuthProvider<T = unknown> {
|
|
65
|
+
/** The identifier of the provider (e.g. "github", "google") */
|
|
66
|
+
id: string;
|
|
67
|
+
/** Zod schema validating the expected request payload (e.g. { code: string }) */
|
|
68
|
+
schema: z.ZodSchema<T>;
|
|
69
|
+
/**
|
|
70
|
+
* Verify external tokens/codes and return a standardized user profile.
|
|
71
|
+
*
|
|
72
|
+
* NOTE: Declared as method syntax (not arrow property) intentionally.
|
|
73
|
+
* This makes `OAuthProvider` bivariant in `T`, which is correct because
|
|
74
|
+
* each provider is self-contained — `schema` validates the request body
|
|
75
|
+
* and `verify` consumes the same `T`. Bivariance lets heterogeneous
|
|
76
|
+
* providers (`OAuthProvider<SpecificPayload>`) coexist in a single
|
|
77
|
+
* `OAuthProvider<unknown>[]` array without resorting to `any`.
|
|
78
|
+
*/
|
|
79
|
+
verify(payload: T): Promise<OAuthProviderProfile | null>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Role data structure
|
|
83
|
+
*/
|
|
84
|
+
export interface RoleData {
|
|
85
|
+
id: string;
|
|
86
|
+
name: string;
|
|
87
|
+
isAdmin: boolean;
|
|
88
|
+
defaultPermissions: {
|
|
89
|
+
read?: boolean;
|
|
90
|
+
create?: boolean;
|
|
91
|
+
edit?: boolean;
|
|
92
|
+
delete?: boolean;
|
|
93
|
+
} | null;
|
|
94
|
+
collectionPermissions: Record<string, {
|
|
95
|
+
read?: boolean;
|
|
96
|
+
create?: boolean;
|
|
97
|
+
edit?: boolean;
|
|
98
|
+
delete?: boolean;
|
|
99
|
+
}> | null;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Data for creating a new role
|
|
103
|
+
*/
|
|
104
|
+
export interface CreateRoleData {
|
|
105
|
+
id: string;
|
|
106
|
+
name: string;
|
|
107
|
+
isAdmin?: boolean;
|
|
108
|
+
defaultPermissions?: RoleData["defaultPermissions"];
|
|
109
|
+
collectionPermissions?: RoleData["collectionPermissions"];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Refresh token info
|
|
113
|
+
*/
|
|
114
|
+
export interface RefreshTokenInfo {
|
|
115
|
+
id: string;
|
|
116
|
+
userId: string;
|
|
117
|
+
tokenHash: string;
|
|
118
|
+
expiresAt: Date;
|
|
119
|
+
createdAt: Date;
|
|
120
|
+
userAgent?: string | null;
|
|
121
|
+
ipAddress?: string | null;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Password reset token info
|
|
125
|
+
*/
|
|
126
|
+
export interface PasswordResetTokenInfo {
|
|
127
|
+
userId: string;
|
|
128
|
+
expiresAt: Date;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Magic link token info
|
|
132
|
+
*/
|
|
133
|
+
export interface MagicLinkTokenInfo {
|
|
134
|
+
userId: string;
|
|
135
|
+
expiresAt: Date;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Options for paginated user listing
|
|
139
|
+
*/
|
|
140
|
+
export interface ListUsersOptions {
|
|
141
|
+
/** Max results per page (default 25) */
|
|
142
|
+
limit?: number;
|
|
143
|
+
/** Number of results to skip (default 0) */
|
|
144
|
+
offset?: number;
|
|
145
|
+
/** Search term — matches against email and displayName (case-insensitive) */
|
|
146
|
+
search?: string;
|
|
147
|
+
/** Field to sort by (default "createdAt") */
|
|
148
|
+
orderBy?: string;
|
|
149
|
+
/** Sort direction (default "desc") */
|
|
150
|
+
orderDir?: "asc" | "desc";
|
|
151
|
+
/** Filter by role ID */
|
|
152
|
+
roleId?: string;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Result of a paginated user listing
|
|
156
|
+
*/
|
|
157
|
+
export interface PaginatedUsersResult {
|
|
158
|
+
users: UserData[];
|
|
159
|
+
/** Total number of users matching the filters (ignoring limit/offset) */
|
|
160
|
+
total: number;
|
|
161
|
+
limit: number;
|
|
162
|
+
offset: number;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Abstract user repository interface.
|
|
166
|
+
* Handles all user-related database operations.
|
|
167
|
+
*/
|
|
168
|
+
export interface UserRepository {
|
|
169
|
+
/**
|
|
170
|
+
* Create a new user
|
|
171
|
+
*/
|
|
172
|
+
createUser(data: CreateUserData): Promise<UserData>;
|
|
173
|
+
/**
|
|
174
|
+
* Get a user by ID
|
|
175
|
+
*/
|
|
176
|
+
getUserById(id: string): Promise<UserData | null>;
|
|
177
|
+
/**
|
|
178
|
+
* Get a user by email
|
|
179
|
+
*/
|
|
180
|
+
getUserByEmail(email: string): Promise<UserData | null>;
|
|
181
|
+
/**
|
|
182
|
+
* Get a user by an OAuth identity
|
|
183
|
+
*/
|
|
184
|
+
getUserByIdentity(provider: string, providerId: string): Promise<UserData | null>;
|
|
185
|
+
/**
|
|
186
|
+
* Get all identities linked to a user
|
|
187
|
+
*/
|
|
188
|
+
getUserIdentities(userId: string): Promise<UserIdentityData[]>;
|
|
189
|
+
/**
|
|
190
|
+
* Link a new OAuth identity to a user
|
|
191
|
+
*/
|
|
192
|
+
linkUserIdentity(userId: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void>;
|
|
193
|
+
/**
|
|
194
|
+
* Update a user
|
|
195
|
+
*/
|
|
196
|
+
updateUser(id: string, data: Partial<Omit<CreateUserData, "id">>): Promise<UserData | null>;
|
|
197
|
+
/**
|
|
198
|
+
* Delete a user
|
|
199
|
+
*/
|
|
200
|
+
deleteUser(id: string): Promise<void>;
|
|
201
|
+
/**
|
|
202
|
+
* List all users (unbounded — use listUsersPaginated for large datasets)
|
|
203
|
+
*/
|
|
204
|
+
listUsers(): Promise<UserData[]>;
|
|
205
|
+
/**
|
|
206
|
+
* List users with server-side pagination, search, and sorting.
|
|
207
|
+
*/
|
|
208
|
+
listUsersPaginated(options?: ListUsersOptions): Promise<PaginatedUsersResult>;
|
|
209
|
+
/**
|
|
210
|
+
* Update user's password hash
|
|
211
|
+
*/
|
|
212
|
+
updatePassword(id: string, passwordHash: string): Promise<void>;
|
|
213
|
+
/**
|
|
214
|
+
* Set email verification status
|
|
215
|
+
*/
|
|
216
|
+
setEmailVerified(id: string, verified: boolean): Promise<void>;
|
|
217
|
+
/**
|
|
218
|
+
* Set email verification token
|
|
219
|
+
*/
|
|
220
|
+
setVerificationToken(id: string, token: string | null): Promise<void>;
|
|
221
|
+
/**
|
|
222
|
+
* Find user by email verification token
|
|
223
|
+
*/
|
|
224
|
+
getUserByVerificationToken(token: string): Promise<UserData | null>;
|
|
225
|
+
/**
|
|
226
|
+
* Get roles for a user
|
|
227
|
+
*/
|
|
228
|
+
getUserRoles(userId: string): Promise<RoleData[]>;
|
|
229
|
+
/**
|
|
230
|
+
* Get role IDs for a user
|
|
231
|
+
*/
|
|
232
|
+
getUserRoleIds(userId: string): Promise<string[]>;
|
|
233
|
+
/**
|
|
234
|
+
* Set roles for a user (replaces existing roles)
|
|
235
|
+
*/
|
|
236
|
+
setUserRoles(userId: string, roleIds: string[]): Promise<void>;
|
|
237
|
+
/**
|
|
238
|
+
* Assign a specific role to a new user
|
|
239
|
+
*/
|
|
240
|
+
assignDefaultRole(userId: string, roleId: string): Promise<void>;
|
|
241
|
+
/**
|
|
242
|
+
* Get user with their roles
|
|
243
|
+
*/
|
|
244
|
+
getUserWithRoles(userId: string): Promise<{
|
|
245
|
+
user: UserData;
|
|
246
|
+
roles: RoleData[];
|
|
247
|
+
} | null>;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Abstract role repository interface.
|
|
251
|
+
* Handles all role-related database operations.
|
|
252
|
+
*/
|
|
253
|
+
export interface RoleRepository {
|
|
254
|
+
/**
|
|
255
|
+
* Get a role by ID
|
|
256
|
+
*/
|
|
257
|
+
getRoleById(id: string): Promise<RoleData | null>;
|
|
258
|
+
/**
|
|
259
|
+
* List all roles
|
|
260
|
+
*/
|
|
261
|
+
listRoles(): Promise<RoleData[]>;
|
|
262
|
+
/**
|
|
263
|
+
* Create a new role
|
|
264
|
+
*/
|
|
265
|
+
createRole(data: CreateRoleData): Promise<RoleData>;
|
|
266
|
+
/**
|
|
267
|
+
* Update a role
|
|
268
|
+
*/
|
|
269
|
+
updateRole(id: string, data: Partial<Omit<RoleData, "id">>): Promise<RoleData | null>;
|
|
270
|
+
/**
|
|
271
|
+
* Delete a role
|
|
272
|
+
*/
|
|
273
|
+
deleteRole(id: string): Promise<void>;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Abstract token repository interface.
|
|
277
|
+
* Handles refresh tokens and password reset tokens.
|
|
278
|
+
*/
|
|
279
|
+
export interface TokenRepository {
|
|
280
|
+
/**
|
|
281
|
+
* Create a new refresh token
|
|
282
|
+
*/
|
|
283
|
+
createRefreshToken(userId: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void>;
|
|
284
|
+
/**
|
|
285
|
+
* Find a refresh token by hash
|
|
286
|
+
*/
|
|
287
|
+
findRefreshTokenByHash(tokenHash: string): Promise<RefreshTokenInfo | null>;
|
|
288
|
+
/**
|
|
289
|
+
* Delete a refresh token by hash
|
|
290
|
+
*/
|
|
291
|
+
deleteRefreshToken(tokenHash: string): Promise<void>;
|
|
292
|
+
/**
|
|
293
|
+
* Delete all refresh tokens for a user
|
|
294
|
+
*/
|
|
295
|
+
deleteAllRefreshTokensForUser(userId: string): Promise<void>;
|
|
296
|
+
/**
|
|
297
|
+
* List all refresh tokens for a user
|
|
298
|
+
*/
|
|
299
|
+
listRefreshTokensForUser(userId: string): Promise<RefreshTokenInfo[]>;
|
|
300
|
+
/**
|
|
301
|
+
* Delete a specific refresh token by its primary key ID
|
|
302
|
+
*/
|
|
303
|
+
deleteRefreshTokenById(id: string, userId: string): Promise<void>;
|
|
304
|
+
/**
|
|
305
|
+
* Create a password reset token
|
|
306
|
+
*/
|
|
307
|
+
createPasswordResetToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void>;
|
|
308
|
+
/**
|
|
309
|
+
* Find a valid (not expired, not used) password reset token by hash
|
|
310
|
+
*/
|
|
311
|
+
findValidPasswordResetToken(tokenHash: string): Promise<PasswordResetTokenInfo | null>;
|
|
312
|
+
/**
|
|
313
|
+
* Mark a password reset token as used
|
|
314
|
+
*/
|
|
315
|
+
markPasswordResetTokenUsed(tokenHash: string): Promise<void>;
|
|
316
|
+
/**
|
|
317
|
+
* Delete all password reset tokens for a user
|
|
318
|
+
*/
|
|
319
|
+
deleteAllPasswordResetTokensForUser(userId: string): Promise<void>;
|
|
320
|
+
/**
|
|
321
|
+
* Clean up expired tokens
|
|
322
|
+
*/
|
|
323
|
+
deleteExpiredTokens(): Promise<void>;
|
|
324
|
+
/**
|
|
325
|
+
* Create a magic link token
|
|
326
|
+
*/
|
|
327
|
+
createMagicLinkToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void>;
|
|
328
|
+
/**
|
|
329
|
+
* Find a valid (not expired, not used) magic link token by hash
|
|
330
|
+
*/
|
|
331
|
+
findValidMagicLinkToken(tokenHash: string): Promise<MagicLinkTokenInfo | null>;
|
|
332
|
+
/**
|
|
333
|
+
* Mark a magic link token as used
|
|
334
|
+
*/
|
|
335
|
+
markMagicLinkTokenUsed(tokenHash: string): Promise<void>;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* MFA factor data structure
|
|
339
|
+
*/
|
|
340
|
+
export interface MfaFactor {
|
|
341
|
+
id: string;
|
|
342
|
+
userId: string;
|
|
343
|
+
factorType: "totp";
|
|
344
|
+
friendlyName?: string;
|
|
345
|
+
verified: boolean;
|
|
346
|
+
createdAt: Date;
|
|
347
|
+
updatedAt: Date;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* MFA challenge information
|
|
351
|
+
*/
|
|
352
|
+
export interface MfaChallengeInfo {
|
|
353
|
+
id: string;
|
|
354
|
+
factorId: string;
|
|
355
|
+
createdAt: Date;
|
|
356
|
+
verifiedAt?: Date;
|
|
357
|
+
ipAddress?: string;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Recovery code data structure
|
|
361
|
+
*/
|
|
362
|
+
export interface RecoveryCode {
|
|
363
|
+
id: string;
|
|
364
|
+
userId: string;
|
|
365
|
+
usedAt?: Date;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Abstract MFA repository interface.
|
|
369
|
+
* Handles all MFA-related database operations.
|
|
370
|
+
*/
|
|
371
|
+
export interface MfaRepository {
|
|
372
|
+
/**
|
|
373
|
+
* Create a new MFA factor for a user
|
|
374
|
+
*/
|
|
375
|
+
createMfaFactor(userId: string, factorType: "totp", secretEncrypted: string, friendlyName?: string): Promise<MfaFactor>;
|
|
376
|
+
/**
|
|
377
|
+
* Get all MFA factors for a user
|
|
378
|
+
*/
|
|
379
|
+
getMfaFactors(userId: string): Promise<MfaFactor[]>;
|
|
380
|
+
/**
|
|
381
|
+
* Get a specific MFA factor by ID
|
|
382
|
+
*/
|
|
383
|
+
getMfaFactorById(factorId: string): Promise<(MfaFactor & {
|
|
384
|
+
secretEncrypted: string;
|
|
385
|
+
}) | null>;
|
|
386
|
+
/**
|
|
387
|
+
* Mark an MFA factor as verified
|
|
388
|
+
*/
|
|
389
|
+
verifyMfaFactor(factorId: string): Promise<void>;
|
|
390
|
+
/**
|
|
391
|
+
* Delete an MFA factor
|
|
392
|
+
*/
|
|
393
|
+
deleteMfaFactor(factorId: string, userId: string): Promise<void>;
|
|
394
|
+
/**
|
|
395
|
+
* Create an MFA challenge
|
|
396
|
+
*/
|
|
397
|
+
createMfaChallenge(factorId: string, ipAddress?: string): Promise<MfaChallengeInfo>;
|
|
398
|
+
/**
|
|
399
|
+
* Get an MFA challenge by ID
|
|
400
|
+
*/
|
|
401
|
+
getMfaChallengeById(challengeId: string): Promise<MfaChallengeInfo | null>;
|
|
402
|
+
/**
|
|
403
|
+
* Mark an MFA challenge as verified
|
|
404
|
+
*/
|
|
405
|
+
verifyMfaChallenge(challengeId: string): Promise<void>;
|
|
406
|
+
/**
|
|
407
|
+
* Create recovery codes for a user
|
|
408
|
+
*/
|
|
409
|
+
createRecoveryCodes(userId: string, codeHashes: string[]): Promise<void>;
|
|
410
|
+
/**
|
|
411
|
+
* Use a recovery code (mark as used)
|
|
412
|
+
*/
|
|
413
|
+
useRecoveryCode(userId: string, codeHash: string): Promise<boolean>;
|
|
414
|
+
/**
|
|
415
|
+
* Get unused recovery code count for a user
|
|
416
|
+
*/
|
|
417
|
+
getUnusedRecoveryCodeCount(userId: string): Promise<number>;
|
|
418
|
+
/**
|
|
419
|
+
* Delete all recovery codes for a user
|
|
420
|
+
*/
|
|
421
|
+
deleteAllRecoveryCodes(userId: string): Promise<void>;
|
|
422
|
+
/**
|
|
423
|
+
* Check if a user has any verified MFA factors
|
|
424
|
+
*/
|
|
425
|
+
hasVerifiedMfaFactors(userId: string): Promise<boolean>;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Combined auth repository interface for convenience
|
|
429
|
+
*/
|
|
430
|
+
export interface AuthRepository extends UserRepository, RoleRepository, TokenRepository, MfaRepository {
|
|
431
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export interface JwtConfig {
|
|
2
|
+
secret: string;
|
|
3
|
+
accessExpiresIn?: string;
|
|
4
|
+
refreshExpiresIn?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface AccessTokenPayload {
|
|
7
|
+
userId: string;
|
|
8
|
+
roles: string[];
|
|
9
|
+
uid?: string;
|
|
10
|
+
/** Authentication Assurance Level: aal1 = password/oauth, aal2 = MFA verified */
|
|
11
|
+
aal?: "aal1" | "aal2";
|
|
12
|
+
/** Email claim from the JWT, if present */
|
|
13
|
+
email?: string;
|
|
14
|
+
/** Display name claim from the JWT, if present */
|
|
15
|
+
displayName?: string;
|
|
16
|
+
/** Photo URL claim from the JWT, if present */
|
|
17
|
+
photoURL?: string;
|
|
18
|
+
/** Whether MFA has been verified for this session */
|
|
19
|
+
mfa_verified?: boolean;
|
|
20
|
+
/** Authentication Methods Reference — list of methods used (e.g. 'pwd', 'otp') */
|
|
21
|
+
amr?: string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Configure JWT settings - call this during initialization.
|
|
25
|
+
* Validates the secret strength to prevent deployment with default/weak secrets.
|
|
26
|
+
*/
|
|
27
|
+
export declare function configureJwt(config: JwtConfig): void;
|
|
28
|
+
/**
|
|
29
|
+
* Generate an access token (short-lived, 1 hour by default)
|
|
30
|
+
*/
|
|
31
|
+
export declare function generateAccessToken(userId: string, roles: string[], aal?: "aal1" | "aal2", customClaims?: Record<string, unknown>): string;
|
|
32
|
+
/**
|
|
33
|
+
* Get the expiration time of an access token in milliseconds from now
|
|
34
|
+
*/
|
|
35
|
+
export declare function getAccessTokenExpiryMs(): number;
|
|
36
|
+
/**
|
|
37
|
+
* Get the expiration timestamp for an access token
|
|
38
|
+
*/
|
|
39
|
+
export declare function getAccessTokenExpiry(): number;
|
|
40
|
+
/**
|
|
41
|
+
* Verify and decode an access token
|
|
42
|
+
*/
|
|
43
|
+
export declare function verifyAccessToken(token: string): AccessTokenPayload | null;
|
|
44
|
+
/**
|
|
45
|
+
* Generate a random refresh token (long-lived, 30 days by default)
|
|
46
|
+
*/
|
|
47
|
+
export declare function generateRefreshToken(): string;
|
|
48
|
+
/**
|
|
49
|
+
* Hash a refresh token for database storage (don't store raw tokens)
|
|
50
|
+
*/
|
|
51
|
+
export declare function hashRefreshToken(token: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Calculate refresh token expiration date
|
|
54
|
+
*/
|
|
55
|
+
export declare function getRefreshTokenExpiry(): Date;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { OAuthProvider } from "./interfaces";
|
|
2
|
+
export interface LinkedinUserInfo {
|
|
3
|
+
linkedinId: string;
|
|
4
|
+
email: string;
|
|
5
|
+
displayName: string | null;
|
|
6
|
+
photoUrl: string | null;
|
|
7
|
+
emailVerified: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Creates a LinkedIn OAuth Provider integration
|
|
11
|
+
*/
|
|
12
|
+
export declare function createLinkedinProvider(config: {
|
|
13
|
+
clientId: string;
|
|
14
|
+
clientSecret: string;
|
|
15
|
+
}): OAuthProvider<{
|
|
16
|
+
code: string;
|
|
17
|
+
redirectUri: string;
|
|
18
|
+
}>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import type { AuthModuleConfig } from "./routes";
|
|
3
|
+
import type { ResolvedAuthHooks } from "./auth-hooks";
|
|
4
|
+
import type { HonoEnv } from "../api/types";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasepro/types";
|
|
7
|
+
/**
|
|
8
|
+
* Mount magic link routes onto the auth router.
|
|
9
|
+
*
|
|
10
|
+
* Follows the same delegation pattern as `mountMfaRoutes()` and `mountSessionRoutes()`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function mountMagicLinkRoutes(deps: {
|
|
13
|
+
router: Hono<HonoEnv>;
|
|
14
|
+
config: AuthModuleConfig;
|
|
15
|
+
ops: ResolvedAuthHooks;
|
|
16
|
+
parseBody: <T>(schema: z.ZodSchema<T>, body: unknown) => T;
|
|
17
|
+
buildAuthResponse: (user: {
|
|
18
|
+
id: string;
|
|
19
|
+
email: string;
|
|
20
|
+
displayName?: string | null;
|
|
21
|
+
photoUrl?: string | null;
|
|
22
|
+
metadata?: Record<string, unknown> | null;
|
|
23
|
+
}, roleIds: string[], accessToken: string, refreshToken: string) => unknown;
|
|
24
|
+
createSessionAndTokens: (userId: string, userAgent: string, ipAddress: string) => Promise<{
|
|
25
|
+
roleIds: string[];
|
|
26
|
+
accessToken: string;
|
|
27
|
+
refreshToken: string;
|
|
28
|
+
}>;
|
|
29
|
+
applyTransformHook: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, userId: string) => Promise<AuthResponsePayload>;
|
|
30
|
+
}): void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Envelope encryption for TOTP secrets using AES-256-GCM.
|
|
3
|
+
*
|
|
4
|
+
* - Derives a 32-byte key via SHA-256 from `MFA_ENCRYPTION_KEY` or `JWT_SECRET`.
|
|
5
|
+
* - Generates a random 12-byte IV per encryption call.
|
|
6
|
+
* - Returns ciphertexts in the format `iv_hex:authTag_hex:ciphertext_hex`.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Encrypt a plaintext TOTP secret.
|
|
12
|
+
*
|
|
13
|
+
* @param plaintext - The Base32 TOTP secret to encrypt.
|
|
14
|
+
* @returns A string in the format `iv_hex:authTag_hex:ciphertext_hex`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function encryptTotpSecret(plaintext: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Decrypt a previously encrypted TOTP secret.
|
|
19
|
+
*
|
|
20
|
+
* @param ciphertext - A string in the format `iv_hex:authTag_hex:ciphertext_hex`.
|
|
21
|
+
* @returns The original Base32 TOTP secret.
|
|
22
|
+
*/
|
|
23
|
+
export declare function decryptTotpSecret(ciphertext: string): string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { HonoEnv } from "../api/types";
|
|
4
|
+
import type { AuthModuleConfig } from "./routes";
|
|
5
|
+
import { resolveAuthHooks } from "./auth-hooks";
|
|
6
|
+
import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasepro/types";
|
|
7
|
+
export declare function mountMfaRoutes(router: Hono<HonoEnv>, config: AuthModuleConfig, ops: ReturnType<typeof resolveAuthHooks>, parseBody: <T>(schema: z.ZodSchema<T>, body: unknown) => T, applyTransformHook?: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, userId: string) => Promise<AuthResponsePayload>): void;
|