@loomcore/api 0.1.27 → 0.1.29

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 (44) hide show
  1. package/dist/__tests__/common-test.utils.d.ts +7 -2
  2. package/dist/__tests__/common-test.utils.js +65 -11
  3. package/dist/__tests__/postgres-test-migrations/run-test-migrations.js +0 -2
  4. package/dist/__tests__/postgres.test-database.js +7 -6
  5. package/dist/__tests__/test-express-app.js +2 -31
  6. package/dist/__tests__/test-objects.d.ts +1 -0
  7. package/dist/__tests__/test-objects.js +5 -1
  8. package/dist/config/base-api-config.js +1 -1
  9. package/dist/controllers/api.controller.d.ts +2 -3
  10. package/dist/controllers/api.controller.js +12 -12
  11. package/dist/controllers/auth.controller.js +2 -2
  12. package/dist/controllers/users.controller.d.ts +2 -1
  13. package/dist/controllers/users.controller.js +2 -2
  14. package/dist/databases/postgres/migrations/003-create-users-table.migration.js +5 -2
  15. package/dist/databases/postgres/migrations/004-create-refresh-tokens-table.migration.js +5 -1
  16. package/dist/databases/postgres/migrations/005-create-meta-org.migration.d.ts +1 -5
  17. package/dist/databases/postgres/migrations/005-create-meta-org.migration.js +7 -7
  18. package/dist/databases/postgres/migrations/006-create-admin-user.migration.d.ts +6 -3
  19. package/dist/databases/postgres/migrations/006-create-admin-user.migration.js +16 -13
  20. package/dist/databases/postgres/migrations/007-create-roles-table.migration.d.ts +1 -1
  21. package/dist/databases/postgres/migrations/007-create-roles-table.migration.js +6 -3
  22. package/dist/databases/postgres/migrations/008-create-user-roles-table.migration.d.ts +1 -1
  23. package/dist/databases/postgres/migrations/008-create-user-roles-table.migration.js +6 -2
  24. package/dist/databases/postgres/migrations/009-create-features-table.migration.d.ts +1 -1
  25. package/dist/databases/postgres/migrations/009-create-features-table.migration.js +6 -3
  26. package/dist/databases/postgres/migrations/010-create-authorizations-table.migration.d.ts +1 -1
  27. package/dist/databases/postgres/migrations/010-create-authorizations-table.migration.js +6 -3
  28. package/dist/databases/postgres/migrations/011-create-admin-authorization.migration.d.ts +3 -3
  29. package/dist/databases/postgres/migrations/011-create-admin-authorization.migration.js +22 -9
  30. package/dist/databases/postgres/migrations/database-builder.d.ts +15 -0
  31. package/dist/databases/postgres/migrations/database-builder.interface.d.ts +10 -0
  32. package/dist/databases/postgres/migrations/database-builder.interface.js +1 -0
  33. package/dist/databases/postgres/migrations/database-builder.js +62 -0
  34. package/dist/databases/postgres/migrations/setup-for-auth.migration.d.ts +5 -2
  35. package/dist/databases/postgres/migrations/setup-for-auth.migration.js +12 -18
  36. package/dist/databases/postgres/migrations/setup-for-multitenant.migration.d.ts +5 -3
  37. package/dist/databases/postgres/migrations/setup-for-multitenant.migration.js +7 -9
  38. package/dist/models/base-api-config.interface.d.ts +11 -5
  39. package/dist/services/email.service.js +6 -3
  40. package/dist/utils/api.utils.d.ts +1 -2
  41. package/dist/utils/api.utils.js +2 -3
  42. package/package.json +2 -2
  43. package/dist/__tests__/postgres-test-migrations/004-create-test-users-table.migration.d.ts +0 -21
  44. package/dist/__tests__/postgres-test-migrations/004-create-test-users-table.migration.js +0 -75
@@ -2,33 +2,34 @@ import { PostgresDatabase } from "../index.js";
2
2
  import { randomUUID } from "crypto";
3
3
  import { getSystemUserContext } from "@loomcore/common/models";
4
4
  import { AuthService } from "../../../services/auth.service.js";
5
+ import { config } from "../../../config/index.js";
5
6
  export class CreateAdminUserMigration {
6
7
  client;
7
8
  constructor(client) {
8
9
  this.client = client;
10
+ const database = new PostgresDatabase(this.client);
11
+ this.authService = new AuthService(database);
9
12
  }
13
+ authService;
10
14
  index = 6;
11
- async execute(adminEmail, adminPassword, metaOrgId) {
15
+ async execute() {
12
16
  const _id = randomUUID().toString();
13
17
  const systemUserContext = getSystemUserContext();
14
18
  let createdUser;
15
19
  try {
16
- const database = new PostgresDatabase(this.client);
17
- const authService = new AuthService(database);
18
- createdUser = await authService.createUser(systemUserContext, {
20
+ createdUser = await this.authService.createUser(systemUserContext, {
19
21
  _id: _id,
20
- _orgId: metaOrgId,
21
- email: adminEmail,
22
- password: adminPassword,
22
+ _orgId: systemUserContext._orgId,
23
+ email: config.adminUser?.email,
24
+ password: config.adminUser?.password,
23
25
  firstName: 'Admin',
24
26
  lastName: 'User',
25
27
  displayName: 'Admin User',
26
28
  });
27
29
  }
28
30
  catch (error) {
29
- return {
30
- success: false, adminUserId: undefined, error: new Error(`Error creating admin user: ${error.message}`)
31
- };
31
+ console.error(`Error creating admin user: ${error.message}`);
32
+ return { success: false, error: new Error(`Error creating admin user: ${error.message}`) };
32
33
  }
33
34
  try {
34
35
  const result = await this.client.query(`
@@ -36,13 +37,15 @@ export class CreateAdminUserMigration {
36
37
  VALUES ('${_id}', ${this.index}, TRUE, FALSE);
37
38
  `);
38
39
  if (result.rowCount === 0) {
39
- return { success: false, adminUserId: undefined, error: new Error(`Error inserting migration ${this.index} to migrations table: No row returned`) };
40
+ console.error(`Error inserting migration ${this.index} to migrations table: No row returned`);
41
+ return { success: false, error: new Error(`Error inserting migration ${this.index} to migrations table: No row returned`) };
40
42
  }
41
43
  }
42
44
  catch (error) {
43
- return { success: false, adminUserId: undefined, error: new Error(`Error inserting migration ${this.index} to migrations table: ${error.message}`) };
45
+ console.error(`Error inserting migration ${this.index} to migrations table: ${error.message}`);
46
+ return { success: false, error: new Error(`Error inserting migration ${this.index} to migrations table: ${error.message}`) };
44
47
  }
45
- return { success: true, adminUserId: createdUser?._id, error: null };
48
+ return { success: true, error: null };
46
49
  }
47
50
  async revert() {
48
51
  throw new Error('Not implemented');
@@ -4,7 +4,7 @@ export declare class CreateRoleTableMigration implements IMigration {
4
4
  private readonly client;
5
5
  constructor(client: Client);
6
6
  index: number;
7
- execute(_orgId?: string): Promise<{
7
+ execute(): Promise<{
8
8
  success: boolean;
9
9
  error: Error;
10
10
  } | {
@@ -1,24 +1,27 @@
1
1
  import { randomUUID } from "crypto";
2
2
  import { doesTableExist } from "../utils/does-table-exist.util.js";
3
+ import { config } from "../../../config/index.js";
3
4
  export class CreateRoleTableMigration {
4
5
  client;
5
6
  constructor(client) {
6
7
  this.client = client;
7
8
  }
8
9
  index = 7;
9
- async execute(_orgId) {
10
+ async execute() {
10
11
  const _id = randomUUID().toString();
11
12
  try {
12
13
  await this.client.query('BEGIN');
13
14
  const tableExists = await doesTableExist(this.client, 'roles');
14
15
  if (!tableExists) {
16
+ const fkConstraint = config.app.isMultiTenant
17
+ ? ',\n CONSTRAINT "fk_roles_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE'
18
+ : '';
15
19
  await this.client.query(`
16
20
  CREATE TABLE "roles" (
17
21
  "_id" VARCHAR(255) PRIMARY KEY,
18
22
  "_orgId" VARCHAR(255),
19
23
  "name" VARCHAR(255) NOT NULL,
20
- CONSTRAINT "fk_roles_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE,
21
- CONSTRAINT "uk_roles_name" UNIQUE ("_orgId", "name")
24
+ CONSTRAINT "uk_roles_name" UNIQUE ("_orgId", "name")${fkConstraint}
22
25
  )
23
26
  `);
24
27
  }
@@ -4,7 +4,7 @@ export declare class CreateUserRolesTableMigration implements IMigration {
4
4
  private readonly client;
5
5
  constructor(client: Client);
6
6
  index: number;
7
- execute(_orgId?: string): Promise<{
7
+ execute(): Promise<{
8
8
  success: boolean;
9
9
  error: Error;
10
10
  } | {
@@ -1,17 +1,21 @@
1
1
  import { randomUUID } from "crypto";
2
2
  import { doesTableExist } from "../utils/does-table-exist.util.js";
3
+ import { config } from "../../../config/index.js";
3
4
  export class CreateUserRolesTableMigration {
4
5
  client;
5
6
  constructor(client) {
6
7
  this.client = client;
7
8
  }
8
9
  index = 8;
9
- async execute(_orgId) {
10
+ async execute() {
10
11
  const _id = randomUUID().toString();
11
12
  try {
12
13
  await this.client.query('BEGIN');
13
14
  const tableExists = await doesTableExist(this.client, 'user_roles');
14
15
  if (!tableExists) {
16
+ const fkConstraint = config.app.isMultiTenant
17
+ ? '\n CONSTRAINT "fk_user_roles_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE,'
18
+ : '';
15
19
  await this.client.query(`
16
20
  CREATE TABLE "user_roles" (
17
21
  "_id" VARCHAR(255) PRIMARY KEY,
@@ -24,7 +28,7 @@ export class CreateUserRolesTableMigration {
24
28
  "_updatedBy" VARCHAR(255) NOT NULL,
25
29
  "_deleted" TIMESTAMP,
26
30
  "_deletedBy" VARCHAR(255),
27
- CONSTRAINT "fk_user_roles_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE,
31
+ ${fkConstraint}
28
32
  CONSTRAINT "fk_user_roles_user" FOREIGN KEY ("_userId") REFERENCES "users"("_id") ON DELETE CASCADE,
29
33
  CONSTRAINT "fk_user_roles_role" FOREIGN KEY ("_roleId") REFERENCES "roles"("_id") ON DELETE CASCADE,
30
34
  CONSTRAINT "uk_user_roles" UNIQUE ("_orgId", "_userId", "_roleId")
@@ -4,7 +4,7 @@ export declare class CreateFeaturesTableMigration implements IMigration {
4
4
  private readonly client;
5
5
  constructor(client: Client);
6
6
  index: number;
7
- execute(_orgId?: string): Promise<{
7
+ execute(): Promise<{
8
8
  success: boolean;
9
9
  error: Error;
10
10
  } | {
@@ -1,24 +1,27 @@
1
1
  import { randomUUID } from "crypto";
2
2
  import { doesTableExist } from "../utils/does-table-exist.util.js";
3
+ import { config } from "../../../config/index.js";
3
4
  export class CreateFeaturesTableMigration {
4
5
  client;
5
6
  constructor(client) {
6
7
  this.client = client;
7
8
  }
8
9
  index = 9;
9
- async execute(_orgId) {
10
+ async execute() {
10
11
  const _id = randomUUID().toString();
11
12
  try {
12
13
  await this.client.query('BEGIN');
13
14
  const tableExists = await doesTableExist(this.client, 'features');
14
15
  if (!tableExists) {
16
+ const fkConstraint = config.app.isMultiTenant
17
+ ? ',\n CONSTRAINT "fk_features_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE'
18
+ : '';
15
19
  await this.client.query(`
16
20
  CREATE TABLE "features" (
17
21
  "_id" VARCHAR(255) PRIMARY KEY,
18
22
  "_orgId" VARCHAR(255),
19
23
  "name" VARCHAR(255) NOT NULL,
20
- CONSTRAINT "fk_features_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE,
21
- CONSTRAINT "uk_features" UNIQUE ("_orgId", "name")
24
+ CONSTRAINT "uk_features" UNIQUE ("_orgId", "name")${fkConstraint}
22
25
  )
23
26
  `);
24
27
  }
@@ -4,7 +4,7 @@ export declare class CreateAuthorizationsTableMigration implements IMigration {
4
4
  private readonly client;
5
5
  constructor(client: Client);
6
6
  index: number;
7
- execute(_orgId?: string): Promise<{
7
+ execute(): Promise<{
8
8
  success: boolean;
9
9
  error: Error;
10
10
  } | {
@@ -1,17 +1,21 @@
1
1
  import { randomUUID } from "crypto";
2
2
  import { doesTableExist } from "../utils/does-table-exist.util.js";
3
+ import { config } from "../../../config/index.js";
3
4
  export class CreateAuthorizationsTableMigration {
4
5
  client;
5
6
  constructor(client) {
6
7
  this.client = client;
7
8
  }
8
9
  index = 10;
9
- async execute(_orgId) {
10
+ async execute() {
10
11
  const _id = randomUUID().toString();
11
12
  try {
12
13
  await this.client.query('BEGIN');
13
14
  const tableExists = await doesTableExist(this.client, 'authorizations');
14
15
  if (!tableExists) {
16
+ const fkConstraint = config.app.isMultiTenant
17
+ ? ',\n CONSTRAINT "fk_authorizations_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE'
18
+ : '';
15
19
  await this.client.query(`
16
20
  CREATE TABLE "authorizations" (
17
21
  "_id" VARCHAR(255) PRIMARY KEY,
@@ -27,10 +31,9 @@ export class CreateAuthorizationsTableMigration {
27
31
  "_updatedBy" VARCHAR(255) NOT NULL,
28
32
  "_deleted" TIMESTAMP,
29
33
  "_deletedBy" VARCHAR(255),
30
- CONSTRAINT "fk_authorizations_organization" FOREIGN KEY ("_orgId") REFERENCES "organizations"("_id") ON DELETE CASCADE,
31
34
  CONSTRAINT "fk_authorizations_role" FOREIGN KEY ("_roleId") REFERENCES "roles"("_id") ON DELETE CASCADE,
32
35
  CONSTRAINT "fk_authorizations_feature" FOREIGN KEY ("_featureId") REFERENCES "features"("_id") ON DELETE CASCADE,
33
- CONSTRAINT "uk_authorizations" UNIQUE ("_orgId", "_roleId", "_featureId")
36
+ CONSTRAINT "uk_authorizations" UNIQUE ("_orgId", "_roleId", "_featureId")${fkConstraint}
34
37
  )
35
38
  `);
36
39
  }
@@ -2,9 +2,9 @@ import { Client } from "pg";
2
2
  import { IMigration } from "./migration.interface.js";
3
3
  export declare class CreateAdminAuthorizationMigration implements IMigration {
4
4
  private readonly client;
5
- private readonly adminUserId;
6
- private readonly metaOrgId?;
7
- constructor(client: Client, adminUserId: string, metaOrgId?: string | undefined);
5
+ constructor(client: Client);
6
+ private organizationService;
7
+ private authService;
8
8
  index: number;
9
9
  execute(): Promise<{
10
10
  success: boolean;
@@ -1,23 +1,36 @@
1
1
  import { randomUUID } from "crypto";
2
+ import { AuthService, OrganizationService } from "../../../services/index.js";
3
+ import { PostgresDatabase } from "../index.js";
4
+ import { config } from "../../../config/index.js";
5
+ import { EmptyUserContext } from "@loomcore/common/models";
2
6
  export class CreateAdminAuthorizationMigration {
3
7
  client;
4
- adminUserId;
5
- metaOrgId;
6
- constructor(client, adminUserId, metaOrgId) {
8
+ constructor(client) {
7
9
  this.client = client;
8
- this.adminUserId = adminUserId;
9
- this.metaOrgId = metaOrgId;
10
+ const database = new PostgresDatabase(this.client);
11
+ this.organizationService = new OrganizationService(database);
12
+ this.authService = new AuthService(database);
10
13
  }
14
+ organizationService;
15
+ authService;
11
16
  index = 11;
12
17
  async execute() {
13
18
  const _id = randomUUID().toString();
14
19
  try {
20
+ const metaOrg = await this.organizationService.getMetaOrg(EmptyUserContext).catch(() => null);
21
+ if (!config.adminUser?.email) {
22
+ return { success: false, error: new Error('Create admin authorization: Admin user email not found in config') };
23
+ }
24
+ const adminUser = await this.authService.getUserByEmail(config.adminUser?.email);
25
+ if (!adminUser) {
26
+ return { success: false, error: new Error('Create admin authorization: Admin user not found') };
27
+ }
15
28
  await this.client.query('BEGIN');
16
29
  const roleId = randomUUID().toString();
17
30
  const roleResult = await this.client.query(`
18
31
  INSERT INTO "roles" ("_id", "_orgId", "name")
19
32
  VALUES ($1, $2, 'admin')
20
- `, [roleId, this.metaOrgId]);
33
+ `, [roleId, metaOrg?._id ?? null]);
21
34
  if (roleResult.rowCount === 0) {
22
35
  await this.client.query('ROLLBACK');
23
36
  return { success: false, error: new Error('Failed to create admin role') };
@@ -26,7 +39,7 @@ export class CreateAdminAuthorizationMigration {
26
39
  const userRoleResult = await this.client.query(`
27
40
  INSERT INTO "user_roles" ("_id", "_orgId", "_userId", "_roleId", "_created", "_createdBy", "_updated", "_updatedBy")
28
41
  VALUES ($1, $2, $3, $4, NOW(), 'system', NOW(), 'system')
29
- `, [userRoleId, this.metaOrgId, this.adminUserId, roleId]);
42
+ `, [userRoleId, metaOrg?._id ?? null, adminUser?._id, roleId]);
30
43
  if (userRoleResult.rowCount === 0) {
31
44
  await this.client.query('ROLLBACK');
32
45
  return { success: false, error: new Error('Failed to create user role') };
@@ -35,7 +48,7 @@ export class CreateAdminAuthorizationMigration {
35
48
  const featureResult = await this.client.query(`
36
49
  INSERT INTO "features" ("_id", "_orgId", "name")
37
50
  VALUES ($1, $2, 'admin')
38
- `, [featureId, this.metaOrgId]);
51
+ `, [featureId, metaOrg?._id ?? null]);
39
52
  if (featureResult.rowCount === 0) {
40
53
  await this.client.query('ROLLBACK');
41
54
  return { success: false, error: new Error('Failed to create admin feature') };
@@ -47,7 +60,7 @@ export class CreateAdminAuthorizationMigration {
47
60
  "_created", "_createdBy", "_updated", "_updatedBy"
48
61
  )
49
62
  VALUES ($1, $2, $3, $4, NOW(), 'system', NOW(), 'system')
50
- `, [authorizationId, this.metaOrgId, roleId, featureId]);
63
+ `, [authorizationId, metaOrg?._id ?? null, roleId, featureId]);
51
64
  if (authorizationResult.rowCount === 0) {
52
65
  await this.client.query('ROLLBACK');
53
66
  return { success: false, error: new Error('Failed to create admin authorization') };
@@ -0,0 +1,15 @@
1
+ import { Client } from "pg";
2
+ import { IDatabaseBuilder } from "./database-builder.interface.js";
3
+ import { IMigration } from "./migration.interface.js";
4
+ export declare class DatabaseBuilder implements IDatabaseBuilder {
5
+ private client;
6
+ private migrationsToRun;
7
+ constructor(client: Client);
8
+ withAuth(): IDatabaseBuilder;
9
+ withMultitenant(): IDatabaseBuilder;
10
+ withMigrations(migrations: IMigration[]): IDatabaseBuilder;
11
+ build(): Promise<{
12
+ success: boolean;
13
+ error: Error | null;
14
+ }>;
15
+ }
@@ -0,0 +1,10 @@
1
+ import { IMigration } from "./migration.interface.js";
2
+ export interface IDatabaseBuilder {
3
+ withAuth(): IDatabaseBuilder;
4
+ withMultitenant(): IDatabaseBuilder;
5
+ withMigrations(migrations: IMigration[]): IDatabaseBuilder;
6
+ build(): Promise<{
7
+ success: boolean;
8
+ error: Error | null;
9
+ }>;
10
+ }
@@ -0,0 +1,62 @@
1
+ import { CreateMigrationTableMigration } from "./001-create-migrations-table.migration.js";
2
+ import { CreateUsersTableMigration } from "./003-create-users-table.migration.js";
3
+ import { CreateAdminUserMigration } from "./006-create-admin-user.migration.js";
4
+ import { CreateUserRolesTableMigration } from "./008-create-user-roles-table.migration.js";
5
+ import { CreateAuthorizationsTableMigration } from "./010-create-authorizations-table.migration.js";
6
+ import { CreateFeaturesTableMigration } from "./009-create-features-table.migration.js";
7
+ import { CreateRoleTableMigration } from "./007-create-roles-table.migration.js";
8
+ import { CreateRefreshTokenTableMigration } from "./004-create-refresh-tokens-table.migration.js";
9
+ import { CreateAdminAuthorizationMigration } from "./011-create-admin-authorization.migration.js";
10
+ import { CreateMetaOrgMigration } from "./005-create-meta-org.migration.js";
11
+ import { CreateOrganizationsTableMigration } from "./002-create-organizations-table.migration.js";
12
+ import { doesTableExist } from "../utils/index.js";
13
+ export class DatabaseBuilder {
14
+ client;
15
+ migrationsToRun = [];
16
+ constructor(client) {
17
+ this.client = client;
18
+ }
19
+ withAuth() {
20
+ this.migrationsToRun.push(new CreateMigrationTableMigration(this.client));
21
+ this.migrationsToRun.push(new CreateUsersTableMigration(this.client));
22
+ this.migrationsToRun.push(new CreateRefreshTokenTableMigration(this.client));
23
+ this.migrationsToRun.push(new CreateAdminUserMigration(this.client));
24
+ this.migrationsToRun.push(new CreateRoleTableMigration(this.client));
25
+ this.migrationsToRun.push(new CreateUserRolesTableMigration(this.client));
26
+ this.migrationsToRun.push(new CreateFeaturesTableMigration(this.client));
27
+ this.migrationsToRun.push(new CreateAuthorizationsTableMigration(this.client));
28
+ this.migrationsToRun.push(new CreateAdminAuthorizationMigration(this.client));
29
+ return this;
30
+ }
31
+ withMultitenant() {
32
+ this.migrationsToRun.push(new CreateMigrationTableMigration(this.client));
33
+ this.migrationsToRun.push(new CreateOrganizationsTableMigration(this.client));
34
+ this.migrationsToRun.push(new CreateMetaOrgMigration(this.client));
35
+ return this;
36
+ }
37
+ withMigrations(migrations) {
38
+ this.migrationsToRun.push(...migrations);
39
+ return this;
40
+ }
41
+ async build() {
42
+ let runMigrations = [];
43
+ if (await doesTableExist(this.client, 'migrations')) {
44
+ const migrations = await this.client.query(`
45
+ SELECT "_id", "index"
46
+ FROM migrations
47
+ WHERE "hasRun" = TRUE AND "reverted" = FALSE
48
+ `);
49
+ runMigrations = migrations.rows.map((row) => {
50
+ return row.index;
51
+ });
52
+ }
53
+ const orderedMigrations = this.migrationsToRun.filter((migration) => !runMigrations.includes(migration.index)).sort((migration) => migration.index);
54
+ for (const migration of orderedMigrations) {
55
+ const result = await migration.execute();
56
+ if (!result.success) {
57
+ return result;
58
+ }
59
+ }
60
+ return { success: true, error: null };
61
+ }
62
+ }
@@ -1,5 +1,8 @@
1
1
  import { Client } from "pg";
2
- export declare function setupDatabaseForAuth(client: Client, adminEmail: string, adminPassword: string, metaOrgId?: string): Promise<{
2
+ export declare function setupDatabaseForAuth(client: Client): Promise<{
3
3
  success: boolean;
4
- error: Error | null;
4
+ error: Error;
5
+ } | {
6
+ success: boolean;
7
+ error: null;
5
8
  }>;
@@ -8,7 +8,7 @@ import { CreateRoleTableMigration } from "./007-create-roles-table.migration.js"
8
8
  import { CreateAuthorizationsTableMigration } from "./010-create-authorizations-table.migration.js";
9
9
  import { CreateFeaturesTableMigration } from "./009-create-features-table.migration.js";
10
10
  import { CreateAdminAuthorizationMigration } from "./011-create-admin-authorization.migration.js";
11
- export async function setupDatabaseForAuth(client, adminEmail, adminPassword, metaOrgId) {
11
+ export async function setupDatabaseForAuth(client) {
12
12
  let runMigrations = [];
13
13
  if (await doesTableExist(client, 'migrations')) {
14
14
  const migrations = await client.query(`
@@ -20,13 +20,12 @@ export async function setupDatabaseForAuth(client, adminEmail, adminPassword, me
20
20
  return row.index;
21
21
  });
22
22
  }
23
- let adminUserId;
24
23
  if (!runMigrations.includes(1)) {
25
24
  const migration = new CreateMigrationTableMigration(client);
26
25
  const result = await migration.execute();
27
26
  if (!result.success) {
28
27
  console.error('setupDatabaseForAuth: error creating migrations table', result.error);
29
- return { success: false, error: result.error };
28
+ return result;
30
29
  }
31
30
  }
32
31
  if (!runMigrations.includes(3)) {
@@ -34,7 +33,7 @@ export async function setupDatabaseForAuth(client, adminEmail, adminPassword, me
34
33
  const result = await migration.execute();
35
34
  if (!result.success) {
36
35
  console.error('setupDatabaseForAuth: error creating users table', result.error);
37
- return { success: false, error: result.error };
36
+ return result;
38
37
  }
39
38
  }
40
39
  if (!runMigrations.includes(4)) {
@@ -42,24 +41,23 @@ export async function setupDatabaseForAuth(client, adminEmail, adminPassword, me
42
41
  const result = await migration.execute();
43
42
  if (!result.success) {
44
43
  console.error('setupDatabaseForAuth: error creating refresh_tokens table', result.error);
45
- return { success: false, error: result.error };
44
+ return result;
46
45
  }
47
46
  }
48
47
  if (!runMigrations.includes(6)) {
49
48
  const migration = new CreateAdminUserMigration(client);
50
- const result = await migration.execute(adminEmail, adminPassword, metaOrgId);
49
+ const result = await migration.execute();
51
50
  if (!result.success) {
52
51
  console.error('setupDatabaseForAuth: error creating admin user', result.error);
53
- return { success: false, error: result.error };
52
+ return result;
54
53
  }
55
- adminUserId = result.adminUserId;
56
54
  }
57
55
  if (!runMigrations.includes(7)) {
58
56
  const migration = new CreateRoleTableMigration(client);
59
57
  const result = await migration.execute();
60
58
  if (!result.success) {
61
59
  console.error('setupDatabaseForAuth: error creating roles table', result.error);
62
- return { success: false, error: result.error };
60
+ return result;
63
61
  }
64
62
  }
65
63
  if (!runMigrations.includes(8)) {
@@ -67,7 +65,7 @@ export async function setupDatabaseForAuth(client, adminEmail, adminPassword, me
67
65
  const result = await migration.execute();
68
66
  if (!result.success) {
69
67
  console.error('setupDatabaseForAuth: error creating user_roles table', result.error);
70
- return { success: false, error: result.error };
68
+ return result;
71
69
  }
72
70
  }
73
71
  if (!runMigrations.includes(9)) {
@@ -75,7 +73,7 @@ export async function setupDatabaseForAuth(client, adminEmail, adminPassword, me
75
73
  const result = await migration.execute();
76
74
  if (!result.success) {
77
75
  console.error('setupDatabaseForAuth: error creating features table', result.error);
78
- return { success: false, error: result.error };
76
+ return result;
79
77
  }
80
78
  }
81
79
  if (!runMigrations.includes(10)) {
@@ -83,19 +81,15 @@ export async function setupDatabaseForAuth(client, adminEmail, adminPassword, me
83
81
  const result = await migration.execute();
84
82
  if (!result.success) {
85
83
  console.error('setupDatabaseForAuth: error creating authorizations table', result.error);
86
- return { success: false, error: result.error };
84
+ return result;
87
85
  }
88
86
  }
89
87
  if (!runMigrations.includes(11)) {
90
- if (!adminUserId) {
91
- console.error('setupDatabaseForAuth: Admin user ID is required');
92
- return { success: false, error: new Error('Admin user ID is required') };
93
- }
94
- const migration = new CreateAdminAuthorizationMigration(client, adminUserId, metaOrgId);
88
+ const migration = new CreateAdminAuthorizationMigration(client);
95
89
  const result = await migration.execute();
96
90
  if (!result.success) {
97
91
  console.error('setupDatabaseForAuth: error creating admin authorization', result.error);
98
- return { success: false, error: result.error };
92
+ return result;
99
93
  }
100
94
  }
101
95
  return { success: true, error: null };
@@ -1,6 +1,8 @@
1
1
  import { Client } from "pg";
2
- export declare function setupDatabaseForMultitenant(client: Client, metaOrgName: string, metaOrgCode: string): Promise<{
2
+ export declare function setupDatabaseForMultitenant(client: Client): Promise<{
3
3
  success: boolean;
4
- metaOrgId: string | undefined;
5
- error: Error | null;
4
+ error: Error;
5
+ } | {
6
+ success: boolean;
7
+ error: null;
6
8
  }>;
@@ -2,9 +2,8 @@ import { CreateMigrationTableMigration } from "./001-create-migrations-table.mig
2
2
  import { CreateOrganizationsTableMigration } from "./002-create-organizations-table.migration.js";
3
3
  import { doesTableExist } from "../utils/does-table-exist.util.js";
4
4
  import { CreateMetaOrgMigration } from "./005-create-meta-org.migration.js";
5
- export async function setupDatabaseForMultitenant(client, metaOrgName, metaOrgCode) {
5
+ export async function setupDatabaseForMultitenant(client) {
6
6
  let runMigrations = [];
7
- let metaOrgId;
8
7
  if (await doesTableExist(client, 'migrations')) {
9
8
  const migrations = await client.query(`
10
9
  SELECT "_id", "index"
@@ -20,7 +19,7 @@ export async function setupDatabaseForMultitenant(client, metaOrgName, metaOrgCo
20
19
  const result = await createMigrationTableMigration.execute();
21
20
  if (!result.success) {
22
21
  console.log('setupDatabaseForMultitenant: error creating migration table', result.error);
23
- return { success: false, metaOrgId: metaOrgId, error: result.error };
22
+ return result;
24
23
  }
25
24
  }
26
25
  if (!runMigrations.includes(2)) {
@@ -28,17 +27,16 @@ export async function setupDatabaseForMultitenant(client, metaOrgName, metaOrgCo
28
27
  const result = await createOrganizationTableMigration.execute();
29
28
  if (!result.success) {
30
29
  console.log('setupDatabaseForMultitenant: error creating organizations table', result.error);
31
- return { success: false, metaOrgId: metaOrgId, error: result.error };
30
+ return result;
32
31
  }
33
32
  }
34
33
  if (!runMigrations.includes(5)) {
35
- const createMetaOrgMigration = new CreateMetaOrgMigration(client, metaOrgName, metaOrgCode);
34
+ const createMetaOrgMigration = new CreateMetaOrgMigration(client);
36
35
  const result = await createMetaOrgMigration.execute();
37
- if (!result.success || !result.metaOrgId) {
36
+ if (!result.success) {
38
37
  console.log('setupDatabaseForMultitenant: error creating meta org', result.error);
39
- return { success: false, metaOrgId: result.metaOrgId, error: result.error };
38
+ return result;
40
39
  }
41
- metaOrgId = result.metaOrgId;
42
40
  }
43
- return { success: true, metaOrgId: metaOrgId, error: null };
41
+ return { success: true, error: null };
44
42
  }
@@ -17,6 +17,12 @@ export interface IBaseApiConfig {
17
17
  };
18
18
  app: {
19
19
  isMultiTenant: boolean;
20
+ metaOrgName?: string;
21
+ metaOrgCode?: string;
22
+ };
23
+ adminUser?: {
24
+ email: string;
25
+ password: string;
20
26
  };
21
27
  auth: {
22
28
  jwtExpirationInSeconds: number;
@@ -24,10 +30,10 @@ export interface IBaseApiConfig {
24
30
  deviceIdCookieMaxAgeInDays: number;
25
31
  passwordResetTokenExpirationInMinutes: number;
26
32
  };
27
- email: {
28
- emailApiKey?: string;
29
- emailApiSecret?: string;
30
- fromAddress?: string;
31
- systemEmailAddress?: string;
33
+ email?: {
34
+ emailApiKey: string;
35
+ emailApiSecret: string;
36
+ fromAddress: string;
37
+ systemEmailAddress: string;
32
38
  };
33
39
  }
@@ -5,16 +5,19 @@ export class EmailService {
5
5
  mailjet;
6
6
  constructor() {
7
7
  this.mailjet = new Mailjet.default({
8
- apiKey: config.email.emailApiKey || '',
9
- apiSecret: config.email.emailApiSecret || ''
8
+ apiKey: config.email?.emailApiKey || '',
9
+ apiSecret: config.email?.emailApiSecret || ''
10
10
  });
11
11
  }
12
12
  async sendHtmlEmail(emailAddress, subject, body) {
13
+ if (!config.email?.fromAddress) {
14
+ throw new ServerError('From address is not set in the config');
15
+ }
13
16
  const messageData = {
14
17
  Messages: [
15
18
  {
16
19
  From: {
17
- Email: config.email.fromAddress,
20
+ Email: config.email?.fromAddress,
18
21
  Name: config.appName || 'Application'
19
22
  },
20
23
  To: [