@loomcore/api 0.1.87 → 0.1.89
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/dist/__tests__/common-test.utils.js +0 -4
- package/dist/__tests__/postgres.test-database.d.ts +1 -1
- package/dist/__tests__/postgres.test-database.js +3 -3
- package/dist/__tests__/test-database.interface.d.ts +1 -1
- package/dist/__tests__/test-express-app.js +1 -1
- package/dist/databases/migrations/migration-runner.d.ts +3 -1
- package/dist/databases/migrations/migration-runner.js +6 -1
- package/dist/databases/mongo-db/migrations/mongo-initial-schema.d.ts +2 -1
- package/dist/databases/mongo-db/migrations/mongo-initial-schema.js +8 -8
- package/dist/databases/postgres/commands/postgres-partial-update-by-id.command.js +0 -3
- package/dist/databases/postgres/migrations/__tests__/test-migration-helper.js +1 -1
- package/dist/databases/postgres/migrations/postgres-initial-schema.d.ts +2 -1
- package/dist/databases/postgres/migrations/postgres-initial-schema.js +8 -8
- package/dist/models/auth-config.interface.d.ts +0 -4
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +1 -0
- package/dist/models/reset-api-config.interface.d.ts +6 -0
- package/dist/models/reset-api-config.interface.js +1 -0
- package/package.json +2 -2
|
@@ -200,10 +200,6 @@ export function setupTestConfig(isMultiTenant = true, dbType) {
|
|
|
200
200
|
dbType: dbType,
|
|
201
201
|
},
|
|
202
202
|
auth: {
|
|
203
|
-
adminUser: {
|
|
204
|
-
email: 'admin@test.com',
|
|
205
|
-
password: 'admin-password'
|
|
206
|
-
},
|
|
207
203
|
clientSecret: 'test-secret',
|
|
208
204
|
saltWorkFactor: 10,
|
|
209
205
|
jwtExpirationInSeconds: 3600,
|
|
@@ -5,7 +5,7 @@ export declare class TestPostgresDatabase implements ITestDatabase {
|
|
|
5
5
|
private postgresClient;
|
|
6
6
|
private postgresPool;
|
|
7
7
|
private initPromise;
|
|
8
|
-
init(
|
|
8
|
+
init(): Promise<IDatabase>;
|
|
9
9
|
getRandomId(): string;
|
|
10
10
|
private _performInit;
|
|
11
11
|
private createIndexes;
|
|
@@ -10,17 +10,17 @@ export class TestPostgresDatabase {
|
|
|
10
10
|
postgresClient = null;
|
|
11
11
|
postgresPool = null;
|
|
12
12
|
initPromise = null;
|
|
13
|
-
async init(
|
|
13
|
+
async init() {
|
|
14
14
|
if (this.initPromise) {
|
|
15
15
|
return this.initPromise;
|
|
16
16
|
}
|
|
17
|
-
this.initPromise = this._performInit(
|
|
17
|
+
this.initPromise = this._performInit();
|
|
18
18
|
return this.initPromise;
|
|
19
19
|
}
|
|
20
20
|
getRandomId() {
|
|
21
21
|
throw new Error('getRandomId() should not be used for PostgreSQL _id fields. PostgreSQL uses auto-generated integer IDs. Remove _id from entities and let the database generate it.');
|
|
22
22
|
}
|
|
23
|
-
async _performInit(
|
|
23
|
+
async _performInit() {
|
|
24
24
|
if (!this.database) {
|
|
25
25
|
let postgresClient;
|
|
26
26
|
let pool;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IDatabase } from "../databases/models/index.js";
|
|
2
2
|
export type ITestDatabase = {
|
|
3
|
-
init(
|
|
3
|
+
init(): Promise<IDatabase>;
|
|
4
4
|
getRandomId(): string;
|
|
5
5
|
clearCollections(): Promise<void>;
|
|
6
6
|
cleanup(): Promise<void>;
|
|
@@ -36,7 +36,7 @@ export class TestExpressApp {
|
|
|
36
36
|
else {
|
|
37
37
|
const testPostgresDb = new TestPostgresDatabase();
|
|
38
38
|
this.testDatabase = testPostgresDb;
|
|
39
|
-
this.database = await testPostgresDb.init(
|
|
39
|
+
this.database = await testPostgresDb.init();
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
if (!this.app) {
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { IBaseApiConfig } from '../../models/base-api-config.interface.js';
|
|
2
|
+
import { IResetApiConfig } from '../../models/reset-api-config.interface.js';
|
|
2
3
|
export declare class MigrationRunner {
|
|
3
4
|
private config;
|
|
5
|
+
private resetConfig?;
|
|
4
6
|
private dbType;
|
|
5
7
|
private dbUrl;
|
|
6
8
|
private migrationsDir;
|
|
7
9
|
private primaryTimezone;
|
|
8
10
|
private dbConnection;
|
|
9
|
-
constructor(config: IBaseApiConfig);
|
|
11
|
+
constructor(config: IBaseApiConfig, resetConfig?: IResetApiConfig);
|
|
10
12
|
private getTimestamp;
|
|
11
13
|
private parseSql;
|
|
12
14
|
private getMigrator;
|
|
@@ -10,14 +10,16 @@ import { getPostgresInitialSchema } from '../postgres/migrations/postgres-initia
|
|
|
10
10
|
import { getMongoInitialSchema } from '../mongo-db/migrations/mongo-initial-schema.js';
|
|
11
11
|
export class MigrationRunner {
|
|
12
12
|
config;
|
|
13
|
+
resetConfig;
|
|
13
14
|
dbType;
|
|
14
15
|
dbUrl;
|
|
15
16
|
migrationsDir;
|
|
16
17
|
primaryTimezone;
|
|
17
18
|
dbConnection;
|
|
18
|
-
constructor(config) {
|
|
19
|
+
constructor(config, resetConfig) {
|
|
19
20
|
setBaseApiConfig(config);
|
|
20
21
|
this.config = config;
|
|
22
|
+
this.resetConfig = resetConfig;
|
|
21
23
|
this.dbType = config.app.dbType;
|
|
22
24
|
this.dbUrl = this.dbType === 'postgres' ? buildPostgresUrl(config) : buildMongoUrl(config);
|
|
23
25
|
this.migrationsDir = path.join(process.cwd(), 'database', 'migrations');
|
|
@@ -186,6 +188,9 @@ export class MigrationRunner {
|
|
|
186
188
|
async run(command = 'up', target) {
|
|
187
189
|
try {
|
|
188
190
|
if (command === 'reset') {
|
|
191
|
+
if (!this.resetConfig) {
|
|
192
|
+
throw new Error('Reset configuration not found');
|
|
193
|
+
}
|
|
189
194
|
await this.wipeDatabase();
|
|
190
195
|
console.log('🚀 Restarting migrations...');
|
|
191
196
|
const migrator = await this.getMigrator();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Db } from 'mongodb';
|
|
2
2
|
import { IBaseApiConfig } from '../../../models/base-api-config.interface.js';
|
|
3
|
+
import { IResetApiConfig } from '../../../models/reset-api-config.interface.js';
|
|
3
4
|
export interface ISyntheticMigration {
|
|
4
5
|
name: string;
|
|
5
6
|
up: (context: {
|
|
@@ -9,4 +10,4 @@ export interface ISyntheticMigration {
|
|
|
9
10
|
context: Db;
|
|
10
11
|
}) => Promise<void>;
|
|
11
12
|
}
|
|
12
|
-
export declare const getMongoInitialSchema: (config: IBaseApiConfig) => ISyntheticMigration[];
|
|
13
|
+
export declare const getMongoInitialSchema: (config: IBaseApiConfig, resetConfig?: IResetApiConfig) => ISyntheticMigration[];
|
|
@@ -2,7 +2,7 @@ import { randomUUID } from 'crypto';
|
|
|
2
2
|
import { initializeSystemUserContext, EmptyUserContext, getSystemUserContext, isSystemUserContextInitialized, personModelSpec } from '@loomcore/common/models';
|
|
3
3
|
import { MongoDBDatabase } from '../mongo-db.database.js';
|
|
4
4
|
import { AuthService, GenericApiService, OrganizationService } from '../../../services/index.js';
|
|
5
|
-
export const getMongoInitialSchema = (config) => {
|
|
5
|
+
export const getMongoInitialSchema = (config, resetConfig) => {
|
|
6
6
|
const migrations = [];
|
|
7
7
|
const isMultiTenant = config.app.isMultiTenant;
|
|
8
8
|
if (isMultiTenant && !config.multiTenant) {
|
|
@@ -161,7 +161,7 @@ export const getMongoInitialSchema = (config) => {
|
|
|
161
161
|
}
|
|
162
162
|
});
|
|
163
163
|
}
|
|
164
|
-
if (isAuthEnabled) {
|
|
164
|
+
if (isAuthEnabled && resetConfig) {
|
|
165
165
|
migrations.push({
|
|
166
166
|
name: '00000000000009_data-admin-user',
|
|
167
167
|
up: async ({ context: db }) => {
|
|
@@ -198,19 +198,19 @@ export const getMongoInitialSchema = (config) => {
|
|
|
198
198
|
_id: _id,
|
|
199
199
|
_orgId: systemUserContext.organization?._id,
|
|
200
200
|
externalId: 'admin-user-external-id',
|
|
201
|
-
email:
|
|
202
|
-
password:
|
|
201
|
+
email: resetConfig.adminUser.email,
|
|
202
|
+
password: resetConfig.adminUser.password,
|
|
203
203
|
displayName: 'Admin User',
|
|
204
204
|
}, person);
|
|
205
205
|
},
|
|
206
206
|
down: async ({ context: db }) => {
|
|
207
|
-
if (!
|
|
207
|
+
if (!resetConfig?.adminUser?.email)
|
|
208
208
|
return;
|
|
209
|
-
await db.collection('users').deleteOne({ email:
|
|
209
|
+
await db.collection('users').deleteOne({ email: resetConfig.adminUser.email });
|
|
210
210
|
}
|
|
211
211
|
});
|
|
212
212
|
}
|
|
213
|
-
if (
|
|
213
|
+
if (resetConfig?.adminUser?.email && isMultiTenant) {
|
|
214
214
|
migrations.push({
|
|
215
215
|
name: '00000000000010_data-admin-authorizations',
|
|
216
216
|
up: async ({ context: db }) => {
|
|
@@ -221,7 +221,7 @@ export const getMongoInitialSchema = (config) => {
|
|
|
221
221
|
if (!metaOrg) {
|
|
222
222
|
throw new Error('Meta organization not found. Ensure meta-org migration ran successfully.');
|
|
223
223
|
}
|
|
224
|
-
const adminUser = await authService.getUserByEmail(
|
|
224
|
+
const adminUser = await authService.getUserByEmail(resetConfig.adminUser.email);
|
|
225
225
|
if (!adminUser) {
|
|
226
226
|
throw new Error('Admin user not found. Ensure admin-user migration ran successfully.');
|
|
227
227
|
}
|
|
@@ -3,10 +3,7 @@ import { buildJoinClauses } from '../utils/build-join-clauses.js';
|
|
|
3
3
|
import { columnsAndValuesFromEntity } from '../utils/columns-and-values-from-entity.js';
|
|
4
4
|
export async function partialUpdateById(client, operations, id, entity, pluralResourceName) {
|
|
5
5
|
try {
|
|
6
|
-
console.log('entity', JSON.stringify(entity, null, 2));
|
|
7
6
|
const { columns, values } = columnsAndValuesFromEntity(entity);
|
|
8
|
-
console.log('columns', JSON.stringify(columns, null, 2));
|
|
9
|
-
console.log('values', JSON.stringify(values, null, 2));
|
|
10
7
|
const updateColumns = columns.filter(col => col !== '"_id"');
|
|
11
8
|
const updateValues = values.filter((_, index) => columns[index] !== '"_id"');
|
|
12
9
|
if (updateColumns.length === 0) {
|
|
@@ -2,7 +2,7 @@ import { Umzug } from 'umzug';
|
|
|
2
2
|
import { getPostgresInitialSchema } from '../postgres-initial-schema.js';
|
|
3
3
|
import { getPostgresTestSchema } from '../../../../__tests__/postgres-test-migrations/postgres-test-schema.js';
|
|
4
4
|
export async function runInitialSchemaMigrations(pool, config) {
|
|
5
|
-
const initialSchema = getPostgresInitialSchema(config);
|
|
5
|
+
const initialSchema = getPostgresInitialSchema(config, { adminUser: { email: 'admin@test.com', password: 'admin-password' } });
|
|
6
6
|
const umzug = new Umzug({
|
|
7
7
|
migrations: async () => {
|
|
8
8
|
return initialSchema.map(m => ({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Pool } from 'pg';
|
|
2
2
|
import { IBaseApiConfig } from '../../../models/base-api-config.interface.js';
|
|
3
|
+
import { IResetApiConfig } from '../../../models/reset-api-config.interface.js';
|
|
3
4
|
export interface SyntheticMigration {
|
|
4
5
|
name: string;
|
|
5
6
|
up: (context: {
|
|
@@ -9,4 +10,4 @@ export interface SyntheticMigration {
|
|
|
9
10
|
context: Pool;
|
|
10
11
|
}) => Promise<void>;
|
|
11
12
|
}
|
|
12
|
-
export declare const getPostgresInitialSchema: (config: IBaseApiConfig) => SyntheticMigration[];
|
|
13
|
+
export declare const getPostgresInitialSchema: (config: IBaseApiConfig, resetConfig?: IResetApiConfig) => SyntheticMigration[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { initializeSystemUserContext, EmptyUserContext, getSystemUserContext, isSystemUserContextInitialized } from '@loomcore/common/models';
|
|
2
2
|
import { PostgresDatabase } from '../postgres.database.js';
|
|
3
3
|
import { AuthService, OrganizationService } from '../../../services/index.js';
|
|
4
|
-
export const getPostgresInitialSchema = (config) => {
|
|
4
|
+
export const getPostgresInitialSchema = (config, resetConfig) => {
|
|
5
5
|
const migrations = [];
|
|
6
6
|
const isMultiTenant = config.app.isMultiTenant;
|
|
7
7
|
if (isMultiTenant && !config.multiTenant) {
|
|
@@ -285,7 +285,7 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
285
285
|
}
|
|
286
286
|
});
|
|
287
287
|
}
|
|
288
|
-
if (isAuthEnabled) {
|
|
288
|
+
if (isAuthEnabled && resetConfig?.adminUser) {
|
|
289
289
|
migrations.push({
|
|
290
290
|
name: '00000000000011_data-admin-user',
|
|
291
291
|
up: async ({ context: pool }) => {
|
|
@@ -304,8 +304,8 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
304
304
|
}
|
|
305
305
|
const systemUserContext = getSystemUserContext();
|
|
306
306
|
const userData = {
|
|
307
|
-
email:
|
|
308
|
-
password:
|
|
307
|
+
email: resetConfig.adminUser.email,
|
|
308
|
+
password: resetConfig.adminUser.password,
|
|
309
309
|
displayName: 'Admin User',
|
|
310
310
|
};
|
|
311
311
|
if (isMultiTenant && systemUserContext.organization?._id) {
|
|
@@ -325,13 +325,13 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
325
325
|
}
|
|
326
326
|
},
|
|
327
327
|
down: async ({ context: pool }) => {
|
|
328
|
-
if (!
|
|
328
|
+
if (!resetConfig?.adminUser?.email)
|
|
329
329
|
return;
|
|
330
|
-
const result = await pool.query(`DELETE FROM "users" WHERE "email" = $1`, [
|
|
330
|
+
const result = await pool.query(`DELETE FROM "users" WHERE "email" = $1`, [resetConfig.adminUser.email]);
|
|
331
331
|
}
|
|
332
332
|
});
|
|
333
333
|
}
|
|
334
|
-
if (config.auth) {
|
|
334
|
+
if (config.auth && resetConfig) {
|
|
335
335
|
migrations.push({
|
|
336
336
|
name: '00000000000012_data-admin-authorizations',
|
|
337
337
|
up: async ({ context: pool }) => {
|
|
@@ -344,7 +344,7 @@ export const getPostgresInitialSchema = (config) => {
|
|
|
344
344
|
if (isMultiTenant && !metaOrg) {
|
|
345
345
|
throw new Error('Meta organization not found. Ensure meta-org migration ran successfully.');
|
|
346
346
|
}
|
|
347
|
-
const adminUser = await authService.getUserByEmail(
|
|
347
|
+
const adminUser = await authService.getUserByEmail(resetConfig.adminUser.email);
|
|
348
348
|
if (!adminUser) {
|
|
349
349
|
throw new Error('Admin user not found. Ensure admin-user migration ran successfully.');
|
|
350
350
|
}
|
package/dist/models/index.d.ts
CHANGED
package/dist/models/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loomcore/api",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.89",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Loom Core Api - An opinionated Node.js api using Typescript, Express, and MongoDb or PostgreSQL",
|
|
6
6
|
"scripts": {
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"jsonwebtoken": "^9.0.2",
|
|
56
56
|
"node-mailjet": "^6.0.8",
|
|
57
|
-
"qs": "^6.
|
|
57
|
+
"qs": "^6.15.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@loomcore/common": "^0.0.50",
|