@terreno/api 0.13.3 → 0.14.1

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 (172) hide show
  1. package/dist/__tests__/versionCheckPlugin.test.js +136 -3
  2. package/dist/api.arrayOperations.test.js +1 -0
  3. package/dist/api.d.ts +15 -4
  4. package/dist/api.errors.test.js +1 -0
  5. package/dist/api.hooks.test.js +1 -0
  6. package/dist/api.js +153 -104
  7. package/dist/api.query.test.js +1 -0
  8. package/dist/api.test.js +174 -0
  9. package/dist/auth.d.ts +10 -5
  10. package/dist/auth.js +163 -90
  11. package/dist/auth.test.js +159 -0
  12. package/dist/betterAuthApp.test.js +1 -0
  13. package/dist/betterAuthSetup.d.ts +5 -6
  14. package/dist/betterAuthSetup.js +30 -17
  15. package/dist/betterAuthSetup.test.js +1 -0
  16. package/dist/config.d.ts +48 -0
  17. package/dist/config.js +257 -0
  18. package/dist/config.test.d.ts +1 -0
  19. package/dist/config.test.js +328 -0
  20. package/dist/configuration.test.js +1 -0
  21. package/dist/configurationApp.d.ts +1 -1
  22. package/dist/configurationApp.js +17 -13
  23. package/dist/configurationPlugin.test.js +1 -0
  24. package/dist/consentApp.test.js +1 -0
  25. package/dist/envConfigurationPlugin.d.ts +2 -0
  26. package/dist/envConfigurationPlugin.js +173 -0
  27. package/dist/envConfigurationPlugin.test.d.ts +1 -0
  28. package/dist/envConfigurationPlugin.test.js +322 -0
  29. package/dist/errors.d.ts +18 -7
  30. package/dist/errors.js +111 -12
  31. package/dist/errors.test.js +16 -1
  32. package/dist/example.js +19 -7
  33. package/dist/expressServer.d.ts +10 -9
  34. package/dist/expressServer.js +62 -53
  35. package/dist/expressServer.test.js +165 -2
  36. package/dist/githubAuth.d.ts +2 -1
  37. package/dist/githubAuth.js +41 -26
  38. package/dist/githubAuth.test.js +1 -0
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.js +4 -0
  41. package/dist/logger.d.ts +1 -1
  42. package/dist/logger.js +42 -20
  43. package/dist/models/versionConfig.d.ts +2 -0
  44. package/dist/models/versionConfig.js +8 -0
  45. package/dist/notifiers/googleChatNotifier.js +14 -16
  46. package/dist/notifiers/googleChatNotifier.test.js +1 -0
  47. package/dist/notifiers/slackNotifier.js +16 -14
  48. package/dist/notifiers/slackNotifier.test.js +41 -3
  49. package/dist/notifiers/zoomNotifier.js +7 -10
  50. package/dist/notifiers/zoomNotifier.test.js +1 -0
  51. package/dist/openApi.d.ts +1 -1
  52. package/dist/openApi.test.js +1 -0
  53. package/dist/openApiBuilder.d.ts +39 -6
  54. package/dist/openApiBuilder.js +1 -31
  55. package/dist/openApiBuilder.test.js +1 -0
  56. package/dist/openApiValidator.js +1 -0
  57. package/dist/openApiValidator.test.js +1 -0
  58. package/dist/permissions.d.ts +4 -4
  59. package/dist/permissions.js +67 -65
  60. package/dist/permissions.middleware.test.js +1 -0
  61. package/dist/permissions.test.js +1 -0
  62. package/dist/plugins.d.ts +5 -5
  63. package/dist/plugins.js +18 -9
  64. package/dist/plugins.test.js +1 -1
  65. package/dist/populate.d.ts +15 -8
  66. package/dist/populate.js +23 -24
  67. package/dist/populate.test.js +1 -0
  68. package/dist/realtime/changeStreamWatcher.d.ts +73 -0
  69. package/dist/realtime/changeStreamWatcher.js +724 -0
  70. package/dist/realtime/index.d.ts +6 -0
  71. package/dist/realtime/index.js +27 -0
  72. package/dist/realtime/queryMatcher.d.ts +14 -0
  73. package/dist/realtime/queryMatcher.js +250 -0
  74. package/dist/realtime/queryStore.d.ts +37 -0
  75. package/dist/realtime/queryStore.js +195 -0
  76. package/dist/realtime/realtime.test.d.ts +10 -0
  77. package/dist/realtime/realtime.test.js +3066 -0
  78. package/dist/realtime/realtimeApp.d.ts +93 -0
  79. package/dist/realtime/realtimeApp.js +560 -0
  80. package/dist/realtime/registry.d.ts +40 -0
  81. package/dist/realtime/registry.js +38 -0
  82. package/dist/realtime/socketUser.d.ts +10 -0
  83. package/dist/realtime/socketUser.js +17 -0
  84. package/dist/realtime/types.d.ts +100 -0
  85. package/dist/realtime/types.js +2 -0
  86. package/dist/requestContext.d.ts +37 -0
  87. package/dist/requestContext.js +344 -0
  88. package/dist/requestContext.test.d.ts +1 -0
  89. package/dist/requestContext.test.js +384 -0
  90. package/dist/terrenoApp.d.ts +8 -0
  91. package/dist/terrenoApp.js +50 -13
  92. package/dist/terrenoApp.test.js +194 -21
  93. package/dist/terrenoPlugin.d.ts +11 -0
  94. package/dist/tests/bunSetup.js +1 -0
  95. package/dist/tests.js +1 -1
  96. package/dist/transformers.d.ts +2 -2
  97. package/dist/transformers.js +5 -3
  98. package/dist/transformers.test.js +90 -0
  99. package/dist/types/consentResponse.d.ts +6 -3
  100. package/dist/versionCheckPlugin.d.ts +2 -0
  101. package/dist/versionCheckPlugin.js +18 -12
  102. package/package.json +4 -2
  103. package/src/__tests__/versionCheckPlugin.test.ts +94 -3
  104. package/src/api.arrayOperations.test.ts +1 -0
  105. package/src/api.errors.test.ts +1 -0
  106. package/src/api.hooks.test.ts +1 -0
  107. package/src/api.query.test.ts +1 -0
  108. package/src/api.test.ts +132 -0
  109. package/src/api.ts +199 -84
  110. package/src/auth.test.ts +160 -0
  111. package/src/auth.ts +120 -50
  112. package/src/betterAuthApp.test.ts +1 -0
  113. package/src/betterAuthSetup.test.ts +1 -0
  114. package/src/betterAuthSetup.ts +59 -22
  115. package/src/config.test.ts +255 -0
  116. package/src/config.ts +216 -0
  117. package/src/configuration.test.ts +1 -0
  118. package/src/configurationApp.ts +59 -24
  119. package/src/configurationPlugin.test.ts +1 -0
  120. package/src/consentApp.test.ts +1 -0
  121. package/src/envConfigurationPlugin.test.ts +143 -0
  122. package/src/envConfigurationPlugin.ts +100 -0
  123. package/src/errors.test.ts +19 -1
  124. package/src/errors.ts +118 -38
  125. package/src/example.ts +49 -21
  126. package/src/express.d.ts +18 -1
  127. package/src/expressServer.test.ts +147 -2
  128. package/src/expressServer.ts +80 -50
  129. package/src/githubAuth.test.ts +1 -0
  130. package/src/githubAuth.ts +59 -38
  131. package/src/index.ts +4 -0
  132. package/src/logger.ts +47 -17
  133. package/src/models/versionConfig.ts +13 -2
  134. package/src/notifiers/googleChatNotifier.test.ts +1 -0
  135. package/src/notifiers/googleChatNotifier.ts +7 -9
  136. package/src/notifiers/slackNotifier.test.ts +29 -3
  137. package/src/notifiers/slackNotifier.ts +9 -7
  138. package/src/notifiers/zoomNotifier.test.ts +1 -0
  139. package/src/notifiers/zoomNotifier.ts +8 -11
  140. package/src/openApi.test.ts +1 -0
  141. package/src/openApi.ts +4 -4
  142. package/src/openApiBuilder.test.ts +1 -0
  143. package/src/openApiBuilder.ts +14 -11
  144. package/src/openApiValidator.test.ts +1 -0
  145. package/src/openApiValidator.ts +3 -2
  146. package/src/permissions.middleware.test.ts +1 -0
  147. package/src/permissions.test.ts +1 -0
  148. package/src/permissions.ts +30 -25
  149. package/src/plugins.test.ts +1 -1
  150. package/src/plugins.ts +21 -14
  151. package/src/populate.test.ts +1 -0
  152. package/src/populate.ts +44 -36
  153. package/src/realtime/changeStreamWatcher.ts +572 -0
  154. package/src/realtime/index.ts +34 -0
  155. package/src/realtime/queryMatcher.ts +179 -0
  156. package/src/realtime/queryStore.ts +132 -0
  157. package/src/realtime/realtime.test.ts +2465 -0
  158. package/src/realtime/realtimeApp.ts +478 -0
  159. package/src/realtime/registry.ts +64 -0
  160. package/src/realtime/socketUser.ts +25 -0
  161. package/src/realtime/types.ts +112 -0
  162. package/src/requestContext.test.ts +321 -0
  163. package/src/requestContext.ts +368 -0
  164. package/src/terrenoApp.test.ts +137 -11
  165. package/src/terrenoApp.ts +64 -17
  166. package/src/terrenoPlugin.ts +12 -0
  167. package/src/tests/bunSetup.ts +1 -0
  168. package/src/tests.ts +7 -2
  169. package/src/transformers.test.ts +70 -2
  170. package/src/transformers.ts +15 -7
  171. package/src/types/consentResponse.ts +8 -10
  172. package/src/versionCheckPlugin.ts +15 -7
@@ -102,10 +102,6 @@ var requireAdmin = function (req, _res, next) {
102
102
  }
103
103
  next();
104
104
  };
105
- /**
106
- * Extracts field metadata from an OpenAPI properties object, augmented with
107
- * secret info from the Mongoose schema.
108
- */
109
105
  var extractFieldMeta = function (properties, required, schema, prefix, fieldOverrides) {
110
106
  var e_1, _a;
111
107
  var _b, _c, _d;
@@ -157,9 +153,15 @@ var redactSecrets = function (obj, secretFields) {
157
153
  var parts = field.path.split(".");
158
154
  var current = redacted;
159
155
  for (var i = 0; i < parts.length - 1; i++) {
160
- if (current[parts[i]] != null && typeof current[parts[i]] === "object") {
161
- current[parts[i]] = __assign({}, current[parts[i]]);
162
- current = current[parts[i]];
156
+ if (!current) {
157
+ break;
158
+ }
159
+ var part = parts[i];
160
+ var nested = current[part];
161
+ if (nested != null && typeof nested === "object") {
162
+ var copy = __assign({}, nested);
163
+ current[part] = copy;
164
+ current = copy;
163
165
  }
164
166
  else {
165
167
  current = null;
@@ -231,7 +233,7 @@ var ConfigurationApp = /** @class */ (function () {
231
233
  }
232
234
  ConfigurationApp.prototype.register = function (app) {
233
235
  var _this = this;
234
- var _a, _b, _c, _d;
236
+ var _a, _b, _c;
235
237
  var basePath = (_a = this.options.basePath) !== null && _a !== void 0 ? _a : "/configuration";
236
238
  var ConfigModel = this.options.model;
237
239
  var schema = ConfigModel.schema;
@@ -241,14 +243,15 @@ var ConfigurationApp = /** @class */ (function () {
241
243
  app.get("".concat(basePath, "/meta"), (0, auth_1.authenticateMiddleware)(), requireAdmin, function (_req, res) {
242
244
  return res.json(meta);
243
245
  });
246
+ var ConfigStatics = ConfigModel;
244
247
  // Discover secret fields once at registration time
245
- var secretFields = (_d = (_c = (_b = ConfigModel).getSecretFields) === null || _c === void 0 ? void 0 : _c.call(_b)) !== null && _d !== void 0 ? _d : [];
248
+ var secretFields = (_c = (_b = ConfigStatics.getSecretFields) === null || _b === void 0 ? void 0 : _b.call(ConfigStatics)) !== null && _c !== void 0 ? _c : [];
246
249
  // GET /configuration — current values (secrets redacted)
247
250
  app.get("".concat(basePath), (0, auth_1.authenticateMiddleware)(), requireAdmin, (0, api_1.asyncHandler)(function (_req, res) { return __awaiter(_this, void 0, void 0, function () {
248
251
  var config, data;
249
252
  return __generator(this, function (_a) {
250
253
  switch (_a.label) {
251
- case 0: return [4 /*yield*/, ConfigModel.getConfig()];
254
+ case 0: return [4 /*yield*/, ConfigStatics.getConfig()];
252
255
  case 1:
253
256
  config = _a.sent();
254
257
  data = redactSecrets(config.toJSON(), secretFields);
@@ -264,7 +267,7 @@ var ConfigurationApp = /** @class */ (function () {
264
267
  switch (_d.label) {
265
268
  case 0:
266
269
  _a = req.body, _s = _a._singleton, _i = _a._id, _v = _a.__v, safeBody = __rest(_a, ["_singleton", "_id", "__v"]);
267
- return [4 /*yield*/, ConfigModel.updateConfig(safeBody)];
270
+ return [4 /*yield*/, ConfigStatics.updateConfig(safeBody)];
268
271
  case 1:
269
272
  config = _d.sent();
270
273
  logger_1.logger.info("Configuration updated by ".concat((_c = (_b = req.user) === null || _b === void 0 ? void 0 : _b.email) !== null && _c !== void 0 ? _c : "unknown"));
@@ -279,7 +282,7 @@ var ConfigurationApp = /** @class */ (function () {
279
282
  var e_3, _b;
280
283
  return __generator(this, function (_c) {
281
284
  switch (_c.label) {
282
- case 0: return [4 /*yield*/, ConfigModel.resolveSecrets()];
285
+ case 0: return [4 /*yield*/, ConfigStatics.resolveSecrets()];
283
286
  case 1:
284
287
  resolved = _c.sent();
285
288
  if (!(resolved.size > 0)) return [3 /*break*/, 3];
@@ -297,7 +300,7 @@ var ConfigurationApp = /** @class */ (function () {
297
300
  }
298
301
  finally { if (e_3) throw e_3.error; }
299
302
  }
300
- return [4 /*yield*/, ConfigModel.updateConfig(updates)];
303
+ return [4 /*yield*/, ConfigStatics.updateConfig(updates)];
301
304
  case 2:
302
305
  _c.sent();
303
306
  logger_1.logger.info("Refreshed ".concat(resolved.size, "/").concat(secretFields.length, " secrets"));
@@ -318,6 +321,7 @@ var ConfigurationApp = /** @class */ (function () {
318
321
  * Top-level fields with subschemas become sections.
319
322
  * Top-level scalar fields go into a "General" section.
320
323
  */
324
+ // biome-ignore lint/suspicious/noExplicitAny: Model<any> required for invariance with consumer-supplied configuration models
321
325
  ConfigurationApp.prototype.buildMetadata = function (_model, schema) {
322
326
  var _this = this;
323
327
  var sections = [];
@@ -85,6 +85,7 @@ var __read = (this && this.__read) || function (o, n) {
85
85
  return ar;
86
86
  };
87
87
  Object.defineProperty(exports, "__esModule", { value: true });
88
+ // biome-ignore-all lint/suspicious/noExplicitAny: test mock typing
88
89
  var bun_test_1 = require("bun:test");
89
90
  var mongoose_1 = __importStar(require("mongoose"));
90
91
  var configurationPlugin_1 = require("./configurationPlugin");
@@ -55,6 +55,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
55
55
  return (mod && mod.__esModule) ? mod : { "default": mod };
56
56
  };
57
57
  Object.defineProperty(exports, "__esModule", { value: true });
58
+ // biome-ignore-all lint/suspicious/noExplicitAny: test mock typing
58
59
  var bun_test_1 = require("bun:test");
59
60
  var supertest_1 = __importDefault(require("supertest"));
60
61
  var consentApp_1 = require("./consentApp");
@@ -0,0 +1,2 @@
1
+ import type { Schema } from "mongoose";
2
+ export declare const envConfigurationPlugin: (schema: Schema<any, any, any, any>) => void;
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __values = (this && this.__values) || function(o) {
50
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
51
+ if (m) return m.call(o);
52
+ if (o && typeof o.length === "number") return {
53
+ next: function () {
54
+ if (o && i >= o.length) o = void 0;
55
+ return { value: o && o[i++], done: !o };
56
+ }
57
+ };
58
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
59
+ };
60
+ var __read = (this && this.__read) || function (o, n) {
61
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
62
+ if (!m) return o;
63
+ var i = m.call(o), r, ar = [], e;
64
+ try {
65
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
66
+ }
67
+ catch (error) { e = { error: error }; }
68
+ finally {
69
+ try {
70
+ if (r && !r.done && (m = i["return"])) m.call(i);
71
+ }
72
+ finally { if (e) throw e.error; }
73
+ }
74
+ return ar;
75
+ };
76
+ Object.defineProperty(exports, "__esModule", { value: true });
77
+ exports.envConfigurationPlugin = void 0;
78
+ var config_1 = require("./config");
79
+ var logger_1 = require("./logger");
80
+ var plugins_1 = require("./plugins");
81
+ var mapToObject = function (env) {
82
+ var e_1, _a;
83
+ if (!env) {
84
+ return {};
85
+ }
86
+ if (env instanceof Map) {
87
+ var out = {};
88
+ try {
89
+ for (var env_1 = __values(env), env_1_1 = env_1.next(); !env_1_1.done; env_1_1 = env_1.next()) {
90
+ var _b = __read(env_1_1.value, 2), k = _b[0], v = _b[1];
91
+ out[k] = v;
92
+ }
93
+ }
94
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
95
+ finally {
96
+ try {
97
+ if (env_1_1 && !env_1_1.done && (_a = env_1.return)) _a.call(env_1);
98
+ }
99
+ finally { if (e_1) throw e_1.error; }
100
+ }
101
+ return out;
102
+ }
103
+ return __assign({}, env);
104
+ };
105
+ var refreshFromDoc = function (Model) { return __awaiter(void 0, void 0, void 0, function () {
106
+ var doc, error_1;
107
+ return __generator(this, function (_a) {
108
+ switch (_a.label) {
109
+ case 0:
110
+ _a.trys.push([0, 2, , 3]);
111
+ return [4 /*yield*/, (0, plugins_1.findOneOrNoneFor)(Model, {})];
112
+ case 1:
113
+ doc = (_a.sent());
114
+ config_1.Config.setCachedEnv(mapToObject(doc === null || doc === void 0 ? void 0 : doc.env));
115
+ return [3 /*break*/, 3];
116
+ case 2:
117
+ error_1 = _a.sent();
118
+ logger_1.logger.warn("envConfigurationPlugin: failed to refresh Config cache: ".concat(error_1.message));
119
+ return [3 /*break*/, 3];
120
+ case 3: return [2 /*return*/];
121
+ }
122
+ });
123
+ }); };
124
+ // biome-ignore lint/suspicious/noExplicitAny: Schema generics must be loose to accept arbitrary consumer schemas
125
+ var envConfigurationPlugin = function (schema) {
126
+ schema.add({
127
+ env: {
128
+ default: function () { return new Map(); },
129
+ description: "Admin-editable overrides for runtime configuration. Keys are env-var names " +
130
+ "(e.g. EXPO_ACCESS_TOKEN) and values are stored as strings. Overrides win " +
131
+ "over process.env at read time via the Config registry.",
132
+ of: String,
133
+ type: Map,
134
+ },
135
+ });
136
+ schema.post("save", function () {
137
+ return __awaiter(this, void 0, void 0, function () {
138
+ return __generator(this, function (_a) {
139
+ switch (_a.label) {
140
+ case 0: return [4 /*yield*/, refreshFromDoc(this.constructor)];
141
+ case 1:
142
+ _a.sent();
143
+ return [2 /*return*/];
144
+ }
145
+ });
146
+ });
147
+ });
148
+ schema.post("findOneAndUpdate", function () {
149
+ return __awaiter(this, void 0, void 0, function () {
150
+ return __generator(this, function (_a) {
151
+ switch (_a.label) {
152
+ case 0: return [4 /*yield*/, refreshFromDoc(this.model)];
153
+ case 1:
154
+ _a.sent();
155
+ return [2 /*return*/];
156
+ }
157
+ });
158
+ });
159
+ });
160
+ schema.post("updateOne", function () {
161
+ return __awaiter(this, void 0, void 0, function () {
162
+ return __generator(this, function (_a) {
163
+ switch (_a.label) {
164
+ case 0: return [4 /*yield*/, refreshFromDoc(this.model)];
165
+ case 1:
166
+ _a.sent();
167
+ return [2 /*return*/];
168
+ }
169
+ });
170
+ });
171
+ });
172
+ };
173
+ exports.envConfigurationPlugin = envConfigurationPlugin;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,322 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
47
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
48
+ return new (P || (P = Promise))(function (resolve, reject) {
49
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
50
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
51
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
52
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
53
+ });
54
+ };
55
+ var __generator = (this && this.__generator) || function (thisArg, body) {
56
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
57
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
58
+ function verb(n) { return function (v) { return step([n, v]); }; }
59
+ function step(op) {
60
+ if (f) throw new TypeError("Generator is already executing.");
61
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
62
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
63
+ if (y = 0, t) op = [op[0] & 2, t.value];
64
+ switch (op[0]) {
65
+ case 0: case 1: t = op; break;
66
+ case 4: _.label++; return { value: op[1], done: false };
67
+ case 5: _.label++; y = op[1]; op = [0]; continue;
68
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
69
+ default:
70
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
71
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
72
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
73
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
74
+ if (t[2]) _.ops.pop();
75
+ _.trys.pop(); continue;
76
+ }
77
+ op = body.call(thisArg, _);
78
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
79
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
80
+ }
81
+ };
82
+ var __values = (this && this.__values) || function(o) {
83
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
84
+ if (m) return m.call(o);
85
+ if (o && typeof o.length === "number") return {
86
+ next: function () {
87
+ if (o && i >= o.length) o = void 0;
88
+ return { value: o && o[i++], done: !o };
89
+ }
90
+ };
91
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
92
+ };
93
+ var __read = (this && this.__read) || function (o, n) {
94
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
95
+ if (!m) return o;
96
+ var i = m.call(o), r, ar = [], e;
97
+ try {
98
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
99
+ }
100
+ catch (error) { e = { error: error }; }
101
+ finally {
102
+ try {
103
+ if (r && !r.done && (m = i["return"])) m.call(i);
104
+ }
105
+ finally { if (e) throw e.error; }
106
+ }
107
+ return ar;
108
+ };
109
+ var _a;
110
+ Object.defineProperty(exports, "__esModule", { value: true });
111
+ // biome-ignore-all lint/suspicious/noExplicitAny: test model typing
112
+ var bun_test_1 = require("bun:test");
113
+ var mongoose_1 = __importStar(require("mongoose"));
114
+ var config_1 = require("./config");
115
+ var envConfigurationPlugin_1 = require("./envConfigurationPlugin");
116
+ var testSchema = new mongoose_1.Schema({}, { strict: "throw" });
117
+ testSchema.plugin(envConfigurationPlugin_1.envConfigurationPlugin);
118
+ var TestEnvConfig = (_a = mongoose_1.default.models.TestEnvConfig) !== null && _a !== void 0 ? _a : mongoose_1.default.model("TestEnvConfig", testSchema);
119
+ var setupLoader = function () {
120
+ config_1.Config.setEnvLoader(function () { return __awaiter(void 0, void 0, void 0, function () {
121
+ var doc, out, _a, _b, _c, k, v;
122
+ var e_1, _d;
123
+ return __generator(this, function (_e) {
124
+ switch (_e.label) {
125
+ case 0: return [4 /*yield*/, TestEnvConfig.findOne({}).lean()];
126
+ case 1:
127
+ doc = (_e.sent());
128
+ if (!(doc === null || doc === void 0 ? void 0 : doc.env)) {
129
+ return [2 /*return*/, {}];
130
+ }
131
+ if (doc.env instanceof Map) {
132
+ out = {};
133
+ try {
134
+ for (_a = __values(doc.env), _b = _a.next(); !_b.done; _b = _a.next()) {
135
+ _c = __read(_b.value, 2), k = _c[0], v = _c[1];
136
+ out[k] = v;
137
+ }
138
+ }
139
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
140
+ finally {
141
+ try {
142
+ if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
143
+ }
144
+ finally { if (e_1) throw e_1.error; }
145
+ }
146
+ return [2 /*return*/, out];
147
+ }
148
+ return [2 /*return*/, __assign({}, doc.env)];
149
+ }
150
+ });
151
+ }); });
152
+ };
153
+ (0, bun_test_1.describe)("envConfigurationPlugin", function () {
154
+ (0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
155
+ var _a;
156
+ return __generator(this, function (_b) {
157
+ switch (_b.label) {
158
+ case 0:
159
+ config_1.Config.clearRegistryForTesting();
160
+ config_1.Config.clearOverrides();
161
+ config_1.Config.setCachedEnv(null);
162
+ config_1.Config.setEnvLoader(null);
163
+ Reflect.deleteProperty(process.env, "TERRENO_PLUGIN_KEY");
164
+ config_1.Config.register("TERRENO_PLUGIN_KEY", { default: "fallback" });
165
+ return [4 /*yield*/, ((_a = mongoose_1.default.connection.db) === null || _a === void 0 ? void 0 : _a.collection("testenvconfigs").deleteMany({}))];
166
+ case 1:
167
+ _b.sent();
168
+ setupLoader();
169
+ return [2 /*return*/];
170
+ }
171
+ });
172
+ }); });
173
+ (0, bun_test_1.afterEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
174
+ var _a;
175
+ return __generator(this, function (_b) {
176
+ switch (_b.label) {
177
+ case 0:
178
+ config_1.Config.clearRegistryForTesting();
179
+ config_1.Config.clearOverrides();
180
+ config_1.Config.setCachedEnv(null);
181
+ config_1.Config.setEnvLoader(null);
182
+ Reflect.deleteProperty(process.env, "TERRENO_PLUGIN_KEY");
183
+ return [4 /*yield*/, ((_a = mongoose_1.default.connection.db) === null || _a === void 0 ? void 0 : _a.collection("testenvconfigs").deleteMany({}))];
184
+ case 1:
185
+ _b.sent();
186
+ return [2 /*return*/];
187
+ }
188
+ });
189
+ }); });
190
+ (0, bun_test_1.it)("adds an env Map field to the schema", function () {
191
+ var doc = new TestEnvConfig();
192
+ (0, bun_test_1.expect)(doc.env).toBeInstanceOf(Map);
193
+ });
194
+ (0, bun_test_1.it)("Config.refresh() loads values from the document", function () { return __awaiter(void 0, void 0, void 0, function () {
195
+ var doc;
196
+ return __generator(this, function (_a) {
197
+ switch (_a.label) {
198
+ case 0:
199
+ doc = new TestEnvConfig();
200
+ doc.env.set("TERRENO_PLUGIN_KEY", "fromDoc");
201
+ return [4 /*yield*/, doc.save()];
202
+ case 1:
203
+ _a.sent();
204
+ config_1.Config.setCachedEnv(null);
205
+ return [4 /*yield*/, config_1.Config.refresh()];
206
+ case 2:
207
+ _a.sent();
208
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_PLUGIN_KEY")).toBe("fromDoc");
209
+ return [2 /*return*/];
210
+ }
211
+ });
212
+ }); });
213
+ (0, bun_test_1.it)("post-save hook refreshes the cache automatically", function () { return __awaiter(void 0, void 0, void 0, function () {
214
+ var doc;
215
+ return __generator(this, function (_a) {
216
+ switch (_a.label) {
217
+ case 0:
218
+ doc = new TestEnvConfig();
219
+ doc.env.set("TERRENO_PLUGIN_KEY", "first");
220
+ return [4 /*yield*/, doc.save()];
221
+ case 1:
222
+ _a.sent();
223
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_PLUGIN_KEY")).toBe("first");
224
+ doc.env.set("TERRENO_PLUGIN_KEY", "second");
225
+ return [4 /*yield*/, doc.save()];
226
+ case 2:
227
+ _a.sent();
228
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_PLUGIN_KEY")).toBe("second");
229
+ return [2 /*return*/];
230
+ }
231
+ });
232
+ }); });
233
+ (0, bun_test_1.it)("post-findOneAndUpdate hook refreshes the cache", function () { return __awaiter(void 0, void 0, void 0, function () {
234
+ var doc;
235
+ return __generator(this, function (_a) {
236
+ switch (_a.label) {
237
+ case 0:
238
+ doc = new TestEnvConfig();
239
+ doc.env.set("TERRENO_PLUGIN_KEY", "initial");
240
+ return [4 /*yield*/, doc.save()];
241
+ case 1:
242
+ _a.sent();
243
+ return [4 /*yield*/, TestEnvConfig.findOneAndUpdate({ _id: doc._id }, { env: new Map([["TERRENO_PLUGIN_KEY", "updated"]]) })];
244
+ case 2:
245
+ _a.sent();
246
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_PLUGIN_KEY")).toBe("updated");
247
+ return [2 /*return*/];
248
+ }
249
+ });
250
+ }); });
251
+ (0, bun_test_1.it)("post-updateOne hook refreshes the cache", function () { return __awaiter(void 0, void 0, void 0, function () {
252
+ var doc;
253
+ return __generator(this, function (_a) {
254
+ switch (_a.label) {
255
+ case 0:
256
+ doc = new TestEnvConfig();
257
+ doc.env.set("TERRENO_PLUGIN_KEY", "initial");
258
+ return [4 /*yield*/, doc.save()];
259
+ case 1:
260
+ _a.sent();
261
+ return [4 /*yield*/, TestEnvConfig.updateOne({ _id: doc._id }, { env: new Map([["TERRENO_PLUGIN_KEY", "updatedViaUpdateOne"]]) })];
262
+ case 2:
263
+ _a.sent();
264
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_PLUGIN_KEY")).toBe("updatedViaUpdateOne");
265
+ return [2 /*return*/];
266
+ }
267
+ });
268
+ }); });
269
+ (0, bun_test_1.it)("empty-string env values fall through to process.env", function () { return __awaiter(void 0, void 0, void 0, function () {
270
+ var doc;
271
+ return __generator(this, function (_a) {
272
+ switch (_a.label) {
273
+ case 0:
274
+ process.env.TERRENO_PLUGIN_KEY = "fromEnv";
275
+ doc = new TestEnvConfig();
276
+ doc.env.set("TERRENO_PLUGIN_KEY", "");
277
+ return [4 /*yield*/, doc.save()];
278
+ case 1:
279
+ _a.sent();
280
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_PLUGIN_KEY")).toBe("fromEnv");
281
+ return [2 /*return*/];
282
+ }
283
+ });
284
+ }); });
285
+ (0, bun_test_1.it)("missing document yields registered defaults", function () { return __awaiter(void 0, void 0, void 0, function () {
286
+ return __generator(this, function (_a) {
287
+ switch (_a.label) {
288
+ case 0: return [4 /*yield*/, config_1.Config.refresh()];
289
+ case 1:
290
+ _a.sent();
291
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_PLUGIN_KEY")).toBe("fallback");
292
+ return [2 /*return*/];
293
+ }
294
+ });
295
+ }); });
296
+ (0, bun_test_1.it)("refreshFromDoc handles null document via Mongoose hook when collection is empty", function () { return __awaiter(void 0, void 0, void 0, function () {
297
+ var _a;
298
+ return __generator(this, function (_b) {
299
+ switch (_b.label) {
300
+ case 0:
301
+ // Ensure collection is empty — no documents to find
302
+ return [4 /*yield*/, ((_a = mongoose_1.default.connection.db) === null || _a === void 0 ? void 0 : _a.collection("testenvconfigs").deleteMany({}))];
303
+ case 1:
304
+ // Ensure collection is empty — no documents to find
305
+ _b.sent();
306
+ // Override the cache so we can verify it gets cleared by the hook
307
+ config_1.Config.setCachedEnv({ TERRENO_PLUGIN_KEY: "stale" });
308
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_PLUGIN_KEY")).toBe("stale");
309
+ // Trigger findOneAndUpdate hook on a non-existent doc — refreshFromDoc
310
+ // calls findOneOrNone which returns null, so mapToObject(undefined) runs
311
+ return [4 /*yield*/, TestEnvConfig.findOneAndUpdate({ _id: new mongoose_1.default.Types.ObjectId() }, { $set: { __v: 1 } })];
312
+ case 2:
313
+ // Trigger findOneAndUpdate hook on a non-existent doc — refreshFromDoc
314
+ // calls findOneOrNone which returns null, so mapToObject(undefined) runs
315
+ _b.sent();
316
+ // mapToObject(undefined) returns {}, so Config falls back to the registered default
317
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_PLUGIN_KEY")).toBe("fallback");
318
+ return [2 /*return*/];
319
+ }
320
+ });
321
+ }); });
322
+ });
package/dist/errors.d.ts CHANGED
@@ -21,7 +21,7 @@ export interface APIErrorConstructor {
21
21
  meta?: {
22
22
  [id: string]: string;
23
23
  };
24
- error?: Error;
24
+ error?: unknown;
25
25
  disableExternalErrorTracking?: boolean;
26
26
  }
27
27
  /**
@@ -54,22 +54,33 @@ export declare class APIError extends Error {
54
54
  header?: string;
55
55
  } | undefined;
56
56
  meta: {
57
- [id: string]: any;
57
+ [id: string]: unknown;
58
58
  } | undefined;
59
- error?: Error;
59
+ error?: unknown;
60
60
  disableExternalErrorTracking?: boolean;
61
61
  constructor(data: APIErrorConstructor);
62
62
  }
63
63
  export declare const errorsPlugin: (schema: Schema) => void;
64
- export declare const isAPIError: (error: Error) => error is APIError;
64
+ export declare const isAPIError: (error: unknown) => error is APIError;
65
+ /** Extract a human-readable message from an unknown error. */
66
+ export declare const errorMessage: (error: unknown) => string;
67
+ /** Extract a stack trace string from an unknown error. */
68
+ export declare const errorStack: (error: unknown) => string;
65
69
  /**
66
70
  * Safely extracts the disableExternalErrorTracking property from an error.
67
71
  * Works with both APIError instances and regular Error objects that may have
68
72
  * this property attached.
69
73
  */
70
74
  export declare const getDisableExternalErrorTracking: (error: unknown) => boolean | undefined;
71
- export declare const getAPIErrorBody: (error: APIError) => {
72
- [id: string]: any;
73
- };
75
+ export declare const getAPIErrorBody: (error: APIError) => Record<string, unknown>;
74
76
  export declare const apiUnauthorizedMiddleware: (err: Error, _req: Request, res: Response, next: NextFunction) => void;
77
+ /**
78
+ * Converts Mongoose validation/cast errors into client-friendly APIErrors.
79
+ */
80
+ export declare const mongooseErrorToAPIError: (err: Error) => APIError | null;
75
81
  export declare const apiErrorMiddleware: (err: Error, _req: Request, res: Response, next: NextFunction) => void;
82
+ /**
83
+ * Final Express error handler for unexpected errors. Always returns JSON so
84
+ * clients (e.g. RTK Query) can parse the response.
85
+ */
86
+ export declare const apiFallthroughErrorMiddleware: (err: Error, _req: Request, res: Response, _next: NextFunction) => void;