@carbonorm/carbonnode 4.0.1 → 5.0.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.
Files changed (155) hide show
  1. package/README.md +158 -49
  2. package/dist/api/executors/SqlExecutor.d.ts +6 -0
  3. package/dist/api/handlers/ExpressHandler.d.ts +2 -1
  4. package/dist/api/types/ormInterfaces.d.ts +12 -0
  5. package/dist/api/utils/sqlAllowList.d.ts +2 -0
  6. package/dist/index.cjs.js +247 -10
  7. package/dist/index.cjs.js.map +1 -1
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.esm.js +246 -11
  10. package/dist/index.esm.js.map +1 -1
  11. package/package.json +1 -1
  12. package/scripts/assets/handlebars/C6.test.ts.handlebars +578 -32
  13. package/scripts/generateRestBindings.cjs +5 -5
  14. package/scripts/generateRestBindings.ts +5 -5
  15. package/src/__tests__/fixtures/createTestServer.ts +11 -3
  16. package/src/__tests__/fixtures/sqlResponses/actor.get.json +13 -0
  17. package/src/__tests__/fixtures/sqlResponses/sqlAllowList.blocked.json +3 -0
  18. package/src/__tests__/fixtures/sqlResponses/sqlAllowList.json +3 -0
  19. package/src/__tests__/sakila-db/C6.js +1 -1
  20. package/src/__tests__/sakila-db/C6.mysql.cnf +6 -0
  21. package/src/__tests__/sakila-db/C6.mysqldump.json +1 -0
  22. package/src/__tests__/sakila-db/C6.mysqldump.sql +720 -0
  23. package/src/__tests__/sakila-db/C6.sqlAllowList.json +94 -0
  24. package/src/__tests__/sakila-db/C6.test.ts +578 -32
  25. package/src/__tests__/sakila-db/C6.ts +1 -1
  26. package/src/__tests__/sakila-db/sqlResponses/C6.actor.delete.json +10 -0
  27. package/src/__tests__/sakila-db/sqlResponses/C6.actor.delete.lookup.json +9 -0
  28. package/src/__tests__/sakila-db/sqlResponses/C6.actor.get.json +14 -0
  29. package/src/__tests__/sakila-db/sqlResponses/C6.actor.join.json +15 -0
  30. package/src/__tests__/sakila-db/sqlResponses/C6.actor.post.json +12 -0
  31. package/src/__tests__/sakila-db/sqlResponses/C6.actor.post.latest.json +14 -0
  32. package/src/__tests__/sakila-db/sqlResponses/C6.actor.put.json +11 -0
  33. package/src/__tests__/sakila-db/sqlResponses/C6.actor.put.lookup.json +16 -0
  34. package/src/__tests__/sakila-db/sqlResponses/C6.actor.seed.json +14 -0
  35. package/src/__tests__/sakila-db/sqlResponses/C6.address.delete.json +10 -0
  36. package/src/__tests__/sakila-db/sqlResponses/C6.address.delete.lookup.json +9 -0
  37. package/src/__tests__/sakila-db/sqlResponses/C6.address.fk.current.json +358 -0
  38. package/src/__tests__/sakila-db/sqlResponses/C6.address.fk.referenced.json +158 -0
  39. package/src/__tests__/sakila-db/sqlResponses/C6.address.get.json +22 -0
  40. package/src/__tests__/sakila-db/sqlResponses/C6.address.join.json +24 -0
  41. package/src/__tests__/sakila-db/sqlResponses/C6.address.post.json +16 -0
  42. package/src/__tests__/sakila-db/sqlResponses/C6.address.post.latest.json +22 -0
  43. package/src/__tests__/sakila-db/sqlResponses/C6.address.put.json +11 -0
  44. package/src/__tests__/sakila-db/sqlResponses/C6.address.put.lookup.json +24 -0
  45. package/src/__tests__/sakila-db/sqlResponses/C6.address.seed.json +22 -0
  46. package/src/__tests__/sakila-db/sqlResponses/C6.category.delete.json +10 -0
  47. package/src/__tests__/sakila-db/sqlResponses/C6.category.delete.lookup.json +9 -0
  48. package/src/__tests__/sakila-db/sqlResponses/C6.category.get.json +13 -0
  49. package/src/__tests__/sakila-db/sqlResponses/C6.category.join.json +14 -0
  50. package/src/__tests__/sakila-db/sqlResponses/C6.category.post.json +11 -0
  51. package/src/__tests__/sakila-db/sqlResponses/C6.category.post.latest.json +13 -0
  52. package/src/__tests__/sakila-db/sqlResponses/C6.category.put.json +11 -0
  53. package/src/__tests__/sakila-db/sqlResponses/C6.category.put.lookup.json +15 -0
  54. package/src/__tests__/sakila-db/sqlResponses/C6.category.seed.json +13 -0
  55. package/src/__tests__/sakila-db/sqlResponses/C6.city.delete.json +10 -0
  56. package/src/__tests__/sakila-db/sqlResponses/C6.city.delete.lookup.json +9 -0
  57. package/src/__tests__/sakila-db/sqlResponses/C6.city.fk.current.json +158 -0
  58. package/src/__tests__/sakila-db/sqlResponses/C6.city.fk.referenced.json +133 -0
  59. package/src/__tests__/sakila-db/sqlResponses/C6.city.get.json +14 -0
  60. package/src/__tests__/sakila-db/sqlResponses/C6.city.join.json +15 -0
  61. package/src/__tests__/sakila-db/sqlResponses/C6.city.post.json +12 -0
  62. package/src/__tests__/sakila-db/sqlResponses/C6.city.post.latest.json +14 -0
  63. package/src/__tests__/sakila-db/sqlResponses/C6.city.put.json +11 -0
  64. package/src/__tests__/sakila-db/sqlResponses/C6.city.put.lookup.json +16 -0
  65. package/src/__tests__/sakila-db/sqlResponses/C6.city.seed.json +14 -0
  66. package/src/__tests__/sakila-db/sqlResponses/C6.country.delete.json +10 -0
  67. package/src/__tests__/sakila-db/sqlResponses/C6.country.delete.lookup.json +9 -0
  68. package/src/__tests__/sakila-db/sqlResponses/C6.country.get.json +13 -0
  69. package/src/__tests__/sakila-db/sqlResponses/C6.country.join.json +15 -0
  70. package/src/__tests__/sakila-db/sqlResponses/C6.country.post.json +11 -0
  71. package/src/__tests__/sakila-db/sqlResponses/C6.country.post.latest.json +13 -0
  72. package/src/__tests__/sakila-db/sqlResponses/C6.country.put.json +11 -0
  73. package/src/__tests__/sakila-db/sqlResponses/C6.country.put.lookup.json +15 -0
  74. package/src/__tests__/sakila-db/sqlResponses/C6.country.seed.json +13 -0
  75. package/src/__tests__/sakila-db/sqlResponses/C6.customer.delete.json +10 -0
  76. package/src/__tests__/sakila-db/sqlResponses/C6.customer.delete.lookup.json +9 -0
  77. package/src/__tests__/sakila-db/sqlResponses/C6.customer.fk.current.json +283 -0
  78. package/src/__tests__/sakila-db/sqlResponses/C6.customer.fk.referenced.json +358 -0
  79. package/src/__tests__/sakila-db/sqlResponses/C6.customer.get.json +19 -0
  80. package/src/__tests__/sakila-db/sqlResponses/C6.customer.join.json +29 -0
  81. package/src/__tests__/sakila-db/sqlResponses/C6.customer.post.json +17 -0
  82. package/src/__tests__/sakila-db/sqlResponses/C6.customer.post.latest.json +19 -0
  83. package/src/__tests__/sakila-db/sqlResponses/C6.customer.put.json +11 -0
  84. package/src/__tests__/sakila-db/sqlResponses/C6.customer.put.lookup.json +21 -0
  85. package/src/__tests__/sakila-db/sqlResponses/C6.customer.seed.json +19 -0
  86. package/src/__tests__/sakila-db/sqlResponses/C6.film.delete.json +10 -0
  87. package/src/__tests__/sakila-db/sqlResponses/C6.film.delete.lookup.json +9 -0
  88. package/src/__tests__/sakila-db/sqlResponses/C6.film.fk.current.json +383 -0
  89. package/src/__tests__/sakila-db/sqlResponses/C6.film.fk.referenced.json +38 -0
  90. package/src/__tests__/sakila-db/sqlResponses/C6.film.get.json +23 -0
  91. package/src/__tests__/sakila-db/sqlResponses/C6.film.join.json +24 -0
  92. package/src/__tests__/sakila-db/sqlResponses/C6.film.post.json +20 -0
  93. package/src/__tests__/sakila-db/sqlResponses/C6.film.post.latest.json +23 -0
  94. package/src/__tests__/sakila-db/sqlResponses/C6.film.put.json +11 -0
  95. package/src/__tests__/sakila-db/sqlResponses/C6.film.put.lookup.json +25 -0
  96. package/src/__tests__/sakila-db/sqlResponses/C6.film.seed.json +23 -0
  97. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.delete.json +10 -0
  98. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.delete.lookup.json +9 -0
  99. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.fk.current.json +158 -0
  100. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.fk.referenced.json +20 -0
  101. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.get.json +14 -0
  102. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.join.json +25 -0
  103. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.post.json +12 -0
  104. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.post.latest.json +14 -0
  105. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.put.json +11 -0
  106. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.put.lookup.json +16 -0
  107. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.seed.json +14 -0
  108. package/src/__tests__/sakila-db/sqlResponses/C6.language.delete.json +10 -0
  109. package/src/__tests__/sakila-db/sqlResponses/C6.language.delete.lookup.json +9 -0
  110. package/src/__tests__/sakila-db/sqlResponses/C6.language.get.json +13 -0
  111. package/src/__tests__/sakila-db/sqlResponses/C6.language.join.json +24 -0
  112. package/src/__tests__/sakila-db/sqlResponses/C6.language.post.json +11 -0
  113. package/src/__tests__/sakila-db/sqlResponses/C6.language.post.latest.json +13 -0
  114. package/src/__tests__/sakila-db/sqlResponses/C6.language.put.json +11 -0
  115. package/src/__tests__/sakila-db/sqlResponses/C6.language.put.lookup.json +15 -0
  116. package/src/__tests__/sakila-db/sqlResponses/C6.language.seed.json +13 -0
  117. package/src/__tests__/sakila-db/sqlResponses/C6.payment.delete.json +10 -0
  118. package/src/__tests__/sakila-db/sqlResponses/C6.payment.delete.lookup.json +9 -0
  119. package/src/__tests__/sakila-db/sqlResponses/C6.payment.fk.current.json +233 -0
  120. package/src/__tests__/sakila-db/sqlResponses/C6.payment.fk.referenced.json +233 -0
  121. package/src/__tests__/sakila-db/sqlResponses/C6.payment.get.json +17 -0
  122. package/src/__tests__/sakila-db/sqlResponses/C6.payment.join.json +24 -0
  123. package/src/__tests__/sakila-db/sqlResponses/C6.payment.post.json +15 -0
  124. package/src/__tests__/sakila-db/sqlResponses/C6.payment.post.latest.json +17 -0
  125. package/src/__tests__/sakila-db/sqlResponses/C6.payment.put.json +11 -0
  126. package/src/__tests__/sakila-db/sqlResponses/C6.payment.put.lookup.json +19 -0
  127. package/src/__tests__/sakila-db/sqlResponses/C6.payment.seed.json +17 -0
  128. package/src/__tests__/sakila-db/sqlResponses/C6.rental.delete.json +10 -0
  129. package/src/__tests__/sakila-db/sqlResponses/C6.rental.delete.lookup.json +9 -0
  130. package/src/__tests__/sakila-db/sqlResponses/C6.rental.fk.current.json +233 -0
  131. package/src/__tests__/sakila-db/sqlResponses/C6.rental.fk.referenced.json +34 -0
  132. package/src/__tests__/sakila-db/sqlResponses/C6.rental.get.json +17 -0
  133. package/src/__tests__/sakila-db/sqlResponses/C6.rental.join.json +24 -0
  134. package/src/__tests__/sakila-db/sqlResponses/C6.rental.post.json +15 -0
  135. package/src/__tests__/sakila-db/sqlResponses/C6.rental.post.latest.json +17 -0
  136. package/src/__tests__/sakila-db/sqlResponses/C6.rental.put.json +11 -0
  137. package/src/__tests__/sakila-db/sqlResponses/C6.rental.put.lookup.json +19 -0
  138. package/src/__tests__/sakila-db/sqlResponses/C6.rental.seed.json +17 -0
  139. package/src/__tests__/sakila-db/sqlResponses/C6.staff.fk.current.json +34 -0
  140. package/src/__tests__/sakila-db/sqlResponses/C6.staff.fk.referenced.json +20 -0
  141. package/src/__tests__/sakila-db/sqlResponses/C6.staff.get.json +21 -0
  142. package/src/__tests__/sakila-db/sqlResponses/C6.staff.join.json +31 -0
  143. package/src/__tests__/sakila-db/sqlResponses/C6.staff.seed.json +21 -0
  144. package/src/__tests__/sakila-db/sqlResponses/C6.store.fk.current.json +20 -0
  145. package/src/__tests__/sakila-db/sqlResponses/C6.store.fk.referenced.json +34 -0
  146. package/src/__tests__/sakila-db/sqlResponses/C6.store.get.json +14 -0
  147. package/src/__tests__/sakila-db/sqlResponses/C6.store.join.json +24 -0
  148. package/src/__tests__/sakila-db/sqlResponses/C6.store.seed.json +14 -0
  149. package/src/__tests__/sakila.generated.test.ts +31 -0
  150. package/src/__tests__/sqlAllowList.test.ts +135 -0
  151. package/src/api/executors/SqlExecutor.ts +156 -0
  152. package/src/api/handlers/ExpressHandler.ts +10 -1
  153. package/src/api/types/ormInterfaces.ts +15 -0
  154. package/src/api/utils/sqlAllowList.ts +54 -0
  155. package/src/index.ts +1 -0
package/dist/index.d.ts CHANGED
@@ -36,6 +36,7 @@ export * from "./api/utils/determineRuntimeJsType";
36
36
  export * from "./api/utils/logger";
37
37
  export * from "./api/utils/normalizeSingularRequest";
38
38
  export * from "./api/utils/sortAndSerializeQueryObject";
39
+ export * from "./api/utils/sqlAllowList";
39
40
  export * from "./api/utils/testHelpers";
40
41
  export * from "./api/utils/toastNotifier";
41
42
  export * from "./variables/getEnvVar";
package/dist/index.esm.js CHANGED
@@ -2960,6 +2960,63 @@ function normalizeSingularRequest(requestMethod, request, restModel, removedPrim
2960
2960
  return __assign(__assign({}, normalized), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
2961
2961
  }
2962
2962
 
2963
+ var allowListCache = new Map();
2964
+ var normalizeSql = function (sql) {
2965
+ return sql.replace(/\s+/g, " ").trim();
2966
+ };
2967
+ var parseAllowList = function (raw, sourcePath) {
2968
+ var parsed;
2969
+ try {
2970
+ parsed = JSON.parse(raw);
2971
+ }
2972
+ catch (error) {
2973
+ throw new Error("SQL allowlist at ".concat(sourcePath, " is not valid JSON."));
2974
+ }
2975
+ if (!Array.isArray(parsed)) {
2976
+ throw new Error("SQL allowlist at ".concat(sourcePath, " must be a JSON array of strings."));
2977
+ }
2978
+ var sqlEntries = parsed
2979
+ .filter(function (entry) { return typeof entry === "string"; })
2980
+ .map(normalizeSql)
2981
+ .filter(function (entry) { return entry.length > 0; });
2982
+ if (sqlEntries.length !== parsed.length) {
2983
+ throw new Error("SQL allowlist at ".concat(sourcePath, " must contain only string entries."));
2984
+ }
2985
+ return sqlEntries;
2986
+ };
2987
+ var loadSqlAllowList = function (allowListPath) { return __awaiter(void 0, void 0, void 0, function () {
2988
+ var readFile, raw, sqlEntries, allowList;
2989
+ return __generator(this, function (_a) {
2990
+ switch (_a.label) {
2991
+ case 0:
2992
+ if (allowListCache.has(allowListPath)) {
2993
+ return [2 /*return*/, allowListCache.get(allowListPath)];
2994
+ }
2995
+ if (!isNode()) {
2996
+ throw new Error("SQL allowlist validation requires a Node runtime.");
2997
+ }
2998
+ return [4 /*yield*/, import('node:fs/promises')];
2999
+ case 1:
3000
+ readFile = (_a.sent()).readFile;
3001
+ _a.label = 2;
3002
+ case 2:
3003
+ _a.trys.push([2, 4, , 5]);
3004
+ return [4 /*yield*/, readFile(allowListPath, "utf-8")];
3005
+ case 3:
3006
+ raw = _a.sent();
3007
+ return [3 /*break*/, 5];
3008
+ case 4:
3009
+ _a.sent();
3010
+ throw new Error("SQL allowlist file not found at ".concat(allowListPath, "."));
3011
+ case 5:
3012
+ sqlEntries = parseAllowList(raw, allowListPath);
3013
+ allowList = new Set(sqlEntries);
3014
+ allowListCache.set(allowListPath, allowList);
3015
+ return [2 /*return*/, allowList];
3016
+ }
3017
+ });
3018
+ }); };
3019
+
2963
3020
  var SqlExecutor = /** @class */ (function (_super) {
2964
3021
  __extends(SqlExecutor, _super);
2965
3022
  function SqlExecutor() {
@@ -2992,10 +3049,10 @@ var SqlExecutor = /** @class */ (function (_super) {
2992
3049
  switch (_a) {
2993
3050
  case 'GET': return [3 /*break*/, 1];
2994
3051
  case 'POST': return [3 /*break*/, 3];
2995
- case 'PUT': return [3 /*break*/, 5];
2996
- case 'DELETE': return [3 /*break*/, 7];
3052
+ case 'PUT': return [3 /*break*/, 6];
3053
+ case 'DELETE': return [3 /*break*/, 9];
2997
3054
  }
2998
- return [3 /*break*/, 9];
3055
+ return [3 /*break*/, 12];
2999
3056
  case 1: return [4 /*yield*/, this.runQuery()];
3000
3057
  case 2:
3001
3058
  rest = _b.sent();
@@ -3003,16 +3060,25 @@ var SqlExecutor = /** @class */ (function (_super) {
3003
3060
  case 3: return [4 /*yield*/, this.runQuery()];
3004
3061
  case 4:
3005
3062
  result = _b.sent();
3063
+ return [4 /*yield*/, this.broadcastWebsocketIfConfigured()];
3064
+ case 5:
3065
+ _b.sent();
3006
3066
  return [2 /*return*/, result];
3007
- case 5: return [4 /*yield*/, this.runQuery()];
3008
- case 6:
3067
+ case 6: return [4 /*yield*/, this.runQuery()];
3068
+ case 7:
3009
3069
  result = _b.sent();
3010
- return [2 /*return*/, result];
3011
- case 7: return [4 /*yield*/, this.runQuery()];
3070
+ return [4 /*yield*/, this.broadcastWebsocketIfConfigured()];
3012
3071
  case 8:
3072
+ _b.sent();
3073
+ return [2 /*return*/, result];
3074
+ case 9: return [4 /*yield*/, this.runQuery()];
3075
+ case 10:
3013
3076
  result = _b.sent();
3077
+ return [4 /*yield*/, this.broadcastWebsocketIfConfigured()];
3078
+ case 11:
3079
+ _b.sent();
3014
3080
  return [2 /*return*/, result];
3015
- case 9: throw new Error("Unsupported request method: ".concat(method));
3081
+ case 12: throw new Error("Unsupported request method: ".concat(method));
3016
3082
  }
3017
3083
  });
3018
3084
  });
@@ -3073,6 +3139,149 @@ var SqlExecutor = /** @class */ (function (_super) {
3073
3139
  return "'".concat(val.toISOString().slice(0, 19).replace('T', ' '), "'");
3074
3140
  return "'".concat(JSON.stringify(val), "'");
3075
3141
  };
3142
+ SqlExecutor.prototype.stripRequestMetadata = function (source) {
3143
+ var ignoredKeys = new Set([
3144
+ C6Constants.SELECT,
3145
+ C6Constants.UPDATE,
3146
+ C6Constants.DELETE,
3147
+ C6Constants.WHERE,
3148
+ C6Constants.JOIN,
3149
+ C6Constants.PAGINATION,
3150
+ C6Constants.INSERT,
3151
+ C6Constants.REPLACE,
3152
+ "dataInsertMultipleRows",
3153
+ "cacheResults",
3154
+ "fetchDependencies",
3155
+ "debug",
3156
+ "success",
3157
+ "error",
3158
+ ]);
3159
+ var filtered = {};
3160
+ for (var _i = 0, _a = Object.entries(source); _i < _a.length; _i++) {
3161
+ var _b = _a[_i], key = _b[0], value = _b[1];
3162
+ if (!ignoredKeys.has(key)) {
3163
+ filtered[key] = value;
3164
+ }
3165
+ }
3166
+ return filtered;
3167
+ };
3168
+ SqlExecutor.prototype.normalizeRequestPayload = function (source) {
3169
+ var _a;
3170
+ var columns = this.config.restModel.COLUMNS;
3171
+ var validColumns = new Set(Object.values(columns));
3172
+ var normalized = {};
3173
+ for (var _i = 0, _b = Object.entries(source); _i < _b.length; _i++) {
3174
+ var _c = _b[_i], key = _c[0], value = _c[1];
3175
+ var shortKey = (_a = columns[key]) !== null && _a !== void 0 ? _a : (key.includes(".") ? key.split(".").pop() : key);
3176
+ if (validColumns.has(shortKey)) {
3177
+ normalized[shortKey] = value;
3178
+ }
3179
+ }
3180
+ return normalized;
3181
+ };
3182
+ SqlExecutor.prototype.extractRequestBody = function () {
3183
+ var _a, _b;
3184
+ var request = this.request;
3185
+ if (this.config.requestMethod === C6Constants.POST) {
3186
+ if (Array.isArray(request.dataInsertMultipleRows) && request.dataInsertMultipleRows.length > 0) {
3187
+ return request.dataInsertMultipleRows[0];
3188
+ }
3189
+ if (C6Constants.INSERT in request) {
3190
+ return (_a = request[C6Constants.INSERT]) !== null && _a !== void 0 ? _a : {};
3191
+ }
3192
+ if (C6Constants.REPLACE in request) {
3193
+ return (_b = request[C6Constants.REPLACE]) !== null && _b !== void 0 ? _b : {};
3194
+ }
3195
+ return this.stripRequestMetadata(request);
3196
+ }
3197
+ if (this.config.requestMethod === C6Constants.PUT) {
3198
+ if (request[C6Constants.UPDATE] && typeof request[C6Constants.UPDATE] === "object") {
3199
+ return request[C6Constants.UPDATE];
3200
+ }
3201
+ return this.stripRequestMetadata(request);
3202
+ }
3203
+ return {};
3204
+ };
3205
+ SqlExecutor.prototype.extractPrimaryKeyValues = function () {
3206
+ var _a, _b, _c;
3207
+ var request = this.request;
3208
+ var where = request === null || request === void 0 ? void 0 : request[C6Constants.WHERE];
3209
+ var sources = [request, (where && typeof where === "object" && !Array.isArray(where)) ? where : undefined];
3210
+ var columns = this.config.restModel.COLUMNS;
3211
+ var primaryShorts = (_a = this.config.restModel.PRIMARY_SHORT) !== null && _a !== void 0 ? _a : [];
3212
+ var primaryFulls = (_b = this.config.restModel.PRIMARY) !== null && _b !== void 0 ? _b : [];
3213
+ var pkValues = {};
3214
+ var _loop_1 = function (pkShort) {
3215
+ var value = undefined;
3216
+ for (var _d = 0, sources_1 = sources; _d < sources_1.length; _d++) {
3217
+ var source = sources_1[_d];
3218
+ if (source && pkShort in source) {
3219
+ value = source[pkShort];
3220
+ break;
3221
+ }
3222
+ }
3223
+ if (value === undefined) {
3224
+ var fullKey = (_c = primaryFulls.find(function (key) { return key.endsWith("." + pkShort); })) !== null && _c !== void 0 ? _c : Object.keys(columns).find(function (key) { return columns[key] === pkShort; });
3225
+ if (fullKey) {
3226
+ for (var _e = 0, sources_2 = sources; _e < sources_2.length; _e++) {
3227
+ var source = sources_2[_e];
3228
+ if (source && fullKey in source) {
3229
+ value = source[fullKey];
3230
+ break;
3231
+ }
3232
+ }
3233
+ }
3234
+ }
3235
+ if (value !== undefined) {
3236
+ pkValues[pkShort] = value;
3237
+ }
3238
+ };
3239
+ for (var _i = 0, primaryShorts_1 = primaryShorts; _i < primaryShorts_1.length; _i++) {
3240
+ var pkShort = primaryShorts_1[_i];
3241
+ _loop_1(pkShort);
3242
+ }
3243
+ if (primaryShorts.length > 0 && Object.keys(pkValues).length < primaryShorts.length) {
3244
+ return null;
3245
+ }
3246
+ return Object.keys(pkValues).length > 0 ? pkValues : null;
3247
+ };
3248
+ SqlExecutor.prototype.broadcastWebsocketIfConfigured = function () {
3249
+ return __awaiter(this, void 0, void 0, function () {
3250
+ var broadcast, payload, error_1;
3251
+ var _a, _b;
3252
+ return __generator(this, function (_c) {
3253
+ switch (_c.label) {
3254
+ case 0:
3255
+ broadcast = this.config.websocketBroadcast;
3256
+ if (!broadcast || this.config.requestMethod === C6Constants.GET)
3257
+ return [2 /*return*/];
3258
+ payload = {
3259
+ REST: {
3260
+ TABLE_NAME: this.config.restModel.TABLE_NAME,
3261
+ TABLE_PREFIX: (_b = (_a = this.config.C6) === null || _a === void 0 ? void 0 : _a.PREFIX) !== null && _b !== void 0 ? _b : "",
3262
+ METHOD: this.config.requestMethod,
3263
+ REQUEST: this.normalizeRequestPayload(this.extractRequestBody()),
3264
+ REQUEST_PRIMARY_KEY: this.extractPrimaryKeyValues(),
3265
+ },
3266
+ };
3267
+ _c.label = 1;
3268
+ case 1:
3269
+ _c.trys.push([1, 3, , 4]);
3270
+ return [4 /*yield*/, broadcast(payload)];
3271
+ case 2:
3272
+ _c.sent();
3273
+ return [3 /*break*/, 4];
3274
+ case 3:
3275
+ error_1 = _c.sent();
3276
+ if (this.config.verbose) {
3277
+ console.error("[SQL EXECUTOR] websocketBroadcast failed", error_1);
3278
+ }
3279
+ return [3 /*break*/, 4];
3280
+ case 4: return [2 /*return*/];
3281
+ }
3282
+ });
3283
+ });
3284
+ };
3076
3285
  SqlExecutor.prototype.runQuery = function () {
3077
3286
  return __awaiter(this, void 0, void 0, function () {
3078
3287
  var TABLE_NAME, method, builder, QueryResult, formatted, toUnnamed, _a, sql, values;
@@ -3104,6 +3313,9 @@ var SqlExecutor = /** @class */ (function (_super) {
3104
3313
  this.config.verbose && console.log("[SQL EXECUTOR] \uD83E\uDDE0 Formatted ".concat(method.toUpperCase(), " SQL:"), formatted);
3105
3314
  toUnnamed = namedPlaceholders();
3106
3315
  _a = toUnnamed(QueryResult.sql, QueryResult.params), sql = _a[0], values = _a[1];
3316
+ return [4 /*yield*/, this.validateSqlAllowList(sql)];
3317
+ case 1:
3318
+ _b.sent();
3107
3319
  return [4 /*yield*/, this.withConnection(function (conn) { return __awaiter(_this, void 0, void 0, function () {
3108
3320
  var result;
3109
3321
  return __generator(this, function (_a) {
@@ -3128,7 +3340,29 @@ var SqlExecutor = /** @class */ (function (_super) {
3128
3340
  }
3129
3341
  });
3130
3342
  }); })];
3131
- case 1: return [2 /*return*/, _b.sent()];
3343
+ case 2: return [2 /*return*/, _b.sent()];
3344
+ }
3345
+ });
3346
+ });
3347
+ };
3348
+ SqlExecutor.prototype.validateSqlAllowList = function (sql) {
3349
+ return __awaiter(this, void 0, void 0, function () {
3350
+ var allowListPath, allowList, normalized;
3351
+ return __generator(this, function (_a) {
3352
+ switch (_a.label) {
3353
+ case 0:
3354
+ allowListPath = this.config.sqlAllowListPath;
3355
+ if (!allowListPath) {
3356
+ return [2 /*return*/];
3357
+ }
3358
+ return [4 /*yield*/, loadSqlAllowList(allowListPath)];
3359
+ case 1:
3360
+ allowList = _a.sent();
3361
+ normalized = normalizeSql(sql);
3362
+ if (!allowList.has(normalized)) {
3363
+ throw new Error("SQL statement is not permitted by allowlist (".concat(allowListPath, ")."));
3364
+ }
3365
+ return [2 /*return*/];
3132
3366
  }
3133
3367
  });
3134
3368
  });
@@ -3145,7 +3379,7 @@ var SqlExecutor$1 = /*#__PURE__*/Object.freeze({
3145
3379
  // note sure how it would help anyone actually...
3146
3380
  function ExpressHandler(_a) {
3147
3381
  var _this = this;
3148
- var C6 = _a.C6, mysqlPool = _a.mysqlPool;
3382
+ var C6 = _a.C6, mysqlPool = _a.mysqlPool, sqlAllowListPath = _a.sqlAllowListPath;
3149
3383
  return function (req, res, next) { return __awaiter(_this, void 0, void 0, function () {
3150
3384
  var incomingMethod, table, primary, methodOverrideRaw, methodOverride, treatAsGet, method, payload, restModel, primaryKeys_1, primaryShortKeys_1, columnMap_1, resolveShortKey_1, hasPrimaryKeyValues, primaryKeyName, response, err_1;
3151
3385
  var _a, _b, _c, _d, _e, _f, _g;
@@ -3231,6 +3465,7 @@ function ExpressHandler(_a) {
3231
3465
  return [4 /*yield*/, restRequest({
3232
3466
  C6: C6,
3233
3467
  mysqlPool: mysqlPool,
3468
+ sqlAllowListPath: sqlAllowListPath,
3234
3469
  requestMethod: method,
3235
3470
  restModel: C6.TABLES[table]
3236
3471
  })(payload)];
@@ -3349,5 +3584,5 @@ function isVerbose () {
3349
3584
  return ['true', '1', 'yes', 'on'].includes(envVerbose.toLowerCase());
3350
3585
  }
3351
3586
 
3352
- export { A, AggregateBuilder, C6C, C6Constants, ConditionBuilder, DELETE, DeleteQueryBuilder, Executor, ExpressHandler, F, GET, HttpExecutor, JoinBuilder, POST, PUT, PaginationBuilder, PostQueryBuilder, SelectQueryBuilder, SqlExecutor, TestRestfulResponse, UpdateQueryBuilder, apiRequestCache, axiosInstance, bbox, carbonNodeQsStringify, checkAllRequestsComplete, checkCache, clearCache, convertForRequestBody, convertHexIfBinary, derivedTable, determineRuntimeJsType, distSphere, eFetchDependencies, error, fieldEq, getEnvVar, getPrimaryKeyTypes, group, info, isDerivedTableKey, isLocal, isNode, isTest, isVerbose, normalizeSingularRequest, onError, onSuccess, removeInvalidKeys, removePrefixIfExists, resolveDerivedTable, restOrm, restRequest, setCache, sortAndSerializeQueryObject, stContains, timeout, toastOptions, toastOptionsDevs, userCustomClearCache, warn };
3587
+ export { A, AggregateBuilder, C6C, C6Constants, ConditionBuilder, DELETE, DeleteQueryBuilder, Executor, ExpressHandler, F, GET, HttpExecutor, JoinBuilder, POST, PUT, PaginationBuilder, PostQueryBuilder, SelectQueryBuilder, SqlExecutor, TestRestfulResponse, UpdateQueryBuilder, apiRequestCache, axiosInstance, bbox, carbonNodeQsStringify, checkAllRequestsComplete, checkCache, clearCache, convertForRequestBody, convertHexIfBinary, derivedTable, determineRuntimeJsType, distSphere, eFetchDependencies, error, fieldEq, getEnvVar, getPrimaryKeyTypes, group, info, isDerivedTableKey, isLocal, isNode, isTest, isVerbose, loadSqlAllowList, normalizeSingularRequest, normalizeSql, onError, onSuccess, removeInvalidKeys, removePrefixIfExists, resolveDerivedTable, restOrm, restRequest, setCache, sortAndSerializeQueryObject, stContains, timeout, toastOptions, toastOptionsDevs, userCustomClearCache, warn };
3353
3588
  //# sourceMappingURL=index.esm.js.map