@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.d.mts +279 -307
- package/dist/index.d.ts +279 -307
- package/dist/index.js +548 -577
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +544 -573
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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/
|
|
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/
|
|
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/
|
|
167
|
-
import
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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/
|
|
217
|
-
import
|
|
218
|
-
import
|
|
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
|
|
558
|
-
let apiString = `/** Auto generated file
|
|
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
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
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
|
-
|
|
645
|
-
|
|
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
|
|
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
|
-
|
|
667
|
-
path2.join(
|
|
668
|
-
path2.join(
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
|
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
|
-
|
|
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/
|
|
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/
|
|
1013
|
-
function
|
|
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
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
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
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
2515
|
-
|
|
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
|
-
|
|
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
|
|
2651
|
-
const
|
|
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
|
-
|
|
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"
|