@restura/core 0.1.0-alpha.24 → 0.1.0-alpha.26
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 +285 -307
- package/dist/index.d.ts +285 -307
- package/dist/index.js +571 -585
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +567 -581
- 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;
|
|
@@ -548,108 +812,49 @@ var ApiTree = class _ApiTree {
|
|
|
548
812
|
return {
|
|
549
813
|
responseType: SqlUtils.convertDatabaseTypeToTypescript(column.type, column.value),
|
|
550
814
|
isNullable: column.roles.length > 0 || column.isNullable
|
|
551
|
-
};
|
|
552
|
-
}
|
|
553
|
-
};
|
|
554
|
-
function pathToNamespaces(path5) {
|
|
555
|
-
return path5.split("/").map((e) => StringUtils.toPascalCasing(e)).filter((e) => e);
|
|
556
|
-
}
|
|
557
|
-
function apiGenerator(schema, schemaHash) {
|
|
558
|
-
let apiString = `/** Auto generated file from Schema Hash (${schemaHash}). DO NOT MODIFY **/`;
|
|
559
|
-
const rootNamespace = ApiTree.createRootNode(schema.database);
|
|
560
|
-
for (const endpoint of schema.endpoints) {
|
|
561
|
-
const endpointNamespaces = pathToNamespaces(endpoint.baseUrl);
|
|
562
|
-
rootNamespace.addData(endpointNamespaces, endpoint);
|
|
563
|
-
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
|
-
});
|
|
633
|
-
}
|
|
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
|
-
});
|
|
815
|
+
};
|
|
642
816
|
}
|
|
643
817
|
};
|
|
644
|
-
|
|
645
|
-
|
|
818
|
+
function pathToNamespaces(path5) {
|
|
819
|
+
return path5.split("/").map((e) => StringUtils.toPascalCasing(e)).filter((e) => e);
|
|
820
|
+
}
|
|
821
|
+
function apiGenerator(schema) {
|
|
822
|
+
let apiString = `/** Auto generated file. DO NOT MODIFY **/
|
|
823
|
+
`;
|
|
824
|
+
const rootNamespace = ApiTree.createRootNode(schema.database);
|
|
825
|
+
for (const endpoint of schema.endpoints) {
|
|
826
|
+
const endpointNamespaces = pathToNamespaces(endpoint.baseUrl);
|
|
827
|
+
rootNamespace.addData(endpointNamespaces, endpoint);
|
|
828
|
+
for (const route of endpoint.routes) {
|
|
829
|
+
const fullNamespace = [...endpointNamespaces, ...pathToNamespaces(route.path)];
|
|
830
|
+
rootNamespace.addData(fullNamespace, route);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
apiString += rootNamespace.createApiModels();
|
|
834
|
+
if (schema.customTypes.length > 0) {
|
|
835
|
+
apiString += `
|
|
836
|
+
|
|
837
|
+
declare namespace CustomTypes {
|
|
838
|
+
${schema.customTypes}
|
|
839
|
+
}`;
|
|
840
|
+
}
|
|
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) {
|
|
@@ -1130,234 +1416,88 @@ function performMaxCheck(requestValue, validator, requestParamName) {
|
|
|
1130
1416
|
"BAD_REQUEST",
|
|
1131
1417
|
`Request param (${requestParamName}) with value (${requestValue}) is more than (${validator.value})`
|
|
1132
1418
|
);
|
|
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 }
|
|
1296
|
-
);
|
|
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
|
-
|
|
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
|
|
@@ -1368,7 +1508,22 @@ function escapeColumnName(columnName) {
|
|
|
1368
1508
|
}
|
|
1369
1509
|
function questionMarksToOrderedParams(query) {
|
|
1370
1510
|
let count = 1;
|
|
1371
|
-
|
|
1511
|
+
let inSingleQuote = false;
|
|
1512
|
+
let inDoubleQuote = false;
|
|
1513
|
+
return query.replace(/('|"|\?)/g, (char) => {
|
|
1514
|
+
if (char === "'") {
|
|
1515
|
+
inSingleQuote = !inSingleQuote && !inDoubleQuote;
|
|
1516
|
+
return char;
|
|
1517
|
+
}
|
|
1518
|
+
if (char === '"') {
|
|
1519
|
+
inDoubleQuote = !inDoubleQuote && !inSingleQuote;
|
|
1520
|
+
return char;
|
|
1521
|
+
}
|
|
1522
|
+
if (char === "?" && !inSingleQuote && !inDoubleQuote) {
|
|
1523
|
+
return `$${count++}`;
|
|
1524
|
+
}
|
|
1525
|
+
return char;
|
|
1526
|
+
});
|
|
1372
1527
|
}
|
|
1373
1528
|
function insertObjectQuery(table, obj) {
|
|
1374
1529
|
const keys = Object.keys(obj);
|
|
@@ -1410,7 +1565,6 @@ function SQL(strings, ...values) {
|
|
|
1410
1565
|
}
|
|
1411
1566
|
|
|
1412
1567
|
// src/restura/sql/PsqlConnection.ts
|
|
1413
|
-
import crypto from "crypto";
|
|
1414
1568
|
var PsqlConnection = class {
|
|
1415
1569
|
constructor() {
|
|
1416
1570
|
this.instanceId = crypto.randomUUID();
|
|
@@ -2262,121 +2416,6 @@ function schemaToPsqlType(column) {
|
|
|
2262
2416
|
return column.type;
|
|
2263
2417
|
}
|
|
2264
2418
|
|
|
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
2419
|
// src/restura/utils/TempCache.ts
|
|
2381
2420
|
import fs3 from "fs";
|
|
2382
2421
|
import path3 from "path";
|
|
@@ -2429,7 +2468,7 @@ var ResturaEngine = class {
|
|
|
2429
2468
|
*/
|
|
2430
2469
|
async init(app, authenticationHandler, psqlConnectionPool) {
|
|
2431
2470
|
this.resturaConfig = config2.validate("restura", resturaConfigSchema);
|
|
2432
|
-
this.multerCommonUpload =
|
|
2471
|
+
this.multerCommonUpload = getMulterUpload(this.resturaConfig.fileTempCachePath);
|
|
2433
2472
|
new TempCache(this.resturaConfig.fileTempCachePath);
|
|
2434
2473
|
this.psqlConnectionPool = psqlConnectionPool;
|
|
2435
2474
|
this.psqlEngine = new PsqlEngine(this.psqlConnectionPool, true);
|
|
@@ -2497,10 +2536,7 @@ var ResturaEngine = class {
|
|
|
2497
2536
|
* @returns A promise that resolves when the API has been successfully generated and written to the output file.
|
|
2498
2537
|
*/
|
|
2499
2538
|
async generateApiFromSchema(outputFile, providedSchema) {
|
|
2500
|
-
fs4.writeFileSync(
|
|
2501
|
-
outputFile,
|
|
2502
|
-
await apiGenerator(providedSchema, await this.generateHashForSchema(providedSchema))
|
|
2503
|
-
);
|
|
2539
|
+
fs4.writeFileSync(outputFile, await apiGenerator(providedSchema));
|
|
2504
2540
|
}
|
|
2505
2541
|
/**
|
|
2506
2542
|
* Generates a model from the provided schema and writes it to the specified output file.
|
|
@@ -2510,10 +2546,15 @@ var ResturaEngine = class {
|
|
|
2510
2546
|
* @returns A promise that resolves when the model has been successfully written to the output file.
|
|
2511
2547
|
*/
|
|
2512
2548
|
async generateModelFromSchema(outputFile, providedSchema) {
|
|
2513
|
-
fs4.writeFileSync(
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2549
|
+
fs4.writeFileSync(outputFile, await modelGenerator(providedSchema));
|
|
2550
|
+
}
|
|
2551
|
+
/**
|
|
2552
|
+
* Generates the ambient module declaration for Restura global types and writes it to the specified output file.
|
|
2553
|
+
* These types are used sometimes in the CustomTypes
|
|
2554
|
+
* @param outputFile
|
|
2555
|
+
*/
|
|
2556
|
+
generateResturaGlobalTypes(outputFile) {
|
|
2557
|
+
fs4.writeFileSync(outputFile, resturaGlobalTypesGenerator());
|
|
2517
2558
|
}
|
|
2518
2559
|
/**
|
|
2519
2560
|
* Retrieves the latest file system schema for Restura.
|
|
@@ -2535,28 +2576,6 @@ var ResturaEngine = class {
|
|
|
2535
2576
|
}
|
|
2536
2577
|
return schema;
|
|
2537
2578
|
}
|
|
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
2579
|
async reloadEndpoints() {
|
|
2561
2580
|
this.schema = await this.getLatestFileSystemSchema();
|
|
2562
2581
|
this.customTypeValidation = customTypeValidationGenerator(this.schema);
|
|
@@ -2588,27 +2607,7 @@ var ResturaEngine = class {
|
|
|
2588
2607
|
if (!fs4.existsSync(this.resturaConfig.generatedTypesPath)) {
|
|
2589
2608
|
fs4.mkdirSync(this.resturaConfig.generatedTypesPath, { recursive: true });
|
|
2590
2609
|
}
|
|
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
|
-
}
|
|
2610
|
+
this.updateTypes();
|
|
2612
2611
|
}
|
|
2613
2612
|
resturaAuthentication(req, res, next) {
|
|
2614
2613
|
if (req.headers["x-auth-token"] !== this.resturaConfig.authToken) res.status(401).send("Unauthorized");
|
|
@@ -2640,6 +2639,7 @@ var ResturaEngine = class {
|
|
|
2640
2639
|
path4.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
|
|
2641
2640
|
this.schema
|
|
2642
2641
|
);
|
|
2642
|
+
this.generateResturaGlobalTypes(path4.join(this.resturaConfig.generatedTypesPath, "restura.d.ts"));
|
|
2643
2643
|
}
|
|
2644
2644
|
async getSchema(req, res) {
|
|
2645
2645
|
res.send({ data: this.schema });
|
|
@@ -2647,9 +2647,8 @@ var ResturaEngine = class {
|
|
|
2647
2647
|
async getSchemaAndTypes(req, res) {
|
|
2648
2648
|
try {
|
|
2649
2649
|
const schema = await this.getLatestFileSystemSchema();
|
|
2650
|
-
const
|
|
2651
|
-
const
|
|
2652
|
-
const modelsText = await modelGenerator(schema, schemaHash);
|
|
2650
|
+
const apiText = await apiGenerator(schema);
|
|
2651
|
+
const modelsText = await modelGenerator(schema);
|
|
2653
2652
|
res.send({ schema, api: apiText, models: modelsText });
|
|
2654
2653
|
} catch (err) {
|
|
2655
2654
|
res.status(400).send({ error: err });
|
|
@@ -2679,7 +2678,7 @@ var ResturaEngine = class {
|
|
|
2679
2678
|
const routeData = this.getRouteData(req.method, req.baseUrl, req.path);
|
|
2680
2679
|
this.validateAuthorization(req, routeData);
|
|
2681
2680
|
await this.getMulterFilesIfAny(req, res, routeData);
|
|
2682
|
-
|
|
2681
|
+
requestValidator(req, routeData, this.customTypeValidation);
|
|
2683
2682
|
if (this.isCustomRoute(routeData)) {
|
|
2684
2683
|
await this.runCustomRouteLogic(req, res, routeData);
|
|
2685
2684
|
return;
|
|
@@ -2719,19 +2718,6 @@ var ResturaEngine = class {
|
|
|
2719
2718
|
throw new RsError("NOT_FOUND", `API path ${routeData.path} not implemented ${functionName}`);
|
|
2720
2719
|
await customFunction(req, res, routeData);
|
|
2721
2720
|
}
|
|
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
2721
|
async storeFileSystemSchema() {
|
|
2736
2722
|
const schemaPrettyStr = await prettier3.format(JSON.stringify(this.schema), __spreadValues({
|
|
2737
2723
|
parser: "json"
|