@byline/db-postgres 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +18 -0
  3. package/dist/database/schema/auth.d.ts +857 -0
  4. package/dist/database/schema/auth.d.ts.map +1 -0
  5. package/dist/database/schema/auth.js +176 -0
  6. package/dist/database/schema/auth.js.map +1 -0
  7. package/dist/database/schema/index.d.ts +2955 -0
  8. package/dist/database/schema/index.d.ts.map +1 -0
  9. package/dist/database/schema/index.js +500 -0
  10. package/dist/database/schema/index.js.map +1 -0
  11. package/dist/index.d.ts +31 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +30 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/lib/test-helper.d.ts +17 -0
  16. package/dist/lib/test-helper.d.ts.map +1 -0
  17. package/dist/lib/test-helper.js +47 -0
  18. package/dist/lib/test-helper.js.map +1 -0
  19. package/dist/modules/admin/admin-permissions-repository.d.ts +17 -0
  20. package/dist/modules/admin/admin-permissions-repository.d.ts.map +1 -0
  21. package/dist/modules/admin/admin-permissions-repository.js +76 -0
  22. package/dist/modules/admin/admin-permissions-repository.js.map +1 -0
  23. package/dist/modules/admin/admin-roles-repository.d.ts +12 -0
  24. package/dist/modules/admin/admin-roles-repository.d.ts.map +1 -0
  25. package/dist/modules/admin/admin-roles-repository.js +168 -0
  26. package/dist/modules/admin/admin-roles-repository.js.map +1 -0
  27. package/dist/modules/admin/admin-store.d.ts +20 -0
  28. package/dist/modules/admin/admin-store.d.ts.map +1 -0
  29. package/dist/modules/admin/admin-store.js +28 -0
  30. package/dist/modules/admin/admin-store.js.map +1 -0
  31. package/dist/modules/admin/admin-users-repository.d.ts +12 -0
  32. package/dist/modules/admin/admin-users-repository.d.ts.map +1 -0
  33. package/dist/modules/admin/admin-users-repository.js +208 -0
  34. package/dist/modules/admin/admin-users-repository.js.map +1 -0
  35. package/dist/modules/admin/index.d.ts +27 -0
  36. package/dist/modules/admin/index.d.ts.map +1 -0
  37. package/dist/modules/admin/index.js +27 -0
  38. package/dist/modules/admin/index.js.map +1 -0
  39. package/dist/modules/admin/refresh-tokens-repository.d.ts +16 -0
  40. package/dist/modules/admin/refresh-tokens-repository.d.ts.map +1 -0
  41. package/dist/modules/admin/refresh-tokens-repository.js +132 -0
  42. package/dist/modules/admin/refresh-tokens-repository.js.map +1 -0
  43. package/dist/modules/admin/tests/auth-integration.test.d.ts +9 -0
  44. package/dist/modules/admin/tests/auth-integration.test.d.ts.map +1 -0
  45. package/dist/modules/admin/tests/auth-integration.test.js +392 -0
  46. package/dist/modules/admin/tests/auth-integration.test.js.map +1 -0
  47. package/dist/modules/admin/tests/session-provider.test.d.ts +9 -0
  48. package/dist/modules/admin/tests/session-provider.test.d.ts.map +1 -0
  49. package/dist/modules/admin/tests/session-provider.test.js +370 -0
  50. package/dist/modules/admin/tests/session-provider.test.js.map +1 -0
  51. package/dist/modules/storage/@types.d.ts +116 -0
  52. package/dist/modules/storage/@types.d.ts.map +1 -0
  53. package/dist/modules/storage/@types.js +9 -0
  54. package/dist/modules/storage/@types.js.map +1 -0
  55. package/dist/modules/storage/storage-commands.d.ts +136 -0
  56. package/dist/modules/storage/storage-commands.d.ts.map +1 -0
  57. package/dist/modules/storage/storage-commands.js +272 -0
  58. package/dist/modules/storage/storage-commands.js.map +1 -0
  59. package/dist/modules/storage/storage-flatten.d.ts +19 -0
  60. package/dist/modules/storage/storage-flatten.d.ts.map +1 -0
  61. package/dist/modules/storage/storage-flatten.js +261 -0
  62. package/dist/modules/storage/storage-flatten.js.map +1 -0
  63. package/dist/modules/storage/storage-insert.d.ts +22 -0
  64. package/dist/modules/storage/storage-insert.d.ts.map +1 -0
  65. package/dist/modules/storage/storage-insert.js +115 -0
  66. package/dist/modules/storage/storage-insert.js.map +1 -0
  67. package/dist/modules/storage/storage-queries.d.ts +377 -0
  68. package/dist/modules/storage/storage-queries.d.ts.map +1 -0
  69. package/dist/modules/storage/storage-queries.js +976 -0
  70. package/dist/modules/storage/storage-queries.js.map +1 -0
  71. package/dist/modules/storage/storage-restore.d.ts +19 -0
  72. package/dist/modules/storage/storage-restore.d.ts.map +1 -0
  73. package/dist/modules/storage/storage-restore.js +350 -0
  74. package/dist/modules/storage/storage-restore.js.map +1 -0
  75. package/dist/modules/storage/storage-store-manifest.d.ts +71 -0
  76. package/dist/modules/storage/storage-store-manifest.d.ts.map +1 -0
  77. package/dist/modules/storage/storage-store-manifest.js +294 -0
  78. package/dist/modules/storage/storage-store-manifest.js.map +1 -0
  79. package/dist/modules/storage/storage-utils.d.ts +23 -0
  80. package/dist/modules/storage/storage-utils.d.ts.map +1 -0
  81. package/dist/modules/storage/storage-utils.js +72 -0
  82. package/dist/modules/storage/storage-utils.js.map +1 -0
  83. package/dist/modules/storage/tests/storage-field-types.test.d.ts +9 -0
  84. package/dist/modules/storage/tests/storage-field-types.test.d.ts.map +1 -0
  85. package/dist/modules/storage/tests/storage-field-types.test.js +146 -0
  86. package/dist/modules/storage/tests/storage-field-types.test.js.map +1 -0
  87. package/dist/modules/storage/tests/storage-flatten-reconstruct.test.d.ts +9 -0
  88. package/dist/modules/storage/tests/storage-flatten-reconstruct.test.d.ts.map +1 -0
  89. package/dist/modules/storage/tests/storage-flatten-reconstruct.test.js +327 -0
  90. package/dist/modules/storage/tests/storage-flatten-reconstruct.test.js.map +1 -0
  91. package/dist/modules/storage/tests/storage-store-manifest.test.d.ts +9 -0
  92. package/dist/modules/storage/tests/storage-store-manifest.test.d.ts.map +1 -0
  93. package/dist/modules/storage/tests/storage-store-manifest.test.js +141 -0
  94. package/dist/modules/storage/tests/storage-store-manifest.test.js.map +1 -0
  95. package/dist/modules/storage/tests/storage-versioning.test.d.ts +9 -0
  96. package/dist/modules/storage/tests/storage-versioning.test.d.ts.map +1 -0
  97. package/dist/modules/storage/tests/storage-versioning.test.js +336 -0
  98. package/dist/modules/storage/tests/storage-versioning.test.js.map +1 -0
  99. package/package.json +81 -0
@@ -0,0 +1,47 @@
1
+ import { drizzle } from 'drizzle-orm/node-postgres';
2
+ import pg from 'pg';
3
+ import * as schema from '../database/schema/index.js';
4
+ import { createCommandBuilders } from '../modules/storage/storage-commands.js';
5
+ import { createQueryBuilders } from '../modules/storage/storage-queries.js';
6
+ let pool;
7
+ let db;
8
+ let commandBuilders;
9
+ let queryBuilders;
10
+ export function setupTestDB(collections = []) {
11
+ if (!pool) {
12
+ pool = new pg.Pool({
13
+ connectionString: process.env.POSTGRES_CONNECTION_STRING,
14
+ // Integration tests share the dev database with the running webapp,
15
+ // and node:test may run multiple test files in separate processes.
16
+ // A pool-per-file of 20 connections × N files + the webapp's own
17
+ // pool of 20 blows past Postgres's default `max_connections=100`
18
+ // and throws `FATAL: sorry, too many clients already`. The tests
19
+ // are serial and run one query at a time, so a small pool is
20
+ // sufficient — keep total test connections low regardless of
21
+ // process / file parallelism.
22
+ max: 4,
23
+ idleTimeoutMillis: 2000,
24
+ connectionTimeoutMillis: 1000,
25
+ });
26
+ }
27
+ if (!db) {
28
+ db = drizzle(pool, { schema });
29
+ }
30
+ if (!commandBuilders) {
31
+ commandBuilders = createCommandBuilders(db);
32
+ }
33
+ // Recreate queryBuilders when collections are provided so that
34
+ // DocumentQueries can resolve collection definitions by path.
35
+ queryBuilders = createQueryBuilders(db, collections);
36
+ return { pool, db, commandBuilders, queryBuilders };
37
+ }
38
+ export async function teardownTestDB() {
39
+ if (pool) {
40
+ await pool.end();
41
+ pool = undefined;
42
+ db = undefined;
43
+ commandBuilders = undefined;
44
+ queryBuilders = undefined;
45
+ }
46
+ }
47
+ //# sourceMappingURL=test-helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-helper.js","sourceRoot":"","sources":["../../src/lib/test-helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAuB,MAAM,2BAA2B,CAAA;AACxE,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,OAAO,KAAK,MAAM,MAAM,6BAA6B,CAAA;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAA;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAA;AAE3E,IAAI,IAAa,CAAA;AACjB,IAAI,EAAiC,CAAA;AACrC,IAAI,eAAyD,CAAA;AAC7D,IAAI,aAAqD,CAAA;AAEzD,MAAM,UAAU,WAAW,CAAC,cAAsC,EAAE;IAClE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC;YACjB,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B;YACxD,oEAAoE;YACpE,mEAAmE;YACnE,iEAAiE;YACjE,iEAAiE;YACjE,iEAAiE;YACjE,6DAA6D;YAC7D,6DAA6D;YAC7D,8BAA8B;YAC9B,GAAG,EAAE,CAAC;YACN,iBAAiB,EAAE,IAAI;YACvB,uBAAuB,EAAE,IAAI;SAC9B,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;IAChC,CAAC;IAED,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,eAAe,GAAG,qBAAqB,CAAC,EAAE,CAAC,CAAA;IAC7C,CAAC;IAED,+DAA+D;IAC/D,8DAA8D;IAC9D,aAAa,GAAG,mBAAmB,CAAC,EAAE,EAAE,WAAW,CAAC,CAAA;IAEpD,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,eAAe,EAAE,aAAa,EAAE,CAAA;AACrD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,IAAI,CAAC,GAAG,EAAE,CAAA;QAChB,IAAI,GAAG,SAAgB,CAAA;QACvB,EAAE,GAAG,SAAgB,CAAA;QACrB,eAAe,GAAG,SAAgB,CAAA;QAClC,aAAa,GAAG,SAAgB,CAAA;IAClC,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import type { AdminPermissionsRepository } from '@byline/admin/admin-permissions';
9
+ import type { NodePgDatabase } from 'drizzle-orm/node-postgres';
10
+ import type * as schema from '../../database/schema/index.js';
11
+ /**
12
+ * Postgres implementation of `AdminPermissionsRepository` — per-role
13
+ * ability grants and the distinct-abilities-for-user join that drives
14
+ * `resolveActor()`.
15
+ */
16
+ export declare function createAdminPermissionsRepository(db: NodePgDatabase<typeof schema>): AdminPermissionsRepository;
17
+ //# sourceMappingURL=admin-permissions-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-permissions-repository.d.ts","sourceRoot":"","sources":["../../../src/modules/admin/admin-permissions-repository.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAA;AAEjF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAI/D,OAAO,KAAK,KAAK,MAAM,MAAM,gCAAgC,CAAA;AAE7D;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,EAAE,EAAE,cAAc,CAAC,OAAO,MAAM,CAAC,GAChC,0BAA0B,CAwE5B"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { and, eq } from 'drizzle-orm';
9
+ import { v7 as uuidv7 } from 'uuid';
10
+ import { adminPermissions, adminRoleAdminUser } from '../../database/schema/auth.js';
11
+ /**
12
+ * Postgres implementation of `AdminPermissionsRepository` — per-role
13
+ * ability grants and the distinct-abilities-for-user join that drives
14
+ * `resolveActor()`.
15
+ */
16
+ export function createAdminPermissionsRepository(db) {
17
+ return {
18
+ async grantAbility(roleId, ability) {
19
+ await db
20
+ .insert(adminPermissions)
21
+ .values({ id: uuidv7(), admin_role_id: roleId, ability })
22
+ .onConflictDoNothing({
23
+ target: [adminPermissions.admin_role_id, adminPermissions.ability],
24
+ });
25
+ },
26
+ async revokeAbility(roleId, ability) {
27
+ await db
28
+ .delete(adminPermissions)
29
+ .where(and(eq(adminPermissions.admin_role_id, roleId), eq(adminPermissions.ability, ability)));
30
+ },
31
+ async listAbilities(roleId) {
32
+ const rows = await db
33
+ .select({ ability: adminPermissions.ability })
34
+ .from(adminPermissions)
35
+ .where(eq(adminPermissions.admin_role_id, roleId));
36
+ return rows.map((r) => r.ability);
37
+ },
38
+ async setAbilities(roleId, abilities) {
39
+ await db.transaction(async (tx) => {
40
+ await tx.delete(adminPermissions).where(eq(adminPermissions.admin_role_id, roleId));
41
+ if (abilities.length === 0)
42
+ return;
43
+ const rows = abilities.map((ability) => ({
44
+ id: uuidv7(),
45
+ admin_role_id: roleId,
46
+ ability,
47
+ }));
48
+ await tx.insert(adminPermissions).values(rows);
49
+ });
50
+ },
51
+ async listAbilitiesForUser(userId) {
52
+ const rows = await db
53
+ .selectDistinct({ ability: adminPermissions.ability })
54
+ .from(adminPermissions)
55
+ .innerJoin(adminRoleAdminUser, eq(adminRoleAdminUser.admin_role_id, adminPermissions.admin_role_id))
56
+ .where(eq(adminRoleAdminUser.admin_user_id, userId));
57
+ return rows.map((r) => r.ability);
58
+ },
59
+ async listRolesForAbility(ability) {
60
+ const rows = await db
61
+ .select({ admin_role_id: adminPermissions.admin_role_id })
62
+ .from(adminPermissions)
63
+ .where(eq(adminPermissions.ability, ability));
64
+ return rows.map((r) => r.admin_role_id);
65
+ },
66
+ async listUsersForAbility(ability) {
67
+ const rows = await db
68
+ .selectDistinct({ admin_user_id: adminRoleAdminUser.admin_user_id })
69
+ .from(adminRoleAdminUser)
70
+ .innerJoin(adminPermissions, eq(adminPermissions.admin_role_id, adminRoleAdminUser.admin_role_id))
71
+ .where(eq(adminPermissions.ability, ability));
72
+ return rows.map((r) => r.admin_user_id);
73
+ },
74
+ };
75
+ }
76
+ //# sourceMappingURL=admin-permissions-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-permissions-repository.js","sourceRoot":"","sources":["../../../src/modules/admin/admin-permissions-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { type AdminRolesRepository } from '@byline/admin/admin-roles';
9
+ import type { NodePgDatabase } from 'drizzle-orm/node-postgres';
10
+ import type * as schema from '../../database/schema/index.js';
11
+ export declare function createAdminRolesRepository(db: NodePgDatabase<typeof schema>): AdminRolesRepository;
12
+ //# sourceMappingURL=admin-roles-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-roles-repository.d.ts","sourceRoot":"","sources":["../../../src/modules/admin/admin-roles-repository.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,2BAA2B,CAAA;AAElC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAI/D,OAAO,KAAK,KAAK,MAAM,MAAM,gCAAgC,CAAA;AAwB7D,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,cAAc,CAAC,OAAO,MAAM,CAAC,GAChC,oBAAoB,CAkJtB"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { ERR_ADMIN_ROLE_VERSION_CONFLICT, } from '@byline/admin/admin-roles';
9
+ import { and, asc, eq, sql } from 'drizzle-orm';
10
+ import { v7 as uuidv7 } from 'uuid';
11
+ import { adminRoleAdminUser, adminRoles } from '../../database/schema/auth.js';
12
+ /**
13
+ * Postgres implementation of `AdminRolesRepository` — role CRUD,
14
+ * reorder, and role ↔ user assignments. Ability grants live on
15
+ * `AdminPermissionsRepository` (see `admin-permissions-repository.ts`).
16
+ *
17
+ * Optimistic-concurrency writes (`update`, `delete`) gate on
18
+ * `WHERE id = $id AND vid = $expected` — zero rows means another writer
19
+ * bumped the row first; throw `VERSION_CONFLICT`. Reorder is vid-less
20
+ * (see contract docs) and runs as a single transaction.
21
+ */
22
+ const PUBLIC_ROLE_COLUMNS = {
23
+ id: adminRoles.id,
24
+ vid: adminRoles.vid,
25
+ name: adminRoles.name,
26
+ machine_name: adminRoles.machine_name,
27
+ description: adminRoles.description,
28
+ order: adminRoles.order,
29
+ created_at: adminRoles.created_at,
30
+ updated_at: adminRoles.updated_at,
31
+ };
32
+ export function createAdminRolesRepository(db) {
33
+ return {
34
+ // -----------------------------------------------------------------
35
+ // Role CRUD
36
+ // -----------------------------------------------------------------
37
+ async create(input) {
38
+ const [row] = await db
39
+ .insert(adminRoles)
40
+ .values({
41
+ id: uuidv7(),
42
+ name: input.name,
43
+ machine_name: input.machine_name,
44
+ description: input.description ?? null,
45
+ order: input.order ?? 0,
46
+ })
47
+ .returning(PUBLIC_ROLE_COLUMNS);
48
+ if (!row)
49
+ throw new Error('createAdminRole: insert returned no row');
50
+ return row;
51
+ },
52
+ async getById(id) {
53
+ const [row] = await db
54
+ .select(PUBLIC_ROLE_COLUMNS)
55
+ .from(adminRoles)
56
+ .where(eq(adminRoles.id, id));
57
+ return row ?? null;
58
+ },
59
+ async getByMachineName(machineName) {
60
+ const [row] = await db
61
+ .select(PUBLIC_ROLE_COLUMNS)
62
+ .from(adminRoles)
63
+ .where(eq(adminRoles.machine_name, machineName));
64
+ return row ?? null;
65
+ },
66
+ async list() {
67
+ return db
68
+ .select(PUBLIC_ROLE_COLUMNS)
69
+ .from(adminRoles)
70
+ .orderBy(asc(adminRoles.order), asc(adminRoles.created_at));
71
+ },
72
+ async update(id, expectedVid, patch) {
73
+ const updateSet = {
74
+ updated_at: new Date(),
75
+ vid: sql `${adminRoles.vid} + 1`,
76
+ };
77
+ if (patch.name !== undefined)
78
+ updateSet.name = patch.name;
79
+ if (patch.description !== undefined)
80
+ updateSet.description = patch.description;
81
+ if (patch.order !== undefined)
82
+ updateSet.order = patch.order;
83
+ const [row] = await db
84
+ .update(adminRoles)
85
+ .set(updateSet)
86
+ .where(and(eq(adminRoles.id, id), eq(adminRoles.vid, expectedVid)))
87
+ .returning(PUBLIC_ROLE_COLUMNS);
88
+ if (!row)
89
+ throw ERR_ADMIN_ROLE_VERSION_CONFLICT();
90
+ return row;
91
+ },
92
+ async delete(id, expectedVid) {
93
+ // Cascades remove role ↔ user assignments and per-role permissions.
94
+ const result = await db
95
+ .delete(adminRoles)
96
+ .where(and(eq(adminRoles.id, id), eq(adminRoles.vid, expectedVid)))
97
+ .returning({ id: adminRoles.id });
98
+ if (result.length === 0)
99
+ throw ERR_ADMIN_ROLE_VERSION_CONFLICT();
100
+ },
101
+ async reorder(ids) {
102
+ if (ids.length === 0)
103
+ return;
104
+ // Single transaction so the list is never observed half-reordered.
105
+ // No vid gate: see `AdminRolesRepository.reorder` contract docs.
106
+ await db.transaction(async (tx) => {
107
+ const now = new Date();
108
+ for (let i = 0; i < ids.length; i++) {
109
+ await tx
110
+ .update(adminRoles)
111
+ .set({
112
+ order: i,
113
+ updated_at: now,
114
+ vid: sql `${adminRoles.vid} + 1`,
115
+ })
116
+ .where(eq(adminRoles.id, ids[i]));
117
+ }
118
+ });
119
+ },
120
+ // -----------------------------------------------------------------
121
+ // Role ↔ user assignments
122
+ // -----------------------------------------------------------------
123
+ async assignToUser(roleId, userId) {
124
+ await db
125
+ .insert(adminRoleAdminUser)
126
+ .values({ admin_role_id: roleId, admin_user_id: userId })
127
+ .onConflictDoNothing({
128
+ target: [adminRoleAdminUser.admin_role_id, adminRoleAdminUser.admin_user_id],
129
+ });
130
+ },
131
+ async unassignFromUser(roleId, userId) {
132
+ await db
133
+ .delete(adminRoleAdminUser)
134
+ .where(and(eq(adminRoleAdminUser.admin_role_id, roleId), eq(adminRoleAdminUser.admin_user_id, userId)));
135
+ },
136
+ async listRolesForUser(userId) {
137
+ const rows = await db
138
+ .select(PUBLIC_ROLE_COLUMNS)
139
+ .from(adminRoles)
140
+ .innerJoin(adminRoleAdminUser, eq(adminRoleAdminUser.admin_role_id, adminRoles.id))
141
+ .where(eq(adminRoleAdminUser.admin_user_id, userId))
142
+ .orderBy(asc(adminRoles.order));
143
+ return rows;
144
+ },
145
+ async listUsersForRole(roleId) {
146
+ const rows = await db
147
+ .select({ admin_user_id: adminRoleAdminUser.admin_user_id })
148
+ .from(adminRoleAdminUser)
149
+ .where(eq(adminRoleAdminUser.admin_role_id, roleId));
150
+ return rows.map((r) => r.admin_user_id);
151
+ },
152
+ async setRolesForUser(userId, roleIds) {
153
+ // Single transaction — user assignments are never observed
154
+ // half-edited. Symmetric to AdminPermissionsRepository.setAbilities.
155
+ await db.transaction(async (tx) => {
156
+ await tx.delete(adminRoleAdminUser).where(eq(adminRoleAdminUser.admin_user_id, userId));
157
+ if (roleIds.length === 0)
158
+ return;
159
+ const rows = roleIds.map((admin_role_id) => ({
160
+ admin_role_id,
161
+ admin_user_id: userId,
162
+ }));
163
+ await tx.insert(adminRoleAdminUser).values(rows);
164
+ });
165
+ },
166
+ };
167
+ }
168
+ //# sourceMappingURL=admin-roles-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-roles-repository.js","sourceRoot":"","sources":["../../../src/modules/admin/admin-roles-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import type { AdminStore } from '@byline/admin';
9
+ import type { NodePgDatabase } from 'drizzle-orm/node-postgres';
10
+ import type * as schema from '../../database/schema/index.js';
11
+ /**
12
+ * Wire the four admin repositories against a Drizzle handle and return the
13
+ * `AdminStore` bundle expected by `@byline/admin` — specifically by the
14
+ * built-in `JwtSessionProvider`, by `seedSuperAdmin`, and (later) by the
15
+ * admin-user / admin-role commands.
16
+ *
17
+ * Construct once per process, alongside the `pgAdapter` call.
18
+ */
19
+ export declare function createAdminStore(db: NodePgDatabase<typeof schema>): AdminStore;
20
+ //# sourceMappingURL=admin-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-store.d.ts","sourceRoot":"","sources":["../../../src/modules/admin/admin-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAM/D,OAAO,KAAK,KAAK,MAAM,MAAM,gCAAgC,CAAA;AAE7D;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,cAAc,CAAC,OAAO,MAAM,CAAC,GAAG,UAAU,CAO9E"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { createAdminPermissionsRepository } from './admin-permissions-repository.js';
9
+ import { createAdminRolesRepository } from './admin-roles-repository.js';
10
+ import { createAdminUsersRepository } from './admin-users-repository.js';
11
+ import { createRefreshTokensRepository } from './refresh-tokens-repository.js';
12
+ /**
13
+ * Wire the four admin repositories against a Drizzle handle and return the
14
+ * `AdminStore` bundle expected by `@byline/admin` — specifically by the
15
+ * built-in `JwtSessionProvider`, by `seedSuperAdmin`, and (later) by the
16
+ * admin-user / admin-role commands.
17
+ *
18
+ * Construct once per process, alongside the `pgAdapter` call.
19
+ */
20
+ export function createAdminStore(db) {
21
+ return {
22
+ adminUsers: createAdminUsersRepository(db),
23
+ adminRoles: createAdminRolesRepository(db),
24
+ adminPermissions: createAdminPermissionsRepository(db),
25
+ refreshTokens: createRefreshTokensRepository(db),
26
+ };
27
+ }
28
+ //# sourceMappingURL=admin-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-store.js","sourceRoot":"","sources":["../../../src/modules/admin/admin-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EAAE,gCAAgC,EAAE,MAAM,mCAAmC,CAAA;AACpF,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AACxE,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AACxE,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAA;AAG9E;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAiC;IAChE,OAAO;QACL,UAAU,EAAE,0BAA0B,CAAC,EAAE,CAAC;QAC1C,UAAU,EAAE,0BAA0B,CAAC,EAAE,CAAC;QAC1C,gBAAgB,EAAE,gCAAgC,CAAC,EAAE,CAAC;QACtD,aAAa,EAAE,6BAA6B,CAAC,EAAE,CAAC;KACjD,CAAA;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { type AdminUsersRepository } from '@byline/admin/admin-users';
9
+ import type { NodePgDatabase } from 'drizzle-orm/node-postgres';
10
+ import type * as schema from '../../database/schema/index.js';
11
+ export declare function createAdminUsersRepository(db: NodePgDatabase<typeof schema>): AdminUsersRepository;
12
+ //# sourceMappingURL=admin-users-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-users-repository.d.ts","sourceRoot":"","sources":["../../../src/modules/admin/admin-users-repository.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,2BAA2B,CAAA;AAElC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAI/D,OAAO,KAAK,KAAK,MAAM,MAAM,gCAAgC,CAAA;AA+C7D,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,cAAc,CAAC,OAAO,MAAM,CAAC,GAChC,oBAAoB,CA2KtB"}
@@ -0,0 +1,208 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { ERR_ADMIN_USER_VERSION_CONFLICT, } from '@byline/admin/admin-users';
9
+ import { and, asc, desc, eq, ilike, or, sql } from 'drizzle-orm';
10
+ import { v7 as uuidv7 } from 'uuid';
11
+ import { adminUsers } from '../../database/schema/auth.js';
12
+ /**
13
+ * Postgres implementation of `AdminUsersRepository`.
14
+ *
15
+ * The DB column for the password hash is `password`; the public interface
16
+ * exposes it as `password_hash`. The mapping happens entirely inside this
17
+ * factory — callers speak the interface shape and never see the column
18
+ * name.
19
+ *
20
+ * Password hashing is *not* done here — the interface takes a pre-hashed
21
+ * PHC string. Callers (seed, admin-user commands) hash first via
22
+ * `hashPassword` from `@byline/admin/auth`.
23
+ *
24
+ * Optimistic-concurrency writes (`update`, `setPasswordHash`, `delete`)
25
+ * guard the `UPDATE ... WHERE id = $id AND vid = $expected` pattern —
26
+ * zero rows returned means another writer bumped the row first; throw
27
+ * `VERSION_CONFLICT`.
28
+ */
29
+ const PUBLIC_COLUMNS = {
30
+ id: adminUsers.id,
31
+ vid: adminUsers.vid,
32
+ given_name: adminUsers.given_name,
33
+ family_name: adminUsers.family_name,
34
+ username: adminUsers.username,
35
+ email: adminUsers.email,
36
+ remember_me: adminUsers.remember_me,
37
+ last_login: adminUsers.last_login,
38
+ last_login_ip: adminUsers.last_login_ip,
39
+ failed_login_attempts: adminUsers.failed_login_attempts,
40
+ is_super_admin: adminUsers.is_super_admin,
41
+ is_enabled: adminUsers.is_enabled,
42
+ is_email_verified: adminUsers.is_email_verified,
43
+ created_at: adminUsers.created_at,
44
+ updated_at: adminUsers.updated_at,
45
+ };
46
+ const ORDER_COLUMN = {
47
+ given_name: adminUsers.given_name,
48
+ family_name: adminUsers.family_name,
49
+ email: adminUsers.email,
50
+ username: adminUsers.username,
51
+ created_at: adminUsers.created_at,
52
+ updated_at: adminUsers.updated_at,
53
+ };
54
+ export function createAdminUsersRepository(db) {
55
+ return {
56
+ async create(input) {
57
+ const [row] = await db
58
+ .insert(adminUsers)
59
+ .values({
60
+ id: uuidv7(),
61
+ email: input.email.toLowerCase(),
62
+ password: input.password_hash,
63
+ given_name: input.given_name ?? null,
64
+ family_name: input.family_name ?? null,
65
+ username: input.username ?? null,
66
+ is_super_admin: input.is_super_admin ?? false,
67
+ is_enabled: input.is_enabled ?? false,
68
+ is_email_verified: input.is_email_verified ?? false,
69
+ })
70
+ .returning(PUBLIC_COLUMNS);
71
+ if (!row)
72
+ throw new Error('createAdminUser: insert returned no row');
73
+ return row;
74
+ },
75
+ async getById(id) {
76
+ const [row] = await db.select(PUBLIC_COLUMNS).from(adminUsers).where(eq(adminUsers.id, id));
77
+ return row ?? null;
78
+ },
79
+ async getByEmail(email) {
80
+ const [row] = await db
81
+ .select(PUBLIC_COLUMNS)
82
+ .from(adminUsers)
83
+ .where(eq(adminUsers.email, email.toLowerCase()));
84
+ return row ?? null;
85
+ },
86
+ async getByUsername(username) {
87
+ const [row] = await db
88
+ .select(PUBLIC_COLUMNS)
89
+ .from(adminUsers)
90
+ .where(eq(adminUsers.username, username));
91
+ return row ?? null;
92
+ },
93
+ async getByEmailForSignIn(email) {
94
+ const [row] = await db
95
+ .select({ ...PUBLIC_COLUMNS, password_hash: adminUsers.password })
96
+ .from(adminUsers)
97
+ .where(eq(adminUsers.email, email.toLowerCase()));
98
+ return row ?? null;
99
+ },
100
+ async getByIdForSignIn(id) {
101
+ const [row] = await db
102
+ .select({ ...PUBLIC_COLUMNS, password_hash: adminUsers.password })
103
+ .from(adminUsers)
104
+ .where(eq(adminUsers.id, id));
105
+ return row ?? null;
106
+ },
107
+ async list(options) {
108
+ const needle = options.query?.trim();
109
+ const filter = needle && needle.length > 0
110
+ ? or(ilike(adminUsers.email, `%${needle}%`), ilike(adminUsers.given_name, `%${needle}%`), ilike(adminUsers.family_name, `%${needle}%`), ilike(adminUsers.username, `%${needle}%`))
111
+ : undefined;
112
+ const sortCol = ORDER_COLUMN[options.order];
113
+ const orderExpr = options.desc ? desc(sortCol) : asc(sortCol);
114
+ const offset = Math.max(0, (options.page - 1) * options.pageSize);
115
+ const query = db.select(PUBLIC_COLUMNS).from(adminUsers);
116
+ const filtered = filter ? query.where(filter) : query;
117
+ return filtered.orderBy(orderExpr).limit(options.pageSize).offset(offset);
118
+ },
119
+ async count(options) {
120
+ const needle = options?.query?.trim();
121
+ const filter = needle && needle.length > 0
122
+ ? or(ilike(adminUsers.email, `%${needle}%`), ilike(adminUsers.given_name, `%${needle}%`), ilike(adminUsers.family_name, `%${needle}%`), ilike(adminUsers.username, `%${needle}%`))
123
+ : undefined;
124
+ const base = db.select({ value: sql `count(*)::int` }).from(adminUsers);
125
+ const [row] = await (filter ? base.where(filter) : base);
126
+ return row?.value ?? 0;
127
+ },
128
+ async update(id, expectedVid, patch) {
129
+ const updateSet = {
130
+ updated_at: new Date(),
131
+ vid: sql `${adminUsers.vid} + 1`,
132
+ };
133
+ if (patch.given_name !== undefined)
134
+ updateSet.given_name = patch.given_name;
135
+ if (patch.family_name !== undefined)
136
+ updateSet.family_name = patch.family_name;
137
+ if (patch.username !== undefined)
138
+ updateSet.username = patch.username;
139
+ if (patch.email !== undefined)
140
+ updateSet.email = patch.email.toLowerCase();
141
+ if (patch.is_super_admin !== undefined)
142
+ updateSet.is_super_admin = patch.is_super_admin;
143
+ if (patch.is_enabled !== undefined)
144
+ updateSet.is_enabled = patch.is_enabled;
145
+ if (patch.is_email_verified !== undefined)
146
+ updateSet.is_email_verified = patch.is_email_verified;
147
+ if (patch.remember_me !== undefined)
148
+ updateSet.remember_me = patch.remember_me;
149
+ const [row] = await db
150
+ .update(adminUsers)
151
+ .set(updateSet)
152
+ .where(and(eq(adminUsers.id, id), eq(adminUsers.vid, expectedVid)))
153
+ .returning(PUBLIC_COLUMNS);
154
+ if (!row)
155
+ throw ERR_ADMIN_USER_VERSION_CONFLICT();
156
+ return row;
157
+ },
158
+ async setPasswordHash(id, expectedVid, passwordHash) {
159
+ const [row] = await db
160
+ .update(adminUsers)
161
+ .set({
162
+ password: passwordHash,
163
+ updated_at: new Date(),
164
+ vid: sql `${adminUsers.vid} + 1`,
165
+ })
166
+ .where(and(eq(adminUsers.id, id), eq(adminUsers.vid, expectedVid)))
167
+ .returning(PUBLIC_COLUMNS);
168
+ if (!row)
169
+ throw ERR_ADMIN_USER_VERSION_CONFLICT();
170
+ return row;
171
+ },
172
+ async setEnabled(id, enabled) {
173
+ await db
174
+ .update(adminUsers)
175
+ .set({ is_enabled: enabled, updated_at: new Date(), vid: sql `${adminUsers.vid} + 1` })
176
+ .where(eq(adminUsers.id, id));
177
+ },
178
+ async recordLoginSuccess(id, ip) {
179
+ await db
180
+ .update(adminUsers)
181
+ .set({
182
+ last_login: new Date(),
183
+ last_login_ip: ip,
184
+ failed_login_attempts: 0,
185
+ updated_at: new Date(),
186
+ })
187
+ .where(eq(adminUsers.id, id));
188
+ },
189
+ async recordLoginFailure(id) {
190
+ await db
191
+ .update(adminUsers)
192
+ .set({
193
+ failed_login_attempts: sql `${adminUsers.failed_login_attempts} + 1`,
194
+ updated_at: new Date(),
195
+ })
196
+ .where(eq(adminUsers.id, id));
197
+ },
198
+ async delete(id, expectedVid) {
199
+ const result = await db
200
+ .delete(adminUsers)
201
+ .where(and(eq(adminUsers.id, id), eq(adminUsers.vid, expectedVid)))
202
+ .returning({ id: adminUsers.id });
203
+ if (result.length === 0)
204
+ throw ERR_ADMIN_USER_VERSION_CONFLICT();
205
+ },
206
+ };
207
+ }
208
+ //# sourceMappingURL=admin-users-repository.js.map