@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 CHANGED
@@ -42,18 +42,21 @@ declare const resturaConfigSchema: z.ZodObject<{
42
42
  schemaFilePath: z.ZodDefault<z.ZodString>;
43
43
  customApiFolderPath: z.ZodDefault<z.ZodString>;
44
44
  generatedTypesPath: z.ZodDefault<z.ZodString>;
45
+ fileTempCachePath: z.ZodOptional<z.ZodString>;
45
46
  }, "strip", z.ZodTypeAny, {
46
47
  authToken: string;
47
48
  sendErrorStackTrace: boolean;
48
49
  schemaFilePath: string;
49
50
  customApiFolderPath: string;
50
51
  generatedTypesPath: string;
52
+ fileTempCachePath?: string | undefined;
51
53
  }, {
52
54
  authToken: string;
53
55
  sendErrorStackTrace?: boolean | undefined;
54
56
  schemaFilePath?: string | undefined;
55
57
  customApiFolderPath?: string | undefined;
56
58
  generatedTypesPath?: string | undefined;
59
+ fileTempCachePath?: string | undefined;
57
60
  }>;
58
61
  type ResturaConfigSchema = z.infer<typeof resturaConfigSchema>;
59
62
 
@@ -2377,6 +2380,7 @@ declare class PsqlPool extends PsqlConnection {
2377
2380
 
2378
2381
  declare class ResturaEngine {
2379
2382
  resturaConfig: ResturaConfigSchema;
2383
+ private multerCommonUpload;
2380
2384
  private resturaRouter;
2381
2385
  private publicEndpoints;
2382
2386
  private expressApp;
@@ -2455,6 +2459,7 @@ declare class ResturaEngine {
2455
2459
  private updateTypes;
2456
2460
  private getSchema;
2457
2461
  private getSchemaAndTypes;
2462
+ private getMulterFilesIfAny;
2458
2463
  private executeRouteLogic;
2459
2464
  private isCustomRoute;
2460
2465
  private runCustomRouteLogic;
package/dist/index.d.ts CHANGED
@@ -42,18 +42,21 @@ declare const resturaConfigSchema: z.ZodObject<{
42
42
  schemaFilePath: z.ZodDefault<z.ZodString>;
43
43
  customApiFolderPath: z.ZodDefault<z.ZodString>;
44
44
  generatedTypesPath: z.ZodDefault<z.ZodString>;
45
+ fileTempCachePath: z.ZodOptional<z.ZodString>;
45
46
  }, "strip", z.ZodTypeAny, {
46
47
  authToken: string;
47
48
  sendErrorStackTrace: boolean;
48
49
  schemaFilePath: string;
49
50
  customApiFolderPath: string;
50
51
  generatedTypesPath: string;
52
+ fileTempCachePath?: string | undefined;
51
53
  }, {
52
54
  authToken: string;
53
55
  sendErrorStackTrace?: boolean | undefined;
54
56
  schemaFilePath?: string | undefined;
55
57
  customApiFolderPath?: string | undefined;
56
58
  generatedTypesPath?: string | undefined;
59
+ fileTempCachePath?: string | undefined;
57
60
  }>;
58
61
  type ResturaConfigSchema = z.infer<typeof resturaConfigSchema>;
59
62
 
@@ -2377,6 +2380,7 @@ declare class PsqlPool extends PsqlConnection {
2377
2380
 
2378
2381
  declare class ResturaEngine {
2379
2382
  resturaConfig: ResturaConfigSchema;
2383
+ private multerCommonUpload;
2380
2384
  private resturaRouter;
2381
2385
  private publicEndpoints;
2382
2386
  private expressApp;
@@ -2455,6 +2459,7 @@ declare class ResturaEngine {
2455
2459
  private updateTypes;
2456
2460
  private getSchema;
2457
2461
  private getSchemaAndTypes;
2462
+ private getMulterFilesIfAny;
2458
2463
  private executeRouteLogic;
2459
2464
  private isCustomRoute;
2460
2465
  private runCustomRouteLogic;
package/dist/index.js CHANGED
@@ -95,12 +95,17 @@ var import_zod = require("zod");
95
95
  var loggerConfigSchema = import_zod.z.object({
96
96
  level: import_zod.z.enum(["info", "warn", "error", "debug", "silly"]).default("info")
97
97
  });
98
+ var _a;
99
+ var isTsx = (_a = process.argv[1]) == null ? void 0 : _a.endsWith(".ts");
100
+ var isTsNode = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
101
+ var customApiFolderPath = isTsx || isTsNode ? "/src/api" : "/dist/api";
98
102
  var resturaConfigSchema = import_zod.z.object({
99
103
  authToken: import_zod.z.string().min(1, "Missing Restura Auth Token"),
100
104
  sendErrorStackTrace: import_zod.z.boolean().default(false),
101
105
  schemaFilePath: import_zod.z.string().default(process.cwd() + "/restura.schema.json"),
102
- customApiFolderPath: import_zod.z.string().default(process.cwd() + "/dist/api"),
103
- generatedTypesPath: import_zod.z.string().default(process.cwd() + "/src/@types")
106
+ customApiFolderPath: import_zod.z.string().default(process.cwd() + customApiFolderPath),
107
+ generatedTypesPath: import_zod.z.string().default(process.cwd() + "/src/@types"),
108
+ fileTempCachePath: import_zod.z.string().optional()
104
109
  });
105
110
 
106
111
  // src/logger/logger.ts
@@ -205,8 +210,8 @@ var htmlStatusMap = {
205
210
  };
206
211
 
207
212
  // src/restura/restura.ts
208
- var import_core_utils6 = require("@redskytech/core-utils");
209
- var import_internal2 = require("@restura/internal");
213
+ var import_core_utils7 = require("@redskytech/core-utils");
214
+ var import_internal4 = require("@restura/internal");
210
215
 
211
216
  // ../../node_modules/.pnpm/autobind-decorator@2.4.0/node_modules/autobind-decorator/lib/esm/index.js
212
217
  function _typeof(obj) {
@@ -260,8 +265,8 @@ var import_compression = __toESM(require("compression"));
260
265
  var import_cookie_parser = __toESM(require("cookie-parser"));
261
266
  var import_crypto = require("crypto");
262
267
  var express = __toESM(require("express"));
263
- var import_fs3 = __toESM(require("fs"));
264
- var import_path3 = __toESM(require("path"));
268
+ var import_fs4 = __toESM(require("fs"));
269
+ var import_path5 = __toESM(require("path"));
265
270
  var import_pg3 = __toESM(require("pg"));
266
271
  var prettier3 = __toESM(require("prettier"));
267
272
 
@@ -356,9 +361,9 @@ var ResponseValidator = class _ResponseValidator {
356
361
  return { validator: "any" };
357
362
  }
358
363
  getTypeFromTable(selector, name) {
359
- const path4 = selector.split(".");
360
- if (path4.length === 0 || path4.length > 2 || path4[0] === "") return { validator: "any", isOptional: false };
361
- const tableName = path4.length == 2 ? path4[0] : name, columnName = path4.length == 2 ? path4[1] : path4[0];
364
+ const path5 = selector.split(".");
365
+ if (path5.length === 0 || path5.length > 2 || path5[0] === "") return { validator: "any", isOptional: false };
366
+ const tableName = path5.length == 2 ? path5[0] : name, columnName = path5.length == 2 ? path5[1] : path5[0];
362
367
  const table = this.database.find((t) => t.name == tableName);
363
368
  const column = table == null ? void 0 : table.columns.find((c) => c.name == columnName);
364
369
  if (!table || !column) return { validator: "any", isOptional: false };
@@ -574,10 +579,10 @@ var ApiTree = class _ApiTree {
574
579
  return `${p.name}:${responseType}${array ? "[]" : ""}${isNullable ? " | null" : ""}`;
575
580
  }
576
581
  getTypeFromTable(selector, name) {
577
- const path4 = selector.split(".");
578
- if (path4.length === 0 || path4.length > 2 || path4[0] === "") return { responseType: "any", isNullable: false };
579
- let tableName = path4.length == 2 ? path4[0] : name;
580
- const columnName = path4.length == 2 ? path4[1] : path4[0];
582
+ const path5 = selector.split(".");
583
+ if (path5.length === 0 || path5.length > 2 || path5[0] === "") return { responseType: "any", isNullable: false };
584
+ let tableName = path5.length == 2 ? path5[0] : name;
585
+ const columnName = path5.length == 2 ? path5[1] : path5[0];
581
586
  let table = this.database.find((t) => t.name == tableName);
582
587
  if (!table && tableName.includes("_")) {
583
588
  const tableAliasSplit = tableName.split("_");
@@ -592,8 +597,8 @@ var ApiTree = class _ApiTree {
592
597
  };
593
598
  }
594
599
  };
595
- function pathToNamespaces(path4) {
596
- return path4.split("/").map((e) => import_core_utils.StringUtils.toPascalCasing(e)).filter((e) => e);
600
+ function pathToNamespaces(path5) {
601
+ return path5.split("/").map((e) => import_core_utils.StringUtils.toPascalCasing(e)).filter((e) => e);
597
602
  }
598
603
  function apiGenerator(schema, schemaHash) {
599
604
  let apiString = `/** Auto generated file from Schema Hash (${schemaHash}). DO NOT MODIFY **/`;
@@ -629,6 +634,8 @@ function apiGenerator(schema, schemaHash) {
629
634
  // src/restura/customApiFactory.ts
630
635
  var import_fs = __toESM(require("fs"));
631
636
  var import_path = __toESM(require("path"));
637
+ var import_bluebird = __toESM(require("bluebird"));
638
+ var import_internal2 = require("@restura/internal");
632
639
  var CustomApiFactory = class {
633
640
  constructor() {
634
641
  this.customApis = {};
@@ -637,7 +644,8 @@ var CustomApiFactory = class {
637
644
  const apiVersions = ["v1"];
638
645
  for (const apiVersion of apiVersions) {
639
646
  const apiVersionFolderPath = import_path.default.join(baseFolderPath, apiVersion);
640
- if (!import_fs.default.existsSync(apiVersionFolderPath)) continue;
647
+ const directoryExists = await import_internal2.fileUtils.existDir(apiVersionFolderPath);
648
+ if (!directoryExists) continue;
641
649
  await this.addDirectory(apiVersionFolderPath, apiVersion);
642
650
  }
643
651
  }
@@ -645,12 +653,17 @@ var CustomApiFactory = class {
645
653
  return this.customApis[customApiName];
646
654
  }
647
655
  async addDirectory(directoryPath, apiVersion) {
648
- const entries = import_fs.default.readdirSync(directoryPath, {
656
+ var _a2;
657
+ const entries = await import_fs.default.promises.readdir(directoryPath, {
649
658
  withFileTypes: true
650
659
  });
651
- for (const entry of entries) {
660
+ const isTsx2 = (_a2 = process.argv[1]) == null ? void 0 : _a2.endsWith(".ts");
661
+ const isTsNode2 = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
662
+ const extension = isTsx2 || isTsNode2 ? "ts" : "js";
663
+ const shouldEndWith = `.api.${apiVersion}.${extension}`;
664
+ await import_bluebird.default.map(entries, async (entry) => {
652
665
  if (entry.isFile()) {
653
- if (entry.name.endsWith(`.api.${apiVersion}.js`) === false) continue;
666
+ if (entry.name.endsWith(shouldEndWith) === false) return;
654
667
  try {
655
668
  const importPath = `${import_path.default.join(directoryPath, entry.name)}`;
656
669
  const ApiImport = await import(importPath);
@@ -662,7 +675,7 @@ var CustomApiFactory = class {
662
675
  console.error(e);
663
676
  }
664
677
  }
665
- }
678
+ });
666
679
  }
667
680
  bindMethodsToInstance(instance) {
668
681
  const proto = Object.getPrototypeOf(instance);
@@ -1463,11 +1476,11 @@ var SqlEngine = class {
1463
1476
  return returnValue;
1464
1477
  }
1465
1478
  replaceLocalParamKeywords(value, routeData, req, sqlParams) {
1466
- var _a;
1479
+ var _a2;
1467
1480
  if (!routeData.request) return value;
1468
1481
  const data = req.data;
1469
1482
  if (typeof value === "string") {
1470
- (_a = value.match(/\$[a-zA-Z][a-zA-Z0-9_]+/g)) == null ? void 0 : _a.forEach((param) => {
1483
+ (_a2 = value.match(/\$[a-zA-Z][a-zA-Z0-9_]+/g)) == null ? void 0 : _a2.forEach((param) => {
1471
1484
  const requestParam = routeData.request.find((item) => {
1472
1485
  return item.name === param.replace("$", "");
1473
1486
  });
@@ -1480,9 +1493,9 @@ var SqlEngine = class {
1480
1493
  return value;
1481
1494
  }
1482
1495
  replaceGlobalParamKeywords(value, routeData, req, sqlParams) {
1483
- var _a;
1496
+ var _a2;
1484
1497
  if (typeof value === "string") {
1485
- (_a = value.match(/#[a-zA-Z][a-zA-Z0-9_]+/g)) == null ? void 0 : _a.forEach((param) => {
1498
+ (_a2 = value.match(/#[a-zA-Z][a-zA-Z0-9_]+/g)) == null ? void 0 : _a2.forEach((param) => {
1486
1499
  param = param.replace("#", "");
1487
1500
  const globalParamValue = req.requesterDetails[param];
1488
1501
  if (!globalParamValue)
@@ -1598,7 +1611,7 @@ var filterPsqlParser = import_pegjs.default.generate(filterSqlGrammar, {
1598
1611
  var filterPsqlParser_default = filterPsqlParser;
1599
1612
 
1600
1613
  // src/restura/eventManager.ts
1601
- var import_bluebird = __toESM(require("bluebird"));
1614
+ var import_bluebird2 = __toESM(require("bluebird"));
1602
1615
  var EventManager = class {
1603
1616
  constructor() {
1604
1617
  this.actionHandlers = {
@@ -1635,7 +1648,7 @@ var EventManager = class {
1635
1648
  }
1636
1649
  }
1637
1650
  async fireInsertActions(data, triggerResult) {
1638
- await import_bluebird.default.map(
1651
+ await import_bluebird2.default.map(
1639
1652
  this.actionHandlers.DATABASE_ROW_INSERT,
1640
1653
  ({ callback, filter }) => {
1641
1654
  if (!this.hasHandlersForEventType("DATABASE_ROW_INSERT", filter, triggerResult)) return;
@@ -1651,7 +1664,7 @@ var EventManager = class {
1651
1664
  );
1652
1665
  }
1653
1666
  async fireDeleteActions(data, triggerResult) {
1654
- await import_bluebird.default.map(
1667
+ await import_bluebird2.default.map(
1655
1668
  this.actionHandlers.DATABASE_ROW_DELETE,
1656
1669
  ({ callback, filter }) => {
1657
1670
  if (!this.hasHandlersForEventType("DATABASE_ROW_DELETE", filter, triggerResult)) return;
@@ -1666,7 +1679,7 @@ var EventManager = class {
1666
1679
  );
1667
1680
  }
1668
1681
  async fireUpdateActions(data, triggerResult) {
1669
- await import_bluebird.default.map(
1682
+ await import_bluebird2.default.map(
1670
1683
  this.actionHandlers.DATABASE_COLUMN_UPDATE,
1671
1684
  ({ callback, filter }) => {
1672
1685
  if (!this.hasHandlersForEventType("DATABASE_COLUMN_UPDATE", filter, triggerResult)) return;
@@ -1840,16 +1853,19 @@ var PsqlEngine = class extends SqlEngine {
1840
1853
  return enums.join("\n") + "\n" + sqlStatements.join("\n\n");
1841
1854
  }
1842
1855
  async getScratchPool() {
1843
- await this.psqlConnectionPool.runQuery(
1844
- `DROP DATABASE IF EXISTS ${this.psqlConnectionPool.poolConfig.database}_scratch`,
1845
- [],
1846
- systemUser
1847
- );
1848
- await this.psqlConnectionPool.runQuery(
1849
- `CREATE DATABASE ${this.psqlConnectionPool.poolConfig.database}_scratch;`,
1856
+ const response = await this.psqlConnectionPool.runQuery(
1857
+ `SELECT * FROM pg_database
1858
+ WHERE datname = '${this.psqlConnectionPool.poolConfig.database}_scratch'`,
1850
1859
  [],
1851
1860
  systemUser
1852
1861
  );
1862
+ if (response.length === 0) {
1863
+ await this.psqlConnectionPool.runQuery(
1864
+ `CREATE DATABASE ${this.psqlConnectionPool.poolConfig.database}_scratch;`,
1865
+ [],
1866
+ systemUser
1867
+ );
1868
+ }
1853
1869
  const scratchPool = new PsqlPool({
1854
1870
  host: this.psqlConnectionPool.poolConfig.host,
1855
1871
  port: this.psqlConnectionPool.poolConfig.port,
@@ -1860,6 +1876,12 @@ var PsqlEngine = class extends SqlEngine {
1860
1876
  idleTimeoutMillis: this.psqlConnectionPool.poolConfig.idleTimeoutMillis,
1861
1877
  connectionTimeoutMillis: this.psqlConnectionPool.poolConfig.connectionTimeoutMillis
1862
1878
  });
1879
+ await scratchPool.runQuery(`drop schema public cascade;`, [], systemUser);
1880
+ await scratchPool.runQuery(
1881
+ `create schema public authorization ${this.psqlConnectionPool.poolConfig.user};`,
1882
+ [],
1883
+ systemUser
1884
+ );
1863
1885
  return scratchPool;
1864
1886
  }
1865
1887
  async diffDatabaseToSchema(schema) {
@@ -1879,17 +1901,13 @@ var PsqlEngine = class extends SqlEngine {
1879
1901
  host: this.psqlConnectionPool.poolConfig.host,
1880
1902
  port: this.psqlConnectionPool.poolConfig.port
1881
1903
  });
1882
- await originalClient.connect();
1883
- await scratchClient.connect();
1884
- const info1 = await (0, import_pg_info.default)({
1885
- client: originalClient
1886
- });
1887
- const info2 = await (0, import_pg_info.default)({
1888
- client: scratchClient
1889
- });
1904
+ const promises = [originalClient.connect(), scratchClient.connect()];
1905
+ await Promise.all(promises);
1906
+ const infoPromises = [(0, import_pg_info.default)({ client: originalClient }), (0, import_pg_info.default)({ client: scratchClient })];
1907
+ const [info1, info2] = await Promise.all(infoPromises);
1890
1908
  const diff = (0, import_pg_diff_sync.default)(info1, info2);
1891
- await originalClient.end();
1892
- await scratchClient.end();
1909
+ const endPromises = [originalClient.end(), scratchClient.end()];
1910
+ await Promise.all(endPromises);
1893
1911
  return diff.join("\n");
1894
1912
  }
1895
1913
  createNestedSelect(req, schema, item, routeData, userRole, sqlParams) {
@@ -2012,7 +2030,7 @@ var PsqlEngine = class extends SqlEngine {
2012
2030
  );
2013
2031
  const totalQuery = `SELECT COUNT(${routeData.groupBy ? `DISTINCT ${routeData.groupBy.tableName}.${routeData.groupBy.columnName}` : "*"}) AS total
2014
2032
  ${sqlStatement};`;
2015
- const totalPromise = await this.psqlConnectionPool.runQuery(
2033
+ const totalPromise = this.psqlConnectionPool.runQuery(
2016
2034
  totalQuery,
2017
2035
  sqlParams,
2018
2036
  req.requesterDetails
@@ -2029,7 +2047,7 @@ var PsqlEngine = class extends SqlEngine {
2029
2047
  }
2030
2048
  async executeUpdateRequest(req, routeData, schema) {
2031
2049
  const sqlParams = [];
2032
- const _a = req.body, { id } = _a, bodyNoId = __objRest(_a, ["id"]);
2050
+ const _a2 = req.body, { id } = _a2, bodyNoId = __objRest(_a2, ["id"]);
2033
2051
  const table = schema.database.find((item) => {
2034
2052
  return item.name === routeData.table;
2035
2053
  });
@@ -2144,22 +2162,22 @@ DELETE FROM "${routeData.table}" ${joinStatement} ${whereClause}`;
2144
2162
  const data = req.data;
2145
2163
  if (routeData.type === "PAGED" && !!(data == null ? void 0 : data.filter)) {
2146
2164
  let statement = data.filter.replace(/\$[a-zA-Z][a-zA-Z0-9_]+/g, (value) => {
2147
- var _a;
2165
+ var _a2;
2148
2166
  const requestParam = routeData.request.find((item) => {
2149
2167
  return item.name === value.replace("$", "");
2150
2168
  });
2151
2169
  if (!requestParam)
2152
2170
  throw new RsError("SCHEMA_ERROR", `Invalid route keyword in route ${routeData.name}`);
2153
- return ((_a = data[requestParam.name]) == null ? void 0 : _a.toString()) || "";
2171
+ return ((_a2 = data[requestParam.name]) == null ? void 0 : _a2.toString()) || "";
2154
2172
  });
2155
2173
  statement = statement.replace(/#[a-zA-Z][a-zA-Z0-9_]+/g, (value) => {
2156
- var _a;
2174
+ var _a2;
2157
2175
  const requestParam = routeData.request.find((item) => {
2158
2176
  return item.name === value.replace("#", "");
2159
2177
  });
2160
2178
  if (!requestParam)
2161
2179
  throw new RsError("SCHEMA_ERROR", `Invalid route keyword in route ${routeData.name}`);
2162
- return ((_a = data[requestParam.name]) == null ? void 0 : _a.toString()) || "";
2180
+ return ((_a2 = data[requestParam.name]) == null ? void 0 : _a2.toString()) || "";
2163
2181
  });
2164
2182
  statement = filterPsqlParser_default.parse(statement);
2165
2183
  if (whereClause.startsWith("WHERE")) {
@@ -2281,13 +2299,13 @@ var CompareSchema = class {
2281
2299
  const originalClone = (0, import_lodash.default)(originalEndpoints);
2282
2300
  const diffObj = [];
2283
2301
  newEndPoints.forEach((endPoint) => {
2284
- const { path: path4, method } = endPoint;
2302
+ const { path: path5, method } = endPoint;
2285
2303
  const endPointIndex = originalClone.findIndex((original) => {
2286
2304
  return original.path === endPoint.path && original.method === endPoint.method;
2287
2305
  });
2288
2306
  if (endPointIndex === -1) {
2289
2307
  diffObj.push({
2290
- name: `${method} ${path4}`,
2308
+ name: `${method} ${path5}`,
2291
2309
  changeType: "NEW"
2292
2310
  });
2293
2311
  } else {
@@ -2296,7 +2314,7 @@ var CompareSchema = class {
2296
2314
  });
2297
2315
  if (original === -1) {
2298
2316
  diffObj.push({
2299
- name: `${method} ${path4}`,
2317
+ name: `${method} ${path5}`,
2300
2318
  changeType: "MODIFIED"
2301
2319
  });
2302
2320
  }
@@ -2304,9 +2322,9 @@ var CompareSchema = class {
2304
2322
  }
2305
2323
  });
2306
2324
  originalClone.forEach((original) => {
2307
- const { path: path4, method } = original;
2325
+ const { path: path5, method } = original;
2308
2326
  diffObj.push({
2309
- name: `${method} ${path4}`,
2327
+ name: `${method} ${path5}`,
2310
2328
  changeType: "DELETED"
2311
2329
  });
2312
2330
  });
@@ -2331,6 +2349,63 @@ __decorateClass([
2331
2349
  var compareSchema = new CompareSchema();
2332
2350
  var compareSchema_default = compareSchema;
2333
2351
 
2352
+ // src/restura/middleware/getMulterUploadSingleton.ts
2353
+ var import_multer = __toESM(require("multer"));
2354
+ var import_path3 = require("path");
2355
+ var os = __toESM(require("os"));
2356
+ var OneHundredMB = 100 * 1024 * 1024;
2357
+ var commonUpload = null;
2358
+ var getMulterUploadSingleton = (directory) => {
2359
+ if (commonUpload) return commonUpload;
2360
+ const storage = import_multer.default.diskStorage({
2361
+ destination: directory || os.tmpdir(),
2362
+ filename: function(request, file, cb) {
2363
+ const extension = (0, import_path3.extname)(file.originalname);
2364
+ const uniqueName = Date.now() + "-" + Math.round(Math.random() * 1e3);
2365
+ cb(null, `${uniqueName}${extension}`);
2366
+ }
2367
+ });
2368
+ commonUpload = (0, import_multer.default)({
2369
+ storage,
2370
+ limits: {
2371
+ fileSize: OneHundredMB
2372
+ }
2373
+ });
2374
+ return commonUpload;
2375
+ };
2376
+
2377
+ // src/restura/utils/TempCache.ts
2378
+ var import_fs3 = __toESM(require("fs"));
2379
+ var import_path4 = __toESM(require("path"));
2380
+ var import_core_utils6 = require("@redskytech/core-utils");
2381
+ var import_bluebird3 = __toESM(require("bluebird"));
2382
+ var os2 = __toESM(require("os"));
2383
+ var import_internal3 = require("@restura/internal");
2384
+ var TempCache = class {
2385
+ constructor(location) {
2386
+ this.maxDurationDays = 7;
2387
+ this.location = location || os2.tmpdir();
2388
+ import_internal3.fileUtils.ensureDir(this.location).catch((e) => {
2389
+ throw e;
2390
+ });
2391
+ }
2392
+ async cleanup() {
2393
+ const fileList = await import_fs3.default.promises.readdir(this.location);
2394
+ await import_bluebird3.default.map(
2395
+ fileList,
2396
+ async (file) => {
2397
+ const fullFilePath = import_path4.default.join(this.location, file);
2398
+ const fileStats = await import_fs3.default.promises.stat(fullFilePath);
2399
+ if (import_core_utils6.DateUtils.daysBetweenStartAndEndDates(new Date(fileStats.mtimeMs), /* @__PURE__ */ new Date()) > this.maxDurationDays) {
2400
+ logger.info(`Deleting old temp file: ${file}`);
2401
+ await import_fs3.default.promises.unlink(fullFilePath);
2402
+ }
2403
+ },
2404
+ { concurrency: 10 }
2405
+ );
2406
+ }
2407
+ };
2408
+
2334
2409
  // src/restura/restura.ts
2335
2410
  var { types } = import_pg3.default;
2336
2411
  var ResturaEngine = class {
@@ -2350,7 +2425,9 @@ var ResturaEngine = class {
2350
2425
  * @returns A promise that resolves when the initialization is complete.
2351
2426
  */
2352
2427
  async init(app, authenticationHandler, psqlConnectionPool) {
2353
- this.resturaConfig = import_internal2.config.validate("restura", resturaConfigSchema);
2428
+ this.resturaConfig = import_internal4.config.validate("restura", resturaConfigSchema);
2429
+ this.multerCommonUpload = getMulterUploadSingleton(this.resturaConfig.fileTempCachePath);
2430
+ new TempCache(this.resturaConfig.fileTempCachePath);
2354
2431
  this.psqlConnectionPool = psqlConnectionPool;
2355
2432
  this.psqlEngine = new PsqlEngine(this.psqlConnectionPool, true);
2356
2433
  setupPgReturnTypes();
@@ -2417,7 +2494,7 @@ var ResturaEngine = class {
2417
2494
  * @returns A promise that resolves when the API has been successfully generated and written to the output file.
2418
2495
  */
2419
2496
  async generateApiFromSchema(outputFile, providedSchema) {
2420
- import_fs3.default.writeFileSync(
2497
+ import_fs4.default.writeFileSync(
2421
2498
  outputFile,
2422
2499
  await apiGenerator(providedSchema, await this.generateHashForSchema(providedSchema))
2423
2500
  );
@@ -2430,7 +2507,7 @@ var ResturaEngine = class {
2430
2507
  * @returns A promise that resolves when the model has been successfully written to the output file.
2431
2508
  */
2432
2509
  async generateModelFromSchema(outputFile, providedSchema) {
2433
- import_fs3.default.writeFileSync(
2510
+ import_fs4.default.writeFileSync(
2434
2511
  outputFile,
2435
2512
  await modelGenerator(providedSchema, await this.generateHashForSchema(providedSchema))
2436
2513
  );
@@ -2442,12 +2519,12 @@ var ResturaEngine = class {
2442
2519
  * @throws {Error} If the schema file is missing or the schema is not valid.
2443
2520
  */
2444
2521
  async getLatestFileSystemSchema() {
2445
- if (!import_fs3.default.existsSync(this.resturaConfig.schemaFilePath)) {
2522
+ if (!import_fs4.default.existsSync(this.resturaConfig.schemaFilePath)) {
2446
2523
  logger.error(`Missing restura schema file, expected path: ${this.resturaConfig.schemaFilePath}`);
2447
2524
  throw new Error("Missing restura schema file");
2448
2525
  }
2449
- const schemaFileData = import_fs3.default.readFileSync(this.resturaConfig.schemaFilePath, { encoding: "utf8" });
2450
- const schema = import_core_utils6.ObjectUtils.safeParse(schemaFileData);
2526
+ const schemaFileData = import_fs4.default.readFileSync(this.resturaConfig.schemaFilePath, { encoding: "utf8" });
2527
+ const schema = import_core_utils7.ObjectUtils.safeParse(schemaFileData);
2451
2528
  const isValid = await isSchemaValid(schema);
2452
2529
  if (!isValid) {
2453
2530
  logger.error("Schema is not valid");
@@ -2465,11 +2542,11 @@ var ResturaEngine = class {
2465
2542
  * - `modelCreatedSchemaHash`: The hash extracted from the generated `models.d.ts` file.
2466
2543
  */
2467
2544
  async getHashes(providedSchema) {
2468
- var _a, _b, _c, _d;
2545
+ var _a2, _b, _c, _d;
2469
2546
  const schemaHash = await this.generateHashForSchema(providedSchema);
2470
- const apiFile = import_fs3.default.readFileSync(import_path3.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"));
2471
- const apiCreatedSchemaHash = (_b = (_a = apiFile.toString().match(/\((.*)\)/)) == null ? void 0 : _a[1]) != null ? _b : "";
2472
- const modelFile = import_fs3.default.readFileSync(import_path3.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"));
2547
+ const apiFile = import_fs4.default.readFileSync(import_path5.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"));
2548
+ const apiCreatedSchemaHash = (_b = (_a2 = apiFile.toString().match(/\((.*)\)/)) == null ? void 0 : _a2[1]) != null ? _b : "";
2549
+ const modelFile = import_fs4.default.readFileSync(import_path5.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"));
2473
2550
  const modelCreatedSchemaHash = (_d = (_c = modelFile.toString().match(/\((.*)\)/)) == null ? void 0 : _c[1]) != null ? _d : "";
2474
2551
  return {
2475
2552
  schemaHash,
@@ -2505,27 +2582,27 @@ var ResturaEngine = class {
2505
2582
  logger.info(`Restura loaded (${routeCount}) endpoint${routeCount > 1 ? "s" : ""}`);
2506
2583
  }
2507
2584
  async validateGeneratedTypesFolder() {
2508
- if (!import_fs3.default.existsSync(this.resturaConfig.generatedTypesPath)) {
2509
- import_fs3.default.mkdirSync(this.resturaConfig.generatedTypesPath, { recursive: true });
2585
+ if (!import_fs4.default.existsSync(this.resturaConfig.generatedTypesPath)) {
2586
+ import_fs4.default.mkdirSync(this.resturaConfig.generatedTypesPath, { recursive: true });
2510
2587
  }
2511
- const hasApiFile = import_fs3.default.existsSync(import_path3.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"));
2512
- const hasModelsFile = import_fs3.default.existsSync(import_path3.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"));
2588
+ const hasApiFile = import_fs4.default.existsSync(import_path5.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"));
2589
+ const hasModelsFile = import_fs4.default.existsSync(import_path5.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"));
2513
2590
  if (!hasApiFile) {
2514
- await this.generateApiFromSchema(import_path3.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
2591
+ await this.generateApiFromSchema(import_path5.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
2515
2592
  }
2516
2593
  if (!hasModelsFile) {
2517
2594
  await this.generateModelFromSchema(
2518
- import_path3.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
2595
+ import_path5.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
2519
2596
  this.schema
2520
2597
  );
2521
2598
  }
2522
2599
  const hashes = await this.getHashes(this.schema);
2523
2600
  if (hashes.schemaHash !== hashes.apiCreatedSchemaHash) {
2524
- await this.generateApiFromSchema(import_path3.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
2601
+ await this.generateApiFromSchema(import_path5.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
2525
2602
  }
2526
2603
  if (hashes.schemaHash !== hashes.modelCreatedSchemaHash) {
2527
2604
  await this.generateModelFromSchema(
2528
- import_path3.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
2605
+ import_path5.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
2529
2606
  this.schema
2530
2607
  );
2531
2608
  }
@@ -2555,9 +2632,9 @@ var ResturaEngine = class {
2555
2632
  }
2556
2633
  }
2557
2634
  async updateTypes() {
2558
- await this.generateApiFromSchema(import_path3.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
2635
+ await this.generateApiFromSchema(import_path5.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
2559
2636
  await this.generateModelFromSchema(
2560
- import_path3.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
2637
+ import_path5.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
2561
2638
  this.schema
2562
2639
  );
2563
2640
  }
@@ -2575,10 +2652,30 @@ var ResturaEngine = class {
2575
2652
  res.status(400).send({ error: err });
2576
2653
  }
2577
2654
  }
2655
+ async getMulterFilesIfAny(req, res, routeData) {
2656
+ var _a2;
2657
+ if (!((_a2 = req.header("content-type")) == null ? void 0 : _a2.includes("multipart/form-data"))) return;
2658
+ if (!this.isCustomRoute(routeData)) return;
2659
+ if (!routeData.fileUploadType) {
2660
+ throw new RsError("BAD_REQUEST", "File upload type not defined for route");
2661
+ }
2662
+ const multerFileUploadFunction = routeData.fileUploadType === "MULTIPLE" ? this.multerCommonUpload.array("files") : this.multerCommonUpload.single("file");
2663
+ return new Promise((resolve2, reject) => {
2664
+ multerFileUploadFunction(req, res, (err) => {
2665
+ if (err) {
2666
+ logger.warn("Multer error: " + err);
2667
+ reject(err);
2668
+ }
2669
+ if (req.body["data"]) req.body = JSON.parse(req.body["data"]);
2670
+ resolve2();
2671
+ });
2672
+ });
2673
+ }
2578
2674
  async executeRouteLogic(req, res, next) {
2579
2675
  try {
2580
2676
  const routeData = this.getRouteData(req.method, req.baseUrl, req.path);
2581
2677
  this.validateAuthorization(req, routeData);
2678
+ await this.getMulterFilesIfAny(req, res, routeData);
2582
2679
  validateRequestParams(req, routeData, this.customTypeValidation);
2583
2680
  if (this.isCustomRoute(routeData)) {
2584
2681
  await this.runCustomRouteLogic(req, res, routeData);
@@ -2604,18 +2701,19 @@ var ResturaEngine = class {
2604
2701
  let domain = routeData.path.split("/")[1];
2605
2702
  domain = domain.split("-").reduce((acc, value, index) => {
2606
2703
  if (index === 0) acc = value;
2607
- else acc += import_core_utils6.StringUtils.capitalizeFirst(value);
2704
+ else acc += import_core_utils7.StringUtils.capitalizeFirst(value);
2608
2705
  return acc;
2609
2706
  }, "");
2610
- const customApiName = `${import_core_utils6.StringUtils.capitalizeFirst(domain)}Api${import_core_utils6.StringUtils.capitalizeFirst(version)}`;
2707
+ const customApiName = `${import_core_utils7.StringUtils.capitalizeFirst(domain)}Api${import_core_utils7.StringUtils.capitalizeFirst(version)}`;
2611
2708
  const customApi = customApiFactory_default.getCustomApi(customApiName);
2612
2709
  if (!customApi) throw new RsError("NOT_FOUND", `API domain ${domain}-${version} not found`);
2613
2710
  const functionName = `${routeData.method.toLowerCase()}${routeData.path.replace(new RegExp("-", "g"), "/").split("/").reduce((acc, cur) => {
2614
2711
  if (cur === "") return acc;
2615
- return acc + import_core_utils6.StringUtils.capitalizeFirst(cur);
2712
+ return acc + import_core_utils7.StringUtils.capitalizeFirst(cur);
2616
2713
  }, "")}`;
2617
2714
  const customFunction = customApi[functionName];
2618
- if (!customFunction) throw new RsError("NOT_FOUND", `API path ${routeData.path} not implemented`);
2715
+ if (!customFunction)
2716
+ throw new RsError("NOT_FOUND", `API path ${routeData.path} not implemented ${functionName}`);
2619
2717
  await customFunction(req, res, routeData);
2620
2718
  }
2621
2719
  async generateHashForSchema(providedSchema) {
@@ -2642,7 +2740,7 @@ var ResturaEngine = class {
2642
2740
  printWidth: 120,
2643
2741
  singleQuote: true
2644
2742
  }));
2645
- import_fs3.default.writeFileSync(this.resturaConfig.schemaFilePath, schemaPrettyStr);
2743
+ import_fs4.default.writeFileSync(this.resturaConfig.schemaFilePath, schemaPrettyStr);
2646
2744
  }
2647
2745
  resetPublicEndpoints() {
2648
2746
  this.publicEndpoints = {
@@ -2659,13 +2757,13 @@ var ResturaEngine = class {
2659
2757
  if (!routeData.roles.includes(role))
2660
2758
  throw new RsError("UNAUTHORIZED", "Not authorized to access this endpoint");
2661
2759
  }
2662
- getRouteData(method, baseUrl, path4) {
2760
+ getRouteData(method, baseUrl, path5) {
2663
2761
  const endpoint = this.schema.endpoints.find((item) => {
2664
2762
  return item.baseUrl === baseUrl;
2665
2763
  });
2666
2764
  if (!endpoint) throw new RsError("NOT_FOUND", "Route not found");
2667
2765
  const route = endpoint.routes.find((item) => {
2668
- return item.method === method && item.path === path4;
2766
+ return item.method === method && item.path === path5;
2669
2767
  });
2670
2768
  if (!route) throw new RsError("NOT_FOUND", "Route not found");
2671
2769
  return route;
@@ -2686,6 +2784,9 @@ __decorateClass([
2686
2784
  __decorateClass([
2687
2785
  boundMethod
2688
2786
  ], ResturaEngine.prototype, "getSchemaAndTypes", 1);
2787
+ __decorateClass([
2788
+ boundMethod
2789
+ ], ResturaEngine.prototype, "getMulterFilesIfAny", 1);
2689
2790
  __decorateClass([
2690
2791
  boundMethod
2691
2792
  ], ResturaEngine.prototype, "executeRouteLogic", 1);