@restura/core 0.2.1 → 1.0.0-beta.0

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.js CHANGED
@@ -1,39 +1,10 @@
1
1
  "use strict";
2
2
  var __create = Object.create;
3
3
  var __defProp = Object.defineProperty;
4
- var __defProps = Object.defineProperties;
5
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
8
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
6
  var __getProtoOf = Object.getPrototypeOf;
10
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
11
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
- var __spreadValues = (a, b) => {
14
- for (var prop in b || (b = {}))
15
- if (__hasOwnProp.call(b, prop))
16
- __defNormalProp(a, prop, b[prop]);
17
- if (__getOwnPropSymbols)
18
- for (var prop of __getOwnPropSymbols(b)) {
19
- if (__propIsEnum.call(b, prop))
20
- __defNormalProp(a, prop, b[prop]);
21
- }
22
- return a;
23
- };
24
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
- var __objRest = (source, exclude) => {
26
- var target = {};
27
- for (var prop in source)
28
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
29
- target[prop] = source[prop];
30
- if (source != null && __getOwnPropSymbols)
31
- for (var prop of __getOwnPropSymbols(source)) {
32
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
33
- target[prop] = source[prop];
34
- }
35
- return target;
36
- };
37
8
  var __export = (target, all) => {
38
9
  for (var name in all)
39
10
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -92,13 +63,12 @@ var import_winston = __toESM(require("winston"));
92
63
  var import_logform = require("logform");
93
64
 
94
65
  // src/logger/loggerConfigSchema.ts
95
- var import_zod = require("zod");
96
- var loggerConfigSchema = import_zod.z.object({
97
- level: import_zod.z.enum(["info", "warn", "error", "debug", "silly"]).default("info")
66
+ var import_v4 = require("zod/v4");
67
+ var loggerConfigSchema = import_v4.z.object({
68
+ level: import_v4.z.enum(["info", "warn", "error", "debug", "silly"]).default("info")
98
69
  });
99
70
 
100
71
  // src/logger/logger.ts
101
- var loggerConfig = import_internal.config.validate("logger", loggerConfigSchema);
102
72
  var consoleFormat = import_logform.format.combine(
103
73
  import_logform.format.timestamp({
104
74
  format: "YYYY-MM-DD HH:mm:ss.sss"
@@ -111,7 +81,7 @@ var consoleFormat = import_logform.format.combine(
111
81
  })
112
82
  );
113
83
  var logger = import_winston.default.createLogger({
114
- level: loggerConfig.level,
84
+ level: "info",
115
85
  format: import_logform.format.combine(
116
86
  import_logform.format.timestamp({
117
87
  format: "YYYY-MM-DD HH:mm:ss.sss"
@@ -119,29 +89,24 @@ var logger = import_winston.default.createLogger({
119
89
  import_logform.format.errors({ stack: true }),
120
90
  import_logform.format.json()
121
91
  ),
122
- //defaultMeta: { service: 'user-service' },
123
- transports: [
124
- //
125
- // - Write to all logs with level `info` and below to `combined.log`
126
- // - Write all logs error (and below) to `error.log`.
127
- // - Write all logs to standard out.
128
- //
129
- // new winston.transports.File({ filename: 'error.log', level: 'error' }),
130
- // new winston.transports.File({ filename: 'combined.log' }),
131
- new import_winston.default.transports.Console({ format: consoleFormat })
132
- ]
92
+ transports: [new import_winston.default.transports.Console({ format: consoleFormat })]
93
+ });
94
+ import_internal.config.validate("logger", loggerConfigSchema).then((loggerConfig) => {
95
+ if (loggerConfig.level) {
96
+ logger.level = loggerConfig.level;
97
+ }
98
+ }).catch((error) => {
99
+ logger.error("Failed to load logger config:", error);
133
100
  });
134
101
 
135
102
  // src/restura/eventManager.ts
136
103
  var import_bluebird = __toESM(require("bluebird"));
137
104
  var EventManager = class {
138
- constructor() {
139
- this.actionHandlers = {
140
- DATABASE_ROW_DELETE: [],
141
- DATABASE_ROW_INSERT: [],
142
- DATABASE_COLUMN_UPDATE: []
143
- };
144
- }
105
+ actionHandlers = {
106
+ DATABASE_ROW_DELETE: [],
107
+ DATABASE_ROW_INSERT: [],
108
+ DATABASE_COLUMN_UPDATE: []
109
+ };
145
110
  addRowInsertHandler(onInsert, filter) {
146
111
  this.actionHandlers.DATABASE_ROW_INSERT.push({
147
112
  callback: onInsert,
@@ -338,6 +303,10 @@ var HtmlStatusCodes = /* @__PURE__ */ ((HtmlStatusCodes2) => {
338
303
  return HtmlStatusCodes2;
339
304
  })(HtmlStatusCodes || {});
340
305
  var RsError = class _RsError {
306
+ err;
307
+ msg;
308
+ status;
309
+ stack;
341
310
  constructor(errCode, message) {
342
311
  this.err = errCode;
343
312
  this.msg = message || "";
@@ -490,9 +459,7 @@ var import_fs = __toESM(require("fs"));
490
459
  var import_path = __toESM(require("path"));
491
460
  var import_internal2 = require("@restura/internal");
492
461
  var CustomApiFactory = class {
493
- constructor() {
494
- this.customApis = {};
495
- }
462
+ customApis = {};
496
463
  async loadApiFiles(baseFolderPath) {
497
464
  const apiVersions = ["v1"];
498
465
  for (const apiVersion of apiVersions) {
@@ -506,11 +473,10 @@ var CustomApiFactory = class {
506
473
  return this.customApis[customApiName];
507
474
  }
508
475
  async addDirectory(directoryPath, apiVersion) {
509
- var _a2;
510
476
  const entries = await import_fs.default.promises.readdir(directoryPath, {
511
477
  withFileTypes: true
512
478
  });
513
- const isTsx2 = (_a2 = process.argv[1]) == null ? void 0 : _a2.endsWith(".ts");
479
+ const isTsx2 = process.argv[1]?.endsWith(".ts");
514
480
  const isTsNode2 = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
515
481
  const extension = isTsx2 || isTsNode2 ? "ts" : "js";
516
482
  const shouldEndWith = `.api.${apiVersion}.${extension}`;
@@ -575,6 +541,8 @@ var SqlUtils = class _SqlUtils {
575
541
 
576
542
  // src/restura/validators/ResponseValidator.ts
577
543
  var ResponseValidator = class _ResponseValidator {
544
+ rootMap;
545
+ database;
578
546
  constructor(schema) {
579
547
  this.database = schema.database;
580
548
  this.rootMap = {};
@@ -650,7 +618,7 @@ var ResponseValidator = class _ResponseValidator {
650
618
  if (path5.length === 0 || path5.length > 2 || path5[0] === "") return { validator: "any", isOptional: false };
651
619
  const tableName = path5.length == 2 ? path5[0] : name, columnName = path5.length == 2 ? path5[1] : path5[0];
652
620
  const table = this.database.find((t) => t.name == tableName);
653
- const column = table == null ? void 0 : table.columns.find((c) => c.name == columnName);
621
+ const column = table?.columns.find((c) => c.name == columnName);
654
622
  if (!table || !column) return { validator: "any", isOptional: false };
655
623
  let validator = SqlUtils.convertDatabaseTypeToTypescript(
656
624
  column.type,
@@ -734,10 +702,12 @@ var ResponseValidator = class _ResponseValidator {
734
702
  var ApiTree = class _ApiTree {
735
703
  constructor(namespace, database) {
736
704
  this.database = database;
737
- this.data = [];
738
705
  this.namespace = namespace;
739
706
  this.children = /* @__PURE__ */ new Map();
740
707
  }
708
+ namespace;
709
+ data = [];
710
+ children;
741
711
  static createRootNode(database) {
742
712
  return new _ApiTree(null, database);
743
713
  }
@@ -881,7 +851,7 @@ var ApiTree = class _ApiTree {
881
851
  tableName = tableAliasSplit[1];
882
852
  table = this.database.find((t) => t.name == tableName);
883
853
  }
884
- const column = table == null ? void 0 : table.columns.find((c) => c.name == columnName);
854
+ const column = table?.columns.find((c) => c.name == columnName);
885
855
  if (!table || !column) return { responseType: "any", isNullable: false };
886
856
  return {
887
857
  responseType: SqlUtils.convertDatabaseTypeToTypescript(column.type, column.value),
@@ -912,16 +882,17 @@ function apiGenerator(schema) {
912
882
  ${schema.customTypes.join("\n")}
913
883
  }`;
914
884
  }
915
- return import_prettier.default.format(apiString, __spreadValues({
916
- parser: "typescript"
917
- }, {
918
- trailingComma: "none",
919
- tabWidth: 4,
920
- useTabs: true,
921
- endOfLine: "lf",
922
- printWidth: 120,
923
- singleQuote: true
924
- }));
885
+ return import_prettier.default.format(apiString, {
886
+ parser: "typescript",
887
+ ...{
888
+ trailingComma: "none",
889
+ tabWidth: 4,
890
+ useTabs: true,
891
+ endOfLine: "lf",
892
+ printWidth: 120,
893
+ singleQuote: true
894
+ }
895
+ });
925
896
  }
926
897
 
927
898
  // src/restura/generators/customTypeValidationGenerator.ts
@@ -932,7 +903,7 @@ var TJS = __toESM(require("typescript-json-schema"));
932
903
  function customTypeValidationGenerator(currentSchema) {
933
904
  const schemaObject = {};
934
905
  const customInterfaceNames = currentSchema.customTypes.map((customType) => {
935
- const matches = customType.match(new RegExp("(?<=interface\\s)(\\w+)|(?<=type\\s)(\\w+)", "g"));
906
+ const matches = customType.match(/(?<=interface\s)(\w+)|(?<=type\s)(\w+)/g);
936
907
  if (matches && matches.length > 0) return matches[0];
937
908
  return "";
938
909
  }).filter(Boolean);
@@ -976,16 +947,17 @@ function modelGenerator(schema) {
976
947
  modelString += convertTable(table);
977
948
  }
978
949
  modelString += `}`;
979
- return import_prettier2.default.format(modelString, __spreadValues({
980
- parser: "typescript"
981
- }, {
982
- trailingComma: "none",
983
- tabWidth: 4,
984
- useTabs: true,
985
- endOfLine: "lf",
986
- printWidth: 120,
987
- singleQuote: true
988
- }));
950
+ return import_prettier2.default.format(modelString, {
951
+ parser: "typescript",
952
+ ...{
953
+ trailingComma: "none",
954
+ tabWidth: 4,
955
+ useTabs: true,
956
+ endOfLine: "lf",
957
+ printWidth: 120,
958
+ singleQuote: true
959
+ }
960
+ });
989
961
  }
990
962
  function convertTable(table) {
991
963
  let modelString = ` export interface ${import_core_utils2.StringUtils.capitalizeFirst(table.name)} {
@@ -1037,20 +1009,21 @@ function addApiResponseFunctions(req, res, next) {
1037
1009
  htmlStatusCode = 500;
1038
1010
  }
1039
1011
  }
1040
- const errorData = __spreadValues({
1012
+ const errorData = {
1041
1013
  err: shortError,
1042
- msg
1043
- }, restura.resturaConfig.sendErrorStackTrace && stack ? { stack } : {});
1014
+ msg,
1015
+ ...restura.resturaConfig.sendErrorStackTrace && stack ? { stack } : {}
1016
+ };
1044
1017
  res.status(htmlStatusCode).send(errorData);
1045
1018
  };
1046
1019
  next();
1047
1020
  }
1048
1021
 
1049
- // src/restura/middleware/authenticateUser.ts
1050
- function authenticateUser(applicationAuthenticateHandler) {
1022
+ // src/restura/middleware/authenticateRequester.ts
1023
+ function authenticateRequester(applicationAuthenticateHandler) {
1051
1024
  return (req, res, next) => {
1052
- applicationAuthenticateHandler(req, res, (userDetails) => {
1053
- req.requesterDetails = __spreadValues({ host: req.hostname, ipAddress: req.ip || "" }, userDetails);
1025
+ applicationAuthenticateHandler(req, res, (authenticatedRequesterDetails) => {
1026
+ req.requesterDetails = { host: req.hostname, ipAddress: req.ip || "", ...authenticatedRequesterDetails };
1054
1027
  next();
1055
1028
  });
1056
1029
  };
@@ -1082,110 +1055,97 @@ var getMulterUpload = (directory) => {
1082
1055
  };
1083
1056
 
1084
1057
  // src/restura/schemas/resturaSchema.ts
1085
- var import_zod3 = require("zod");
1058
+ var import_zod2 = require("zod");
1086
1059
 
1087
1060
  // src/restura/schemas/validatorDataSchema.ts
1088
- var import_zod2 = require("zod");
1089
- 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())]);
1090
- var validatorDataSchema = import_zod2.z.object({
1091
- type: import_zod2.z.enum(["TYPE_CHECK", "MIN", "MAX", "ONE_OF"]),
1061
+ var import_zod = require("zod");
1062
+ var validatorDataSchemeValue = import_zod.z.union([import_zod.z.string(), import_zod.z.array(import_zod.z.string()), import_zod.z.number(), import_zod.z.array(import_zod.z.number())]);
1063
+ var validatorDataSchema = import_zod.z.object({
1064
+ type: import_zod.z.enum(["TYPE_CHECK", "MIN", "MAX", "ONE_OF"]),
1092
1065
  value: validatorDataSchemeValue
1093
1066
  }).strict();
1094
1067
 
1095
1068
  // src/restura/schemas/resturaSchema.ts
1096
- var orderBySchema = import_zod3.z.object({
1097
- columnName: import_zod3.z.string(),
1098
- order: import_zod3.z.enum(["ASC", "DESC"]),
1099
- tableName: import_zod3.z.string()
1069
+ var orderBySchema = import_zod2.z.object({
1070
+ columnName: import_zod2.z.string(),
1071
+ order: import_zod2.z.enum(["ASC", "DESC"]),
1072
+ tableName: import_zod2.z.string()
1100
1073
  }).strict();
1101
- var groupBySchema = import_zod3.z.object({
1102
- columnName: import_zod3.z.string(),
1103
- tableName: import_zod3.z.string()
1074
+ var groupBySchema = import_zod2.z.object({
1075
+ columnName: import_zod2.z.string(),
1076
+ tableName: import_zod2.z.string()
1104
1077
  }).strict();
1105
- var whereDataSchema = import_zod3.z.object({
1106
- tableName: import_zod3.z.string().optional(),
1107
- columnName: import_zod3.z.string().optional(),
1108
- operator: import_zod3.z.enum([
1109
- "=",
1110
- "<",
1111
- ">",
1112
- "<=",
1113
- ">=",
1114
- "!=",
1115
- "LIKE",
1116
- "NOT LIKE",
1117
- "IN",
1118
- "NOT IN",
1119
- "STARTS WITH",
1120
- "ENDS WITH",
1121
- "IS",
1122
- "IS NOT"
1123
- ]).optional(),
1124
- value: import_zod3.z.string().or(import_zod3.z.number()).optional(),
1125
- custom: import_zod3.z.string().optional(),
1126
- conjunction: import_zod3.z.enum(["AND", "OR"]).optional()
1078
+ var whereDataSchema = import_zod2.z.object({
1079
+ tableName: import_zod2.z.string().optional(),
1080
+ columnName: import_zod2.z.string().optional(),
1081
+ operator: import_zod2.z.enum(["=", "<", ">", "<=", ">=", "!=", "LIKE", "IN", "NOT IN", "STARTS WITH", "ENDS WITH", "IS", "IS NOT"]).optional(),
1082
+ value: import_zod2.z.string().or(import_zod2.z.number()).optional(),
1083
+ custom: import_zod2.z.string().optional(),
1084
+ conjunction: import_zod2.z.enum(["AND", "OR"]).optional()
1127
1085
  }).strict();
1128
- var assignmentDataSchema = import_zod3.z.object({
1129
- name: import_zod3.z.string(),
1130
- value: import_zod3.z.string()
1086
+ var assignmentDataSchema = import_zod2.z.object({
1087
+ name: import_zod2.z.string(),
1088
+ value: import_zod2.z.string()
1131
1089
  }).strict();
1132
- var joinDataSchema = import_zod3.z.object({
1133
- table: import_zod3.z.string(),
1134
- localColumnName: import_zod3.z.string().optional(),
1135
- foreignColumnName: import_zod3.z.string().optional(),
1136
- custom: import_zod3.z.string().optional(),
1137
- type: import_zod3.z.enum(["LEFT", "INNER"]),
1138
- alias: import_zod3.z.string().optional()
1090
+ var joinDataSchema = import_zod2.z.object({
1091
+ table: import_zod2.z.string(),
1092
+ localColumnName: import_zod2.z.string().optional(),
1093
+ foreignColumnName: import_zod2.z.string().optional(),
1094
+ custom: import_zod2.z.string().optional(),
1095
+ type: import_zod2.z.enum(["LEFT", "INNER"]),
1096
+ alias: import_zod2.z.string().optional()
1139
1097
  }).strict();
1140
- var requestDataSchema = import_zod3.z.object({
1141
- name: import_zod3.z.string(),
1142
- required: import_zod3.z.boolean(),
1143
- isNullable: import_zod3.z.boolean().optional(),
1144
- validator: import_zod3.z.array(validatorDataSchema)
1098
+ var requestDataSchema = import_zod2.z.object({
1099
+ name: import_zod2.z.string(),
1100
+ required: import_zod2.z.boolean(),
1101
+ isNullable: import_zod2.z.boolean().optional(),
1102
+ validator: import_zod2.z.array(validatorDataSchema)
1145
1103
  }).strict();
1146
- var responseDataSchema = import_zod3.z.object({
1147
- name: import_zod3.z.string(),
1148
- selector: import_zod3.z.string().optional(),
1149
- subquery: import_zod3.z.object({
1150
- table: import_zod3.z.string(),
1151
- joins: import_zod3.z.array(joinDataSchema),
1152
- where: import_zod3.z.array(whereDataSchema),
1153
- properties: import_zod3.z.array(import_zod3.z.lazy(() => responseDataSchema)),
1104
+ var responseDataSchema = import_zod2.z.object({
1105
+ name: import_zod2.z.string(),
1106
+ selector: import_zod2.z.string().optional(),
1107
+ subquery: import_zod2.z.object({
1108
+ table: import_zod2.z.string(),
1109
+ joins: import_zod2.z.array(joinDataSchema),
1110
+ where: import_zod2.z.array(whereDataSchema),
1111
+ properties: import_zod2.z.array(import_zod2.z.lazy(() => responseDataSchema)),
1154
1112
  // Explicit type for the lazy schema
1155
1113
  groupBy: groupBySchema.optional(),
1156
1114
  orderBy: orderBySchema.optional()
1157
1115
  }).optional(),
1158
- type: import_zod3.z.string().optional()
1116
+ type: import_zod2.z.string().optional()
1117
+ // Type allows you to override the type of the response, used in custom selectors
1159
1118
  }).strict();
1160
- var routeDataBaseSchema = import_zod3.z.object({
1161
- method: import_zod3.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
1162
- name: import_zod3.z.string(),
1163
- description: import_zod3.z.string(),
1164
- path: import_zod3.z.string(),
1165
- roles: import_zod3.z.array(import_zod3.z.string())
1119
+ var routeDataBaseSchema = import_zod2.z.object({
1120
+ method: import_zod2.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
1121
+ name: import_zod2.z.string(),
1122
+ description: import_zod2.z.string(),
1123
+ path: import_zod2.z.string(),
1124
+ roles: import_zod2.z.array(import_zod2.z.string()),
1125
+ scopes: import_zod2.z.array(import_zod2.z.string())
1166
1126
  }).strict();
1167
1127
  var standardRouteSchema = routeDataBaseSchema.extend({
1168
- type: import_zod3.z.enum(["ONE", "ARRAY", "PAGED"]),
1169
- table: import_zod3.z.string(),
1170
- joins: import_zod3.z.array(joinDataSchema),
1171
- assignments: import_zod3.z.array(assignmentDataSchema),
1172
- where: import_zod3.z.array(whereDataSchema),
1173
- request: import_zod3.z.array(requestDataSchema),
1174
- response: import_zod3.z.array(responseDataSchema),
1128
+ type: import_zod2.z.enum(["ONE", "ARRAY", "PAGED"]),
1129
+ table: import_zod2.z.string(),
1130
+ joins: import_zod2.z.array(joinDataSchema),
1131
+ assignments: import_zod2.z.array(assignmentDataSchema),
1132
+ where: import_zod2.z.array(whereDataSchema),
1133
+ request: import_zod2.z.array(requestDataSchema),
1134
+ response: import_zod2.z.array(responseDataSchema),
1175
1135
  groupBy: groupBySchema.optional(),
1176
1136
  orderBy: orderBySchema.optional()
1177
1137
  }).strict();
1178
1138
  var customRouteSchema = routeDataBaseSchema.extend({
1179
- type: import_zod3.z.enum(["CUSTOM_ONE", "CUSTOM_ARRAY", "CUSTOM_PAGED"]),
1180
- responseType: import_zod3.z.union([import_zod3.z.string(), import_zod3.z.enum(["string", "number", "boolean"])]),
1181
- requestType: import_zod3.z.string().optional(),
1182
- request: import_zod3.z.array(requestDataSchema).optional(),
1183
- table: import_zod3.z.undefined(),
1184
- joins: import_zod3.z.undefined(),
1185
- assignments: import_zod3.z.undefined(),
1186
- fileUploadType: import_zod3.z.enum(["SINGLE", "MULTIPLE"]).optional()
1139
+ type: import_zod2.z.enum(["CUSTOM_ONE", "CUSTOM_ARRAY", "CUSTOM_PAGED"]),
1140
+ responseType: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.enum(["string", "number", "boolean"])]),
1141
+ requestType: import_zod2.z.string().optional(),
1142
+ request: import_zod2.z.array(requestDataSchema).optional(),
1143
+ table: import_zod2.z.undefined(),
1144
+ joins: import_zod2.z.undefined(),
1145
+ assignments: import_zod2.z.undefined(),
1146
+ fileUploadType: import_zod2.z.enum(["SINGLE", "MULTIPLE"]).optional()
1187
1147
  }).strict();
1188
- var postgresColumnNumericTypesSchema = import_zod3.z.enum([
1148
+ var postgresColumnNumericTypesSchema = import_zod2.z.enum([
1189
1149
  "SMALLINT",
1190
1150
  // 2 bytes, -32,768 to 32,767
1191
1151
  "INTEGER",
@@ -1205,7 +1165,7 @@ var postgresColumnNumericTypesSchema = import_zod3.z.enum([
1205
1165
  "BIGSERIAL"
1206
1166
  // auto-incrementing big integer
1207
1167
  ]);
1208
- var postgresColumnStringTypesSchema = import_zod3.z.enum([
1168
+ var postgresColumnStringTypesSchema = import_zod2.z.enum([
1209
1169
  "CHAR",
1210
1170
  // fixed-length, blank-padded
1211
1171
  "VARCHAR",
@@ -1215,7 +1175,7 @@ var postgresColumnStringTypesSchema = import_zod3.z.enum([
1215
1175
  "BYTEA"
1216
1176
  // binary data
1217
1177
  ]);
1218
- var postgresColumnDateTypesSchema = import_zod3.z.enum([
1178
+ var postgresColumnDateTypesSchema = import_zod2.z.enum([
1219
1179
  "DATE",
1220
1180
  // calendar date (year, month, day)
1221
1181
  "TIMESTAMP",
@@ -1227,13 +1187,13 @@ var postgresColumnDateTypesSchema = import_zod3.z.enum([
1227
1187
  "INTERVAL"
1228
1188
  // time span
1229
1189
  ]);
1230
- var postgresColumnJsonTypesSchema = import_zod3.z.enum([
1190
+ var postgresColumnJsonTypesSchema = import_zod2.z.enum([
1231
1191
  "JSON",
1232
1192
  // stores JSON data as raw text
1233
1193
  "JSONB"
1234
1194
  // stores JSON data in a binary format, optimized for query performance
1235
1195
  ]);
1236
- var mariaDbColumnNumericTypesSchema = import_zod3.z.enum([
1196
+ var mariaDbColumnNumericTypesSchema = import_zod2.z.enum([
1237
1197
  "BOOLEAN",
1238
1198
  // 1-byte A synonym for "TINYINT(1)". Supported from version 1.2.0 onwards.
1239
1199
  "TINYINT",
@@ -1253,7 +1213,7 @@ var mariaDbColumnNumericTypesSchema = import_zod3.z.enum([
1253
1213
  "DOUBLE"
1254
1214
  // 8 bytes Stored in 64-bit IEEE-754 floating point format. As such, the number of significant digits is about 15 and the range of values is approximately +/-1e308.
1255
1215
  ]);
1256
- var mariaDbColumnStringTypesSchema = import_zod3.z.enum([
1216
+ var mariaDbColumnStringTypesSchema = import_zod2.z.enum([
1257
1217
  "CHAR",
1258
1218
  // 1, 2, 4, or 8 bytes Holds letters and special characters of fixed length. Max length is 255. Default and minimum size is 1 byte.
1259
1219
  "VARCHAR",
@@ -1279,7 +1239,7 @@ var mariaDbColumnStringTypesSchema = import_zod3.z.enum([
1279
1239
  "ENUM"
1280
1240
  // Enum type
1281
1241
  ]);
1282
- var mariaDbColumnDateTypesSchema = import_zod3.z.enum([
1242
+ var mariaDbColumnDateTypesSchema = import_zod2.z.enum([
1283
1243
  "DATE",
1284
1244
  // 4-bytes Date has year, month, and day.
1285
1245
  "DATETIME",
@@ -1289,9 +1249,9 @@ var mariaDbColumnDateTypesSchema = import_zod3.z.enum([
1289
1249
  "TIMESTAMP"
1290
1250
  // 4-bytes Values are stored as the number of seconds since 1970-01-01 00:00:00 UTC, and optionally microseconds.
1291
1251
  ]);
1292
- var columnDataSchema = import_zod3.z.object({
1293
- name: import_zod3.z.string(),
1294
- type: import_zod3.z.union([
1252
+ var columnDataSchema = import_zod2.z.object({
1253
+ name: import_zod2.z.string(),
1254
+ type: import_zod2.z.union([
1295
1255
  postgresColumnNumericTypesSchema,
1296
1256
  postgresColumnStringTypesSchema,
1297
1257
  postgresColumnDateTypesSchema,
@@ -1300,24 +1260,25 @@ var columnDataSchema = import_zod3.z.object({
1300
1260
  mariaDbColumnStringTypesSchema,
1301
1261
  mariaDbColumnDateTypesSchema
1302
1262
  ]),
1303
- isNullable: import_zod3.z.boolean(),
1304
- roles: import_zod3.z.array(import_zod3.z.string()),
1305
- comment: import_zod3.z.string().optional(),
1306
- default: import_zod3.z.string().optional(),
1307
- value: import_zod3.z.string().optional(),
1308
- isPrimary: import_zod3.z.boolean().optional(),
1309
- isUnique: import_zod3.z.boolean().optional(),
1310
- hasAutoIncrement: import_zod3.z.boolean().optional(),
1311
- length: import_zod3.z.number().optional()
1263
+ isNullable: import_zod2.z.boolean(),
1264
+ roles: import_zod2.z.array(import_zod2.z.string()),
1265
+ scopes: import_zod2.z.array(import_zod2.z.string()),
1266
+ comment: import_zod2.z.string().optional(),
1267
+ default: import_zod2.z.string().optional(),
1268
+ value: import_zod2.z.string().optional(),
1269
+ isPrimary: import_zod2.z.boolean().optional(),
1270
+ isUnique: import_zod2.z.boolean().optional(),
1271
+ hasAutoIncrement: import_zod2.z.boolean().optional(),
1272
+ length: import_zod2.z.number().optional()
1312
1273
  }).strict();
1313
- var indexDataSchema = import_zod3.z.object({
1314
- name: import_zod3.z.string(),
1315
- columns: import_zod3.z.array(import_zod3.z.string()),
1316
- isUnique: import_zod3.z.boolean(),
1317
- isPrimaryKey: import_zod3.z.boolean(),
1318
- order: import_zod3.z.enum(["ASC", "DESC"])
1274
+ var indexDataSchema = import_zod2.z.object({
1275
+ name: import_zod2.z.string(),
1276
+ columns: import_zod2.z.array(import_zod2.z.string()),
1277
+ isUnique: import_zod2.z.boolean(),
1278
+ isPrimaryKey: import_zod2.z.boolean(),
1279
+ order: import_zod2.z.enum(["ASC", "DESC"])
1319
1280
  }).strict();
1320
- var foreignKeyActionsSchema = import_zod3.z.enum([
1281
+ var foreignKeyActionsSchema = import_zod2.z.enum([
1321
1282
  "CASCADE",
1322
1283
  // CASCADE action for foreign keys
1323
1284
  "SET NULL",
@@ -1329,39 +1290,41 @@ var foreignKeyActionsSchema = import_zod3.z.enum([
1329
1290
  "SET DEFAULT"
1330
1291
  // SET DEFAULT action for foreign keys
1331
1292
  ]);
1332
- var foreignKeyDataSchema = import_zod3.z.object({
1333
- name: import_zod3.z.string(),
1334
- column: import_zod3.z.string(),
1335
- refTable: import_zod3.z.string(),
1336
- refColumn: import_zod3.z.string(),
1293
+ var foreignKeyDataSchema = import_zod2.z.object({
1294
+ name: import_zod2.z.string(),
1295
+ column: import_zod2.z.string(),
1296
+ refTable: import_zod2.z.string(),
1297
+ refColumn: import_zod2.z.string(),
1337
1298
  onDelete: foreignKeyActionsSchema,
1338
1299
  onUpdate: foreignKeyActionsSchema
1339
1300
  }).strict();
1340
- var checkConstraintDataSchema = import_zod3.z.object({
1341
- name: import_zod3.z.string(),
1342
- check: import_zod3.z.string()
1301
+ var checkConstraintDataSchema = import_zod2.z.object({
1302
+ name: import_zod2.z.string(),
1303
+ check: import_zod2.z.string()
1343
1304
  }).strict();
1344
- var tableDataSchema = import_zod3.z.object({
1345
- name: import_zod3.z.string(),
1346
- columns: import_zod3.z.array(columnDataSchema),
1347
- indexes: import_zod3.z.array(indexDataSchema),
1348
- foreignKeys: import_zod3.z.array(foreignKeyDataSchema),
1349
- checkConstraints: import_zod3.z.array(checkConstraintDataSchema),
1350
- roles: import_zod3.z.array(import_zod3.z.string()),
1351
- notify: import_zod3.z.union([import_zod3.z.literal("ALL"), import_zod3.z.array(import_zod3.z.string())]).optional()
1305
+ var tableDataSchema = import_zod2.z.object({
1306
+ name: import_zod2.z.string(),
1307
+ columns: import_zod2.z.array(columnDataSchema),
1308
+ indexes: import_zod2.z.array(indexDataSchema),
1309
+ foreignKeys: import_zod2.z.array(foreignKeyDataSchema),
1310
+ checkConstraints: import_zod2.z.array(checkConstraintDataSchema),
1311
+ roles: import_zod2.z.array(import_zod2.z.string()),
1312
+ scopes: import_zod2.z.array(import_zod2.z.string()),
1313
+ notify: import_zod2.z.union([import_zod2.z.literal("ALL"), import_zod2.z.array(import_zod2.z.string())]).optional()
1352
1314
  }).strict();
1353
- var endpointDataSchema = import_zod3.z.object({
1354
- name: import_zod3.z.string(),
1355
- description: import_zod3.z.string(),
1356
- baseUrl: import_zod3.z.string(),
1357
- routes: import_zod3.z.array(import_zod3.z.union([standardRouteSchema, customRouteSchema]))
1315
+ var endpointDataSchema = import_zod2.z.object({
1316
+ name: import_zod2.z.string(),
1317
+ description: import_zod2.z.string(),
1318
+ baseUrl: import_zod2.z.string(),
1319
+ routes: import_zod2.z.array(import_zod2.z.union([standardRouteSchema, customRouteSchema]))
1358
1320
  }).strict();
1359
- var resturaSchema = import_zod3.z.object({
1360
- database: import_zod3.z.array(tableDataSchema),
1361
- endpoints: import_zod3.z.array(endpointDataSchema),
1362
- globalParams: import_zod3.z.array(import_zod3.z.string()),
1363
- roles: import_zod3.z.array(import_zod3.z.string()),
1364
- customTypes: import_zod3.z.array(import_zod3.z.string())
1321
+ var resturaSchema = import_zod2.z.object({
1322
+ database: import_zod2.z.array(tableDataSchema),
1323
+ endpoints: import_zod2.z.array(endpointDataSchema),
1324
+ globalParams: import_zod2.z.array(import_zod2.z.string()),
1325
+ roles: import_zod2.z.array(import_zod2.z.string()),
1326
+ scopes: import_zod2.z.array(import_zod2.z.string()),
1327
+ customTypes: import_zod2.z.array(import_zod2.z.string())
1365
1328
  }).strict();
1366
1329
  async function isSchemaValid(schemaToCheck) {
1367
1330
  try {
@@ -1376,7 +1339,7 @@ async function isSchemaValid(schemaToCheck) {
1376
1339
  // src/restura/validators/requestValidator.ts
1377
1340
  var import_core_utils3 = require("@redskytech/core-utils");
1378
1341
  var import_jsonschema = __toESM(require("jsonschema"));
1379
- var import_zod4 = require("zod");
1342
+ var import_zod3 = require("zod");
1380
1343
 
1381
1344
  // src/restura/utils/utils.ts
1382
1345
  function addQuotesToStrings(variable) {
@@ -1458,31 +1421,31 @@ function isValidType(type, requestValue) {
1458
1421
  try {
1459
1422
  expectValidType(type, requestValue);
1460
1423
  return true;
1461
- } catch (e) {
1424
+ } catch {
1462
1425
  return false;
1463
1426
  }
1464
1427
  }
1465
1428
  function expectValidType(type, requestValue) {
1466
1429
  if (type === "number") {
1467
- return import_zod4.z.number().parse(requestValue);
1430
+ return import_zod3.z.number().parse(requestValue);
1468
1431
  }
1469
1432
  if (type === "string") {
1470
- return import_zod4.z.string().parse(requestValue);
1433
+ return import_zod3.z.string().parse(requestValue);
1471
1434
  }
1472
1435
  if (type === "boolean") {
1473
- return import_zod4.z.boolean().parse(requestValue);
1436
+ return import_zod3.z.boolean().parse(requestValue);
1474
1437
  }
1475
1438
  if (type === "string[]") {
1476
- return import_zod4.z.array(import_zod4.z.string()).parse(requestValue);
1439
+ return import_zod3.z.array(import_zod3.z.string()).parse(requestValue);
1477
1440
  }
1478
1441
  if (type === "number[]") {
1479
- return import_zod4.z.array(import_zod4.z.number()).parse(requestValue);
1442
+ return import_zod3.z.array(import_zod3.z.number()).parse(requestValue);
1480
1443
  }
1481
1444
  if (type === "any[]") {
1482
- return import_zod4.z.array(import_zod4.z.any()).parse(requestValue);
1445
+ return import_zod3.z.array(import_zod3.z.any()).parse(requestValue);
1483
1446
  }
1484
1447
  if (type === "object") {
1485
- return import_zod4.z.object({}).strict().parse(requestValue);
1448
+ return import_zod3.z.object({}).strict().parse(requestValue);
1486
1449
  }
1487
1450
  }
1488
1451
  function performTypeCheck(requestValue, validator, requestParamName) {
@@ -1494,7 +1457,7 @@ function performTypeCheck(requestValue, validator, requestParamName) {
1494
1457
  }
1495
1458
  try {
1496
1459
  validatorDataSchemeValue.parse(validator.value);
1497
- } catch (e) {
1460
+ } catch {
1498
1461
  throw new RsError("SCHEMA_ERROR", `Schema validator value (${validator.value}) is not a valid type`);
1499
1462
  }
1500
1463
  }
@@ -1585,18 +1548,18 @@ async function schemaValidation(req, res, next) {
1585
1548
  }
1586
1549
 
1587
1550
  // src/restura/schemas/resturaConfigSchema.ts
1588
- var import_zod5 = require("zod");
1589
- var _a;
1590
- var isTsx = (_a = process.argv[1]) == null ? void 0 : _a.endsWith(".ts");
1551
+ var import_v42 = require("zod/v4");
1552
+ var isTsx = process.argv[1]?.endsWith(".ts");
1591
1553
  var isTsNode = process.env.TS_NODE_DEV || process.env.TS_NODE_PROJECT;
1592
1554
  var customApiFolderPath = isTsx || isTsNode ? "/src/api" : "/dist/api";
1593
- var resturaConfigSchema = import_zod5.z.object({
1594
- authToken: import_zod5.z.string().min(1, "Missing Restura Auth Token"),
1595
- sendErrorStackTrace: import_zod5.z.boolean().default(false),
1596
- schemaFilePath: import_zod5.z.string().default(process.cwd() + "/restura.schema.json"),
1597
- customApiFolderPath: import_zod5.z.string().default(process.cwd() + customApiFolderPath),
1598
- generatedTypesPath: import_zod5.z.string().default(process.cwd() + "/src/@types"),
1599
- fileTempCachePath: import_zod5.z.string().optional()
1555
+ var resturaConfigSchema = import_v42.z.object({
1556
+ authToken: import_v42.z.string().min(1, "Missing Restura Auth Token"),
1557
+ sendErrorStackTrace: import_v42.z.boolean().default(false),
1558
+ schemaFilePath: import_v42.z.string().default(process.cwd() + "/restura.schema.json"),
1559
+ customApiFolderPath: import_v42.z.string().default(process.cwd() + customApiFolderPath),
1560
+ generatedTypesPath: import_v42.z.string().default(process.cwd() + "/src/@types"),
1561
+ fileTempCachePath: import_v42.z.string().optional(),
1562
+ scratchDatabaseSuffix: import_v42.z.string().optional()
1600
1563
  });
1601
1564
 
1602
1565
  // src/restura/sql/PsqlEngine.ts
@@ -1682,13 +1645,14 @@ function SQL(strings, ...values) {
1682
1645
 
1683
1646
  // src/restura/sql/PsqlConnection.ts
1684
1647
  var PsqlConnection = class {
1648
+ instanceId;
1685
1649
  constructor(instanceId) {
1686
1650
  this.instanceId = instanceId || import_crypto.default.randomUUID();
1687
1651
  }
1688
1652
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1689
1653
  async queryOne(query, options, requesterDetails) {
1690
1654
  const formattedQuery = questionMarksToOrderedParams(query);
1691
- const meta = __spreadValues({ connectionInstanceId: this.instanceId }, requesterDetails);
1655
+ const meta = { connectionInstanceId: this.instanceId, ...requesterDetails };
1692
1656
  this.logSqlStatement(formattedQuery, options, meta);
1693
1657
  const queryMetadata = `--QUERY_METADATA(${JSON.stringify(meta)})
1694
1658
  `;
@@ -1701,7 +1665,7 @@ var PsqlConnection = class {
1701
1665
  return response.rows[0];
1702
1666
  } catch (error) {
1703
1667
  if (RsError.isRsError(error)) throw error;
1704
- if ((error == null ? void 0 : error.routine) === "_bt_check_unique") {
1668
+ if (error?.routine === "_bt_check_unique") {
1705
1669
  throw new RsError("DUPLICATE", error.message);
1706
1670
  }
1707
1671
  throw new RsError("DATABASE_ERROR", `${error.message}`);
@@ -1710,7 +1674,7 @@ var PsqlConnection = class {
1710
1674
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1711
1675
  async runQuery(query, options, requesterDetails) {
1712
1676
  const formattedQuery = questionMarksToOrderedParams(query);
1713
- const meta = __spreadValues({ connectionInstanceId: this.instanceId }, requesterDetails);
1677
+ const meta = { connectionInstanceId: this.instanceId, ...requesterDetails };
1714
1678
  this.logSqlStatement(formattedQuery, options, meta);
1715
1679
  const queryMetadata = `--QUERY_METADATA(${JSON.stringify(meta)})
1716
1680
  `;
@@ -1720,7 +1684,7 @@ var PsqlConnection = class {
1720
1684
  this.logQueryDuration(startTime);
1721
1685
  return response.rows;
1722
1686
  } catch (error) {
1723
- if ((error == null ? void 0 : error.routine) === "_bt_check_unique") {
1687
+ if (error?.routine === "_bt_check_unique") {
1724
1688
  throw new RsError("DUPLICATE", error.message);
1725
1689
  }
1726
1690
  throw new RsError("DATABASE_ERROR", `${error.message}`);
@@ -1770,13 +1734,20 @@ var PsqlPool = class extends PsqlConnection {
1770
1734
  super();
1771
1735
  this.poolConfig = poolConfig;
1772
1736
  this.pool = new Pool(poolConfig);
1773
- this.queryOne("SELECT NOW();", [], { isSystemUser: true, role: "", host: "localhost", ipAddress: "" }).then(() => {
1737
+ this.queryOne("SELECT NOW();", [], {
1738
+ isSystemUser: true,
1739
+ role: "",
1740
+ host: "localhost",
1741
+ ipAddress: "",
1742
+ scopes: []
1743
+ }).then(() => {
1774
1744
  logger.info("Connected to PostgreSQL database");
1775
1745
  }).catch((error) => {
1776
1746
  logger.error("Error connecting to database", error);
1777
1747
  process.exit(1);
1778
1748
  });
1779
1749
  }
1750
+ pool;
1780
1751
  async query(query, values) {
1781
1752
  return this.pool.query(query, values);
1782
1753
  }
@@ -1786,7 +1757,12 @@ var PsqlPool = class extends PsqlConnection {
1786
1757
  var import_core_utils4 = require("@redskytech/core-utils");
1787
1758
  var SqlEngine = class {
1788
1759
  async runQueryForRoute(req, routeData, schema) {
1789
- if (!this.doesRoleHavePermissionToTable(req.requesterDetails.role, schema, routeData.table))
1760
+ if (!this.canRequesterAccessTable(
1761
+ req.requesterDetails.role,
1762
+ req.requesterDetails.scopes,
1763
+ schema,
1764
+ routeData.table
1765
+ ))
1790
1766
  throw new RsError("FORBIDDEN", "You do not have permission to access this table");
1791
1767
  switch (routeData.method) {
1792
1768
  case "POST":
@@ -1805,7 +1781,7 @@ var SqlEngine = class {
1805
1781
  if (!tableSchema) throw new RsError("SCHEMA_ERROR", `Table ${tableName} not found in schema`);
1806
1782
  return tableSchema;
1807
1783
  }
1808
- doesRoleHavePermissionToColumn(role, schema, item, joins) {
1784
+ canRequesterAccessColumn(requesterRole, requesterScopes, schema, item, joins) {
1809
1785
  if (item.type) return true;
1810
1786
  if (item.selector) {
1811
1787
  let tableName = item.selector.split(".")[0];
@@ -1821,26 +1797,36 @@ var SqlEngine = class {
1821
1797
  const columnSchema = tableSchema.columns.find((item2) => item2.name === columnName);
1822
1798
  if (!columnSchema)
1823
1799
  throw new RsError("SCHEMA_ERROR", `Column ${columnName} not found in table ${tableName}`);
1824
- const doesColumnHaveRoles = import_core_utils4.ObjectUtils.isArrayWithData(columnSchema.roles);
1825
- if (!doesColumnHaveRoles) return true;
1826
- if (!role) return false;
1827
- return columnSchema.roles.includes(role);
1800
+ if (import_core_utils4.ObjectUtils.isArrayWithData(columnSchema.roles)) {
1801
+ if (!requesterRole) return false;
1802
+ return columnSchema.roles.includes(requesterRole);
1803
+ }
1804
+ if (import_core_utils4.ObjectUtils.isArrayWithData(columnSchema.scopes)) {
1805
+ if (!requesterScopes) return false;
1806
+ return columnSchema.scopes.some((scope) => requesterScopes.includes(scope));
1807
+ }
1808
+ return true;
1828
1809
  }
1829
1810
  if (item.subquery) {
1830
1811
  return import_core_utils4.ObjectUtils.isArrayWithData(
1831
1812
  item.subquery.properties.filter((nestedItem) => {
1832
- return this.doesRoleHavePermissionToColumn(role, schema, nestedItem, joins);
1813
+ return this.canRequesterAccessColumn(requesterRole, requesterScopes, schema, nestedItem, joins);
1833
1814
  })
1834
1815
  );
1835
1816
  }
1836
1817
  return false;
1837
1818
  }
1838
- doesRoleHavePermissionToTable(userRole, schema, tableName) {
1819
+ canRequesterAccessTable(requesterRole, requesterScopes, schema, tableName) {
1839
1820
  const tableSchema = this.getTableSchema(schema, tableName);
1840
- const doesTableHaveRoles = import_core_utils4.ObjectUtils.isArrayWithData(tableSchema.roles);
1841
- if (!doesTableHaveRoles) return true;
1842
- if (!userRole) return false;
1843
- return tableSchema.roles.includes(userRole);
1821
+ if (import_core_utils4.ObjectUtils.isArrayWithData(tableSchema.roles)) {
1822
+ if (!requesterRole) return false;
1823
+ return tableSchema.roles.includes(requesterRole);
1824
+ }
1825
+ if (import_core_utils4.ObjectUtils.isArrayWithData(tableSchema.scopes)) {
1826
+ if (!requesterScopes) return false;
1827
+ return tableSchema.scopes.some((scope) => requesterScopes.includes(scope));
1828
+ }
1829
+ return true;
1844
1830
  }
1845
1831
  replaceParamKeywords(value, routeData, req, sqlParams) {
1846
1832
  let returnValue = value;
@@ -1849,11 +1835,10 @@ var SqlEngine = class {
1849
1835
  return returnValue;
1850
1836
  }
1851
1837
  replaceLocalParamKeywords(value, routeData, req, sqlParams) {
1852
- var _a2;
1853
1838
  if (!routeData.request) return value;
1854
1839
  const data = req.data;
1855
1840
  if (typeof value === "string") {
1856
- (_a2 = value.match(/\$[a-zA-Z][a-zA-Z0-9_]+/g)) == null ? void 0 : _a2.forEach((param) => {
1841
+ value.match(/\$[a-zA-Z][a-zA-Z0-9_]+/g)?.forEach((param) => {
1857
1842
  const requestParam = routeData.request.find((item) => {
1858
1843
  return item.name === param.replace("$", "");
1859
1844
  });
@@ -1866,9 +1851,8 @@ var SqlEngine = class {
1866
1851
  return value;
1867
1852
  }
1868
1853
  replaceGlobalParamKeywords(value, routeData, req, sqlParams) {
1869
- var _a2;
1870
1854
  if (typeof value === "string") {
1871
- (_a2 = value.match(/#[a-zA-Z][a-zA-Z0-9_]+/g)) == null ? void 0 : _a2.forEach((param) => {
1855
+ value.match(/#[a-zA-Z][a-zA-Z0-9_]+/g)?.forEach((param) => {
1872
1856
  param = param.replace("#", "");
1873
1857
  const globalParamValue = req.requesterDetails[param];
1874
1858
  if (!globalParamValue)
@@ -1958,10 +1942,32 @@ negate = "!"
1958
1942
  operator = "and"i / "or"i
1959
1943
 
1960
1944
 
1961
- column = left:text "." right:text { return \`\${quoteSqlIdentity(left)}.\${quoteSqlIdentity(right)}\`; }
1962
- /
1963
- text:text { return quoteSqlIdentity(text); }
1945
+ column = first:text rest:("." text)* {
1946
+ const partsArray = [first];
1947
+ if (rest && rest.length > 0) {
1948
+ partsArray.push(...rest.map(item => item[1]));
1949
+ }
1950
+
1951
+ if (partsArray.length > 3) {
1952
+ throw new SyntaxError('Column path cannot have more than 3 parts (table.column.jsonField)');
1953
+ }
1954
+
1955
+ if (partsArray.length === 1) {
1956
+ return quoteSqlIdentity(partsArray[0]);
1957
+ }
1958
+ const tableName = quoteSqlIdentity(partsArray[0]);
1959
+
1960
+ // If we only have two parts (table.column), use regular dot notation
1961
+ if (partsArray.length === 2) {
1962
+ return tableName + "." + quoteSqlIdentity(partsArray[1]);
1963
+ }
1964
1964
 
1965
+ // For JSON paths (more than 2 parts), first part is a column, last part uses ->>
1966
+ const jsonColumn = quoteSqlIdentity(partsArray[1]);
1967
+ const lastPart = partsArray[partsArray.length - 1];
1968
+ const result = tableName + "." + jsonColumn + "->>'" + lastPart + "'";
1969
+ return result;
1970
+ }
1965
1971
 
1966
1972
  text = text:[a-z0-9 \\t\\r\\n\\-_:@']i+ { return text.join(""); }
1967
1973
 
@@ -1991,19 +1997,24 @@ var filterPsqlParser_default = filterPsqlParser;
1991
1997
  var { Client, types } = import_pg2.default;
1992
1998
  var systemUser = {
1993
1999
  role: "",
2000
+ scopes: [],
1994
2001
  host: "",
1995
2002
  ipAddress: "",
1996
2003
  isSystemUser: true
1997
2004
  };
1998
2005
  var PsqlEngine = class extends SqlEngine {
1999
- constructor(psqlConnectionPool, shouldListenForDbTriggers = false) {
2006
+ constructor(psqlConnectionPool, shouldListenForDbTriggers = false, scratchDatabaseSuffix = "") {
2000
2007
  super();
2001
2008
  this.psqlConnectionPool = psqlConnectionPool;
2002
2009
  this.setupPgReturnTypes();
2003
2010
  if (shouldListenForDbTriggers) {
2004
2011
  this.setupTriggerListeners = this.listenForDbTriggers();
2005
2012
  }
2013
+ this.scratchDbName = `${psqlConnectionPool.poolConfig.database}_scratch${scratchDatabaseSuffix ? `_${scratchDatabaseSuffix}` : ""}`;
2006
2014
  }
2015
+ setupTriggerListeners;
2016
+ triggerClient;
2017
+ scratchDbName = "";
2007
2018
  async close() {
2008
2019
  if (this.triggerClient) {
2009
2020
  await this.triggerClient.end();
@@ -2132,27 +2143,22 @@ var PsqlEngine = class extends SqlEngine {
2132
2143
  sqlStatements.push(triggers.join("\n"));
2133
2144
  return sqlStatements.join("\n\n");
2134
2145
  }
2135
- async getScratchPool() {
2136
- var _a2, _b;
2146
+ async getNewPublicSchemaAndScratchPool() {
2137
2147
  const scratchDbExists = await this.psqlConnectionPool.runQuery(
2138
2148
  `SELECT *
2139
2149
  FROM pg_database
2140
- WHERE datname = '${this.psqlConnectionPool.poolConfig.database}_scratch';`,
2150
+ WHERE datname = '${this.scratchDbName}';`,
2141
2151
  [],
2142
2152
  systemUser
2143
2153
  );
2144
2154
  if (scratchDbExists.length === 0) {
2145
- await this.psqlConnectionPool.runQuery(
2146
- `CREATE DATABASE ${this.psqlConnectionPool.poolConfig.database}_scratch;`,
2147
- [],
2148
- systemUser
2149
- );
2155
+ await this.psqlConnectionPool.runQuery(`CREATE DATABASE ${this.scratchDbName};`, [], systemUser);
2150
2156
  }
2151
2157
  const scratchPool = new PsqlPool({
2152
2158
  host: this.psqlConnectionPool.poolConfig.host,
2153
2159
  port: this.psqlConnectionPool.poolConfig.port,
2154
2160
  user: this.psqlConnectionPool.poolConfig.user,
2155
- database: this.psqlConnectionPool.poolConfig.database + "_scratch",
2161
+ database: this.scratchDbName,
2156
2162
  password: this.psqlConnectionPool.poolConfig.password,
2157
2163
  max: this.psqlConnectionPool.poolConfig.max,
2158
2164
  idleTimeoutMillis: this.psqlConnectionPool.poolConfig.idleTimeoutMillis,
@@ -2165,16 +2171,17 @@ var PsqlEngine = class extends SqlEngine {
2165
2171
  systemUser
2166
2172
  );
2167
2173
  const schemaComment = await this.psqlConnectionPool.runQuery(
2168
- `SELECT pg_description.description
2169
- FROM pg_description
2170
- JOIN pg_namespace ON pg_namespace.oid = pg_description.objoid
2171
- WHERE pg_namespace.nspname = 'public';`,
2174
+ `
2175
+ SELECT pg_description.description
2176
+ FROM pg_description
2177
+ JOIN pg_namespace ON pg_namespace.oid = pg_description.objoid
2178
+ WHERE pg_namespace.nspname = 'public';`,
2172
2179
  [],
2173
2180
  systemUser
2174
2181
  );
2175
- if ((_a2 = schemaComment[0]) == null ? void 0 : _a2.description) {
2182
+ if (schemaComment[0]?.description) {
2176
2183
  await scratchPool.runQuery(
2177
- `COMMENT ON SCHEMA public IS '${(_b = schemaComment[0]) == null ? void 0 : _b.description}';`,
2184
+ `COMMENT ON SCHEMA public IS '${schemaComment[0]?.description}';`,
2178
2185
  [],
2179
2186
  systemUser
2180
2187
  );
@@ -2182,7 +2189,7 @@ var PsqlEngine = class extends SqlEngine {
2182
2189
  return scratchPool;
2183
2190
  }
2184
2191
  async diffDatabaseToSchema(schema) {
2185
- const scratchPool = await this.getScratchPool();
2192
+ const scratchPool = await this.getNewPublicSchemaAndScratchPool();
2186
2193
  await this.createDatabaseFromSchema(schema, scratchPool);
2187
2194
  const originalClient = new Client({
2188
2195
  database: this.psqlConnectionPool.poolConfig.database,
@@ -2192,7 +2199,7 @@ var PsqlEngine = class extends SqlEngine {
2192
2199
  port: this.psqlConnectionPool.poolConfig.port
2193
2200
  });
2194
2201
  const scratchClient = new Client({
2195
- database: this.psqlConnectionPool.poolConfig.database + "_scratch",
2202
+ database: this.scratchDbName,
2196
2203
  user: this.psqlConnectionPool.poolConfig.user,
2197
2204
  password: this.psqlConnectionPool.poolConfig.password,
2198
2205
  host: this.psqlConnectionPool.poolConfig.host,
@@ -2207,24 +2214,30 @@ var PsqlEngine = class extends SqlEngine {
2207
2214
  await Promise.all(endPromises);
2208
2215
  return diff.join("\n");
2209
2216
  }
2210
- createNestedSelect(req, schema, item, routeData, userRole, sqlParams) {
2217
+ createNestedSelect(req, schema, item, routeData, sqlParams) {
2211
2218
  if (!item.subquery) return "";
2212
2219
  if (!import_core_utils5.ObjectUtils.isArrayWithData(
2213
2220
  item.subquery.properties.filter((nestedItem) => {
2214
- return this.doesRoleHavePermissionToColumn(req.requesterDetails.role, schema, nestedItem, [
2215
- ...routeData.joins,
2216
- ...item.subquery.joins
2217
- ]);
2221
+ return this.canRequesterAccessColumn(
2222
+ req.requesterDetails.role,
2223
+ req.requesterDetails.scopes,
2224
+ schema,
2225
+ nestedItem,
2226
+ [...routeData.joins, ...item.subquery.joins]
2227
+ );
2218
2228
  })
2219
2229
  )) {
2220
2230
  return "'[]'";
2221
2231
  }
2222
2232
  return `COALESCE((SELECT JSON_AGG(JSON_BUILD_OBJECT(
2223
2233
  ${item.subquery.properties.map((nestedItem) => {
2224
- if (!this.doesRoleHavePermissionToColumn(req.requesterDetails.role, schema, nestedItem, [
2225
- ...routeData.joins,
2226
- ...item.subquery.joins
2227
- ])) {
2234
+ if (!this.canRequesterAccessColumn(
2235
+ req.requesterDetails.role,
2236
+ req.requesterDetails.scopes,
2237
+ schema,
2238
+ nestedItem,
2239
+ [...routeData.joins, ...item.subquery.joins]
2240
+ )) {
2228
2241
  return;
2229
2242
  }
2230
2243
  if (nestedItem.subquery) {
@@ -2234,7 +2247,6 @@ var PsqlEngine = class extends SqlEngine {
2234
2247
  schema,
2235
2248
  nestedItem,
2236
2249
  routeData,
2237
- userRole,
2238
2250
  sqlParams
2239
2251
  )}`;
2240
2252
  }
@@ -2243,7 +2255,7 @@ var PsqlEngine = class extends SqlEngine {
2243
2255
  ))
2244
2256
  FROM
2245
2257
  "${item.subquery.table}"
2246
- ${this.generateJoinStatements(req, item.subquery.joins, item.subquery.table, routeData, schema, userRole, sqlParams)}
2258
+ ${this.generateJoinStatements(req, item.subquery.joins, item.subquery.table, routeData, schema, sqlParams)}
2247
2259
  ${this.generateWhereClause(req, item.subquery.where, routeData, sqlParams)}
2248
2260
  ), '[]')`;
2249
2261
  }
@@ -2253,7 +2265,7 @@ var PsqlEngine = class extends SqlEngine {
2253
2265
  (routeData.assignments || []).forEach((assignment) => {
2254
2266
  parameterObj[assignment.name] = this.replaceParamKeywords(assignment.value, routeData, req, sqlParams);
2255
2267
  });
2256
- const query = insertObjectQuery(routeData.table, __spreadValues(__spreadValues({}, req.data), parameterObj));
2268
+ const query = insertObjectQuery(routeData.table, { ...req.data, ...parameterObj });
2257
2269
  const createdItem = await this.psqlConnectionPool.queryOne(
2258
2270
  query,
2259
2271
  sqlParams,
@@ -2268,24 +2280,29 @@ var PsqlEngine = class extends SqlEngine {
2268
2280
  };
2269
2281
  const whereData = [whereId];
2270
2282
  req.data = { id: insertId };
2271
- return this.executeGetRequest(req, __spreadProps(__spreadValues({}, routeData), { where: whereData }), schema);
2283
+ return this.executeGetRequest(req, { ...routeData, where: whereData }, schema);
2272
2284
  }
2273
2285
  async executeGetRequest(req, routeData, schema) {
2274
2286
  const DEFAULT_PAGED_PAGE_NUMBER = 0;
2275
2287
  const DEFAULT_PAGED_PER_PAGE_NUMBER = 25;
2276
2288
  const sqlParams = [];
2277
- const userRole = req.requesterDetails.role;
2278
2289
  let sqlStatement = "";
2279
2290
  const selectColumns = [];
2280
2291
  routeData.response.forEach((item) => {
2281
- if (item.subquery || this.doesRoleHavePermissionToColumn(userRole, schema, item, routeData.joins))
2292
+ if (item.subquery || this.canRequesterAccessColumn(
2293
+ req.requesterDetails.role,
2294
+ req.requesterDetails.scopes,
2295
+ schema,
2296
+ item,
2297
+ routeData.joins
2298
+ ))
2282
2299
  selectColumns.push(item);
2283
2300
  });
2284
2301
  if (!selectColumns.length) throw new RsError("FORBIDDEN", `You do not have permission to access this data.`);
2285
2302
  let selectStatement = "SELECT \n";
2286
2303
  selectStatement += ` ${selectColumns.map((item) => {
2287
2304
  if (item.subquery) {
2288
- return `${this.createNestedSelect(req, schema, item, routeData, userRole, sqlParams)} AS ${escapeColumnName(
2305
+ return `${this.createNestedSelect(req, schema, item, routeData, sqlParams)} AS ${escapeColumnName(
2289
2306
  item.name
2290
2307
  )}`;
2291
2308
  }
@@ -2300,7 +2317,6 @@ var PsqlEngine = class extends SqlEngine {
2300
2317
  routeData.table,
2301
2318
  routeData,
2302
2319
  schema,
2303
- userRole,
2304
2320
  sqlParams
2305
2321
  );
2306
2322
  sqlStatement += this.generateWhereClause(req, routeData.where, routeData, sqlParams);
@@ -2344,7 +2360,7 @@ var PsqlEngine = class extends SqlEngine {
2344
2360
  }
2345
2361
  async executeUpdateRequest(req, routeData, schema) {
2346
2362
  const sqlParams = [];
2347
- const _a2 = req.body, { id } = _a2, bodyNoId = __objRest(_a2, ["id"]);
2363
+ const { id, ...bodyNoId } = req.body;
2348
2364
  const table = schema.database.find((item) => {
2349
2365
  return item.name === routeData.table;
2350
2366
  });
@@ -2373,7 +2389,6 @@ var PsqlEngine = class extends SqlEngine {
2373
2389
  routeData.table,
2374
2390
  routeData,
2375
2391
  schema,
2376
- req.requesterDetails.role,
2377
2392
  sqlParams
2378
2393
  );
2379
2394
  const whereClause = this.generateWhereClause(req, routeData.where, routeData, sqlParams);
@@ -2385,10 +2400,15 @@ DELETE FROM "${routeData.table}" ${joinStatement} ${whereClause}`;
2385
2400
  await this.psqlConnectionPool.runQuery(deleteStatement, sqlParams, req.requesterDetails);
2386
2401
  return true;
2387
2402
  }
2388
- generateJoinStatements(req, joins, baseTable, routeData, schema, userRole, sqlParams) {
2403
+ generateJoinStatements(req, joins, baseTable, routeData, schema, sqlParams) {
2389
2404
  let joinStatements = "";
2390
2405
  joins.forEach((item) => {
2391
- if (!this.doesRoleHavePermissionToTable(userRole, schema, item.table))
2406
+ if (!this.canRequesterAccessTable(
2407
+ req.requesterDetails.role,
2408
+ req.requesterDetails.scopes,
2409
+ schema,
2410
+ item.table
2411
+ ))
2392
2412
  throw new RsError("FORBIDDEN", "You do not have permission to access this table");
2393
2413
  if (item.custom) {
2394
2414
  const customReplaced = this.replaceParamKeywords(item.custom, routeData, req, sqlParams);
@@ -2443,41 +2463,36 @@ DELETE FROM "${routeData.table}" ${joinStatement} ${whereClause}`;
2443
2463
  `Invalid where clause in route ${routeData.name}, missing required fields if not custom`
2444
2464
  );
2445
2465
  let operator = item.operator;
2446
- let value = item.value;
2447
2466
  if (operator === "LIKE") {
2448
- value = `'%${value}%'`;
2449
- } else if (operator === "NOT LIKE") {
2450
- value = `'%${value}%'`;
2467
+ item.value = `'%${item.value}%'`;
2451
2468
  } else if (operator === "STARTS WITH") {
2452
2469
  operator = "LIKE";
2453
- value = `'${value}%'`;
2470
+ item.value = `'${item.value}%'`;
2454
2471
  } else if (operator === "ENDS WITH") {
2455
2472
  operator = "LIKE";
2456
- value = `'%${value}'`;
2473
+ item.value = `'%${item.value}'`;
2457
2474
  }
2458
- const replacedValue = this.replaceParamKeywords(value, routeData, req, sqlParams);
2475
+ const replacedValue = this.replaceParamKeywords(item.value, routeData, req, sqlParams);
2459
2476
  whereClause += ` ${item.conjunction || ""} "${item.tableName}"."${item.columnName}" ${operator.replace("LIKE", "ILIKE")} ${["IN", "NOT IN"].includes(operator) ? `(${replacedValue})` : replacedValue}
2460
2477
  `;
2461
2478
  });
2462
2479
  const data = req.data;
2463
- if (routeData.type === "PAGED" && !!(data == null ? void 0 : data.filter)) {
2480
+ if (routeData.type === "PAGED" && !!data?.filter) {
2464
2481
  let statement = data.filter.replace(/\$[a-zA-Z][a-zA-Z0-9_]+/g, (value) => {
2465
- var _a2;
2466
2482
  const requestParam = routeData.request.find((item) => {
2467
2483
  return item.name === value.replace("$", "");
2468
2484
  });
2469
2485
  if (!requestParam)
2470
2486
  throw new RsError("SCHEMA_ERROR", `Invalid route keyword in route ${routeData.name}`);
2471
- return ((_a2 = data[requestParam.name]) == null ? void 0 : _a2.toString()) || "";
2487
+ return data[requestParam.name]?.toString() || "";
2472
2488
  });
2473
2489
  statement = statement.replace(/#[a-zA-Z][a-zA-Z0-9_]+/g, (value) => {
2474
- var _a2;
2475
2490
  const requestParam = routeData.request.find((item) => {
2476
2491
  return item.name === value.replace("#", "");
2477
2492
  });
2478
2493
  if (!requestParam)
2479
2494
  throw new RsError("SCHEMA_ERROR", `Invalid route keyword in route ${routeData.name}`);
2480
- return ((_a2 = data[requestParam.name]) == null ? void 0 : _a2.toString()) || "";
2495
+ return data[requestParam.name]?.toString() || "";
2481
2496
  });
2482
2497
  statement = filterPsqlParser_default.parse(statement);
2483
2498
  if (whereClause.startsWith("WHERE")) {
@@ -2718,8 +2733,9 @@ var import_internal3 = require("@restura/internal");
2718
2733
  var import_bluebird3 = __toESM(require("bluebird"));
2719
2734
  var os2 = __toESM(require("os"));
2720
2735
  var TempCache = class {
2736
+ location;
2737
+ maxDurationDays = 7;
2721
2738
  constructor(location) {
2722
- this.maxDurationDays = 7;
2723
2739
  this.location = location || os2.tmpdir();
2724
2740
  import_internal3.FileUtils.ensureDir(this.location).catch((e) => {
2725
2741
  throw e;
@@ -2744,15 +2760,24 @@ var TempCache = class {
2744
2760
 
2745
2761
  // src/restura/restura.ts
2746
2762
  var ResturaEngine = class {
2747
- constructor() {
2748
- this.publicEndpoints = {
2749
- GET: [],
2750
- POST: [],
2751
- PUT: [],
2752
- PATCH: [],
2753
- DELETE: []
2754
- };
2755
- }
2763
+ // Make public so other modules can access without re-parsing the config
2764
+ resturaConfig;
2765
+ multerCommonUpload;
2766
+ resturaRouter;
2767
+ publicEndpoints = {
2768
+ GET: [],
2769
+ POST: [],
2770
+ PUT: [],
2771
+ PATCH: [],
2772
+ DELETE: []
2773
+ };
2774
+ expressApp;
2775
+ schema;
2776
+ responseValidator;
2777
+ authenticationHandler;
2778
+ customTypeValidation;
2779
+ psqlConnectionPool;
2780
+ psqlEngine;
2756
2781
  /**
2757
2782
  * Initializes the Restura engine with the provided Express application.
2758
2783
  *
@@ -2760,11 +2785,11 @@ var ResturaEngine = class {
2760
2785
  * @returns A promise that resolves when the initialization is complete.
2761
2786
  */
2762
2787
  async init(app, authenticationHandler, psqlConnectionPool) {
2763
- this.resturaConfig = import_internal4.config.validate("restura", resturaConfigSchema);
2788
+ this.resturaConfig = await import_internal4.config.validate("restura", resturaConfigSchema);
2764
2789
  this.multerCommonUpload = getMulterUpload(this.resturaConfig.fileTempCachePath);
2765
2790
  new TempCache(this.resturaConfig.fileTempCachePath);
2766
2791
  this.psqlConnectionPool = psqlConnectionPool;
2767
- this.psqlEngine = new PsqlEngine(this.psqlConnectionPool, true);
2792
+ this.psqlEngine = new PsqlEngine(this.psqlConnectionPool, true, this.resturaConfig.scratchDatabaseSuffix);
2768
2793
  await customApiFactory_default.loadApiFiles(this.resturaConfig.customApiFolderPath);
2769
2794
  this.authenticationHandler = authenticationHandler;
2770
2795
  app.use((0, import_compression.default)());
@@ -2773,7 +2798,7 @@ var ResturaEngine = class {
2773
2798
  app.use((0, import_cookie_parser.default)());
2774
2799
  app.disable("x-powered-by");
2775
2800
  app.use("/", addApiResponseFunctions);
2776
- app.use("/api/", authenticateUser(this.authenticationHandler));
2801
+ app.use("/api/", authenticateRequester(this.authenticationHandler));
2777
2802
  app.use("/restura", this.resturaAuthentication);
2778
2803
  app.put(
2779
2804
  "/restura/v1/schema",
@@ -2794,7 +2819,7 @@ var ResturaEngine = class {
2794
2819
  }
2795
2820
  /**
2796
2821
  * Determines if a given endpoint is public based on the HTTP method and full URL. This
2797
- * is determined on whether the endpoint in the schema has no roles assigned to it.
2822
+ * is determined on whether the endpoint in the schema has no roles or scopes assigned to it.
2798
2823
  *
2799
2824
  * @param method - The HTTP method (e.g., 'GET', 'POST', 'PUT', 'PATCH', 'DELETE').
2800
2825
  * @param fullUrl - The full URL of the endpoint.
@@ -2883,7 +2908,8 @@ var ResturaEngine = class {
2883
2908
  route.path = route.path.startsWith("/") ? route.path : `/${route.path}`;
2884
2909
  route.path = route.path.endsWith("/") ? route.path.slice(0, -1) : route.path;
2885
2910
  const fullUrl = `${baseUrl}${route.path}`;
2886
- if (route.roles.length === 0) this.publicEndpoints[route.method].push(fullUrl);
2911
+ if (route.roles.length === 0 && route.scopes.length === 0)
2912
+ this.publicEndpoints[route.method].push(fullUrl);
2887
2913
  this.resturaRouter[route.method.toLowerCase()](
2888
2914
  route.path,
2889
2915
  // <-- Notice we only use path here since the baseUrl is already added to the router.
@@ -2933,10 +2959,10 @@ var ResturaEngine = class {
2933
2959
  );
2934
2960
  this.generateResturaGlobalTypes(import_path5.default.join(this.resturaConfig.generatedTypesPath, "restura.d.ts"));
2935
2961
  }
2936
- async getSchema(req, res) {
2962
+ async getSchema(_req, res) {
2937
2963
  res.send({ data: this.schema });
2938
2964
  }
2939
- async getSchemaAndTypes(req, res) {
2965
+ async getSchemaAndTypes(_req, res) {
2940
2966
  try {
2941
2967
  const schema = await this.getLatestFileSystemSchema();
2942
2968
  const apiText = await apiGenerator(schema);
@@ -2947,8 +2973,7 @@ var ResturaEngine = class {
2947
2973
  }
2948
2974
  }
2949
2975
  async getMulterFilesIfAny(req, res, routeData) {
2950
- var _a2;
2951
- if (!((_a2 = req.header("content-type")) == null ? void 0 : _a2.includes("multipart/form-data"))) return;
2976
+ if (!req.header("content-type")?.includes("multipart/form-data")) return;
2952
2977
  if (!this.isCustomRoute(routeData)) return;
2953
2978
  if (!routeData.fileUploadType) {
2954
2979
  throw new RsError("BAD_REQUEST", "File upload type not defined for route");
@@ -3011,16 +3036,17 @@ var ResturaEngine = class {
3011
3036
  await customFunction(req, res, routeData);
3012
3037
  }
3013
3038
  async storeFileSystemSchema() {
3014
- const schemaPrettyStr = await prettier3.format(JSON.stringify(this.schema), __spreadValues({
3015
- parser: "json"
3016
- }, {
3017
- trailingComma: "none",
3018
- tabWidth: 4,
3019
- useTabs: true,
3020
- endOfLine: "lf",
3021
- printWidth: 120,
3022
- singleQuote: true
3023
- }));
3039
+ const schemaPrettyStr = await prettier3.format(JSON.stringify(this.schema), {
3040
+ parser: "json",
3041
+ ...{
3042
+ trailingComma: "none",
3043
+ tabWidth: 4,
3044
+ useTabs: true,
3045
+ endOfLine: "lf",
3046
+ printWidth: 120,
3047
+ singleQuote: true
3048
+ }
3049
+ });
3024
3050
  import_fs4.default.writeFileSync(this.resturaConfig.schemaFilePath, schemaPrettyStr);
3025
3051
  }
3026
3052
  resetPublicEndpoints() {
@@ -3033,9 +3059,13 @@ var ResturaEngine = class {
3033
3059
  };
3034
3060
  }
3035
3061
  validateAuthorization(req, routeData) {
3036
- const role = req.requesterDetails.role;
3037
- if (routeData.roles.length === 0 || !role) return;
3038
- if (!routeData.roles.includes(role)) throw new RsError("FORBIDDEN", "Not authorized to access this endpoint");
3062
+ const requesterRole = req.requesterDetails.role;
3063
+ const requesterScopes = req.requesterDetails.scopes;
3064
+ if (routeData.roles.length === 0 && routeData.scopes.length === 0) return;
3065
+ if (requesterRole && routeData.roles.length > 0 && !routeData.roles.includes(requesterRole))
3066
+ throw new RsError("FORBIDDEN", "Not authorized to access this endpoint");
3067
+ if (requesterScopes.length > 0 && routeData.scopes.length > 0 && !routeData.scopes.some((scope) => requesterScopes.includes(scope)))
3068
+ throw new RsError("FORBIDDEN", "Not authorized to access this endpoint");
3039
3069
  }
3040
3070
  getRouteData(method, baseUrl, path5) {
3041
3071
  const endpoint = this.schema.endpoints.find((item) => {
@@ -3089,6 +3119,9 @@ var PsqlTransaction = class extends PsqlConnection {
3089
3119
  this.connectPromise = this.client.connect();
3090
3120
  this.beginTransactionPromise = this.beginTransaction();
3091
3121
  }
3122
+ client;
3123
+ beginTransactionPromise;
3124
+ connectPromise;
3092
3125
  async close() {
3093
3126
  if (this.client) {
3094
3127
  await this.client.end();