@restura/core 0.1.0-alpha.24 → 0.1.0-alpha.25

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.mjs CHANGED
@@ -44,23 +44,11 @@ import { config } from "@restura/internal";
44
44
  import winston from "winston";
45
45
  import { format } from "logform";
46
46
 
47
- // src/config.schema.ts
47
+ // src/logger/loggerConfigSchema.ts
48
48
  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";
56
- var resturaConfigSchema = z.object({
57
- authToken: z.string().min(1, "Missing Restura Auth Token"),
58
- sendErrorStackTrace: z.boolean().default(false),
59
- schemaFilePath: z.string().default(process.cwd() + "/restura.schema.json"),
60
- customApiFolderPath: z.string().default(process.cwd() + customApiFolderPath),
61
- generatedTypesPath: z.string().default(process.cwd() + "/src/@types"),
62
- fileTempCachePath: z.string().optional()
63
- });
64
52
 
65
53
  // src/logger/logger.ts
66
54
  var loggerConfig = config.validate("logger", loggerConfigSchema);
@@ -97,7 +85,194 @@ var logger = winston.createLogger({
97
85
  ]
98
86
  });
99
87
 
100
- // src/restura/errors.ts
88
+ // src/restura/eventManager.ts
89
+ import Bluebird from "bluebird";
90
+ var EventManager = class {
91
+ constructor() {
92
+ this.actionHandlers = {
93
+ DATABASE_ROW_DELETE: [],
94
+ DATABASE_ROW_INSERT: [],
95
+ DATABASE_COLUMN_UPDATE: []
96
+ };
97
+ }
98
+ addRowInsertHandler(onInsert, filter) {
99
+ this.actionHandlers.DATABASE_ROW_INSERT.push({
100
+ callback: onInsert,
101
+ filter
102
+ });
103
+ }
104
+ addColumnChangeHandler(onUpdate, filter) {
105
+ this.actionHandlers.DATABASE_COLUMN_UPDATE.push({
106
+ callback: onUpdate,
107
+ filter
108
+ });
109
+ }
110
+ addRowDeleteHandler(onDelete, filter) {
111
+ this.actionHandlers.DATABASE_ROW_DELETE.push({
112
+ callback: onDelete,
113
+ filter
114
+ });
115
+ }
116
+ async fireActionFromDbTrigger(sqlMutationData, result) {
117
+ if (sqlMutationData.mutationType === "INSERT") {
118
+ await this.fireInsertActions(sqlMutationData, result);
119
+ } else if (sqlMutationData.mutationType === "UPDATE") {
120
+ await this.fireUpdateActions(sqlMutationData, result);
121
+ } else if (sqlMutationData.mutationType === "DELETE") {
122
+ await this.fireDeleteActions(sqlMutationData, result);
123
+ }
124
+ }
125
+ async fireInsertActions(data, triggerResult) {
126
+ await Bluebird.map(
127
+ this.actionHandlers.DATABASE_ROW_INSERT,
128
+ ({ callback, filter }) => {
129
+ if (!this.hasHandlersForEventType("DATABASE_ROW_INSERT", filter, triggerResult)) return;
130
+ const insertData = {
131
+ tableName: triggerResult.table,
132
+ insertId: triggerResult.record.id,
133
+ insertObject: triggerResult.record,
134
+ queryMetadata: data.queryMetadata
135
+ };
136
+ callback(insertData, data.queryMetadata);
137
+ },
138
+ { concurrency: 10 }
139
+ );
140
+ }
141
+ async fireDeleteActions(data, triggerResult) {
142
+ await Bluebird.map(
143
+ this.actionHandlers.DATABASE_ROW_DELETE,
144
+ ({ callback, filter }) => {
145
+ if (!this.hasHandlersForEventType("DATABASE_ROW_DELETE", filter, triggerResult)) return;
146
+ const deleteData = {
147
+ tableName: triggerResult.table,
148
+ deletedRow: triggerResult.previousRecord,
149
+ queryMetadata: data.queryMetadata
150
+ };
151
+ callback(deleteData, data.queryMetadata);
152
+ },
153
+ { concurrency: 10 }
154
+ );
155
+ }
156
+ async fireUpdateActions(data, triggerResult) {
157
+ await Bluebird.map(
158
+ this.actionHandlers.DATABASE_COLUMN_UPDATE,
159
+ ({ callback, filter }) => {
160
+ if (!this.hasHandlersForEventType("DATABASE_COLUMN_UPDATE", filter, triggerResult)) return;
161
+ const columnChangeData = {
162
+ tableName: triggerResult.table,
163
+ rowId: triggerResult.record.id,
164
+ newData: triggerResult.record,
165
+ oldData: triggerResult.previousRecord,
166
+ queryMetadata: data.queryMetadata
167
+ };
168
+ callback(columnChangeData, data.queryMetadata);
169
+ },
170
+ { concurrency: 10 }
171
+ );
172
+ }
173
+ hasHandlersForEventType(eventType, filter, triggerResult) {
174
+ if (filter) {
175
+ switch (eventType) {
176
+ case "DATABASE_ROW_INSERT":
177
+ case "DATABASE_ROW_DELETE":
178
+ if (filter.tableName && filter.tableName !== triggerResult.table) return false;
179
+ break;
180
+ case "DATABASE_COLUMN_UPDATE":
181
+ const filterColumnChange = filter;
182
+ if (filterColumnChange.tableName !== filter.tableName) return false;
183
+ if (!filterColumnChange.columns.some((item) => {
184
+ const updatedColumns = Object.keys(
185
+ changedValues(triggerResult.record, triggerResult.previousRecord)
186
+ );
187
+ return updatedColumns.includes(item);
188
+ }))
189
+ return false;
190
+ break;
191
+ }
192
+ }
193
+ return true;
194
+ }
195
+ };
196
+ var eventManager = new EventManager();
197
+ var eventManager_default = eventManager;
198
+ function changedValues(record, previousRecord) {
199
+ const changed = {};
200
+ for (const i in previousRecord) {
201
+ if (previousRecord[i] !== record[i]) {
202
+ if (typeof previousRecord[i] === "object" && typeof record[i] === "object") {
203
+ const nestedChanged = changedValues(record[i], previousRecord[i]);
204
+ if (Object.keys(nestedChanged).length > 0) {
205
+ changed[i] = record[i];
206
+ }
207
+ } else {
208
+ changed[i] = record[i];
209
+ }
210
+ }
211
+ }
212
+ return changed;
213
+ }
214
+
215
+ // src/restura/restura.ts
216
+ import { ObjectUtils as ObjectUtils5, StringUtils as StringUtils3 } from "@redskytech/core-utils";
217
+ import { config as config2 } from "@restura/internal";
218
+
219
+ // ../../node_modules/.pnpm/autobind-decorator@2.4.0/node_modules/autobind-decorator/lib/esm/index.js
220
+ function _typeof(obj) {
221
+ if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
222
+ _typeof = function _typeof2(obj2) {
223
+ return typeof obj2;
224
+ };
225
+ } else {
226
+ _typeof = function _typeof2(obj2) {
227
+ return obj2 && typeof Symbol === "function" && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2;
228
+ };
229
+ }
230
+ return _typeof(obj);
231
+ }
232
+ function boundMethod(target, key, descriptor) {
233
+ var fn = descriptor.value;
234
+ if (typeof fn !== "function") {
235
+ throw new TypeError("@boundMethod decorator can only be applied to methods not: ".concat(_typeof(fn)));
236
+ }
237
+ var definingProperty = false;
238
+ return {
239
+ configurable: true,
240
+ get: function get() {
241
+ if (definingProperty || this === target.prototype || this.hasOwnProperty(key) || typeof fn !== "function") {
242
+ return fn;
243
+ }
244
+ var boundFn = fn.bind(this);
245
+ definingProperty = true;
246
+ Object.defineProperty(this, key, {
247
+ configurable: true,
248
+ get: function get2() {
249
+ return boundFn;
250
+ },
251
+ set: function set(value) {
252
+ fn = value;
253
+ delete this[key];
254
+ }
255
+ });
256
+ definingProperty = false;
257
+ return boundFn;
258
+ },
259
+ set: function set(value) {
260
+ fn = value;
261
+ }
262
+ };
263
+ }
264
+
265
+ // src/restura/restura.ts
266
+ import bodyParser from "body-parser";
267
+ import compression from "compression";
268
+ import cookieParser from "cookie-parser";
269
+ import * as express from "express";
270
+ import fs4 from "fs";
271
+ import path4 from "path";
272
+ import pg3 from "pg";
273
+ import * as prettier3 from "prettier";
274
+
275
+ // src/restura/RsError.ts
101
276
  var HtmlStatusCodes = /* @__PURE__ */ ((HtmlStatusCodes2) => {
102
277
  HtmlStatusCodes2[HtmlStatusCodes2["BAD_REQUEST"] = 400] = "BAD_REQUEST";
103
278
  HtmlStatusCodes2[HtmlStatusCodes2["UNAUTHORIZED"] = 401] = "UNAUTHORIZED";
@@ -121,7 +296,6 @@ var RsError = class _RsError {
121
296
  static htmlStatus(code) {
122
297
  return htmlStatusMap[code];
123
298
  }
124
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
125
299
  static isRsError(error) {
126
300
  return error instanceof _RsError;
127
301
  }
@@ -163,66 +337,158 @@ var htmlStatusMap = {
163
337
  SCHEMA_ERROR: 500 /* SERVER_ERROR */
164
338
  };
165
339
 
166
- // src/restura/restura.ts
167
- import { ObjectUtils as ObjectUtils5, StringUtils as StringUtils3 } from "@redskytech/core-utils";
168
- import { config as config2 } from "@restura/internal";
169
-
170
- // ../../node_modules/.pnpm/autobind-decorator@2.4.0/node_modules/autobind-decorator/lib/esm/index.js
171
- function _typeof(obj) {
172
- if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
173
- _typeof = function _typeof2(obj2) {
174
- return typeof obj2;
175
- };
176
- } else {
177
- _typeof = function _typeof2(obj2) {
178
- return obj2 && typeof Symbol === "function" && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2;
179
- };
180
- }
181
- return _typeof(obj);
182
- }
183
- function boundMethod(target, key, descriptor) {
184
- var fn = descriptor.value;
185
- if (typeof fn !== "function") {
186
- throw new TypeError("@boundMethod decorator can only be applied to methods not: ".concat(_typeof(fn)));
340
+ // src/restura/compareSchema.ts
341
+ import cloneDeep from "lodash.clonedeep";
342
+ var CompareSchema = class {
343
+ async diffSchema(newSchema, latestSchema, psqlEngine) {
344
+ const endPoints = this.diffEndPoints(newSchema.endpoints[0].routes, latestSchema.endpoints[0].routes);
345
+ const globalParams = this.diffStringArray(newSchema.globalParams, latestSchema.globalParams);
346
+ const roles = this.diffStringArray(newSchema.roles, latestSchema.roles);
347
+ let commands = "";
348
+ if (JSON.stringify(newSchema.database) !== JSON.stringify(latestSchema.database))
349
+ commands = await psqlEngine.diffDatabaseToSchema(newSchema);
350
+ const customTypes = newSchema.customTypes !== latestSchema.customTypes;
351
+ const schemaPreview = { endPoints, globalParams, roles, commands, customTypes };
352
+ return schemaPreview;
187
353
  }
188
- var definingProperty = false;
189
- return {
190
- configurable: true,
191
- get: function get() {
192
- if (definingProperty || this === target.prototype || this.hasOwnProperty(key) || typeof fn !== "function") {
193
- return fn;
354
+ diffStringArray(newArray, originalArray) {
355
+ const stringsDiff = [];
356
+ const originalClone = new Set(originalArray);
357
+ newArray.forEach((item) => {
358
+ const originalIndex = originalClone.has(item);
359
+ if (!originalIndex) {
360
+ stringsDiff.push({
361
+ name: item,
362
+ changeType: "NEW"
363
+ });
364
+ } else {
365
+ originalClone.delete(item);
194
366
  }
195
- var boundFn = fn.bind(this);
196
- definingProperty = true;
197
- Object.defineProperty(this, key, {
198
- configurable: true,
199
- get: function get2() {
200
- return boundFn;
201
- },
202
- set: function set(value) {
203
- fn = value;
204
- delete this[key];
367
+ });
368
+ originalClone.forEach((item) => {
369
+ stringsDiff.push({
370
+ name: item,
371
+ changeType: "DELETED"
372
+ });
373
+ });
374
+ return stringsDiff;
375
+ }
376
+ diffEndPoints(newEndPoints, originalEndpoints) {
377
+ const originalClone = cloneDeep(originalEndpoints);
378
+ const diffObj = [];
379
+ newEndPoints.forEach((endPoint) => {
380
+ const { path: path5, method } = endPoint;
381
+ const endPointIndex = originalClone.findIndex((original) => {
382
+ return original.path === endPoint.path && original.method === endPoint.method;
383
+ });
384
+ if (endPointIndex === -1) {
385
+ diffObj.push({
386
+ name: `${method} ${path5}`,
387
+ changeType: "NEW"
388
+ });
389
+ } else {
390
+ const original = originalClone.findIndex((original2) => {
391
+ return this.compareEndPoints(endPoint, original2);
392
+ });
393
+ if (original === -1) {
394
+ diffObj.push({
395
+ name: `${method} ${path5}`,
396
+ changeType: "MODIFIED"
397
+ });
205
398
  }
399
+ originalClone.splice(endPointIndex, 1);
400
+ }
401
+ });
402
+ originalClone.forEach((original) => {
403
+ const { path: path5, method } = original;
404
+ diffObj.push({
405
+ name: `${method} ${path5}`,
406
+ changeType: "DELETED"
206
407
  });
207
- definingProperty = false;
208
- return boundFn;
209
- },
210
- set: function set(value) {
211
- fn = value;
408
+ });
409
+ return diffObj;
410
+ }
411
+ compareEndPoints(endPoint1, endPoint2) {
412
+ return JSON.stringify(endPoint1) === JSON.stringify(endPoint2);
413
+ }
414
+ };
415
+ __decorateClass([
416
+ boundMethod
417
+ ], CompareSchema.prototype, "diffSchema", 1);
418
+ __decorateClass([
419
+ boundMethod
420
+ ], CompareSchema.prototype, "diffStringArray", 1);
421
+ __decorateClass([
422
+ boundMethod
423
+ ], CompareSchema.prototype, "diffEndPoints", 1);
424
+ __decorateClass([
425
+ boundMethod
426
+ ], CompareSchema.prototype, "compareEndPoints", 1);
427
+ var compareSchema = new CompareSchema();
428
+ var compareSchema_default = compareSchema;
429
+
430
+ // src/restura/customApiFactory.ts
431
+ import { fileUtils } from "@restura/internal";
432
+ import Bluebird2 from "bluebird";
433
+ import fs from "fs";
434
+ import path from "path";
435
+ var CustomApiFactory = class {
436
+ constructor() {
437
+ this.customApis = {};
438
+ }
439
+ async loadApiFiles(baseFolderPath) {
440
+ const apiVersions = ["v1"];
441
+ for (const apiVersion of apiVersions) {
442
+ const apiVersionFolderPath = path.join(baseFolderPath, apiVersion);
443
+ const directoryExists = await fileUtils.existDir(apiVersionFolderPath);
444
+ if (!directoryExists) continue;
445
+ await this.addDirectory(apiVersionFolderPath, apiVersion);
212
446
  }
213
- };
214
- }
447
+ }
448
+ getCustomApi(customApiName) {
449
+ return this.customApis[customApiName];
450
+ }
451
+ async addDirectory(directoryPath, apiVersion) {
452
+ var _a2;
453
+ const entries = await fs.promises.readdir(directoryPath, {
454
+ withFileTypes: true
455
+ });
456
+ const isTsx2 = (_a2 = process.argv[1]) == null ? void 0 : _a2.endsWith(".ts");
457
+ const isTsNode2 = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
458
+ const extension = isTsx2 || isTsNode2 ? "ts" : "js";
459
+ const shouldEndWith = `.api.${apiVersion}.${extension}`;
460
+ await Bluebird2.map(entries, async (entry) => {
461
+ if (entry.isFile()) {
462
+ if (entry.name.endsWith(shouldEndWith) === false) return;
463
+ try {
464
+ const importPath = `${path.join(directoryPath, entry.name)}`;
465
+ const ApiImport = await import(importPath);
466
+ const customApiClass = new ApiImport.default();
467
+ logger.info(`Registering custom API: ${ApiImport.default.name}`);
468
+ this.bindMethodsToInstance(customApiClass);
469
+ this.customApis[ApiImport.default.name] = customApiClass;
470
+ } catch (e) {
471
+ console.error(e);
472
+ }
473
+ }
474
+ });
475
+ }
476
+ bindMethodsToInstance(instance) {
477
+ const proto = Object.getPrototypeOf(instance);
478
+ Object.getOwnPropertyNames(proto).forEach((key) => {
479
+ const property = instance[key];
480
+ if (typeof property === "function" && key !== "constructor") {
481
+ instance[key] = property.bind(instance);
482
+ }
483
+ });
484
+ }
485
+ };
486
+ var customApiFactory = new CustomApiFactory();
487
+ var customApiFactory_default = customApiFactory;
215
488
 
216
- // src/restura/restura.ts
217
- import bodyParser from "body-parser";
218
- import compression from "compression";
219
- import cookieParser from "cookie-parser";
220
- import { createHash } from "crypto";
221
- import * as express from "express";
222
- import fs4 from "fs";
223
- import path4 from "path";
224
- import pg3 from "pg";
225
- import * as prettier3 from "prettier";
489
+ // src/restura/generators/apiGenerator.ts
490
+ import { ObjectUtils, StringUtils } from "@redskytech/core-utils";
491
+ import prettier from "prettier";
226
492
 
227
493
  // src/restura/sql/SqlUtils.ts
228
494
  var SqlUtils = class _SqlUtils {
@@ -250,7 +516,7 @@ var SqlUtils = class _SqlUtils {
250
516
  }
251
517
  };
252
518
 
253
- // src/restura/ResponseValidator.ts
519
+ // src/restura/validators/ResponseValidator.ts
254
520
  var ResponseValidator = class _ResponseValidator {
255
521
  constructor(schema) {
256
522
  this.database = schema.database;
@@ -399,9 +665,7 @@ var ResponseValidator = class _ResponseValidator {
399
665
  }
400
666
  };
401
667
 
402
- // src/restura/apiGenerator.ts
403
- import { ObjectUtils, StringUtils } from "@redskytech/core-utils";
404
- import prettier from "prettier";
668
+ // src/restura/generators/apiGenerator.ts
405
669
  var ApiTree = class _ApiTree {
406
670
  constructor(namespace, database) {
407
671
  this.database = database;
@@ -554,102 +818,43 @@ var ApiTree = class _ApiTree {
554
818
  function pathToNamespaces(path5) {
555
819
  return path5.split("/").map((e) => StringUtils.toPascalCasing(e)).filter((e) => e);
556
820
  }
557
- function apiGenerator(schema, schemaHash) {
558
- let apiString = `/** Auto generated file from Schema Hash (${schemaHash}). DO NOT MODIFY **/`;
821
+ function apiGenerator(schema) {
822
+ let apiString = `/** Auto generated file. DO NOT MODIFY **/
823
+ `;
559
824
  const rootNamespace = ApiTree.createRootNode(schema.database);
560
825
  for (const endpoint of schema.endpoints) {
561
826
  const endpointNamespaces = pathToNamespaces(endpoint.baseUrl);
562
827
  rootNamespace.addData(endpointNamespaces, endpoint);
563
828
  for (const route of endpoint.routes) {
564
- const fullNamespace = [...endpointNamespaces, ...pathToNamespaces(route.path)];
565
- rootNamespace.addData(fullNamespace, route);
566
- }
567
- }
568
- apiString += rootNamespace.createApiModels();
569
- if (schema.customTypes.length > 0) {
570
- apiString += `
571
-
572
- declare namespace CustomTypes {
573
- ${schema.customTypes}
574
- }`;
575
- }
576
- return prettier.format(apiString, __spreadValues({
577
- parser: "typescript"
578
- }, {
579
- trailingComma: "none",
580
- tabWidth: 4,
581
- useTabs: true,
582
- endOfLine: "lf",
583
- printWidth: 120,
584
- singleQuote: true
585
- }));
586
- }
587
-
588
- // src/restura/customApiFactory.ts
589
- import fs from "fs";
590
- import path from "path";
591
- import Bluebird from "bluebird";
592
- import { fileUtils } from "@restura/internal";
593
- var CustomApiFactory = class {
594
- constructor() {
595
- this.customApis = {};
596
- }
597
- async loadApiFiles(baseFolderPath) {
598
- const apiVersions = ["v1"];
599
- for (const apiVersion of apiVersions) {
600
- const apiVersionFolderPath = path.join(baseFolderPath, apiVersion);
601
- const directoryExists = await fileUtils.existDir(apiVersionFolderPath);
602
- if (!directoryExists) continue;
603
- await this.addDirectory(apiVersionFolderPath, apiVersion);
604
- }
605
- }
606
- getCustomApi(customApiName) {
607
- return this.customApis[customApiName];
608
- }
609
- async addDirectory(directoryPath, apiVersion) {
610
- var _a2;
611
- const entries = await fs.promises.readdir(directoryPath, {
612
- withFileTypes: true
613
- });
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) => {
619
- if (entry.isFile()) {
620
- if (entry.name.endsWith(shouldEndWith) === false) return;
621
- try {
622
- const importPath = `${path.join(directoryPath, entry.name)}`;
623
- const ApiImport = await import(importPath);
624
- const customApiClass = new ApiImport.default();
625
- logger.info(`Registering custom API: ${ApiImport.default.name}`);
626
- this.bindMethodsToInstance(customApiClass);
627
- this.customApis[ApiImport.default.name] = customApiClass;
628
- } catch (e) {
629
- console.error(e);
630
- }
631
- }
632
- });
829
+ const fullNamespace = [...endpointNamespaces, ...pathToNamespaces(route.path)];
830
+ rootNamespace.addData(fullNamespace, route);
831
+ }
633
832
  }
634
- bindMethodsToInstance(instance) {
635
- const proto = Object.getPrototypeOf(instance);
636
- Object.getOwnPropertyNames(proto).forEach((key) => {
637
- const property = instance[key];
638
- if (typeof property === "function" && key !== "constructor") {
639
- instance[key] = property.bind(instance);
640
- }
641
- });
833
+ apiString += rootNamespace.createApiModels();
834
+ if (schema.customTypes.length > 0) {
835
+ apiString += `
836
+
837
+ declare namespace CustomTypes {
838
+ ${schema.customTypes}
839
+ }`;
642
840
  }
643
- };
644
- var customApiFactory = new CustomApiFactory();
645
- var customApiFactory_default = customApiFactory;
841
+ return prettier.format(apiString, __spreadValues({
842
+ parser: "typescript"
843
+ }, {
844
+ trailingComma: "none",
845
+ tabWidth: 4,
846
+ useTabs: true,
847
+ endOfLine: "lf",
848
+ printWidth: 120,
849
+ singleQuote: true
850
+ }));
851
+ }
646
852
 
647
- // src/restura/customTypeValidationGenerator.ts
853
+ // src/restura/generators/customTypeValidationGenerator.ts
648
854
  import fs2 from "fs";
649
- import * as TJS from "typescript-json-schema";
650
855
  import path2, { resolve } from "path";
651
856
  import tmp from "tmp";
652
- import * as process2 from "process";
857
+ import * as TJS from "typescript-json-schema";
653
858
  function customTypeValidationGenerator(currentSchema) {
654
859
  const schemaObject = {};
655
860
  const customInterfaceNames = currentSchema.customTypes.match(new RegExp("(?<=interface\\s)(\\w+)|(?<=type\\s)(\\w+)", "g"));
@@ -659,13 +864,14 @@ function customTypeValidationGenerator(currentSchema) {
659
864
  const compilerOptions = {
660
865
  strictNullChecks: true,
661
866
  skipLibCheck: true
867
+ // Needed if we are processing ES modules
662
868
  };
663
869
  const program = TJS.getProgramFromFiles(
664
870
  [
665
871
  resolve(temporaryFile.name),
666
- // find a way to remove
667
- path2.join(process2.cwd(), "src/@types/models.d.ts"),
668
- path2.join(process2.cwd(), "src/@types/api.d.ts")
872
+ path2.join(restura.resturaConfig.generatedTypesPath, "restura.d.ts"),
873
+ path2.join(restura.resturaConfig.generatedTypesPath, "models.d.ts"),
874
+ path2.join(restura.resturaConfig.generatedTypesPath, "api.d.ts")
669
875
  ],
670
876
  compilerOptions
671
877
  );
@@ -679,6 +885,61 @@ function customTypeValidationGenerator(currentSchema) {
679
885
  return schemaObject;
680
886
  }
681
887
 
888
+ // src/restura/generators/modelGenerator.ts
889
+ import { StringUtils as StringUtils2 } from "@redskytech/core-utils";
890
+ import prettier2 from "prettier";
891
+ function modelGenerator(schema) {
892
+ let modelString = `/** Auto generated file. DO NOT MODIFY **/
893
+
894
+ `;
895
+ modelString += `declare namespace Model {
896
+ `;
897
+ for (const table of schema.database) {
898
+ modelString += convertTable(table);
899
+ }
900
+ modelString += `}`;
901
+ return prettier2.format(modelString, __spreadValues({
902
+ parser: "typescript"
903
+ }, {
904
+ trailingComma: "none",
905
+ tabWidth: 4,
906
+ useTabs: true,
907
+ endOfLine: "lf",
908
+ printWidth: 120,
909
+ singleQuote: true
910
+ }));
911
+ }
912
+ function convertTable(table) {
913
+ let modelString = ` export interface ${StringUtils2.capitalizeFirst(table.name)} {
914
+ `;
915
+ for (const column of table.columns) {
916
+ modelString += ` ${column.name}${column.isNullable ? "?" : ""}: ${SqlUtils.convertDatabaseTypeToTypescript(column.type, column.value)};
917
+ `;
918
+ }
919
+ modelString += ` }
920
+ `;
921
+ return modelString;
922
+ }
923
+
924
+ // src/restura/generators/resturaGlobalTypesGenerator.ts
925
+ function resturaGlobalTypesGenerator() {
926
+ return `/** Auto generated file. DO NOT MODIFY **/
927
+ /** This file contains types that may be used in the CustomTypes of Restura **/
928
+ /** For example export interface MyPagedQuery extends Restura.PageQuery { } **/
929
+
930
+ declare namespace Restura {
931
+ export type StandardOrderTypes = 'ASC' | 'DESC' | 'RAND' | 'NONE';
932
+ export interface PageQuery {
933
+ page?: number;
934
+ perPage?: number;
935
+ sortBy?: string;
936
+ sortOrder?: StandardOrderTypes;
937
+ filter?: string;
938
+ }
939
+ }
940
+ `;
941
+ }
942
+
682
943
  // src/restura/middleware/addApiResponseFunctions.ts
683
944
  function addApiResponseFunctions(req, res, next) {
684
945
  res.sendData = function(data, statusCode = 200) {
@@ -717,10 +978,35 @@ function authenticateUser(applicationAuthenticateHandler) {
717
978
  };
718
979
  }
719
980
 
720
- // src/restura/restura.schema.ts
981
+ // src/restura/middleware/getMulterUpload.ts
982
+ import multer from "multer";
983
+ import * as os from "os";
984
+ import { extname } from "path";
985
+ var OneHundredMB = 100 * 1024 * 1024;
986
+ var commonUpload = null;
987
+ var getMulterUpload = (directory) => {
988
+ if (commonUpload) return commonUpload;
989
+ const storage = multer.diskStorage({
990
+ destination: directory || os.tmpdir(),
991
+ filename: function(request, file, cb) {
992
+ const extension = extname(file.originalname);
993
+ const uniqueName = Date.now() + "-" + Math.round(Math.random() * 1e3);
994
+ cb(null, `${uniqueName}${extension}`);
995
+ }
996
+ });
997
+ commonUpload = multer({
998
+ storage,
999
+ limits: {
1000
+ fileSize: OneHundredMB
1001
+ }
1002
+ });
1003
+ return commonUpload;
1004
+ };
1005
+
1006
+ // src/restura/schemas/resturaSchema.ts
721
1007
  import { z as z3 } from "zod";
722
1008
 
723
- // src/restura/types/validation.types.ts
1009
+ // src/restura/schemas/validatorDataSchema.ts
724
1010
  import { z as z2 } from "zod";
725
1011
  var validatorDataSchemeValue = z2.union([z2.string(), z2.array(z2.string()), z2.number(), z2.array(z2.number())]);
726
1012
  var validatorDataSchema = z2.object({
@@ -728,7 +1014,7 @@ var validatorDataSchema = z2.object({
728
1014
  value: validatorDataSchemeValue
729
1015
  }).strict();
730
1016
 
731
- // src/restura/restura.schema.ts
1017
+ // src/restura/schemas/resturaSchema.ts
732
1018
  var orderBySchema = z3.object({
733
1019
  columnName: z3.string(),
734
1020
  order: z3.enum(["ASC", "DESC"]),
@@ -975,7 +1261,7 @@ var endpointDataSchema = z3.object({
975
1261
  baseUrl: z3.string(),
976
1262
  routes: z3.array(z3.union([standardRouteSchema, customRouteSchema]))
977
1263
  }).strict();
978
- var resturaZodSchema = z3.object({
1264
+ var resturaSchema = z3.object({
979
1265
  database: z3.array(tableDataSchema),
980
1266
  endpoints: z3.array(endpointDataSchema),
981
1267
  globalParams: z3.array(z3.string()),
@@ -984,7 +1270,7 @@ var resturaZodSchema = z3.object({
984
1270
  }).strict();
985
1271
  async function isSchemaValid(schemaToCheck) {
986
1272
  try {
987
- resturaZodSchema.parse(schemaToCheck);
1273
+ resturaSchema.parse(schemaToCheck);
988
1274
  return true;
989
1275
  } catch (error) {
990
1276
  logger.error(error);
@@ -992,7 +1278,7 @@ async function isSchemaValid(schemaToCheck) {
992
1278
  }
993
1279
  }
994
1280
 
995
- // src/restura/validateRequestParams.ts
1281
+ // src/restura/validators/requestValidator.ts
996
1282
  import { ObjectUtils as ObjectUtils2 } from "@redskytech/core-utils";
997
1283
  import jsonschema from "jsonschema";
998
1284
  import { z as z4 } from "zod";
@@ -1009,8 +1295,8 @@ function addQuotesToStrings(variable) {
1009
1295
  }
1010
1296
  }
1011
1297
 
1012
- // src/restura/validateRequestParams.ts
1013
- function validateRequestParams(req, routeData, validationSchema) {
1298
+ // src/restura/validators/requestValidator.ts
1299
+ function requestValidator(req, routeData, validationSchema) {
1014
1300
  const requestData = getRequestData(req);
1015
1301
  req.data = requestData;
1016
1302
  if (routeData.request === void 0) {
@@ -1125,239 +1411,93 @@ function performMinCheck(requestValue, validator, requestParamName) {
1125
1411
  }
1126
1412
  function performMaxCheck(requestValue, validator, requestParamName) {
1127
1413
  expectOnlyNumbers(requestValue, validator, requestParamName);
1128
- if (requestValue > validator.value)
1129
- throw new RsError(
1130
- "BAD_REQUEST",
1131
- `Request param (${requestParamName}) with value (${requestValue}) is more than (${validator.value})`
1132
- );
1133
- }
1134
- function performOneOfCheck(requestValue, validator, requestParamName) {
1135
- if (!ObjectUtils2.isArrayWithData(validator.value))
1136
- throw new RsError("SCHEMA_ERROR", `Schema validator value (${validator.value}) is not of type array`);
1137
- if (typeof requestValue === "object")
1138
- throw new RsError("BAD_REQUEST", `Request param (${requestParamName}) is not of type string or number`);
1139
- if (!validator.value.includes(requestValue))
1140
- throw new RsError(
1141
- "BAD_REQUEST",
1142
- `Request param (${requestParamName}) with value (${requestValue}) is not one of (${validator.value.join(", ")})`
1143
- );
1144
- }
1145
- function isValueNumber(value) {
1146
- return !isNaN(Number(value));
1147
- }
1148
- function getRequestData(req) {
1149
- let body = "";
1150
- if (req.method === "GET" || req.method === "DELETE") {
1151
- body = "query";
1152
- } else {
1153
- body = "body";
1154
- }
1155
- const bodyData = req[body];
1156
- if (bodyData && body === "query") {
1157
- for (const attr in bodyData) {
1158
- if (bodyData[attr] instanceof Array) {
1159
- const attrList = [];
1160
- for (const value of bodyData[attr]) {
1161
- if (isNaN(Number(value))) continue;
1162
- attrList.push(Number(value));
1163
- }
1164
- if (ObjectUtils2.isArrayWithData(attrList)) {
1165
- bodyData[attr] = attrList;
1166
- }
1167
- } else {
1168
- bodyData[attr] = ObjectUtils2.safeParse(bodyData[attr]);
1169
- if (isNaN(Number(bodyData[attr]))) continue;
1170
- bodyData[attr] = Number(bodyData[attr]);
1171
- }
1172
- }
1173
- }
1174
- return bodyData;
1175
- }
1176
-
1177
- // src/restura/middleware/schemaValidation.ts
1178
- async function schemaValidation(req, res, next) {
1179
- req.data = getRequestData(req);
1180
- try {
1181
- resturaZodSchema.parse(req.data);
1182
- next();
1183
- } catch (error) {
1184
- logger.error(error);
1185
- res.sendError("BAD_REQUEST", error, 400 /* BAD_REQUEST */);
1186
- }
1187
- }
1188
-
1189
- // src/restura/modelGenerator.ts
1190
- import { StringUtils as StringUtils2 } from "@redskytech/core-utils";
1191
- import prettier2 from "prettier";
1192
- function modelGenerator(schema, schemaHash) {
1193
- let modelString = `/** Auto generated file from Schema Hash (${schemaHash}). DO NOT MODIFY **/
1194
- `;
1195
- modelString += `declare namespace Model {
1196
- `;
1197
- for (const table of schema.database) {
1198
- modelString += convertTable(table);
1199
- }
1200
- modelString += `}`;
1201
- return prettier2.format(modelString, __spreadValues({
1202
- parser: "typescript"
1203
- }, {
1204
- trailingComma: "none",
1205
- tabWidth: 4,
1206
- useTabs: true,
1207
- endOfLine: "lf",
1208
- printWidth: 120,
1209
- singleQuote: true
1210
- }));
1211
- }
1212
- function convertTable(table) {
1213
- let modelString = ` export interface ${StringUtils2.capitalizeFirst(table.name)} {
1214
- `;
1215
- for (const column of table.columns) {
1216
- modelString += ` ${column.name}${column.isNullable ? "?" : ""}: ${SqlUtils.convertDatabaseTypeToTypescript(column.type, column.value)};
1217
- `;
1218
- }
1219
- modelString += ` }
1220
- `;
1221
- return modelString;
1222
- }
1223
-
1224
- // src/restura/sql/PsqlEngine.ts
1225
- import { ObjectUtils as ObjectUtils4 } from "@redskytech/core-utils";
1226
- import getDiff from "@wmfs/pg-diff-sync";
1227
- import pgInfo from "@wmfs/pg-info";
1228
- import pg2 from "pg";
1229
-
1230
- // src/restura/eventManager.ts
1231
- import Bluebird2 from "bluebird";
1232
- var EventManager = class {
1233
- constructor() {
1234
- this.actionHandlers = {
1235
- DATABASE_ROW_DELETE: [],
1236
- DATABASE_ROW_INSERT: [],
1237
- DATABASE_COLUMN_UPDATE: []
1238
- };
1239
- }
1240
- addRowInsertHandler(onInsert, filter) {
1241
- this.actionHandlers.DATABASE_ROW_INSERT.push({
1242
- callback: onInsert,
1243
- filter
1244
- });
1245
- }
1246
- addColumnChangeHandler(onUpdate, filter) {
1247
- this.actionHandlers.DATABASE_COLUMN_UPDATE.push({
1248
- callback: onUpdate,
1249
- filter
1250
- });
1251
- }
1252
- addRowDeleteHandler(onDelete, filter) {
1253
- this.actionHandlers.DATABASE_ROW_DELETE.push({
1254
- callback: onDelete,
1255
- filter
1256
- });
1257
- }
1258
- async fireActionFromDbTrigger(sqlMutationData, result) {
1259
- if (sqlMutationData.mutationType === "INSERT") {
1260
- await this.fireInsertActions(sqlMutationData, result);
1261
- } else if (sqlMutationData.mutationType === "UPDATE") {
1262
- await this.fireUpdateActions(sqlMutationData, result);
1263
- } else if (sqlMutationData.mutationType === "DELETE") {
1264
- await this.fireDeleteActions(sqlMutationData, result);
1265
- }
1266
- }
1267
- async fireInsertActions(data, triggerResult) {
1268
- await Bluebird2.map(
1269
- this.actionHandlers.DATABASE_ROW_INSERT,
1270
- ({ callback, filter }) => {
1271
- if (!this.hasHandlersForEventType("DATABASE_ROW_INSERT", filter, triggerResult)) return;
1272
- const insertData = {
1273
- tableName: triggerResult.table,
1274
- insertId: triggerResult.record.id,
1275
- insertObject: triggerResult.record,
1276
- queryMetadata: data.queryMetadata
1277
- };
1278
- callback(insertData, data.queryMetadata);
1279
- },
1280
- { concurrency: 10 }
1281
- );
1282
- }
1283
- async fireDeleteActions(data, triggerResult) {
1284
- await Bluebird2.map(
1285
- this.actionHandlers.DATABASE_ROW_DELETE,
1286
- ({ callback, filter }) => {
1287
- if (!this.hasHandlersForEventType("DATABASE_ROW_DELETE", filter, triggerResult)) return;
1288
- const deleteData = {
1289
- tableName: triggerResult.table,
1290
- deletedRow: triggerResult.previousRecord,
1291
- queryMetadata: data.queryMetadata
1292
- };
1293
- callback(deleteData, data.queryMetadata);
1294
- },
1295
- { concurrency: 10 }
1414
+ if (requestValue > validator.value)
1415
+ throw new RsError(
1416
+ "BAD_REQUEST",
1417
+ `Request param (${requestParamName}) with value (${requestValue}) is more than (${validator.value})`
1296
1418
  );
1297
- }
1298
- async fireUpdateActions(data, triggerResult) {
1299
- await Bluebird2.map(
1300
- this.actionHandlers.DATABASE_COLUMN_UPDATE,
1301
- ({ callback, filter }) => {
1302
- if (!this.hasHandlersForEventType("DATABASE_COLUMN_UPDATE", filter, triggerResult)) return;
1303
- const columnChangeData = {
1304
- tableName: triggerResult.table,
1305
- rowId: triggerResult.record.id,
1306
- newData: triggerResult.record,
1307
- oldData: triggerResult.previousRecord,
1308
- queryMetadata: data.queryMetadata
1309
- };
1310
- callback(columnChangeData, data.queryMetadata);
1311
- },
1312
- { concurrency: 10 }
1419
+ }
1420
+ function performOneOfCheck(requestValue, validator, requestParamName) {
1421
+ if (!ObjectUtils2.isArrayWithData(validator.value))
1422
+ throw new RsError("SCHEMA_ERROR", `Schema validator value (${validator.value}) is not of type array`);
1423
+ if (typeof requestValue === "object")
1424
+ throw new RsError("BAD_REQUEST", `Request param (${requestParamName}) is not of type string or number`);
1425
+ if (!validator.value.includes(requestValue))
1426
+ throw new RsError(
1427
+ "BAD_REQUEST",
1428
+ `Request param (${requestParamName}) with value (${requestValue}) is not one of (${validator.value.join(", ")})`
1313
1429
  );
1430
+ }
1431
+ function isValueNumber(value) {
1432
+ return !isNaN(Number(value));
1433
+ }
1434
+ function getRequestData(req) {
1435
+ let body = "";
1436
+ if (req.method === "GET" || req.method === "DELETE") {
1437
+ body = "query";
1438
+ } else {
1439
+ body = "body";
1314
1440
  }
1315
- hasHandlersForEventType(eventType, filter, triggerResult) {
1316
- if (filter) {
1317
- switch (eventType) {
1318
- case "DATABASE_ROW_INSERT":
1319
- case "DATABASE_ROW_DELETE":
1320
- if (filter.tableName && filter.tableName !== triggerResult.table) return false;
1321
- break;
1322
- case "DATABASE_COLUMN_UPDATE":
1323
- const filterColumnChange = filter;
1324
- if (filterColumnChange.tableName !== filter.tableName) return false;
1325
- if (!filterColumnChange.columns.some((item) => {
1326
- const updatedColumns = Object.keys(
1327
- changedValues(triggerResult.record, triggerResult.previousRecord)
1328
- );
1329
- return updatedColumns.includes(item);
1330
- }))
1331
- return false;
1332
- break;
1333
- }
1334
- }
1335
- return true;
1336
- }
1337
- };
1338
- var eventManager = new EventManager();
1339
- var eventManager_default = eventManager;
1340
- function changedValues(record, previousRecord) {
1341
- const changed = {};
1342
- for (const i in previousRecord) {
1343
- if (previousRecord[i] !== record[i]) {
1344
- if (typeof previousRecord[i] === "object" && typeof record[i] === "object") {
1345
- const nestedChanged = changedValues(record[i], previousRecord[i]);
1346
- if (Object.keys(nestedChanged).length > 0) {
1347
- changed[i] = record[i];
1441
+ const bodyData = req[body];
1442
+ if (bodyData && body === "query") {
1443
+ for (const attr in bodyData) {
1444
+ if (bodyData[attr] instanceof Array) {
1445
+ const attrList = [];
1446
+ for (const value of bodyData[attr]) {
1447
+ if (isNaN(Number(value))) continue;
1448
+ attrList.push(Number(value));
1449
+ }
1450
+ if (ObjectUtils2.isArrayWithData(attrList)) {
1451
+ bodyData[attr] = attrList;
1348
1452
  }
1349
1453
  } else {
1350
- changed[i] = record[i];
1454
+ bodyData[attr] = ObjectUtils2.safeParse(bodyData[attr]);
1455
+ if (isNaN(Number(bodyData[attr]))) continue;
1456
+ bodyData[attr] = Number(bodyData[attr]);
1351
1457
  }
1352
1458
  }
1353
1459
  }
1354
- return changed;
1460
+ return bodyData;
1461
+ }
1462
+
1463
+ // src/restura/middleware/schemaValidation.ts
1464
+ async function schemaValidation(req, res, next) {
1465
+ req.data = getRequestData(req);
1466
+ try {
1467
+ resturaSchema.parse(req.data);
1468
+ next();
1469
+ } catch (error) {
1470
+ logger.error(error);
1471
+ res.sendError("BAD_REQUEST", error, 400 /* BAD_REQUEST */);
1472
+ }
1355
1473
  }
1356
1474
 
1475
+ // src/restura/schemas/resturaConfigSchema.ts
1476
+ import { z as z5 } from "zod";
1477
+ var _a;
1478
+ var isTsx = (_a = process.argv[1]) == null ? void 0 : _a.endsWith(".ts");
1479
+ var isTsNode = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
1480
+ var customApiFolderPath = isTsx || isTsNode ? "/src/api" : "/dist/api";
1481
+ var resturaConfigSchema = z5.object({
1482
+ authToken: z5.string().min(1, "Missing Restura Auth Token"),
1483
+ sendErrorStackTrace: z5.boolean().default(false),
1484
+ schemaFilePath: z5.string().default(process.cwd() + "/restura.schema.json"),
1485
+ customApiFolderPath: z5.string().default(process.cwd() + customApiFolderPath),
1486
+ generatedTypesPath: z5.string().default(process.cwd() + "/src/@types"),
1487
+ fileTempCachePath: z5.string().optional()
1488
+ });
1489
+
1490
+ // src/restura/sql/PsqlEngine.ts
1491
+ import { ObjectUtils as ObjectUtils4 } from "@redskytech/core-utils";
1492
+ import getDiff from "@wmfs/pg-diff-sync";
1493
+ import pgInfo from "@wmfs/pg-info";
1494
+ import pg2 from "pg";
1495
+
1357
1496
  // src/restura/sql/PsqlPool.ts
1358
1497
  import pg from "pg";
1359
1498
 
1360
1499
  // src/restura/sql/PsqlConnection.ts
1500
+ import crypto from "crypto";
1361
1501
  import format3 from "pg-format";
1362
1502
 
1363
1503
  // src/restura/sql/PsqlUtils.ts
@@ -1410,7 +1550,6 @@ function SQL(strings, ...values) {
1410
1550
  }
1411
1551
 
1412
1552
  // src/restura/sql/PsqlConnection.ts
1413
- import crypto from "crypto";
1414
1553
  var PsqlConnection = class {
1415
1554
  constructor() {
1416
1555
  this.instanceId = crypto.randomUUID();
@@ -2262,121 +2401,6 @@ function schemaToPsqlType(column) {
2262
2401
  return column.type;
2263
2402
  }
2264
2403
 
2265
- // src/restura/compareSchema.ts
2266
- import cloneDeep from "lodash.clonedeep";
2267
- var CompareSchema = class {
2268
- async diffSchema(newSchema, latestSchema, psqlEngine) {
2269
- const endPoints = this.diffEndPoints(newSchema.endpoints[0].routes, latestSchema.endpoints[0].routes);
2270
- const globalParams = this.diffStringArray(newSchema.globalParams, latestSchema.globalParams);
2271
- const roles = this.diffStringArray(newSchema.roles, latestSchema.roles);
2272
- let commands = "";
2273
- if (JSON.stringify(newSchema.database) !== JSON.stringify(latestSchema.database))
2274
- commands = await psqlEngine.diffDatabaseToSchema(newSchema);
2275
- const customTypes = newSchema.customTypes !== latestSchema.customTypes;
2276
- const schemaPreview = { endPoints, globalParams, roles, commands, customTypes };
2277
- return schemaPreview;
2278
- }
2279
- diffStringArray(newArray, originalArray) {
2280
- const stringsDiff = [];
2281
- const originalClone = new Set(originalArray);
2282
- newArray.forEach((item) => {
2283
- const originalIndex = originalClone.has(item);
2284
- if (!originalIndex) {
2285
- stringsDiff.push({
2286
- name: item,
2287
- changeType: "NEW"
2288
- });
2289
- } else {
2290
- originalClone.delete(item);
2291
- }
2292
- });
2293
- originalClone.forEach((item) => {
2294
- stringsDiff.push({
2295
- name: item,
2296
- changeType: "DELETED"
2297
- });
2298
- });
2299
- return stringsDiff;
2300
- }
2301
- diffEndPoints(newEndPoints, originalEndpoints) {
2302
- const originalClone = cloneDeep(originalEndpoints);
2303
- const diffObj = [];
2304
- newEndPoints.forEach((endPoint) => {
2305
- const { path: path5, method } = endPoint;
2306
- const endPointIndex = originalClone.findIndex((original) => {
2307
- return original.path === endPoint.path && original.method === endPoint.method;
2308
- });
2309
- if (endPointIndex === -1) {
2310
- diffObj.push({
2311
- name: `${method} ${path5}`,
2312
- changeType: "NEW"
2313
- });
2314
- } else {
2315
- const original = originalClone.findIndex((original2) => {
2316
- return this.compareEndPoints(endPoint, original2);
2317
- });
2318
- if (original === -1) {
2319
- diffObj.push({
2320
- name: `${method} ${path5}`,
2321
- changeType: "MODIFIED"
2322
- });
2323
- }
2324
- originalClone.splice(endPointIndex, 1);
2325
- }
2326
- });
2327
- originalClone.forEach((original) => {
2328
- const { path: path5, method } = original;
2329
- diffObj.push({
2330
- name: `${method} ${path5}`,
2331
- changeType: "DELETED"
2332
- });
2333
- });
2334
- return diffObj;
2335
- }
2336
- compareEndPoints(endPoint1, endPoint2) {
2337
- return JSON.stringify(endPoint1) === JSON.stringify(endPoint2);
2338
- }
2339
- };
2340
- __decorateClass([
2341
- boundMethod
2342
- ], CompareSchema.prototype, "diffSchema", 1);
2343
- __decorateClass([
2344
- boundMethod
2345
- ], CompareSchema.prototype, "diffStringArray", 1);
2346
- __decorateClass([
2347
- boundMethod
2348
- ], CompareSchema.prototype, "diffEndPoints", 1);
2349
- __decorateClass([
2350
- boundMethod
2351
- ], CompareSchema.prototype, "compareEndPoints", 1);
2352
- var compareSchema = new CompareSchema();
2353
- var compareSchema_default = compareSchema;
2354
-
2355
- // src/restura/middleware/getMulterUploadSingleton.ts
2356
- import multer from "multer";
2357
- import { extname } from "path";
2358
- import * as os from "os";
2359
- var OneHundredMB = 100 * 1024 * 1024;
2360
- var commonUpload = null;
2361
- var getMulterUploadSingleton = (directory) => {
2362
- if (commonUpload) return commonUpload;
2363
- const storage = multer.diskStorage({
2364
- destination: directory || os.tmpdir(),
2365
- filename: function(request, file, cb) {
2366
- const extension = extname(file.originalname);
2367
- const uniqueName = Date.now() + "-" + Math.round(Math.random() * 1e3);
2368
- cb(null, `${uniqueName}${extension}`);
2369
- }
2370
- });
2371
- commonUpload = multer({
2372
- storage,
2373
- limits: {
2374
- fileSize: OneHundredMB
2375
- }
2376
- });
2377
- return commonUpload;
2378
- };
2379
-
2380
2404
  // src/restura/utils/TempCache.ts
2381
2405
  import fs3 from "fs";
2382
2406
  import path3 from "path";
@@ -2429,7 +2453,7 @@ var ResturaEngine = class {
2429
2453
  */
2430
2454
  async init(app, authenticationHandler, psqlConnectionPool) {
2431
2455
  this.resturaConfig = config2.validate("restura", resturaConfigSchema);
2432
- this.multerCommonUpload = getMulterUploadSingleton(this.resturaConfig.fileTempCachePath);
2456
+ this.multerCommonUpload = getMulterUpload(this.resturaConfig.fileTempCachePath);
2433
2457
  new TempCache(this.resturaConfig.fileTempCachePath);
2434
2458
  this.psqlConnectionPool = psqlConnectionPool;
2435
2459
  this.psqlEngine = new PsqlEngine(this.psqlConnectionPool, true);
@@ -2497,10 +2521,7 @@ var ResturaEngine = class {
2497
2521
  * @returns A promise that resolves when the API has been successfully generated and written to the output file.
2498
2522
  */
2499
2523
  async generateApiFromSchema(outputFile, providedSchema) {
2500
- fs4.writeFileSync(
2501
- outputFile,
2502
- await apiGenerator(providedSchema, await this.generateHashForSchema(providedSchema))
2503
- );
2524
+ fs4.writeFileSync(outputFile, await apiGenerator(providedSchema));
2504
2525
  }
2505
2526
  /**
2506
2527
  * Generates a model from the provided schema and writes it to the specified output file.
@@ -2510,10 +2531,15 @@ var ResturaEngine = class {
2510
2531
  * @returns A promise that resolves when the model has been successfully written to the output file.
2511
2532
  */
2512
2533
  async generateModelFromSchema(outputFile, providedSchema) {
2513
- fs4.writeFileSync(
2514
- outputFile,
2515
- await modelGenerator(providedSchema, await this.generateHashForSchema(providedSchema))
2516
- );
2534
+ fs4.writeFileSync(outputFile, await modelGenerator(providedSchema));
2535
+ }
2536
+ /**
2537
+ * Generates the ambient module declaration for Restura global types and writes it to the specified output file.
2538
+ * These types are used sometimes in the CustomTypes
2539
+ * @param outputFile
2540
+ */
2541
+ generateResturaGlobalTypes(outputFile) {
2542
+ fs4.writeFileSync(outputFile, resturaGlobalTypesGenerator());
2517
2543
  }
2518
2544
  /**
2519
2545
  * Retrieves the latest file system schema for Restura.
@@ -2535,28 +2561,6 @@ var ResturaEngine = class {
2535
2561
  }
2536
2562
  return schema;
2537
2563
  }
2538
- /**
2539
- * Asynchronously generates and retrieves hashes for the provided schema and related generated files.
2540
- *
2541
- * @param providedSchema - The schema for which hashes need to be generated.
2542
- * @returns A promise that resolves to an object containing:
2543
- * - `schemaHash`: The hash of the provided schema.
2544
- * - `apiCreatedSchemaHash`: The hash extracted from the generated `api.d.ts` file.
2545
- * - `modelCreatedSchemaHash`: The hash extracted from the generated `models.d.ts` file.
2546
- */
2547
- async getHashes(providedSchema) {
2548
- var _a2, _b, _c, _d;
2549
- const schemaHash = await this.generateHashForSchema(providedSchema);
2550
- const apiFile = fs4.readFileSync(path4.join(this.resturaConfig.generatedTypesPath, "api.d.ts"));
2551
- const apiCreatedSchemaHash = (_b = (_a2 = apiFile.toString().match(/\((.*)\)/)) == null ? void 0 : _a2[1]) != null ? _b : "";
2552
- const modelFile = fs4.readFileSync(path4.join(this.resturaConfig.generatedTypesPath, "models.d.ts"));
2553
- const modelCreatedSchemaHash = (_d = (_c = modelFile.toString().match(/\((.*)\)/)) == null ? void 0 : _c[1]) != null ? _d : "";
2554
- return {
2555
- schemaHash,
2556
- apiCreatedSchemaHash,
2557
- modelCreatedSchemaHash
2558
- };
2559
- }
2560
2564
  async reloadEndpoints() {
2561
2565
  this.schema = await this.getLatestFileSystemSchema();
2562
2566
  this.customTypeValidation = customTypeValidationGenerator(this.schema);
@@ -2588,27 +2592,7 @@ var ResturaEngine = class {
2588
2592
  if (!fs4.existsSync(this.resturaConfig.generatedTypesPath)) {
2589
2593
  fs4.mkdirSync(this.resturaConfig.generatedTypesPath, { recursive: true });
2590
2594
  }
2591
- const hasApiFile = fs4.existsSync(path4.join(this.resturaConfig.generatedTypesPath, "api.d.ts"));
2592
- const hasModelsFile = fs4.existsSync(path4.join(this.resturaConfig.generatedTypesPath, "models.d.ts"));
2593
- if (!hasApiFile) {
2594
- await this.generateApiFromSchema(path4.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
2595
- }
2596
- if (!hasModelsFile) {
2597
- await this.generateModelFromSchema(
2598
- path4.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
2599
- this.schema
2600
- );
2601
- }
2602
- const hashes = await this.getHashes(this.schema);
2603
- if (hashes.schemaHash !== hashes.apiCreatedSchemaHash) {
2604
- await this.generateApiFromSchema(path4.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
2605
- }
2606
- if (hashes.schemaHash !== hashes.modelCreatedSchemaHash) {
2607
- await this.generateModelFromSchema(
2608
- path4.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
2609
- this.schema
2610
- );
2611
- }
2595
+ this.updateTypes();
2612
2596
  }
2613
2597
  resturaAuthentication(req, res, next) {
2614
2598
  if (req.headers["x-auth-token"] !== this.resturaConfig.authToken) res.status(401).send("Unauthorized");
@@ -2640,6 +2624,7 @@ var ResturaEngine = class {
2640
2624
  path4.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
2641
2625
  this.schema
2642
2626
  );
2627
+ this.generateResturaGlobalTypes(path4.join(this.resturaConfig.generatedTypesPath, "restura.d.ts"));
2643
2628
  }
2644
2629
  async getSchema(req, res) {
2645
2630
  res.send({ data: this.schema });
@@ -2647,9 +2632,8 @@ var ResturaEngine = class {
2647
2632
  async getSchemaAndTypes(req, res) {
2648
2633
  try {
2649
2634
  const schema = await this.getLatestFileSystemSchema();
2650
- const schemaHash = await this.generateHashForSchema(schema);
2651
- const apiText = await apiGenerator(schema, schemaHash);
2652
- const modelsText = await modelGenerator(schema, schemaHash);
2635
+ const apiText = await apiGenerator(schema);
2636
+ const modelsText = await modelGenerator(schema);
2653
2637
  res.send({ schema, api: apiText, models: modelsText });
2654
2638
  } catch (err) {
2655
2639
  res.status(400).send({ error: err });
@@ -2679,7 +2663,7 @@ var ResturaEngine = class {
2679
2663
  const routeData = this.getRouteData(req.method, req.baseUrl, req.path);
2680
2664
  this.validateAuthorization(req, routeData);
2681
2665
  await this.getMulterFilesIfAny(req, res, routeData);
2682
- validateRequestParams(req, routeData, this.customTypeValidation);
2666
+ requestValidator(req, routeData, this.customTypeValidation);
2683
2667
  if (this.isCustomRoute(routeData)) {
2684
2668
  await this.runCustomRouteLogic(req, res, routeData);
2685
2669
  return;
@@ -2719,19 +2703,6 @@ var ResturaEngine = class {
2719
2703
  throw new RsError("NOT_FOUND", `API path ${routeData.path} not implemented ${functionName}`);
2720
2704
  await customFunction(req, res, routeData);
2721
2705
  }
2722
- async generateHashForSchema(providedSchema) {
2723
- const schemaPrettyStr = await prettier3.format(JSON.stringify(providedSchema), __spreadValues({
2724
- parser: "json"
2725
- }, {
2726
- trailingComma: "none",
2727
- tabWidth: 4,
2728
- useTabs: true,
2729
- endOfLine: "lf",
2730
- printWidth: 120,
2731
- singleQuote: true
2732
- }));
2733
- return createHash("sha256").update(schemaPrettyStr).digest("hex");
2734
- }
2735
2706
  async storeFileSystemSchema() {
2736
2707
  const schemaPrettyStr = await prettier3.format(JSON.stringify(this.schema), __spreadValues({
2737
2708
  parser: "json"