@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.
Files changed (164) hide show
  1. package/LICENSE +115 -0
  2. package/dist/authorization.d.ts +107 -0
  3. package/dist/authorization.d.ts.map +1 -0
  4. package/dist/authorization.js +375 -0
  5. package/dist/authorization.js.map +1 -0
  6. package/dist/authorizers/auth.d.ts +8 -0
  7. package/dist/authorizers/auth.d.ts.map +1 -0
  8. package/dist/authorizers/auth.js +19 -0
  9. package/dist/authorizers/auth.js.map +1 -0
  10. package/dist/authorizers/authSelf.d.ts +14 -0
  11. package/dist/authorizers/authSelf.d.ts.map +1 -0
  12. package/dist/authorizers/authSelf.js +31 -0
  13. package/dist/authorizers/authSelf.js.map +1 -0
  14. package/dist/authorizers/index.d.ts +5 -0
  15. package/dist/authorizers/index.d.ts.map +1 -0
  16. package/dist/authorizers/index.js +5 -0
  17. package/dist/authorizers/index.js.map +1 -0
  18. package/dist/authorizers/rateLimit.d.ts +84 -0
  19. package/dist/authorizers/rateLimit.d.ts.map +1 -0
  20. package/dist/authorizers/rateLimit.js +144 -0
  21. package/dist/authorizers/rateLimit.js.map +1 -0
  22. package/dist/authorizers/requireWebhookAuthenticity.d.ts +23 -0
  23. package/dist/authorizers/requireWebhookAuthenticity.d.ts.map +1 -0
  24. package/dist/authorizers/requireWebhookAuthenticity.js +76 -0
  25. package/dist/authorizers/requireWebhookAuthenticity.js.map +1 -0
  26. package/dist/browser-guard.d.ts +2 -0
  27. package/dist/browser-guard.d.ts.map +1 -0
  28. package/dist/browser-guard.js +19 -0
  29. package/dist/browser-guard.js.map +1 -0
  30. package/dist/handlers/create.d.ts +52 -0
  31. package/dist/handlers/create.d.ts.map +1 -0
  32. package/dist/handlers/create.js +208 -0
  33. package/dist/handlers/create.js.map +1 -0
  34. package/dist/handlers/del.d.ts +30 -0
  35. package/dist/handlers/del.d.ts.map +1 -0
  36. package/dist/handlers/del.js +55 -0
  37. package/dist/handlers/del.js.map +1 -0
  38. package/dist/handlers/forgotPassword.d.ts +34 -0
  39. package/dist/handlers/forgotPassword.d.ts.map +1 -0
  40. package/dist/handlers/forgotPassword.js +119 -0
  41. package/dist/handlers/forgotPassword.js.map +1 -0
  42. package/dist/handlers/index.d.ts +16 -0
  43. package/dist/handlers/index.d.ts.map +1 -0
  44. package/dist/handlers/index.js +16 -0
  45. package/dist/handlers/index.js.map +1 -0
  46. package/dist/handlers/logIn.d.ts +91 -0
  47. package/dist/handlers/logIn.d.ts.map +1 -0
  48. package/dist/handlers/logIn.js +223 -0
  49. package/dist/handlers/logIn.js.map +1 -0
  50. package/dist/handlers/logInOAuth.d.ts +66 -0
  51. package/dist/handlers/logInOAuth.d.ts.map +1 -0
  52. package/dist/handlers/logInOAuth.js +462 -0
  53. package/dist/handlers/logInOAuth.js.map +1 -0
  54. package/dist/handlers/logout.d.ts +22 -0
  55. package/dist/handlers/logout.d.ts.map +1 -0
  56. package/dist/handlers/logout.js +57 -0
  57. package/dist/handlers/logout.js.map +1 -0
  58. package/dist/handlers/oauthAuthorize.d.ts +44 -0
  59. package/dist/handlers/oauthAuthorize.d.ts.map +1 -0
  60. package/dist/handlers/oauthAuthorize.js +141 -0
  61. package/dist/handlers/oauthAuthorize.js.map +1 -0
  62. package/dist/handlers/payments/handlePaymentNotification.d.ts +28 -0
  63. package/dist/handlers/payments/handlePaymentNotification.d.ts.map +1 -0
  64. package/dist/handlers/payments/handlePaymentNotification.js +217 -0
  65. package/dist/handlers/payments/handlePaymentNotification.js.map +1 -0
  66. package/dist/handlers/payments/registry.d.ts +13 -0
  67. package/dist/handlers/payments/registry.d.ts.map +1 -0
  68. package/dist/handlers/payments/registry.js +13 -0
  69. package/dist/handlers/payments/registry.js.map +1 -0
  70. package/dist/handlers/payments/verifyPayment.d.ts +37 -0
  71. package/dist/handlers/payments/verifyPayment.d.ts.map +1 -0
  72. package/dist/handlers/payments/verifyPayment.js +383 -0
  73. package/dist/handlers/payments/verifyPayment.js.map +1 -0
  74. package/dist/handlers/read.d.ts +17 -0
  75. package/dist/handlers/read.d.ts.map +1 -0
  76. package/dist/handlers/read.js +60 -0
  77. package/dist/handlers/read.js.map +1 -0
  78. package/dist/handlers/readSelf.d.ts +23 -0
  79. package/dist/handlers/readSelf.d.ts.map +1 -0
  80. package/dist/handlers/readSelf.js +77 -0
  81. package/dist/handlers/readSelf.js.map +1 -0
  82. package/dist/handlers/resetPassword.d.ts +40 -0
  83. package/dist/handlers/resetPassword.d.ts.map +1 -0
  84. package/dist/handlers/resetPassword.js +147 -0
  85. package/dist/handlers/resetPassword.js.map +1 -0
  86. package/dist/handlers/update.d.ts +28 -0
  87. package/dist/handlers/update.d.ts.map +1 -0
  88. package/dist/handlers/update.js +250 -0
  89. package/dist/handlers/update.js.map +1 -0
  90. package/dist/handlers/updatePassword.d.ts +35 -0
  91. package/dist/handlers/updatePassword.d.ts.map +1 -0
  92. package/dist/handlers/updatePassword.js +113 -0
  93. package/dist/handlers/updatePassword.js.map +1 -0
  94. package/dist/handlers/updatePlan.d.ts +41 -0
  95. package/dist/handlers/updatePlan.d.ts.map +1 -0
  96. package/dist/handlers/updatePlan.js +242 -0
  97. package/dist/handlers/updatePlan.js.map +1 -0
  98. package/dist/handlers/verifyTwoFactor.d.ts +46 -0
  99. package/dist/handlers/verifyTwoFactor.d.ts.map +1 -0
  100. package/dist/handlers/verifyTwoFactor.js +162 -0
  101. package/dist/handlers/verifyTwoFactor.js.map +1 -0
  102. package/dist/i18n.d.ts +10 -0
  103. package/dist/i18n.d.ts.map +1 -0
  104. package/dist/i18n.js +25 -0
  105. package/dist/i18n.js.map +1 -0
  106. package/dist/index.d.ts +88 -0
  107. package/dist/index.d.ts.map +1 -0
  108. package/dist/index.js +88 -0
  109. package/dist/index.js.map +1 -0
  110. package/dist/requestHandlerMap.d.ts +44 -0
  111. package/dist/requestHandlerMap.d.ts.map +1 -0
  112. package/dist/requestHandlerMap.js +68 -0
  113. package/dist/requestHandlerMap.js.map +1 -0
  114. package/dist/resource.d.ts +22 -0
  115. package/dist/resource.d.ts.map +1 -0
  116. package/dist/resource.js +23 -0
  117. package/dist/resource.js.map +1 -0
  118. package/dist/routes.d.ts +44 -0
  119. package/dist/routes.d.ts.map +1 -0
  120. package/dist/routes.js +121 -0
  121. package/dist/routes.js.map +1 -0
  122. package/dist/schema.d.ts +193 -0
  123. package/dist/schema.d.ts.map +1 -0
  124. package/dist/schema.js +229 -0
  125. package/dist/schema.js.map +1 -0
  126. package/dist/secrets.d.ts +16 -0
  127. package/dist/secrets.d.ts.map +1 -0
  128. package/dist/secrets.js +28 -0
  129. package/dist/secrets.js.map +1 -0
  130. package/dist/types.d.ts +14 -0
  131. package/dist/types.d.ts.map +1 -0
  132. package/dist/types.js +9 -0
  133. package/dist/types.js.map +1 -0
  134. package/dist/utilities/getPlan.d.ts +19 -0
  135. package/dist/utilities/getPlan.d.ts.map +1 -0
  136. package/dist/utilities/getPlan.js +26 -0
  137. package/dist/utilities/getPlan.js.map +1 -0
  138. package/dist/utilities/hashResetToken.d.ts +16 -0
  139. package/dist/utilities/hashResetToken.d.ts.map +1 -0
  140. package/dist/utilities/hashResetToken.js +19 -0
  141. package/dist/utilities/hashResetToken.js.map +1 -0
  142. package/dist/utilities/index.d.ts +5 -0
  143. package/dist/utilities/index.d.ts.map +1 -0
  144. package/dist/utilities/index.js +5 -0
  145. package/dist/utilities/index.js.map +1 -0
  146. package/dist/utilities/invalidateEntitlements.d.ts +24 -0
  147. package/dist/utilities/invalidateEntitlements.d.ts.map +1 -0
  148. package/dist/utilities/invalidateEntitlements.js +41 -0
  149. package/dist/utilities/invalidateEntitlements.js.map +1 -0
  150. package/dist/utilities/normalizeEmail.d.ts +22 -0
  151. package/dist/utilities/normalizeEmail.d.ts.map +1 -0
  152. package/dist/utilities/normalizeEmail.js +28 -0
  153. package/dist/utilities/normalizeEmail.js.map +1 -0
  154. package/dist/utilities/notify.d.ts +21 -0
  155. package/dist/utilities/notify.d.ts.map +1 -0
  156. package/dist/utilities/notify.js +39 -0
  157. package/dist/utilities/notify.js.map +1 -0
  158. package/dist/utilities/stripSensitiveUserColumns.d.ts +25 -0
  159. package/dist/utilities/stripSensitiveUserColumns.d.ts.map +1 -0
  160. package/dist/utilities/stripSensitiveUserColumns.js +43 -0
  161. package/dist/utilities/stripSensitiveUserColumns.js.map +1 -0
  162. package/package.json +94 -0
  163. package/setup/users.sql +22 -0
  164. 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"}
@@ -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"}
@@ -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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"}
@@ -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"}