@loomcore/api 0.1.42 → 0.1.43

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 (33) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +49 -49
  3. package/dist/__tests__/postgres-test-migrations/100-create-test-entities-table.migration.js +22 -22
  4. package/dist/__tests__/postgres-test-migrations/101-create-categories-table.migration.js +12 -12
  5. package/dist/__tests__/postgres-test-migrations/102-create-products-table.migration.js +21 -21
  6. package/dist/__tests__/postgres-test-migrations/103-create-test-items-table.migration.js +20 -20
  7. package/dist/__tests__/postgres.test-database.js +8 -8
  8. package/dist/databases/postgres/commands/postgres-batch-update.command.js +7 -7
  9. package/dist/databases/postgres/commands/postgres-create-many.command.js +10 -10
  10. package/dist/databases/postgres/commands/postgres-create.command.js +4 -4
  11. package/dist/databases/postgres/commands/postgres-full-update-by-id.command.js +13 -13
  12. package/dist/databases/postgres/commands/postgres-partial-update-by-id.command.js +7 -7
  13. package/dist/databases/postgres/commands/postgres-update.command.js +7 -7
  14. package/dist/databases/postgres/migrations/001-create-migrations-table.migration.js +12 -12
  15. package/dist/databases/postgres/migrations/002-create-organizations-table.migration.js +24 -24
  16. package/dist/databases/postgres/migrations/003-create-users-table.migration.js +26 -26
  17. package/dist/databases/postgres/migrations/004-create-refresh-tokens-table.migration.js +18 -18
  18. package/dist/databases/postgres/migrations/005-create-meta-org.migration.js +9 -9
  19. package/dist/databases/postgres/migrations/006-create-admin-user.migration.js +3 -3
  20. package/dist/databases/postgres/migrations/007-create-roles-table.migration.js +14 -14
  21. package/dist/databases/postgres/migrations/008-create-user-roles-table.migration.js +24 -24
  22. package/dist/databases/postgres/migrations/009-create-features-table.migration.js +14 -14
  23. package/dist/databases/postgres/migrations/010-create-authorizations-table.migration.js +26 -26
  24. package/dist/databases/postgres/migrations/011-create-admin-authorization.migration.js +44 -44
  25. package/dist/databases/postgres/migrations/database-builder.js +4 -4
  26. package/dist/databases/postgres/postgres.database.js +17 -17
  27. package/dist/databases/postgres/utils/build-select-clause.js +6 -6
  28. package/dist/databases/postgres/utils/does-table-exist.util.js +4 -4
  29. package/dist/middleware/index.d.ts +1 -0
  30. package/dist/middleware/index.js +1 -0
  31. package/dist/middleware/request-lifecycle.d.ts +6 -0
  32. package/dist/middleware/request-lifecycle.js +45 -0
  33. package/package.json +88 -88
@@ -16,18 +16,18 @@ export class CreateRoleTableMigration {
16
16
  const fkConstraint = config.app.isMultiTenant
17
17
  ? ',\n CONSTRAINT "fk_roles_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE'
18
18
  : '';
19
- await this.client.query(`
20
- CREATE TABLE "roles" (
21
- "_id" VARCHAR(255) PRIMARY KEY,
22
- "_orgId" VARCHAR(255),
23
- "name" VARCHAR(255) NOT NULL,
24
- CONSTRAINT "uk_roles_name" UNIQUE ("_orgId", "name")${fkConstraint}
25
- )
19
+ await this.client.query(`
20
+ CREATE TABLE "roles" (
21
+ "_id" VARCHAR(255) PRIMARY KEY,
22
+ "_orgId" VARCHAR(255),
23
+ "name" VARCHAR(255) NOT NULL,
24
+ CONSTRAINT "uk_roles_name" UNIQUE ("_orgId", "name")${fkConstraint}
25
+ )
26
26
  `);
27
27
  }
28
- const result = await this.client.query(`
29
- INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
30
- VALUES ('${_id}', ${this.index}, TRUE, FALSE);
28
+ const result = await this.client.query(`
29
+ INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
30
+ VALUES ('${_id}', ${this.index}, TRUE, FALSE);
31
31
  `);
32
32
  if (result.rowCount === 0) {
33
33
  await this.client.query('ROLLBACK');
@@ -44,11 +44,11 @@ export class CreateRoleTableMigration {
44
44
  async revert() {
45
45
  try {
46
46
  await this.client.query('BEGIN');
47
- await this.client.query(`
48
- DROP TABLE "roles";
47
+ await this.client.query(`
48
+ DROP TABLE "roles";
49
49
  `);
50
- const updateResult = await this.client.query(`
51
- UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
50
+ const updateResult = await this.client.query(`
51
+ UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
52
52
  `);
53
53
  if (updateResult.rowCount === 0) {
54
54
  await this.client.query('ROLLBACK');
@@ -16,28 +16,28 @@ export class CreateUserRolesTableMigration {
16
16
  const fkConstraint = config.app.isMultiTenant
17
17
  ? '\n CONSTRAINT "fk_user_roles_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE,'
18
18
  : '';
19
- await this.client.query(`
20
- CREATE TABLE "user_roles" (
21
- "_id" VARCHAR(255) PRIMARY KEY,
22
- "_orgId" VARCHAR(255),
23
- "userId" VARCHAR(255) NOT NULL,
24
- "roleId" VARCHAR(255) NOT NULL,
25
- "_created" TIMESTAMP NOT NULL,
26
- "_createdBy" VARCHAR(255) NOT NULL,
27
- "_updated" TIMESTAMP NOT NULL,
28
- "_updatedBy" VARCHAR(255) NOT NULL,
29
- "_deleted" TIMESTAMP,
30
- "_deletedBy" VARCHAR(255),
31
- ${fkConstraint}
32
- CONSTRAINT "fk_user_roles_user" FOREIGN KEY ("userId") REFERENCES "users"("_id") ON DELETE CASCADE,
33
- CONSTRAINT "fk_user_roles_role" FOREIGN KEY ("roleId") REFERENCES "roles"("_id") ON DELETE CASCADE,
34
- CONSTRAINT "uk_user_roles" UNIQUE ("_orgId", "userId", "roleId")
35
- )
19
+ await this.client.query(`
20
+ CREATE TABLE "user_roles" (
21
+ "_id" VARCHAR(255) PRIMARY KEY,
22
+ "_orgId" VARCHAR(255),
23
+ "userId" VARCHAR(255) NOT NULL,
24
+ "roleId" VARCHAR(255) NOT NULL,
25
+ "_created" TIMESTAMP NOT NULL,
26
+ "_createdBy" VARCHAR(255) NOT NULL,
27
+ "_updated" TIMESTAMP NOT NULL,
28
+ "_updatedBy" VARCHAR(255) NOT NULL,
29
+ "_deleted" TIMESTAMP,
30
+ "_deletedBy" VARCHAR(255),
31
+ ${fkConstraint}
32
+ CONSTRAINT "fk_user_roles_user" FOREIGN KEY ("userId") REFERENCES "users"("_id") ON DELETE CASCADE,
33
+ CONSTRAINT "fk_user_roles_role" FOREIGN KEY ("roleId") REFERENCES "roles"("_id") ON DELETE CASCADE,
34
+ CONSTRAINT "uk_user_roles" UNIQUE ("_orgId", "userId", "roleId")
35
+ )
36
36
  `);
37
37
  }
38
- const result = await this.client.query(`
39
- INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
40
- VALUES ('${_id}', ${this.index}, TRUE, FALSE);
38
+ const result = await this.client.query(`
39
+ INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
40
+ VALUES ('${_id}', ${this.index}, TRUE, FALSE);
41
41
  `);
42
42
  if (result.rowCount === 0) {
43
43
  await this.client.query('ROLLBACK');
@@ -54,11 +54,11 @@ export class CreateUserRolesTableMigration {
54
54
  async revert() {
55
55
  try {
56
56
  await this.client.query('BEGIN');
57
- await this.client.query(`
58
- DROP TABLE "user_roles";
57
+ await this.client.query(`
58
+ DROP TABLE "user_roles";
59
59
  `);
60
- const updateResult = await this.client.query(`
61
- UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
60
+ const updateResult = await this.client.query(`
61
+ UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
62
62
  `);
63
63
  if (updateResult.rowCount === 0) {
64
64
  await this.client.query('ROLLBACK');
@@ -16,18 +16,18 @@ export class CreateFeaturesTableMigration {
16
16
  const fkConstraint = config.app.isMultiTenant
17
17
  ? ',\n CONSTRAINT "fk_features_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE'
18
18
  : '';
19
- await this.client.query(`
20
- CREATE TABLE "features" (
21
- "_id" VARCHAR(255) PRIMARY KEY,
22
- "_orgId" VARCHAR(255),
23
- "name" VARCHAR(255) NOT NULL,
24
- CONSTRAINT "uk_features" UNIQUE ("_orgId", "name")${fkConstraint}
25
- )
19
+ await this.client.query(`
20
+ CREATE TABLE "features" (
21
+ "_id" VARCHAR(255) PRIMARY KEY,
22
+ "_orgId" VARCHAR(255),
23
+ "name" VARCHAR(255) NOT NULL,
24
+ CONSTRAINT "uk_features" UNIQUE ("_orgId", "name")${fkConstraint}
25
+ )
26
26
  `);
27
27
  }
28
- const result = await this.client.query(`
29
- INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
30
- VALUES ('${_id}', ${this.index}, TRUE, FALSE);
28
+ const result = await this.client.query(`
29
+ INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
30
+ VALUES ('${_id}', ${this.index}, TRUE, FALSE);
31
31
  `);
32
32
  if (result.rowCount === 0) {
33
33
  await this.client.query('ROLLBACK');
@@ -44,11 +44,11 @@ export class CreateFeaturesTableMigration {
44
44
  async revert() {
45
45
  try {
46
46
  await this.client.query('BEGIN');
47
- await this.client.query(`
48
- DROP TABLE "features";
47
+ await this.client.query(`
48
+ DROP TABLE "features";
49
49
  `);
50
- const updateResult = await this.client.query(`
51
- UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
50
+ const updateResult = await this.client.query(`
51
+ UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
52
52
  `);
53
53
  if (updateResult.rowCount === 0) {
54
54
  await this.client.query('ROLLBACK');
@@ -16,30 +16,30 @@ export class CreateAuthorizationsTableMigration {
16
16
  const fkConstraint = config.app.isMultiTenant
17
17
  ? ',\n CONSTRAINT "fk_authorizations_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE'
18
18
  : '';
19
- await this.client.query(`
20
- CREATE TABLE "authorizations" (
21
- "_id" VARCHAR(255) PRIMARY KEY,
22
- "_orgId" VARCHAR(255),
23
- "roleId" VARCHAR(255) NOT NULL,
24
- "featureId" VARCHAR(255) NOT NULL,
25
- "startDate" TIMESTAMP,
26
- "endDate" TIMESTAMP,
27
- "config" JSONB,
28
- "_created" TIMESTAMP NOT NULL,
29
- "_createdBy" VARCHAR(255) NOT NULL,
30
- "_updated" TIMESTAMP NOT NULL,
31
- "_updatedBy" VARCHAR(255) NOT NULL,
32
- "_deleted" TIMESTAMP,
33
- "_deletedBy" VARCHAR(255),
34
- CONSTRAINT "fk_authorizations_role" FOREIGN KEY ("roleId") REFERENCES "roles"("_id") ON DELETE CASCADE,
35
- CONSTRAINT "fk_authorizations_feature" FOREIGN KEY ("featureId") REFERENCES "features"("_id") ON DELETE CASCADE,
36
- CONSTRAINT "uk_authorizations" UNIQUE ("_orgId", "roleId", "featureId")${fkConstraint}
37
- )
19
+ await this.client.query(`
20
+ CREATE TABLE "authorizations" (
21
+ "_id" VARCHAR(255) PRIMARY KEY,
22
+ "_orgId" VARCHAR(255),
23
+ "roleId" VARCHAR(255) NOT NULL,
24
+ "featureId" VARCHAR(255) NOT NULL,
25
+ "startDate" TIMESTAMP,
26
+ "endDate" TIMESTAMP,
27
+ "config" JSONB,
28
+ "_created" TIMESTAMP NOT NULL,
29
+ "_createdBy" VARCHAR(255) NOT NULL,
30
+ "_updated" TIMESTAMP NOT NULL,
31
+ "_updatedBy" VARCHAR(255) NOT NULL,
32
+ "_deleted" TIMESTAMP,
33
+ "_deletedBy" VARCHAR(255),
34
+ CONSTRAINT "fk_authorizations_role" FOREIGN KEY ("roleId") REFERENCES "roles"("_id") ON DELETE CASCADE,
35
+ CONSTRAINT "fk_authorizations_feature" FOREIGN KEY ("featureId") REFERENCES "features"("_id") ON DELETE CASCADE,
36
+ CONSTRAINT "uk_authorizations" UNIQUE ("_orgId", "roleId", "featureId")${fkConstraint}
37
+ )
38
38
  `);
39
39
  }
40
- const result = await this.client.query(`
41
- INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
42
- VALUES ('${_id}', ${this.index}, TRUE, FALSE);
40
+ const result = await this.client.query(`
41
+ INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
42
+ VALUES ('${_id}', ${this.index}, TRUE, FALSE);
43
43
  `);
44
44
  if (result.rowCount === 0) {
45
45
  await this.client.query('ROLLBACK');
@@ -56,11 +56,11 @@ export class CreateAuthorizationsTableMigration {
56
56
  async revert() {
57
57
  try {
58
58
  await this.client.query('BEGIN');
59
- await this.client.query(`
60
- DROP TABLE "authorizations";
59
+ await this.client.query(`
60
+ DROP TABLE "authorizations";
61
61
  `);
62
- const updateResult = await this.client.query(`
63
- UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
62
+ const updateResult = await this.client.query(`
63
+ UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = '${this.index}';
64
64
  `);
65
65
  if (updateResult.rowCount === 0) {
66
66
  await this.client.query('ROLLBACK');
@@ -27,47 +27,47 @@ export class CreateAdminAuthorizationMigration {
27
27
  }
28
28
  await this.client.query('BEGIN');
29
29
  const roleId = randomUUID().toString();
30
- const roleResult = await this.client.query(`
31
- INSERT INTO "roles" ("_id", "_orgId", "name")
32
- VALUES ($1, $2, 'admin')
30
+ const roleResult = await this.client.query(`
31
+ INSERT INTO "roles" ("_id", "_orgId", "name")
32
+ VALUES ($1, $2, 'admin')
33
33
  `, [roleId, metaOrg?._id]);
34
34
  if (roleResult.rowCount === 0) {
35
35
  await this.client.query('ROLLBACK');
36
36
  return { success: false, error: new Error('Failed to create admin role') };
37
37
  }
38
38
  const userRoleId = randomUUID().toString();
39
- const userRoleResult = await this.client.query(`
40
- INSERT INTO "user_roles" ("_id", "_orgId", "userId", "roleId", "_created", "_createdBy", "_updated", "_updatedBy")
41
- VALUES ($1, $2, $3, $4, NOW(), 'system', NOW(), 'system')
39
+ const userRoleResult = await this.client.query(`
40
+ INSERT INTO "user_roles" ("_id", "_orgId", "userId", "roleId", "_created", "_createdBy", "_updated", "_updatedBy")
41
+ VALUES ($1, $2, $3, $4, NOW(), 'system', NOW(), 'system')
42
42
  `, [userRoleId, metaOrg?._id, adminUser?._id, roleId]);
43
43
  if (userRoleResult.rowCount === 0) {
44
44
  await this.client.query('ROLLBACK');
45
45
  return { success: false, error: new Error('Failed to create user role') };
46
46
  }
47
47
  const featureId = randomUUID().toString();
48
- const featureResult = await this.client.query(`
49
- INSERT INTO "features" ("_id", "_orgId", "name")
50
- VALUES ($1, $2, 'admin')
48
+ const featureResult = await this.client.query(`
49
+ INSERT INTO "features" ("_id", "_orgId", "name")
50
+ VALUES ($1, $2, 'admin')
51
51
  `, [featureId, metaOrg?._id]);
52
52
  if (featureResult.rowCount === 0) {
53
53
  await this.client.query('ROLLBACK');
54
54
  return { success: false, error: new Error('Failed to create admin feature') };
55
55
  }
56
56
  const authorizationId = randomUUID().toString();
57
- const authorizationResult = await this.client.query(`
58
- INSERT INTO "authorizations" (
59
- "_id", "_orgId", "roleId", "featureId",
60
- "_created", "_createdBy", "_updated", "_updatedBy"
61
- )
62
- VALUES ($1, $2, $3, $4, NOW(), 'system', NOW(), 'system')
57
+ const authorizationResult = await this.client.query(`
58
+ INSERT INTO "authorizations" (
59
+ "_id", "_orgId", "roleId", "featureId",
60
+ "_created", "_createdBy", "_updated", "_updatedBy"
61
+ )
62
+ VALUES ($1, $2, $3, $4, NOW(), 'system', NOW(), 'system')
63
63
  `, [authorizationId, metaOrg?._id, roleId, featureId]);
64
64
  if (authorizationResult.rowCount === 0) {
65
65
  await this.client.query('ROLLBACK');
66
66
  return { success: false, error: new Error('Failed to create admin authorization') };
67
67
  }
68
- const migrationResult = await this.client.query(`
69
- INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
70
- VALUES ($1, $2, TRUE, FALSE)
68
+ const migrationResult = await this.client.query(`
69
+ INSERT INTO "migrations" ("_id", "index", "hasRun", "reverted")
70
+ VALUES ($1, $2, TRUE, FALSE)
71
71
  `, [_id, this.index]);
72
72
  if (migrationResult.rowCount === 0) {
73
73
  await this.client.query('ROLLBACK');
@@ -84,36 +84,36 @@ export class CreateAdminAuthorizationMigration {
84
84
  async revert(metaOrgId) {
85
85
  try {
86
86
  await this.client.query('BEGIN');
87
- await this.client.query(`
88
- DELETE FROM "authorizations"
89
- WHERE "_orgId" = $1
90
- AND "_featureId" IN (
91
- SELECT "_id" FROM "features"
92
- WHERE "_orgId" = $1 AND "name" = 'admin'
93
- )
94
- AND "_roleId" IN (
95
- SELECT "_id" FROM "roles"
96
- WHERE "_orgId" = $1 AND "name" = 'admin'
97
- )
87
+ await this.client.query(`
88
+ DELETE FROM "authorizations"
89
+ WHERE "_orgId" = $1
90
+ AND "_featureId" IN (
91
+ SELECT "_id" FROM "features"
92
+ WHERE "_orgId" = $1 AND "name" = 'admin'
93
+ )
94
+ AND "_roleId" IN (
95
+ SELECT "_id" FROM "roles"
96
+ WHERE "_orgId" = $1 AND "name" = 'admin'
97
+ )
98
98
  `, [metaOrgId]);
99
- await this.client.query(`
100
- DELETE FROM "features"
101
- WHERE "_orgId" = $1 AND "name" = 'admin'
99
+ await this.client.query(`
100
+ DELETE FROM "features"
101
+ WHERE "_orgId" = $1 AND "name" = 'admin'
102
102
  `, [metaOrgId]);
103
- await this.client.query(`
104
- DELETE FROM "user_roles"
105
- WHERE "_orgId" = $1
106
- AND "_roleId" IN (
107
- SELECT "_id" FROM "roles"
108
- WHERE "_orgId" = $1 AND "name" = 'admin'
109
- )
103
+ await this.client.query(`
104
+ DELETE FROM "user_roles"
105
+ WHERE "_orgId" = $1
106
+ AND "_roleId" IN (
107
+ SELECT "_id" FROM "roles"
108
+ WHERE "_orgId" = $1 AND "name" = 'admin'
109
+ )
110
110
  `, [metaOrgId]);
111
- await this.client.query(`
112
- DELETE FROM "roles"
113
- WHERE "_orgId" = $1 AND "name" = 'admin'
111
+ await this.client.query(`
112
+ DELETE FROM "roles"
113
+ WHERE "_orgId" = $1 AND "name" = 'admin'
114
114
  `, [metaOrgId]);
115
- const updateResult = await this.client.query(`
116
- UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = $1
115
+ const updateResult = await this.client.query(`
116
+ UPDATE "migrations" SET "reverted" = TRUE WHERE "index" = $1
117
117
  `, [this.index]);
118
118
  if (updateResult.rowCount === 0) {
119
119
  await this.client.query('ROLLBACK');
@@ -42,10 +42,10 @@ export class DatabaseBuilder {
42
42
  async build() {
43
43
  let runMigrations = [];
44
44
  if (await doesTableExist(this.client, 'migrations')) {
45
- const migrations = await this.client.query(`
46
- SELECT "_id", "index"
47
- FROM migrations
48
- WHERE "hasRun" = TRUE AND "reverted" = FALSE
45
+ const migrations = await this.client.query(`
46
+ SELECT "_id", "index"
47
+ FROM migrations
48
+ WHERE "hasRun" = TRUE AND "reverted" = FALSE
49
49
  `);
50
50
  runMigrations = migrations.rows.map((row) => {
51
51
  return row.index;
@@ -68,23 +68,23 @@ export class PostgresDatabase {
68
68
  }
69
69
  async getUserAuthorizations(userId, orgId) {
70
70
  const now = new Date();
71
- let query = `
72
- SELECT DISTINCT
73
- ur."userId" as "userId",
74
- r."name" as "role",
75
- f."name" as "feature",
76
- a."config",
77
- a."_id",
78
- a."_orgId"
79
- FROM "user_roles" ur
80
- INNER JOIN "roles" r ON ur."roleId" = r."_id"
81
- INNER JOIN "authorizations" a ON r."_id" = a."roleId"
82
- INNER JOIN "features" f ON a."featureId" = f."_id"
83
- WHERE ur."userId" = $1
84
- AND ur."_deleted" IS NULL
85
- AND a."_deleted" IS NULL
86
- AND (a."startDate" IS NULL OR a."startDate" <= $2)
87
- AND (a."endDate" IS NULL OR a."endDate" >= $2)
71
+ let query = `
72
+ SELECT DISTINCT
73
+ ur."userId" as "userId",
74
+ r."name" as "role",
75
+ f."name" as "feature",
76
+ a."config",
77
+ a."_id",
78
+ a."_orgId"
79
+ FROM "user_roles" ur
80
+ INNER JOIN "roles" r ON ur."roleId" = r."_id"
81
+ INNER JOIN "authorizations" a ON r."_id" = a."roleId"
82
+ INNER JOIN "features" f ON a."featureId" = f."_id"
83
+ WHERE ur."userId" = $1
84
+ AND ur."_deleted" IS NULL
85
+ AND a."_deleted" IS NULL
86
+ AND (a."startDate" IS NULL OR a."startDate" <= $2)
87
+ AND (a."endDate" IS NULL OR a."endDate" >= $2)
88
88
  `;
89
89
  const values = [userId, now];
90
90
  if (orgId) {
@@ -1,11 +1,11 @@
1
1
  import { Join } from '../../operations/join.operation.js';
2
2
  async function getTableColumns(client, tableName) {
3
- const result = await client.query(`
4
- SELECT column_name
5
- FROM information_schema.columns
6
- WHERE table_schema = current_schema()
7
- AND table_name = $1
8
- ORDER BY ordinal_position
3
+ const result = await client.query(`
4
+ SELECT column_name
5
+ FROM information_schema.columns
6
+ WHERE table_schema = current_schema()
7
+ AND table_name = $1
8
+ ORDER BY ordinal_position
9
9
  `, [tableName]);
10
10
  return result.rows.map(row => row.column_name);
11
11
  }
@@ -1,8 +1,8 @@
1
1
  export async function doesTableExist(client, tableName) {
2
- const result = await client.query(`
3
- SELECT EXISTS (
4
- SELECT 1 FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = $1
5
- )
2
+ const result = await client.query(`
3
+ SELECT EXISTS (
4
+ SELECT 1 FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = $1
5
+ )
6
6
  `, [tableName]);
7
7
  return result.rows[0].exists;
8
8
  }
@@ -1,3 +1,4 @@
1
1
  export * from './error-handler.js';
2
2
  export * from './is-authorized.js';
3
3
  export * from './ensure-user-context.js';
4
+ export * from './request-lifecycle.js';
@@ -1,3 +1,4 @@
1
1
  export * from './error-handler.js';
2
2
  export * from './is-authorized.js';
3
3
  export * from './ensure-user-context.js';
4
+ export * from './request-lifecycle.js';
@@ -0,0 +1,6 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ export interface RequestLifecycleOptions {
3
+ onRequestStart?: (req: Request, res: Response) => void | Promise<void>;
4
+ onRequestEnd?: (req: Request, res: Response, error?: Error) => void | Promise<void>;
5
+ }
6
+ export declare const requestLifecycle: (options?: RequestLifecycleOptions) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
@@ -0,0 +1,45 @@
1
+ export const requestLifecycle = (options = {}) => {
2
+ const { onRequestStart, onRequestEnd } = options;
3
+ return async (req, res, next) => {
4
+ req.startTime = Date.now();
5
+ if (onRequestStart) {
6
+ try {
7
+ await onRequestStart(req, res);
8
+ }
9
+ catch (error) {
10
+ console.error('Error in onRequestStart callback:', error);
11
+ }
12
+ }
13
+ let endCallbackCalled = false;
14
+ const callOnRequestEnd = async (error) => {
15
+ if (endCallbackCalled)
16
+ return;
17
+ endCallbackCalled = true;
18
+ if (onRequestEnd) {
19
+ try {
20
+ await onRequestEnd(req, res, error);
21
+ }
22
+ catch (callbackError) {
23
+ console.error('Error in onRequestEnd callback:', callbackError);
24
+ }
25
+ }
26
+ };
27
+ res.on('finish', () => {
28
+ const error = req.lifecycleError;
29
+ callOnRequestEnd(error);
30
+ });
31
+ res.on('close', () => {
32
+ if (!res.writableEnded && !endCallbackCalled) {
33
+ const error = req.lifecycleError || new Error('Request closed before completion');
34
+ callOnRequestEnd(error);
35
+ }
36
+ });
37
+ try {
38
+ await next();
39
+ }
40
+ catch (error) {
41
+ req.lifecycleError = error instanceof Error ? error : new Error(String(error));
42
+ throw error;
43
+ }
44
+ };
45
+ };