@fonderie/auth 7.11.0 → 7.12.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/brain/outcomes.md +2 -2
- package/brain/signatures.md +4 -1
- package/dist/index.cjs +29 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +29 -6
- package/dist/index.js.map +1 -1
- package/dist/middlewares/index.cjs +11 -1
- package/dist/middlewares/index.cjs.map +1 -1
- package/dist/middlewares/index.js +11 -1
- package/dist/middlewares/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -230,8 +230,11 @@ declare function importUser(store: IStoreAdapter, user: IImportUser): Promise<{
|
|
|
230
230
|
|
|
231
231
|
interface IPurgeOptions {
|
|
232
232
|
olderThanDays: number;
|
|
233
|
+
bus?: {
|
|
234
|
+
emit(type: string, payload: unknown): Promise<void>;
|
|
235
|
+
} | undefined;
|
|
233
236
|
}
|
|
234
|
-
declare function purgeSoftDeletedUsers(store: IStoreAdapter, { olderThanDays }: IPurgeOptions): Promise<number>;
|
|
237
|
+
declare function purgeSoftDeletedUsers(store: IStoreAdapter, { olderThanDays, bus }: IPurgeOptions): Promise<number>;
|
|
235
238
|
interface IUserRetentionScheduleOptions extends IPurgeOptions {
|
|
236
239
|
intervalMs?: number;
|
|
237
240
|
onPurge?: (deleted: number) => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -230,8 +230,11 @@ declare function importUser(store: IStoreAdapter, user: IImportUser): Promise<{
|
|
|
230
230
|
|
|
231
231
|
interface IPurgeOptions {
|
|
232
232
|
olderThanDays: number;
|
|
233
|
+
bus?: {
|
|
234
|
+
emit(type: string, payload: unknown): Promise<void>;
|
|
235
|
+
} | undefined;
|
|
233
236
|
}
|
|
234
|
-
declare function purgeSoftDeletedUsers(store: IStoreAdapter, { olderThanDays }: IPurgeOptions): Promise<number>;
|
|
237
|
+
declare function purgeSoftDeletedUsers(store: IStoreAdapter, { olderThanDays, bus }: IPurgeOptions): Promise<number>;
|
|
235
238
|
interface IUserRetentionScheduleOptions extends IPurgeOptions {
|
|
236
239
|
intervalMs?: number;
|
|
237
240
|
onPurge?: (deleted: number) => void;
|
package/dist/index.js
CHANGED
|
@@ -275,6 +275,8 @@ var MESSAGE_KEYS = {
|
|
|
275
275
|
var EVENT_KEYS = {
|
|
276
276
|
userRegistered: "fonderie.user.registered",
|
|
277
277
|
userDeleted: "fonderie.user.deleted",
|
|
278
|
+
// Emitted by purgeSoftDeletedUsers (given a bus) once the row is hard-deleted.
|
|
279
|
+
userPurged: "fonderie.user.purged",
|
|
278
280
|
emailVerified: "fonderie.user.email_verified",
|
|
279
281
|
passwordChanged: "fonderie.user.password_changed"
|
|
280
282
|
};
|
|
@@ -548,7 +550,7 @@ var UserModel = class {
|
|
|
548
550
|
async list(query = {}) {
|
|
549
551
|
const limit = Math.min(query.limit ?? 50, MAX_LIST_LIMIT);
|
|
550
552
|
const params = [];
|
|
551
|
-
const where = ["deleted_at IS NULL"];
|
|
553
|
+
const where = [query.deleted ? "deleted_at IS NOT NULL" : "deleted_at IS NULL"];
|
|
552
554
|
if (query.cursor) {
|
|
553
555
|
params.push(query.cursor.createdAt, query.cursor.id);
|
|
554
556
|
where.push(`(created_at, id) < ($${params.length - 1}::timestamptz, $${params.length}::uuid)`);
|
|
@@ -564,6 +566,16 @@ var UserModel = class {
|
|
|
564
566
|
);
|
|
565
567
|
return { users: rows.slice(0, limit), hasMore: rows.length > limit };
|
|
566
568
|
}
|
|
569
|
+
// For operator views only: a soft-deleted account still resolves, with
|
|
570
|
+
// deletedAt set, so the console can say "deleted on …" instead of "no such
|
|
571
|
+
// user". Nothing that authenticates or acts on an account may use this.
|
|
572
|
+
async findByIdIncludingDeleted(id) {
|
|
573
|
+
const [row] = await this.store.query(
|
|
574
|
+
`SELECT ${USER_COLUMNS} FROM fonderie_users WHERE id = $1`,
|
|
575
|
+
[id]
|
|
576
|
+
);
|
|
577
|
+
return row ?? null;
|
|
578
|
+
}
|
|
567
579
|
async findById(id) {
|
|
568
580
|
const [row] = await this.store.query(
|
|
569
581
|
`SELECT ${USER_COLUMNS} FROM fonderie_users WHERE id = $1 AND deleted_at IS NULL`,
|
|
@@ -3381,7 +3393,12 @@ function adminRouteTable(store) {
|
|
|
3381
3393
|
const cursor = cursorParam ? decodeLoginCursor(cursorParam) : null;
|
|
3382
3394
|
if (cursorParam && !cursor)
|
|
3383
3395
|
return setApiResponse7(HTTP7.UNPROCESSABLE, "INVALID_PARAMETER", "Invalid cursor");
|
|
3384
|
-
const
|
|
3396
|
+
const deleted = params.get("deleted") === "1" || params.get("deleted") === "true";
|
|
3397
|
+
const page = await users.list({
|
|
3398
|
+
limit,
|
|
3399
|
+
...cursor ? { cursor } : {},
|
|
3400
|
+
...deleted ? { deleted } : {}
|
|
3401
|
+
});
|
|
3385
3402
|
return setApiResponse7(HTTP7.OK, "USERS", "Users", toAdminUserPageDTO(page));
|
|
3386
3403
|
}
|
|
3387
3404
|
],
|
|
@@ -3389,7 +3406,7 @@ function adminRouteTable(store) {
|
|
|
3389
3406
|
"GET",
|
|
3390
3407
|
"/_admin/users/:id",
|
|
3391
3408
|
async (ctx) => {
|
|
3392
|
-
const user = await users.
|
|
3409
|
+
const user = await users.findByIdIncludingDeleted(idOf(ctx));
|
|
3393
3410
|
return user ? setApiResponse7(HTTP7.OK, "USER", "User", toAdminUserDTO(user)) : NOT_FOUND();
|
|
3394
3411
|
}
|
|
3395
3412
|
],
|
|
@@ -3468,7 +3485,7 @@ var AuthModule = class {
|
|
|
3468
3485
|
name = "@fonderie/auth";
|
|
3469
3486
|
// Baked in at build time by tsup.base, so the operator's Modules page can
|
|
3470
3487
|
// say what is actually deployed rather than 'not reported'.
|
|
3471
|
-
version = "7.
|
|
3488
|
+
version = "7.12.0";
|
|
3472
3489
|
// Users, sessions, login history, suspend — only through @fonderie/admin.
|
|
3473
3490
|
describeAdmin() {
|
|
3474
3491
|
return { routes: describeAuthAdminRoutes(this.store) };
|
|
@@ -3699,7 +3716,7 @@ async function importUser(store, user) {
|
|
|
3699
3716
|
}
|
|
3700
3717
|
|
|
3701
3718
|
// src/services/retention.ts
|
|
3702
|
-
async function purgeSoftDeletedUsers(store, { olderThanDays }) {
|
|
3719
|
+
async function purgeSoftDeletedUsers(store, { olderThanDays, bus }) {
|
|
3703
3720
|
if (!Number.isFinite(olderThanDays) || olderThanDays < 0) {
|
|
3704
3721
|
throw new Error("[auth] purgeSoftDeletedUsers: olderThanDays must be a non-negative number");
|
|
3705
3722
|
}
|
|
@@ -3710,6 +3727,9 @@ async function purgeSoftDeletedUsers(store, { olderThanDays }) {
|
|
|
3710
3727
|
RETURNING id`,
|
|
3711
3728
|
[olderThanDays]
|
|
3712
3729
|
);
|
|
3730
|
+
if (bus) {
|
|
3731
|
+
for (const { id } of rows) await bus.emit("fonderie.user.purged", { userId: id });
|
|
3732
|
+
}
|
|
3713
3733
|
return rows.length;
|
|
3714
3734
|
}
|
|
3715
3735
|
function startUserRetention(store, options) {
|
|
@@ -3718,7 +3738,10 @@ function startUserRetention(store, options) {
|
|
|
3718
3738
|
const run = async () => {
|
|
3719
3739
|
if (stopped) return;
|
|
3720
3740
|
try {
|
|
3721
|
-
const deleted = await purgeSoftDeletedUsers(store, {
|
|
3741
|
+
const deleted = await purgeSoftDeletedUsers(store, {
|
|
3742
|
+
olderThanDays: options.olderThanDays,
|
|
3743
|
+
...options.bus ? { bus: options.bus } : {}
|
|
3744
|
+
});
|
|
3722
3745
|
options.onPurge?.(deleted);
|
|
3723
3746
|
} catch (err) {
|
|
3724
3747
|
console.error("[auth] scheduled user retention purge failed:", err);
|