@molecule/api-resource-user 1.0.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/LICENSE +115 -0
- package/dist/authorization.d.ts +107 -0
- package/dist/authorization.d.ts.map +1 -0
- package/dist/authorization.js +375 -0
- package/dist/authorization.js.map +1 -0
- package/dist/authorizers/auth.d.ts +8 -0
- package/dist/authorizers/auth.d.ts.map +1 -0
- package/dist/authorizers/auth.js +19 -0
- package/dist/authorizers/auth.js.map +1 -0
- package/dist/authorizers/authSelf.d.ts +14 -0
- package/dist/authorizers/authSelf.d.ts.map +1 -0
- package/dist/authorizers/authSelf.js +31 -0
- package/dist/authorizers/authSelf.js.map +1 -0
- package/dist/authorizers/index.d.ts +5 -0
- package/dist/authorizers/index.d.ts.map +1 -0
- package/dist/authorizers/index.js +5 -0
- package/dist/authorizers/index.js.map +1 -0
- package/dist/authorizers/rateLimit.d.ts +84 -0
- package/dist/authorizers/rateLimit.d.ts.map +1 -0
- package/dist/authorizers/rateLimit.js +144 -0
- package/dist/authorizers/rateLimit.js.map +1 -0
- package/dist/authorizers/requireWebhookAuthenticity.d.ts +23 -0
- package/dist/authorizers/requireWebhookAuthenticity.d.ts.map +1 -0
- package/dist/authorizers/requireWebhookAuthenticity.js +76 -0
- package/dist/authorizers/requireWebhookAuthenticity.js.map +1 -0
- package/dist/browser-guard.d.ts +2 -0
- package/dist/browser-guard.d.ts.map +1 -0
- package/dist/browser-guard.js +19 -0
- package/dist/browser-guard.js.map +1 -0
- package/dist/handlers/create.d.ts +52 -0
- package/dist/handlers/create.d.ts.map +1 -0
- package/dist/handlers/create.js +208 -0
- package/dist/handlers/create.js.map +1 -0
- package/dist/handlers/del.d.ts +30 -0
- package/dist/handlers/del.d.ts.map +1 -0
- package/dist/handlers/del.js +55 -0
- package/dist/handlers/del.js.map +1 -0
- package/dist/handlers/forgotPassword.d.ts +34 -0
- package/dist/handlers/forgotPassword.d.ts.map +1 -0
- package/dist/handlers/forgotPassword.js +119 -0
- package/dist/handlers/forgotPassword.js.map +1 -0
- package/dist/handlers/index.d.ts +16 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +16 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/logIn.d.ts +91 -0
- package/dist/handlers/logIn.d.ts.map +1 -0
- package/dist/handlers/logIn.js +223 -0
- package/dist/handlers/logIn.js.map +1 -0
- package/dist/handlers/logInOAuth.d.ts +66 -0
- package/dist/handlers/logInOAuth.d.ts.map +1 -0
- package/dist/handlers/logInOAuth.js +462 -0
- package/dist/handlers/logInOAuth.js.map +1 -0
- package/dist/handlers/logout.d.ts +22 -0
- package/dist/handlers/logout.d.ts.map +1 -0
- package/dist/handlers/logout.js +57 -0
- package/dist/handlers/logout.js.map +1 -0
- package/dist/handlers/oauthAuthorize.d.ts +44 -0
- package/dist/handlers/oauthAuthorize.d.ts.map +1 -0
- package/dist/handlers/oauthAuthorize.js +141 -0
- package/dist/handlers/oauthAuthorize.js.map +1 -0
- package/dist/handlers/payments/handlePaymentNotification.d.ts +28 -0
- package/dist/handlers/payments/handlePaymentNotification.d.ts.map +1 -0
- package/dist/handlers/payments/handlePaymentNotification.js +217 -0
- package/dist/handlers/payments/handlePaymentNotification.js.map +1 -0
- package/dist/handlers/payments/registry.d.ts +13 -0
- package/dist/handlers/payments/registry.d.ts.map +1 -0
- package/dist/handlers/payments/registry.js +13 -0
- package/dist/handlers/payments/registry.js.map +1 -0
- package/dist/handlers/payments/verifyPayment.d.ts +37 -0
- package/dist/handlers/payments/verifyPayment.d.ts.map +1 -0
- package/dist/handlers/payments/verifyPayment.js +383 -0
- package/dist/handlers/payments/verifyPayment.js.map +1 -0
- package/dist/handlers/read.d.ts +17 -0
- package/dist/handlers/read.d.ts.map +1 -0
- package/dist/handlers/read.js +60 -0
- package/dist/handlers/read.js.map +1 -0
- package/dist/handlers/readSelf.d.ts +23 -0
- package/dist/handlers/readSelf.d.ts.map +1 -0
- package/dist/handlers/readSelf.js +77 -0
- package/dist/handlers/readSelf.js.map +1 -0
- package/dist/handlers/resetPassword.d.ts +40 -0
- package/dist/handlers/resetPassword.d.ts.map +1 -0
- package/dist/handlers/resetPassword.js +147 -0
- package/dist/handlers/resetPassword.js.map +1 -0
- package/dist/handlers/update.d.ts +28 -0
- package/dist/handlers/update.d.ts.map +1 -0
- package/dist/handlers/update.js +250 -0
- package/dist/handlers/update.js.map +1 -0
- package/dist/handlers/updatePassword.d.ts +35 -0
- package/dist/handlers/updatePassword.d.ts.map +1 -0
- package/dist/handlers/updatePassword.js +113 -0
- package/dist/handlers/updatePassword.js.map +1 -0
- package/dist/handlers/updatePlan.d.ts +41 -0
- package/dist/handlers/updatePlan.d.ts.map +1 -0
- package/dist/handlers/updatePlan.js +242 -0
- package/dist/handlers/updatePlan.js.map +1 -0
- package/dist/handlers/verifyTwoFactor.d.ts +46 -0
- package/dist/handlers/verifyTwoFactor.d.ts.map +1 -0
- package/dist/handlers/verifyTwoFactor.js +162 -0
- package/dist/handlers/verifyTwoFactor.js.map +1 -0
- package/dist/i18n.d.ts +10 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +25 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +88 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/requestHandlerMap.d.ts +44 -0
- package/dist/requestHandlerMap.d.ts.map +1 -0
- package/dist/requestHandlerMap.js +68 -0
- package/dist/requestHandlerMap.js.map +1 -0
- package/dist/resource.d.ts +22 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/resource.js +23 -0
- package/dist/resource.js.map +1 -0
- package/dist/routes.d.ts +44 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +121 -0
- package/dist/routes.js.map +1 -0
- package/dist/schema.d.ts +193 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +229 -0
- package/dist/schema.js.map +1 -0
- package/dist/secrets.d.ts +16 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +28 -0
- package/dist/secrets.js.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/utilities/getPlan.d.ts +19 -0
- package/dist/utilities/getPlan.d.ts.map +1 -0
- package/dist/utilities/getPlan.js +26 -0
- package/dist/utilities/getPlan.js.map +1 -0
- package/dist/utilities/hashResetToken.d.ts +16 -0
- package/dist/utilities/hashResetToken.d.ts.map +1 -0
- package/dist/utilities/hashResetToken.js +19 -0
- package/dist/utilities/hashResetToken.js.map +1 -0
- package/dist/utilities/index.d.ts +5 -0
- package/dist/utilities/index.d.ts.map +1 -0
- package/dist/utilities/index.js +5 -0
- package/dist/utilities/index.js.map +1 -0
- package/dist/utilities/invalidateEntitlements.d.ts +24 -0
- package/dist/utilities/invalidateEntitlements.d.ts.map +1 -0
- package/dist/utilities/invalidateEntitlements.js +41 -0
- package/dist/utilities/invalidateEntitlements.js.map +1 -0
- package/dist/utilities/normalizeEmail.d.ts +22 -0
- package/dist/utilities/normalizeEmail.d.ts.map +1 -0
- package/dist/utilities/normalizeEmail.js +28 -0
- package/dist/utilities/normalizeEmail.js.map +1 -0
- package/dist/utilities/notify.d.ts +21 -0
- package/dist/utilities/notify.d.ts.map +1 -0
- package/dist/utilities/notify.js +39 -0
- package/dist/utilities/notify.js.map +1 -0
- package/dist/utilities/stripSensitiveUserColumns.d.ts +25 -0
- package/dist/utilities/stripSensitiveUserColumns.d.ts.map +1 -0
- package/dist/utilities/stripSensitiveUserColumns.js +43 -0
- package/dist/utilities/stripSensitiveUserColumns.js.map +1 -0
- package/package.json +94 -0
- package/setup/users.sql +22 -0
- package/setup/usersSecrets.sql +9 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `user` resource types, schema, and definition.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* The user record is split across TWO schemas — pick the right one or you leak credentials:
|
|
6
|
+
* - **{@link Props} (`propsSchema`)** — SAFE, client-facing fields (username, name, email,
|
|
7
|
+
* `emailVerified`, `twoFactorEnabled`, plan). This is what handlers return and what lives
|
|
8
|
+
* in the `users` table.
|
|
9
|
+
* - **{@link SecretProps} (`secretPropsSchema`)** — SERVER-ONLY secrets: `passwordHash`, the
|
|
10
|
+
* TOTP `twoFactorSecret` (and its pending-setup value). Stored in a SEPARATE secrets table
|
|
11
|
+
* and NEVER serialized to the client. Note the pair `twoFactorEnabled` (safe boolean, in
|
|
12
|
+
* `Props`) vs `twoFactorSecret` (secret, in `SecretProps`).
|
|
13
|
+
*
|
|
14
|
+
* When you extend the user, put a secret (token, hash, key, provider refresh token) in
|
|
15
|
+
* `SecretProps`; put a display field in `Props`. **Never add a secret to `Props`, never
|
|
16
|
+
* return a secrets-table value in a response or log, and never `res.json(userRow)` a raw DB
|
|
17
|
+
* row** — return `Props`.
|
|
18
|
+
*
|
|
19
|
+
* Auth is ALREADY wired globally (the router's `verifyMiddleware` → `res.locals.session`),
|
|
20
|
+
* so a handler reads the current user with `getUserId(res)` and does NOT add per-route auth
|
|
21
|
+
* middleware (see the `auth` skill). Scope every custom user query by the authenticated id.
|
|
22
|
+
*
|
|
23
|
+
* On the CLIENT, the bearer token is held IN MEMORY only — a `localStorage` copy is
|
|
24
|
+
* XSS-exfiltratable and is forbidden. The session is restored after a reload via the
|
|
25
|
+
* httpOnly cookie + `GET /users/me`; don't persist the token yourself.
|
|
26
|
+
*
|
|
27
|
+
* **Client-facing endpoints** (mounted under the app's `/api` prefix → `/api/users/...`).
|
|
28
|
+
* The auth CLIENT (`useAuth()` → `login` / `register` / `logout` / `refresh`) already wraps
|
|
29
|
+
* login / signup / logout — do NOT hand-roll those against the raw routes. The rest have NO
|
|
30
|
+
* client method; call them with raw `http.*`. Use these EXACT paths — a weak model guesses
|
|
31
|
+
* `/api/auth/*` or `/api/user` (singular), and neither exists:
|
|
32
|
+
* - `POST /api/users/forgot-password` — request a reset email (body `{ email }`)
|
|
33
|
+
* - `POST /api/users/reset-password` — confirm with the emailed token (body `{ token, password }`)
|
|
34
|
+
* - `PATCH /api/users/:id` — update profile fields (name, username, email, bio); NOT `PUT /api/user`
|
|
35
|
+
* - `PATCH /api/users/:id/password` — change password · `DELETE /api/users/:id` — delete account
|
|
36
|
+
* - `PATCH /api/users/:id/plan` — update the subscription plan
|
|
37
|
+
* - `GET /api/users/me` — the current user (session restore) · `GET /api/users/:id` — read one
|
|
38
|
+
* The full, authoritative route list is the `routes` export (see `routes.ts`).
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* // Extend safely: a display field in Props, a secret in SecretProps.
|
|
43
|
+
* // propsSchema: { …, timezone: z.string().optional() } // safe → client
|
|
44
|
+
* // secretPropsSchema: { …, passwordResetToken: z.string().optional() } // server-only, secrets table
|
|
45
|
+
*
|
|
46
|
+
* // A custom handler returns SAFE props — never the secrets row.
|
|
47
|
+
* router.get('/me/timezone', async (req, res) => {
|
|
48
|
+
* const userId = getUserId(res)
|
|
49
|
+
* if (!userId) return res.status(401).json({ error: 'Authentication required.' })
|
|
50
|
+
* const user = await findById('users', userId) // the users table holds Props only
|
|
51
|
+
* res.json({ timezone: user?.timezone }) // never spread a secrets-table row here
|
|
52
|
+
* })
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @e2e
|
|
56
|
+
* Integration checklist — drive the real UI (live preview, no mocks), adapt
|
|
57
|
+
* each item to this app's actual screens/flows, and check every box off one
|
|
58
|
+
* by one. A box you can't check is an integration bug to fix — not a skip:
|
|
59
|
+
* - [ ] A new user can sign up with email + password and lands authenticated (the
|
|
60
|
+
* UI reflects the signed-in user, e.g. their name/menu appears).
|
|
61
|
+
* - [ ] Any flow that emails a link/code (signup verification, password reset)
|
|
62
|
+
* round-trips: the sandbox CAPTURES the message instead of sending — read it
|
|
63
|
+
* with the `read_activity` tool (filter type 'email') and follow the link/code
|
|
64
|
+
* in its payload; never mock the flow or modify production code to expose it.
|
|
65
|
+
* - [ ] Logging out and logging back in with the same credentials reaches the same
|
|
66
|
+
* account and its data.
|
|
67
|
+
* - [ ] The session survives a full page reload (restored via the httpOnly cookie +
|
|
68
|
+
* `GET /users/me` — never from a token persisted in localStorage).
|
|
69
|
+
* - [ ] A wrong password shows a visible error and does NOT authenticate.
|
|
70
|
+
* - [ ] Authenticated-only screens are unreachable when logged out (redirect to
|
|
71
|
+
* login or an explicit denial — never a blank page).
|
|
72
|
+
* - [ ] A profile/account edit (e.g. display name) persists across a reload.
|
|
73
|
+
*
|
|
74
|
+
* @module
|
|
75
|
+
*/
|
|
76
|
+
export * as authorization from './authorization.js';
|
|
77
|
+
export * as authorizers from './authorizers/index.js';
|
|
78
|
+
export * from './browser-guard.js';
|
|
79
|
+
export * as handlers from './handlers/index.js';
|
|
80
|
+
export * from './i18n.js';
|
|
81
|
+
export * from './requestHandlerMap.js';
|
|
82
|
+
export * from './resource.js';
|
|
83
|
+
export * from './routes.js';
|
|
84
|
+
export * from './schema.js';
|
|
85
|
+
export * from './secrets.js';
|
|
86
|
+
export * as types from './types.js';
|
|
87
|
+
export * as utilities from './utilities/index.js';
|
|
88
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EG;AAEH,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,WAAW,MAAM,wBAAwB,CAAA;AACrD,cAAc,oBAAoB,CAAA;AAClC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAA;AAC/C,cAAc,WAAW,CAAA;AACzB,cAAc,wBAAwB,CAAA;AACtC,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { createRequestHandler as CreateRequestHandler, MoleculeRequestHandler } from '@molecule/api-resource';
|
|
2
|
+
type RequestHandlerCreator = typeof CreateRequestHandler;
|
|
3
|
+
/**
|
|
4
|
+
* Shape of the user request-handler map produced by `createRequestHandlerMap`.
|
|
5
|
+
* Names match the route definitions in `routes.ts`. Exported so helpers that
|
|
6
|
+
* accept the map (e.g. `mountDefaultUserAuthRoutes`, `mountDefaultUserCrudRoutes`)
|
|
7
|
+
* can type their parameter precisely instead of widening to
|
|
8
|
+
* `Record<string, MoleculeRequestHandler>`.
|
|
9
|
+
*/
|
|
10
|
+
export interface UserRequestHandlerMap {
|
|
11
|
+
auth: MoleculeRequestHandler;
|
|
12
|
+
authSelf: MoleculeRequestHandler;
|
|
13
|
+
rateLimitAuth: MoleculeRequestHandler;
|
|
14
|
+
rateLimitTwoFactor: MoleculeRequestHandler;
|
|
15
|
+
create: MoleculeRequestHandler;
|
|
16
|
+
logIn: MoleculeRequestHandler;
|
|
17
|
+
oauthAuthorize: MoleculeRequestHandler;
|
|
18
|
+
logInOAuth: MoleculeRequestHandler;
|
|
19
|
+
logout: MoleculeRequestHandler;
|
|
20
|
+
read: MoleculeRequestHandler;
|
|
21
|
+
readSelf: MoleculeRequestHandler;
|
|
22
|
+
update: MoleculeRequestHandler;
|
|
23
|
+
del: MoleculeRequestHandler;
|
|
24
|
+
updatePassword: MoleculeRequestHandler;
|
|
25
|
+
forgotPassword: MoleculeRequestHandler;
|
|
26
|
+
resetPassword: MoleculeRequestHandler;
|
|
27
|
+
verifyTwoFactor: MoleculeRequestHandler;
|
|
28
|
+
updatePlan: MoleculeRequestHandler;
|
|
29
|
+
verifyPayment: MoleculeRequestHandler;
|
|
30
|
+
handlePaymentNotification: MoleculeRequestHandler;
|
|
31
|
+
requireWebhookAuthenticity: MoleculeRequestHandler;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Creates the full request handler map for the User resource.
|
|
35
|
+
* Optional features (OAuth, payments) are conditionally included
|
|
36
|
+
* based on bonded providers.
|
|
37
|
+
*
|
|
38
|
+
* Handler names match the route definitions in routes.ts.
|
|
39
|
+
* @param createRequestHandler - Factory from `@molecule/api-resource` that wraps handler configs into Express middleware.
|
|
40
|
+
* @returns A `UserRequestHandlerMap` of handler names to Express middleware.
|
|
41
|
+
*/
|
|
42
|
+
export declare const createRequestHandlerMap: (createRequestHandler: RequestHandlerCreator) => UserRequestHandlerMap;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=requestHandlerMap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestHandlerMap.d.ts","sourceRoot":"","sources":["../src/requestHandlerMap.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,oBAAoB,IAAI,oBAAoB,EAC5C,sBAAsB,EACvB,MAAM,wBAAwB,CAAA;AAM/B,KAAK,qBAAqB,GAAG,OAAO,oBAAoB,CAAA;AAExD;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,sBAAsB,CAAA;IAC5B,QAAQ,EAAE,sBAAsB,CAAA;IAChC,aAAa,EAAE,sBAAsB,CAAA;IACrC,kBAAkB,EAAE,sBAAsB,CAAA;IAC1C,MAAM,EAAE,sBAAsB,CAAA;IAC9B,KAAK,EAAE,sBAAsB,CAAA;IAC7B,cAAc,EAAE,sBAAsB,CAAA;IACtC,UAAU,EAAE,sBAAsB,CAAA;IAClC,MAAM,EAAE,sBAAsB,CAAA;IAC9B,IAAI,EAAE,sBAAsB,CAAA;IAC5B,QAAQ,EAAE,sBAAsB,CAAA;IAChC,MAAM,EAAE,sBAAsB,CAAA;IAC9B,GAAG,EAAE,sBAAsB,CAAA;IAC3B,cAAc,EAAE,sBAAsB,CAAA;IACtC,cAAc,EAAE,sBAAsB,CAAA;IACtC,aAAa,EAAE,sBAAsB,CAAA;IACrC,eAAe,EAAE,sBAAsB,CAAA;IACvC,UAAU,EAAE,sBAAsB,CAAA;IAClC,aAAa,EAAE,sBAAsB,CAAA;IACrC,yBAAyB,EAAE,sBAAsB,CAAA;IACjD,0BAA0B,EAAE,sBAAsB,CAAA;CACnD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,GAClC,sBAAsB,qBAAqB,KAC1C,qBA0DF,CAAA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { getAll } from '@molecule/api-bond';
|
|
2
|
+
import * as authorizers from './authorizers/index.js';
|
|
3
|
+
import * as handlers from './handlers/index.js';
|
|
4
|
+
import { resource } from './resource.js';
|
|
5
|
+
/**
|
|
6
|
+
* Creates the full request handler map for the User resource.
|
|
7
|
+
* Optional features (OAuth, payments) are conditionally included
|
|
8
|
+
* based on bonded providers.
|
|
9
|
+
*
|
|
10
|
+
* Handler names match the route definitions in routes.ts.
|
|
11
|
+
* @param createRequestHandler - Factory from `@molecule/api-resource` that wraps handler configs into Express middleware.
|
|
12
|
+
* @returns A `UserRequestHandlerMap` of handler names to Express middleware.
|
|
13
|
+
*/
|
|
14
|
+
export const createRequestHandlerMap = (createRequestHandler) => {
|
|
15
|
+
const map = {
|
|
16
|
+
// Authorizers
|
|
17
|
+
auth: authorizers.auth(),
|
|
18
|
+
authSelf: authorizers.authSelf(),
|
|
19
|
+
// Default brute-force protection for the public/credential-bearing auth
|
|
20
|
+
// endpoints (login, oauth, forgot/reset-password). Keyed by IP and by the
|
|
21
|
+
// submitted account, with a low ceiling. No-ops (logs a warning) if no
|
|
22
|
+
// rate-limit provider is bonded, so apps that opt out still boot.
|
|
23
|
+
rateLimitAuth: authorizers.rateLimit({
|
|
24
|
+
scope: 'auth',
|
|
25
|
+
accountFrom: [authorizers.loginAccountKey, authorizers.emailAccountKey],
|
|
26
|
+
}),
|
|
27
|
+
// Stricter limiter for the authSelf-gated 2FA verification route — temp-locks
|
|
28
|
+
// the second factor per account after consecutive misses.
|
|
29
|
+
rateLimitTwoFactor: authorizers.rateLimit({
|
|
30
|
+
scope: '2fa',
|
|
31
|
+
max: 5,
|
|
32
|
+
accountFrom: [authorizers.paramIdAccountKey],
|
|
33
|
+
}),
|
|
34
|
+
// Authenticity guard for the public payment-notification (IAP S2S) route.
|
|
35
|
+
requireWebhookAuthenticity: authorizers.requireWebhookAuthenticity(),
|
|
36
|
+
// Core handlers
|
|
37
|
+
create: createRequestHandler(handlers.create(resource)),
|
|
38
|
+
logIn: createRequestHandler(handlers.logIn(resource)),
|
|
39
|
+
logout: createRequestHandler(handlers.logout()),
|
|
40
|
+
read: createRequestHandler(handlers.read(resource)),
|
|
41
|
+
readSelf: createRequestHandler(handlers.readSelf(resource)),
|
|
42
|
+
update: createRequestHandler(handlers.update(resource)),
|
|
43
|
+
del: createRequestHandler(handlers.del(resource)),
|
|
44
|
+
updatePassword: createRequestHandler(handlers.updatePassword(resource)),
|
|
45
|
+
forgotPassword: createRequestHandler(handlers.forgotPassword(resource)),
|
|
46
|
+
resetPassword: createRequestHandler(handlers.resetPassword(resource)),
|
|
47
|
+
verifyTwoFactor: createRequestHandler(handlers.verifyTwoFactor(resource)),
|
|
48
|
+
updatePlan: createRequestHandler(handlers.updatePlan(resource)),
|
|
49
|
+
// OAuth initiation + login — both check the bond registry at request
|
|
50
|
+
// time (a provider that isn't bonded yields a clean 404, so the mounts
|
|
51
|
+
// never crash when no oauth bond is wired).
|
|
52
|
+
oauthAuthorize: createRequestHandler(handlers.oauthAuthorize()),
|
|
53
|
+
logInOAuth: createRequestHandler(handlers.logInOAuth(resource)),
|
|
54
|
+
// Payment handlers — always registered so route mounts don't crash with
|
|
55
|
+
// "argument handler must be a function" when no payments bond is wired
|
|
56
|
+
// at module-init time. The handlers themselves check the bond registry
|
|
57
|
+
// at REQUEST time and respond with 503 if no provider is bonded for the
|
|
58
|
+
// requested :provider. Adding a new payment provider requires only a
|
|
59
|
+
// new bond package — no source changes here.
|
|
60
|
+
verifyPayment: createRequestHandler(handlers.verifyPayment(resource)),
|
|
61
|
+
handlePaymentNotification: createRequestHandler(handlers.handlePaymentNotification(resource)),
|
|
62
|
+
};
|
|
63
|
+
// Suppress unused-import warning while keeping the bond-registry import
|
|
64
|
+
// for future reuse (handlers themselves still consult `getAll<PaymentProvider>('payments')`).
|
|
65
|
+
void getAll;
|
|
66
|
+
return map;
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=requestHandlerMap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestHandlerMap.js","sourceRoot":"","sources":["../src/requestHandlerMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAO3C,OAAO,KAAK,WAAW,MAAM,wBAAwB,CAAA;AACrD,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAmCxC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,oBAA2C,EACpB,EAAE;IACzB,MAAM,GAAG,GAA0B;QACjC,cAAc;QACd,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE;QACxB,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAAE;QAChC,wEAAwE;QACxE,0EAA0E;QAC1E,uEAAuE;QACvE,kEAAkE;QAClE,aAAa,EAAE,WAAW,CAAC,SAAS,CAAC;YACnC,KAAK,EAAE,MAAM;YACb,WAAW,EAAE,CAAC,WAAW,CAAC,eAAe,EAAE,WAAW,CAAC,eAAe,CAAC;SACxE,CAAC;QACF,8EAA8E;QAC9E,0DAA0D;QAC1D,kBAAkB,EAAE,WAAW,CAAC,SAAS,CAAC;YACxC,KAAK,EAAE,KAAK;YACZ,GAAG,EAAE,CAAC;YACN,WAAW,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC;SAC7C,CAAC;QACF,0EAA0E;QAC1E,0BAA0B,EAAE,WAAW,CAAC,0BAA0B,EAAE;QAEpE,gBAAgB;QAChB,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvD,KAAK,EAAE,oBAAoB,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACrD,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC/C,IAAI,EAAE,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC3D,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvD,GAAG,EAAE,oBAAoB,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACjD,cAAc,EAAE,oBAAoB,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QACvE,cAAc,EAAE,oBAAoB,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QACvE,aAAa,EAAE,oBAAoB,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACrE,eAAe,EAAE,oBAAoB,CAAC,QAAQ,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QACzE,UAAU,EAAE,oBAAoB,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAE/D,qEAAqE;QACrE,uEAAuE;QACvE,4CAA4C;QAC5C,cAAc,EAAE,oBAAoB,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC;QAC/D,UAAU,EAAE,oBAAoB,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAE/D,wEAAwE;QACxE,uEAAuE;QACvE,uEAAuE;QACvE,wEAAwE;QACxE,qEAAqE;QACrE,6CAA6C;QAC7C,aAAa,EAAE,oBAAoB,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACrE,yBAAyB,EAAE,oBAAoB,CAAC,QAAQ,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC;KAC9F,CAAA;IAED,wEAAwE;IACxE,8FAA8F;IAC9F,KAAK,MAAuB,CAAA;IAE5B,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User resource definition.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type * as types from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Creates a user resource definition with optional OAuth servers and plan keys.
|
|
9
|
+
* @param options - Optional configuration.
|
|
10
|
+
* @param options.oauthServers - Tuple of allowed OAuth server names (e.g. `['google', 'github']`). Constrains the `oauthServer` schema field.
|
|
11
|
+
* @param options.planKeys - Tuple of allowed plan key strings (e.g. `['free', 'pro']`). Constrains the `planKey` schema field.
|
|
12
|
+
* @returns A `Resource` with name `'User'`, table `'users'`, and a Zod schema reflecting the options.
|
|
13
|
+
*/
|
|
14
|
+
export declare const createResource: <OAuthServers extends readonly [string, ...string[]] | undefined = undefined, PlanKeys extends readonly [string, ...string[]] | undefined = undefined>(options?: {
|
|
15
|
+
oauthServers?: OAuthServers;
|
|
16
|
+
planKeys?: PlanKeys;
|
|
17
|
+
}) => types.Resource;
|
|
18
|
+
/**
|
|
19
|
+
* Default user resource definition.
|
|
20
|
+
*/
|
|
21
|
+
export declare const resource: types.Resource;
|
|
22
|
+
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAExC;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GACzB,YAAY,SAAS,SAAS,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,GAAG,SAAS,EAC3E,QAAQ,SAAS,SAAS,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,GAAG,SAAS,EACvE,UAAU;IACV,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB,KAAG,KAAK,CAAC,QAIR,CAAA;AAEF;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,QAA2B,CAAA"}
|
package/dist/resource.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User resource definition.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { createSchema } from './schema.js';
|
|
7
|
+
/**
|
|
8
|
+
* Creates a user resource definition with optional OAuth servers and plan keys.
|
|
9
|
+
* @param options - Optional configuration.
|
|
10
|
+
* @param options.oauthServers - Tuple of allowed OAuth server names (e.g. `['google', 'github']`). Constrains the `oauthServer` schema field.
|
|
11
|
+
* @param options.planKeys - Tuple of allowed plan key strings (e.g. `['free', 'pro']`). Constrains the `planKey` schema field.
|
|
12
|
+
* @returns A `Resource` with name `'User'`, table `'users'`, and a Zod schema reflecting the options.
|
|
13
|
+
*/
|
|
14
|
+
export const createResource = (options) => ({
|
|
15
|
+
name: `User`,
|
|
16
|
+
tableName: `users`,
|
|
17
|
+
schema: createSchema(options),
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Default user resource definition.
|
|
21
|
+
*/
|
|
22
|
+
export const resource = createResource();
|
|
23
|
+
//# sourceMappingURL=resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.js","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAG1C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAG5B,OAGD,EAAkB,EAAE,CAAC,CAAC;IACrB,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,OAAO;IAClB,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC;CAC9B,CAAC,CAAA;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAmB,cAAc,EAAE,CAAA"}
|
package/dist/routes.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route definitions for the User resource.
|
|
3
|
+
* Routes marked optional require additional packages to be installed.
|
|
4
|
+
*
|
|
5
|
+
* Declarative route definitions used by the injection engine.
|
|
6
|
+
*/
|
|
7
|
+
export declare const routes: ({
|
|
8
|
+
method: "post";
|
|
9
|
+
path: string;
|
|
10
|
+
middlewares: string[];
|
|
11
|
+
handler: string;
|
|
12
|
+
optional?: undefined;
|
|
13
|
+
} | {
|
|
14
|
+
method: "get";
|
|
15
|
+
path: string;
|
|
16
|
+
middlewares: string[];
|
|
17
|
+
handler: string;
|
|
18
|
+
optional: string;
|
|
19
|
+
} | {
|
|
20
|
+
method: "post";
|
|
21
|
+
path: string;
|
|
22
|
+
middlewares: string[];
|
|
23
|
+
handler: string;
|
|
24
|
+
optional: string;
|
|
25
|
+
} | {
|
|
26
|
+
method: "get";
|
|
27
|
+
path: string;
|
|
28
|
+
middlewares: string[];
|
|
29
|
+
handler: string;
|
|
30
|
+
optional?: undefined;
|
|
31
|
+
} | {
|
|
32
|
+
method: "patch";
|
|
33
|
+
path: string;
|
|
34
|
+
middlewares: string[];
|
|
35
|
+
handler: string;
|
|
36
|
+
optional?: undefined;
|
|
37
|
+
} | {
|
|
38
|
+
method: "delete";
|
|
39
|
+
path: string;
|
|
40
|
+
middlewares: string[];
|
|
41
|
+
handler: string;
|
|
42
|
+
optional?: undefined;
|
|
43
|
+
})[];
|
|
44
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAsHlB,CAAA"}
|
package/dist/routes.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route definitions for the User resource.
|
|
3
|
+
* Routes marked optional require additional packages to be installed.
|
|
4
|
+
*
|
|
5
|
+
* Declarative route definitions used by the injection engine.
|
|
6
|
+
*/
|
|
7
|
+
export const routes = [
|
|
8
|
+
// Auth
|
|
9
|
+
{ method: 'post', path: '/users', middlewares: [], handler: 'create' },
|
|
10
|
+
{
|
|
11
|
+
method: 'post',
|
|
12
|
+
path: '/users/log-in',
|
|
13
|
+
middlewares: ['rateLimitAuth'],
|
|
14
|
+
handler: 'logIn',
|
|
15
|
+
},
|
|
16
|
+
// OAuth initiation — generates the CSRF state + PKCE verifier cookies and
|
|
17
|
+
// 302-redirects to the bonded provider's authorization URL. The first half
|
|
18
|
+
// of the flow whose second half is POST /users/log-in/oauth below; without
|
|
19
|
+
// it the state cookie logInOAuth requires is never set.
|
|
20
|
+
//
|
|
21
|
+
// rateLimitAuth: the GET has no body, so only the generous per-IP bucket
|
|
22
|
+
// applies (no per-account lockout risk) — it bounds cookie-mint/redirect
|
|
23
|
+
// flooding from a single source. A trip is a 429 JSON on a top-level
|
|
24
|
+
// navigation, which is acceptable for an abuse ceiling a legitimate user
|
|
25
|
+
// never reaches (a login is one GET + one POST against a 60/15min bucket).
|
|
26
|
+
{
|
|
27
|
+
method: 'get',
|
|
28
|
+
path: '/users/oauth/:provider',
|
|
29
|
+
middlewares: ['rateLimitAuth'],
|
|
30
|
+
handler: 'oauthAuthorize',
|
|
31
|
+
optional: 'oauth',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
method: 'post',
|
|
35
|
+
path: '/users/log-in/oauth',
|
|
36
|
+
middlewares: ['rateLimitAuth'],
|
|
37
|
+
handler: 'logInOAuth',
|
|
38
|
+
optional: 'oauth',
|
|
39
|
+
},
|
|
40
|
+
// Logout — revoke the device + clear the credential cookies (token, sessionId,
|
|
41
|
+
// mol_auth hint). Cookie-authed (`auth`) — the session identifies the user; no
|
|
42
|
+
// `:id`. [M1-1] under the in-memory-token model logout MUST clear the httpOnly
|
|
43
|
+
// cookie, else cookie-restore re-logs-in on the next load.
|
|
44
|
+
{ method: 'post', path: '/users/logout', middlewares: ['auth'], handler: 'logout' },
|
|
45
|
+
{
|
|
46
|
+
method: 'post',
|
|
47
|
+
path: '/users/forgot-password',
|
|
48
|
+
middlewares: ['rateLimitAuth'],
|
|
49
|
+
handler: 'forgotPassword',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
method: 'post',
|
|
53
|
+
path: '/users/reset-password',
|
|
54
|
+
middlewares: ['rateLimitAuth'],
|
|
55
|
+
handler: 'resetPassword',
|
|
56
|
+
},
|
|
57
|
+
// Current user — session restore. MUST precede `/users/:id` so `me` isn't
|
|
58
|
+
// matched as an `:id`. Cookie-authed (`auth`, not `authSelf` — there is no
|
|
59
|
+
// `:id` to match); the app calls this on init to restore the session from the
|
|
60
|
+
// httpOnly cookie after a full page load ([M1-1] the bearer token is in-memory
|
|
61
|
+
// and lost on reload).
|
|
62
|
+
{ method: 'get', path: '/users/me', middlewares: ['auth'], handler: 'readSelf' },
|
|
63
|
+
// User CRUD (requires auth)
|
|
64
|
+
{ method: 'get', path: '/users/:id', middlewares: ['authSelf'], handler: 'read' },
|
|
65
|
+
{ method: 'patch', path: '/users/:id', middlewares: ['authSelf'], handler: 'update' },
|
|
66
|
+
{ method: 'delete', path: '/users/:id', middlewares: ['authSelf'], handler: 'del' },
|
|
67
|
+
// Password & 2FA
|
|
68
|
+
{
|
|
69
|
+
method: 'patch',
|
|
70
|
+
path: '/users/:id/password',
|
|
71
|
+
middlewares: ['authSelf'],
|
|
72
|
+
handler: 'updatePassword',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
method: 'post',
|
|
76
|
+
path: '/users/:id/verify-two-factor',
|
|
77
|
+
middlewares: ['authSelf', 'rateLimitTwoFactor'],
|
|
78
|
+
handler: 'verifyTwoFactor',
|
|
79
|
+
},
|
|
80
|
+
// Plans
|
|
81
|
+
{
|
|
82
|
+
method: 'patch',
|
|
83
|
+
path: '/users/:id/plan',
|
|
84
|
+
middlewares: ['authSelf'],
|
|
85
|
+
handler: 'updatePlan',
|
|
86
|
+
},
|
|
87
|
+
// Payment verification — GET (redirect callbacks, e.g. Stripe Checkout). [M3-1]
|
|
88
|
+
// authSelf like the POST + molecule-dev's router: the plan is granted to `:id` and the
|
|
89
|
+
// handler echoes the user row, so an unauthenticated/cross-user GET must not reach it.
|
|
90
|
+
// The Stripe success_url is a top-level browser navigation carrying the session cookie,
|
|
91
|
+
// so authSelf does not break the legitimate redirect callback.
|
|
92
|
+
{
|
|
93
|
+
method: 'get',
|
|
94
|
+
path: '/users/:id/verify-payment/:provider',
|
|
95
|
+
middlewares: ['authSelf'],
|
|
96
|
+
handler: 'verifyPayment',
|
|
97
|
+
optional: 'payments',
|
|
98
|
+
},
|
|
99
|
+
// Payment verification — POST (mobile receipt verification). Requires the
|
|
100
|
+
// caller to be the user being credited (authSelf): the plan is granted to
|
|
101
|
+
// `:id`, so an unauthenticated/cross-user POST must never reach the handler.
|
|
102
|
+
{
|
|
103
|
+
method: 'post',
|
|
104
|
+
path: '/users/:id/verify-payment/:provider',
|
|
105
|
+
middlewares: ['authSelf'],
|
|
106
|
+
handler: 'verifyPayment',
|
|
107
|
+
optional: 'payments',
|
|
108
|
+
},
|
|
109
|
+
// Payment notifications (webhooks, S2S). The authenticity guard lets
|
|
110
|
+
// signature-verifying webhook providers (Stripe) through and requires a shared
|
|
111
|
+
// secret for unsigned server-to-server providers (Apple/Google) so the public
|
|
112
|
+
// endpoint is not open by default.
|
|
113
|
+
{
|
|
114
|
+
method: 'post',
|
|
115
|
+
path: '/users/payment-notification/:provider',
|
|
116
|
+
middlewares: ['requireWebhookAuthenticity'],
|
|
117
|
+
handler: 'handlePaymentNotification',
|
|
118
|
+
optional: 'payments',
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User resource schema definitions using Zod.
|
|
3
|
+
*
|
|
4
|
+
* Types are automatically inferred from schemas using z.infer<>.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
/**
|
|
10
|
+
* Maximum length (in characters) of a user's `bio`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const MAX_BIO_LENGTH = 1000;
|
|
13
|
+
/**
|
|
14
|
+
* Maximum length (in characters) of a user's `avatar`. Sized to permit a small
|
|
15
|
+
* inline data-URI (~256KB) without requiring an external upload/storage bond.
|
|
16
|
+
* Larger avatars must be hosted elsewhere and referenced by URL.
|
|
17
|
+
*/
|
|
18
|
+
export declare const MAX_AVATAR_LENGTH: number;
|
|
19
|
+
/**
|
|
20
|
+
* Creates a full schema for user props.
|
|
21
|
+
*
|
|
22
|
+
* OAuth servers and plan keys can be constrained by passing them as options.
|
|
23
|
+
* @param options - Optional configuration.
|
|
24
|
+
* @param options.oauthServers - Tuple of allowed OAuth server names. Constrains `oauthServer` to a Zod enum.
|
|
25
|
+
* @param options.planKeys - Tuple of allowed plan key strings. Constrains `planKey` to a Zod enum.
|
|
26
|
+
* @returns A Zod object schema extending `basePropsSchema` with user-specific fields (username, email, OAuth, plan).
|
|
27
|
+
*/
|
|
28
|
+
export declare const createSchema: <OAuthServers extends readonly [string, ...string[]] | undefined = undefined, PlanKeys extends readonly [string, ...string[]] | undefined = undefined>(options?: {
|
|
29
|
+
oauthServers?: OAuthServers;
|
|
30
|
+
planKeys?: PlanKeys;
|
|
31
|
+
}) => z.ZodObject<{
|
|
32
|
+
id: z.ZodString;
|
|
33
|
+
createdAt: z.ZodString;
|
|
34
|
+
updatedAt: z.ZodString;
|
|
35
|
+
username: z.ZodOptional<z.ZodString>;
|
|
36
|
+
name: z.ZodOptional<z.ZodString>;
|
|
37
|
+
email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
38
|
+
emailVerified: z.ZodOptional<z.ZodBoolean>;
|
|
39
|
+
avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
40
|
+
bio: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
41
|
+
twoFactorEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
42
|
+
oauthServer: z.ZodOptional<z.ZodString> | z.ZodOptional<z.ZodEnum<{ [k_1 in NonNullable<OAuthServers>[number]]: k_1; } extends infer T ? { [k in keyof T]: T[k]; } : never>>;
|
|
43
|
+
oauthId: z.ZodOptional<z.ZodString>;
|
|
44
|
+
oauthData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
45
|
+
planKey: z.ZodOptional<z.ZodString> | z.ZodOptional<z.ZodEnum<{ [k_3 in NonNullable<PlanKeys>[number]]: k_3; } extends infer T_1 ? { [k_2 in keyof T_1]: T_1[k_2]; } : never>>;
|
|
46
|
+
planExpiresAt: z.ZodOptional<z.ZodString>;
|
|
47
|
+
planAutoRenews: z.ZodOptional<z.ZodBoolean>;
|
|
48
|
+
}, z.core.$strip>;
|
|
49
|
+
/**
|
|
50
|
+
* Default schema for user props.
|
|
51
|
+
*/
|
|
52
|
+
export declare const propsSchema: z.ZodObject<{
|
|
53
|
+
id: z.ZodString;
|
|
54
|
+
createdAt: z.ZodString;
|
|
55
|
+
updatedAt: z.ZodString;
|
|
56
|
+
username: z.ZodOptional<z.ZodString>;
|
|
57
|
+
name: z.ZodOptional<z.ZodString>;
|
|
58
|
+
email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
59
|
+
emailVerified: z.ZodOptional<z.ZodBoolean>;
|
|
60
|
+
avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
61
|
+
bio: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
62
|
+
twoFactorEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
63
|
+
oauthServer: z.ZodOptional<z.ZodString> | z.ZodOptional<z.ZodEnum<{}>>;
|
|
64
|
+
oauthId: z.ZodOptional<z.ZodString>;
|
|
65
|
+
oauthData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
66
|
+
planKey: z.ZodOptional<z.ZodString> | z.ZodOptional<z.ZodEnum<{}>>;
|
|
67
|
+
planExpiresAt: z.ZodOptional<z.ZodString>;
|
|
68
|
+
planAutoRenews: z.ZodOptional<z.ZodBoolean>;
|
|
69
|
+
}, z.core.$strip>;
|
|
70
|
+
/**
|
|
71
|
+
* User props type inferred from schema.
|
|
72
|
+
*/
|
|
73
|
+
export type Props = z.infer<typeof propsSchema>;
|
|
74
|
+
/**
|
|
75
|
+
* Secret properties stored in a separate table.
|
|
76
|
+
*/
|
|
77
|
+
export declare const secretPropsSchema: z.ZodObject<{
|
|
78
|
+
id: z.ZodString;
|
|
79
|
+
passwordHash: z.ZodOptional<z.ZodString>;
|
|
80
|
+
passwordResetToken: z.ZodOptional<z.ZodString>;
|
|
81
|
+
passwordResetTokenAt: z.ZodOptional<z.ZodString>;
|
|
82
|
+
pendingTwoFactorSecret: z.ZodOptional<z.ZodString>;
|
|
83
|
+
twoFactorSecret: z.ZodOptional<z.ZodString>;
|
|
84
|
+
lastTwoFactorTimeStep: z.ZodOptional<z.ZodNumber>;
|
|
85
|
+
}, z.core.$strip>;
|
|
86
|
+
/**
|
|
87
|
+
* Secret Props type.
|
|
88
|
+
*/
|
|
89
|
+
export type SecretProps = z.infer<typeof secretPropsSchema>;
|
|
90
|
+
/**
|
|
91
|
+
* Schema for creating a user via password.
|
|
92
|
+
*/
|
|
93
|
+
export declare const createPropsSchema: z.ZodObject<{
|
|
94
|
+
username: z.ZodOptional<z.ZodString>;
|
|
95
|
+
name: z.ZodOptional<z.ZodString>;
|
|
96
|
+
email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
97
|
+
}, z.core.$strip>;
|
|
98
|
+
/**
|
|
99
|
+
* Create Props type.
|
|
100
|
+
*/
|
|
101
|
+
export type CreateProps = z.infer<typeof createPropsSchema>;
|
|
102
|
+
/** Schema for creating secret props (password hash only). */
|
|
103
|
+
export declare const createSecretPropsSchema: z.ZodObject<{
|
|
104
|
+
passwordHash: z.ZodOptional<z.ZodString>;
|
|
105
|
+
}, z.core.$strip>;
|
|
106
|
+
/**
|
|
107
|
+
* Create Secret Props type.
|
|
108
|
+
*/
|
|
109
|
+
export type CreateSecretProps = z.infer<typeof createSecretPropsSchema>;
|
|
110
|
+
/**
|
|
111
|
+
* Schema for creating a user via OAuth.
|
|
112
|
+
*/
|
|
113
|
+
export declare const createOAuthPropsSchema: z.ZodObject<{
|
|
114
|
+
username: z.ZodOptional<z.ZodString>;
|
|
115
|
+
name: z.ZodOptional<z.ZodString>;
|
|
116
|
+
email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
117
|
+
emailVerified: z.ZodOptional<z.ZodBoolean>;
|
|
118
|
+
oauthServer: z.ZodOptional<z.ZodString> | z.ZodOptional<z.ZodEnum<{}>>;
|
|
119
|
+
oauthId: z.ZodOptional<z.ZodString>;
|
|
120
|
+
oauthData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
121
|
+
}, z.core.$strip>;
|
|
122
|
+
/**
|
|
123
|
+
* Create O Auth Props type.
|
|
124
|
+
*/
|
|
125
|
+
export type CreateOAuthProps = z.infer<typeof createOAuthPropsSchema>;
|
|
126
|
+
/** Schema for updating a user (partial username, name, email, avatar, bio). */
|
|
127
|
+
export declare const updatePropsSchema: z.ZodObject<{
|
|
128
|
+
username: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
129
|
+
name: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
130
|
+
email: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
131
|
+
avatar: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
132
|
+
bio: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
133
|
+
}, z.core.$strip>;
|
|
134
|
+
/**
|
|
135
|
+
* Update Props type.
|
|
136
|
+
*/
|
|
137
|
+
export type UpdateProps = z.infer<typeof updatePropsSchema>;
|
|
138
|
+
/** Schema for updating password secret props (partial password hash). */
|
|
139
|
+
export declare const updatePasswordSecretPropsSchema: z.ZodObject<{
|
|
140
|
+
passwordHash: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
141
|
+
}, z.core.$strip>;
|
|
142
|
+
/**
|
|
143
|
+
* Update Password Secret Props type.
|
|
144
|
+
*/
|
|
145
|
+
export type UpdatePasswordSecretProps = z.infer<typeof updatePasswordSecretPropsSchema>;
|
|
146
|
+
/** Schema for updating a user's plan (partial planKey, planExpiresAt, planAutoRenews). */
|
|
147
|
+
export declare const updatePlanPropsSchema: z.ZodObject<{
|
|
148
|
+
planKey: z.ZodOptional<z.ZodOptional<z.ZodString> | z.ZodOptional<z.ZodEnum<{}>>>;
|
|
149
|
+
planExpiresAt: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
150
|
+
planAutoRenews: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
151
|
+
}, z.core.$strip>;
|
|
152
|
+
/**
|
|
153
|
+
* Update Plan Props type.
|
|
154
|
+
*/
|
|
155
|
+
export type UpdatePlanProps = z.infer<typeof updatePlanPropsSchema>;
|
|
156
|
+
/**
|
|
157
|
+
* Schema for verifying two-factor authentication.
|
|
158
|
+
*/
|
|
159
|
+
export declare const verifyTwoFactorPropsSchema: z.ZodObject<{
|
|
160
|
+
twoFactorEnabled: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
161
|
+
}, z.core.$strip>;
|
|
162
|
+
/**
|
|
163
|
+
* Verify Two Factor Props type.
|
|
164
|
+
*/
|
|
165
|
+
export type VerifyTwoFactorProps = z.infer<typeof verifyTwoFactorPropsSchema>;
|
|
166
|
+
/**
|
|
167
|
+
* Schema for two-factor secret props.
|
|
168
|
+
*/
|
|
169
|
+
export declare const verifyTwoFactorSecretPropsSchema: z.ZodObject<{
|
|
170
|
+
pendingTwoFactorSecret: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
171
|
+
twoFactorSecret: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
172
|
+
}, z.core.$strip>;
|
|
173
|
+
/**
|
|
174
|
+
* Verify Two Factor Secret Props type.
|
|
175
|
+
*/
|
|
176
|
+
export type VerifyTwoFactorSecretProps = z.infer<typeof verifyTwoFactorSecretPropsSchema>;
|
|
177
|
+
/** Zod schema for JWT session payloads (userId, deviceId, optional OAuth fields). */
|
|
178
|
+
export declare const sessionSchema: z.ZodObject<{
|
|
179
|
+
id: z.ZodOptional<z.ZodString>;
|
|
180
|
+
userId: z.ZodString;
|
|
181
|
+
deviceId: z.ZodString;
|
|
182
|
+
oauthServer: z.ZodOptional<z.ZodString>;
|
|
183
|
+
oauthId: z.ZodOptional<z.ZodString>;
|
|
184
|
+
}, z.core.$strip>;
|
|
185
|
+
/**
|
|
186
|
+
* User session data (userId, email, role, permissions, metadata) inferred from sessionSchema.
|
|
187
|
+
*/
|
|
188
|
+
export type Session = z.infer<typeof sessionSchema>;
|
|
189
|
+
/**
|
|
190
|
+
* Re-export zod for convenience.
|
|
191
|
+
*/
|
|
192
|
+
export { z };
|
|
193
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB;;GAEG;AACH,eAAO,MAAM,cAAc,OAAO,CAAA;AAElC;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAa,CAAA;AAE3C;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GACvB,YAAY,SAAS,SAAS,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,GAAG,SAAS,EAC3E,QAAQ,SAAS,SAAS,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,GAAG,SAAS,EACvE,UAAU;IACV,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAEpB;;;;;;;;;;;;;;;;;iBAmEA,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;iBAAiB,CAAA;AAEzC;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAA;AAE/C;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;iBAgC5B,CAAA;AAEF;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAE3D;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;iBAI5B,CAAA;AAEF;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAE3D,6DAA6D;AAC7D,eAAO,MAAM,uBAAuB;;iBAElC,CAAA;AAEF;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAA;AAEvE;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;iBAQjC,CAAA;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAErE,+EAA+E;AAC/E,eAAO,MAAM,iBAAiB;;;;;;iBAQlB,CAAA;AAEZ;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAE3D,yEAAyE;AACzE,eAAO,MAAM,+BAA+B;;iBAIhC,CAAA;AAEZ;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAA;AAEvF,0FAA0F;AAC1F,eAAO,MAAM,qBAAqB;;;;iBAMtB,CAAA;AAEZ;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEnE;;GAEG;AACH,eAAO,MAAM,0BAA0B;;iBAI3B,CAAA;AAEZ;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAA;AAE7E;;GAEG;AACH,eAAO,MAAM,gCAAgC;;;iBAKjC,CAAA;AAEZ;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAA;AAEzF,qFAAqF;AACrF,eAAO,MAAM,aAAa;;;;;;iBAqBxB,CAAA;AAEF;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAEnD;;GAEG;AACH,OAAO,EAAE,CAAC,EAAE,CAAA"}
|