@molecule/api-resource-user 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +978 -0
- package/dist/handlers/logInOAuth.d.ts.map +1 -1
- package/dist/handlers/logInOAuth.js +44 -2
- package/dist/handlers/logInOAuth.js.map +1 -1
- package/dist/schema.d.ts +2 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2 -0
- package/dist/schema.js.map +1 -1
- package/dist/utilities/fetchAvatarDataUri.d.ts +16 -0
- package/dist/utilities/fetchAvatarDataUri.d.ts.map +1 -0
- package/dist/utilities/fetchAvatarDataUri.js +155 -0
- package/dist/utilities/fetchAvatarDataUri.js.map +1 -0
- package/dist/utilities/index.d.ts +1 -0
- package/dist/utilities/index.d.ts.map +1 -1
- package/dist/utilities/index.js +1 -0
- package/dist/utilities/index.js.map +1 -1
- package/package.json +27 -26
package/README.md
ADDED
|
@@ -0,0 +1,978 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
3
|
+
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
|
+
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
|
+
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
+
Generated: 2026-08-08T07:15:54.389Z
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
# @molecule/api-resource-user
|
|
10
|
+
|
|
11
|
+
> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
|
|
12
|
+
> It is written to be read by coding agents as much as by people, and is generated from this
|
|
13
|
+
> package's source — edit `src/index.ts` JSDoc, not this file.
|
|
14
|
+
|
|
15
|
+
The `user` resource types, schema, and definition.
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// Extend safely: a display field in Props, a secret in SecretProps.
|
|
21
|
+
// propsSchema: { …, timezone: z.string().optional() } // safe → client
|
|
22
|
+
// secretPropsSchema: { …, passwordResetToken: z.string().optional() } // server-only, secrets table
|
|
23
|
+
|
|
24
|
+
// A custom handler returns SAFE props — never the secrets row.
|
|
25
|
+
router.get('/me/timezone', async (req, res) => {
|
|
26
|
+
const userId = getUserId(res)
|
|
27
|
+
if (!userId) return res.status(401).json({ error: 'Authentication required.' })
|
|
28
|
+
const user = await findById('users', userId) // the users table holds Props only
|
|
29
|
+
res.json({ timezone: user?.timezone }) // never spread a secrets-table row here
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Type
|
|
34
|
+
|
|
35
|
+
`resource`
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @molecule/api-resource-user @molecule/api-bond @molecule/api-config @molecule/api-database @molecule/api-entitlements @molecule/api-i18n @molecule/api-jwt @molecule/api-locales-user @molecule/api-locales-user-payments @molecule/api-password @molecule/api-payments @molecule/api-push-notifications @molecule/api-rate-limit @molecule/api-resource @molecule/api-resource-device @molecule/api-secrets @molecule/api-two-factor zod
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## API
|
|
44
|
+
|
|
45
|
+
### Interfaces
|
|
46
|
+
|
|
47
|
+
#### `UserRequestHandlerMap`
|
|
48
|
+
|
|
49
|
+
Shape of the user request-handler map produced by `createRequestHandlerMap`.
|
|
50
|
+
Names match the route definitions in `routes.ts`. Exported so helpers that
|
|
51
|
+
accept the map (e.g. `mountDefaultUserAuthRoutes`, `mountDefaultUserCrudRoutes`)
|
|
52
|
+
can type their parameter precisely instead of widening to
|
|
53
|
+
`Record<string, MoleculeRequestHandler>`.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
interface UserRequestHandlerMap {
|
|
57
|
+
auth: MoleculeRequestHandler
|
|
58
|
+
authSelf: MoleculeRequestHandler
|
|
59
|
+
rateLimitAuth: MoleculeRequestHandler
|
|
60
|
+
rateLimitTwoFactor: MoleculeRequestHandler
|
|
61
|
+
create: MoleculeRequestHandler
|
|
62
|
+
logIn: MoleculeRequestHandler
|
|
63
|
+
oauthAuthorize: MoleculeRequestHandler
|
|
64
|
+
logInOAuth: MoleculeRequestHandler
|
|
65
|
+
logout: MoleculeRequestHandler
|
|
66
|
+
read: MoleculeRequestHandler
|
|
67
|
+
readSelf: MoleculeRequestHandler
|
|
68
|
+
update: MoleculeRequestHandler
|
|
69
|
+
del: MoleculeRequestHandler
|
|
70
|
+
updatePassword: MoleculeRequestHandler
|
|
71
|
+
forgotPassword: MoleculeRequestHandler
|
|
72
|
+
resetPassword: MoleculeRequestHandler
|
|
73
|
+
verifyTwoFactor: MoleculeRequestHandler
|
|
74
|
+
updatePlan: MoleculeRequestHandler
|
|
75
|
+
verifyPayment: MoleculeRequestHandler
|
|
76
|
+
handlePaymentNotification: MoleculeRequestHandler
|
|
77
|
+
requireWebhookAuthenticity: MoleculeRequestHandler
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Types
|
|
82
|
+
|
|
83
|
+
#### `CreateOAuthProps`
|
|
84
|
+
|
|
85
|
+
Create O Auth Props type.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
type CreateOAuthProps = z.infer<typeof createOAuthPropsSchema>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### `CreateProps`
|
|
92
|
+
|
|
93
|
+
Create Props type.
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
type CreateProps = z.infer<typeof createPropsSchema>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### `CreateSecretProps`
|
|
100
|
+
|
|
101
|
+
Create Secret Props type.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
type CreateSecretProps = z.infer<typeof createSecretPropsSchema>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### `Props`
|
|
108
|
+
|
|
109
|
+
User props type inferred from schema.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
type Props = z.infer<typeof propsSchema>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### `SecretProps`
|
|
116
|
+
|
|
117
|
+
Secret Props type.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
type SecretProps = z.infer<typeof secretPropsSchema>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### `Session`
|
|
124
|
+
|
|
125
|
+
User session data (userId, email, role, permissions, metadata) inferred from sessionSchema.
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
type Session = z.infer<typeof sessionSchema>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
#### `UpdatePasswordSecretProps`
|
|
132
|
+
|
|
133
|
+
Update Password Secret Props type.
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
type UpdatePasswordSecretProps = z.infer<typeof updatePasswordSecretPropsSchema>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### `UpdatePlanProps`
|
|
140
|
+
|
|
141
|
+
Update Plan Props type.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
type UpdatePlanProps = z.infer<typeof updatePlanPropsSchema>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### `UpdateProps`
|
|
148
|
+
|
|
149
|
+
Update Props type.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
type UpdateProps = z.infer<typeof updatePropsSchema>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### `VerifyTwoFactorProps`
|
|
156
|
+
|
|
157
|
+
Verify Two Factor Props type.
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
type VerifyTwoFactorProps = z.infer<typeof verifyTwoFactorPropsSchema>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
#### `VerifyTwoFactorSecretProps`
|
|
164
|
+
|
|
165
|
+
Verify Two Factor Secret Props type.
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
type VerifyTwoFactorSecretProps = z.infer<typeof verifyTwoFactorSecretPropsSchema>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Functions
|
|
172
|
+
|
|
173
|
+
#### `createRequestHandlerMap(createRequestHandler)`
|
|
174
|
+
|
|
175
|
+
Creates the full request handler map for the User resource.
|
|
176
|
+
Optional features (OAuth, payments) are conditionally included
|
|
177
|
+
based on bonded providers.
|
|
178
|
+
|
|
179
|
+
Handler names match the route definitions in routes.ts.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
function createRequestHandlerMap(
|
|
183
|
+
createRequestHandler: (
|
|
184
|
+
handler: Handler,
|
|
185
|
+
) => (req: MoleculeRequest, res: MoleculeResponse, next: MoleculeNextFunction) => Promise<void>,
|
|
186
|
+
): UserRequestHandlerMap
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
- `createRequestHandler` — Factory from `@molecule/api-resource` that wraps handler configs into Express middleware.
|
|
190
|
+
|
|
191
|
+
**Returns:** A `UserRequestHandlerMap` of handler names to Express middleware.
|
|
192
|
+
|
|
193
|
+
#### `createResource(options)`
|
|
194
|
+
|
|
195
|
+
Creates a user resource definition with optional OAuth servers and plan keys.
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
function createResource(options?: {
|
|
199
|
+
oauthServers?: OAuthServers
|
|
200
|
+
planKeys?: PlanKeys
|
|
201
|
+
}): types.Resource<unknown>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
- `options` — Optional configuration.
|
|
205
|
+
- `options.oauthServers` — Tuple of allowed OAuth server names (e.g. `['google', 'github']`). Constrains the `oauthServer` schema field.
|
|
206
|
+
- `options.planKeys` — Tuple of allowed plan key strings (e.g. `['free', 'pro']`). Constrains the `planKey` schema field.
|
|
207
|
+
|
|
208
|
+
**Returns:** A `Resource` with name `'User'`, table `'users'`, and a Zod schema reflecting the options.
|
|
209
|
+
|
|
210
|
+
#### `createSchema(options)`
|
|
211
|
+
|
|
212
|
+
Creates a full schema for user props.
|
|
213
|
+
|
|
214
|
+
OAuth servers and plan keys can be constrained by passing them as options.
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
function createSchema(options?: { oauthServers?: OAuthServers; planKeys?: PlanKeys }): z.ZodObject<
|
|
218
|
+
{
|
|
219
|
+
id: z.ZodString
|
|
220
|
+
createdAt: z.ZodString
|
|
221
|
+
updatedAt: z.ZodString
|
|
222
|
+
username: z.ZodOptional<z.ZodString>
|
|
223
|
+
name: z.ZodOptional<z.ZodString>
|
|
224
|
+
email: z.ZodOptional<z.ZodNullable<z.ZodString>>
|
|
225
|
+
emailVerified: z.ZodOptional<z.ZodBoolean>
|
|
226
|
+
avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>
|
|
227
|
+
bio: z.ZodOptional<z.ZodNullable<z.ZodString>>
|
|
228
|
+
twoFactorEnabled: z.ZodOptional<z.ZodBoolean>
|
|
229
|
+
oauthServer:
|
|
230
|
+
| z.ZodOptional<z.ZodString>
|
|
231
|
+
| z.ZodOptional<
|
|
232
|
+
z.ZodEnum<{
|
|
233
|
+
[k in keyof { [k in NonNullable<OAuthServers>[number]]: k }]: {
|
|
234
|
+
[k in NonNullable<OAuthServers>[number]]: k
|
|
235
|
+
}[k]
|
|
236
|
+
}>
|
|
237
|
+
>
|
|
238
|
+
oauthId: z.ZodOptional<z.ZodString>
|
|
239
|
+
oauthData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>
|
|
240
|
+
planKey:
|
|
241
|
+
| z.ZodOptional<z.ZodString>
|
|
242
|
+
| z.ZodOptional<
|
|
243
|
+
z.ZodEnum<{
|
|
244
|
+
[k in keyof { [k in NonNullable<PlanKeys>[number]]: k }]: {
|
|
245
|
+
[k in NonNullable<PlanKeys>[number]]: k
|
|
246
|
+
}[k]
|
|
247
|
+
}>
|
|
248
|
+
>
|
|
249
|
+
planExpiresAt: z.ZodOptional<z.ZodString>
|
|
250
|
+
planAutoRenews: z.ZodOptional<z.ZodBoolean>
|
|
251
|
+
},
|
|
252
|
+
z.core.$strip
|
|
253
|
+
>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
- `options` — Optional configuration.
|
|
257
|
+
- `options.oauthServers` — Tuple of allowed OAuth server names. Constrains `oauthServer` to a Zod enum.
|
|
258
|
+
- `options.planKeys` — Tuple of allowed plan key strings. Constrains `planKey` to a Zod enum.
|
|
259
|
+
|
|
260
|
+
**Returns:** A Zod object schema extending `basePropsSchema` with user-specific fields (username, email, OAuth, plan).
|
|
261
|
+
|
|
262
|
+
### Constants
|
|
263
|
+
|
|
264
|
+
#### `createOAuthPropsSchema`
|
|
265
|
+
|
|
266
|
+
Schema for creating a user via OAuth.
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
const createOAuthPropsSchema: z.ZodObject<
|
|
270
|
+
{
|
|
271
|
+
username: z.ZodOptional<z.ZodString>
|
|
272
|
+
name: z.ZodOptional<z.ZodString>
|
|
273
|
+
email: z.ZodOptional<z.ZodNullable<z.ZodString>>
|
|
274
|
+
emailVerified: z.ZodOptional<z.ZodBoolean>
|
|
275
|
+
avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>
|
|
276
|
+
bio: z.ZodOptional<z.ZodNullable<z.ZodString>>
|
|
277
|
+
oauthServer: z.ZodOptional<z.ZodString> | z.ZodOptional<z.ZodEnum<{}>>
|
|
278
|
+
oauthId: z.ZodOptional<z.ZodString>
|
|
279
|
+
oauthData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>
|
|
280
|
+
},
|
|
281
|
+
z.core.$strip
|
|
282
|
+
>
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### `createPropsSchema`
|
|
286
|
+
|
|
287
|
+
Schema for creating a user via password.
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
const createPropsSchema: z.ZodObject<
|
|
291
|
+
{
|
|
292
|
+
username: z.ZodOptional<z.ZodString>
|
|
293
|
+
name: z.ZodOptional<z.ZodString>
|
|
294
|
+
email: z.ZodOptional<z.ZodNullable<z.ZodString>>
|
|
295
|
+
},
|
|
296
|
+
z.core.$strip
|
|
297
|
+
>
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
#### `createSecretPropsSchema`
|
|
301
|
+
|
|
302
|
+
Schema for creating secret props (password hash only).
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
const createSecretPropsSchema: z.ZodObject<
|
|
306
|
+
{ passwordHash: z.ZodOptional<z.ZodString> },
|
|
307
|
+
z.core.$strip
|
|
308
|
+
>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
#### `i18nRegistered`
|
|
312
|
+
|
|
313
|
+
The i18n registered.
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
const i18nRegistered: true
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### `MAX_AVATAR_LENGTH`
|
|
320
|
+
|
|
321
|
+
Maximum length (in characters) of a user's `avatar`. Sized to permit a small
|
|
322
|
+
inline data-URI (~256KB) without requiring an external upload/storage bond.
|
|
323
|
+
Larger avatars must be hosted elsewhere and referenced by URL.
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
const MAX_AVATAR_LENGTH: number
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
#### `MAX_BIO_LENGTH`
|
|
330
|
+
|
|
331
|
+
Maximum length (in characters) of a user's `bio`.
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
const MAX_BIO_LENGTH: 1000
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
#### `propsSchema`
|
|
338
|
+
|
|
339
|
+
Default schema for user props.
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
const propsSchema: z.ZodObject<
|
|
343
|
+
{
|
|
344
|
+
id: z.ZodString
|
|
345
|
+
createdAt: z.ZodString
|
|
346
|
+
updatedAt: z.ZodString
|
|
347
|
+
username: z.ZodOptional<z.ZodString>
|
|
348
|
+
name: z.ZodOptional<z.ZodString>
|
|
349
|
+
email: z.ZodOptional<z.ZodNullable<z.ZodString>>
|
|
350
|
+
emailVerified: z.ZodOptional<z.ZodBoolean>
|
|
351
|
+
avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>
|
|
352
|
+
bio: z.ZodOptional<z.ZodNullable<z.ZodString>>
|
|
353
|
+
twoFactorEnabled: z.ZodOptional<z.ZodBoolean>
|
|
354
|
+
oauthServer: z.ZodOptional<z.ZodString> | z.ZodOptional<z.ZodEnum<{}>>
|
|
355
|
+
oauthId: z.ZodOptional<z.ZodString>
|
|
356
|
+
oauthData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>
|
|
357
|
+
planKey: z.ZodOptional<z.ZodString> | z.ZodOptional<z.ZodEnum<{}>>
|
|
358
|
+
planExpiresAt: z.ZodOptional<z.ZodString>
|
|
359
|
+
planAutoRenews: z.ZodOptional<z.ZodBoolean>
|
|
360
|
+
},
|
|
361
|
+
z.core.$strip
|
|
362
|
+
>
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
#### `resource`
|
|
366
|
+
|
|
367
|
+
Default user resource definition.
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
const resource: types.Resource<unknown>
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### `resourceUserSecretDefinitions`
|
|
374
|
+
|
|
375
|
+
Secret definitions required by the user resource.
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
const resourceUserSecretDefinitions: SecretDefinition[]
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
#### `routes`
|
|
382
|
+
|
|
383
|
+
Route definitions for the User resource.
|
|
384
|
+
Routes marked optional require additional packages to be installed.
|
|
385
|
+
|
|
386
|
+
Declarative route definitions used by the injection engine.
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
const routes: (
|
|
390
|
+
| { method: 'post'; path: string; middlewares: string[]; handler: string; optional?: undefined }
|
|
391
|
+
| { method: 'get'; path: string; middlewares: string[]; handler: string; optional: string }
|
|
392
|
+
| { method: 'post'; path: string; middlewares: string[]; handler: string; optional: string }
|
|
393
|
+
| { method: 'get'; path: string; middlewares: string[]; handler: string; optional?: undefined }
|
|
394
|
+
| { method: 'patch'; path: string; middlewares: string[]; handler: string; optional?: undefined }
|
|
395
|
+
| { method: 'delete'; path: string; middlewares: string[]; handler: string; optional?: undefined }
|
|
396
|
+
)[]
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
#### `secretPropsSchema`
|
|
400
|
+
|
|
401
|
+
Secret properties stored in a separate table.
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
const secretPropsSchema: z.ZodObject<
|
|
405
|
+
{
|
|
406
|
+
id: z.ZodString
|
|
407
|
+
passwordHash: z.ZodOptional<z.ZodString>
|
|
408
|
+
passwordResetToken: z.ZodOptional<z.ZodString>
|
|
409
|
+
passwordResetTokenAt: z.ZodOptional<z.ZodString>
|
|
410
|
+
pendingTwoFactorSecret: z.ZodOptional<z.ZodString>
|
|
411
|
+
twoFactorSecret: z.ZodOptional<z.ZodString>
|
|
412
|
+
lastTwoFactorTimeStep: z.ZodOptional<z.ZodNumber>
|
|
413
|
+
},
|
|
414
|
+
z.core.$strip
|
|
415
|
+
>
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
#### `sessionSchema`
|
|
419
|
+
|
|
420
|
+
Zod schema for JWT session payloads (userId, deviceId, optional OAuth fields).
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
const sessionSchema: z.ZodObject<
|
|
424
|
+
{
|
|
425
|
+
id: z.ZodOptional<z.ZodString>
|
|
426
|
+
userId: z.ZodString
|
|
427
|
+
deviceId: z.ZodString
|
|
428
|
+
oauthServer: z.ZodOptional<z.ZodString>
|
|
429
|
+
oauthId: z.ZodOptional<z.ZodString>
|
|
430
|
+
},
|
|
431
|
+
z.core.$strip
|
|
432
|
+
>
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
#### `updatePasswordSecretPropsSchema`
|
|
436
|
+
|
|
437
|
+
Schema for updating password secret props (partial password hash).
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
const updatePasswordSecretPropsSchema: z.ZodObject<
|
|
441
|
+
{ passwordHash: z.ZodOptional<z.ZodOptional<z.ZodString>> },
|
|
442
|
+
z.core.$strip
|
|
443
|
+
>
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
#### `updatePlanPropsSchema`
|
|
447
|
+
|
|
448
|
+
Schema for updating a user's plan (partial planKey, planExpiresAt, planAutoRenews).
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
const updatePlanPropsSchema: z.ZodObject<
|
|
452
|
+
{
|
|
453
|
+
planKey: z.ZodOptional<z.ZodOptional<z.ZodString> | z.ZodOptional<z.ZodEnum<{}>>>
|
|
454
|
+
planExpiresAt: z.ZodOptional<z.ZodOptional<z.ZodString>>
|
|
455
|
+
planAutoRenews: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>
|
|
456
|
+
},
|
|
457
|
+
z.core.$strip
|
|
458
|
+
>
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
#### `updatePropsSchema`
|
|
462
|
+
|
|
463
|
+
Schema for updating a user (partial username, name, email, avatar, bio).
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
const updatePropsSchema: z.ZodObject<
|
|
467
|
+
{
|
|
468
|
+
username: z.ZodOptional<z.ZodOptional<z.ZodString>>
|
|
469
|
+
name: z.ZodOptional<z.ZodOptional<z.ZodString>>
|
|
470
|
+
email: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>
|
|
471
|
+
avatar: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>
|
|
472
|
+
bio: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>
|
|
473
|
+
},
|
|
474
|
+
z.core.$strip
|
|
475
|
+
>
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
#### `verifyTwoFactorPropsSchema`
|
|
479
|
+
|
|
480
|
+
Schema for verifying two-factor authentication.
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
const verifyTwoFactorPropsSchema: z.ZodObject<
|
|
484
|
+
{ twoFactorEnabled: z.ZodOptional<z.ZodOptional<z.ZodBoolean>> },
|
|
485
|
+
z.core.$strip
|
|
486
|
+
>
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
#### `verifyTwoFactorSecretPropsSchema`
|
|
490
|
+
|
|
491
|
+
Schema for two-factor secret props.
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
const verifyTwoFactorSecretPropsSchema: z.ZodObject<
|
|
495
|
+
{
|
|
496
|
+
pendingTwoFactorSecret: z.ZodOptional<z.ZodOptional<z.ZodString>>
|
|
497
|
+
twoFactorSecret: z.ZodOptional<z.ZodOptional<z.ZodString>>
|
|
498
|
+
},
|
|
499
|
+
z.core.$strip
|
|
500
|
+
>
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### Namespaces
|
|
504
|
+
|
|
505
|
+
#### `authorization`
|
|
506
|
+
|
|
507
|
+
Members:
|
|
508
|
+
|
|
509
|
+
- `authorization.getAuthCookieName` — function: Resolve the actual cookie name for an auth cookie.
|
|
510
|
+
- `authorization.getAuthCookieOptions` — function: Base cookie attributes shared by EVERY auth cookie this resource sets and
|
|
511
|
+
- `authorization.invalidateDeviceExistsCache` — function: Evict a single device's positive entry from the device-exists cache so the
|
|
512
|
+
- `authorization.invalidateAllDeviceExistsCache` — function: Evict ALL positive entries from the device-exists cache.
|
|
513
|
+
- `authorization.set` — function: Set authorization headers and cookie for a session.
|
|
514
|
+
- `authorization.verifyMiddleware` — function: Middleware that verifies the JWT token from the `Authorization` header and sets `res.locals.session`.
|
|
515
|
+
|
|
516
|
+
#### `authorizers`
|
|
517
|
+
|
|
518
|
+
Members:
|
|
519
|
+
|
|
520
|
+
- `authorizers.auth` — function: Middleware that checks if the request has an authenticated session (`res.locals.session.userId`).
|
|
521
|
+
- `authorizers.authSelf` — function: Middleware that checks if the authenticated user's ID matches the `:id` route parameter.
|
|
522
|
+
- `authorizers.RateLimitAuthOptions` — interface: Configuration for {@link rateLimit}.
|
|
523
|
+
- `authorizers.rateLimit` — function: Creates an authorizer middleware that brute-force-protects an auth endpoint.
|
|
524
|
+
- `authorizers.loginAccountKey` — function: Account-identifier extractor for the login endpoint: the submitted username
|
|
525
|
+
- `authorizers.emailAccountKey` — function: Account-identifier extractor for the forgot-password endpoint: the submitted
|
|
526
|
+
- `authorizers.paramIdAccountKey` — function: Account-identifier extractor for the verify-two-factor endpoint: the target
|
|
527
|
+
- `authorizers.requireWebhookAuthenticity` — function: Middleware guarding the public `POST /users/payment-notification/:provider`
|
|
528
|
+
|
|
529
|
+
#### `handlers`
|
|
530
|
+
|
|
531
|
+
Members:
|
|
532
|
+
|
|
533
|
+
- `handlers.handlePaymentNotification` — function: Generic payment notification handler that works with any bonded PaymentProvider. Reads the
|
|
534
|
+
- `handlers.verifyPayment` — function: Generic payment verification handler that works with any bonded PaymentProvider. Reads the
|
|
535
|
+
- `handlers.CreateRequest` — interface: Request body for user creation, including password and optional device name.
|
|
536
|
+
- `handlers.create` — function: Creates a user with username and password. Validates username uniqueness and email format,
|
|
537
|
+
- `handlers.del` — function: Deletes a user and their associated data. Removes secrets from the secrets table,
|
|
538
|
+
- `handlers.ForgotPasswordRequest` — interface: Request body for password reset initiation.
|
|
539
|
+
- `handlers.forgotPassword` — function: Generates a UUID password reset token, stores it in the secrets table, and sends a reset
|
|
540
|
+
- `handlers.LogInRequest` — interface: Request body for user login, supporting password, reset token, and 2FA flows.
|
|
541
|
+
- `handlers.logIn` — function: Logs in a user by username or email. Supports password authentication, password reset token
|
|
542
|
+
- `handlers.LogInOAuthRequest` — interface: Request body for OAuth login, including the OAuth server name, authorization code, and PKCE verifier.
|
|
543
|
+
- `handlers.logInOAuth` — function: Logs in or creates a user via OAuth. Verifies the authorization code with the bonded OAuth
|
|
544
|
+
- `handlers.logout` — function: Logs the current user out. Revokes the session device server-side (so the JWT
|
|
545
|
+
- `handlers.oauthAuthorize` — function: OAuth initiation — `GET /users/oauth/:provider`.
|
|
546
|
+
- `handlers.read` — function: Reads a user by ID from the database. Attaches plan info (with expiration/renewal status) via the
|
|
547
|
+
- `handlers.readSelf` — function: Reads the AUTHENTICATED user from the session — no `:id` param. Backs
|
|
548
|
+
- `handlers.ResetPasswordRequest` — interface: Request body for confirming a password reset using a token.
|
|
549
|
+
- `handlers.resetPassword` — function: Confirms a password reset by validating the one-time token previously generated by
|
|
550
|
+
- `handlers.update` — function: Updates a user's profile fields (username, name, email). Validates username format
|
|
551
|
+
- `handlers.UpdatePasswordRequest` — interface: Request body for password update, with current password verification and new password.
|
|
552
|
+
- `handlers.updatePassword` — function: Updates a user's password. If the user already has a password hash, the current password
|
|
553
|
+
- `handlers.UpdatePlanRequest` — interface: Request body for plan update, containing the target plan key.
|
|
554
|
+
- `handlers.updatePlan` — function: Updates a user's subscription plan. Uses the bonded PlanService to look up plan metadata and
|
|
555
|
+
- `handlers.VerifyTwoFactorRequest` — interface: Request body for two-factor authentication operations (setup, enable, or disable).
|
|
556
|
+
- `handlers.verifyTwoFactor` — function: Handles two-factor authentication lifecycle via `@molecule/api-two-factor`:
|
|
557
|
+
|
|
558
|
+
#### `types`
|
|
559
|
+
|
|
560
|
+
Members:
|
|
561
|
+
|
|
562
|
+
- `types.CreateOAuthProps` — type: Create O Auth Props type.
|
|
563
|
+
- `types.CreateProps` — type: Create Props type.
|
|
564
|
+
- `types.CreateSecretProps` — type: Create Secret Props type.
|
|
565
|
+
- `types.Props` — type: User props type inferred from schema.
|
|
566
|
+
- `types.SecretProps` — type: Secret Props type.
|
|
567
|
+
- `types.Session` — type: User session data (userId, email, role, permissions, metadata) inferred from sessionSchema.
|
|
568
|
+
- `types.UpdatePasswordSecretProps` — type: Update Password Secret Props type.
|
|
569
|
+
- `types.UpdatePlanProps` — type: Update Plan Props type.
|
|
570
|
+
- `types.UpdateProps` — type: Update Props type.
|
|
571
|
+
- `types.VerifyTwoFactorProps` — type: Verify Two Factor Props type.
|
|
572
|
+
- `types.VerifyTwoFactorSecretProps` — type: Verify Two Factor Secret Props type.
|
|
573
|
+
- `types.Resource` — type: An object describing the `user` resource.
|
|
574
|
+
|
|
575
|
+
#### `utilities`
|
|
576
|
+
|
|
577
|
+
Members:
|
|
578
|
+
|
|
579
|
+
- `utilities.fetchAvatarDataUri` — function: Downloads an OAuth provider's profile image and re-hosts it as an inline
|
|
580
|
+
- `utilities.getPlan` — function: Get a user's current plan info.
|
|
581
|
+
- `utilities.invalidateEntitlementsCache` — function: Invalidates the entitlements plan-key cache for a user after their plan
|
|
582
|
+
- `utilities.invalidateEntitlementsCacheSafe` — function: Fire-and-forget variant of {@link invalidateEntitlementsCache} for call
|
|
583
|
+
- `utilities.normalizeEmail` — function: Normalizes an email address for storage and lookup so case/whitespace
|
|
584
|
+
- `utilities.notify` — function: Sends push notifications to all of a user's devices except the current one. Retrieves devices
|
|
585
|
+
|
|
586
|
+
#### `z`
|
|
587
|
+
|
|
588
|
+
Members:
|
|
589
|
+
|
|
590
|
+
- `z.core` — namespace
|
|
591
|
+
- `z.infer` — type
|
|
592
|
+
- `z.output` — type
|
|
593
|
+
- `z.input` — type
|
|
594
|
+
- `z.JSONType` — type
|
|
595
|
+
- `z.globalRegistry` — const
|
|
596
|
+
- `z.GlobalMeta` — interface
|
|
597
|
+
- `z.registry` — function
|
|
598
|
+
- `z.config` — function
|
|
599
|
+
- `z.$output` — const
|
|
600
|
+
- `z.$input` — const
|
|
601
|
+
- `z.$brand` — const
|
|
602
|
+
- `z.clone` — function
|
|
603
|
+
- `z.regexes` — namespace
|
|
604
|
+
- `z.treeifyError` — function
|
|
605
|
+
- `z.prettifyError` — function
|
|
606
|
+
- `z.formatError` — function
|
|
607
|
+
- `z.flattenError` — function
|
|
608
|
+
- `z.TimePrecision` — const
|
|
609
|
+
- `z.util` — namespace
|
|
610
|
+
- `z.NEVER` — const: A special constant with type `never`
|
|
611
|
+
- `z.toJSONSchema` — function
|
|
612
|
+
- `z.fromJSONSchema` — function: Converts a JSON Schema to a Zod schema. This function should be considered semi-experimental. It's behavior is liable to change.
|
|
613
|
+
- `z.locales` — namespace
|
|
614
|
+
- `z.ZodISODateTime` — interface
|
|
615
|
+
- `z.ZodISODate` — interface
|
|
616
|
+
- `z.ZodISOTime` — interface
|
|
617
|
+
- `z.ZodISODuration` — interface
|
|
618
|
+
- `z.iso` — namespace
|
|
619
|
+
- `z.ZodCoercedString` — interface
|
|
620
|
+
- `z.ZodCoercedNumber` — interface
|
|
621
|
+
- `z.ZodCoercedBigInt` — interface
|
|
622
|
+
- `z.ZodCoercedBoolean` — interface
|
|
623
|
+
- `z.ZodCoercedDate` — interface
|
|
624
|
+
- `z.coerce` — namespace
|
|
625
|
+
- `z.string` — function
|
|
626
|
+
- `z.email` — function
|
|
627
|
+
- `z.guid` — function
|
|
628
|
+
- `z.uuid` — function
|
|
629
|
+
- `z.uuidv4` — function
|
|
630
|
+
- `z.uuidv6` — function
|
|
631
|
+
- `z.uuidv7` — function
|
|
632
|
+
- `z.url` — function
|
|
633
|
+
- `z.httpUrl` — function
|
|
634
|
+
- `z.emoji` — function
|
|
635
|
+
- `z.nanoid` — function
|
|
636
|
+
- `z.cuid` — function: Validates a CUID v1 string.
|
|
637
|
+
- `z.cuid2` — function
|
|
638
|
+
- `z.ulid` — function
|
|
639
|
+
- `z.xid` — function
|
|
640
|
+
- `z.ksuid` — function
|
|
641
|
+
- `z.ipv4` — function
|
|
642
|
+
- `z.mac` — function
|
|
643
|
+
- `z.ipv6` — function
|
|
644
|
+
- `z.cidrv4` — function
|
|
645
|
+
- `z.cidrv6` — function
|
|
646
|
+
- `z.base64` — function
|
|
647
|
+
- `z.base64url` — function
|
|
648
|
+
- `z.e164` — function
|
|
649
|
+
- `z.jwt` — function
|
|
650
|
+
- `z.stringFormat` — function
|
|
651
|
+
- `z.hostname` — function
|
|
652
|
+
- `z.hex` — function
|
|
653
|
+
- `z.hash` — function
|
|
654
|
+
- `z.number` — function
|
|
655
|
+
- `z.int` — function
|
|
656
|
+
- `z.float32` — function
|
|
657
|
+
- `z.float64` — function
|
|
658
|
+
- `z.int32` — function
|
|
659
|
+
- `z.uint32` — function
|
|
660
|
+
- `z.boolean` — function
|
|
661
|
+
- `z.bigint` — function
|
|
662
|
+
- `z.int64` — function
|
|
663
|
+
- `z.uint64` — function
|
|
664
|
+
- `z.symbol` — function
|
|
665
|
+
- `z.any` — function
|
|
666
|
+
- `z.unknown` — function
|
|
667
|
+
- `z.never` — function
|
|
668
|
+
- `z.date` — function
|
|
669
|
+
- `z.array` — function
|
|
670
|
+
- `z.keyof` — function
|
|
671
|
+
- `z.object` — function
|
|
672
|
+
- `z.strictObject` — function
|
|
673
|
+
- `z.looseObject` — function
|
|
674
|
+
- `z.union` — function
|
|
675
|
+
- `z.xor` — function: Creates an exclusive union (XOR) where exactly one option must match.
|
|
676
|
+
- `z.discriminatedUnion` — function
|
|
677
|
+
- `z.intersection` — function
|
|
678
|
+
- `z.tuple` — function
|
|
679
|
+
- `z.record` — function
|
|
680
|
+
- `z.partialRecord` — function
|
|
681
|
+
- `z.looseRecord` — function
|
|
682
|
+
- `z.map` — function
|
|
683
|
+
- `z.set` — function
|
|
684
|
+
- `z.nativeEnum` — function
|
|
685
|
+
- `z.literal` — function
|
|
686
|
+
- `z.file` — function
|
|
687
|
+
- `z.transform` — function
|
|
688
|
+
- `z.optional` — function
|
|
689
|
+
- `z.exactOptional` — function
|
|
690
|
+
- `z.nullable` — function
|
|
691
|
+
- `z.nullish` — function
|
|
692
|
+
- `z._default` — function
|
|
693
|
+
- `z.prefault` — function
|
|
694
|
+
- `z.nonoptional` — function
|
|
695
|
+
- `z.success` — function
|
|
696
|
+
- `z.nan` — function
|
|
697
|
+
- `z.pipe` — function
|
|
698
|
+
- `z.codec` — function
|
|
699
|
+
- `z.invertCodec` — function
|
|
700
|
+
- `z.readonly` — function
|
|
701
|
+
- `z.templateLiteral` — function
|
|
702
|
+
- `z.lazy` — function
|
|
703
|
+
- `z.promise` — function
|
|
704
|
+
- `z._function` — function
|
|
705
|
+
- `z.check` — function
|
|
706
|
+
- `z.custom` — function
|
|
707
|
+
- `z.refine` — function
|
|
708
|
+
- `z.superRefine` — function
|
|
709
|
+
- `z.json` — function
|
|
710
|
+
- `z.preprocess` — function
|
|
711
|
+
- `z.ZodStandardSchemaWithJSON` — type
|
|
712
|
+
- `z.ZodType` — interface
|
|
713
|
+
- `z._ZodType` — interface
|
|
714
|
+
- `z._ZodString` — interface
|
|
715
|
+
- `z.ZodString` — interface
|
|
716
|
+
- `z.ZodStringFormat` — interface
|
|
717
|
+
- `z.ZodEmail` — interface
|
|
718
|
+
- `z.ZodGUID` — interface
|
|
719
|
+
- `z.ZodUUID` — interface
|
|
720
|
+
- `z.ZodURL` — interface
|
|
721
|
+
- `z.ZodEmoji` — interface
|
|
722
|
+
- `z.ZodNanoID` — interface
|
|
723
|
+
- `z.ZodCUID` — interface
|
|
724
|
+
- `z.ZodCUID2` — interface
|
|
725
|
+
- `z.ZodULID` — interface
|
|
726
|
+
- `z.ZodXID` — interface
|
|
727
|
+
- `z.ZodKSUID` — interface
|
|
728
|
+
- `z.ZodIPv4` — interface
|
|
729
|
+
- `z.ZodMAC` — interface
|
|
730
|
+
- `z.ZodIPv6` — interface
|
|
731
|
+
- `z.ZodCIDRv4` — interface
|
|
732
|
+
- `z.ZodCIDRv6` — interface
|
|
733
|
+
- `z.ZodBase64` — interface
|
|
734
|
+
- `z.ZodBase64URL` — interface
|
|
735
|
+
- `z.ZodE164` — interface
|
|
736
|
+
- `z.ZodJWT` — interface
|
|
737
|
+
- `z.ZodCustomStringFormat` — interface
|
|
738
|
+
- `z._ZodNumber` — interface
|
|
739
|
+
- `z.ZodNumber` — interface
|
|
740
|
+
- `z.ZodNumberFormat` — interface
|
|
741
|
+
- `z.ZodInt` — interface
|
|
742
|
+
- `z.ZodFloat32` — interface
|
|
743
|
+
- `z.ZodFloat64` — interface
|
|
744
|
+
- `z.ZodInt32` — interface
|
|
745
|
+
- `z.ZodUInt32` — interface
|
|
746
|
+
- `z._ZodBoolean` — interface
|
|
747
|
+
- `z.ZodBoolean` — interface
|
|
748
|
+
- `z._ZodBigInt` — interface
|
|
749
|
+
- `z.ZodBigInt` — interface
|
|
750
|
+
- `z.ZodBigIntFormat` — interface
|
|
751
|
+
- `z.ZodSymbol` — interface
|
|
752
|
+
- `z.ZodUndefined` — interface
|
|
753
|
+
- `z.undefined` — function
|
|
754
|
+
- `z.ZodNull` — interface
|
|
755
|
+
- `z.null` — function
|
|
756
|
+
- `z.ZodAny` — interface
|
|
757
|
+
- `z.ZodUnknown` — interface
|
|
758
|
+
- `z.ZodNever` — interface
|
|
759
|
+
- `z.ZodVoid` — interface
|
|
760
|
+
- `z.void` — function
|
|
761
|
+
- `z._ZodDate` — interface
|
|
762
|
+
- `z.ZodDate` — interface
|
|
763
|
+
- `z.ZodArray` — interface
|
|
764
|
+
- `z.SafeExtendShape` — type
|
|
765
|
+
- `z.ZodObject` — interface
|
|
766
|
+
- `z.ZodUnion` — interface
|
|
767
|
+
- `z.ZodXor` — interface
|
|
768
|
+
- `z.ZodDiscriminatedUnion` — interface
|
|
769
|
+
- `z.ZodIntersection` — interface
|
|
770
|
+
- `z.ZodTuple` — interface
|
|
771
|
+
- `z.ZodRecord` — interface
|
|
772
|
+
- `z.ZodMap` — interface
|
|
773
|
+
- `z.ZodSet` — interface
|
|
774
|
+
- `z.ZodEnum` — interface
|
|
775
|
+
- `z.enum` — function
|
|
776
|
+
- `z.ZodLiteral` — interface
|
|
777
|
+
- `z.ZodFile` — interface
|
|
778
|
+
- `z.ZodTransform` — interface
|
|
779
|
+
- `z.ZodOptional` — interface
|
|
780
|
+
- `z.ZodExactOptional` — interface
|
|
781
|
+
- `z.ZodNullable` — interface
|
|
782
|
+
- `z.ZodDefault` — interface
|
|
783
|
+
- `z.ZodPrefault` — interface
|
|
784
|
+
- `z.ZodNonOptional` — interface
|
|
785
|
+
- `z.ZodSuccess` — interface
|
|
786
|
+
- `z.ZodCatch` — interface
|
|
787
|
+
- `z.catch` — function
|
|
788
|
+
- `z.ZodNaN` — interface
|
|
789
|
+
- `z.ZodPipe` — interface
|
|
790
|
+
- `z.ZodCodec` — interface
|
|
791
|
+
- `z.ZodPreprocess` — interface
|
|
792
|
+
- `z.ZodReadonly` — interface
|
|
793
|
+
- `z.ZodTemplateLiteral` — interface
|
|
794
|
+
- `z.ZodLazy` — interface
|
|
795
|
+
- `z.ZodPromise` — interface
|
|
796
|
+
- `z.ZodFunction` — interface
|
|
797
|
+
- `z.function` — function
|
|
798
|
+
- `z.ZodCustom` — interface
|
|
799
|
+
- `z.describe` — const
|
|
800
|
+
- `z.meta` — const
|
|
801
|
+
- `z.instanceof` — function
|
|
802
|
+
- `z.stringbool` — const
|
|
803
|
+
- `z.ZodJSONSchemaInternals` — interface
|
|
804
|
+
- `z.ZodJSONSchema` — interface
|
|
805
|
+
- `z.lt` — function
|
|
806
|
+
- `z.lte` — function
|
|
807
|
+
- `z.gt` — function
|
|
808
|
+
- `z.gte` — function
|
|
809
|
+
- `z.positive` — function
|
|
810
|
+
- `z.negative` — function
|
|
811
|
+
- `z.nonpositive` — function
|
|
812
|
+
- `z.nonnegative` — function
|
|
813
|
+
- `z.multipleOf` — function
|
|
814
|
+
- `z.maxSize` — function
|
|
815
|
+
- `z.minSize` — function
|
|
816
|
+
- `z.size` — function
|
|
817
|
+
- `z.maxLength` — function
|
|
818
|
+
- `z.minLength` — function
|
|
819
|
+
- `z.length` — function
|
|
820
|
+
- `z.regex` — function
|
|
821
|
+
- `z.lowercase` — function
|
|
822
|
+
- `z.uppercase` — function
|
|
823
|
+
- `z.includes` — function
|
|
824
|
+
- `z.startsWith` — function
|
|
825
|
+
- `z.endsWith` — function
|
|
826
|
+
- `z.property` — function
|
|
827
|
+
- `z.mime` — function
|
|
828
|
+
- `z.overwrite` — function
|
|
829
|
+
- `z.normalize` — function
|
|
830
|
+
- `z.trim` — function
|
|
831
|
+
- `z.toLowerCase` — function
|
|
832
|
+
- `z.toUpperCase` — function
|
|
833
|
+
- `z.slugify` — function
|
|
834
|
+
- `z.RefinementCtx` — interface
|
|
835
|
+
- `z.ZodIssue` — type
|
|
836
|
+
- `z.ZodError` — interface: An Error-like class used to store Zod validation issues.
|
|
837
|
+
- `z.ZodRealError` — const
|
|
838
|
+
- `z.ZodFlattenedError` — type
|
|
839
|
+
- `z.ZodFormattedError` — type
|
|
840
|
+
- `z.ZodErrorMap` — interface
|
|
841
|
+
- `z.IssueData` — type
|
|
842
|
+
- `z.ZodSafeParseResult` — type
|
|
843
|
+
- `z.ZodSafeParseSuccess` — type
|
|
844
|
+
- `z.ZodSafeParseError` — type
|
|
845
|
+
- `z.parse` — const
|
|
846
|
+
- `z.parseAsync` — const
|
|
847
|
+
- `z.safeParse` — const
|
|
848
|
+
- `z.safeParseAsync` — const
|
|
849
|
+
- `z.encode` — const
|
|
850
|
+
- `z.decode` — const
|
|
851
|
+
- `z.encodeAsync` — const
|
|
852
|
+
- `z.decodeAsync` — const
|
|
853
|
+
- `z.safeEncode` — const
|
|
854
|
+
- `z.safeDecode` — const
|
|
855
|
+
- `z.safeEncodeAsync` — const
|
|
856
|
+
- `z.safeDecodeAsync` — const
|
|
857
|
+
- `z.setErrorMap` — function
|
|
858
|
+
- `z.getErrorMap` — function
|
|
859
|
+
- `z.TypeOf` — type
|
|
860
|
+
- `z.Infer` — type
|
|
861
|
+
- `z.ZodFirstPartySchemaTypes` — type
|
|
862
|
+
- `z.ZodIssueCode` — const
|
|
863
|
+
- `z.inferFlattenedErrors` — type
|
|
864
|
+
- `z.inferFormattedError` — type
|
|
865
|
+
- `z.BRAND` — type: Use `z.$brand` instead
|
|
866
|
+
- `z.ZodTypeAny` — interface
|
|
867
|
+
- `z.ZodSchema` — interface
|
|
868
|
+
- `z.Schema` — interface
|
|
869
|
+
- `z.ZodRawShape` — type: Included for Zod 3 compatibility
|
|
870
|
+
- `z.ZodFirstPartyTypeKind` — enum
|
|
871
|
+
|
|
872
|
+
## Injection Notes
|
|
873
|
+
|
|
874
|
+
### Requirements
|
|
875
|
+
|
|
876
|
+
Peer dependencies:
|
|
877
|
+
|
|
878
|
+
- `@molecule/api-bond` ^1.0.1
|
|
879
|
+
- `@molecule/api-config` ^1.0.1
|
|
880
|
+
- `@molecule/api-database` ^1.0.1
|
|
881
|
+
- `@molecule/api-entitlements` ^1.0.1
|
|
882
|
+
- `@molecule/api-i18n` ^1.0.1
|
|
883
|
+
- `@molecule/api-jwt` ^1.0.1
|
|
884
|
+
- `@molecule/api-locales-user` ^1.0.1
|
|
885
|
+
- `@molecule/api-locales-user-payments` ^1.0.1
|
|
886
|
+
- `@molecule/api-password` ^1.0.1
|
|
887
|
+
- `@molecule/api-payments` ^1.0.1
|
|
888
|
+
- `@molecule/api-push-notifications` ^1.0.1
|
|
889
|
+
- `@molecule/api-rate-limit` ^1.0.1
|
|
890
|
+
- `@molecule/api-resource` ^1.0.1
|
|
891
|
+
- `@molecule/api-resource-device` ^1.0.1
|
|
892
|
+
- `@molecule/api-secrets` ^1.0.1
|
|
893
|
+
- `@molecule/api-two-factor` ^1.0.1
|
|
894
|
+
|
|
895
|
+
### Environment Variables
|
|
896
|
+
|
|
897
|
+
- `JWT_PRIVATE_KEY` _(required)_ — JWT signing key (RSA private)
|
|
898
|
+
- **Auto-generated at scaffold — no manual setup.**
|
|
899
|
+
- `JWT_PUBLIC_KEY` _(required)_ — JWT verification key (RSA public)
|
|
900
|
+
- **Auto-generated at scaffold — no manual setup.**
|
|
901
|
+
|
|
902
|
+
### Runtime Dependencies
|
|
903
|
+
|
|
904
|
+
- `@molecule/api-bond`
|
|
905
|
+
- `@molecule/api-config`
|
|
906
|
+
- `@molecule/api-database`
|
|
907
|
+
- `@molecule/api-entitlements`
|
|
908
|
+
- `@molecule/api-i18n`
|
|
909
|
+
- `@molecule/api-jwt`
|
|
910
|
+
- `@molecule/api-locales-user`
|
|
911
|
+
- `@molecule/api-locales-user-payments`
|
|
912
|
+
- `@molecule/api-password`
|
|
913
|
+
- `@molecule/api-payments`
|
|
914
|
+
- `@molecule/api-push-notifications`
|
|
915
|
+
- `@molecule/api-rate-limit`
|
|
916
|
+
- `@molecule/api-resource`
|
|
917
|
+
- `@molecule/api-resource-device`
|
|
918
|
+
- `@molecule/api-secrets`
|
|
919
|
+
- `@molecule/api-two-factor`
|
|
920
|
+
- `zod`
|
|
921
|
+
|
|
922
|
+
The user record is split across TWO schemas — pick the right one or you leak credentials:
|
|
923
|
+
|
|
924
|
+
- **{@link Props} (`propsSchema`)** — SAFE, client-facing fields (username, name, email,
|
|
925
|
+
`emailVerified`, `twoFactorEnabled`, plan). This is what handlers return and what lives
|
|
926
|
+
in the `users` table.
|
|
927
|
+
- **{@link SecretProps} (`secretPropsSchema`)** — SERVER-ONLY secrets: `passwordHash`, the
|
|
928
|
+
TOTP `twoFactorSecret` (and its pending-setup value). Stored in a SEPARATE secrets table
|
|
929
|
+
and NEVER serialized to the client. Note the pair `twoFactorEnabled` (safe boolean, in
|
|
930
|
+
`Props`) vs `twoFactorSecret` (secret, in `SecretProps`).
|
|
931
|
+
|
|
932
|
+
When you extend the user, put a secret (token, hash, key, provider refresh token) in
|
|
933
|
+
`SecretProps`; put a display field in `Props`. **Never add a secret to `Props`, never
|
|
934
|
+
return a secrets-table value in a response or log, and never `res.json(userRow)` a raw DB
|
|
935
|
+
row** — return `Props`.
|
|
936
|
+
|
|
937
|
+
Auth is ALREADY wired globally (the router's `verifyMiddleware` → `res.locals.session`),
|
|
938
|
+
so a handler reads the current user with `getUserId(res)` and does NOT add per-route auth
|
|
939
|
+
middleware (see the `auth` skill). Scope every custom user query by the authenticated id.
|
|
940
|
+
|
|
941
|
+
On the CLIENT, the bearer token is held IN MEMORY only — a `localStorage` copy is
|
|
942
|
+
XSS-exfiltratable and is forbidden. The session is restored after a reload via the
|
|
943
|
+
httpOnly cookie + `GET /users/me`; don't persist the token yourself.
|
|
944
|
+
|
|
945
|
+
**Client-facing endpoints** (mounted under the app's `/api` prefix → `/api/users/...`).
|
|
946
|
+
The auth CLIENT (`useAuth()` → `login` / `register` / `logout` / `refresh`) already wraps
|
|
947
|
+
login / signup / logout — do NOT hand-roll those against the raw routes. The rest have NO
|
|
948
|
+
client method; call them with raw `http.*`. Use these EXACT paths — a weak model guesses
|
|
949
|
+
`/api/auth/*` or `/api/user` (singular), and neither exists:
|
|
950
|
+
|
|
951
|
+
- `POST /api/users/forgot-password` — request a reset email (body `{ email }`)
|
|
952
|
+
- `POST /api/users/reset-password` — confirm with the emailed token (body `{ token, password }`)
|
|
953
|
+
- `PATCH /api/users/:id` — update profile fields (name, username, email, bio); NOT `PUT /api/user`
|
|
954
|
+
- `PATCH /api/users/:id/password` — change password · `DELETE /api/users/:id` — delete account
|
|
955
|
+
- `PATCH /api/users/:id/plan` — update the subscription plan
|
|
956
|
+
- `GET /api/users/me` — the current user (session restore) · `GET /api/users/:id` — read one
|
|
957
|
+
The full, authoritative route list is the `routes` export (see `routes.ts`).
|
|
958
|
+
|
|
959
|
+
## E2E Tests
|
|
960
|
+
|
|
961
|
+
Integration checklist — drive the real UI (live preview, no mocks), adapt
|
|
962
|
+
each item to this app's actual screens/flows, and check every box off one
|
|
963
|
+
by one. A box you can't check is an integration bug to fix — not a skip:
|
|
964
|
+
|
|
965
|
+
- [ ] A new user can sign up with email + password and lands authenticated (the
|
|
966
|
+
UI reflects the signed-in user, e.g. their name/menu appears).
|
|
967
|
+
- [ ] Any flow that emails a link/code (signup verification, password reset)
|
|
968
|
+
round-trips: the sandbox CAPTURES the message instead of sending — read it
|
|
969
|
+
with the `read_activity` tool (filter type 'email') and follow the link/code
|
|
970
|
+
in its payload; never mock the flow or modify production code to expose it.
|
|
971
|
+
- [ ] Logging out and logging back in with the same credentials reaches the same
|
|
972
|
+
account and its data.
|
|
973
|
+
- [ ] The session survives a full page reload (restored via the httpOnly cookie +
|
|
974
|
+
`GET /users/me` — never from a token persisted in localStorage).
|
|
975
|
+
- [ ] A wrong password shows a visible error and does NOT authenticate.
|
|
976
|
+
- [ ] Authenticated-only screens are unreachable when logged out (redirect to
|
|
977
|
+
login or an explicit denial — never a blank page).
|
|
978
|
+
- [ ] A profile/account edit (e.g. display name) persists across a reload.
|