@loomcore/api 0.1.73 → 0.1.75

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 +77 -77
  3. package/dist/__tests__/common-test.utils.js +4 -1
  4. package/dist/__tests__/postgres-test-migrations/postgres-test-schema.js +239 -239
  5. package/dist/__tests__/postgres.test-database.js +8 -8
  6. package/dist/controllers/auth.controller.d.ts +1 -2
  7. package/dist/controllers/auth.controller.js +2 -2
  8. package/dist/databases/migrations/migration-runner.d.ts +1 -3
  9. package/dist/databases/migrations/migration-runner.js +24 -26
  10. package/dist/databases/mongo-db/migrations/mongo-initial-schema.d.ts +1 -2
  11. package/dist/databases/mongo-db/migrations/mongo-initial-schema.js +4 -4
  12. package/dist/databases/postgres/commands/postgres-batch-update.command.js +7 -7
  13. package/dist/databases/postgres/commands/postgres-create-many.command.js +4 -4
  14. package/dist/databases/postgres/commands/postgres-create.command.js +4 -4
  15. package/dist/databases/postgres/commands/postgres-full-update-by-id.command.js +13 -13
  16. package/dist/databases/postgres/commands/postgres-partial-update-by-id.command.js +7 -7
  17. package/dist/databases/postgres/commands/postgres-update.command.js +7 -7
  18. package/dist/databases/postgres/migrations/__tests__/test-migration-helper.js +1 -2
  19. package/dist/databases/postgres/migrations/postgres-initial-schema.d.ts +1 -2
  20. package/dist/databases/postgres/migrations/postgres-initial-schema.js +201 -201
  21. package/dist/databases/postgres/postgres.database.js +17 -17
  22. package/dist/databases/postgres/utils/build-join-clauses.js +22 -22
  23. package/dist/databases/postgres/utils/build-select-clause.js +6 -6
  24. package/dist/databases/postgres/utils/does-table-exist.util.js +4 -4
  25. package/dist/models/base-api-config.interface.d.ts +4 -0
  26. package/dist/services/auth.service.d.ts +1 -2
  27. package/dist/services/auth.service.js +2 -2
  28. package/dist/services/email.service.d.ts +1 -2
  29. package/dist/services/email.service.js +7 -2
  30. package/dist/services/generic-query-service/generic-query-service.interface.d.ts +1 -1
  31. package/dist/services/generic-query-service/generic-query.service.d.ts +2 -1
  32. package/dist/services/generic-query-service/generic-query.service.js +8 -4
  33. package/package.json +92 -92
@@ -3,12 +3,12 @@ import { JoinMany } from '../../operations/join-many.operation.js';
3
3
  import { JoinThrough } from '../../operations/join-through.operation.js';
4
4
  import { JoinThroughMany } from '../../operations/join-through-many.operation.js';
5
5
  async function getTableColumns(client, tableName) {
6
- const result = await client.query(`
7
- SELECT column_name
8
- FROM information_schema.columns
9
- WHERE table_schema = current_schema()
10
- AND table_name = $1
11
- ORDER BY ordinal_position
6
+ const result = await client.query(`
7
+ SELECT column_name
8
+ FROM information_schema.columns
9
+ WHERE table_schema = current_schema()
10
+ AND table_name = $1
11
+ ORDER BY ordinal_position
12
12
  `, [tableName]);
13
13
  return result.rows.map(row => row.column_name);
14
14
  }
@@ -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,6 +1,7 @@
1
1
  import { DbType } from "../databases/db-type.type.js";
2
2
  import { IAuthConfig } from "./auth-config.interface.js";
3
3
  import { IEmailConfig } from "./email-config.interface.js";
4
+ import { IEmailClient } from "./email-client.interface.js";
4
5
  import { IMultiTenantConfig } from "./multi-tenant-config.interface.js";
5
6
  export interface IBaseApiConfig {
6
7
  app: {
@@ -30,4 +31,7 @@ export interface IBaseApiConfig {
30
31
  hostName: string;
31
32
  internalPort?: number;
32
33
  };
34
+ thirdPartyClients?: {
35
+ emailClient?: IEmailClient;
36
+ };
33
37
  }
@@ -5,14 +5,13 @@ import { MultiTenantApiService } from './multi-tenant-api.service.js';
5
5
  import { UpdateResult } from '../databases/models/update-result.js';
6
6
  import { IRefreshToken } from '../models/refresh-token.model.js';
7
7
  import { IDatabase } from '../databases/models/index.js';
8
- import { IEmailClient } from '../models/email-client.interface.js';
9
8
  export declare class AuthService extends MultiTenantApiService<IUser> {
10
9
  private refreshTokenService;
11
10
  private passwordResetTokenService;
12
11
  private emailService;
13
12
  private organizationService;
14
13
  private authConfig;
15
- constructor(database: IDatabase, emailClient: IEmailClient);
14
+ constructor(database: IDatabase);
16
15
  attemptLogin(req: Request, res: Response, email: string, password: string): Promise<ILoginResponse | null>;
17
16
  logUserIn(userContext: IUserContext, deviceId: string): Promise<{
18
17
  tokens: {
@@ -18,11 +18,11 @@ export class AuthService extends MultiTenantApiService {
18
18
  emailService;
19
19
  organizationService;
20
20
  authConfig;
21
- constructor(database, emailClient) {
21
+ constructor(database) {
22
22
  super(database, 'users', 'user', UserSpec);
23
23
  this.refreshTokenService = new GenericApiService(database, 'refresh_tokens', 'refresh_token', refreshTokenModelSpec);
24
24
  this.passwordResetTokenService = new PasswordResetTokenService(database);
25
- this.emailService = new EmailService(emailClient);
25
+ this.emailService = new EmailService();
26
26
  this.organizationService = new OrganizationService(database);
27
27
  if (!config.auth) {
28
28
  throw new ServerError('Auth configuration is not set');
@@ -1,7 +1,6 @@
1
- import { IEmailClient } from '../models/email-client.interface.js';
2
1
  export declare class EmailService {
3
2
  private emailConfig;
4
3
  private emailClient;
5
- constructor(emailClient: IEmailClient);
4
+ constructor();
6
5
  sendHtmlEmail(emailAddress: string, subject: string, body: string): Promise<void>;
7
6
  }
@@ -3,14 +3,19 @@ import { config } from '../config/index.js';
3
3
  export class EmailService {
4
4
  emailConfig;
5
5
  emailClient;
6
- constructor(emailClient) {
6
+ constructor() {
7
7
  if (config.email) {
8
8
  this.emailConfig = config.email;
9
9
  }
10
10
  else {
11
11
  throw new ServerError('Email configuration is not available. Email API credentials are not set in the config.');
12
12
  }
13
- this.emailClient = emailClient;
13
+ if (config.thirdPartyClients?.emailClient) {
14
+ this.emailClient = config.thirdPartyClients.emailClient;
15
+ }
16
+ else {
17
+ throw new ServerError('Email client is not available. Email client is not set in the config.');
18
+ }
14
19
  }
15
20
  async sendHtmlEmail(emailAddress, subject, body) {
16
21
  const messageData = {
@@ -7,7 +7,7 @@ export interface IGenericQueryService<T extends IEntity> {
7
7
  operations: Operation[];
8
8
  };
9
9
  prepareQueryOptions(userContext: IUserContext | undefined, queryOptions: IQueryOptions): IQueryOptions;
10
- postProcessEntity(userContext: IUserContext, entity: T): T;
10
+ postProcessEntity(userContext: IUserContext, entity: any): T;
11
11
  getAll(userContext: IUserContext): Promise<T[]>;
12
12
  get(userContext: IUserContext, queryOptions: IQueryOptions): Promise<IPagedResult<T>>;
13
13
  getById(userContext: IUserContext, id: AppIdType): Promise<T>;
@@ -14,7 +14,8 @@ export declare class GenericQueryService<T extends IEntity> implements IGenericQ
14
14
  operations: Operation[];
15
15
  };
16
16
  prepareQueryOptions(userContext: IUserContext | undefined, queryOptions: IQueryOptions): IQueryOptions;
17
- postProcessEntity(userContext: IUserContext, entity: T): T;
17
+ protected postProcessEntityInternal(userContext: IUserContext, entity: any): T;
18
+ postProcessEntity(userContext: IUserContext, entity: any): T;
18
19
  getAll(userContext: IUserContext): Promise<T[]>;
19
20
  get(userContext: IUserContext, queryOptions?: IQueryOptions): Promise<IPagedResult<T>>;
20
21
  getById(userContext: IUserContext, id: AppIdType): Promise<T>;
@@ -18,19 +18,23 @@ export class GenericQueryService {
18
18
  prepareQueryOptions(userContext, queryOptions) {
19
19
  return queryOptions;
20
20
  }
21
+ postProcessEntityInternal(userContext, entity) {
22
+ const dbPostProcessedEntity = this.database.postProcessEntity(entity, this.modelSpec.fullSchema);
23
+ return this.postProcessEntity(userContext, dbPostProcessedEntity);
24
+ }
21
25
  postProcessEntity(userContext, entity) {
22
- return this.database.postProcessEntity(entity, this.modelSpec.fullSchema);
26
+ return entity;
23
27
  }
24
28
  async getAll(userContext) {
25
29
  const { operations } = this.prepareQuery(userContext, {}, []);
26
30
  const entities = await this.database.getAll(operations, this.rootTableName);
27
- return entities.map(entity => this.postProcessEntity(userContext, entity));
31
+ return entities.map(entity => this.postProcessEntityInternal(userContext, entity));
28
32
  }
29
33
  async get(userContext, queryOptions = { ...DefaultQueryOptions }) {
30
34
  const preparedOptions = this.prepareQueryOptions(userContext, queryOptions);
31
35
  const { operations } = this.prepareQuery(userContext, {}, []);
32
36
  const pagedResult = await this.database.get(operations, preparedOptions, this.modelSpec, this.rootTableName);
33
- const transformedEntities = (pagedResult.entities || []).map(entity => this.postProcessEntity(userContext, entity));
37
+ const transformedEntities = (pagedResult.entities || []).map(entity => this.postProcessEntityInternal(userContext, entity));
34
38
  return {
35
39
  ...pagedResult,
36
40
  entities: transformedEntities
@@ -42,7 +46,7 @@ export class GenericQueryService {
42
46
  if (!entity) {
43
47
  throw new IdNotFoundError();
44
48
  }
45
- return this.postProcessEntity(userContext, entity);
49
+ return this.postProcessEntityInternal(userContext, entity);
46
50
  }
47
51
  async getCount(userContext) {
48
52
  const { operations } = this.prepareQuery(userContext, {}, []);
package/package.json CHANGED
@@ -1,92 +1,92 @@
1
- {
2
- "name": "@loomcore/api",
3
- "version": "0.1.73",
4
- "private": false,
5
- "description": "Loom Core Api - An opinionated Node.js api using Typescript, Express, and MongoDb or PostgreSQL",
6
- "scripts": {
7
- "clean": "rm -rf dist",
8
- "tsc": "tsc --project tsconfig.prod.json",
9
- "build": "npm-run-all -s clean tsc",
10
- "add": "git add .",
11
- "commit": "git commit -m \"Updates\"",
12
- "patch": "npm version patch",
13
- "push": "git push",
14
- "publishMe": "npm publish --access public",
15
- "pub": "npm-run-all -s add commit patch build push publishMe",
16
- "update-lib-versions": "npx --yes npm-check-updates -u -f @loomcore/common",
17
- "install-updated-libs": "npm i @loomcore/common",
18
- "update-libs": "npm-run-all -s update-lib-versions install-updated-libs",
19
- "typecheck": "tsc",
20
- "test": "npm-run-all -s test:postgres test:mongodb",
21
- "test:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run",
22
- "test:postgres:real": "cross-env NODE_ENV=test TEST_DATABASE=postgres USE_REAL_POSTGRES=true vitest run",
23
- "test:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run",
24
- "test:ci": "npm-run-all -s test:ci:postgres test:ci:mongodb",
25
- "test:ci:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --reporter=json --outputFile=test-results-postgres.json",
26
- "test:ci:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --reporter=json --outputFile=test-results-mongodb.json",
27
- "test:watch": "cross-env NODE_ENV=test vitest",
28
- "coverage": "npm-run-all -s coverage:postgres coverage:mongodb",
29
- "coverage:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --coverage",
30
- "coverage:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --coverage",
31
- "test:db:start": "docker-compose -f docker-compose.test.yml up -d",
32
- "test:db:stop": "docker-compose -f docker-compose.test.yml down",
33
- "test:db:logs": "docker-compose -f docker-compose.test.yml logs -f"
34
- },
35
- "author": "Tim Hardy",
36
- "license": "Apache 2.0",
37
- "main": "dist/index.js",
38
- "type": "module",
39
- "types": "dist/index.d.ts",
40
- "files": [
41
- "dist/**/*"
42
- ],
43
- "exports": {
44
- "./__tests__": "./dist/__tests__/index.js",
45
- "./config": "./dist/config/index.js",
46
- "./controllers": "./dist/controllers/index.js",
47
- "./databases": "./dist/databases/index.js",
48
- "./errors": "./dist/errors/index.js",
49
- "./middleware": "./dist/middleware/index.js",
50
- "./models": "./dist/models/index.js",
51
- "./services": "./dist/services/index.js",
52
- "./utils": "./dist/utils/index.js"
53
- },
54
- "dependencies": {
55
- "jsonwebtoken": "^9.0.2",
56
- "node-mailjet": "^6.0.8",
57
- "qs": "^6.14.1"
58
- },
59
- "peerDependencies": {
60
- "@loomcore/common": "^0.0.43",
61
- "@sinclair/typebox": "0.34.33",
62
- "cookie-parser": "^1.4.6",
63
- "cors": "^2.8.5",
64
- "express": "^5.1.0",
65
- "lodash": "^4.17.21",
66
- "moment": "^2.30.1",
67
- "mongodb": "^6.16.0",
68
- "pg": "^8.15.6",
69
- "rxjs": "^7.8.0",
70
- "umzug": "^3.8.2"
71
- },
72
- "devDependencies": {
73
- "@types/cookie-parser": "^1.4.7",
74
- "@types/cors": "^2.8.18",
75
- "@types/express": "^5.0.1",
76
- "@types/jsonwebtoken": "^9.0.9",
77
- "@types/lodash": "^4.17.13",
78
- "@types/pg": "^8.15.6",
79
- "@types/qs": "^6.14.0",
80
- "@types/supertest": "^6.0.3",
81
- "@vitest/coverage-v8": "^3.0.9",
82
- "cross-env": "^7.0.3",
83
- "mongodb-memory-server": "^9.3.0",
84
- "npm-run-all": "^4.1.5",
85
- "pg-mem": "^3.0.8",
86
- "rxjs": "^7.8.0",
87
- "supertest": "^7.1.0",
88
- "typescript": "^5.8.3",
89
- "vite": "^6.2.5",
90
- "vitest": "^3.0.9"
91
- }
92
- }
1
+ {
2
+ "name": "@loomcore/api",
3
+ "version": "0.1.75",
4
+ "private": false,
5
+ "description": "Loom Core Api - An opinionated Node.js api using Typescript, Express, and MongoDb or PostgreSQL",
6
+ "scripts": {
7
+ "clean": "rm -rf dist",
8
+ "tsc": "tsc --project tsconfig.prod.json",
9
+ "build": "npm-run-all -s clean tsc",
10
+ "add": "git add .",
11
+ "commit": "git commit -m \"Updates\"",
12
+ "patch": "npm version patch",
13
+ "push": "git push",
14
+ "publishMe": "npm publish --access public",
15
+ "pub": "npm-run-all -s add commit patch build push publishMe",
16
+ "update-lib-versions": "npx --yes npm-check-updates -u -f @loomcore/common",
17
+ "install-updated-libs": "npm i @loomcore/common",
18
+ "update-libs": "npm-run-all -s update-lib-versions install-updated-libs",
19
+ "typecheck": "tsc",
20
+ "test": "npm-run-all -s test:postgres test:mongodb",
21
+ "test:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run",
22
+ "test:postgres:real": "cross-env NODE_ENV=test TEST_DATABASE=postgres USE_REAL_POSTGRES=true vitest run",
23
+ "test:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run",
24
+ "test:ci": "npm-run-all -s test:ci:postgres test:ci:mongodb",
25
+ "test:ci:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --reporter=json --outputFile=test-results-postgres.json",
26
+ "test:ci:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --reporter=json --outputFile=test-results-mongodb.json",
27
+ "test:watch": "cross-env NODE_ENV=test vitest",
28
+ "coverage": "npm-run-all -s coverage:postgres coverage:mongodb",
29
+ "coverage:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --coverage",
30
+ "coverage:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --coverage",
31
+ "test:db:start": "docker-compose -f docker-compose.test.yml up -d",
32
+ "test:db:stop": "docker-compose -f docker-compose.test.yml down",
33
+ "test:db:logs": "docker-compose -f docker-compose.test.yml logs -f"
34
+ },
35
+ "author": "Tim Hardy",
36
+ "license": "Apache 2.0",
37
+ "main": "dist/index.js",
38
+ "type": "module",
39
+ "types": "dist/index.d.ts",
40
+ "files": [
41
+ "dist/**/*"
42
+ ],
43
+ "exports": {
44
+ "./__tests__": "./dist/__tests__/index.js",
45
+ "./config": "./dist/config/index.js",
46
+ "./controllers": "./dist/controllers/index.js",
47
+ "./databases": "./dist/databases/index.js",
48
+ "./errors": "./dist/errors/index.js",
49
+ "./middleware": "./dist/middleware/index.js",
50
+ "./models": "./dist/models/index.js",
51
+ "./services": "./dist/services/index.js",
52
+ "./utils": "./dist/utils/index.js"
53
+ },
54
+ "dependencies": {
55
+ "jsonwebtoken": "^9.0.2",
56
+ "node-mailjet": "^6.0.8",
57
+ "qs": "^6.14.1"
58
+ },
59
+ "peerDependencies": {
60
+ "@loomcore/common": "^0.0.43",
61
+ "@sinclair/typebox": "0.34.33",
62
+ "cookie-parser": "^1.4.6",
63
+ "cors": "^2.8.5",
64
+ "express": "^5.1.0",
65
+ "lodash": "^4.17.21",
66
+ "moment": "^2.30.1",
67
+ "mongodb": "^6.16.0",
68
+ "pg": "^8.15.6",
69
+ "rxjs": "^7.8.0",
70
+ "umzug": "^3.8.2"
71
+ },
72
+ "devDependencies": {
73
+ "@types/cookie-parser": "^1.4.7",
74
+ "@types/cors": "^2.8.18",
75
+ "@types/express": "^5.0.1",
76
+ "@types/jsonwebtoken": "^9.0.9",
77
+ "@types/lodash": "^4.17.13",
78
+ "@types/pg": "^8.15.6",
79
+ "@types/qs": "^6.14.0",
80
+ "@types/supertest": "^6.0.3",
81
+ "@vitest/coverage-v8": "^3.0.9",
82
+ "cross-env": "^7.0.3",
83
+ "mongodb-memory-server": "^9.3.0",
84
+ "npm-run-all": "^4.1.5",
85
+ "pg-mem": "^3.0.8",
86
+ "rxjs": "^7.8.0",
87
+ "supertest": "^7.1.0",
88
+ "typescript": "^5.8.3",
89
+ "vite": "^6.2.5",
90
+ "vitest": "^3.0.9"
91
+ }
92
+ }