@canmingir/link-express 1.6.10 → 1.7.0
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/.eslintrc.ts +29 -0
- package/index.ts +2 -0
- package/package.json +55 -12
- package/{prepare.js → prepare.ts} +1 -1
- package/src/{authorization.js → authorization.ts} +31 -9
- package/src/config.ts +112 -0
- package/src/dynamodb.ts +24 -0
- package/src/{error.js → error.ts} +30 -11
- package/src/express.ts +66 -0
- package/src/lib/{settings.js → settings.ts} +16 -4
- package/src/lib/test.ts +68 -0
- package/src/logger.ts +36 -0
- package/src/metrics/{dbMetrics.js → dbMetrics.ts} +37 -14
- package/src/models/Organization.model.ts +27 -0
- package/src/models/Permission.model.ts +48 -0
- package/src/models/Project.model.ts +50 -0
- package/src/models/Settings.model.ts +31 -0
- package/src/models/{index.js → index.ts} +8 -8
- package/src/platform.ts +55 -0
- package/src/postgres.ts +309 -0
- package/src/routes/index.ts +8 -0
- package/src/routes/metrics.ts +13 -0
- package/src/routes/oauth.ts +267 -0
- package/src/routes/{organizations.js → organizations.ts} +10 -8
- package/src/routes/{permissions.js → permissions.ts} +8 -6
- package/src/routes/{projects.js → projects.ts} +22 -16
- package/src/routes/settings.ts +31 -0
- package/src/schemas/{Organization.js → Organization.ts} +2 -2
- package/src/schemas/{Permission.js → Permission.ts} +2 -2
- package/src/schemas/{Project.js → Project.ts} +2 -2
- package/src/schemas/index.ts +5 -0
- package/src/sequelize.ts +13 -0
- package/src/{test.js → test.ts} +11 -13
- package/src/types/Organization.ts +9 -0
- package/src/types/Permission.ts +13 -0
- package/src/types/Project.ts +14 -0
- package/src/types/index.ts +5 -0
- package/tsconfig.json +32 -0
- package/.eslintrc.js +0 -20
- package/index.js +0 -1
- package/src/config.js +0 -21
- package/src/dynamodb.js +0 -18
- package/src/express.js +0 -58
- package/src/lib/test.js +0 -69
- package/src/models/Organization.js +0 -17
- package/src/models/Permission.js +0 -33
- package/src/models/Project.js +0 -37
- package/src/models/Settings.js +0 -21
- package/src/openapi.js +0 -40
- package/src/platform.js +0 -46
- package/src/postgres.js +0 -308
- package/src/routes/index.js +0 -15
- package/src/routes/metrics.js +0 -12
- package/src/routes/oauth.js +0 -213
- package/src/routes/settings.js +0 -25
- package/src/schemas/index.js +0 -5
|
@@ -1,6 +1,30 @@
|
|
|
1
|
-
|
|
1
|
+
import promClient from "prom-client";
|
|
2
|
+
|
|
3
|
+
interface PushgatewayConfig {
|
|
4
|
+
url: string;
|
|
5
|
+
jobName: string;
|
|
6
|
+
instance?: string;
|
|
7
|
+
interval: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface MetricsConfig {
|
|
11
|
+
url?: string;
|
|
12
|
+
pushGateway: {
|
|
13
|
+
jobName?: string;
|
|
14
|
+
instance?: string;
|
|
15
|
+
};
|
|
16
|
+
interval?: number;
|
|
17
|
+
}
|
|
2
18
|
|
|
3
19
|
class DBMetrics {
|
|
20
|
+
registry: promClient.Registry;
|
|
21
|
+
pushgatewayInterval: NodeJS.Timeout | null;
|
|
22
|
+
pushgatewayConfig: PushgatewayConfig | null;
|
|
23
|
+
dbReadOps: promClient.Counter<string>;
|
|
24
|
+
dbWriteOps: promClient.Counter<string>;
|
|
25
|
+
dbReadLatency: promClient.Histogram<string>;
|
|
26
|
+
dbWriteLatency: promClient.Histogram<string>;
|
|
27
|
+
|
|
4
28
|
constructor() {
|
|
5
29
|
this.registry = new promClient.Registry();
|
|
6
30
|
this.pushgatewayInterval = null;
|
|
@@ -33,17 +57,17 @@ class DBMetrics {
|
|
|
33
57
|
});
|
|
34
58
|
}
|
|
35
59
|
|
|
36
|
-
recordDbRead() {
|
|
60
|
+
recordDbRead(): () => number {
|
|
37
61
|
this.dbReadOps.inc();
|
|
38
62
|
return this.dbReadLatency.startTimer();
|
|
39
63
|
}
|
|
40
64
|
|
|
41
|
-
recordDbWrite() {
|
|
65
|
+
recordDbWrite(): () => number {
|
|
42
66
|
this.dbWriteOps.inc();
|
|
43
67
|
return this.dbWriteLatency.startTimer();
|
|
44
68
|
}
|
|
45
69
|
|
|
46
|
-
startPushgateway(metrics
|
|
70
|
+
startPushgateway(metrics: MetricsConfig): void {
|
|
47
71
|
this.pushgatewayConfig = {
|
|
48
72
|
url: metrics.url || "http://localhost:9091",
|
|
49
73
|
jobName: metrics.pushGateway.jobName || "api",
|
|
@@ -62,19 +86,18 @@ class DBMetrics {
|
|
|
62
86
|
);
|
|
63
87
|
}
|
|
64
88
|
|
|
65
|
-
stopPushgateway() {
|
|
89
|
+
stopPushgateway(): void {
|
|
66
90
|
if (this.pushgatewayInterval) {
|
|
67
91
|
clearInterval(this.pushgatewayInterval);
|
|
68
|
-
this.pushgatewayInterval =
|
|
92
|
+
this.pushgatewayInterval = null;
|
|
69
93
|
console.log("Stopped pushing metrics to Pushgateway");
|
|
70
94
|
}
|
|
71
95
|
}
|
|
72
96
|
|
|
73
|
-
async pushMetricsToGateway() {
|
|
97
|
+
async pushMetricsToGateway(): Promise<void> {
|
|
74
98
|
if (!this.pushgatewayConfig) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
);
|
|
99
|
+
console.error("[DBMetrics] Pushgateway not configured");
|
|
100
|
+
return;
|
|
78
101
|
}
|
|
79
102
|
|
|
80
103
|
try {
|
|
@@ -95,15 +118,15 @@ class DBMetrics {
|
|
|
95
118
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
96
119
|
}
|
|
97
120
|
|
|
98
|
-
console.log("Metrics pushed to Pushgateway successfully");
|
|
121
|
+
console.log("[DBMetrics] Metrics pushed to Pushgateway successfully");
|
|
99
122
|
} catch (err) {
|
|
100
|
-
console.error("Failed to push metrics to Pushgateway:", err);
|
|
123
|
+
console.error("[DBMetrics] Failed to push metrics to Pushgateway:", err);
|
|
101
124
|
}
|
|
102
125
|
}
|
|
103
126
|
|
|
104
|
-
getPushgatewayConfig() {
|
|
127
|
+
getPushgatewayConfig(): PushgatewayConfig | null {
|
|
105
128
|
return this.pushgatewayConfig;
|
|
106
129
|
}
|
|
107
130
|
}
|
|
108
131
|
|
|
109
|
-
|
|
132
|
+
export { DBMetrics };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Table,
|
|
3
|
+
Column,
|
|
4
|
+
Model,
|
|
5
|
+
DataType,
|
|
6
|
+
Default,
|
|
7
|
+
PrimaryKey,
|
|
8
|
+
AllowNull,
|
|
9
|
+
} from "sequelize-typescript";
|
|
10
|
+
|
|
11
|
+
@Table({
|
|
12
|
+
tableName: "Organization",
|
|
13
|
+
timestamps: false,
|
|
14
|
+
underscored: true,
|
|
15
|
+
})
|
|
16
|
+
class Organization extends Model {
|
|
17
|
+
@PrimaryKey
|
|
18
|
+
@Default(DataType.UUIDV4)
|
|
19
|
+
@Column(DataType.UUID)
|
|
20
|
+
declare id: string;
|
|
21
|
+
|
|
22
|
+
@AllowNull(false)
|
|
23
|
+
@Column(DataType.STRING)
|
|
24
|
+
declare name: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default Organization;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Table,
|
|
3
|
+
Column,
|
|
4
|
+
Model,
|
|
5
|
+
DataType,
|
|
6
|
+
Default,
|
|
7
|
+
PrimaryKey,
|
|
8
|
+
AllowNull,
|
|
9
|
+
ForeignKey,
|
|
10
|
+
} from "sequelize-typescript";
|
|
11
|
+
import Organization from "./Organization.model";
|
|
12
|
+
import Project from "./Project.model";
|
|
13
|
+
|
|
14
|
+
@Table({
|
|
15
|
+
tableName: "Permission",
|
|
16
|
+
timestamps: false,
|
|
17
|
+
underscored: true,
|
|
18
|
+
})
|
|
19
|
+
class Permission extends Model {
|
|
20
|
+
@PrimaryKey
|
|
21
|
+
@Default(DataType.UUIDV4)
|
|
22
|
+
@Column(DataType.UUID)
|
|
23
|
+
declare id: string;
|
|
24
|
+
|
|
25
|
+
@AllowNull(false)
|
|
26
|
+
@Column(DataType.UUID)
|
|
27
|
+
declare appId: string;
|
|
28
|
+
|
|
29
|
+
@AllowNull(false)
|
|
30
|
+
@ForeignKey(() => Organization)
|
|
31
|
+
@Column(DataType.UUID)
|
|
32
|
+
declare organizationId: string;
|
|
33
|
+
|
|
34
|
+
@AllowNull(false)
|
|
35
|
+
@ForeignKey(() => Project)
|
|
36
|
+
@Column(DataType.UUID)
|
|
37
|
+
declare projectId: string;
|
|
38
|
+
|
|
39
|
+
@AllowNull(false)
|
|
40
|
+
@Column(DataType.STRING)
|
|
41
|
+
declare userId: string;
|
|
42
|
+
|
|
43
|
+
@AllowNull(false)
|
|
44
|
+
@Column(DataType.STRING)
|
|
45
|
+
declare role: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default Permission;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Table,
|
|
3
|
+
Column,
|
|
4
|
+
Model,
|
|
5
|
+
DataType,
|
|
6
|
+
Default,
|
|
7
|
+
PrimaryKey,
|
|
8
|
+
AllowNull,
|
|
9
|
+
ForeignKey,
|
|
10
|
+
} from "sequelize-typescript";
|
|
11
|
+
import Organization from "./Organization.model";
|
|
12
|
+
|
|
13
|
+
@Table({
|
|
14
|
+
tableName: "Project",
|
|
15
|
+
timestamps: false,
|
|
16
|
+
underscored: true,
|
|
17
|
+
})
|
|
18
|
+
class Project extends Model {
|
|
19
|
+
@PrimaryKey
|
|
20
|
+
@Default(DataType.UUIDV4)
|
|
21
|
+
@Column(DataType.UUID)
|
|
22
|
+
declare id: string;
|
|
23
|
+
|
|
24
|
+
@AllowNull(false)
|
|
25
|
+
@Column(DataType.STRING)
|
|
26
|
+
declare name: string;
|
|
27
|
+
|
|
28
|
+
@AllowNull(false)
|
|
29
|
+
@Column(DataType.STRING)
|
|
30
|
+
declare icon: string;
|
|
31
|
+
|
|
32
|
+
@AllowNull(true)
|
|
33
|
+
@Column(DataType.STRING)
|
|
34
|
+
declare description: string | null;
|
|
35
|
+
|
|
36
|
+
@AllowNull(true)
|
|
37
|
+
@Column(DataType.STRING)
|
|
38
|
+
declare type: string | null;
|
|
39
|
+
|
|
40
|
+
@AllowNull(true)
|
|
41
|
+
@ForeignKey(() => Organization)
|
|
42
|
+
@Column(DataType.UUID)
|
|
43
|
+
declare organizationId: string | null;
|
|
44
|
+
|
|
45
|
+
@AllowNull(true)
|
|
46
|
+
@Column(DataType.STRING)
|
|
47
|
+
declare coach: string | null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default Project;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Table,
|
|
3
|
+
Column,
|
|
4
|
+
Model,
|
|
5
|
+
DataType,
|
|
6
|
+
Default,
|
|
7
|
+
PrimaryKey,
|
|
8
|
+
AllowNull,
|
|
9
|
+
} from "sequelize-typescript";
|
|
10
|
+
|
|
11
|
+
@Table({
|
|
12
|
+
tableName: "Settings",
|
|
13
|
+
timestamps: false,
|
|
14
|
+
underscored: true,
|
|
15
|
+
})
|
|
16
|
+
class Settings extends Model {
|
|
17
|
+
@PrimaryKey
|
|
18
|
+
@Default(DataType.UUIDV4)
|
|
19
|
+
@Column(DataType.UUID)
|
|
20
|
+
declare id: string;
|
|
21
|
+
|
|
22
|
+
@AllowNull(false)
|
|
23
|
+
@Column(DataType.UUID)
|
|
24
|
+
declare projectId: string;
|
|
25
|
+
|
|
26
|
+
@AllowNull(false)
|
|
27
|
+
@Column(DataType.JSONB)
|
|
28
|
+
declare settings: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default Settings;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import Project from "./Project.model";
|
|
2
|
+
import Organization from "./Organization.model";
|
|
3
|
+
import Permission from "./Permission.model";
|
|
4
|
+
import Setting from "./Settings.model";
|
|
5
5
|
|
|
6
6
|
let _init = false;
|
|
7
7
|
|
|
8
|
-
async function init() {
|
|
8
|
+
async function init(): Promise<boolean> {
|
|
9
9
|
if (!_init) {
|
|
10
10
|
_init = true;
|
|
11
11
|
} else {
|
|
@@ -37,10 +37,10 @@ async function init() {
|
|
|
37
37
|
as: "permissions",
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
Organization.addHook("beforeDestroy", async (organization) => {
|
|
40
|
+
Organization.addHook("beforeDestroy", async (organization: Organization) => {
|
|
41
41
|
await Project.destroy({
|
|
42
42
|
where: {
|
|
43
|
-
organizationId: organization.id,
|
|
43
|
+
organizationId: organization.getDataValue("id"),
|
|
44
44
|
},
|
|
45
45
|
});
|
|
46
46
|
});
|
|
@@ -48,4 +48,4 @@ async function init() {
|
|
|
48
48
|
return true;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
export { Project, Organization, Permission, init, Setting };
|
package/src/platform.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as authorization from "./authorization";
|
|
2
|
+
import * as error from "./error";
|
|
3
|
+
import { Application } from "express";
|
|
4
|
+
import { Sequelize } from "sequelize-typescript";
|
|
5
|
+
import { Config } from "./config";
|
|
6
|
+
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
|
|
7
|
+
import type { Logger } from "pino";
|
|
8
|
+
|
|
9
|
+
let _express: Application;
|
|
10
|
+
let _postgres: { sequelize: Sequelize };
|
|
11
|
+
let _dynamodb: { docClient: DynamoDBDocumentClient };
|
|
12
|
+
let _logger: Logger | Console;
|
|
13
|
+
|
|
14
|
+
async function init(config: Partial<Config> = {}): Promise<void> {
|
|
15
|
+
const configModule = await import("./config.ts");
|
|
16
|
+
const { postgres, dynamodb, logger } = configModule.init(config as Config);
|
|
17
|
+
|
|
18
|
+
const expressModule = await import("./express.ts");
|
|
19
|
+
_express = (expressModule as any).default as Application;
|
|
20
|
+
|
|
21
|
+
if (logger) {
|
|
22
|
+
const loggerModule = await import("./logger.ts");
|
|
23
|
+
_logger = (loggerModule as any).default;
|
|
24
|
+
} else {
|
|
25
|
+
_logger = console;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (postgres) {
|
|
29
|
+
const postgresModule = await import("./postgres.ts");
|
|
30
|
+
_postgres = { sequelize: postgresModule.sequelize };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (dynamodb) {
|
|
34
|
+
const dynamodbModule = await import("./dynamodb.ts");
|
|
35
|
+
_dynamodb = { docClient: dynamodbModule.docClient };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const getModules = () => ({
|
|
40
|
+
Postgres: _postgres,
|
|
41
|
+
DynamoDB: _dynamodb,
|
|
42
|
+
Kafka: {},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const importModule = (pkg: string) => import(pkg);
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
init,
|
|
49
|
+
_express as express,
|
|
50
|
+
getModules,
|
|
51
|
+
importModule,
|
|
52
|
+
authorization,
|
|
53
|
+
error,
|
|
54
|
+
_logger as logger,
|
|
55
|
+
};
|
package/src/postgres.ts
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { Model, Sequelize } from "sequelize-typescript";
|
|
2
|
+
import config from "./config";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import { DBMetrics } from "./metrics/dbMetrics";
|
|
6
|
+
import { DestroyOptions, InstanceDestroyOptions } from "sequelize";
|
|
7
|
+
|
|
8
|
+
const appConfig = config();
|
|
9
|
+
|
|
10
|
+
const { postgres, project } = appConfig;
|
|
11
|
+
|
|
12
|
+
const metricsConfig = appConfig.metrics;
|
|
13
|
+
|
|
14
|
+
if (!postgres) {
|
|
15
|
+
throw new Error("Postgres configuration is required");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let dbMetrics: DBMetrics | null = null;
|
|
19
|
+
|
|
20
|
+
if (metricsConfig && metricsConfig.enabled) {
|
|
21
|
+
dbMetrics = new DBMetrics();
|
|
22
|
+
dbMetrics.startPushgateway(metricsConfig);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface SequelizeOptions {
|
|
26
|
+
metricsTimer?: () => number;
|
|
27
|
+
metricsType?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const originalDestroy = Model.prototype.destroy;
|
|
31
|
+
Model.prototype.destroy = async function (
|
|
32
|
+
options?: InstanceDestroyOptions
|
|
33
|
+
): Promise<void> {
|
|
34
|
+
return originalDestroy.call(this, {
|
|
35
|
+
...options,
|
|
36
|
+
individualHooks: true,
|
|
37
|
+
}) as Promise<void>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const sequelize = new Sequelize(process.env.PG || postgres.uri, {
|
|
41
|
+
logging: postgres.debug && console.log,
|
|
42
|
+
models: [
|
|
43
|
+
path.join(__dirname, "models/*.model.ts"),
|
|
44
|
+
path.join(process.cwd(), "src/models/[A-Z]*.ts"),
|
|
45
|
+
],
|
|
46
|
+
define: {
|
|
47
|
+
freezeTableName: true,
|
|
48
|
+
underscored: true,
|
|
49
|
+
timestamps: false,
|
|
50
|
+
paranoid: false,
|
|
51
|
+
},
|
|
52
|
+
hooks:
|
|
53
|
+
metricsConfig && metricsConfig.enabled
|
|
54
|
+
? {
|
|
55
|
+
beforeFind: (options = {}) => {
|
|
56
|
+
const timer = dbMetrics!.dbReadLatency.startTimer();
|
|
57
|
+
(options as SequelizeOptions).metricsTimer = timer;
|
|
58
|
+
(options as SequelizeOptions).metricsType = "read";
|
|
59
|
+
},
|
|
60
|
+
afterFind: (_result, options = {}) => {
|
|
61
|
+
const opts = options as SequelizeOptions;
|
|
62
|
+
if (opts?.metricsTimer) {
|
|
63
|
+
opts.metricsTimer();
|
|
64
|
+
dbMetrics!.dbReadOps.inc();
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
beforeCreate: (_instance, options = {}) => {
|
|
69
|
+
const timer = dbMetrics!.dbWriteLatency.startTimer();
|
|
70
|
+
(options as SequelizeOptions).metricsTimer = timer;
|
|
71
|
+
(options as SequelizeOptions).metricsType = "write";
|
|
72
|
+
},
|
|
73
|
+
afterCreate: (_instance, options = {}) => {
|
|
74
|
+
const opts = options as SequelizeOptions;
|
|
75
|
+
if (opts?.metricsTimer) {
|
|
76
|
+
opts.metricsTimer();
|
|
77
|
+
dbMetrics!.dbWriteOps.inc();
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
beforeUpdate: (_instance, options = {}) => {
|
|
82
|
+
const timer = dbMetrics!.dbWriteLatency.startTimer();
|
|
83
|
+
(options as SequelizeOptions).metricsTimer = timer;
|
|
84
|
+
(options as SequelizeOptions).metricsType = "write";
|
|
85
|
+
},
|
|
86
|
+
afterUpdate: (_instance, options = {}) => {
|
|
87
|
+
const opts = options as SequelizeOptions;
|
|
88
|
+
if (opts?.metricsTimer) {
|
|
89
|
+
opts.metricsTimer();
|
|
90
|
+
dbMetrics!.dbWriteOps.inc();
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
beforeDestroy: (_instance, options = {}) => {
|
|
95
|
+
const timer = dbMetrics!.dbWriteLatency.startTimer();
|
|
96
|
+
(options as SequelizeOptions).metricsTimer = timer;
|
|
97
|
+
(options as SequelizeOptions).metricsType = "write";
|
|
98
|
+
},
|
|
99
|
+
afterDestroy: (_instance, options = {}) => {
|
|
100
|
+
const opts = options as SequelizeOptions;
|
|
101
|
+
if (opts?.metricsTimer) {
|
|
102
|
+
opts.metricsTimer();
|
|
103
|
+
dbMetrics!.dbWriteOps.inc();
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
beforeBulkCreate: (_instances, options = {}) => {
|
|
108
|
+
const timer = dbMetrics!.dbWriteLatency.startTimer();
|
|
109
|
+
(options as SequelizeOptions).metricsTimer = timer;
|
|
110
|
+
(options as SequelizeOptions).metricsType = "write";
|
|
111
|
+
},
|
|
112
|
+
afterBulkCreate: (instances, options = {}) => {
|
|
113
|
+
const opts = options as SequelizeOptions;
|
|
114
|
+
if (opts?.metricsTimer) {
|
|
115
|
+
opts.metricsTimer();
|
|
116
|
+
dbMetrics!.dbWriteOps.inc(instances.length || 1);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
beforeBulkUpdate: (_instances, options = {}) => {
|
|
121
|
+
const timer = dbMetrics!.dbWriteLatency.startTimer();
|
|
122
|
+
(options as SequelizeOptions).metricsTimer = timer;
|
|
123
|
+
(options as SequelizeOptions).metricsType = "write";
|
|
124
|
+
},
|
|
125
|
+
afterBulkUpdate: (_instances, options = {}) => {
|
|
126
|
+
const opts = options as SequelizeOptions;
|
|
127
|
+
if (opts?.metricsTimer) {
|
|
128
|
+
opts.metricsTimer();
|
|
129
|
+
dbMetrics!.dbWriteOps.inc(1);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
beforeBulkDestroy: (options = {}) => {
|
|
134
|
+
const timer = dbMetrics!.dbWriteLatency.startTimer();
|
|
135
|
+
(options as SequelizeOptions).metricsTimer = timer;
|
|
136
|
+
(options as SequelizeOptions).metricsType = "write";
|
|
137
|
+
},
|
|
138
|
+
afterBulkDestroy: (options = {}) => {
|
|
139
|
+
const opts = options as SequelizeOptions;
|
|
140
|
+
if (opts?.metricsTimer) {
|
|
141
|
+
opts.metricsTimer();
|
|
142
|
+
dbMetrics!.dbWriteOps.inc(1);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
: {},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const seed = async (): Promise<void> => {
|
|
150
|
+
const currentWorkingDirectory = process.cwd();
|
|
151
|
+
const baseDir = path.join(currentWorkingDirectory, "src", "models");
|
|
152
|
+
const seedDir = path.join(currentWorkingDirectory, "src", "seeds");
|
|
153
|
+
|
|
154
|
+
if (!fs.existsSync(seedDir)) {
|
|
155
|
+
console.error(`[NUC] Seed directory not found at path: ${seedDir}`);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!fs.existsSync(baseDir)) {
|
|
160
|
+
console.error(`[NUC] Model directory not found at path: ${baseDir}`);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
if (project) {
|
|
166
|
+
const { seed: companiesSeed } = require("./seeds/Organization.json");
|
|
167
|
+
|
|
168
|
+
sequelize.models.Organization.bulkCreate(companiesSeed, {
|
|
169
|
+
validate: true,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
console.log(`[NUC] Loading internal seed data for Organization`);
|
|
173
|
+
|
|
174
|
+
if (fs.existsSync(path.join(seedDir, "Organization.json"))) {
|
|
175
|
+
const seedData = require(path.join(seedDir, "Organization.json"));
|
|
176
|
+
const seed = seedData["seed"];
|
|
177
|
+
sequelize.models.Organization.bulkCreate(seed, {
|
|
178
|
+
validate: true,
|
|
179
|
+
});
|
|
180
|
+
console.log(`[NUC] Loading seed data for Organization`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const { seed: projectSeed } = require("./seeds/Project.json");
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const { seed: extProjectSeed } = require(path.join(
|
|
187
|
+
seedDir,
|
|
188
|
+
"Project.json"
|
|
189
|
+
));
|
|
190
|
+
if (extProjectSeed) {
|
|
191
|
+
projectSeed.push(...extProjectSeed);
|
|
192
|
+
}
|
|
193
|
+
console.log(
|
|
194
|
+
`[NUC] Loading internal${
|
|
195
|
+
extProjectSeed ? " and external" : ""
|
|
196
|
+
} seed data for Project`
|
|
197
|
+
);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
console.log(`[NUC] Loading internal seed data for Project`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
sequelize.models.Project.bulkCreate(projectSeed, {
|
|
203
|
+
validate: true,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
const fileNames = fs.readdirSync(baseDir).filter((fileName) => {
|
|
207
|
+
return !["index.ts"].includes(fileName);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const fileSequences = fileNames
|
|
211
|
+
.map((fileName) => {
|
|
212
|
+
const seedName = fileName.split(".")[0];
|
|
213
|
+
const seederPath = path.join(seedDir, `${seedName}.json`);
|
|
214
|
+
|
|
215
|
+
if (fs.existsSync(seederPath)) {
|
|
216
|
+
const seedData = require(seederPath);
|
|
217
|
+
return { sequence: seedData.sequence, fileName };
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
})
|
|
221
|
+
.filter(Boolean) as { sequence: number; fileName: string }[];
|
|
222
|
+
|
|
223
|
+
fileSequences.sort((a, b) => a.sequence - b.sequence);
|
|
224
|
+
|
|
225
|
+
for (const { fileName } of fileSequences) {
|
|
226
|
+
const seedName = fileName.split(".")[0];
|
|
227
|
+
const seederPath = path.join(seedDir, `${seedName}.json`);
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const seedData = require(seederPath);
|
|
231
|
+
const seed = seedData["seed"];
|
|
232
|
+
|
|
233
|
+
console.log(`[NUC] Loading seed data for ${fileName}`);
|
|
234
|
+
|
|
235
|
+
await sequelize.model(seedName).bulkCreate(seed, {
|
|
236
|
+
validate: true,
|
|
237
|
+
});
|
|
238
|
+
} catch (error) {
|
|
239
|
+
console.error(`[NUC] Error loading seed data for ${fileName}:`, error);
|
|
240
|
+
throw error;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (project) {
|
|
245
|
+
const { seed: permissionsSeed } = require("./seeds/Permission.json");
|
|
246
|
+
try {
|
|
247
|
+
const { seed: extPermissionsSeed } = require(path.join(
|
|
248
|
+
seedDir,
|
|
249
|
+
"Permission.json"
|
|
250
|
+
));
|
|
251
|
+
if (extPermissionsSeed) {
|
|
252
|
+
permissionsSeed.push(...extPermissionsSeed);
|
|
253
|
+
}
|
|
254
|
+
console.log(
|
|
255
|
+
`[NUC] Loading internal${
|
|
256
|
+
extPermissionsSeed ? " and external" : ""
|
|
257
|
+
} seed data for Permission`
|
|
258
|
+
);
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.log(`[NUC] Loading internal seed data for Permission`);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
sequelize.models.Permission.bulkCreate(permissionsSeed, {
|
|
264
|
+
validate: true,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
const { seed: settingsSeed } = require("./seeds/Settings.json");
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
const { seed: extSettingsSeed } = require(path.join(
|
|
271
|
+
seedDir,
|
|
272
|
+
"Settings.json"
|
|
273
|
+
));
|
|
274
|
+
if (extSettingsSeed) {
|
|
275
|
+
settingsSeed.push(...extSettingsSeed);
|
|
276
|
+
}
|
|
277
|
+
console.log(
|
|
278
|
+
`[NUC] Loading internal${
|
|
279
|
+
extSettingsSeed ? " and external" : ""
|
|
280
|
+
} seed data for Settings`
|
|
281
|
+
);
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.log(`[NUC] Loading internal seed data for Settings`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
sequelize.models.Settings.bulkCreate(settingsSeed, {
|
|
287
|
+
validate: true,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
} catch (error) {
|
|
291
|
+
console.error("[NUC] Error during seed operation:", error);
|
|
292
|
+
throw error;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const associateModels = async (): Promise<void> => {
|
|
297
|
+
const models = await import("./models");
|
|
298
|
+
await models.init();
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
if (postgres.sync) {
|
|
302
|
+
setImmediate(async () => {
|
|
303
|
+
project && (await associateModels());
|
|
304
|
+
await sequelize.sync({ force: true });
|
|
305
|
+
await seed();
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export { sequelize };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import metrics from "./metrics";
|
|
2
|
+
import permissions from "./permissions";
|
|
3
|
+
import oauth from "./oauth";
|
|
4
|
+
import organizations from "./organizations";
|
|
5
|
+
import projects from "./projects";
|
|
6
|
+
import settings from "./settings";
|
|
7
|
+
|
|
8
|
+
export { metrics, permissions, oauth, organizations, projects, settings };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import express, { Request, Response } from "express";
|
|
2
|
+
import os from "os";
|
|
3
|
+
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
|
|
6
|
+
router.get("/", (_req: Request, res: Response) => {
|
|
7
|
+
res.json({
|
|
8
|
+
free: os.freemem(),
|
|
9
|
+
total: os.totalmem(),
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export default router;
|