@teamblind/axeda-better-auth 0.0.0-stage → 0.1.0-alpha.1
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/CHANGELOG.md +48 -0
- package/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +87 -2
- package/dist/client.d.ts +10 -0
- package/dist/client.js +9 -0
- package/dist/dto.d.ts +89 -0
- package/dist/dto.js +78 -0
- package/dist/endpoints-tenants.d.ts +748 -0
- package/dist/endpoints-tenants.js +247 -0
- package/dist/endpoints-users.d.ts +242 -0
- package/dist/endpoints-users.js +85 -0
- package/dist/endpoints.d.ts +555 -0
- package/dist/endpoints.js +232 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +32 -0
- package/dist/http-errors.d.ts +12 -0
- package/dist/http-errors.js +58 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +10 -0
- package/dist/plugin.d.ts +1987 -0
- package/dist/plugin.js +208 -0
- package/dist/preset.d.ts +63 -0
- package/dist/preset.js +130 -0
- package/dist/principal.d.ts +61 -0
- package/dist/principal.js +61 -0
- package/dist/rows.d.ts +47 -0
- package/dist/rows.js +66 -0
- package/dist/schema.d.ts +479 -0
- package/dist/schema.js +175 -0
- package/dist/session-lifetime.d.ts +21 -0
- package/dist/session-lifetime.js +50 -0
- package/dist/shared.d.ts +15 -0
- package/dist/shared.js +8 -0
- package/dist/stores.d.ts +13 -0
- package/dist/stores.js +401 -0
- package/dist/tenant-stores.d.ts +5 -0
- package/dist/tenant-stores.js +408 -0
- package/dist/user-admin.d.ts +28 -0
- package/dist/user-admin.js +105 -0
- package/dist/users.d.ts +10 -0
- package/dist/users.js +27 -0
- package/package.json +70 -4
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
/** Nombres de los modelos que Axeda añade al esquema de Better Auth. */
|
|
2
|
+
export declare const MODELS: {
|
|
3
|
+
readonly role: "axedaRole";
|
|
4
|
+
readonly assignment: "axedaAssignment";
|
|
5
|
+
readonly state: "axedaState";
|
|
6
|
+
readonly audit: "axedaAudit";
|
|
7
|
+
readonly company: "axedaCompany";
|
|
8
|
+
readonly business: "axedaBusiness";
|
|
9
|
+
readonly invitation: "axedaInvitation";
|
|
10
|
+
};
|
|
11
|
+
/** Fila única de `axedaState` que guarda la versión de política. */
|
|
12
|
+
export declare const POLICY_STATE_KEY = "policy";
|
|
13
|
+
/**
|
|
14
|
+
* Valor guardado en `scopeId` para una asignación global. Es una cadena vacía y no `null`
|
|
15
|
+
* porque un índice único trata los `NULL` como distintos: con `null` podrían duplicarse
|
|
16
|
+
* asignaciones globales.
|
|
17
|
+
*/
|
|
18
|
+
export declare const GLOBAL_SCOPE_ID = "";
|
|
19
|
+
/**
|
|
20
|
+
* Esquema que el plugin añade a Better Auth. Las migraciones las genera Better Auth a partir
|
|
21
|
+
* de esto (`getMigrations` o su CLI). Reglas: columnas nuevas siempre opcionales o con valor
|
|
22
|
+
* por defecto; un cambio destructivo exige una migración manual.
|
|
23
|
+
*
|
|
24
|
+
* Las restricciones únicas van como `indexes` con `unique: true` y no como `unique` de un campo: el
|
|
25
|
+
* adaptador de MongoDB de Better Auth solo crea los índices de tabla, y sin ellos dos escrituras
|
|
26
|
+
* simultáneas con la misma clave caben las dos. En SQL son equivalentes.
|
|
27
|
+
*/
|
|
28
|
+
export declare const axedaSchema: {
|
|
29
|
+
user: {
|
|
30
|
+
fields: {
|
|
31
|
+
/** Sube con cada cambio que afecta a la autorización de ese usuario. */
|
|
32
|
+
authzVersion: {
|
|
33
|
+
type: "number";
|
|
34
|
+
required: false;
|
|
35
|
+
defaultValue: number;
|
|
36
|
+
input: false;
|
|
37
|
+
};
|
|
38
|
+
banned: {
|
|
39
|
+
type: "boolean";
|
|
40
|
+
required: false;
|
|
41
|
+
defaultValue: false;
|
|
42
|
+
input: false;
|
|
43
|
+
};
|
|
44
|
+
banReason: {
|
|
45
|
+
type: "string";
|
|
46
|
+
required: false;
|
|
47
|
+
input: false;
|
|
48
|
+
};
|
|
49
|
+
banExpires: {
|
|
50
|
+
type: "date";
|
|
51
|
+
required: false;
|
|
52
|
+
input: false;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
axedaRole: {
|
|
57
|
+
fields: {
|
|
58
|
+
key: {
|
|
59
|
+
type: "string";
|
|
60
|
+
required: true;
|
|
61
|
+
input: false;
|
|
62
|
+
};
|
|
63
|
+
name: {
|
|
64
|
+
type: "string";
|
|
65
|
+
required: true;
|
|
66
|
+
input: false;
|
|
67
|
+
};
|
|
68
|
+
description: {
|
|
69
|
+
type: "string";
|
|
70
|
+
required: false;
|
|
71
|
+
input: false;
|
|
72
|
+
};
|
|
73
|
+
permissions: {
|
|
74
|
+
type: "string[]";
|
|
75
|
+
required: true;
|
|
76
|
+
input: false;
|
|
77
|
+
};
|
|
78
|
+
requireMfa: {
|
|
79
|
+
type: "boolean";
|
|
80
|
+
required: true;
|
|
81
|
+
defaultValue: false;
|
|
82
|
+
input: false;
|
|
83
|
+
};
|
|
84
|
+
status: {
|
|
85
|
+
type: "string";
|
|
86
|
+
required: true;
|
|
87
|
+
defaultValue: string;
|
|
88
|
+
input: false;
|
|
89
|
+
};
|
|
90
|
+
managed: {
|
|
91
|
+
type: "boolean";
|
|
92
|
+
required: true;
|
|
93
|
+
defaultValue: false;
|
|
94
|
+
input: false;
|
|
95
|
+
};
|
|
96
|
+
version: {
|
|
97
|
+
type: "number";
|
|
98
|
+
required: true;
|
|
99
|
+
defaultValue: number;
|
|
100
|
+
input: false;
|
|
101
|
+
};
|
|
102
|
+
createdAt: {
|
|
103
|
+
type: "date";
|
|
104
|
+
required: true;
|
|
105
|
+
input: false;
|
|
106
|
+
};
|
|
107
|
+
updatedAt: {
|
|
108
|
+
type: "date";
|
|
109
|
+
required: true;
|
|
110
|
+
input: false;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
indexes: {
|
|
114
|
+
fields: [string];
|
|
115
|
+
unique: true;
|
|
116
|
+
}[];
|
|
117
|
+
};
|
|
118
|
+
axedaAssignment: {
|
|
119
|
+
fields: {
|
|
120
|
+
userId: {
|
|
121
|
+
type: "string";
|
|
122
|
+
required: true;
|
|
123
|
+
input: false;
|
|
124
|
+
references: {
|
|
125
|
+
model: string;
|
|
126
|
+
field: string;
|
|
127
|
+
onDelete: "cascade";
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
roleId: {
|
|
131
|
+
type: "string";
|
|
132
|
+
required: true;
|
|
133
|
+
input: false;
|
|
134
|
+
references: {
|
|
135
|
+
model: "axedaRole";
|
|
136
|
+
field: string;
|
|
137
|
+
onDelete: "cascade";
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
scopeType: {
|
|
141
|
+
type: "string";
|
|
142
|
+
required: true;
|
|
143
|
+
input: false;
|
|
144
|
+
};
|
|
145
|
+
scopeId: {
|
|
146
|
+
type: "string";
|
|
147
|
+
required: true;
|
|
148
|
+
input: false;
|
|
149
|
+
};
|
|
150
|
+
grantedBy: {
|
|
151
|
+
type: "string";
|
|
152
|
+
required: false;
|
|
153
|
+
input: false;
|
|
154
|
+
};
|
|
155
|
+
createdAt: {
|
|
156
|
+
type: "date";
|
|
157
|
+
required: true;
|
|
158
|
+
input: false;
|
|
159
|
+
};
|
|
160
|
+
expiresAt: {
|
|
161
|
+
type: "date";
|
|
162
|
+
required: false;
|
|
163
|
+
input: false;
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
indexes: ({
|
|
167
|
+
fields: [string, string, string, string];
|
|
168
|
+
unique: true;
|
|
169
|
+
} | {
|
|
170
|
+
fields: [string, string];
|
|
171
|
+
unique?: never;
|
|
172
|
+
})[];
|
|
173
|
+
};
|
|
174
|
+
axedaState: {
|
|
175
|
+
fields: {
|
|
176
|
+
key: {
|
|
177
|
+
type: "string";
|
|
178
|
+
required: true;
|
|
179
|
+
input: false;
|
|
180
|
+
};
|
|
181
|
+
version: {
|
|
182
|
+
type: "number";
|
|
183
|
+
required: true;
|
|
184
|
+
defaultValue: number;
|
|
185
|
+
input: false;
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
indexes: {
|
|
189
|
+
fields: [string];
|
|
190
|
+
unique: true;
|
|
191
|
+
}[];
|
|
192
|
+
};
|
|
193
|
+
axedaAudit: {
|
|
194
|
+
fields: {
|
|
195
|
+
actorId: {
|
|
196
|
+
type: "string";
|
|
197
|
+
required: false;
|
|
198
|
+
input: false;
|
|
199
|
+
};
|
|
200
|
+
action: {
|
|
201
|
+
type: "string";
|
|
202
|
+
required: true;
|
|
203
|
+
input: false;
|
|
204
|
+
};
|
|
205
|
+
targetType: {
|
|
206
|
+
type: "string";
|
|
207
|
+
required: true;
|
|
208
|
+
input: false;
|
|
209
|
+
};
|
|
210
|
+
targetId: {
|
|
211
|
+
type: "string";
|
|
212
|
+
required: false;
|
|
213
|
+
input: false;
|
|
214
|
+
};
|
|
215
|
+
scopeType: {
|
|
216
|
+
type: "string";
|
|
217
|
+
required: false;
|
|
218
|
+
input: false;
|
|
219
|
+
};
|
|
220
|
+
scopeId: {
|
|
221
|
+
type: "string";
|
|
222
|
+
required: false;
|
|
223
|
+
input: false;
|
|
224
|
+
};
|
|
225
|
+
outcome: {
|
|
226
|
+
type: "string";
|
|
227
|
+
required: true;
|
|
228
|
+
input: false;
|
|
229
|
+
};
|
|
230
|
+
ip: {
|
|
231
|
+
type: "string";
|
|
232
|
+
required: false;
|
|
233
|
+
input: false;
|
|
234
|
+
};
|
|
235
|
+
userAgent: {
|
|
236
|
+
type: "string";
|
|
237
|
+
required: false;
|
|
238
|
+
input: false;
|
|
239
|
+
};
|
|
240
|
+
metadata: {
|
|
241
|
+
type: "json";
|
|
242
|
+
required: true;
|
|
243
|
+
input: false;
|
|
244
|
+
};
|
|
245
|
+
at: {
|
|
246
|
+
type: "date";
|
|
247
|
+
required: true;
|
|
248
|
+
input: false;
|
|
249
|
+
};
|
|
250
|
+
};
|
|
251
|
+
indexes: ({
|
|
252
|
+
fields: [string];
|
|
253
|
+
} | {
|
|
254
|
+
fields: [string, string];
|
|
255
|
+
})[];
|
|
256
|
+
};
|
|
257
|
+
axedaCompany: {
|
|
258
|
+
fields: {
|
|
259
|
+
slug: {
|
|
260
|
+
type: "string";
|
|
261
|
+
required: true;
|
|
262
|
+
input: false;
|
|
263
|
+
};
|
|
264
|
+
name: {
|
|
265
|
+
type: "string";
|
|
266
|
+
required: true;
|
|
267
|
+
input: false;
|
|
268
|
+
};
|
|
269
|
+
legalName: {
|
|
270
|
+
type: "string";
|
|
271
|
+
required: false;
|
|
272
|
+
input: false;
|
|
273
|
+
};
|
|
274
|
+
logoUrl: {
|
|
275
|
+
type: "string";
|
|
276
|
+
required: false;
|
|
277
|
+
input: false;
|
|
278
|
+
};
|
|
279
|
+
faviconUrl: {
|
|
280
|
+
type: "string";
|
|
281
|
+
required: false;
|
|
282
|
+
input: false;
|
|
283
|
+
};
|
|
284
|
+
status: {
|
|
285
|
+
type: "string";
|
|
286
|
+
required: true;
|
|
287
|
+
defaultValue: string;
|
|
288
|
+
input: false;
|
|
289
|
+
};
|
|
290
|
+
metadata: {
|
|
291
|
+
type: "json";
|
|
292
|
+
required: true;
|
|
293
|
+
input: false;
|
|
294
|
+
};
|
|
295
|
+
version: {
|
|
296
|
+
type: "number";
|
|
297
|
+
required: true;
|
|
298
|
+
defaultValue: number;
|
|
299
|
+
input: false;
|
|
300
|
+
};
|
|
301
|
+
deletedAt: {
|
|
302
|
+
type: "date";
|
|
303
|
+
required: false;
|
|
304
|
+
input: false;
|
|
305
|
+
};
|
|
306
|
+
createdAt: {
|
|
307
|
+
type: "date";
|
|
308
|
+
required: true;
|
|
309
|
+
input: false;
|
|
310
|
+
};
|
|
311
|
+
updatedAt: {
|
|
312
|
+
type: "date";
|
|
313
|
+
required: true;
|
|
314
|
+
input: false;
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
indexes: ({
|
|
318
|
+
fields: [string];
|
|
319
|
+
unique: true;
|
|
320
|
+
} | {
|
|
321
|
+
fields: [string];
|
|
322
|
+
unique?: never;
|
|
323
|
+
})[];
|
|
324
|
+
};
|
|
325
|
+
axedaBusiness: {
|
|
326
|
+
fields: {
|
|
327
|
+
companyId: {
|
|
328
|
+
type: "string";
|
|
329
|
+
required: true;
|
|
330
|
+
input: false;
|
|
331
|
+
references: {
|
|
332
|
+
model: "axedaCompany";
|
|
333
|
+
field: string;
|
|
334
|
+
onDelete: "cascade";
|
|
335
|
+
};
|
|
336
|
+
};
|
|
337
|
+
slug: {
|
|
338
|
+
type: "string";
|
|
339
|
+
required: true;
|
|
340
|
+
input: false;
|
|
341
|
+
};
|
|
342
|
+
name: {
|
|
343
|
+
type: "string";
|
|
344
|
+
required: true;
|
|
345
|
+
input: false;
|
|
346
|
+
};
|
|
347
|
+
logoUrl: {
|
|
348
|
+
type: "string";
|
|
349
|
+
required: false;
|
|
350
|
+
input: false;
|
|
351
|
+
};
|
|
352
|
+
faviconUrl: {
|
|
353
|
+
type: "string";
|
|
354
|
+
required: false;
|
|
355
|
+
input: false;
|
|
356
|
+
};
|
|
357
|
+
status: {
|
|
358
|
+
type: "string";
|
|
359
|
+
required: true;
|
|
360
|
+
defaultValue: string;
|
|
361
|
+
input: false;
|
|
362
|
+
};
|
|
363
|
+
metadata: {
|
|
364
|
+
type: "json";
|
|
365
|
+
required: true;
|
|
366
|
+
input: false;
|
|
367
|
+
};
|
|
368
|
+
version: {
|
|
369
|
+
type: "number";
|
|
370
|
+
required: true;
|
|
371
|
+
defaultValue: number;
|
|
372
|
+
input: false;
|
|
373
|
+
};
|
|
374
|
+
deletedAt: {
|
|
375
|
+
type: "date";
|
|
376
|
+
required: false;
|
|
377
|
+
input: false;
|
|
378
|
+
};
|
|
379
|
+
createdAt: {
|
|
380
|
+
type: "date";
|
|
381
|
+
required: true;
|
|
382
|
+
input: false;
|
|
383
|
+
};
|
|
384
|
+
updatedAt: {
|
|
385
|
+
type: "date";
|
|
386
|
+
required: true;
|
|
387
|
+
input: false;
|
|
388
|
+
};
|
|
389
|
+
};
|
|
390
|
+
indexes: ({
|
|
391
|
+
fields: [string, string];
|
|
392
|
+
unique: true;
|
|
393
|
+
} | {
|
|
394
|
+
fields: [string];
|
|
395
|
+
unique?: never;
|
|
396
|
+
})[];
|
|
397
|
+
};
|
|
398
|
+
axedaInvitation: {
|
|
399
|
+
fields: {
|
|
400
|
+
email: {
|
|
401
|
+
type: "string";
|
|
402
|
+
required: true;
|
|
403
|
+
input: false;
|
|
404
|
+
};
|
|
405
|
+
scopeType: {
|
|
406
|
+
type: "string";
|
|
407
|
+
required: true;
|
|
408
|
+
input: false;
|
|
409
|
+
};
|
|
410
|
+
scopeId: {
|
|
411
|
+
type: "string";
|
|
412
|
+
required: true;
|
|
413
|
+
input: false;
|
|
414
|
+
};
|
|
415
|
+
roleIds: {
|
|
416
|
+
type: "string[]";
|
|
417
|
+
required: true;
|
|
418
|
+
input: false;
|
|
419
|
+
};
|
|
420
|
+
invitedBy: {
|
|
421
|
+
type: "string";
|
|
422
|
+
required: true;
|
|
423
|
+
input: false;
|
|
424
|
+
};
|
|
425
|
+
secretHash: {
|
|
426
|
+
type: "string";
|
|
427
|
+
required: true;
|
|
428
|
+
input: false;
|
|
429
|
+
};
|
|
430
|
+
expiresAt: {
|
|
431
|
+
type: "date";
|
|
432
|
+
required: true;
|
|
433
|
+
input: false;
|
|
434
|
+
};
|
|
435
|
+
acceptedAt: {
|
|
436
|
+
type: "date";
|
|
437
|
+
required: false;
|
|
438
|
+
input: false;
|
|
439
|
+
};
|
|
440
|
+
revokedAt: {
|
|
441
|
+
type: "date";
|
|
442
|
+
required: false;
|
|
443
|
+
input: false;
|
|
444
|
+
};
|
|
445
|
+
/**
|
|
446
|
+
* Clave única mientras la invitación está pendiente (hash de correo + alcance); al
|
|
447
|
+
* cerrarla pasa a `closed:<id>`. Así dos invitaciones iguales a la vez no caben, sin
|
|
448
|
+
* depender de índices parciales que no todas las bases tienen.
|
|
449
|
+
*/
|
|
450
|
+
pendingKey: {
|
|
451
|
+
type: "string";
|
|
452
|
+
required: true;
|
|
453
|
+
input: false;
|
|
454
|
+
};
|
|
455
|
+
/** 0 mientras está pendiente. Se sube con `incrementOne`: solo un cierre lo consigue. */
|
|
456
|
+
consumed: {
|
|
457
|
+
type: "number";
|
|
458
|
+
required: true;
|
|
459
|
+
defaultValue: number;
|
|
460
|
+
input: false;
|
|
461
|
+
};
|
|
462
|
+
createdAt: {
|
|
463
|
+
type: "date";
|
|
464
|
+
required: true;
|
|
465
|
+
input: false;
|
|
466
|
+
};
|
|
467
|
+
};
|
|
468
|
+
indexes: ({
|
|
469
|
+
fields: [string];
|
|
470
|
+
unique: true;
|
|
471
|
+
} | {
|
|
472
|
+
fields: [string, string];
|
|
473
|
+
unique?: never;
|
|
474
|
+
} | {
|
|
475
|
+
fields: [string];
|
|
476
|
+
unique?: never;
|
|
477
|
+
})[];
|
|
478
|
+
};
|
|
479
|
+
};
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/** Nombres de los modelos que Axeda añade al esquema de Better Auth. */
|
|
2
|
+
export const MODELS = {
|
|
3
|
+
role: 'axedaRole',
|
|
4
|
+
assignment: 'axedaAssignment',
|
|
5
|
+
state: 'axedaState',
|
|
6
|
+
audit: 'axedaAudit',
|
|
7
|
+
company: 'axedaCompany',
|
|
8
|
+
business: 'axedaBusiness',
|
|
9
|
+
invitation: 'axedaInvitation',
|
|
10
|
+
};
|
|
11
|
+
/** Fila única de `axedaState` que guarda la versión de política. */
|
|
12
|
+
export const POLICY_STATE_KEY = 'policy';
|
|
13
|
+
/**
|
|
14
|
+
* Valor guardado en `scopeId` para una asignación global. Es una cadena vacía y no `null`
|
|
15
|
+
* porque un índice único trata los `NULL` como distintos: con `null` podrían duplicarse
|
|
16
|
+
* asignaciones globales.
|
|
17
|
+
*/
|
|
18
|
+
export const GLOBAL_SCOPE_ID = '';
|
|
19
|
+
/**
|
|
20
|
+
* Esquema que el plugin añade a Better Auth. Las migraciones las genera Better Auth a partir
|
|
21
|
+
* de esto (`getMigrations` o su CLI). Reglas: columnas nuevas siempre opcionales o con valor
|
|
22
|
+
* por defecto; un cambio destructivo exige una migración manual.
|
|
23
|
+
*
|
|
24
|
+
* Las restricciones únicas van como `indexes` con `unique: true` y no como `unique` de un campo: el
|
|
25
|
+
* adaptador de MongoDB de Better Auth solo crea los índices de tabla, y sin ellos dos escrituras
|
|
26
|
+
* simultáneas con la misma clave caben las dos. En SQL son equivalentes.
|
|
27
|
+
*/
|
|
28
|
+
export const axedaSchema = {
|
|
29
|
+
user: {
|
|
30
|
+
fields: {
|
|
31
|
+
/** Sube con cada cambio que afecta a la autorización de ese usuario. */
|
|
32
|
+
authzVersion: { type: 'number', required: false, defaultValue: 0, input: false },
|
|
33
|
+
// Mismos nombres y tipos que el plugin `admin` de Better Auth, para que convivan.
|
|
34
|
+
banned: { type: 'boolean', required: false, defaultValue: false, input: false },
|
|
35
|
+
banReason: { type: 'string', required: false, input: false },
|
|
36
|
+
banExpires: { type: 'date', required: false, input: false },
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
[MODELS.role]: {
|
|
40
|
+
fields: {
|
|
41
|
+
key: { type: 'string', required: true, input: false },
|
|
42
|
+
name: { type: 'string', required: true, input: false },
|
|
43
|
+
description: { type: 'string', required: false, input: false },
|
|
44
|
+
permissions: { type: 'string[]', required: true, input: false },
|
|
45
|
+
requireMfa: { type: 'boolean', required: true, defaultValue: false, input: false },
|
|
46
|
+
status: { type: 'string', required: true, defaultValue: 'active', input: false },
|
|
47
|
+
managed: { type: 'boolean', required: true, defaultValue: false, input: false },
|
|
48
|
+
version: { type: 'number', required: true, defaultValue: 1, input: false },
|
|
49
|
+
createdAt: { type: 'date', required: true, input: false },
|
|
50
|
+
updatedAt: { type: 'date', required: true, input: false },
|
|
51
|
+
},
|
|
52
|
+
indexes: [{ fields: ['key'], unique: true }],
|
|
53
|
+
},
|
|
54
|
+
[MODELS.assignment]: {
|
|
55
|
+
fields: {
|
|
56
|
+
userId: {
|
|
57
|
+
type: 'string',
|
|
58
|
+
required: true,
|
|
59
|
+
input: false,
|
|
60
|
+
references: { model: 'user', field: 'id', onDelete: 'cascade' },
|
|
61
|
+
},
|
|
62
|
+
roleId: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
required: true,
|
|
65
|
+
input: false,
|
|
66
|
+
references: { model: MODELS.role, field: 'id', onDelete: 'cascade' },
|
|
67
|
+
},
|
|
68
|
+
scopeType: { type: 'string', required: true, input: false },
|
|
69
|
+
scopeId: { type: 'string', required: true, input: false },
|
|
70
|
+
grantedBy: { type: 'string', required: false, input: false },
|
|
71
|
+
createdAt: { type: 'date', required: true, input: false },
|
|
72
|
+
expiresAt: { type: 'date', required: false, input: false },
|
|
73
|
+
},
|
|
74
|
+
indexes: [
|
|
75
|
+
{ fields: ['userId', 'roleId', 'scopeType', 'scopeId'], unique: true },
|
|
76
|
+
{ fields: ['scopeType', 'scopeId'] },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
[MODELS.state]: {
|
|
80
|
+
fields: {
|
|
81
|
+
key: { type: 'string', required: true, input: false },
|
|
82
|
+
version: { type: 'number', required: true, defaultValue: 0, input: false },
|
|
83
|
+
},
|
|
84
|
+
indexes: [{ fields: ['key'], unique: true }],
|
|
85
|
+
},
|
|
86
|
+
[MODELS.audit]: {
|
|
87
|
+
fields: {
|
|
88
|
+
// Sin clave foránea: la auditoría debe sobrevivir al borrado del usuario.
|
|
89
|
+
actorId: { type: 'string', required: false, input: false },
|
|
90
|
+
action: { type: 'string', required: true, input: false },
|
|
91
|
+
targetType: { type: 'string', required: true, input: false },
|
|
92
|
+
targetId: { type: 'string', required: false, input: false },
|
|
93
|
+
scopeType: { type: 'string', required: false, input: false },
|
|
94
|
+
scopeId: { type: 'string', required: false, input: false },
|
|
95
|
+
outcome: { type: 'string', required: true, input: false },
|
|
96
|
+
ip: { type: 'string', required: false, input: false },
|
|
97
|
+
userAgent: { type: 'string', required: false, input: false },
|
|
98
|
+
metadata: { type: 'json', required: true, input: false },
|
|
99
|
+
at: { type: 'date', required: true, input: false },
|
|
100
|
+
},
|
|
101
|
+
indexes: [
|
|
102
|
+
{ fields: ['actorId'] },
|
|
103
|
+
// Sin él, filtrar por acción recorre toda la tabla y crece con ella (50-70 ms con 200 000 eventos
|
|
104
|
+
// en PostgreSQL 16 y 18, 30 ms en PGlite); con él son décimas de milisegundo.
|
|
105
|
+
{ fields: ['action'] },
|
|
106
|
+
{ fields: ['targetType', 'targetId'] },
|
|
107
|
+
{ fields: ['scopeType', 'scopeId'] },
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
[MODELS.company]: {
|
|
111
|
+
fields: {
|
|
112
|
+
slug: { type: 'string', required: true, input: false },
|
|
113
|
+
name: { type: 'string', required: true, input: false },
|
|
114
|
+
legalName: { type: 'string', required: false, input: false },
|
|
115
|
+
logoUrl: { type: 'string', required: false, input: false },
|
|
116
|
+
faviconUrl: { type: 'string', required: false, input: false },
|
|
117
|
+
status: { type: 'string', required: true, defaultValue: 'active', input: false },
|
|
118
|
+
metadata: { type: 'json', required: true, input: false },
|
|
119
|
+
version: { type: 'number', required: true, defaultValue: 1, input: false },
|
|
120
|
+
deletedAt: { type: 'date', required: false, input: false },
|
|
121
|
+
createdAt: { type: 'date', required: true, input: false },
|
|
122
|
+
updatedAt: { type: 'date', required: true, input: false },
|
|
123
|
+
},
|
|
124
|
+
indexes: [{ fields: ['slug'], unique: true }, { fields: ['deletedAt'] }],
|
|
125
|
+
},
|
|
126
|
+
[MODELS.business]: {
|
|
127
|
+
fields: {
|
|
128
|
+
companyId: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
required: true,
|
|
131
|
+
input: false,
|
|
132
|
+
references: { model: MODELS.company, field: 'id', onDelete: 'cascade' },
|
|
133
|
+
},
|
|
134
|
+
slug: { type: 'string', required: true, input: false },
|
|
135
|
+
name: { type: 'string', required: true, input: false },
|
|
136
|
+
logoUrl: { type: 'string', required: false, input: false },
|
|
137
|
+
faviconUrl: { type: 'string', required: false, input: false },
|
|
138
|
+
status: { type: 'string', required: true, defaultValue: 'active', input: false },
|
|
139
|
+
metadata: { type: 'json', required: true, input: false },
|
|
140
|
+
version: { type: 'number', required: true, defaultValue: 1, input: false },
|
|
141
|
+
deletedAt: { type: 'date', required: false, input: false },
|
|
142
|
+
createdAt: { type: 'date', required: true, input: false },
|
|
143
|
+
updatedAt: { type: 'date', required: true, input: false },
|
|
144
|
+
},
|
|
145
|
+
indexes: [{ fields: ['companyId', 'slug'], unique: true }, { fields: ['deletedAt'] }],
|
|
146
|
+
},
|
|
147
|
+
[MODELS.invitation]: {
|
|
148
|
+
fields: {
|
|
149
|
+
email: { type: 'string', required: true, input: false },
|
|
150
|
+
scopeType: { type: 'string', required: true, input: false },
|
|
151
|
+
scopeId: { type: 'string', required: true, input: false },
|
|
152
|
+
roleIds: { type: 'string[]', required: true, input: false },
|
|
153
|
+
// Sin clave foránea: la invitación puede sobrevivir al usuario que invitó.
|
|
154
|
+
invitedBy: { type: 'string', required: true, input: false },
|
|
155
|
+
secretHash: { type: 'string', required: true, input: false },
|
|
156
|
+
expiresAt: { type: 'date', required: true, input: false },
|
|
157
|
+
acceptedAt: { type: 'date', required: false, input: false },
|
|
158
|
+
revokedAt: { type: 'date', required: false, input: false },
|
|
159
|
+
/**
|
|
160
|
+
* Clave única mientras la invitación está pendiente (hash de correo + alcance); al
|
|
161
|
+
* cerrarla pasa a `closed:<id>`. Así dos invitaciones iguales a la vez no caben, sin
|
|
162
|
+
* depender de índices parciales que no todas las bases tienen.
|
|
163
|
+
*/
|
|
164
|
+
pendingKey: { type: 'string', required: true, input: false },
|
|
165
|
+
/** 0 mientras está pendiente. Se sube con `incrementOne`: solo un cierre lo consigue. */
|
|
166
|
+
consumed: { type: 'number', required: true, defaultValue: 0, input: false },
|
|
167
|
+
createdAt: { type: 'date', required: true, input: false },
|
|
168
|
+
},
|
|
169
|
+
indexes: [
|
|
170
|
+
{ fields: ['pendingKey'], unique: true },
|
|
171
|
+
{ fields: ['scopeType', 'scopeId'] },
|
|
172
|
+
{ fields: ['email'] },
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Treinta días: tras ese tiempo hay que volver a iniciar sesión, por mucho que se use. */
|
|
2
|
+
export declare const DEFAULT_MAX_SESSION_AGE: number;
|
|
3
|
+
/**
|
|
4
|
+
* La vida máxima de una sesión, en segundos, o `undefined` si se desactivó con `false`.
|
|
5
|
+
* Un valor que no sea un entero positivo es un error de configuración, no se corrige en silencio.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveMaxSessionAge(value: number | false | undefined): number | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Recorta cuándo caduca una sesión para que nunca pase de su creación más `maxAge`. Devuelve
|
|
10
|
+
* `undefined` si no hay nada que recortar.
|
|
11
|
+
*/
|
|
12
|
+
export declare function cappedExpiry(expiresAt: unknown, createdAt: unknown, maxAge: number): Date | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* La sesión que Better Auth está renovando. Una renovación solo trae la nueva fecha de caducidad;
|
|
15
|
+
* la fila (con su `createdAt`) está en el contexto de la petición, donde Better Auth la leyó
|
|
16
|
+
* justo antes. Sin petición (un trabajo que llama a `updateSession` por su cuenta) no hay de dónde
|
|
17
|
+
* sacarla y la renovación se deja pasar.
|
|
18
|
+
*/
|
|
19
|
+
export declare function sessionBeingRefreshed(context: unknown): {
|
|
20
|
+
readonly createdAt: unknown;
|
|
21
|
+
} | undefined;
|