@restura/core 0.1.0-alpha.19 → 0.1.0-alpha.20
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/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +184 -83
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +177 -76
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
package/dist/index.mjs
CHANGED
|
@@ -49,12 +49,17 @@ import { z } from "zod";
|
|
|
49
49
|
var loggerConfigSchema = z.object({
|
|
50
50
|
level: z.enum(["info", "warn", "error", "debug", "silly"]).default("info")
|
|
51
51
|
});
|
|
52
|
+
var _a;
|
|
53
|
+
var isTsx = (_a = process.argv[1]) == null ? void 0 : _a.endsWith(".ts");
|
|
54
|
+
var isTsNode = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
|
|
55
|
+
var customApiFolderPath = isTsx || isTsNode ? "/src/api" : "/dist/api";
|
|
52
56
|
var resturaConfigSchema = z.object({
|
|
53
57
|
authToken: z.string().min(1, "Missing Restura Auth Token"),
|
|
54
58
|
sendErrorStackTrace: z.boolean().default(false),
|
|
55
59
|
schemaFilePath: z.string().default(process.cwd() + "/restura.schema.json"),
|
|
56
|
-
customApiFolderPath: z.string().default(process.cwd() +
|
|
57
|
-
generatedTypesPath: z.string().default(process.cwd() + "/src/@types")
|
|
60
|
+
customApiFolderPath: z.string().default(process.cwd() + customApiFolderPath),
|
|
61
|
+
generatedTypesPath: z.string().default(process.cwd() + "/src/@types"),
|
|
62
|
+
fileTempCachePath: z.string().optional()
|
|
58
63
|
});
|
|
59
64
|
|
|
60
65
|
// src/logger/logger.ts
|
|
@@ -214,8 +219,8 @@ import compression from "compression";
|
|
|
214
219
|
import cookieParser from "cookie-parser";
|
|
215
220
|
import { createHash } from "crypto";
|
|
216
221
|
import * as express from "express";
|
|
217
|
-
import
|
|
218
|
-
import
|
|
222
|
+
import fs4 from "fs";
|
|
223
|
+
import path4 from "path";
|
|
219
224
|
import pg3 from "pg";
|
|
220
225
|
import * as prettier3 from "prettier";
|
|
221
226
|
|
|
@@ -310,9 +315,9 @@ var ResponseValidator = class _ResponseValidator {
|
|
|
310
315
|
return { validator: "any" };
|
|
311
316
|
}
|
|
312
317
|
getTypeFromTable(selector, name) {
|
|
313
|
-
const
|
|
314
|
-
if (
|
|
315
|
-
const tableName =
|
|
318
|
+
const path5 = selector.split(".");
|
|
319
|
+
if (path5.length === 0 || path5.length > 2 || path5[0] === "") return { validator: "any", isOptional: false };
|
|
320
|
+
const tableName = path5.length == 2 ? path5[0] : name, columnName = path5.length == 2 ? path5[1] : path5[0];
|
|
316
321
|
const table = this.database.find((t) => t.name == tableName);
|
|
317
322
|
const column = table == null ? void 0 : table.columns.find((c) => c.name == columnName);
|
|
318
323
|
if (!table || !column) return { validator: "any", isOptional: false };
|
|
@@ -528,10 +533,10 @@ var ApiTree = class _ApiTree {
|
|
|
528
533
|
return `${p.name}:${responseType}${array ? "[]" : ""}${isNullable ? " | null" : ""}`;
|
|
529
534
|
}
|
|
530
535
|
getTypeFromTable(selector, name) {
|
|
531
|
-
const
|
|
532
|
-
if (
|
|
533
|
-
let tableName =
|
|
534
|
-
const columnName =
|
|
536
|
+
const path5 = selector.split(".");
|
|
537
|
+
if (path5.length === 0 || path5.length > 2 || path5[0] === "") return { responseType: "any", isNullable: false };
|
|
538
|
+
let tableName = path5.length == 2 ? path5[0] : name;
|
|
539
|
+
const columnName = path5.length == 2 ? path5[1] : path5[0];
|
|
535
540
|
let table = this.database.find((t) => t.name == tableName);
|
|
536
541
|
if (!table && tableName.includes("_")) {
|
|
537
542
|
const tableAliasSplit = tableName.split("_");
|
|
@@ -546,8 +551,8 @@ var ApiTree = class _ApiTree {
|
|
|
546
551
|
};
|
|
547
552
|
}
|
|
548
553
|
};
|
|
549
|
-
function pathToNamespaces(
|
|
550
|
-
return
|
|
554
|
+
function pathToNamespaces(path5) {
|
|
555
|
+
return path5.split("/").map((e) => StringUtils.toPascalCasing(e)).filter((e) => e);
|
|
551
556
|
}
|
|
552
557
|
function apiGenerator(schema, schemaHash) {
|
|
553
558
|
let apiString = `/** Auto generated file from Schema Hash (${schemaHash}). DO NOT MODIFY **/`;
|
|
@@ -583,6 +588,8 @@ function apiGenerator(schema, schemaHash) {
|
|
|
583
588
|
// src/restura/customApiFactory.ts
|
|
584
589
|
import fs from "fs";
|
|
585
590
|
import path from "path";
|
|
591
|
+
import Bluebird from "bluebird";
|
|
592
|
+
import { fileUtils } from "@restura/internal";
|
|
586
593
|
var CustomApiFactory = class {
|
|
587
594
|
constructor() {
|
|
588
595
|
this.customApis = {};
|
|
@@ -591,7 +598,8 @@ var CustomApiFactory = class {
|
|
|
591
598
|
const apiVersions = ["v1"];
|
|
592
599
|
for (const apiVersion of apiVersions) {
|
|
593
600
|
const apiVersionFolderPath = path.join(baseFolderPath, apiVersion);
|
|
594
|
-
|
|
601
|
+
const directoryExists = await fileUtils.existDir(apiVersionFolderPath);
|
|
602
|
+
if (!directoryExists) continue;
|
|
595
603
|
await this.addDirectory(apiVersionFolderPath, apiVersion);
|
|
596
604
|
}
|
|
597
605
|
}
|
|
@@ -599,12 +607,17 @@ var CustomApiFactory = class {
|
|
|
599
607
|
return this.customApis[customApiName];
|
|
600
608
|
}
|
|
601
609
|
async addDirectory(directoryPath, apiVersion) {
|
|
602
|
-
|
|
610
|
+
var _a2;
|
|
611
|
+
const entries = await fs.promises.readdir(directoryPath, {
|
|
603
612
|
withFileTypes: true
|
|
604
613
|
});
|
|
605
|
-
|
|
614
|
+
const isTsx2 = (_a2 = process.argv[1]) == null ? void 0 : _a2.endsWith(".ts");
|
|
615
|
+
const isTsNode2 = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
|
|
616
|
+
const extension = isTsx2 || isTsNode2 ? "ts" : "js";
|
|
617
|
+
const shouldEndWith = `.api.${apiVersion}.${extension}`;
|
|
618
|
+
await Bluebird.map(entries, async (entry) => {
|
|
606
619
|
if (entry.isFile()) {
|
|
607
|
-
if (entry.name.endsWith(
|
|
620
|
+
if (entry.name.endsWith(shouldEndWith) === false) return;
|
|
608
621
|
try {
|
|
609
622
|
const importPath = `${path.join(directoryPath, entry.name)}`;
|
|
610
623
|
const ApiImport = await import(importPath);
|
|
@@ -616,7 +629,7 @@ var CustomApiFactory = class {
|
|
|
616
629
|
console.error(e);
|
|
617
630
|
}
|
|
618
631
|
}
|
|
619
|
-
}
|
|
632
|
+
});
|
|
620
633
|
}
|
|
621
634
|
bindMethodsToInstance(instance) {
|
|
622
635
|
const proto = Object.getPrototypeOf(instance);
|
|
@@ -1417,11 +1430,11 @@ var SqlEngine = class {
|
|
|
1417
1430
|
return returnValue;
|
|
1418
1431
|
}
|
|
1419
1432
|
replaceLocalParamKeywords(value, routeData, req, sqlParams) {
|
|
1420
|
-
var
|
|
1433
|
+
var _a2;
|
|
1421
1434
|
if (!routeData.request) return value;
|
|
1422
1435
|
const data = req.data;
|
|
1423
1436
|
if (typeof value === "string") {
|
|
1424
|
-
(
|
|
1437
|
+
(_a2 = value.match(/\$[a-zA-Z][a-zA-Z0-9_]+/g)) == null ? void 0 : _a2.forEach((param) => {
|
|
1425
1438
|
const requestParam = routeData.request.find((item) => {
|
|
1426
1439
|
return item.name === param.replace("$", "");
|
|
1427
1440
|
});
|
|
@@ -1434,9 +1447,9 @@ var SqlEngine = class {
|
|
|
1434
1447
|
return value;
|
|
1435
1448
|
}
|
|
1436
1449
|
replaceGlobalParamKeywords(value, routeData, req, sqlParams) {
|
|
1437
|
-
var
|
|
1450
|
+
var _a2;
|
|
1438
1451
|
if (typeof value === "string") {
|
|
1439
|
-
(
|
|
1452
|
+
(_a2 = value.match(/#[a-zA-Z][a-zA-Z0-9_]+/g)) == null ? void 0 : _a2.forEach((param) => {
|
|
1440
1453
|
param = param.replace("#", "");
|
|
1441
1454
|
const globalParamValue = req.requesterDetails[param];
|
|
1442
1455
|
if (!globalParamValue)
|
|
@@ -1552,7 +1565,7 @@ var filterPsqlParser = peg.generate(filterSqlGrammar, {
|
|
|
1552
1565
|
var filterPsqlParser_default = filterPsqlParser;
|
|
1553
1566
|
|
|
1554
1567
|
// src/restura/eventManager.ts
|
|
1555
|
-
import
|
|
1568
|
+
import Bluebird2 from "bluebird";
|
|
1556
1569
|
var EventManager = class {
|
|
1557
1570
|
constructor() {
|
|
1558
1571
|
this.actionHandlers = {
|
|
@@ -1589,7 +1602,7 @@ var EventManager = class {
|
|
|
1589
1602
|
}
|
|
1590
1603
|
}
|
|
1591
1604
|
async fireInsertActions(data, triggerResult) {
|
|
1592
|
-
await
|
|
1605
|
+
await Bluebird2.map(
|
|
1593
1606
|
this.actionHandlers.DATABASE_ROW_INSERT,
|
|
1594
1607
|
({ callback, filter }) => {
|
|
1595
1608
|
if (!this.hasHandlersForEventType("DATABASE_ROW_INSERT", filter, triggerResult)) return;
|
|
@@ -1605,7 +1618,7 @@ var EventManager = class {
|
|
|
1605
1618
|
);
|
|
1606
1619
|
}
|
|
1607
1620
|
async fireDeleteActions(data, triggerResult) {
|
|
1608
|
-
await
|
|
1621
|
+
await Bluebird2.map(
|
|
1609
1622
|
this.actionHandlers.DATABASE_ROW_DELETE,
|
|
1610
1623
|
({ callback, filter }) => {
|
|
1611
1624
|
if (!this.hasHandlersForEventType("DATABASE_ROW_DELETE", filter, triggerResult)) return;
|
|
@@ -1620,7 +1633,7 @@ var EventManager = class {
|
|
|
1620
1633
|
);
|
|
1621
1634
|
}
|
|
1622
1635
|
async fireUpdateActions(data, triggerResult) {
|
|
1623
|
-
await
|
|
1636
|
+
await Bluebird2.map(
|
|
1624
1637
|
this.actionHandlers.DATABASE_COLUMN_UPDATE,
|
|
1625
1638
|
({ callback, filter }) => {
|
|
1626
1639
|
if (!this.hasHandlersForEventType("DATABASE_COLUMN_UPDATE", filter, triggerResult)) return;
|
|
@@ -1794,16 +1807,19 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1794
1807
|
return enums.join("\n") + "\n" + sqlStatements.join("\n\n");
|
|
1795
1808
|
}
|
|
1796
1809
|
async getScratchPool() {
|
|
1797
|
-
await this.psqlConnectionPool.runQuery(
|
|
1798
|
-
`
|
|
1799
|
-
|
|
1800
|
-
systemUser
|
|
1801
|
-
);
|
|
1802
|
-
await this.psqlConnectionPool.runQuery(
|
|
1803
|
-
`CREATE DATABASE ${this.psqlConnectionPool.poolConfig.database}_scratch;`,
|
|
1810
|
+
const response = await this.psqlConnectionPool.runQuery(
|
|
1811
|
+
`SELECT * FROM pg_database
|
|
1812
|
+
WHERE datname = '${this.psqlConnectionPool.poolConfig.database}_scratch'`,
|
|
1804
1813
|
[],
|
|
1805
1814
|
systemUser
|
|
1806
1815
|
);
|
|
1816
|
+
if (response.length === 0) {
|
|
1817
|
+
await this.psqlConnectionPool.runQuery(
|
|
1818
|
+
`CREATE DATABASE ${this.psqlConnectionPool.poolConfig.database}_scratch;`,
|
|
1819
|
+
[],
|
|
1820
|
+
systemUser
|
|
1821
|
+
);
|
|
1822
|
+
}
|
|
1807
1823
|
const scratchPool = new PsqlPool({
|
|
1808
1824
|
host: this.psqlConnectionPool.poolConfig.host,
|
|
1809
1825
|
port: this.psqlConnectionPool.poolConfig.port,
|
|
@@ -1814,6 +1830,12 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1814
1830
|
idleTimeoutMillis: this.psqlConnectionPool.poolConfig.idleTimeoutMillis,
|
|
1815
1831
|
connectionTimeoutMillis: this.psqlConnectionPool.poolConfig.connectionTimeoutMillis
|
|
1816
1832
|
});
|
|
1833
|
+
await scratchPool.runQuery(`drop schema public cascade;`, [], systemUser);
|
|
1834
|
+
await scratchPool.runQuery(
|
|
1835
|
+
`create schema public authorization ${this.psqlConnectionPool.poolConfig.user};`,
|
|
1836
|
+
[],
|
|
1837
|
+
systemUser
|
|
1838
|
+
);
|
|
1817
1839
|
return scratchPool;
|
|
1818
1840
|
}
|
|
1819
1841
|
async diffDatabaseToSchema(schema) {
|
|
@@ -1833,17 +1855,13 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1833
1855
|
host: this.psqlConnectionPool.poolConfig.host,
|
|
1834
1856
|
port: this.psqlConnectionPool.poolConfig.port
|
|
1835
1857
|
});
|
|
1836
|
-
|
|
1837
|
-
await
|
|
1838
|
-
const
|
|
1839
|
-
|
|
1840
|
-
});
|
|
1841
|
-
const info2 = await pgInfo({
|
|
1842
|
-
client: scratchClient
|
|
1843
|
-
});
|
|
1858
|
+
const promises = [originalClient.connect(), scratchClient.connect()];
|
|
1859
|
+
await Promise.all(promises);
|
|
1860
|
+
const infoPromises = [pgInfo({ client: originalClient }), pgInfo({ client: scratchClient })];
|
|
1861
|
+
const [info1, info2] = await Promise.all(infoPromises);
|
|
1844
1862
|
const diff = getDiff(info1, info2);
|
|
1845
|
-
|
|
1846
|
-
await
|
|
1863
|
+
const endPromises = [originalClient.end(), scratchClient.end()];
|
|
1864
|
+
await Promise.all(endPromises);
|
|
1847
1865
|
return diff.join("\n");
|
|
1848
1866
|
}
|
|
1849
1867
|
createNestedSelect(req, schema, item, routeData, userRole, sqlParams) {
|
|
@@ -1966,7 +1984,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1966
1984
|
);
|
|
1967
1985
|
const totalQuery = `SELECT COUNT(${routeData.groupBy ? `DISTINCT ${routeData.groupBy.tableName}.${routeData.groupBy.columnName}` : "*"}) AS total
|
|
1968
1986
|
${sqlStatement};`;
|
|
1969
|
-
const totalPromise =
|
|
1987
|
+
const totalPromise = this.psqlConnectionPool.runQuery(
|
|
1970
1988
|
totalQuery,
|
|
1971
1989
|
sqlParams,
|
|
1972
1990
|
req.requesterDetails
|
|
@@ -1983,7 +2001,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1983
2001
|
}
|
|
1984
2002
|
async executeUpdateRequest(req, routeData, schema) {
|
|
1985
2003
|
const sqlParams = [];
|
|
1986
|
-
const
|
|
2004
|
+
const _a2 = req.body, { id } = _a2, bodyNoId = __objRest(_a2, ["id"]);
|
|
1987
2005
|
const table = schema.database.find((item) => {
|
|
1988
2006
|
return item.name === routeData.table;
|
|
1989
2007
|
});
|
|
@@ -2098,22 +2116,22 @@ DELETE FROM "${routeData.table}" ${joinStatement} ${whereClause}`;
|
|
|
2098
2116
|
const data = req.data;
|
|
2099
2117
|
if (routeData.type === "PAGED" && !!(data == null ? void 0 : data.filter)) {
|
|
2100
2118
|
let statement = data.filter.replace(/\$[a-zA-Z][a-zA-Z0-9_]+/g, (value) => {
|
|
2101
|
-
var
|
|
2119
|
+
var _a2;
|
|
2102
2120
|
const requestParam = routeData.request.find((item) => {
|
|
2103
2121
|
return item.name === value.replace("$", "");
|
|
2104
2122
|
});
|
|
2105
2123
|
if (!requestParam)
|
|
2106
2124
|
throw new RsError("SCHEMA_ERROR", `Invalid route keyword in route ${routeData.name}`);
|
|
2107
|
-
return ((
|
|
2125
|
+
return ((_a2 = data[requestParam.name]) == null ? void 0 : _a2.toString()) || "";
|
|
2108
2126
|
});
|
|
2109
2127
|
statement = statement.replace(/#[a-zA-Z][a-zA-Z0-9_]+/g, (value) => {
|
|
2110
|
-
var
|
|
2128
|
+
var _a2;
|
|
2111
2129
|
const requestParam = routeData.request.find((item) => {
|
|
2112
2130
|
return item.name === value.replace("#", "");
|
|
2113
2131
|
});
|
|
2114
2132
|
if (!requestParam)
|
|
2115
2133
|
throw new RsError("SCHEMA_ERROR", `Invalid route keyword in route ${routeData.name}`);
|
|
2116
|
-
return ((
|
|
2134
|
+
return ((_a2 = data[requestParam.name]) == null ? void 0 : _a2.toString()) || "";
|
|
2117
2135
|
});
|
|
2118
2136
|
statement = filterPsqlParser_default.parse(statement);
|
|
2119
2137
|
if (whereClause.startsWith("WHERE")) {
|
|
@@ -2235,13 +2253,13 @@ var CompareSchema = class {
|
|
|
2235
2253
|
const originalClone = cloneDeep(originalEndpoints);
|
|
2236
2254
|
const diffObj = [];
|
|
2237
2255
|
newEndPoints.forEach((endPoint) => {
|
|
2238
|
-
const { path:
|
|
2256
|
+
const { path: path5, method } = endPoint;
|
|
2239
2257
|
const endPointIndex = originalClone.findIndex((original) => {
|
|
2240
2258
|
return original.path === endPoint.path && original.method === endPoint.method;
|
|
2241
2259
|
});
|
|
2242
2260
|
if (endPointIndex === -1) {
|
|
2243
2261
|
diffObj.push({
|
|
2244
|
-
name: `${method} ${
|
|
2262
|
+
name: `${method} ${path5}`,
|
|
2245
2263
|
changeType: "NEW"
|
|
2246
2264
|
});
|
|
2247
2265
|
} else {
|
|
@@ -2250,7 +2268,7 @@ var CompareSchema = class {
|
|
|
2250
2268
|
});
|
|
2251
2269
|
if (original === -1) {
|
|
2252
2270
|
diffObj.push({
|
|
2253
|
-
name: `${method} ${
|
|
2271
|
+
name: `${method} ${path5}`,
|
|
2254
2272
|
changeType: "MODIFIED"
|
|
2255
2273
|
});
|
|
2256
2274
|
}
|
|
@@ -2258,9 +2276,9 @@ var CompareSchema = class {
|
|
|
2258
2276
|
}
|
|
2259
2277
|
});
|
|
2260
2278
|
originalClone.forEach((original) => {
|
|
2261
|
-
const { path:
|
|
2279
|
+
const { path: path5, method } = original;
|
|
2262
2280
|
diffObj.push({
|
|
2263
|
-
name: `${method} ${
|
|
2281
|
+
name: `${method} ${path5}`,
|
|
2264
2282
|
changeType: "DELETED"
|
|
2265
2283
|
});
|
|
2266
2284
|
});
|
|
@@ -2285,6 +2303,63 @@ __decorateClass([
|
|
|
2285
2303
|
var compareSchema = new CompareSchema();
|
|
2286
2304
|
var compareSchema_default = compareSchema;
|
|
2287
2305
|
|
|
2306
|
+
// src/restura/middleware/getMulterUploadSingleton.ts
|
|
2307
|
+
import multer from "multer";
|
|
2308
|
+
import { extname } from "path";
|
|
2309
|
+
import * as os from "os";
|
|
2310
|
+
var OneHundredMB = 100 * 1024 * 1024;
|
|
2311
|
+
var commonUpload = null;
|
|
2312
|
+
var getMulterUploadSingleton = (directory) => {
|
|
2313
|
+
if (commonUpload) return commonUpload;
|
|
2314
|
+
const storage = multer.diskStorage({
|
|
2315
|
+
destination: directory || os.tmpdir(),
|
|
2316
|
+
filename: function(request, file, cb) {
|
|
2317
|
+
const extension = extname(file.originalname);
|
|
2318
|
+
const uniqueName = Date.now() + "-" + Math.round(Math.random() * 1e3);
|
|
2319
|
+
cb(null, `${uniqueName}${extension}`);
|
|
2320
|
+
}
|
|
2321
|
+
});
|
|
2322
|
+
commonUpload = multer({
|
|
2323
|
+
storage,
|
|
2324
|
+
limits: {
|
|
2325
|
+
fileSize: OneHundredMB
|
|
2326
|
+
}
|
|
2327
|
+
});
|
|
2328
|
+
return commonUpload;
|
|
2329
|
+
};
|
|
2330
|
+
|
|
2331
|
+
// src/restura/utils/TempCache.ts
|
|
2332
|
+
import fs3 from "fs";
|
|
2333
|
+
import path3 from "path";
|
|
2334
|
+
import { DateUtils } from "@redskytech/core-utils";
|
|
2335
|
+
import Bluebird3 from "bluebird";
|
|
2336
|
+
import * as os2 from "os";
|
|
2337
|
+
import { fileUtils as fileUtils2 } from "@restura/internal";
|
|
2338
|
+
var TempCache = class {
|
|
2339
|
+
constructor(location) {
|
|
2340
|
+
this.maxDurationDays = 7;
|
|
2341
|
+
this.location = location || os2.tmpdir();
|
|
2342
|
+
fileUtils2.ensureDir(this.location).catch((e) => {
|
|
2343
|
+
throw e;
|
|
2344
|
+
});
|
|
2345
|
+
}
|
|
2346
|
+
async cleanup() {
|
|
2347
|
+
const fileList = await fs3.promises.readdir(this.location);
|
|
2348
|
+
await Bluebird3.map(
|
|
2349
|
+
fileList,
|
|
2350
|
+
async (file) => {
|
|
2351
|
+
const fullFilePath = path3.join(this.location, file);
|
|
2352
|
+
const fileStats = await fs3.promises.stat(fullFilePath);
|
|
2353
|
+
if (DateUtils.daysBetweenStartAndEndDates(new Date(fileStats.mtimeMs), /* @__PURE__ */ new Date()) > this.maxDurationDays) {
|
|
2354
|
+
logger.info(`Deleting old temp file: ${file}`);
|
|
2355
|
+
await fs3.promises.unlink(fullFilePath);
|
|
2356
|
+
}
|
|
2357
|
+
},
|
|
2358
|
+
{ concurrency: 10 }
|
|
2359
|
+
);
|
|
2360
|
+
}
|
|
2361
|
+
};
|
|
2362
|
+
|
|
2288
2363
|
// src/restura/restura.ts
|
|
2289
2364
|
var { types } = pg3;
|
|
2290
2365
|
var ResturaEngine = class {
|
|
@@ -2305,6 +2380,8 @@ var ResturaEngine = class {
|
|
|
2305
2380
|
*/
|
|
2306
2381
|
async init(app, authenticationHandler, psqlConnectionPool) {
|
|
2307
2382
|
this.resturaConfig = config2.validate("restura", resturaConfigSchema);
|
|
2383
|
+
this.multerCommonUpload = getMulterUploadSingleton(this.resturaConfig.fileTempCachePath);
|
|
2384
|
+
new TempCache(this.resturaConfig.fileTempCachePath);
|
|
2308
2385
|
this.psqlConnectionPool = psqlConnectionPool;
|
|
2309
2386
|
this.psqlEngine = new PsqlEngine(this.psqlConnectionPool, true);
|
|
2310
2387
|
setupPgReturnTypes();
|
|
@@ -2371,7 +2448,7 @@ var ResturaEngine = class {
|
|
|
2371
2448
|
* @returns A promise that resolves when the API has been successfully generated and written to the output file.
|
|
2372
2449
|
*/
|
|
2373
2450
|
async generateApiFromSchema(outputFile, providedSchema) {
|
|
2374
|
-
|
|
2451
|
+
fs4.writeFileSync(
|
|
2375
2452
|
outputFile,
|
|
2376
2453
|
await apiGenerator(providedSchema, await this.generateHashForSchema(providedSchema))
|
|
2377
2454
|
);
|
|
@@ -2384,7 +2461,7 @@ var ResturaEngine = class {
|
|
|
2384
2461
|
* @returns A promise that resolves when the model has been successfully written to the output file.
|
|
2385
2462
|
*/
|
|
2386
2463
|
async generateModelFromSchema(outputFile, providedSchema) {
|
|
2387
|
-
|
|
2464
|
+
fs4.writeFileSync(
|
|
2388
2465
|
outputFile,
|
|
2389
2466
|
await modelGenerator(providedSchema, await this.generateHashForSchema(providedSchema))
|
|
2390
2467
|
);
|
|
@@ -2396,11 +2473,11 @@ var ResturaEngine = class {
|
|
|
2396
2473
|
* @throws {Error} If the schema file is missing or the schema is not valid.
|
|
2397
2474
|
*/
|
|
2398
2475
|
async getLatestFileSystemSchema() {
|
|
2399
|
-
if (!
|
|
2476
|
+
if (!fs4.existsSync(this.resturaConfig.schemaFilePath)) {
|
|
2400
2477
|
logger.error(`Missing restura schema file, expected path: ${this.resturaConfig.schemaFilePath}`);
|
|
2401
2478
|
throw new Error("Missing restura schema file");
|
|
2402
2479
|
}
|
|
2403
|
-
const schemaFileData =
|
|
2480
|
+
const schemaFileData = fs4.readFileSync(this.resturaConfig.schemaFilePath, { encoding: "utf8" });
|
|
2404
2481
|
const schema = ObjectUtils5.safeParse(schemaFileData);
|
|
2405
2482
|
const isValid = await isSchemaValid(schema);
|
|
2406
2483
|
if (!isValid) {
|
|
@@ -2419,11 +2496,11 @@ var ResturaEngine = class {
|
|
|
2419
2496
|
* - `modelCreatedSchemaHash`: The hash extracted from the generated `models.d.ts` file.
|
|
2420
2497
|
*/
|
|
2421
2498
|
async getHashes(providedSchema) {
|
|
2422
|
-
var
|
|
2499
|
+
var _a2, _b, _c, _d;
|
|
2423
2500
|
const schemaHash = await this.generateHashForSchema(providedSchema);
|
|
2424
|
-
const apiFile =
|
|
2425
|
-
const apiCreatedSchemaHash = (_b = (
|
|
2426
|
-
const modelFile =
|
|
2501
|
+
const apiFile = fs4.readFileSync(path4.join(this.resturaConfig.generatedTypesPath, "api.d.ts"));
|
|
2502
|
+
const apiCreatedSchemaHash = (_b = (_a2 = apiFile.toString().match(/\((.*)\)/)) == null ? void 0 : _a2[1]) != null ? _b : "";
|
|
2503
|
+
const modelFile = fs4.readFileSync(path4.join(this.resturaConfig.generatedTypesPath, "models.d.ts"));
|
|
2427
2504
|
const modelCreatedSchemaHash = (_d = (_c = modelFile.toString().match(/\((.*)\)/)) == null ? void 0 : _c[1]) != null ? _d : "";
|
|
2428
2505
|
return {
|
|
2429
2506
|
schemaHash,
|
|
@@ -2459,27 +2536,27 @@ var ResturaEngine = class {
|
|
|
2459
2536
|
logger.info(`Restura loaded (${routeCount}) endpoint${routeCount > 1 ? "s" : ""}`);
|
|
2460
2537
|
}
|
|
2461
2538
|
async validateGeneratedTypesFolder() {
|
|
2462
|
-
if (!
|
|
2463
|
-
|
|
2539
|
+
if (!fs4.existsSync(this.resturaConfig.generatedTypesPath)) {
|
|
2540
|
+
fs4.mkdirSync(this.resturaConfig.generatedTypesPath, { recursive: true });
|
|
2464
2541
|
}
|
|
2465
|
-
const hasApiFile =
|
|
2466
|
-
const hasModelsFile =
|
|
2542
|
+
const hasApiFile = fs4.existsSync(path4.join(this.resturaConfig.generatedTypesPath, "api.d.ts"));
|
|
2543
|
+
const hasModelsFile = fs4.existsSync(path4.join(this.resturaConfig.generatedTypesPath, "models.d.ts"));
|
|
2467
2544
|
if (!hasApiFile) {
|
|
2468
|
-
await this.generateApiFromSchema(
|
|
2545
|
+
await this.generateApiFromSchema(path4.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
|
|
2469
2546
|
}
|
|
2470
2547
|
if (!hasModelsFile) {
|
|
2471
2548
|
await this.generateModelFromSchema(
|
|
2472
|
-
|
|
2549
|
+
path4.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
|
|
2473
2550
|
this.schema
|
|
2474
2551
|
);
|
|
2475
2552
|
}
|
|
2476
2553
|
const hashes = await this.getHashes(this.schema);
|
|
2477
2554
|
if (hashes.schemaHash !== hashes.apiCreatedSchemaHash) {
|
|
2478
|
-
await this.generateApiFromSchema(
|
|
2555
|
+
await this.generateApiFromSchema(path4.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
|
|
2479
2556
|
}
|
|
2480
2557
|
if (hashes.schemaHash !== hashes.modelCreatedSchemaHash) {
|
|
2481
2558
|
await this.generateModelFromSchema(
|
|
2482
|
-
|
|
2559
|
+
path4.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
|
|
2483
2560
|
this.schema
|
|
2484
2561
|
);
|
|
2485
2562
|
}
|
|
@@ -2509,9 +2586,9 @@ var ResturaEngine = class {
|
|
|
2509
2586
|
}
|
|
2510
2587
|
}
|
|
2511
2588
|
async updateTypes() {
|
|
2512
|
-
await this.generateApiFromSchema(
|
|
2589
|
+
await this.generateApiFromSchema(path4.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
|
|
2513
2590
|
await this.generateModelFromSchema(
|
|
2514
|
-
|
|
2591
|
+
path4.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
|
|
2515
2592
|
this.schema
|
|
2516
2593
|
);
|
|
2517
2594
|
}
|
|
@@ -2529,10 +2606,30 @@ var ResturaEngine = class {
|
|
|
2529
2606
|
res.status(400).send({ error: err });
|
|
2530
2607
|
}
|
|
2531
2608
|
}
|
|
2609
|
+
async getMulterFilesIfAny(req, res, routeData) {
|
|
2610
|
+
var _a2;
|
|
2611
|
+
if (!((_a2 = req.header("content-type")) == null ? void 0 : _a2.includes("multipart/form-data"))) return;
|
|
2612
|
+
if (!this.isCustomRoute(routeData)) return;
|
|
2613
|
+
if (!routeData.fileUploadType) {
|
|
2614
|
+
throw new RsError("BAD_REQUEST", "File upload type not defined for route");
|
|
2615
|
+
}
|
|
2616
|
+
const multerFileUploadFunction = routeData.fileUploadType === "MULTIPLE" ? this.multerCommonUpload.array("files") : this.multerCommonUpload.single("file");
|
|
2617
|
+
return new Promise((resolve2, reject) => {
|
|
2618
|
+
multerFileUploadFunction(req, res, (err) => {
|
|
2619
|
+
if (err) {
|
|
2620
|
+
logger.warn("Multer error: " + err);
|
|
2621
|
+
reject(err);
|
|
2622
|
+
}
|
|
2623
|
+
if (req.body["data"]) req.body = JSON.parse(req.body["data"]);
|
|
2624
|
+
resolve2();
|
|
2625
|
+
});
|
|
2626
|
+
});
|
|
2627
|
+
}
|
|
2532
2628
|
async executeRouteLogic(req, res, next) {
|
|
2533
2629
|
try {
|
|
2534
2630
|
const routeData = this.getRouteData(req.method, req.baseUrl, req.path);
|
|
2535
2631
|
this.validateAuthorization(req, routeData);
|
|
2632
|
+
await this.getMulterFilesIfAny(req, res, routeData);
|
|
2536
2633
|
validateRequestParams(req, routeData, this.customTypeValidation);
|
|
2537
2634
|
if (this.isCustomRoute(routeData)) {
|
|
2538
2635
|
await this.runCustomRouteLogic(req, res, routeData);
|
|
@@ -2569,7 +2666,8 @@ var ResturaEngine = class {
|
|
|
2569
2666
|
return acc + StringUtils3.capitalizeFirst(cur);
|
|
2570
2667
|
}, "")}`;
|
|
2571
2668
|
const customFunction = customApi[functionName];
|
|
2572
|
-
if (!customFunction)
|
|
2669
|
+
if (!customFunction)
|
|
2670
|
+
throw new RsError("NOT_FOUND", `API path ${routeData.path} not implemented ${functionName}`);
|
|
2573
2671
|
await customFunction(req, res, routeData);
|
|
2574
2672
|
}
|
|
2575
2673
|
async generateHashForSchema(providedSchema) {
|
|
@@ -2596,7 +2694,7 @@ var ResturaEngine = class {
|
|
|
2596
2694
|
printWidth: 120,
|
|
2597
2695
|
singleQuote: true
|
|
2598
2696
|
}));
|
|
2599
|
-
|
|
2697
|
+
fs4.writeFileSync(this.resturaConfig.schemaFilePath, schemaPrettyStr);
|
|
2600
2698
|
}
|
|
2601
2699
|
resetPublicEndpoints() {
|
|
2602
2700
|
this.publicEndpoints = {
|
|
@@ -2613,13 +2711,13 @@ var ResturaEngine = class {
|
|
|
2613
2711
|
if (!routeData.roles.includes(role))
|
|
2614
2712
|
throw new RsError("UNAUTHORIZED", "Not authorized to access this endpoint");
|
|
2615
2713
|
}
|
|
2616
|
-
getRouteData(method, baseUrl,
|
|
2714
|
+
getRouteData(method, baseUrl, path5) {
|
|
2617
2715
|
const endpoint = this.schema.endpoints.find((item) => {
|
|
2618
2716
|
return item.baseUrl === baseUrl;
|
|
2619
2717
|
});
|
|
2620
2718
|
if (!endpoint) throw new RsError("NOT_FOUND", "Route not found");
|
|
2621
2719
|
const route = endpoint.routes.find((item) => {
|
|
2622
|
-
return item.method === method && item.path ===
|
|
2720
|
+
return item.method === method && item.path === path5;
|
|
2623
2721
|
});
|
|
2624
2722
|
if (!route) throw new RsError("NOT_FOUND", "Route not found");
|
|
2625
2723
|
return route;
|
|
@@ -2640,6 +2738,9 @@ __decorateClass([
|
|
|
2640
2738
|
__decorateClass([
|
|
2641
2739
|
boundMethod
|
|
2642
2740
|
], ResturaEngine.prototype, "getSchemaAndTypes", 1);
|
|
2741
|
+
__decorateClass([
|
|
2742
|
+
boundMethod
|
|
2743
|
+
], ResturaEngine.prototype, "getMulterFilesIfAny", 1);
|
|
2643
2744
|
__decorateClass([
|
|
2644
2745
|
boundMethod
|
|
2645
2746
|
], ResturaEngine.prototype, "executeRouteLogic", 1);
|