@restura/core 0.1.0-alpha.23 → 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 +566 -595
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +562 -591
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -90,23 +90,11 @@ var import_internal = require("@restura/internal");
|
|
|
90
90
|
var import_winston = __toESM(require("winston"));
|
|
91
91
|
var import_logform = require("logform");
|
|
92
92
|
|
|
93
|
-
// src/
|
|
93
|
+
// src/logger/loggerConfigSchema.ts
|
|
94
94
|
var import_zod = require("zod");
|
|
95
95
|
var loggerConfigSchema = import_zod.z.object({
|
|
96
96
|
level: import_zod.z.enum(["info", "warn", "error", "debug", "silly"]).default("info")
|
|
97
97
|
});
|
|
98
|
-
var _a;
|
|
99
|
-
var isTsx = (_a = process.argv[1]) == null ? void 0 : _a.endsWith(".ts");
|
|
100
|
-
var isTsNode = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
|
|
101
|
-
var customApiFolderPath = isTsx || isTsNode ? "/src/api" : "/dist/api";
|
|
102
|
-
var resturaConfigSchema = import_zod.z.object({
|
|
103
|
-
authToken: import_zod.z.string().min(1, "Missing Restura Auth Token"),
|
|
104
|
-
sendErrorStackTrace: import_zod.z.boolean().default(false),
|
|
105
|
-
schemaFilePath: import_zod.z.string().default(process.cwd() + "/restura.schema.json"),
|
|
106
|
-
customApiFolderPath: import_zod.z.string().default(process.cwd() + customApiFolderPath),
|
|
107
|
-
generatedTypesPath: import_zod.z.string().default(process.cwd() + "/src/@types"),
|
|
108
|
-
fileTempCachePath: import_zod.z.string().optional()
|
|
109
|
-
});
|
|
110
98
|
|
|
111
99
|
// src/logger/logger.ts
|
|
112
100
|
var loggerConfig = import_internal.config.validate("logger", loggerConfigSchema);
|
|
@@ -143,7 +131,194 @@ var logger = import_winston.default.createLogger({
|
|
|
143
131
|
]
|
|
144
132
|
});
|
|
145
133
|
|
|
146
|
-
// src/restura/
|
|
134
|
+
// src/restura/eventManager.ts
|
|
135
|
+
var import_bluebird = __toESM(require("bluebird"));
|
|
136
|
+
var EventManager = class {
|
|
137
|
+
constructor() {
|
|
138
|
+
this.actionHandlers = {
|
|
139
|
+
DATABASE_ROW_DELETE: [],
|
|
140
|
+
DATABASE_ROW_INSERT: [],
|
|
141
|
+
DATABASE_COLUMN_UPDATE: []
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
addRowInsertHandler(onInsert, filter) {
|
|
145
|
+
this.actionHandlers.DATABASE_ROW_INSERT.push({
|
|
146
|
+
callback: onInsert,
|
|
147
|
+
filter
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
addColumnChangeHandler(onUpdate, filter) {
|
|
151
|
+
this.actionHandlers.DATABASE_COLUMN_UPDATE.push({
|
|
152
|
+
callback: onUpdate,
|
|
153
|
+
filter
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
addRowDeleteHandler(onDelete, filter) {
|
|
157
|
+
this.actionHandlers.DATABASE_ROW_DELETE.push({
|
|
158
|
+
callback: onDelete,
|
|
159
|
+
filter
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
async fireActionFromDbTrigger(sqlMutationData, result) {
|
|
163
|
+
if (sqlMutationData.mutationType === "INSERT") {
|
|
164
|
+
await this.fireInsertActions(sqlMutationData, result);
|
|
165
|
+
} else if (sqlMutationData.mutationType === "UPDATE") {
|
|
166
|
+
await this.fireUpdateActions(sqlMutationData, result);
|
|
167
|
+
} else if (sqlMutationData.mutationType === "DELETE") {
|
|
168
|
+
await this.fireDeleteActions(sqlMutationData, result);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async fireInsertActions(data, triggerResult) {
|
|
172
|
+
await import_bluebird.default.map(
|
|
173
|
+
this.actionHandlers.DATABASE_ROW_INSERT,
|
|
174
|
+
({ callback, filter }) => {
|
|
175
|
+
if (!this.hasHandlersForEventType("DATABASE_ROW_INSERT", filter, triggerResult)) return;
|
|
176
|
+
const insertData = {
|
|
177
|
+
tableName: triggerResult.table,
|
|
178
|
+
insertId: triggerResult.record.id,
|
|
179
|
+
insertObject: triggerResult.record,
|
|
180
|
+
queryMetadata: data.queryMetadata
|
|
181
|
+
};
|
|
182
|
+
callback(insertData, data.queryMetadata);
|
|
183
|
+
},
|
|
184
|
+
{ concurrency: 10 }
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
async fireDeleteActions(data, triggerResult) {
|
|
188
|
+
await import_bluebird.default.map(
|
|
189
|
+
this.actionHandlers.DATABASE_ROW_DELETE,
|
|
190
|
+
({ callback, filter }) => {
|
|
191
|
+
if (!this.hasHandlersForEventType("DATABASE_ROW_DELETE", filter, triggerResult)) return;
|
|
192
|
+
const deleteData = {
|
|
193
|
+
tableName: triggerResult.table,
|
|
194
|
+
deletedRow: triggerResult.previousRecord,
|
|
195
|
+
queryMetadata: data.queryMetadata
|
|
196
|
+
};
|
|
197
|
+
callback(deleteData, data.queryMetadata);
|
|
198
|
+
},
|
|
199
|
+
{ concurrency: 10 }
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
async fireUpdateActions(data, triggerResult) {
|
|
203
|
+
await import_bluebird.default.map(
|
|
204
|
+
this.actionHandlers.DATABASE_COLUMN_UPDATE,
|
|
205
|
+
({ callback, filter }) => {
|
|
206
|
+
if (!this.hasHandlersForEventType("DATABASE_COLUMN_UPDATE", filter, triggerResult)) return;
|
|
207
|
+
const columnChangeData = {
|
|
208
|
+
tableName: triggerResult.table,
|
|
209
|
+
rowId: triggerResult.record.id,
|
|
210
|
+
newData: triggerResult.record,
|
|
211
|
+
oldData: triggerResult.previousRecord,
|
|
212
|
+
queryMetadata: data.queryMetadata
|
|
213
|
+
};
|
|
214
|
+
callback(columnChangeData, data.queryMetadata);
|
|
215
|
+
},
|
|
216
|
+
{ concurrency: 10 }
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
hasHandlersForEventType(eventType, filter, triggerResult) {
|
|
220
|
+
if (filter) {
|
|
221
|
+
switch (eventType) {
|
|
222
|
+
case "DATABASE_ROW_INSERT":
|
|
223
|
+
case "DATABASE_ROW_DELETE":
|
|
224
|
+
if (filter.tableName && filter.tableName !== triggerResult.table) return false;
|
|
225
|
+
break;
|
|
226
|
+
case "DATABASE_COLUMN_UPDATE":
|
|
227
|
+
const filterColumnChange = filter;
|
|
228
|
+
if (filterColumnChange.tableName !== filter.tableName) return false;
|
|
229
|
+
if (!filterColumnChange.columns.some((item) => {
|
|
230
|
+
const updatedColumns = Object.keys(
|
|
231
|
+
changedValues(triggerResult.record, triggerResult.previousRecord)
|
|
232
|
+
);
|
|
233
|
+
return updatedColumns.includes(item);
|
|
234
|
+
}))
|
|
235
|
+
return false;
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
var eventManager = new EventManager();
|
|
243
|
+
var eventManager_default = eventManager;
|
|
244
|
+
function changedValues(record, previousRecord) {
|
|
245
|
+
const changed = {};
|
|
246
|
+
for (const i in previousRecord) {
|
|
247
|
+
if (previousRecord[i] !== record[i]) {
|
|
248
|
+
if (typeof previousRecord[i] === "object" && typeof record[i] === "object") {
|
|
249
|
+
const nestedChanged = changedValues(record[i], previousRecord[i]);
|
|
250
|
+
if (Object.keys(nestedChanged).length > 0) {
|
|
251
|
+
changed[i] = record[i];
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
changed[i] = record[i];
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return changed;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/restura/restura.ts
|
|
262
|
+
var import_core_utils7 = require("@redskytech/core-utils");
|
|
263
|
+
var import_internal4 = require("@restura/internal");
|
|
264
|
+
|
|
265
|
+
// ../../node_modules/.pnpm/autobind-decorator@2.4.0/node_modules/autobind-decorator/lib/esm/index.js
|
|
266
|
+
function _typeof(obj) {
|
|
267
|
+
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
|
|
268
|
+
_typeof = function _typeof2(obj2) {
|
|
269
|
+
return typeof obj2;
|
|
270
|
+
};
|
|
271
|
+
} else {
|
|
272
|
+
_typeof = function _typeof2(obj2) {
|
|
273
|
+
return obj2 && typeof Symbol === "function" && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2;
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
return _typeof(obj);
|
|
277
|
+
}
|
|
278
|
+
function boundMethod(target, key, descriptor) {
|
|
279
|
+
var fn = descriptor.value;
|
|
280
|
+
if (typeof fn !== "function") {
|
|
281
|
+
throw new TypeError("@boundMethod decorator can only be applied to methods not: ".concat(_typeof(fn)));
|
|
282
|
+
}
|
|
283
|
+
var definingProperty = false;
|
|
284
|
+
return {
|
|
285
|
+
configurable: true,
|
|
286
|
+
get: function get() {
|
|
287
|
+
if (definingProperty || this === target.prototype || this.hasOwnProperty(key) || typeof fn !== "function") {
|
|
288
|
+
return fn;
|
|
289
|
+
}
|
|
290
|
+
var boundFn = fn.bind(this);
|
|
291
|
+
definingProperty = true;
|
|
292
|
+
Object.defineProperty(this, key, {
|
|
293
|
+
configurable: true,
|
|
294
|
+
get: function get2() {
|
|
295
|
+
return boundFn;
|
|
296
|
+
},
|
|
297
|
+
set: function set(value) {
|
|
298
|
+
fn = value;
|
|
299
|
+
delete this[key];
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
definingProperty = false;
|
|
303
|
+
return boundFn;
|
|
304
|
+
},
|
|
305
|
+
set: function set(value) {
|
|
306
|
+
fn = value;
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/restura/restura.ts
|
|
312
|
+
var import_body_parser = __toESM(require("body-parser"));
|
|
313
|
+
var import_compression = __toESM(require("compression"));
|
|
314
|
+
var import_cookie_parser = __toESM(require("cookie-parser"));
|
|
315
|
+
var express = __toESM(require("express"));
|
|
316
|
+
var import_fs4 = __toESM(require("fs"));
|
|
317
|
+
var import_path5 = __toESM(require("path"));
|
|
318
|
+
var import_pg3 = __toESM(require("pg"));
|
|
319
|
+
var prettier3 = __toESM(require("prettier"));
|
|
320
|
+
|
|
321
|
+
// src/restura/RsError.ts
|
|
147
322
|
var HtmlStatusCodes = /* @__PURE__ */ ((HtmlStatusCodes2) => {
|
|
148
323
|
HtmlStatusCodes2[HtmlStatusCodes2["BAD_REQUEST"] = 400] = "BAD_REQUEST";
|
|
149
324
|
HtmlStatusCodes2[HtmlStatusCodes2["UNAUTHORIZED"] = 401] = "UNAUTHORIZED";
|
|
@@ -167,7 +342,6 @@ var RsError = class _RsError {
|
|
|
167
342
|
static htmlStatus(code) {
|
|
168
343
|
return htmlStatusMap[code];
|
|
169
344
|
}
|
|
170
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
171
345
|
static isRsError(error) {
|
|
172
346
|
return error instanceof _RsError;
|
|
173
347
|
}
|
|
@@ -209,66 +383,158 @@ var htmlStatusMap = {
|
|
|
209
383
|
SCHEMA_ERROR: 500 /* SERVER_ERROR */
|
|
210
384
|
};
|
|
211
385
|
|
|
212
|
-
// src/restura/
|
|
213
|
-
var
|
|
214
|
-
var
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
return _typeof(obj);
|
|
228
|
-
}
|
|
229
|
-
function boundMethod(target, key, descriptor) {
|
|
230
|
-
var fn = descriptor.value;
|
|
231
|
-
if (typeof fn !== "function") {
|
|
232
|
-
throw new TypeError("@boundMethod decorator can only be applied to methods not: ".concat(_typeof(fn)));
|
|
386
|
+
// src/restura/compareSchema.ts
|
|
387
|
+
var import_lodash = __toESM(require("lodash.clonedeep"));
|
|
388
|
+
var CompareSchema = class {
|
|
389
|
+
async diffSchema(newSchema, latestSchema, psqlEngine) {
|
|
390
|
+
const endPoints = this.diffEndPoints(newSchema.endpoints[0].routes, latestSchema.endpoints[0].routes);
|
|
391
|
+
const globalParams = this.diffStringArray(newSchema.globalParams, latestSchema.globalParams);
|
|
392
|
+
const roles = this.diffStringArray(newSchema.roles, latestSchema.roles);
|
|
393
|
+
let commands = "";
|
|
394
|
+
if (JSON.stringify(newSchema.database) !== JSON.stringify(latestSchema.database))
|
|
395
|
+
commands = await psqlEngine.diffDatabaseToSchema(newSchema);
|
|
396
|
+
const customTypes = newSchema.customTypes !== latestSchema.customTypes;
|
|
397
|
+
const schemaPreview = { endPoints, globalParams, roles, commands, customTypes };
|
|
398
|
+
return schemaPreview;
|
|
233
399
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
400
|
+
diffStringArray(newArray, originalArray) {
|
|
401
|
+
const stringsDiff = [];
|
|
402
|
+
const originalClone = new Set(originalArray);
|
|
403
|
+
newArray.forEach((item) => {
|
|
404
|
+
const originalIndex = originalClone.has(item);
|
|
405
|
+
if (!originalIndex) {
|
|
406
|
+
stringsDiff.push({
|
|
407
|
+
name: item,
|
|
408
|
+
changeType: "NEW"
|
|
409
|
+
});
|
|
410
|
+
} else {
|
|
411
|
+
originalClone.delete(item);
|
|
240
412
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
413
|
+
});
|
|
414
|
+
originalClone.forEach((item) => {
|
|
415
|
+
stringsDiff.push({
|
|
416
|
+
name: item,
|
|
417
|
+
changeType: "DELETED"
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
return stringsDiff;
|
|
421
|
+
}
|
|
422
|
+
diffEndPoints(newEndPoints, originalEndpoints) {
|
|
423
|
+
const originalClone = (0, import_lodash.default)(originalEndpoints);
|
|
424
|
+
const diffObj = [];
|
|
425
|
+
newEndPoints.forEach((endPoint) => {
|
|
426
|
+
const { path: path5, method } = endPoint;
|
|
427
|
+
const endPointIndex = originalClone.findIndex((original) => {
|
|
428
|
+
return original.path === endPoint.path && original.method === endPoint.method;
|
|
429
|
+
});
|
|
430
|
+
if (endPointIndex === -1) {
|
|
431
|
+
diffObj.push({
|
|
432
|
+
name: `${method} ${path5}`,
|
|
433
|
+
changeType: "NEW"
|
|
434
|
+
});
|
|
435
|
+
} else {
|
|
436
|
+
const original = originalClone.findIndex((original2) => {
|
|
437
|
+
return this.compareEndPoints(endPoint, original2);
|
|
438
|
+
});
|
|
439
|
+
if (original === -1) {
|
|
440
|
+
diffObj.push({
|
|
441
|
+
name: `${method} ${path5}`,
|
|
442
|
+
changeType: "MODIFIED"
|
|
443
|
+
});
|
|
251
444
|
}
|
|
445
|
+
originalClone.splice(endPointIndex, 1);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
originalClone.forEach((original) => {
|
|
449
|
+
const { path: path5, method } = original;
|
|
450
|
+
diffObj.push({
|
|
451
|
+
name: `${method} ${path5}`,
|
|
452
|
+
changeType: "DELETED"
|
|
252
453
|
});
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
454
|
+
});
|
|
455
|
+
return diffObj;
|
|
456
|
+
}
|
|
457
|
+
compareEndPoints(endPoint1, endPoint2) {
|
|
458
|
+
return JSON.stringify(endPoint1) === JSON.stringify(endPoint2);
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
__decorateClass([
|
|
462
|
+
boundMethod
|
|
463
|
+
], CompareSchema.prototype, "diffSchema", 1);
|
|
464
|
+
__decorateClass([
|
|
465
|
+
boundMethod
|
|
466
|
+
], CompareSchema.prototype, "diffStringArray", 1);
|
|
467
|
+
__decorateClass([
|
|
468
|
+
boundMethod
|
|
469
|
+
], CompareSchema.prototype, "diffEndPoints", 1);
|
|
470
|
+
__decorateClass([
|
|
471
|
+
boundMethod
|
|
472
|
+
], CompareSchema.prototype, "compareEndPoints", 1);
|
|
473
|
+
var compareSchema = new CompareSchema();
|
|
474
|
+
var compareSchema_default = compareSchema;
|
|
475
|
+
|
|
476
|
+
// src/restura/customApiFactory.ts
|
|
477
|
+
var import_internal2 = require("@restura/internal");
|
|
478
|
+
var import_bluebird2 = __toESM(require("bluebird"));
|
|
479
|
+
var import_fs = __toESM(require("fs"));
|
|
480
|
+
var import_path = __toESM(require("path"));
|
|
481
|
+
var CustomApiFactory = class {
|
|
482
|
+
constructor() {
|
|
483
|
+
this.customApis = {};
|
|
484
|
+
}
|
|
485
|
+
async loadApiFiles(baseFolderPath) {
|
|
486
|
+
const apiVersions = ["v1"];
|
|
487
|
+
for (const apiVersion of apiVersions) {
|
|
488
|
+
const apiVersionFolderPath = import_path.default.join(baseFolderPath, apiVersion);
|
|
489
|
+
const directoryExists = await import_internal2.fileUtils.existDir(apiVersionFolderPath);
|
|
490
|
+
if (!directoryExists) continue;
|
|
491
|
+
await this.addDirectory(apiVersionFolderPath, apiVersion);
|
|
258
492
|
}
|
|
259
|
-
}
|
|
260
|
-
|
|
493
|
+
}
|
|
494
|
+
getCustomApi(customApiName) {
|
|
495
|
+
return this.customApis[customApiName];
|
|
496
|
+
}
|
|
497
|
+
async addDirectory(directoryPath, apiVersion) {
|
|
498
|
+
var _a2;
|
|
499
|
+
const entries = await import_fs.default.promises.readdir(directoryPath, {
|
|
500
|
+
withFileTypes: true
|
|
501
|
+
});
|
|
502
|
+
const isTsx2 = (_a2 = process.argv[1]) == null ? void 0 : _a2.endsWith(".ts");
|
|
503
|
+
const isTsNode2 = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
|
|
504
|
+
const extension = isTsx2 || isTsNode2 ? "ts" : "js";
|
|
505
|
+
const shouldEndWith = `.api.${apiVersion}.${extension}`;
|
|
506
|
+
await import_bluebird2.default.map(entries, async (entry) => {
|
|
507
|
+
if (entry.isFile()) {
|
|
508
|
+
if (entry.name.endsWith(shouldEndWith) === false) return;
|
|
509
|
+
try {
|
|
510
|
+
const importPath = `${import_path.default.join(directoryPath, entry.name)}`;
|
|
511
|
+
const ApiImport = await import(importPath);
|
|
512
|
+
const customApiClass = new ApiImport.default();
|
|
513
|
+
logger.info(`Registering custom API: ${ApiImport.default.name}`);
|
|
514
|
+
this.bindMethodsToInstance(customApiClass);
|
|
515
|
+
this.customApis[ApiImport.default.name] = customApiClass;
|
|
516
|
+
} catch (e) {
|
|
517
|
+
console.error(e);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
bindMethodsToInstance(instance) {
|
|
523
|
+
const proto = Object.getPrototypeOf(instance);
|
|
524
|
+
Object.getOwnPropertyNames(proto).forEach((key) => {
|
|
525
|
+
const property = instance[key];
|
|
526
|
+
if (typeof property === "function" && key !== "constructor") {
|
|
527
|
+
instance[key] = property.bind(instance);
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
var customApiFactory = new CustomApiFactory();
|
|
533
|
+
var customApiFactory_default = customApiFactory;
|
|
261
534
|
|
|
262
|
-
// src/restura/
|
|
263
|
-
var
|
|
264
|
-
var
|
|
265
|
-
var import_cookie_parser = __toESM(require("cookie-parser"));
|
|
266
|
-
var import_crypto2 = require("crypto");
|
|
267
|
-
var express = __toESM(require("express"));
|
|
268
|
-
var import_fs4 = __toESM(require("fs"));
|
|
269
|
-
var import_path5 = __toESM(require("path"));
|
|
270
|
-
var import_pg3 = __toESM(require("pg"));
|
|
271
|
-
var prettier3 = __toESM(require("prettier"));
|
|
535
|
+
// src/restura/generators/apiGenerator.ts
|
|
536
|
+
var import_core_utils = require("@redskytech/core-utils");
|
|
537
|
+
var import_prettier = __toESM(require("prettier"));
|
|
272
538
|
|
|
273
539
|
// src/restura/sql/SqlUtils.ts
|
|
274
540
|
var SqlUtils = class _SqlUtils {
|
|
@@ -296,7 +562,7 @@ var SqlUtils = class _SqlUtils {
|
|
|
296
562
|
}
|
|
297
563
|
};
|
|
298
564
|
|
|
299
|
-
// src/restura/ResponseValidator.ts
|
|
565
|
+
// src/restura/validators/ResponseValidator.ts
|
|
300
566
|
var ResponseValidator = class _ResponseValidator {
|
|
301
567
|
constructor(schema) {
|
|
302
568
|
this.database = schema.database;
|
|
@@ -445,9 +711,7 @@ var ResponseValidator = class _ResponseValidator {
|
|
|
445
711
|
}
|
|
446
712
|
};
|
|
447
713
|
|
|
448
|
-
// src/restura/apiGenerator.ts
|
|
449
|
-
var import_core_utils = require("@redskytech/core-utils");
|
|
450
|
-
var import_prettier = __toESM(require("prettier"));
|
|
714
|
+
// src/restura/generators/apiGenerator.ts
|
|
451
715
|
var ApiTree = class _ApiTree {
|
|
452
716
|
constructor(namespace, database) {
|
|
453
717
|
this.database = database;
|
|
@@ -600,8 +864,9 @@ var ApiTree = class _ApiTree {
|
|
|
600
864
|
function pathToNamespaces(path5) {
|
|
601
865
|
return path5.split("/").map((e) => import_core_utils.StringUtils.toPascalCasing(e)).filter((e) => e);
|
|
602
866
|
}
|
|
603
|
-
function apiGenerator(schema
|
|
604
|
-
let apiString = `/** Auto generated file
|
|
867
|
+
function apiGenerator(schema) {
|
|
868
|
+
let apiString = `/** Auto generated file. DO NOT MODIFY **/
|
|
869
|
+
`;
|
|
605
870
|
const rootNamespace = ApiTree.createRootNode(schema.database);
|
|
606
871
|
for (const endpoint of schema.endpoints) {
|
|
607
872
|
const endpointNamespaces = pathToNamespaces(endpoint.baseUrl);
|
|
@@ -631,71 +896,11 @@ function apiGenerator(schema, schemaHash) {
|
|
|
631
896
|
}));
|
|
632
897
|
}
|
|
633
898
|
|
|
634
|
-
// src/restura/
|
|
635
|
-
var import_fs = __toESM(require("fs"));
|
|
636
|
-
var import_path = __toESM(require("path"));
|
|
637
|
-
var import_bluebird = __toESM(require("bluebird"));
|
|
638
|
-
var import_internal2 = require("@restura/internal");
|
|
639
|
-
var CustomApiFactory = class {
|
|
640
|
-
constructor() {
|
|
641
|
-
this.customApis = {};
|
|
642
|
-
}
|
|
643
|
-
async loadApiFiles(baseFolderPath) {
|
|
644
|
-
const apiVersions = ["v1"];
|
|
645
|
-
for (const apiVersion of apiVersions) {
|
|
646
|
-
const apiVersionFolderPath = import_path.default.join(baseFolderPath, apiVersion);
|
|
647
|
-
const directoryExists = await import_internal2.fileUtils.existDir(apiVersionFolderPath);
|
|
648
|
-
if (!directoryExists) continue;
|
|
649
|
-
await this.addDirectory(apiVersionFolderPath, apiVersion);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
getCustomApi(customApiName) {
|
|
653
|
-
return this.customApis[customApiName];
|
|
654
|
-
}
|
|
655
|
-
async addDirectory(directoryPath, apiVersion) {
|
|
656
|
-
var _a2;
|
|
657
|
-
const entries = await import_fs.default.promises.readdir(directoryPath, {
|
|
658
|
-
withFileTypes: true
|
|
659
|
-
});
|
|
660
|
-
const isTsx2 = (_a2 = process.argv[1]) == null ? void 0 : _a2.endsWith(".ts");
|
|
661
|
-
const isTsNode2 = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
|
|
662
|
-
const extension = isTsx2 || isTsNode2 ? "ts" : "js";
|
|
663
|
-
const shouldEndWith = `.api.${apiVersion}.${extension}`;
|
|
664
|
-
await import_bluebird.default.map(entries, async (entry) => {
|
|
665
|
-
if (entry.isFile()) {
|
|
666
|
-
if (entry.name.endsWith(shouldEndWith) === false) return;
|
|
667
|
-
try {
|
|
668
|
-
const importPath = `${import_path.default.join(directoryPath, entry.name)}`;
|
|
669
|
-
const ApiImport = await import(importPath);
|
|
670
|
-
const customApiClass = new ApiImport.default();
|
|
671
|
-
logger.info(`Registering custom API: ${ApiImport.default.name}`);
|
|
672
|
-
this.bindMethodsToInstance(customApiClass);
|
|
673
|
-
this.customApis[ApiImport.default.name] = customApiClass;
|
|
674
|
-
} catch (e) {
|
|
675
|
-
console.error(e);
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
});
|
|
679
|
-
}
|
|
680
|
-
bindMethodsToInstance(instance) {
|
|
681
|
-
const proto = Object.getPrototypeOf(instance);
|
|
682
|
-
Object.getOwnPropertyNames(proto).forEach((key) => {
|
|
683
|
-
const property = instance[key];
|
|
684
|
-
if (typeof property === "function" && key !== "constructor") {
|
|
685
|
-
instance[key] = property.bind(instance);
|
|
686
|
-
}
|
|
687
|
-
});
|
|
688
|
-
}
|
|
689
|
-
};
|
|
690
|
-
var customApiFactory = new CustomApiFactory();
|
|
691
|
-
var customApiFactory_default = customApiFactory;
|
|
692
|
-
|
|
693
|
-
// src/restura/customTypeValidationGenerator.ts
|
|
899
|
+
// src/restura/generators/customTypeValidationGenerator.ts
|
|
694
900
|
var import_fs2 = __toESM(require("fs"));
|
|
695
|
-
var TJS = __toESM(require("typescript-json-schema"));
|
|
696
901
|
var import_path2 = __toESM(require("path"));
|
|
697
902
|
var import_tmp = __toESM(require("tmp"));
|
|
698
|
-
var
|
|
903
|
+
var TJS = __toESM(require("typescript-json-schema"));
|
|
699
904
|
function customTypeValidationGenerator(currentSchema) {
|
|
700
905
|
const schemaObject = {};
|
|
701
906
|
const customInterfaceNames = currentSchema.customTypes.match(new RegExp("(?<=interface\\s)(\\w+)|(?<=type\\s)(\\w+)", "g"));
|
|
@@ -705,13 +910,14 @@ function customTypeValidationGenerator(currentSchema) {
|
|
|
705
910
|
const compilerOptions = {
|
|
706
911
|
strictNullChecks: true,
|
|
707
912
|
skipLibCheck: true
|
|
913
|
+
// Needed if we are processing ES modules
|
|
708
914
|
};
|
|
709
915
|
const program = TJS.getProgramFromFiles(
|
|
710
916
|
[
|
|
711
917
|
(0, import_path2.resolve)(temporaryFile.name),
|
|
712
|
-
|
|
713
|
-
import_path2.default.join(
|
|
714
|
-
import_path2.default.join(
|
|
918
|
+
import_path2.default.join(restura.resturaConfig.generatedTypesPath, "restura.d.ts"),
|
|
919
|
+
import_path2.default.join(restura.resturaConfig.generatedTypesPath, "models.d.ts"),
|
|
920
|
+
import_path2.default.join(restura.resturaConfig.generatedTypesPath, "api.d.ts")
|
|
715
921
|
],
|
|
716
922
|
compilerOptions
|
|
717
923
|
);
|
|
@@ -725,6 +931,61 @@ function customTypeValidationGenerator(currentSchema) {
|
|
|
725
931
|
return schemaObject;
|
|
726
932
|
}
|
|
727
933
|
|
|
934
|
+
// src/restura/generators/modelGenerator.ts
|
|
935
|
+
var import_core_utils2 = require("@redskytech/core-utils");
|
|
936
|
+
var import_prettier2 = __toESM(require("prettier"));
|
|
937
|
+
function modelGenerator(schema) {
|
|
938
|
+
let modelString = `/** Auto generated file. DO NOT MODIFY **/
|
|
939
|
+
|
|
940
|
+
`;
|
|
941
|
+
modelString += `declare namespace Model {
|
|
942
|
+
`;
|
|
943
|
+
for (const table of schema.database) {
|
|
944
|
+
modelString += convertTable(table);
|
|
945
|
+
}
|
|
946
|
+
modelString += `}`;
|
|
947
|
+
return import_prettier2.default.format(modelString, __spreadValues({
|
|
948
|
+
parser: "typescript"
|
|
949
|
+
}, {
|
|
950
|
+
trailingComma: "none",
|
|
951
|
+
tabWidth: 4,
|
|
952
|
+
useTabs: true,
|
|
953
|
+
endOfLine: "lf",
|
|
954
|
+
printWidth: 120,
|
|
955
|
+
singleQuote: true
|
|
956
|
+
}));
|
|
957
|
+
}
|
|
958
|
+
function convertTable(table) {
|
|
959
|
+
let modelString = ` export interface ${import_core_utils2.StringUtils.capitalizeFirst(table.name)} {
|
|
960
|
+
`;
|
|
961
|
+
for (const column of table.columns) {
|
|
962
|
+
modelString += ` ${column.name}${column.isNullable ? "?" : ""}: ${SqlUtils.convertDatabaseTypeToTypescript(column.type, column.value)};
|
|
963
|
+
`;
|
|
964
|
+
}
|
|
965
|
+
modelString += ` }
|
|
966
|
+
`;
|
|
967
|
+
return modelString;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// src/restura/generators/resturaGlobalTypesGenerator.ts
|
|
971
|
+
function resturaGlobalTypesGenerator() {
|
|
972
|
+
return `/** Auto generated file. DO NOT MODIFY **/
|
|
973
|
+
/** This file contains types that may be used in the CustomTypes of Restura **/
|
|
974
|
+
/** For example export interface MyPagedQuery extends Restura.PageQuery { } **/
|
|
975
|
+
|
|
976
|
+
declare namespace Restura {
|
|
977
|
+
export type StandardOrderTypes = 'ASC' | 'DESC' | 'RAND' | 'NONE';
|
|
978
|
+
export interface PageQuery {
|
|
979
|
+
page?: number;
|
|
980
|
+
perPage?: number;
|
|
981
|
+
sortBy?: string;
|
|
982
|
+
sortOrder?: StandardOrderTypes;
|
|
983
|
+
filter?: string;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
`;
|
|
987
|
+
}
|
|
988
|
+
|
|
728
989
|
// src/restura/middleware/addApiResponseFunctions.ts
|
|
729
990
|
function addApiResponseFunctions(req, res, next) {
|
|
730
991
|
res.sendData = function(data, statusCode = 200) {
|
|
@@ -763,10 +1024,35 @@ function authenticateUser(applicationAuthenticateHandler) {
|
|
|
763
1024
|
};
|
|
764
1025
|
}
|
|
765
1026
|
|
|
766
|
-
// src/restura/
|
|
1027
|
+
// src/restura/middleware/getMulterUpload.ts
|
|
1028
|
+
var import_multer = __toESM(require("multer"));
|
|
1029
|
+
var os = __toESM(require("os"));
|
|
1030
|
+
var import_path3 = require("path");
|
|
1031
|
+
var OneHundredMB = 100 * 1024 * 1024;
|
|
1032
|
+
var commonUpload = null;
|
|
1033
|
+
var getMulterUpload = (directory) => {
|
|
1034
|
+
if (commonUpload) return commonUpload;
|
|
1035
|
+
const storage = import_multer.default.diskStorage({
|
|
1036
|
+
destination: directory || os.tmpdir(),
|
|
1037
|
+
filename: function(request, file, cb) {
|
|
1038
|
+
const extension = (0, import_path3.extname)(file.originalname);
|
|
1039
|
+
const uniqueName = Date.now() + "-" + Math.round(Math.random() * 1e3);
|
|
1040
|
+
cb(null, `${uniqueName}${extension}`);
|
|
1041
|
+
}
|
|
1042
|
+
});
|
|
1043
|
+
commonUpload = (0, import_multer.default)({
|
|
1044
|
+
storage,
|
|
1045
|
+
limits: {
|
|
1046
|
+
fileSize: OneHundredMB
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
return commonUpload;
|
|
1050
|
+
};
|
|
1051
|
+
|
|
1052
|
+
// src/restura/schemas/resturaSchema.ts
|
|
767
1053
|
var import_zod3 = require("zod");
|
|
768
1054
|
|
|
769
|
-
// src/restura/
|
|
1055
|
+
// src/restura/schemas/validatorDataSchema.ts
|
|
770
1056
|
var import_zod2 = require("zod");
|
|
771
1057
|
var validatorDataSchemeValue = import_zod2.z.union([import_zod2.z.string(), import_zod2.z.array(import_zod2.z.string()), import_zod2.z.number(), import_zod2.z.array(import_zod2.z.number())]);
|
|
772
1058
|
var validatorDataSchema = import_zod2.z.object({
|
|
@@ -774,7 +1060,7 @@ var validatorDataSchema = import_zod2.z.object({
|
|
|
774
1060
|
value: validatorDataSchemeValue
|
|
775
1061
|
}).strict();
|
|
776
1062
|
|
|
777
|
-
// src/restura/
|
|
1063
|
+
// src/restura/schemas/resturaSchema.ts
|
|
778
1064
|
var orderBySchema = import_zod3.z.object({
|
|
779
1065
|
columnName: import_zod3.z.string(),
|
|
780
1066
|
order: import_zod3.z.enum(["ASC", "DESC"]),
|
|
@@ -1021,7 +1307,7 @@ var endpointDataSchema = import_zod3.z.object({
|
|
|
1021
1307
|
baseUrl: import_zod3.z.string(),
|
|
1022
1308
|
routes: import_zod3.z.array(import_zod3.z.union([standardRouteSchema, customRouteSchema]))
|
|
1023
1309
|
}).strict();
|
|
1024
|
-
var
|
|
1310
|
+
var resturaSchema = import_zod3.z.object({
|
|
1025
1311
|
database: import_zod3.z.array(tableDataSchema),
|
|
1026
1312
|
endpoints: import_zod3.z.array(endpointDataSchema),
|
|
1027
1313
|
globalParams: import_zod3.z.array(import_zod3.z.string()),
|
|
@@ -1030,7 +1316,7 @@ var resturaZodSchema = import_zod3.z.object({
|
|
|
1030
1316
|
}).strict();
|
|
1031
1317
|
async function isSchemaValid(schemaToCheck) {
|
|
1032
1318
|
try {
|
|
1033
|
-
|
|
1319
|
+
resturaSchema.parse(schemaToCheck);
|
|
1034
1320
|
return true;
|
|
1035
1321
|
} catch (error) {
|
|
1036
1322
|
logger.error(error);
|
|
@@ -1038,8 +1324,8 @@ async function isSchemaValid(schemaToCheck) {
|
|
|
1038
1324
|
}
|
|
1039
1325
|
}
|
|
1040
1326
|
|
|
1041
|
-
// src/restura/
|
|
1042
|
-
var
|
|
1327
|
+
// src/restura/validators/requestValidator.ts
|
|
1328
|
+
var import_core_utils3 = require("@redskytech/core-utils");
|
|
1043
1329
|
var import_jsonschema = __toESM(require("jsonschema"));
|
|
1044
1330
|
var import_zod4 = require("zod");
|
|
1045
1331
|
|
|
@@ -1055,8 +1341,8 @@ function addQuotesToStrings(variable) {
|
|
|
1055
1341
|
}
|
|
1056
1342
|
}
|
|
1057
1343
|
|
|
1058
|
-
// src/restura/
|
|
1059
|
-
function
|
|
1344
|
+
// src/restura/validators/requestValidator.ts
|
|
1345
|
+
function requestValidator(req, routeData, validationSchema) {
|
|
1060
1346
|
const requestData = getRequestData(req);
|
|
1061
1347
|
req.data = requestData;
|
|
1062
1348
|
if (routeData.request === void 0) {
|
|
@@ -1178,7 +1464,7 @@ function performMaxCheck(requestValue, validator, requestParamName) {
|
|
|
1178
1464
|
);
|
|
1179
1465
|
}
|
|
1180
1466
|
function performOneOfCheck(requestValue, validator, requestParamName) {
|
|
1181
|
-
if (!
|
|
1467
|
+
if (!import_core_utils3.ObjectUtils.isArrayWithData(validator.value))
|
|
1182
1468
|
throw new RsError("SCHEMA_ERROR", `Schema validator value (${validator.value}) is not of type array`);
|
|
1183
1469
|
if (typeof requestValue === "object")
|
|
1184
1470
|
throw new RsError("BAD_REQUEST", `Request param (${requestParamName}) is not of type string or number`);
|
|
@@ -1207,11 +1493,11 @@ function getRequestData(req) {
|
|
|
1207
1493
|
if (isNaN(Number(value))) continue;
|
|
1208
1494
|
attrList.push(Number(value));
|
|
1209
1495
|
}
|
|
1210
|
-
if (
|
|
1496
|
+
if (import_core_utils3.ObjectUtils.isArrayWithData(attrList)) {
|
|
1211
1497
|
bodyData[attr] = attrList;
|
|
1212
1498
|
}
|
|
1213
1499
|
} else {
|
|
1214
|
-
bodyData[attr] =
|
|
1500
|
+
bodyData[attr] = import_core_utils3.ObjectUtils.safeParse(bodyData[attr]);
|
|
1215
1501
|
if (isNaN(Number(bodyData[attr]))) continue;
|
|
1216
1502
|
bodyData[attr] = Number(bodyData[attr]);
|
|
1217
1503
|
}
|
|
@@ -1224,7 +1510,7 @@ function getRequestData(req) {
|
|
|
1224
1510
|
async function schemaValidation(req, res, next) {
|
|
1225
1511
|
req.data = getRequestData(req);
|
|
1226
1512
|
try {
|
|
1227
|
-
|
|
1513
|
+
resturaSchema.parse(req.data);
|
|
1228
1514
|
next();
|
|
1229
1515
|
} catch (error) {
|
|
1230
1516
|
logger.error(error);
|
|
@@ -1232,40 +1518,20 @@ async function schemaValidation(req, res, next) {
|
|
|
1232
1518
|
}
|
|
1233
1519
|
}
|
|
1234
1520
|
|
|
1235
|
-
// src/restura/
|
|
1236
|
-
var
|
|
1237
|
-
var
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
}, {
|
|
1250
|
-
trailingComma: "none",
|
|
1251
|
-
tabWidth: 4,
|
|
1252
|
-
useTabs: true,
|
|
1253
|
-
endOfLine: "lf",
|
|
1254
|
-
printWidth: 120,
|
|
1255
|
-
singleQuote: true
|
|
1256
|
-
}));
|
|
1257
|
-
}
|
|
1258
|
-
function convertTable(table) {
|
|
1259
|
-
let modelString = ` export interface ${import_core_utils3.StringUtils.capitalizeFirst(table.name)} {
|
|
1260
|
-
`;
|
|
1261
|
-
for (const column of table.columns) {
|
|
1262
|
-
modelString += ` ${column.name}${column.isNullable ? "?" : ""}: ${SqlUtils.convertDatabaseTypeToTypescript(column.type, column.value)};
|
|
1263
|
-
`;
|
|
1264
|
-
}
|
|
1265
|
-
modelString += ` }
|
|
1266
|
-
`;
|
|
1267
|
-
return modelString;
|
|
1268
|
-
}
|
|
1521
|
+
// src/restura/schemas/resturaConfigSchema.ts
|
|
1522
|
+
var import_zod5 = require("zod");
|
|
1523
|
+
var _a;
|
|
1524
|
+
var isTsx = (_a = process.argv[1]) == null ? void 0 : _a.endsWith(".ts");
|
|
1525
|
+
var isTsNode = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
|
|
1526
|
+
var customApiFolderPath = isTsx || isTsNode ? "/src/api" : "/dist/api";
|
|
1527
|
+
var resturaConfigSchema = import_zod5.z.object({
|
|
1528
|
+
authToken: import_zod5.z.string().min(1, "Missing Restura Auth Token"),
|
|
1529
|
+
sendErrorStackTrace: import_zod5.z.boolean().default(false),
|
|
1530
|
+
schemaFilePath: import_zod5.z.string().default(process.cwd() + "/restura.schema.json"),
|
|
1531
|
+
customApiFolderPath: import_zod5.z.string().default(process.cwd() + customApiFolderPath),
|
|
1532
|
+
generatedTypesPath: import_zod5.z.string().default(process.cwd() + "/src/@types"),
|
|
1533
|
+
fileTempCachePath: import_zod5.z.string().optional()
|
|
1534
|
+
});
|
|
1269
1535
|
|
|
1270
1536
|
// src/restura/sql/PsqlEngine.ts
|
|
1271
1537
|
var import_core_utils5 = require("@redskytech/core-utils");
|
|
@@ -1277,6 +1543,7 @@ var import_pg2 = __toESM(require("pg"));
|
|
|
1277
1543
|
var import_pg = __toESM(require("pg"));
|
|
1278
1544
|
|
|
1279
1545
|
// src/restura/sql/PsqlConnection.ts
|
|
1546
|
+
var import_crypto = __toESM(require("crypto"));
|
|
1280
1547
|
var import_pg_format2 = __toESM(require("pg-format"));
|
|
1281
1548
|
|
|
1282
1549
|
// src/restura/sql/PsqlUtils.ts
|
|
@@ -1329,7 +1596,6 @@ function SQL(strings, ...values) {
|
|
|
1329
1596
|
}
|
|
1330
1597
|
|
|
1331
1598
|
// src/restura/sql/PsqlConnection.ts
|
|
1332
|
-
var import_crypto = __toESM(require("crypto"));
|
|
1333
1599
|
var PsqlConnection = class {
|
|
1334
1600
|
constructor() {
|
|
1335
1601
|
this.instanceId = import_crypto.default.randomUUID();
|
|
@@ -1517,233 +1783,106 @@ var SqlEngine = class {
|
|
|
1517
1783
|
|
|
1518
1784
|
// src/restura/sql/filterPsqlParser.ts
|
|
1519
1785
|
var import_pegjs = __toESM(require("pegjs"));
|
|
1520
|
-
var filterSqlGrammar = `
|
|
1521
|
-
{
|
|
1522
|
-
// ported from pg-format but intentionally will add double quotes to every column
|
|
1523
|
-
function quoteSqlIdentity(value) {
|
|
1524
|
-
if (value === undefined || value === null) {
|
|
1525
|
-
throw new Error('SQL identifier cannot be null or undefined');
|
|
1526
|
-
} else if (value === false) {
|
|
1527
|
-
return '"f"';
|
|
1528
|
-
} else if (value === true) {
|
|
1529
|
-
return '"t"';
|
|
1530
|
-
} else if (value instanceof Date) {
|
|
1531
|
-
// return '"' + formatDate(value.toISOString()) + '"';
|
|
1532
|
-
} else if (value instanceof Buffer) {
|
|
1533
|
-
throw new Error('SQL identifier cannot be a buffer');
|
|
1534
|
-
} else if (Array.isArray(value) === true) {
|
|
1535
|
-
var temp = [];
|
|
1536
|
-
for (var i = 0; i < value.length; i++) {
|
|
1537
|
-
if (Array.isArray(value[i]) === true) {
|
|
1538
|
-
throw new Error('Nested array to grouped list conversion is not supported for SQL identifier');
|
|
1539
|
-
} else {
|
|
1540
|
-
// temp.push(quoteIdent(value[i]));
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
|
-
return temp.toString();
|
|
1544
|
-
} else if (value === Object(value)) {
|
|
1545
|
-
throw new Error('SQL identifier cannot be an object');
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
var ident = value.toString().slice(0); // create copy
|
|
1549
|
-
|
|
1550
|
-
// do not quote a valid, unquoted identifier
|
|
1551
|
-
// if (/^[a-z_][a-z0-9_$]*$/.test(ident) === true && isReserved(ident) === false) {
|
|
1552
|
-
// return ident;
|
|
1553
|
-
// }
|
|
1554
|
-
|
|
1555
|
-
var quoted = '"';
|
|
1556
|
-
|
|
1557
|
-
for (var i = 0; i < ident.length; i++) {
|
|
1558
|
-
var c = ident[i];
|
|
1559
|
-
if (c === '"') {
|
|
1560
|
-
quoted += c + c;
|
|
1561
|
-
} else {
|
|
1562
|
-
quoted += c;
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
quoted += '"';
|
|
1567
|
-
|
|
1568
|
-
return quoted;
|
|
1569
|
-
};
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
start = expressionList
|
|
1573
|
-
|
|
1574
|
-
_ = [ \\t\\r\\n]* // Matches spaces, tabs, and line breaks
|
|
1575
|
-
|
|
1576
|
-
expressionList =
|
|
1577
|
-
leftExpression:expression _ operator:operator _ rightExpression:expressionList
|
|
1578
|
-
{ return \`\${leftExpression} \${operator} \${rightExpression}\`;}
|
|
1579
|
-
/ expression
|
|
1580
|
-
|
|
1581
|
-
expression =
|
|
1582
|
-
negate:negate? _ "(" _ "column" _ ":" column:column _ ","? _ value:value? ","? _ type:type? _ ")"_
|
|
1583
|
-
{return \`\${negate? " NOT " : ""}(\${type? type(column, value) : \`\${column} = \${format.literal(value)}\`})\`;}
|
|
1584
|
-
/
|
|
1585
|
-
negate:negate?"("expression:expressionList")" { return \`\${negate? " NOT " : ""}(\${expression})\`; }
|
|
1586
|
-
|
|
1587
|
-
negate = "!"
|
|
1588
|
-
|
|
1589
|
-
operator = "and"i / "or"i
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
column = left:text "." right:text { return \`\${quoteSqlIdentity(left)}.\${quoteSqlIdentity(right)}\`; }
|
|
1593
|
-
/
|
|
1594
|
-
text:text { return quoteSqlIdentity(text); }
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
text = text:[a-z0-9 \\t\\r\\n\\-_:@]i+ { return text.join(""); }
|
|
1598
|
-
|
|
1599
|
-
type = "type" _ ":" _ type:typeString { return type; }
|
|
1600
|
-
typeString = text:"startsWith" { return function(column, value) { return \`\${column} ILIKE '\${format.literal(value).slice(1,-1)}%'\`; } } /
|
|
1601
|
-
text:"endsWith" { return function(column, value) { return \`\${column} ILIKE '%\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1602
|
-
text:"contains" { return function(column, value) { return \`\${column} ILIKE '%\${format.literal(value).slice(1,-1)}%'\`; } } /
|
|
1603
|
-
text:"exact" { return function(column, value) { return \`\${column} = '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1604
|
-
text:"greaterThanEqual" { return function(column, value) { return \`\${column} >= '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1605
|
-
text:"greaterThan" { return function(column, value) { return \`\${column} > '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1606
|
-
text:"lessThanEqual" { return function(column, value) { return \`\${column} <= '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1607
|
-
text:"lessThan" { return function(column, value) { return \`\${column} < '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1608
|
-
text:"isNull" { return function(column, value) { return \`isNull(\${column})\`; } }
|
|
1609
|
-
|
|
1610
|
-
value = "value" _ ":" value:text { return value; }
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
`;
|
|
1614
|
-
var filterPsqlParser = import_pegjs.default.generate(filterSqlGrammar, {
|
|
1615
|
-
format: "commonjs",
|
|
1616
|
-
dependencies: { format: "pg-format" }
|
|
1617
|
-
});
|
|
1618
|
-
var filterPsqlParser_default = filterPsqlParser;
|
|
1619
|
-
|
|
1620
|
-
// src/restura/eventManager.ts
|
|
1621
|
-
var import_bluebird2 = __toESM(require("bluebird"));
|
|
1622
|
-
var EventManager = class {
|
|
1623
|
-
constructor() {
|
|
1624
|
-
this.actionHandlers = {
|
|
1625
|
-
DATABASE_ROW_DELETE: [],
|
|
1626
|
-
DATABASE_ROW_INSERT: [],
|
|
1627
|
-
DATABASE_COLUMN_UPDATE: []
|
|
1628
|
-
};
|
|
1629
|
-
}
|
|
1630
|
-
addRowInsertHandler(onInsert, filter) {
|
|
1631
|
-
this.actionHandlers.DATABASE_ROW_INSERT.push({
|
|
1632
|
-
callback: onInsert,
|
|
1633
|
-
filter
|
|
1634
|
-
});
|
|
1635
|
-
}
|
|
1636
|
-
addColumnChangeHandler(onUpdate, filter) {
|
|
1637
|
-
this.actionHandlers.DATABASE_COLUMN_UPDATE.push({
|
|
1638
|
-
callback: onUpdate,
|
|
1639
|
-
filter
|
|
1640
|
-
});
|
|
1641
|
-
}
|
|
1642
|
-
addRowDeleteHandler(onDelete, filter) {
|
|
1643
|
-
this.actionHandlers.DATABASE_ROW_DELETE.push({
|
|
1644
|
-
callback: onDelete,
|
|
1645
|
-
filter
|
|
1646
|
-
});
|
|
1647
|
-
}
|
|
1648
|
-
async fireActionFromDbTrigger(sqlMutationData, result) {
|
|
1649
|
-
if (sqlMutationData.mutationType === "INSERT") {
|
|
1650
|
-
await this.fireInsertActions(sqlMutationData, result);
|
|
1651
|
-
} else if (sqlMutationData.mutationType === "UPDATE") {
|
|
1652
|
-
await this.fireUpdateActions(sqlMutationData, result);
|
|
1653
|
-
} else if (sqlMutationData.mutationType === "DELETE") {
|
|
1654
|
-
await this.fireDeleteActions(sqlMutationData, result);
|
|
1655
|
-
}
|
|
1656
|
-
}
|
|
1657
|
-
async fireInsertActions(data, triggerResult) {
|
|
1658
|
-
await import_bluebird2.default.map(
|
|
1659
|
-
this.actionHandlers.DATABASE_ROW_INSERT,
|
|
1660
|
-
({ callback, filter }) => {
|
|
1661
|
-
if (!this.hasHandlersForEventType("DATABASE_ROW_INSERT", filter, triggerResult)) return;
|
|
1662
|
-
const insertData = {
|
|
1663
|
-
tableName: triggerResult.table,
|
|
1664
|
-
insertId: triggerResult.record.id,
|
|
1665
|
-
insertObject: triggerResult.record,
|
|
1666
|
-
queryMetadata: data.queryMetadata
|
|
1667
|
-
};
|
|
1668
|
-
callback(insertData, data.queryMetadata);
|
|
1669
|
-
},
|
|
1670
|
-
{ concurrency: 10 }
|
|
1671
|
-
);
|
|
1672
|
-
}
|
|
1673
|
-
async fireDeleteActions(data, triggerResult) {
|
|
1674
|
-
await import_bluebird2.default.map(
|
|
1675
|
-
this.actionHandlers.DATABASE_ROW_DELETE,
|
|
1676
|
-
({ callback, filter }) => {
|
|
1677
|
-
if (!this.hasHandlersForEventType("DATABASE_ROW_DELETE", filter, triggerResult)) return;
|
|
1678
|
-
const deleteData = {
|
|
1679
|
-
tableName: triggerResult.table,
|
|
1680
|
-
deletedRow: triggerResult.previousRecord,
|
|
1681
|
-
queryMetadata: data.queryMetadata
|
|
1682
|
-
};
|
|
1683
|
-
callback(deleteData, data.queryMetadata);
|
|
1684
|
-
},
|
|
1685
|
-
{ concurrency: 10 }
|
|
1686
|
-
);
|
|
1687
|
-
}
|
|
1688
|
-
async fireUpdateActions(data, triggerResult) {
|
|
1689
|
-
await import_bluebird2.default.map(
|
|
1690
|
-
this.actionHandlers.DATABASE_COLUMN_UPDATE,
|
|
1691
|
-
({ callback, filter }) => {
|
|
1692
|
-
if (!this.hasHandlersForEventType("DATABASE_COLUMN_UPDATE", filter, triggerResult)) return;
|
|
1693
|
-
const columnChangeData = {
|
|
1694
|
-
tableName: triggerResult.table,
|
|
1695
|
-
rowId: triggerResult.record.id,
|
|
1696
|
-
newData: triggerResult.record,
|
|
1697
|
-
oldData: triggerResult.previousRecord,
|
|
1698
|
-
queryMetadata: data.queryMetadata
|
|
1699
|
-
};
|
|
1700
|
-
callback(columnChangeData, data.queryMetadata);
|
|
1701
|
-
},
|
|
1702
|
-
{ concurrency: 10 }
|
|
1703
|
-
);
|
|
1704
|
-
}
|
|
1705
|
-
hasHandlersForEventType(eventType, filter, triggerResult) {
|
|
1706
|
-
if (filter) {
|
|
1707
|
-
switch (eventType) {
|
|
1708
|
-
case "DATABASE_ROW_INSERT":
|
|
1709
|
-
case "DATABASE_ROW_DELETE":
|
|
1710
|
-
if (filter.tableName && filter.tableName !== triggerResult.table) return false;
|
|
1711
|
-
break;
|
|
1712
|
-
case "DATABASE_COLUMN_UPDATE":
|
|
1713
|
-
const filterColumnChange = filter;
|
|
1714
|
-
if (filterColumnChange.tableName !== filter.tableName) return false;
|
|
1715
|
-
if (!filterColumnChange.columns.some((item) => {
|
|
1716
|
-
const updatedColumns = Object.keys(
|
|
1717
|
-
changedValues(triggerResult.record, triggerResult.previousRecord)
|
|
1718
|
-
);
|
|
1719
|
-
return updatedColumns.includes(item);
|
|
1720
|
-
}))
|
|
1721
|
-
return false;
|
|
1722
|
-
break;
|
|
1723
|
-
}
|
|
1786
|
+
var filterSqlGrammar = `
|
|
1787
|
+
{
|
|
1788
|
+
// ported from pg-format but intentionally will add double quotes to every column
|
|
1789
|
+
function quoteSqlIdentity(value) {
|
|
1790
|
+
if (value === undefined || value === null) {
|
|
1791
|
+
throw new Error('SQL identifier cannot be null or undefined');
|
|
1792
|
+
} else if (value === false) {
|
|
1793
|
+
return '"f"';
|
|
1794
|
+
} else if (value === true) {
|
|
1795
|
+
return '"t"';
|
|
1796
|
+
} else if (value instanceof Date) {
|
|
1797
|
+
// return '"' + formatDate(value.toISOString()) + '"';
|
|
1798
|
+
} else if (value instanceof Buffer) {
|
|
1799
|
+
throw new Error('SQL identifier cannot be a buffer');
|
|
1800
|
+
} else if (Array.isArray(value) === true) {
|
|
1801
|
+
var temp = [];
|
|
1802
|
+
for (var i = 0; i < value.length; i++) {
|
|
1803
|
+
if (Array.isArray(value[i]) === true) {
|
|
1804
|
+
throw new Error('Nested array to grouped list conversion is not supported for SQL identifier');
|
|
1805
|
+
} else {
|
|
1806
|
+
// temp.push(quoteIdent(value[i]));
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
return temp.toString();
|
|
1810
|
+
} else if (value === Object(value)) {
|
|
1811
|
+
throw new Error('SQL identifier cannot be an object');
|
|
1724
1812
|
}
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1813
|
+
|
|
1814
|
+
var ident = value.toString().slice(0); // create copy
|
|
1815
|
+
|
|
1816
|
+
// do not quote a valid, unquoted identifier
|
|
1817
|
+
// if (/^[a-z_][a-z0-9_$]*$/.test(ident) === true && isReserved(ident) === false) {
|
|
1818
|
+
// return ident;
|
|
1819
|
+
// }
|
|
1820
|
+
|
|
1821
|
+
var quoted = '"';
|
|
1822
|
+
|
|
1823
|
+
for (var i = 0; i < ident.length; i++) {
|
|
1824
|
+
var c = ident[i];
|
|
1825
|
+
if (c === '"') {
|
|
1826
|
+
quoted += c + c;
|
|
1827
|
+
} else {
|
|
1828
|
+
quoted += c;
|
|
1738
1829
|
}
|
|
1739
|
-
} else {
|
|
1740
|
-
changed[i] = record[i];
|
|
1741
|
-
}
|
|
1742
1830
|
}
|
|
1743
|
-
|
|
1744
|
-
|
|
1831
|
+
|
|
1832
|
+
quoted += '"';
|
|
1833
|
+
|
|
1834
|
+
return quoted;
|
|
1835
|
+
};
|
|
1745
1836
|
}
|
|
1746
1837
|
|
|
1838
|
+
start = expressionList
|
|
1839
|
+
|
|
1840
|
+
_ = [ \\t\\r\\n]* // Matches spaces, tabs, and line breaks
|
|
1841
|
+
|
|
1842
|
+
expressionList =
|
|
1843
|
+
leftExpression:expression _ operator:operator _ rightExpression:expressionList
|
|
1844
|
+
{ return \`\${leftExpression} \${operator} \${rightExpression}\`;}
|
|
1845
|
+
/ expression
|
|
1846
|
+
|
|
1847
|
+
expression =
|
|
1848
|
+
negate:negate? _ "(" _ "column" _ ":" column:column _ ","? _ value:value? ","? _ type:type? _ ")"_
|
|
1849
|
+
{return \`\${negate? " NOT " : ""}(\${type? type(column, value) : \`\${column} = \${format.literal(value)}\`})\`;}
|
|
1850
|
+
/
|
|
1851
|
+
negate:negate?"("expression:expressionList")" { return \`\${negate? " NOT " : ""}(\${expression})\`; }
|
|
1852
|
+
|
|
1853
|
+
negate = "!"
|
|
1854
|
+
|
|
1855
|
+
operator = "and"i / "or"i
|
|
1856
|
+
|
|
1857
|
+
|
|
1858
|
+
column = left:text "." right:text { return \`\${quoteSqlIdentity(left)}.\${quoteSqlIdentity(right)}\`; }
|
|
1859
|
+
/
|
|
1860
|
+
text:text { return quoteSqlIdentity(text); }
|
|
1861
|
+
|
|
1862
|
+
|
|
1863
|
+
text = text:[a-z0-9 \\t\\r\\n\\-_:@]i+ { return text.join(""); }
|
|
1864
|
+
|
|
1865
|
+
type = "type" _ ":" _ type:typeString { return type; }
|
|
1866
|
+
typeString = text:"startsWith" { return function(column, value) { return \`\${column} ILIKE '\${format.literal(value).slice(1,-1)}%'\`; } } /
|
|
1867
|
+
text:"endsWith" { return function(column, value) { return \`\${column} ILIKE '%\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1868
|
+
text:"contains" { return function(column, value) { return \`\${column} ILIKE '%\${format.literal(value).slice(1,-1)}%'\`; } } /
|
|
1869
|
+
text:"exact" { return function(column, value) { return \`\${column} = '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1870
|
+
text:"greaterThanEqual" { return function(column, value) { return \`\${column} >= '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1871
|
+
text:"greaterThan" { return function(column, value) { return \`\${column} > '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1872
|
+
text:"lessThanEqual" { return function(column, value) { return \`\${column} <= '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1873
|
+
text:"lessThan" { return function(column, value) { return \`\${column} < '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1874
|
+
text:"isNull" { return function(column, value) { return \`isNull(\${column})\`; } }
|
|
1875
|
+
|
|
1876
|
+
value = "value" _ ":" value:text { return value; }
|
|
1877
|
+
|
|
1878
|
+
|
|
1879
|
+
`;
|
|
1880
|
+
var filterPsqlParser = import_pegjs.default.generate(filterSqlGrammar, {
|
|
1881
|
+
format: "commonjs",
|
|
1882
|
+
dependencies: { format: "pg-format" }
|
|
1883
|
+
});
|
|
1884
|
+
var filterPsqlParser_default = filterPsqlParser;
|
|
1885
|
+
|
|
1747
1886
|
// src/restura/sql/PsqlEngine.ts
|
|
1748
1887
|
var { Client } = import_pg2.default;
|
|
1749
1888
|
var systemUser = {
|
|
@@ -1772,7 +1911,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1772
1911
|
database: this.psqlConnectionPool.poolConfig.database,
|
|
1773
1912
|
password: this.psqlConnectionPool.poolConfig.password,
|
|
1774
1913
|
port: this.psqlConnectionPool.poolConfig.port,
|
|
1775
|
-
connectionTimeoutMillis:
|
|
1914
|
+
connectionTimeoutMillis: this.psqlConnectionPool.poolConfig.connectionTimeoutMillis
|
|
1776
1915
|
});
|
|
1777
1916
|
await this.triggerClient.connect();
|
|
1778
1917
|
const promises = [];
|
|
@@ -2308,121 +2447,6 @@ function schemaToPsqlType(column) {
|
|
|
2308
2447
|
return column.type;
|
|
2309
2448
|
}
|
|
2310
2449
|
|
|
2311
|
-
// src/restura/compareSchema.ts
|
|
2312
|
-
var import_lodash = __toESM(require("lodash.clonedeep"));
|
|
2313
|
-
var CompareSchema = class {
|
|
2314
|
-
async diffSchema(newSchema, latestSchema, psqlEngine) {
|
|
2315
|
-
const endPoints = this.diffEndPoints(newSchema.endpoints[0].routes, latestSchema.endpoints[0].routes);
|
|
2316
|
-
const globalParams = this.diffStringArray(newSchema.globalParams, latestSchema.globalParams);
|
|
2317
|
-
const roles = this.diffStringArray(newSchema.roles, latestSchema.roles);
|
|
2318
|
-
let commands = "";
|
|
2319
|
-
if (JSON.stringify(newSchema.database) !== JSON.stringify(latestSchema.database))
|
|
2320
|
-
commands = await psqlEngine.diffDatabaseToSchema(newSchema);
|
|
2321
|
-
const customTypes = newSchema.customTypes !== latestSchema.customTypes;
|
|
2322
|
-
const schemaPreview = { endPoints, globalParams, roles, commands, customTypes };
|
|
2323
|
-
return schemaPreview;
|
|
2324
|
-
}
|
|
2325
|
-
diffStringArray(newArray, originalArray) {
|
|
2326
|
-
const stringsDiff = [];
|
|
2327
|
-
const originalClone = new Set(originalArray);
|
|
2328
|
-
newArray.forEach((item) => {
|
|
2329
|
-
const originalIndex = originalClone.has(item);
|
|
2330
|
-
if (!originalIndex) {
|
|
2331
|
-
stringsDiff.push({
|
|
2332
|
-
name: item,
|
|
2333
|
-
changeType: "NEW"
|
|
2334
|
-
});
|
|
2335
|
-
} else {
|
|
2336
|
-
originalClone.delete(item);
|
|
2337
|
-
}
|
|
2338
|
-
});
|
|
2339
|
-
originalClone.forEach((item) => {
|
|
2340
|
-
stringsDiff.push({
|
|
2341
|
-
name: item,
|
|
2342
|
-
changeType: "DELETED"
|
|
2343
|
-
});
|
|
2344
|
-
});
|
|
2345
|
-
return stringsDiff;
|
|
2346
|
-
}
|
|
2347
|
-
diffEndPoints(newEndPoints, originalEndpoints) {
|
|
2348
|
-
const originalClone = (0, import_lodash.default)(originalEndpoints);
|
|
2349
|
-
const diffObj = [];
|
|
2350
|
-
newEndPoints.forEach((endPoint) => {
|
|
2351
|
-
const { path: path5, method } = endPoint;
|
|
2352
|
-
const endPointIndex = originalClone.findIndex((original) => {
|
|
2353
|
-
return original.path === endPoint.path && original.method === endPoint.method;
|
|
2354
|
-
});
|
|
2355
|
-
if (endPointIndex === -1) {
|
|
2356
|
-
diffObj.push({
|
|
2357
|
-
name: `${method} ${path5}`,
|
|
2358
|
-
changeType: "NEW"
|
|
2359
|
-
});
|
|
2360
|
-
} else {
|
|
2361
|
-
const original = originalClone.findIndex((original2) => {
|
|
2362
|
-
return this.compareEndPoints(endPoint, original2);
|
|
2363
|
-
});
|
|
2364
|
-
if (original === -1) {
|
|
2365
|
-
diffObj.push({
|
|
2366
|
-
name: `${method} ${path5}`,
|
|
2367
|
-
changeType: "MODIFIED"
|
|
2368
|
-
});
|
|
2369
|
-
}
|
|
2370
|
-
originalClone.splice(endPointIndex, 1);
|
|
2371
|
-
}
|
|
2372
|
-
});
|
|
2373
|
-
originalClone.forEach((original) => {
|
|
2374
|
-
const { path: path5, method } = original;
|
|
2375
|
-
diffObj.push({
|
|
2376
|
-
name: `${method} ${path5}`,
|
|
2377
|
-
changeType: "DELETED"
|
|
2378
|
-
});
|
|
2379
|
-
});
|
|
2380
|
-
return diffObj;
|
|
2381
|
-
}
|
|
2382
|
-
compareEndPoints(endPoint1, endPoint2) {
|
|
2383
|
-
return JSON.stringify(endPoint1) === JSON.stringify(endPoint2);
|
|
2384
|
-
}
|
|
2385
|
-
};
|
|
2386
|
-
__decorateClass([
|
|
2387
|
-
boundMethod
|
|
2388
|
-
], CompareSchema.prototype, "diffSchema", 1);
|
|
2389
|
-
__decorateClass([
|
|
2390
|
-
boundMethod
|
|
2391
|
-
], CompareSchema.prototype, "diffStringArray", 1);
|
|
2392
|
-
__decorateClass([
|
|
2393
|
-
boundMethod
|
|
2394
|
-
], CompareSchema.prototype, "diffEndPoints", 1);
|
|
2395
|
-
__decorateClass([
|
|
2396
|
-
boundMethod
|
|
2397
|
-
], CompareSchema.prototype, "compareEndPoints", 1);
|
|
2398
|
-
var compareSchema = new CompareSchema();
|
|
2399
|
-
var compareSchema_default = compareSchema;
|
|
2400
|
-
|
|
2401
|
-
// src/restura/middleware/getMulterUploadSingleton.ts
|
|
2402
|
-
var import_multer = __toESM(require("multer"));
|
|
2403
|
-
var import_path3 = require("path");
|
|
2404
|
-
var os = __toESM(require("os"));
|
|
2405
|
-
var OneHundredMB = 100 * 1024 * 1024;
|
|
2406
|
-
var commonUpload = null;
|
|
2407
|
-
var getMulterUploadSingleton = (directory) => {
|
|
2408
|
-
if (commonUpload) return commonUpload;
|
|
2409
|
-
const storage = import_multer.default.diskStorage({
|
|
2410
|
-
destination: directory || os.tmpdir(),
|
|
2411
|
-
filename: function(request, file, cb) {
|
|
2412
|
-
const extension = (0, import_path3.extname)(file.originalname);
|
|
2413
|
-
const uniqueName = Date.now() + "-" + Math.round(Math.random() * 1e3);
|
|
2414
|
-
cb(null, `${uniqueName}${extension}`);
|
|
2415
|
-
}
|
|
2416
|
-
});
|
|
2417
|
-
commonUpload = (0, import_multer.default)({
|
|
2418
|
-
storage,
|
|
2419
|
-
limits: {
|
|
2420
|
-
fileSize: OneHundredMB
|
|
2421
|
-
}
|
|
2422
|
-
});
|
|
2423
|
-
return commonUpload;
|
|
2424
|
-
};
|
|
2425
|
-
|
|
2426
2450
|
// src/restura/utils/TempCache.ts
|
|
2427
2451
|
var import_fs3 = __toESM(require("fs"));
|
|
2428
2452
|
var import_path4 = __toESM(require("path"));
|
|
@@ -2475,7 +2499,7 @@ var ResturaEngine = class {
|
|
|
2475
2499
|
*/
|
|
2476
2500
|
async init(app, authenticationHandler, psqlConnectionPool) {
|
|
2477
2501
|
this.resturaConfig = import_internal4.config.validate("restura", resturaConfigSchema);
|
|
2478
|
-
this.multerCommonUpload =
|
|
2502
|
+
this.multerCommonUpload = getMulterUpload(this.resturaConfig.fileTempCachePath);
|
|
2479
2503
|
new TempCache(this.resturaConfig.fileTempCachePath);
|
|
2480
2504
|
this.psqlConnectionPool = psqlConnectionPool;
|
|
2481
2505
|
this.psqlEngine = new PsqlEngine(this.psqlConnectionPool, true);
|
|
@@ -2543,10 +2567,7 @@ var ResturaEngine = class {
|
|
|
2543
2567
|
* @returns A promise that resolves when the API has been successfully generated and written to the output file.
|
|
2544
2568
|
*/
|
|
2545
2569
|
async generateApiFromSchema(outputFile, providedSchema) {
|
|
2546
|
-
import_fs4.default.writeFileSync(
|
|
2547
|
-
outputFile,
|
|
2548
|
-
await apiGenerator(providedSchema, await this.generateHashForSchema(providedSchema))
|
|
2549
|
-
);
|
|
2570
|
+
import_fs4.default.writeFileSync(outputFile, await apiGenerator(providedSchema));
|
|
2550
2571
|
}
|
|
2551
2572
|
/**
|
|
2552
2573
|
* Generates a model from the provided schema and writes it to the specified output file.
|
|
@@ -2556,10 +2577,15 @@ var ResturaEngine = class {
|
|
|
2556
2577
|
* @returns A promise that resolves when the model has been successfully written to the output file.
|
|
2557
2578
|
*/
|
|
2558
2579
|
async generateModelFromSchema(outputFile, providedSchema) {
|
|
2559
|
-
import_fs4.default.writeFileSync(
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2580
|
+
import_fs4.default.writeFileSync(outputFile, await modelGenerator(providedSchema));
|
|
2581
|
+
}
|
|
2582
|
+
/**
|
|
2583
|
+
* Generates the ambient module declaration for Restura global types and writes it to the specified output file.
|
|
2584
|
+
* These types are used sometimes in the CustomTypes
|
|
2585
|
+
* @param outputFile
|
|
2586
|
+
*/
|
|
2587
|
+
generateResturaGlobalTypes(outputFile) {
|
|
2588
|
+
import_fs4.default.writeFileSync(outputFile, resturaGlobalTypesGenerator());
|
|
2563
2589
|
}
|
|
2564
2590
|
/**
|
|
2565
2591
|
* Retrieves the latest file system schema for Restura.
|
|
@@ -2581,28 +2607,6 @@ var ResturaEngine = class {
|
|
|
2581
2607
|
}
|
|
2582
2608
|
return schema;
|
|
2583
2609
|
}
|
|
2584
|
-
/**
|
|
2585
|
-
* Asynchronously generates and retrieves hashes for the provided schema and related generated files.
|
|
2586
|
-
*
|
|
2587
|
-
* @param providedSchema - The schema for which hashes need to be generated.
|
|
2588
|
-
* @returns A promise that resolves to an object containing:
|
|
2589
|
-
* - `schemaHash`: The hash of the provided schema.
|
|
2590
|
-
* - `apiCreatedSchemaHash`: The hash extracted from the generated `api.d.ts` file.
|
|
2591
|
-
* - `modelCreatedSchemaHash`: The hash extracted from the generated `models.d.ts` file.
|
|
2592
|
-
*/
|
|
2593
|
-
async getHashes(providedSchema) {
|
|
2594
|
-
var _a2, _b, _c, _d;
|
|
2595
|
-
const schemaHash = await this.generateHashForSchema(providedSchema);
|
|
2596
|
-
const apiFile = import_fs4.default.readFileSync(import_path5.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"));
|
|
2597
|
-
const apiCreatedSchemaHash = (_b = (_a2 = apiFile.toString().match(/\((.*)\)/)) == null ? void 0 : _a2[1]) != null ? _b : "";
|
|
2598
|
-
const modelFile = import_fs4.default.readFileSync(import_path5.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"));
|
|
2599
|
-
const modelCreatedSchemaHash = (_d = (_c = modelFile.toString().match(/\((.*)\)/)) == null ? void 0 : _c[1]) != null ? _d : "";
|
|
2600
|
-
return {
|
|
2601
|
-
schemaHash,
|
|
2602
|
-
apiCreatedSchemaHash,
|
|
2603
|
-
modelCreatedSchemaHash
|
|
2604
|
-
};
|
|
2605
|
-
}
|
|
2606
2610
|
async reloadEndpoints() {
|
|
2607
2611
|
this.schema = await this.getLatestFileSystemSchema();
|
|
2608
2612
|
this.customTypeValidation = customTypeValidationGenerator(this.schema);
|
|
@@ -2634,27 +2638,7 @@ var ResturaEngine = class {
|
|
|
2634
2638
|
if (!import_fs4.default.existsSync(this.resturaConfig.generatedTypesPath)) {
|
|
2635
2639
|
import_fs4.default.mkdirSync(this.resturaConfig.generatedTypesPath, { recursive: true });
|
|
2636
2640
|
}
|
|
2637
|
-
|
|
2638
|
-
const hasModelsFile = import_fs4.default.existsSync(import_path5.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"));
|
|
2639
|
-
if (!hasApiFile) {
|
|
2640
|
-
await this.generateApiFromSchema(import_path5.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
|
|
2641
|
-
}
|
|
2642
|
-
if (!hasModelsFile) {
|
|
2643
|
-
await this.generateModelFromSchema(
|
|
2644
|
-
import_path5.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
|
|
2645
|
-
this.schema
|
|
2646
|
-
);
|
|
2647
|
-
}
|
|
2648
|
-
const hashes = await this.getHashes(this.schema);
|
|
2649
|
-
if (hashes.schemaHash !== hashes.apiCreatedSchemaHash) {
|
|
2650
|
-
await this.generateApiFromSchema(import_path5.default.join(this.resturaConfig.generatedTypesPath, "api.d.ts"), this.schema);
|
|
2651
|
-
}
|
|
2652
|
-
if (hashes.schemaHash !== hashes.modelCreatedSchemaHash) {
|
|
2653
|
-
await this.generateModelFromSchema(
|
|
2654
|
-
import_path5.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
|
|
2655
|
-
this.schema
|
|
2656
|
-
);
|
|
2657
|
-
}
|
|
2641
|
+
this.updateTypes();
|
|
2658
2642
|
}
|
|
2659
2643
|
resturaAuthentication(req, res, next) {
|
|
2660
2644
|
if (req.headers["x-auth-token"] !== this.resturaConfig.authToken) res.status(401).send("Unauthorized");
|
|
@@ -2686,6 +2670,7 @@ var ResturaEngine = class {
|
|
|
2686
2670
|
import_path5.default.join(this.resturaConfig.generatedTypesPath, "models.d.ts"),
|
|
2687
2671
|
this.schema
|
|
2688
2672
|
);
|
|
2673
|
+
this.generateResturaGlobalTypes(import_path5.default.join(this.resturaConfig.generatedTypesPath, "restura.d.ts"));
|
|
2689
2674
|
}
|
|
2690
2675
|
async getSchema(req, res) {
|
|
2691
2676
|
res.send({ data: this.schema });
|
|
@@ -2693,9 +2678,8 @@ var ResturaEngine = class {
|
|
|
2693
2678
|
async getSchemaAndTypes(req, res) {
|
|
2694
2679
|
try {
|
|
2695
2680
|
const schema = await this.getLatestFileSystemSchema();
|
|
2696
|
-
const
|
|
2697
|
-
const
|
|
2698
|
-
const modelsText = await modelGenerator(schema, schemaHash);
|
|
2681
|
+
const apiText = await apiGenerator(schema);
|
|
2682
|
+
const modelsText = await modelGenerator(schema);
|
|
2699
2683
|
res.send({ schema, api: apiText, models: modelsText });
|
|
2700
2684
|
} catch (err) {
|
|
2701
2685
|
res.status(400).send({ error: err });
|
|
@@ -2725,7 +2709,7 @@ var ResturaEngine = class {
|
|
|
2725
2709
|
const routeData = this.getRouteData(req.method, req.baseUrl, req.path);
|
|
2726
2710
|
this.validateAuthorization(req, routeData);
|
|
2727
2711
|
await this.getMulterFilesIfAny(req, res, routeData);
|
|
2728
|
-
|
|
2712
|
+
requestValidator(req, routeData, this.customTypeValidation);
|
|
2729
2713
|
if (this.isCustomRoute(routeData)) {
|
|
2730
2714
|
await this.runCustomRouteLogic(req, res, routeData);
|
|
2731
2715
|
return;
|
|
@@ -2765,19 +2749,6 @@ var ResturaEngine = class {
|
|
|
2765
2749
|
throw new RsError("NOT_FOUND", `API path ${routeData.path} not implemented ${functionName}`);
|
|
2766
2750
|
await customFunction(req, res, routeData);
|
|
2767
2751
|
}
|
|
2768
|
-
async generateHashForSchema(providedSchema) {
|
|
2769
|
-
const schemaPrettyStr = await prettier3.format(JSON.stringify(providedSchema), __spreadValues({
|
|
2770
|
-
parser: "json"
|
|
2771
|
-
}, {
|
|
2772
|
-
trailingComma: "none",
|
|
2773
|
-
tabWidth: 4,
|
|
2774
|
-
useTabs: true,
|
|
2775
|
-
endOfLine: "lf",
|
|
2776
|
-
printWidth: 120,
|
|
2777
|
-
singleQuote: true
|
|
2778
|
-
}));
|
|
2779
|
-
return (0, import_crypto2.createHash)("sha256").update(schemaPrettyStr).digest("hex");
|
|
2780
|
-
}
|
|
2781
2752
|
async storeFileSystemSchema() {
|
|
2782
2753
|
const schemaPrettyStr = await prettier3.format(JSON.stringify(this.schema), __spreadValues({
|
|
2783
2754
|
parser: "json"
|