@teamblind/axeda-better-auth 0.0.0-stage → 0.1.0-alpha.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/CHANGELOG.md +31 -0
- package/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +13 -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 +1954 -0
- package/dist/plugin.js +188 -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 +462 -0
- package/dist/schema.js +162 -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 +358 -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 +67 -4
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,462 @@
|
|
|
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
|
+
export declare const axedaSchema: {
|
|
25
|
+
user: {
|
|
26
|
+
fields: {
|
|
27
|
+
/** Sube con cada cambio que afecta a la autorización de ese usuario. */
|
|
28
|
+
authzVersion: {
|
|
29
|
+
type: "number";
|
|
30
|
+
required: false;
|
|
31
|
+
defaultValue: number;
|
|
32
|
+
input: false;
|
|
33
|
+
};
|
|
34
|
+
banned: {
|
|
35
|
+
type: "boolean";
|
|
36
|
+
required: false;
|
|
37
|
+
defaultValue: false;
|
|
38
|
+
input: false;
|
|
39
|
+
};
|
|
40
|
+
banReason: {
|
|
41
|
+
type: "string";
|
|
42
|
+
required: false;
|
|
43
|
+
input: false;
|
|
44
|
+
};
|
|
45
|
+
banExpires: {
|
|
46
|
+
type: "date";
|
|
47
|
+
required: false;
|
|
48
|
+
input: false;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
axedaRole: {
|
|
53
|
+
fields: {
|
|
54
|
+
key: {
|
|
55
|
+
type: "string";
|
|
56
|
+
required: true;
|
|
57
|
+
unique: true;
|
|
58
|
+
input: false;
|
|
59
|
+
};
|
|
60
|
+
name: {
|
|
61
|
+
type: "string";
|
|
62
|
+
required: true;
|
|
63
|
+
input: false;
|
|
64
|
+
};
|
|
65
|
+
description: {
|
|
66
|
+
type: "string";
|
|
67
|
+
required: false;
|
|
68
|
+
input: false;
|
|
69
|
+
};
|
|
70
|
+
permissions: {
|
|
71
|
+
type: "string[]";
|
|
72
|
+
required: true;
|
|
73
|
+
input: false;
|
|
74
|
+
};
|
|
75
|
+
requireMfa: {
|
|
76
|
+
type: "boolean";
|
|
77
|
+
required: true;
|
|
78
|
+
defaultValue: false;
|
|
79
|
+
input: false;
|
|
80
|
+
};
|
|
81
|
+
status: {
|
|
82
|
+
type: "string";
|
|
83
|
+
required: true;
|
|
84
|
+
defaultValue: string;
|
|
85
|
+
input: false;
|
|
86
|
+
};
|
|
87
|
+
managed: {
|
|
88
|
+
type: "boolean";
|
|
89
|
+
required: true;
|
|
90
|
+
defaultValue: false;
|
|
91
|
+
input: false;
|
|
92
|
+
};
|
|
93
|
+
version: {
|
|
94
|
+
type: "number";
|
|
95
|
+
required: true;
|
|
96
|
+
defaultValue: number;
|
|
97
|
+
input: false;
|
|
98
|
+
};
|
|
99
|
+
createdAt: {
|
|
100
|
+
type: "date";
|
|
101
|
+
required: true;
|
|
102
|
+
input: false;
|
|
103
|
+
};
|
|
104
|
+
updatedAt: {
|
|
105
|
+
type: "date";
|
|
106
|
+
required: true;
|
|
107
|
+
input: false;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
axedaAssignment: {
|
|
112
|
+
fields: {
|
|
113
|
+
userId: {
|
|
114
|
+
type: "string";
|
|
115
|
+
required: true;
|
|
116
|
+
input: false;
|
|
117
|
+
references: {
|
|
118
|
+
model: string;
|
|
119
|
+
field: string;
|
|
120
|
+
onDelete: "cascade";
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
roleId: {
|
|
124
|
+
type: "string";
|
|
125
|
+
required: true;
|
|
126
|
+
input: false;
|
|
127
|
+
references: {
|
|
128
|
+
model: "axedaRole";
|
|
129
|
+
field: string;
|
|
130
|
+
onDelete: "cascade";
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
scopeType: {
|
|
134
|
+
type: "string";
|
|
135
|
+
required: true;
|
|
136
|
+
input: false;
|
|
137
|
+
};
|
|
138
|
+
scopeId: {
|
|
139
|
+
type: "string";
|
|
140
|
+
required: true;
|
|
141
|
+
input: false;
|
|
142
|
+
};
|
|
143
|
+
grantedBy: {
|
|
144
|
+
type: "string";
|
|
145
|
+
required: false;
|
|
146
|
+
input: false;
|
|
147
|
+
};
|
|
148
|
+
createdAt: {
|
|
149
|
+
type: "date";
|
|
150
|
+
required: true;
|
|
151
|
+
input: false;
|
|
152
|
+
};
|
|
153
|
+
expiresAt: {
|
|
154
|
+
type: "date";
|
|
155
|
+
required: false;
|
|
156
|
+
input: false;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
indexes: ({
|
|
160
|
+
fields: [string, string, string, string];
|
|
161
|
+
unique: true;
|
|
162
|
+
} | {
|
|
163
|
+
fields: [string, string];
|
|
164
|
+
unique?: never;
|
|
165
|
+
})[];
|
|
166
|
+
};
|
|
167
|
+
axedaState: {
|
|
168
|
+
fields: {
|
|
169
|
+
key: {
|
|
170
|
+
type: "string";
|
|
171
|
+
required: true;
|
|
172
|
+
unique: true;
|
|
173
|
+
input: false;
|
|
174
|
+
};
|
|
175
|
+
version: {
|
|
176
|
+
type: "number";
|
|
177
|
+
required: true;
|
|
178
|
+
defaultValue: number;
|
|
179
|
+
input: false;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
axedaAudit: {
|
|
184
|
+
fields: {
|
|
185
|
+
actorId: {
|
|
186
|
+
type: "string";
|
|
187
|
+
required: false;
|
|
188
|
+
input: false;
|
|
189
|
+
};
|
|
190
|
+
action: {
|
|
191
|
+
type: "string";
|
|
192
|
+
required: true;
|
|
193
|
+
input: false;
|
|
194
|
+
};
|
|
195
|
+
targetType: {
|
|
196
|
+
type: "string";
|
|
197
|
+
required: true;
|
|
198
|
+
input: false;
|
|
199
|
+
};
|
|
200
|
+
targetId: {
|
|
201
|
+
type: "string";
|
|
202
|
+
required: false;
|
|
203
|
+
input: false;
|
|
204
|
+
};
|
|
205
|
+
scopeType: {
|
|
206
|
+
type: "string";
|
|
207
|
+
required: false;
|
|
208
|
+
input: false;
|
|
209
|
+
};
|
|
210
|
+
scopeId: {
|
|
211
|
+
type: "string";
|
|
212
|
+
required: false;
|
|
213
|
+
input: false;
|
|
214
|
+
};
|
|
215
|
+
outcome: {
|
|
216
|
+
type: "string";
|
|
217
|
+
required: true;
|
|
218
|
+
input: false;
|
|
219
|
+
};
|
|
220
|
+
ip: {
|
|
221
|
+
type: "string";
|
|
222
|
+
required: false;
|
|
223
|
+
input: false;
|
|
224
|
+
};
|
|
225
|
+
userAgent: {
|
|
226
|
+
type: "string";
|
|
227
|
+
required: false;
|
|
228
|
+
input: false;
|
|
229
|
+
};
|
|
230
|
+
metadata: {
|
|
231
|
+
type: "json";
|
|
232
|
+
required: true;
|
|
233
|
+
input: false;
|
|
234
|
+
};
|
|
235
|
+
at: {
|
|
236
|
+
type: "date";
|
|
237
|
+
required: true;
|
|
238
|
+
input: false;
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
indexes: ({
|
|
242
|
+
fields: [string];
|
|
243
|
+
} | {
|
|
244
|
+
fields: [string, string];
|
|
245
|
+
})[];
|
|
246
|
+
};
|
|
247
|
+
axedaCompany: {
|
|
248
|
+
fields: {
|
|
249
|
+
slug: {
|
|
250
|
+
type: "string";
|
|
251
|
+
required: true;
|
|
252
|
+
unique: true;
|
|
253
|
+
input: false;
|
|
254
|
+
};
|
|
255
|
+
name: {
|
|
256
|
+
type: "string";
|
|
257
|
+
required: true;
|
|
258
|
+
input: false;
|
|
259
|
+
};
|
|
260
|
+
legalName: {
|
|
261
|
+
type: "string";
|
|
262
|
+
required: false;
|
|
263
|
+
input: false;
|
|
264
|
+
};
|
|
265
|
+
logoUrl: {
|
|
266
|
+
type: "string";
|
|
267
|
+
required: false;
|
|
268
|
+
input: false;
|
|
269
|
+
};
|
|
270
|
+
faviconUrl: {
|
|
271
|
+
type: "string";
|
|
272
|
+
required: false;
|
|
273
|
+
input: false;
|
|
274
|
+
};
|
|
275
|
+
status: {
|
|
276
|
+
type: "string";
|
|
277
|
+
required: true;
|
|
278
|
+
defaultValue: string;
|
|
279
|
+
input: false;
|
|
280
|
+
};
|
|
281
|
+
metadata: {
|
|
282
|
+
type: "json";
|
|
283
|
+
required: true;
|
|
284
|
+
input: false;
|
|
285
|
+
};
|
|
286
|
+
version: {
|
|
287
|
+
type: "number";
|
|
288
|
+
required: true;
|
|
289
|
+
defaultValue: number;
|
|
290
|
+
input: false;
|
|
291
|
+
};
|
|
292
|
+
deletedAt: {
|
|
293
|
+
type: "date";
|
|
294
|
+
required: false;
|
|
295
|
+
input: false;
|
|
296
|
+
};
|
|
297
|
+
createdAt: {
|
|
298
|
+
type: "date";
|
|
299
|
+
required: true;
|
|
300
|
+
input: false;
|
|
301
|
+
};
|
|
302
|
+
updatedAt: {
|
|
303
|
+
type: "date";
|
|
304
|
+
required: true;
|
|
305
|
+
input: false;
|
|
306
|
+
};
|
|
307
|
+
};
|
|
308
|
+
indexes: {
|
|
309
|
+
fields: [string];
|
|
310
|
+
}[];
|
|
311
|
+
};
|
|
312
|
+
axedaBusiness: {
|
|
313
|
+
fields: {
|
|
314
|
+
companyId: {
|
|
315
|
+
type: "string";
|
|
316
|
+
required: true;
|
|
317
|
+
input: false;
|
|
318
|
+
references: {
|
|
319
|
+
model: "axedaCompany";
|
|
320
|
+
field: string;
|
|
321
|
+
onDelete: "cascade";
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
slug: {
|
|
325
|
+
type: "string";
|
|
326
|
+
required: true;
|
|
327
|
+
input: false;
|
|
328
|
+
};
|
|
329
|
+
name: {
|
|
330
|
+
type: "string";
|
|
331
|
+
required: true;
|
|
332
|
+
input: false;
|
|
333
|
+
};
|
|
334
|
+
logoUrl: {
|
|
335
|
+
type: "string";
|
|
336
|
+
required: false;
|
|
337
|
+
input: false;
|
|
338
|
+
};
|
|
339
|
+
faviconUrl: {
|
|
340
|
+
type: "string";
|
|
341
|
+
required: false;
|
|
342
|
+
input: false;
|
|
343
|
+
};
|
|
344
|
+
status: {
|
|
345
|
+
type: "string";
|
|
346
|
+
required: true;
|
|
347
|
+
defaultValue: string;
|
|
348
|
+
input: false;
|
|
349
|
+
};
|
|
350
|
+
metadata: {
|
|
351
|
+
type: "json";
|
|
352
|
+
required: true;
|
|
353
|
+
input: false;
|
|
354
|
+
};
|
|
355
|
+
version: {
|
|
356
|
+
type: "number";
|
|
357
|
+
required: true;
|
|
358
|
+
defaultValue: number;
|
|
359
|
+
input: false;
|
|
360
|
+
};
|
|
361
|
+
deletedAt: {
|
|
362
|
+
type: "date";
|
|
363
|
+
required: false;
|
|
364
|
+
input: false;
|
|
365
|
+
};
|
|
366
|
+
createdAt: {
|
|
367
|
+
type: "date";
|
|
368
|
+
required: true;
|
|
369
|
+
input: false;
|
|
370
|
+
};
|
|
371
|
+
updatedAt: {
|
|
372
|
+
type: "date";
|
|
373
|
+
required: true;
|
|
374
|
+
input: false;
|
|
375
|
+
};
|
|
376
|
+
};
|
|
377
|
+
indexes: ({
|
|
378
|
+
fields: [string, string];
|
|
379
|
+
unique: true;
|
|
380
|
+
} | {
|
|
381
|
+
fields: [string];
|
|
382
|
+
unique?: never;
|
|
383
|
+
})[];
|
|
384
|
+
};
|
|
385
|
+
axedaInvitation: {
|
|
386
|
+
fields: {
|
|
387
|
+
email: {
|
|
388
|
+
type: "string";
|
|
389
|
+
required: true;
|
|
390
|
+
input: false;
|
|
391
|
+
};
|
|
392
|
+
scopeType: {
|
|
393
|
+
type: "string";
|
|
394
|
+
required: true;
|
|
395
|
+
input: false;
|
|
396
|
+
};
|
|
397
|
+
scopeId: {
|
|
398
|
+
type: "string";
|
|
399
|
+
required: true;
|
|
400
|
+
input: false;
|
|
401
|
+
};
|
|
402
|
+
roleIds: {
|
|
403
|
+
type: "string[]";
|
|
404
|
+
required: true;
|
|
405
|
+
input: false;
|
|
406
|
+
};
|
|
407
|
+
invitedBy: {
|
|
408
|
+
type: "string";
|
|
409
|
+
required: true;
|
|
410
|
+
input: false;
|
|
411
|
+
};
|
|
412
|
+
secretHash: {
|
|
413
|
+
type: "string";
|
|
414
|
+
required: true;
|
|
415
|
+
input: false;
|
|
416
|
+
};
|
|
417
|
+
expiresAt: {
|
|
418
|
+
type: "date";
|
|
419
|
+
required: true;
|
|
420
|
+
input: false;
|
|
421
|
+
};
|
|
422
|
+
acceptedAt: {
|
|
423
|
+
type: "date";
|
|
424
|
+
required: false;
|
|
425
|
+
input: false;
|
|
426
|
+
};
|
|
427
|
+
revokedAt: {
|
|
428
|
+
type: "date";
|
|
429
|
+
required: false;
|
|
430
|
+
input: false;
|
|
431
|
+
};
|
|
432
|
+
/**
|
|
433
|
+
* Clave única mientras la invitación está pendiente (hash de correo + alcance); al
|
|
434
|
+
* cerrarla pasa a `closed:<id>`. Así dos invitaciones iguales a la vez no caben, sin
|
|
435
|
+
* depender de índices parciales que no todas las bases tienen.
|
|
436
|
+
*/
|
|
437
|
+
pendingKey: {
|
|
438
|
+
type: "string";
|
|
439
|
+
required: true;
|
|
440
|
+
unique: true;
|
|
441
|
+
input: false;
|
|
442
|
+
};
|
|
443
|
+
/** 0 mientras está pendiente. Se sube con `incrementOne`: solo un cierre lo consigue. */
|
|
444
|
+
consumed: {
|
|
445
|
+
type: "number";
|
|
446
|
+
required: true;
|
|
447
|
+
defaultValue: number;
|
|
448
|
+
input: false;
|
|
449
|
+
};
|
|
450
|
+
createdAt: {
|
|
451
|
+
type: "date";
|
|
452
|
+
required: true;
|
|
453
|
+
input: false;
|
|
454
|
+
};
|
|
455
|
+
};
|
|
456
|
+
indexes: ({
|
|
457
|
+
fields: [string, string];
|
|
458
|
+
} | {
|
|
459
|
+
fields: [string];
|
|
460
|
+
})[];
|
|
461
|
+
};
|
|
462
|
+
};
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
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
|
+
export const axedaSchema = {
|
|
25
|
+
user: {
|
|
26
|
+
fields: {
|
|
27
|
+
/** Sube con cada cambio que afecta a la autorización de ese usuario. */
|
|
28
|
+
authzVersion: { type: 'number', required: false, defaultValue: 0, input: false },
|
|
29
|
+
// Mismos nombres y tipos que el plugin `admin` de Better Auth, para que convivan.
|
|
30
|
+
banned: { type: 'boolean', required: false, defaultValue: false, input: false },
|
|
31
|
+
banReason: { type: 'string', required: false, input: false },
|
|
32
|
+
banExpires: { type: 'date', required: false, input: false },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
[MODELS.role]: {
|
|
36
|
+
fields: {
|
|
37
|
+
key: { type: 'string', required: true, unique: true, input: false },
|
|
38
|
+
name: { type: 'string', required: true, input: false },
|
|
39
|
+
description: { type: 'string', required: false, input: false },
|
|
40
|
+
permissions: { type: 'string[]', required: true, input: false },
|
|
41
|
+
requireMfa: { type: 'boolean', required: true, defaultValue: false, input: false },
|
|
42
|
+
status: { type: 'string', required: true, defaultValue: 'active', input: false },
|
|
43
|
+
managed: { type: 'boolean', required: true, defaultValue: false, input: false },
|
|
44
|
+
version: { type: 'number', required: true, defaultValue: 1, input: false },
|
|
45
|
+
createdAt: { type: 'date', required: true, input: false },
|
|
46
|
+
updatedAt: { type: 'date', required: true, input: false },
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
[MODELS.assignment]: {
|
|
50
|
+
fields: {
|
|
51
|
+
userId: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
required: true,
|
|
54
|
+
input: false,
|
|
55
|
+
references: { model: 'user', field: 'id', onDelete: 'cascade' },
|
|
56
|
+
},
|
|
57
|
+
roleId: {
|
|
58
|
+
type: 'string',
|
|
59
|
+
required: true,
|
|
60
|
+
input: false,
|
|
61
|
+
references: { model: MODELS.role, field: 'id', onDelete: 'cascade' },
|
|
62
|
+
},
|
|
63
|
+
scopeType: { type: 'string', required: true, input: false },
|
|
64
|
+
scopeId: { type: 'string', required: true, input: false },
|
|
65
|
+
grantedBy: { type: 'string', required: false, input: false },
|
|
66
|
+
createdAt: { type: 'date', required: true, input: false },
|
|
67
|
+
expiresAt: { type: 'date', required: false, input: false },
|
|
68
|
+
},
|
|
69
|
+
indexes: [
|
|
70
|
+
{ fields: ['userId', 'roleId', 'scopeType', 'scopeId'], unique: true },
|
|
71
|
+
{ fields: ['scopeType', 'scopeId'] },
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
[MODELS.state]: {
|
|
75
|
+
fields: {
|
|
76
|
+
key: { type: 'string', required: true, unique: true, input: false },
|
|
77
|
+
version: { type: 'number', required: true, defaultValue: 0, input: false },
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
[MODELS.audit]: {
|
|
81
|
+
fields: {
|
|
82
|
+
// Sin clave foránea: la auditoría debe sobrevivir al borrado del usuario.
|
|
83
|
+
actorId: { type: 'string', required: false, input: false },
|
|
84
|
+
action: { type: 'string', required: true, input: false },
|
|
85
|
+
targetType: { type: 'string', required: true, input: false },
|
|
86
|
+
targetId: { type: 'string', required: false, input: false },
|
|
87
|
+
scopeType: { type: 'string', required: false, input: false },
|
|
88
|
+
scopeId: { type: 'string', required: false, input: false },
|
|
89
|
+
outcome: { type: 'string', required: true, input: false },
|
|
90
|
+
ip: { type: 'string', required: false, input: false },
|
|
91
|
+
userAgent: { type: 'string', required: false, input: false },
|
|
92
|
+
metadata: { type: 'json', required: true, input: false },
|
|
93
|
+
at: { type: 'date', required: true, input: false },
|
|
94
|
+
},
|
|
95
|
+
indexes: [
|
|
96
|
+
{ fields: ['actorId'] },
|
|
97
|
+
{ fields: ['targetType', 'targetId'] },
|
|
98
|
+
{ fields: ['scopeType', 'scopeId'] },
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
[MODELS.company]: {
|
|
102
|
+
fields: {
|
|
103
|
+
slug: { type: 'string', required: true, unique: true, input: false },
|
|
104
|
+
name: { type: 'string', required: true, input: false },
|
|
105
|
+
legalName: { type: 'string', required: false, input: false },
|
|
106
|
+
logoUrl: { type: 'string', required: false, input: false },
|
|
107
|
+
faviconUrl: { type: 'string', required: false, input: false },
|
|
108
|
+
status: { type: 'string', required: true, defaultValue: 'active', input: false },
|
|
109
|
+
metadata: { type: 'json', required: true, input: false },
|
|
110
|
+
version: { type: 'number', required: true, defaultValue: 1, input: false },
|
|
111
|
+
deletedAt: { type: 'date', required: false, input: false },
|
|
112
|
+
createdAt: { type: 'date', required: true, input: false },
|
|
113
|
+
updatedAt: { type: 'date', required: true, input: false },
|
|
114
|
+
},
|
|
115
|
+
indexes: [{ fields: ['deletedAt'] }],
|
|
116
|
+
},
|
|
117
|
+
[MODELS.business]: {
|
|
118
|
+
fields: {
|
|
119
|
+
companyId: {
|
|
120
|
+
type: 'string',
|
|
121
|
+
required: true,
|
|
122
|
+
input: false,
|
|
123
|
+
references: { model: MODELS.company, field: 'id', onDelete: 'cascade' },
|
|
124
|
+
},
|
|
125
|
+
slug: { type: 'string', required: true, input: false },
|
|
126
|
+
name: { type: 'string', required: true, input: false },
|
|
127
|
+
logoUrl: { type: 'string', required: false, input: false },
|
|
128
|
+
faviconUrl: { type: 'string', required: false, input: false },
|
|
129
|
+
status: { type: 'string', required: true, defaultValue: 'active', input: false },
|
|
130
|
+
metadata: { type: 'json', required: true, input: false },
|
|
131
|
+
version: { type: 'number', required: true, defaultValue: 1, input: false },
|
|
132
|
+
deletedAt: { type: 'date', required: false, input: false },
|
|
133
|
+
createdAt: { type: 'date', required: true, input: false },
|
|
134
|
+
updatedAt: { type: 'date', required: true, input: false },
|
|
135
|
+
},
|
|
136
|
+
indexes: [{ fields: ['companyId', 'slug'], unique: true }, { fields: ['deletedAt'] }],
|
|
137
|
+
},
|
|
138
|
+
[MODELS.invitation]: {
|
|
139
|
+
fields: {
|
|
140
|
+
email: { type: 'string', required: true, input: false },
|
|
141
|
+
scopeType: { type: 'string', required: true, input: false },
|
|
142
|
+
scopeId: { type: 'string', required: true, input: false },
|
|
143
|
+
roleIds: { type: 'string[]', required: true, input: false },
|
|
144
|
+
// Sin clave foránea: la invitación puede sobrevivir al usuario que invitó.
|
|
145
|
+
invitedBy: { type: 'string', required: true, input: false },
|
|
146
|
+
secretHash: { type: 'string', required: true, input: false },
|
|
147
|
+
expiresAt: { type: 'date', required: true, input: false },
|
|
148
|
+
acceptedAt: { type: 'date', required: false, input: false },
|
|
149
|
+
revokedAt: { type: 'date', required: false, input: false },
|
|
150
|
+
/**
|
|
151
|
+
* Clave única mientras la invitación está pendiente (hash de correo + alcance); al
|
|
152
|
+
* cerrarla pasa a `closed:<id>`. Así dos invitaciones iguales a la vez no caben, sin
|
|
153
|
+
* depender de índices parciales que no todas las bases tienen.
|
|
154
|
+
*/
|
|
155
|
+
pendingKey: { type: 'string', required: true, unique: true, input: false },
|
|
156
|
+
/** 0 mientras está pendiente. Se sube con `incrementOne`: solo un cierre lo consigue. */
|
|
157
|
+
consumed: { type: 'number', required: true, defaultValue: 0, input: false },
|
|
158
|
+
createdAt: { type: 'date', required: true, input: false },
|
|
159
|
+
},
|
|
160
|
+
indexes: [{ fields: ['scopeType', 'scopeId'] }, { fields: ['email'] }],
|
|
161
|
+
},
|
|
162
|
+
};
|
package/dist/shared.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DBAdapter, DBTransactionAdapter } from '@better-auth/core/db/adapter';
|
|
2
|
+
export type Adapter = DBAdapter | DBTransactionAdapter;
|
|
3
|
+
/** Ejecuta `work` de forma atómica con el adaptador que corresponda. */
|
|
4
|
+
export type Atomic = <T>(work: (adapter: Adapter) => Promise<T>) => Promise<T>;
|
|
5
|
+
export declare const encodeCursor: (value: string) => string;
|
|
6
|
+
export declare const decodeCursor: (cursor: string) => string;
|
|
7
|
+
export declare const byId: (id: string) => {
|
|
8
|
+
field: string;
|
|
9
|
+
value: string;
|
|
10
|
+
}[];
|
|
11
|
+
/**
|
|
12
|
+
* Better Auth limita `findMany` a 100 filas si no se indica otra cosa. Para datos de seguridad
|
|
13
|
+
* un tope silencioso es peligroso, así que siempre se pide un límite explícito.
|
|
14
|
+
*/
|
|
15
|
+
export declare const MAX_ROWS = 10000;
|
package/dist/shared.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const encodeCursor = (value) => Buffer.from(value, 'utf8').toString('base64url');
|
|
2
|
+
export const decodeCursor = (cursor) => Buffer.from(cursor, 'base64url').toString('utf8');
|
|
3
|
+
export const byId = (id) => [{ field: 'id', value: id }];
|
|
4
|
+
/**
|
|
5
|
+
* Better Auth limita `findMany` a 100 filas si no se indica otra cosa. Para datos de seguridad
|
|
6
|
+
* un tope silencioso es peligroso, así que siempre se pide un límite explícito.
|
|
7
|
+
*/
|
|
8
|
+
export const MAX_ROWS = 10_000;
|
package/dist/stores.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BetterAuthOptions } from '@better-auth/core';
|
|
2
|
+
import type { DBAdapter } from '@better-auth/core/db/adapter';
|
|
3
|
+
import { type AxedaPersistence } from '@teamblind/axeda-core';
|
|
4
|
+
export interface BetterAuthPersistenceOptions {
|
|
5
|
+
/** Reloj para `createdAt` y `updatedAt`. Por defecto, la hora del sistema. */
|
|
6
|
+
readonly now?: () => Date;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Implementa los puertos de persistencia de Axeda sobre el adaptador de base de datos de
|
|
10
|
+
* Better Auth (`ctx.adapter`). Sirve para cualquier base que Better Auth soporte; las
|
|
11
|
+
* transacciones deben ser reales, algo que Axeda comprueba al arrancar.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createBetterAuthPersistence<Options extends BetterAuthOptions>(databaseAdapter: DBAdapter<Options>, options?: BetterAuthPersistenceOptions): AxedaPersistence;
|