@terreno/api 0.13.2 → 0.14.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 (175) hide show
  1. package/dist/__tests__/versionCheckPlugin.test.js +53 -3
  2. package/dist/api.arrayOperations.test.js +1 -0
  3. package/dist/api.asyncHandler.test.d.ts +1 -0
  4. package/dist/api.asyncHandler.test.js +236 -0
  5. package/dist/api.d.ts +15 -4
  6. package/dist/api.errors.test.js +1 -0
  7. package/dist/api.hooks.test.js +1 -0
  8. package/dist/api.js +153 -104
  9. package/dist/api.query.test.js +1 -0
  10. package/dist/api.test.js +174 -0
  11. package/dist/auth.d.ts +10 -5
  12. package/dist/auth.js +163 -90
  13. package/dist/auth.test.js +159 -0
  14. package/dist/betterAuthApp.test.js +1 -0
  15. package/dist/betterAuthSetup.d.ts +5 -6
  16. package/dist/betterAuthSetup.js +17 -14
  17. package/dist/betterAuthSetup.test.js +1 -0
  18. package/dist/config.d.ts +48 -0
  19. package/dist/config.js +248 -0
  20. package/dist/config.test.d.ts +1 -0
  21. package/dist/config.test.js +328 -0
  22. package/dist/configuration.test.js +1 -0
  23. package/dist/configurationApp.d.ts +1 -1
  24. package/dist/configurationApp.js +17 -13
  25. package/dist/configurationPlugin.test.js +1 -0
  26. package/dist/consentApp.test.js +1 -0
  27. package/dist/envConfigurationPlugin.d.ts +2 -0
  28. package/dist/envConfigurationPlugin.js +173 -0
  29. package/dist/envConfigurationPlugin.test.d.ts +1 -0
  30. package/dist/envConfigurationPlugin.test.js +322 -0
  31. package/dist/errors.d.ts +18 -7
  32. package/dist/errors.js +106 -10
  33. package/dist/errors.test.js +16 -1
  34. package/dist/example.js +16 -7
  35. package/dist/expressServer.d.ts +10 -9
  36. package/dist/expressServer.js +62 -53
  37. package/dist/expressServer.test.js +53 -2
  38. package/dist/githubAuth.d.ts +2 -1
  39. package/dist/githubAuth.js +41 -26
  40. package/dist/githubAuth.test.js +1 -0
  41. package/dist/index.d.ts +4 -0
  42. package/dist/index.js +4 -0
  43. package/dist/logger.d.ts +1 -1
  44. package/dist/logger.js +42 -20
  45. package/dist/models/versionConfig.d.ts +2 -0
  46. package/dist/models/versionConfig.js +8 -0
  47. package/dist/notifiers/googleChatNotifier.js +14 -16
  48. package/dist/notifiers/googleChatNotifier.test.js +1 -0
  49. package/dist/notifiers/slackNotifier.js +16 -14
  50. package/dist/notifiers/slackNotifier.test.js +41 -3
  51. package/dist/notifiers/zoomNotifier.js +7 -10
  52. package/dist/notifiers/zoomNotifier.test.js +1 -0
  53. package/dist/openApi.d.ts +1 -1
  54. package/dist/openApi.test.js +1 -0
  55. package/dist/openApiBuilder.d.ts +39 -6
  56. package/dist/openApiBuilder.js +1 -31
  57. package/dist/openApiBuilder.test.js +1 -0
  58. package/dist/openApiValidator.js +1 -0
  59. package/dist/openApiValidator.test.js +65 -0
  60. package/dist/permissions.d.ts +4 -4
  61. package/dist/permissions.js +67 -65
  62. package/dist/permissions.middleware.test.js +1 -0
  63. package/dist/permissions.test.js +1 -0
  64. package/dist/plugins.d.ts +5 -5
  65. package/dist/plugins.js +18 -9
  66. package/dist/plugins.test.js +1 -1
  67. package/dist/populate.d.ts +15 -8
  68. package/dist/populate.js +23 -24
  69. package/dist/populate.test.js +1 -0
  70. package/dist/realtime/changeStreamWatcher.d.ts +73 -0
  71. package/dist/realtime/changeStreamWatcher.js +720 -0
  72. package/dist/realtime/index.d.ts +6 -0
  73. package/dist/realtime/index.js +27 -0
  74. package/dist/realtime/queryMatcher.d.ts +14 -0
  75. package/dist/realtime/queryMatcher.js +250 -0
  76. package/dist/realtime/queryStore.d.ts +37 -0
  77. package/dist/realtime/queryStore.js +195 -0
  78. package/dist/realtime/realtime.test.d.ts +10 -0
  79. package/dist/realtime/realtime.test.js +2158 -0
  80. package/dist/realtime/realtimeApp.d.ts +93 -0
  81. package/dist/realtime/realtimeApp.js +560 -0
  82. package/dist/realtime/registry.d.ts +40 -0
  83. package/dist/realtime/registry.js +38 -0
  84. package/dist/realtime/socketUser.d.ts +10 -0
  85. package/dist/realtime/socketUser.js +17 -0
  86. package/dist/realtime/types.d.ts +100 -0
  87. package/dist/realtime/types.js +2 -0
  88. package/dist/requestContext.d.ts +37 -0
  89. package/dist/requestContext.js +344 -0
  90. package/dist/requestContext.test.d.ts +1 -0
  91. package/dist/requestContext.test.js +241 -0
  92. package/dist/terrenoApp.d.ts +8 -0
  93. package/dist/terrenoApp.js +50 -13
  94. package/dist/terrenoApp.test.js +194 -21
  95. package/dist/terrenoPlugin.d.ts +11 -0
  96. package/dist/tests/bunSetup.js +1 -0
  97. package/dist/tests.js +1 -1
  98. package/dist/transformers.d.ts +2 -2
  99. package/dist/transformers.js +5 -3
  100. package/dist/transformers.test.js +90 -0
  101. package/dist/types/consentResponse.d.ts +6 -3
  102. package/dist/versionCheckPlugin.d.ts +2 -0
  103. package/dist/versionCheckPlugin.js +18 -12
  104. package/package.json +4 -2
  105. package/src/__tests__/versionCheckPlugin.test.ts +37 -3
  106. package/src/api.arrayOperations.test.ts +1 -0
  107. package/src/api.asyncHandler.test.ts +177 -0
  108. package/src/api.errors.test.ts +1 -0
  109. package/src/api.hooks.test.ts +1 -0
  110. package/src/api.query.test.ts +1 -0
  111. package/src/api.test.ts +132 -0
  112. package/src/api.ts +199 -84
  113. package/src/auth.test.ts +160 -0
  114. package/src/auth.ts +120 -50
  115. package/src/betterAuthApp.test.ts +1 -0
  116. package/src/betterAuthSetup.test.ts +1 -0
  117. package/src/betterAuthSetup.ts +46 -19
  118. package/src/config.test.ts +255 -0
  119. package/src/config.ts +206 -0
  120. package/src/configuration.test.ts +1 -0
  121. package/src/configurationApp.ts +59 -24
  122. package/src/configurationPlugin.test.ts +1 -0
  123. package/src/consentApp.test.ts +1 -0
  124. package/src/envConfigurationPlugin.test.ts +143 -0
  125. package/src/envConfigurationPlugin.ts +100 -0
  126. package/src/errors.test.ts +19 -1
  127. package/src/errors.ts +94 -20
  128. package/src/example.ts +46 -21
  129. package/src/express.d.ts +18 -1
  130. package/src/expressServer.test.ts +50 -2
  131. package/src/expressServer.ts +80 -50
  132. package/src/githubAuth.test.ts +1 -0
  133. package/src/githubAuth.ts +59 -38
  134. package/src/index.ts +4 -0
  135. package/src/logger.ts +47 -17
  136. package/src/models/versionConfig.ts +13 -2
  137. package/src/notifiers/googleChatNotifier.test.ts +1 -0
  138. package/src/notifiers/googleChatNotifier.ts +7 -9
  139. package/src/notifiers/slackNotifier.test.ts +29 -3
  140. package/src/notifiers/slackNotifier.ts +9 -7
  141. package/src/notifiers/zoomNotifier.test.ts +1 -0
  142. package/src/notifiers/zoomNotifier.ts +8 -11
  143. package/src/openApi.test.ts +1 -0
  144. package/src/openApi.ts +4 -4
  145. package/src/openApiBuilder.test.ts +1 -0
  146. package/src/openApiBuilder.ts +14 -11
  147. package/src/openApiValidator.test.ts +59 -0
  148. package/src/openApiValidator.ts +3 -2
  149. package/src/permissions.middleware.test.ts +1 -0
  150. package/src/permissions.test.ts +1 -0
  151. package/src/permissions.ts +30 -25
  152. package/src/plugins.test.ts +1 -1
  153. package/src/plugins.ts +21 -14
  154. package/src/populate.test.ts +1 -0
  155. package/src/populate.ts +44 -36
  156. package/src/realtime/changeStreamWatcher.ts +568 -0
  157. package/src/realtime/index.ts +34 -0
  158. package/src/realtime/queryMatcher.ts +179 -0
  159. package/src/realtime/queryStore.ts +132 -0
  160. package/src/realtime/realtime.test.ts +1755 -0
  161. package/src/realtime/realtimeApp.ts +478 -0
  162. package/src/realtime/registry.ts +64 -0
  163. package/src/realtime/socketUser.ts +25 -0
  164. package/src/realtime/types.ts +112 -0
  165. package/src/requestContext.test.ts +196 -0
  166. package/src/requestContext.ts +368 -0
  167. package/src/terrenoApp.test.ts +137 -11
  168. package/src/terrenoApp.ts +64 -17
  169. package/src/terrenoPlugin.ts +12 -0
  170. package/src/tests/bunSetup.ts +1 -0
  171. package/src/tests.ts +7 -2
  172. package/src/transformers.test.ts +70 -2
  173. package/src/transformers.ts +15 -7
  174. package/src/types/consentResponse.ts +8 -10
  175. package/src/versionCheckPlugin.ts +15 -7
@@ -0,0 +1,328 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ 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);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ 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;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __values = (this && this.__values) || function(o) {
39
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
40
+ if (m) return m.call(o);
41
+ if (o && typeof o.length === "number") return {
42
+ next: function () {
43
+ if (o && i >= o.length) o = void 0;
44
+ return { value: o && o[i++], done: !o };
45
+ }
46
+ };
47
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
48
+ };
49
+ var __read = (this && this.__read) || function (o, n) {
50
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
51
+ if (!m) return o;
52
+ var i = m.call(o), r, ar = [], e;
53
+ try {
54
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
55
+ }
56
+ catch (error) { e = { error: error }; }
57
+ finally {
58
+ try {
59
+ if (r && !r.done && (m = i["return"])) m.call(i);
60
+ }
61
+ finally { if (e) throw e.error; }
62
+ }
63
+ return ar;
64
+ };
65
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
66
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
67
+ if (ar || !(i in from)) {
68
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
69
+ ar[i] = from[i];
70
+ }
71
+ }
72
+ return to.concat(ar || Array.prototype.slice.call(from));
73
+ };
74
+ Object.defineProperty(exports, "__esModule", { value: true });
75
+ var bun_test_1 = require("bun:test");
76
+ var config_1 = require("./config");
77
+ var KEYS = [
78
+ "TERRENO_CFG_STRING",
79
+ "TERRENO_CFG_DEFAULTED",
80
+ "TERRENO_CFG_NUM",
81
+ "TERRENO_CFG_BOOL",
82
+ "TERRENO_CFG_JSON",
83
+ "TERRENO_CFG_UNDEFAULTED",
84
+ "TERRENO_CFG_UNREGISTERED",
85
+ ];
86
+ var resetEnv = function () {
87
+ var e_1, _a;
88
+ try {
89
+ for (var KEYS_1 = __values(KEYS), KEYS_1_1 = KEYS_1.next(); !KEYS_1_1.done; KEYS_1_1 = KEYS_1.next()) {
90
+ var key = KEYS_1_1.value;
91
+ Reflect.deleteProperty(process.env, key);
92
+ }
93
+ }
94
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
95
+ finally {
96
+ try {
97
+ if (KEYS_1_1 && !KEYS_1_1.done && (_a = KEYS_1.return)) _a.call(KEYS_1);
98
+ }
99
+ finally { if (e_1) throw e_1.error; }
100
+ }
101
+ };
102
+ (0, bun_test_1.describe)("Config", function () {
103
+ (0, bun_test_1.beforeEach)(function () {
104
+ config_1.Config.clearRegistryForTesting();
105
+ config_1.Config.clearOverrides();
106
+ config_1.Config.setCachedEnv(null);
107
+ config_1.Config.setEnvLoader(null);
108
+ resetEnv();
109
+ config_1.Config.register("TERRENO_CFG_STRING");
110
+ config_1.Config.register("TERRENO_CFG_DEFAULTED", { default: "fallback" });
111
+ config_1.Config.register("TERRENO_CFG_NUM", { default: "1000" });
112
+ config_1.Config.register("TERRENO_CFG_BOOL", { default: "false" });
113
+ config_1.Config.register("TERRENO_CFG_JSON", { default: "{}" });
114
+ config_1.Config.register("TERRENO_CFG_UNDEFAULTED");
115
+ });
116
+ (0, bun_test_1.afterEach)(function () {
117
+ resetEnv();
118
+ config_1.Config.clearRegistryForTesting();
119
+ config_1.Config.clearOverrides();
120
+ config_1.Config.setCachedEnv(null);
121
+ config_1.Config.setEnvLoader(null);
122
+ });
123
+ (0, bun_test_1.describe)("resolution order", function () {
124
+ (0, bun_test_1.it)("returns the registered default when nothing is set", function () {
125
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_DEFAULTED")).toBe("fallback");
126
+ });
127
+ (0, bun_test_1.it)("returns process.env when set and no cache/override is present", function () {
128
+ process.env.TERRENO_CFG_STRING = "fromEnv";
129
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_STRING")).toBe("fromEnv");
130
+ });
131
+ (0, bun_test_1.it)("cache wins over process.env", function () {
132
+ process.env.TERRENO_CFG_STRING = "fromEnv";
133
+ config_1.Config.setCachedEnv({ TERRENO_CFG_STRING: "fromCache" });
134
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_STRING")).toBe("fromCache");
135
+ });
136
+ (0, bun_test_1.it)("override wins over cache and process.env", function () {
137
+ process.env.TERRENO_CFG_STRING = "fromEnv";
138
+ config_1.Config.setCachedEnv({ TERRENO_CFG_STRING: "fromCache" });
139
+ config_1.Config.setOverride("TERRENO_CFG_STRING", "fromOverride");
140
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_STRING")).toBe("fromOverride");
141
+ });
142
+ (0, bun_test_1.it)("falls through empty-string cache values to process.env", function () {
143
+ process.env.TERRENO_CFG_STRING = "fromEnv";
144
+ config_1.Config.setCachedEnv({ TERRENO_CFG_STRING: "" });
145
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_STRING")).toBe("fromEnv");
146
+ });
147
+ (0, bun_test_1.it)("falls through empty-string process.env to default", function () {
148
+ process.env.TERRENO_CFG_DEFAULTED = "";
149
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_DEFAULTED")).toBe("fallback");
150
+ });
151
+ (0, bun_test_1.it)("returns undefined for an unregistered key with nothing set", function () {
152
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_UNREGISTERED")).toBeUndefined();
153
+ });
154
+ (0, bun_test_1.it)("returns process.env for an unregistered key when set", function () {
155
+ process.env.TERRENO_CFG_UNREGISTERED = "value";
156
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_UNREGISTERED")).toBe("value");
157
+ });
158
+ (0, bun_test_1.it)("setOverride(key, undefined) is treated as 'force unset'", function () {
159
+ process.env.TERRENO_CFG_STRING = "fromEnv";
160
+ config_1.Config.setOverride("TERRENO_CFG_STRING", undefined);
161
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_STRING")).toBeUndefined();
162
+ });
163
+ });
164
+ (0, bun_test_1.describe)("getNumber", function () {
165
+ (0, bun_test_1.it)("parses numeric process.env values", function () {
166
+ process.env.TERRENO_CFG_NUM = "5000";
167
+ (0, bun_test_1.expect)(config_1.Config.getNumber("TERRENO_CFG_NUM")).toBe(5000);
168
+ });
169
+ (0, bun_test_1.it)("parses the registered default", function () {
170
+ (0, bun_test_1.expect)(config_1.Config.getNumber("TERRENO_CFG_NUM")).toBe(1000);
171
+ });
172
+ (0, bun_test_1.it)("returns undefined when no value is available", function () {
173
+ (0, bun_test_1.expect)(config_1.Config.getNumber("TERRENO_CFG_UNDEFAULTED")).toBeUndefined();
174
+ });
175
+ (0, bun_test_1.it)("throws on non-numeric values", function () {
176
+ process.env.TERRENO_CFG_NUM = "not-a-number";
177
+ (0, bun_test_1.expect)(function () { return config_1.Config.getNumber("TERRENO_CFG_NUM"); }).toThrow(/not a valid number/);
178
+ });
179
+ (0, bun_test_1.it)("throws on partially-numeric strings like '5000ms'", function () {
180
+ process.env.TERRENO_CFG_NUM = "5000ms";
181
+ (0, bun_test_1.expect)(function () { return config_1.Config.getNumber("TERRENO_CFG_NUM"); }).toThrow(/not a valid number/);
182
+ });
183
+ (0, bun_test_1.it)("supports floats", function () {
184
+ process.env.TERRENO_CFG_NUM = "3.14";
185
+ (0, bun_test_1.expect)(config_1.Config.getNumber("TERRENO_CFG_NUM")).toBe(3.14);
186
+ });
187
+ });
188
+ (0, bun_test_1.describe)("getBoolean", function () {
189
+ (0, bun_test_1.it)("returns true for 'true'", function () {
190
+ process.env.TERRENO_CFG_BOOL = "true";
191
+ (0, bun_test_1.expect)(config_1.Config.getBoolean("TERRENO_CFG_BOOL")).toBe(true);
192
+ });
193
+ (0, bun_test_1.it)("returns true for 'TRUE' (case-insensitive)", function () {
194
+ process.env.TERRENO_CFG_BOOL = "TRUE";
195
+ (0, bun_test_1.expect)(config_1.Config.getBoolean("TERRENO_CFG_BOOL")).toBe(true);
196
+ });
197
+ (0, bun_test_1.it)("returns false for 'false'", function () {
198
+ process.env.TERRENO_CFG_BOOL = "false";
199
+ (0, bun_test_1.expect)(config_1.Config.getBoolean("TERRENO_CFG_BOOL")).toBe(false);
200
+ });
201
+ (0, bun_test_1.it)("returns false when unset and default is 'false'", function () {
202
+ (0, bun_test_1.expect)(config_1.Config.getBoolean("TERRENO_CFG_BOOL")).toBe(false);
203
+ });
204
+ (0, bun_test_1.it)("returns false for any non-true string", function () {
205
+ process.env.TERRENO_CFG_BOOL = "yes";
206
+ (0, bun_test_1.expect)(config_1.Config.getBoolean("TERRENO_CFG_BOOL")).toBe(false);
207
+ });
208
+ });
209
+ (0, bun_test_1.describe)("getJSON", function () {
210
+ (0, bun_test_1.it)("parses valid JSON", function () {
211
+ process.env.TERRENO_CFG_JSON = JSON.stringify({ hook: "https://example.com" });
212
+ (0, bun_test_1.expect)(config_1.Config.getJSON("TERRENO_CFG_JSON")).toEqual({
213
+ hook: "https://example.com",
214
+ });
215
+ });
216
+ (0, bun_test_1.it)("parses the registered default", function () {
217
+ (0, bun_test_1.expect)(config_1.Config.getJSON("TERRENO_CFG_JSON")).toEqual({});
218
+ });
219
+ (0, bun_test_1.it)("returns undefined when nothing is set and no default exists", function () {
220
+ (0, bun_test_1.expect)(config_1.Config.getJSON("TERRENO_CFG_UNDEFAULTED")).toBeUndefined();
221
+ });
222
+ (0, bun_test_1.it)("throws on malformed JSON instead of silently returning undefined", function () {
223
+ process.env.TERRENO_CFG_JSON = "{not json";
224
+ (0, bun_test_1.expect)(function () { return config_1.Config.getJSON("TERRENO_CFG_JSON"); }).toThrow(/not valid JSON/);
225
+ });
226
+ });
227
+ (0, bun_test_1.describe)("registry", function () {
228
+ (0, bun_test_1.it)("exposes registered keys in sorted order", function () {
229
+ var keys = config_1.Config.getRegisteredKeys();
230
+ var sorted = __spreadArray([], __read(keys), false).sort();
231
+ (0, bun_test_1.expect)(keys).toEqual(sorted);
232
+ });
233
+ (0, bun_test_1.it)("isRegistered returns true for known keys", function () {
234
+ (0, bun_test_1.expect)(config_1.Config.isRegistered("TERRENO_CFG_STRING")).toBe(true);
235
+ });
236
+ (0, bun_test_1.it)("isRegistered returns false for unknown keys", function () {
237
+ (0, bun_test_1.expect)(config_1.Config.isRegistered("NOT_A_REAL_KEY")).toBe(false);
238
+ });
239
+ (0, bun_test_1.it)("getDefault returns the registered default", function () {
240
+ (0, bun_test_1.expect)(config_1.Config.getDefault("TERRENO_CFG_DEFAULTED")).toBe("fallback");
241
+ });
242
+ (0, bun_test_1.it)("getDefault returns undefined for keys with no default", function () {
243
+ (0, bun_test_1.expect)(config_1.Config.getDefault("TERRENO_CFG_STRING")).toBeUndefined();
244
+ });
245
+ (0, bun_test_1.it)("getRegistration exposes secret + description metadata", function () {
246
+ config_1.Config.register("TERRENO_CFG_WITH_META", {
247
+ description: "A secret thing",
248
+ secret: true,
249
+ });
250
+ var meta = config_1.Config.getRegistration("TERRENO_CFG_WITH_META");
251
+ (0, bun_test_1.expect)(meta === null || meta === void 0 ? void 0 : meta.secret).toBe(true);
252
+ (0, bun_test_1.expect)(meta === null || meta === void 0 ? void 0 : meta.description).toBe("A secret thing");
253
+ });
254
+ (0, bun_test_1.it)("re-registering the same key throws", function () {
255
+ (0, bun_test_1.expect)(function () { return config_1.Config.register("TERRENO_CFG_STRING"); }).toThrow(/registered more than once/);
256
+ });
257
+ (0, bun_test_1.it)("does not treat Object prototype keys as registered", function () {
258
+ (0, bun_test_1.expect)(config_1.Config.isRegistered("constructor")).toBe(false);
259
+ (0, bun_test_1.expect)(config_1.Config.isRegistered("toString")).toBe(false);
260
+ (0, bun_test_1.expect)(config_1.Config.isRegistered("hasOwnProperty")).toBe(false);
261
+ // And re-registering one of these names should still succeed.
262
+ (0, bun_test_1.expect)(function () { return config_1.Config.register("toString", { default: "x" }); }).not.toThrow();
263
+ (0, bun_test_1.expect)(config_1.Config.get("toString")).toBe("x");
264
+ });
265
+ });
266
+ (0, bun_test_1.describe)("clearOverrides", function () {
267
+ (0, bun_test_1.it)("removes all overrides", function () {
268
+ config_1.Config.setOverride("TERRENO_CFG_STRING", "x");
269
+ config_1.Config.setOverride("TERRENO_CFG_DEFAULTED", "y");
270
+ config_1.Config.clearOverrides();
271
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_STRING")).toBeUndefined();
272
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_DEFAULTED")).toBe("fallback");
273
+ });
274
+ });
275
+ (0, bun_test_1.describe)("refresh", function () {
276
+ (0, bun_test_1.it)("loads values via the registered env loader", function () { return __awaiter(void 0, void 0, void 0, function () {
277
+ return __generator(this, function (_a) {
278
+ switch (_a.label) {
279
+ case 0:
280
+ config_1.Config.setEnvLoader(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
281
+ return [2 /*return*/, ({ TERRENO_CFG_STRING: "fromLoader" })];
282
+ }); }); });
283
+ return [4 /*yield*/, config_1.Config.refresh()];
284
+ case 1:
285
+ _a.sent();
286
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_STRING")).toBe("fromLoader");
287
+ return [2 /*return*/];
288
+ }
289
+ });
290
+ }); });
291
+ (0, bun_test_1.it)("clears the cache when no loader is registered", function () { return __awaiter(void 0, void 0, void 0, function () {
292
+ return __generator(this, function (_a) {
293
+ switch (_a.label) {
294
+ case 0:
295
+ config_1.Config.setCachedEnv({ TERRENO_CFG_STRING: "stale" });
296
+ config_1.Config.setEnvLoader(null);
297
+ return [4 /*yield*/, config_1.Config.refresh()];
298
+ case 1:
299
+ _a.sent();
300
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_STRING")).toBeUndefined();
301
+ return [2 /*return*/];
302
+ }
303
+ });
304
+ }); });
305
+ (0, bun_test_1.it)("updates the cache on each refresh", function () { return __awaiter(void 0, void 0, void 0, function () {
306
+ var payload;
307
+ return __generator(this, function (_a) {
308
+ switch (_a.label) {
309
+ case 0:
310
+ payload = { TERRENO_CFG_STRING: "first" };
311
+ config_1.Config.setEnvLoader(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
312
+ return [2 /*return*/, payload];
313
+ }); }); });
314
+ return [4 /*yield*/, config_1.Config.refresh()];
315
+ case 1:
316
+ _a.sent();
317
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_STRING")).toBe("first");
318
+ payload = { TERRENO_CFG_STRING: "second" };
319
+ return [4 /*yield*/, config_1.Config.refresh()];
320
+ case 2:
321
+ _a.sent();
322
+ (0, bun_test_1.expect)(config_1.Config.get("TERRENO_CFG_STRING")).toBe("second");
323
+ return [2 /*return*/];
324
+ }
325
+ });
326
+ }); });
327
+ });
328
+ });
@@ -72,6 +72,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
72
72
  return (mod && mod.__esModule) ? mod : { "default": mod };
73
73
  };
74
74
  Object.defineProperty(exports, "__esModule", { value: true });
75
+ // biome-ignore-all lint/suspicious/noExplicitAny: test mock typing
75
76
  var bun_test_1 = require("bun:test");
76
77
  var mongoose_1 = __importStar(require("mongoose"));
77
78
  var supertest_1 = __importDefault(require("supertest"));
@@ -9,7 +9,7 @@ interface ConfigFieldMeta {
9
9
  required: boolean;
10
10
  description?: string;
11
11
  enum?: string[];
12
- default?: any;
12
+ default?: unknown;
13
13
  secret?: boolean;
14
14
  widget?: string;
15
15
  }
@@ -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 {};