@terreno/api 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +9 -8
- package/dist/betterAuthSetup.js +1 -1
- package/dist/configuration.test.d.ts +1 -0
- package/dist/configuration.test.js +699 -0
- package/dist/configurationApp.d.ts +91 -0
- package/dist/configurationApp.js +407 -0
- package/dist/configurationPlugin.d.ts +102 -0
- package/dist/configurationPlugin.js +285 -0
- package/dist/configurationPlugin.test.d.ts +1 -0
- package/dist/configurationPlugin.test.js +509 -0
- package/dist/example.js +1 -1
- package/dist/expressServer.js +5 -1
- package/dist/githubAuth.js +2 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/openApiCompat.d.ts +23 -0
- package/dist/openApiCompat.js +198 -0
- package/dist/scriptRunner.d.ts +52 -0
- package/dist/scriptRunner.js +231 -0
- package/dist/secretProviders.d.ts +47 -0
- package/dist/secretProviders.js +214 -0
- package/dist/terrenoApp.d.ts +25 -0
- package/dist/terrenoApp.js +49 -2
- package/dist/tests.d.ts +27 -9
- package/dist/tests.js +10 -1
- package/package.json +13 -13
- package/src/api.ts +9 -8
- package/src/betterAuthSetup.ts +2 -2
- package/src/configuration.test.ts +398 -0
- package/src/configurationApp.ts +359 -0
- package/src/configurationPlugin.test.ts +299 -0
- package/src/configurationPlugin.ts +288 -0
- package/src/example.ts +1 -1
- package/src/expressServer.ts +6 -1
- package/src/githubAuth.ts +4 -4
- package/src/index.ts +5 -0
- package/src/openApiCompat.ts +147 -0
- package/src/permissions.ts +1 -1
- package/src/scriptRunner.ts +219 -0
- package/src/secretProviders.ts +109 -0
- package/src/terrenoApp.ts +44 -2
- package/src/tests.ts +12 -1
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
45
|
+
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);
|
|
46
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
47
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
48
|
+
function step(op) {
|
|
49
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
50
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
51
|
+
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;
|
|
52
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
53
|
+
switch (op[0]) {
|
|
54
|
+
case 0: case 1: t = op; break;
|
|
55
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
56
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
57
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
58
|
+
default:
|
|
59
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
60
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
61
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
62
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
63
|
+
if (t[2]) _.ops.pop();
|
|
64
|
+
_.trys.pop(); continue;
|
|
65
|
+
}
|
|
66
|
+
op = body.call(thisArg, _);
|
|
67
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
68
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
72
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
73
|
+
if (!m) return o;
|
|
74
|
+
var i = m.call(o), r, ar = [], e;
|
|
75
|
+
try {
|
|
76
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
77
|
+
}
|
|
78
|
+
catch (error) { e = { error: error }; }
|
|
79
|
+
finally {
|
|
80
|
+
try {
|
|
81
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
82
|
+
}
|
|
83
|
+
finally { if (e) throw e.error; }
|
|
84
|
+
}
|
|
85
|
+
return ar;
|
|
86
|
+
};
|
|
87
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
88
|
+
var bun_test_1 = require("bun:test");
|
|
89
|
+
var mongoose_1 = __importStar(require("mongoose"));
|
|
90
|
+
var configurationPlugin_1 = require("./configurationPlugin");
|
|
91
|
+
var testConfigSchema = new mongoose_1.Schema({
|
|
92
|
+
apiKey: {
|
|
93
|
+
default: "",
|
|
94
|
+
description: "External API key",
|
|
95
|
+
secret: true,
|
|
96
|
+
secretName: "ext-api-key",
|
|
97
|
+
type: String,
|
|
98
|
+
},
|
|
99
|
+
appName: {
|
|
100
|
+
default: "Test App",
|
|
101
|
+
description: "Application name",
|
|
102
|
+
type: String,
|
|
103
|
+
},
|
|
104
|
+
maintenanceMode: {
|
|
105
|
+
default: false,
|
|
106
|
+
description: "Whether maintenance mode is on",
|
|
107
|
+
type: Boolean,
|
|
108
|
+
},
|
|
109
|
+
nested: {
|
|
110
|
+
type: new mongoose_1.Schema({
|
|
111
|
+
secretToken: {
|
|
112
|
+
default: "",
|
|
113
|
+
description: "A nested secret token",
|
|
114
|
+
secret: true,
|
|
115
|
+
secretName: "nested-token",
|
|
116
|
+
secretProvider: "vault",
|
|
117
|
+
type: String,
|
|
118
|
+
},
|
|
119
|
+
webhookUrl: {
|
|
120
|
+
default: "https://example.com/hook",
|
|
121
|
+
description: "Webhook URL",
|
|
122
|
+
type: String,
|
|
123
|
+
},
|
|
124
|
+
}),
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
testConfigSchema.plugin(configurationPlugin_1.configurationPlugin);
|
|
128
|
+
var TestConfigModel = (0, mongoose_1.model)("TestConfiguration", testConfigSchema);
|
|
129
|
+
// --- Simple schema for singleton tests ---
|
|
130
|
+
var simpleSchema = new mongoose_1.Schema({
|
|
131
|
+
value: { default: "default", description: "A value", type: String },
|
|
132
|
+
});
|
|
133
|
+
simpleSchema.plugin(configurationPlugin_1.configurationPlugin);
|
|
134
|
+
var SimpleConfigModel = (0, mongoose_1.model)("SimpleConfiguration", simpleSchema);
|
|
135
|
+
(0, bun_test_1.describe)("configurationPlugin", function () {
|
|
136
|
+
(0, bun_test_1.describe)("schema setup", function () {
|
|
137
|
+
(0, bun_test_1.it)("adds a _singleton field with unique index", function () {
|
|
138
|
+
var indexes = SimpleConfigModel.schema.indexes();
|
|
139
|
+
var singletonIndex = indexes.find(function (_a) {
|
|
140
|
+
var _b = __read(_a, 1), fields = _b[0];
|
|
141
|
+
return fields._singleton !== undefined;
|
|
142
|
+
});
|
|
143
|
+
(0, bun_test_1.expect)(singletonIndex).toBeDefined();
|
|
144
|
+
(0, bun_test_1.expect)(singletonIndex[1].unique).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
(0, bun_test_1.it)("adds getConfig static", function () {
|
|
147
|
+
(0, bun_test_1.expect)(typeof SimpleConfigModel.getConfig).toBe("function");
|
|
148
|
+
});
|
|
149
|
+
(0, bun_test_1.it)("adds updateConfig static", function () {
|
|
150
|
+
(0, bun_test_1.expect)(typeof SimpleConfigModel.updateConfig).toBe("function");
|
|
151
|
+
});
|
|
152
|
+
(0, bun_test_1.it)("adds getSecretFields static", function () {
|
|
153
|
+
(0, bun_test_1.expect)(typeof TestConfigModel.getSecretFields).toBe("function");
|
|
154
|
+
});
|
|
155
|
+
(0, bun_test_1.it)("adds resolveSecrets static", function () {
|
|
156
|
+
(0, bun_test_1.expect)(typeof TestConfigModel.resolveSecrets).toBe("function");
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
(0, bun_test_1.describe)("getSecretFields", function () {
|
|
160
|
+
(0, bun_test_1.it)("discovers top-level secret fields", function () {
|
|
161
|
+
var secrets = TestConfigModel.getSecretFields();
|
|
162
|
+
var apiKeySecret = secrets.find(function (s) { return s.path === "apiKey"; });
|
|
163
|
+
(0, bun_test_1.expect)(apiKeySecret).toBeDefined();
|
|
164
|
+
(0, bun_test_1.expect)(apiKeySecret.secretName).toBe("ext-api-key");
|
|
165
|
+
});
|
|
166
|
+
(0, bun_test_1.it)("discovers nested secret fields", function () {
|
|
167
|
+
var secrets = TestConfigModel.getSecretFields();
|
|
168
|
+
var nestedSecret = secrets.find(function (s) { return s.path === "nested.secretToken"; });
|
|
169
|
+
(0, bun_test_1.expect)(nestedSecret).toBeDefined();
|
|
170
|
+
(0, bun_test_1.expect)(nestedSecret.secretName).toBe("nested-token");
|
|
171
|
+
(0, bun_test_1.expect)(nestedSecret.secretProvider).toBe("vault");
|
|
172
|
+
});
|
|
173
|
+
(0, bun_test_1.it)("does not include non-secret fields", function () {
|
|
174
|
+
var secrets = TestConfigModel.getSecretFields();
|
|
175
|
+
var nonSecret = secrets.find(function (s) { return s.path === "appName"; });
|
|
176
|
+
(0, bun_test_1.expect)(nonSecret).toBeUndefined();
|
|
177
|
+
});
|
|
178
|
+
(0, bun_test_1.it)("returns the correct total count of secret fields", function () {
|
|
179
|
+
var secrets = TestConfigModel.getSecretFields();
|
|
180
|
+
(0, bun_test_1.expect)(secrets.length).toBe(2);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
(0, bun_test_1.describe)("resolveSecrets", function () {
|
|
184
|
+
(0, bun_test_1.it)("resolves secrets from a provider", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
185
|
+
var provider, resolved;
|
|
186
|
+
return __generator(this, function (_a) {
|
|
187
|
+
switch (_a.label) {
|
|
188
|
+
case 0:
|
|
189
|
+
provider = {
|
|
190
|
+
getSecret: function (name) { return __awaiter(void 0, void 0, void 0, function () {
|
|
191
|
+
return __generator(this, function (_a) {
|
|
192
|
+
if (name === "ext-api-key") {
|
|
193
|
+
return [2 /*return*/, "resolved-api-key"];
|
|
194
|
+
}
|
|
195
|
+
if (name === "nested-token") {
|
|
196
|
+
return [2 /*return*/, "resolved-token"];
|
|
197
|
+
}
|
|
198
|
+
return [2 /*return*/, null];
|
|
199
|
+
});
|
|
200
|
+
}); },
|
|
201
|
+
name: "test-provider",
|
|
202
|
+
};
|
|
203
|
+
return [4 /*yield*/, TestConfigModel.resolveSecrets(provider)];
|
|
204
|
+
case 1:
|
|
205
|
+
resolved = _a.sent();
|
|
206
|
+
(0, bun_test_1.expect)(resolved.get("apiKey")).toBe("resolved-api-key");
|
|
207
|
+
(0, bun_test_1.expect)(resolved.get("nested.secretToken")).toBe("resolved-token");
|
|
208
|
+
return [2 /*return*/];
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}); });
|
|
212
|
+
(0, bun_test_1.it)("handles provider failures gracefully", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
213
|
+
var provider, resolved;
|
|
214
|
+
return __generator(this, function (_a) {
|
|
215
|
+
switch (_a.label) {
|
|
216
|
+
case 0:
|
|
217
|
+
provider = {
|
|
218
|
+
getSecret: function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
219
|
+
return __generator(this, function (_a) {
|
|
220
|
+
throw new Error("provider down");
|
|
221
|
+
});
|
|
222
|
+
}); },
|
|
223
|
+
name: "failing-provider",
|
|
224
|
+
};
|
|
225
|
+
return [4 /*yield*/, TestConfigModel.resolveSecrets(provider)];
|
|
226
|
+
case 1:
|
|
227
|
+
resolved = _a.sent();
|
|
228
|
+
(0, bun_test_1.expect)(resolved.size).toBe(0);
|
|
229
|
+
return [2 /*return*/];
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}); });
|
|
233
|
+
(0, bun_test_1.it)("handles partial resolution", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
234
|
+
var provider, resolved;
|
|
235
|
+
return __generator(this, function (_a) {
|
|
236
|
+
switch (_a.label) {
|
|
237
|
+
case 0:
|
|
238
|
+
provider = {
|
|
239
|
+
getSecret: function (name) { return __awaiter(void 0, void 0, void 0, function () {
|
|
240
|
+
return __generator(this, function (_a) {
|
|
241
|
+
if (name === "ext-api-key") {
|
|
242
|
+
return [2 /*return*/, "resolved-key"];
|
|
243
|
+
}
|
|
244
|
+
return [2 /*return*/, null];
|
|
245
|
+
});
|
|
246
|
+
}); },
|
|
247
|
+
name: "partial-provider",
|
|
248
|
+
};
|
|
249
|
+
return [4 /*yield*/, TestConfigModel.resolveSecrets(provider)];
|
|
250
|
+
case 1:
|
|
251
|
+
resolved = _a.sent();
|
|
252
|
+
(0, bun_test_1.expect)(resolved.size).toBe(1);
|
|
253
|
+
(0, bun_test_1.expect)(resolved.get("apiKey")).toBe("resolved-key");
|
|
254
|
+
return [2 /*return*/];
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}); });
|
|
258
|
+
});
|
|
259
|
+
(0, bun_test_1.describe)("singleton behavior (requires MongoDB)", function () {
|
|
260
|
+
var dbConnected = false;
|
|
261
|
+
(0, bun_test_1.beforeAll)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
262
|
+
var _a;
|
|
263
|
+
return __generator(this, function (_b) {
|
|
264
|
+
switch (_b.label) {
|
|
265
|
+
case 0:
|
|
266
|
+
_b.trys.push([0, 4, , 5]);
|
|
267
|
+
if (!(mongoose_1.default.connection.readyState === 1)) return [3 /*break*/, 1];
|
|
268
|
+
dbConnected = true;
|
|
269
|
+
return [3 /*break*/, 3];
|
|
270
|
+
case 1: return [4 /*yield*/, mongoose_1.default.connect("mongodb://127.0.0.1/terreno-config-test", {
|
|
271
|
+
connectTimeoutMS: 3000,
|
|
272
|
+
serverSelectionTimeoutMS: 3000,
|
|
273
|
+
})];
|
|
274
|
+
case 2:
|
|
275
|
+
_b.sent();
|
|
276
|
+
dbConnected = true;
|
|
277
|
+
_b.label = 3;
|
|
278
|
+
case 3: return [3 /*break*/, 5];
|
|
279
|
+
case 4:
|
|
280
|
+
_a = _b.sent();
|
|
281
|
+
dbConnected = false;
|
|
282
|
+
return [3 /*break*/, 5];
|
|
283
|
+
case 5: return [2 /*return*/];
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}); });
|
|
287
|
+
(0, bun_test_1.afterAll)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
288
|
+
var _a;
|
|
289
|
+
var _b;
|
|
290
|
+
return __generator(this, function (_c) {
|
|
291
|
+
switch (_c.label) {
|
|
292
|
+
case 0:
|
|
293
|
+
if (!(dbConnected && mongoose_1.default.connection.readyState === 1)) return [3 /*break*/, 4];
|
|
294
|
+
_c.label = 1;
|
|
295
|
+
case 1:
|
|
296
|
+
_c.trys.push([1, 3, , 4]);
|
|
297
|
+
return [4 /*yield*/, ((_b = mongoose_1.default.connection.db) === null || _b === void 0 ? void 0 : _b.dropDatabase())];
|
|
298
|
+
case 2:
|
|
299
|
+
_c.sent();
|
|
300
|
+
return [3 /*break*/, 4];
|
|
301
|
+
case 3:
|
|
302
|
+
_a = _c.sent();
|
|
303
|
+
return [3 /*break*/, 4];
|
|
304
|
+
case 4: return [2 /*return*/];
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
}); });
|
|
308
|
+
(0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
309
|
+
var _a;
|
|
310
|
+
return __generator(this, function (_b) {
|
|
311
|
+
switch (_b.label) {
|
|
312
|
+
case 0:
|
|
313
|
+
if (!dbConnected) {
|
|
314
|
+
return [2 /*return*/];
|
|
315
|
+
}
|
|
316
|
+
_b.label = 1;
|
|
317
|
+
case 1:
|
|
318
|
+
_b.trys.push([1, 3, , 4]);
|
|
319
|
+
return [4 /*yield*/, SimpleConfigModel.collection.drop()];
|
|
320
|
+
case 2:
|
|
321
|
+
_b.sent();
|
|
322
|
+
return [3 /*break*/, 4];
|
|
323
|
+
case 3:
|
|
324
|
+
_a = _b.sent();
|
|
325
|
+
return [3 /*break*/, 4];
|
|
326
|
+
case 4: return [4 /*yield*/, SimpleConfigModel.ensureIndexes()];
|
|
327
|
+
case 5:
|
|
328
|
+
_b.sent();
|
|
329
|
+
return [2 /*return*/];
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}); });
|
|
333
|
+
(0, bun_test_1.it)("creates a document via getConfig when none exists", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
334
|
+
var config;
|
|
335
|
+
return __generator(this, function (_a) {
|
|
336
|
+
switch (_a.label) {
|
|
337
|
+
case 0:
|
|
338
|
+
if (!dbConnected) {
|
|
339
|
+
return [2 /*return*/];
|
|
340
|
+
}
|
|
341
|
+
return [4 /*yield*/, SimpleConfigModel.getConfig()];
|
|
342
|
+
case 1:
|
|
343
|
+
config = _a.sent();
|
|
344
|
+
(0, bun_test_1.expect)(config).toBeDefined();
|
|
345
|
+
(0, bun_test_1.expect)(config.value).toBe("default");
|
|
346
|
+
return [2 /*return*/];
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
}); });
|
|
350
|
+
(0, bun_test_1.it)("returns the same document on subsequent getConfig calls", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
351
|
+
var first, second;
|
|
352
|
+
return __generator(this, function (_a) {
|
|
353
|
+
switch (_a.label) {
|
|
354
|
+
case 0:
|
|
355
|
+
if (!dbConnected) {
|
|
356
|
+
return [2 /*return*/];
|
|
357
|
+
}
|
|
358
|
+
return [4 /*yield*/, SimpleConfigModel.getConfig()];
|
|
359
|
+
case 1:
|
|
360
|
+
first = _a.sent();
|
|
361
|
+
return [4 /*yield*/, SimpleConfigModel.getConfig()];
|
|
362
|
+
case 2:
|
|
363
|
+
second = _a.sent();
|
|
364
|
+
(0, bun_test_1.expect)(first._id.toString()).toBe(second._id.toString());
|
|
365
|
+
return [2 /*return*/];
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
}); });
|
|
369
|
+
(0, bun_test_1.it)("prevents creating a second document via save", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
370
|
+
var duplicate;
|
|
371
|
+
return __generator(this, function (_a) {
|
|
372
|
+
switch (_a.label) {
|
|
373
|
+
case 0:
|
|
374
|
+
if (!dbConnected) {
|
|
375
|
+
return [2 /*return*/];
|
|
376
|
+
}
|
|
377
|
+
return [4 /*yield*/, SimpleConfigModel.getConfig()];
|
|
378
|
+
case 1:
|
|
379
|
+
_a.sent();
|
|
380
|
+
duplicate = new SimpleConfigModel({ value: "duplicate" });
|
|
381
|
+
return [4 /*yield*/, (0, bun_test_1.expect)(duplicate.save()).rejects.toThrow()];
|
|
382
|
+
case 2:
|
|
383
|
+
_a.sent();
|
|
384
|
+
return [2 /*return*/];
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
}); });
|
|
388
|
+
(0, bun_test_1.it)("updates an existing document via updateConfig", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
389
|
+
var updated, count;
|
|
390
|
+
return __generator(this, function (_a) {
|
|
391
|
+
switch (_a.label) {
|
|
392
|
+
case 0:
|
|
393
|
+
if (!dbConnected) {
|
|
394
|
+
return [2 /*return*/];
|
|
395
|
+
}
|
|
396
|
+
return [4 /*yield*/, SimpleConfigModel.getConfig()];
|
|
397
|
+
case 1:
|
|
398
|
+
_a.sent();
|
|
399
|
+
return [4 /*yield*/, SimpleConfigModel.updateConfig({ value: "updated" })];
|
|
400
|
+
case 2:
|
|
401
|
+
updated = _a.sent();
|
|
402
|
+
(0, bun_test_1.expect)(updated.value).toBe("updated");
|
|
403
|
+
return [4 /*yield*/, SimpleConfigModel.countDocuments()];
|
|
404
|
+
case 3:
|
|
405
|
+
count = _a.sent();
|
|
406
|
+
(0, bun_test_1.expect)(count).toBe(1);
|
|
407
|
+
return [2 /*return*/];
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
}); });
|
|
411
|
+
(0, bun_test_1.it)("creates a document with values if none exists via updateConfig", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
412
|
+
var config;
|
|
413
|
+
return __generator(this, function (_a) {
|
|
414
|
+
switch (_a.label) {
|
|
415
|
+
case 0:
|
|
416
|
+
if (!dbConnected) {
|
|
417
|
+
return [2 /*return*/];
|
|
418
|
+
}
|
|
419
|
+
return [4 /*yield*/, SimpleConfigModel.updateConfig({ value: "custom" })];
|
|
420
|
+
case 1:
|
|
421
|
+
config = _a.sent();
|
|
422
|
+
(0, bun_test_1.expect)(config.value).toBe("custom");
|
|
423
|
+
return [2 /*return*/];
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
}); });
|
|
427
|
+
(0, bun_test_1.it)("prevents deleteOne", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
428
|
+
var err_1;
|
|
429
|
+
return __generator(this, function (_a) {
|
|
430
|
+
switch (_a.label) {
|
|
431
|
+
case 0:
|
|
432
|
+
if (!dbConnected) {
|
|
433
|
+
return [2 /*return*/];
|
|
434
|
+
}
|
|
435
|
+
return [4 /*yield*/, SimpleConfigModel.getConfig()];
|
|
436
|
+
case 1:
|
|
437
|
+
_a.sent();
|
|
438
|
+
_a.label = 2;
|
|
439
|
+
case 2:
|
|
440
|
+
_a.trys.push([2, 4, , 5]);
|
|
441
|
+
return [4 /*yield*/, SimpleConfigModel.deleteOne({}).exec()];
|
|
442
|
+
case 3:
|
|
443
|
+
_a.sent();
|
|
444
|
+
bun_test_1.expect.unreachable("Should have thrown");
|
|
445
|
+
return [3 /*break*/, 5];
|
|
446
|
+
case 4:
|
|
447
|
+
err_1 = _a.sent();
|
|
448
|
+
(0, bun_test_1.expect)(err_1.title).toMatch(/Cannot hard-delete the configuration document/);
|
|
449
|
+
return [3 /*break*/, 5];
|
|
450
|
+
case 5: return [2 /*return*/];
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
}); });
|
|
454
|
+
(0, bun_test_1.it)("prevents findOneAndDelete", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
455
|
+
var err_2;
|
|
456
|
+
return __generator(this, function (_a) {
|
|
457
|
+
switch (_a.label) {
|
|
458
|
+
case 0:
|
|
459
|
+
if (!dbConnected) {
|
|
460
|
+
return [2 /*return*/];
|
|
461
|
+
}
|
|
462
|
+
return [4 /*yield*/, SimpleConfigModel.getConfig()];
|
|
463
|
+
case 1:
|
|
464
|
+
_a.sent();
|
|
465
|
+
_a.label = 2;
|
|
466
|
+
case 2:
|
|
467
|
+
_a.trys.push([2, 4, , 5]);
|
|
468
|
+
return [4 /*yield*/, SimpleConfigModel.findOneAndDelete({}).exec()];
|
|
469
|
+
case 3:
|
|
470
|
+
_a.sent();
|
|
471
|
+
bun_test_1.expect.unreachable("Should have thrown");
|
|
472
|
+
return [3 /*break*/, 5];
|
|
473
|
+
case 4:
|
|
474
|
+
err_2 = _a.sent();
|
|
475
|
+
(0, bun_test_1.expect)(err_2.title).toMatch(/Cannot hard-delete the configuration document/);
|
|
476
|
+
return [3 /*break*/, 5];
|
|
477
|
+
case 5: return [2 /*return*/];
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
}); });
|
|
481
|
+
(0, bun_test_1.it)("prevents deleteMany", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
482
|
+
var err_3;
|
|
483
|
+
return __generator(this, function (_a) {
|
|
484
|
+
switch (_a.label) {
|
|
485
|
+
case 0:
|
|
486
|
+
if (!dbConnected) {
|
|
487
|
+
return [2 /*return*/];
|
|
488
|
+
}
|
|
489
|
+
return [4 /*yield*/, SimpleConfigModel.getConfig()];
|
|
490
|
+
case 1:
|
|
491
|
+
_a.sent();
|
|
492
|
+
_a.label = 2;
|
|
493
|
+
case 2:
|
|
494
|
+
_a.trys.push([2, 4, , 5]);
|
|
495
|
+
return [4 /*yield*/, SimpleConfigModel.deleteMany({}).exec()];
|
|
496
|
+
case 3:
|
|
497
|
+
_a.sent();
|
|
498
|
+
bun_test_1.expect.unreachable("Should have thrown");
|
|
499
|
+
return [3 /*break*/, 5];
|
|
500
|
+
case 4:
|
|
501
|
+
err_3 = _a.sent();
|
|
502
|
+
(0, bun_test_1.expect)(err_3.title).toMatch(/Cannot hard-delete the configuration document/);
|
|
503
|
+
return [3 /*break*/, 5];
|
|
504
|
+
case 5: return [2 /*return*/];
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
}); });
|
|
508
|
+
});
|
|
509
|
+
});
|
package/dist/example.js
CHANGED
|
@@ -82,7 +82,7 @@ var schema = new mongoose_1.Schema({
|
|
|
82
82
|
var FoodModel = (0, mongoose_1.model)("Food", schema);
|
|
83
83
|
function getBaseServer() {
|
|
84
84
|
var app = (0, express_1.default)();
|
|
85
|
-
app.
|
|
85
|
+
app.use(function (req, res, next) {
|
|
86
86
|
res.header("Access-Control-Allow-Origin", "*");
|
|
87
87
|
res.header("Access-Control-Allow-Headers", "*");
|
|
88
88
|
// intercepts OPTIONS method
|
package/dist/expressServer.js
CHANGED
|
@@ -118,6 +118,7 @@ var errors_1 = require("./errors");
|
|
|
118
118
|
var githubAuth_1 = require("./githubAuth");
|
|
119
119
|
var logger_1 = require("./logger");
|
|
120
120
|
var notifiers_1 = require("./notifiers");
|
|
121
|
+
var openApiCompat_1 = require("./openApiCompat");
|
|
121
122
|
var openApiEtag_1 = require("./openApiEtag");
|
|
122
123
|
var SLOW_READ_MAX = 200;
|
|
123
124
|
var SLOW_WRITE_MAX = 500;
|
|
@@ -234,6 +235,8 @@ function initializeRoutes(UserModel, addRoutes, options) {
|
|
|
234
235
|
var _a;
|
|
235
236
|
if (options === void 0) { options = {}; }
|
|
236
237
|
var app = (0, express_1.default)();
|
|
238
|
+
// Record mount paths on layers for Express 5 → OpenAPI compat
|
|
239
|
+
(0, openApiCompat_1.patchAppUse)(app);
|
|
237
240
|
// TODO: Log a warning when we hit the array limit.
|
|
238
241
|
app.set("query parser", function (str) { var _a; return qs_1.default.parse(str, { arrayLimit: (_a = options.arrayLimit) !== null && _a !== void 0 ? _a : 200 }); });
|
|
239
242
|
app.use((0, cors_1.default)({
|
|
@@ -255,7 +258,7 @@ function initializeRoutes(UserModel, addRoutes, options) {
|
|
|
255
258
|
next();
|
|
256
259
|
});
|
|
257
260
|
// Add Sentry scopes for session, transaction, and userId if any are set
|
|
258
|
-
app.
|
|
261
|
+
app.use(function (req, _res, next) {
|
|
259
262
|
var _a;
|
|
260
263
|
var transactionId = req.header("X-Transaction-ID");
|
|
261
264
|
var sessionId = req.header("X-Session-ID");
|
|
@@ -271,6 +274,7 @@ function initializeRoutes(UserModel, addRoutes, options) {
|
|
|
271
274
|
next();
|
|
272
275
|
});
|
|
273
276
|
// Add ETag middleware for OpenAPI JSON endpoint before the openapi middleware
|
|
277
|
+
app.use(openApiCompat_1.openApiCompatMiddleware);
|
|
274
278
|
app.use(openApiEtag_1.openApiEtagMiddleware);
|
|
275
279
|
var oapi = (0, openapi_1.default)({
|
|
276
280
|
info: {
|
package/dist/githubAuth.js
CHANGED
|
@@ -80,7 +80,7 @@ function setupGitHubAuth(_app, userModel, githubOptions) {
|
|
|
80
80
|
clientSecret: githubOptions.clientSecret,
|
|
81
81
|
passReqToCallback: true,
|
|
82
82
|
scope: scope,
|
|
83
|
-
}, function (req, accessToken, refreshToken, profile, done) { return __awaiter(_this, void 0, void 0, function () {
|
|
83
|
+
}, (function (req, accessToken, refreshToken, profile, done) { return __awaiter(_this, void 0, void 0, function () {
|
|
84
84
|
var existingUser, user, githubId, existingGitHubUser, user, email, existingEmailUser, newUser, error_1;
|
|
85
85
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
86
86
|
return __generator(this, function (_j) {
|
|
@@ -166,7 +166,7 @@ function setupGitHubAuth(_app, userModel, githubOptions) {
|
|
|
166
166
|
case 14: return [2 /*return*/];
|
|
167
167
|
}
|
|
168
168
|
});
|
|
169
|
-
}); }));
|
|
169
|
+
}); })));
|
|
170
170
|
}
|
|
171
171
|
/**
|
|
172
172
|
* Adds GitHub OAuth routes to the Express application.
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export * from "./auth";
|
|
|
3
3
|
export * from "./betterAuth";
|
|
4
4
|
export * from "./betterAuthApp";
|
|
5
5
|
export * from "./betterAuthSetup";
|
|
6
|
+
export * from "./configurationApp";
|
|
7
|
+
export * from "./configurationPlugin";
|
|
6
8
|
export * from "./errors";
|
|
7
9
|
export * from "./expressServer";
|
|
8
10
|
export * from "./githubAuth";
|
|
@@ -10,11 +12,14 @@ export * from "./logger";
|
|
|
10
12
|
export * from "./middleware";
|
|
11
13
|
export * from "./notifiers";
|
|
12
14
|
export * from "./openApiBuilder";
|
|
15
|
+
export * from "./openApiCompat";
|
|
13
16
|
export * from "./openApiEtag";
|
|
14
17
|
export * from "./openApiValidator";
|
|
15
18
|
export * from "./permissions";
|
|
16
19
|
export * from "./plugins";
|
|
17
20
|
export * from "./populate";
|
|
21
|
+
export * from "./scriptRunner";
|
|
22
|
+
export * from "./secretProviders";
|
|
18
23
|
export * from "./terrenoApp";
|
|
19
24
|
export * from "./terrenoPlugin";
|
|
20
25
|
export * from "./transformers";
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,8 @@ __exportStar(require("./auth"), exports);
|
|
|
19
19
|
__exportStar(require("./betterAuth"), exports);
|
|
20
20
|
__exportStar(require("./betterAuthApp"), exports);
|
|
21
21
|
__exportStar(require("./betterAuthSetup"), exports);
|
|
22
|
+
__exportStar(require("./configurationApp"), exports);
|
|
23
|
+
__exportStar(require("./configurationPlugin"), exports);
|
|
22
24
|
__exportStar(require("./errors"), exports);
|
|
23
25
|
__exportStar(require("./expressServer"), exports);
|
|
24
26
|
__exportStar(require("./githubAuth"), exports);
|
|
@@ -26,11 +28,14 @@ __exportStar(require("./logger"), exports);
|
|
|
26
28
|
__exportStar(require("./middleware"), exports);
|
|
27
29
|
__exportStar(require("./notifiers"), exports);
|
|
28
30
|
__exportStar(require("./openApiBuilder"), exports);
|
|
31
|
+
__exportStar(require("./openApiCompat"), exports);
|
|
29
32
|
__exportStar(require("./openApiEtag"), exports);
|
|
30
33
|
__exportStar(require("./openApiValidator"), exports);
|
|
31
34
|
__exportStar(require("./permissions"), exports);
|
|
32
35
|
__exportStar(require("./plugins"), exports);
|
|
33
36
|
__exportStar(require("./populate"), exports);
|
|
37
|
+
__exportStar(require("./scriptRunner"), exports);
|
|
38
|
+
__exportStar(require("./secretProviders"), exports);
|
|
34
39
|
__exportStar(require("./terrenoApp"), exports);
|
|
35
40
|
__exportStar(require("./terrenoPlugin"), exports);
|
|
36
41
|
__exportStar(require("./transformers"), exports);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patches the Express router stack to add `.regexp` on layers for
|
|
3
|
+
* compatibility with @wesleytodd/openapi, which expects Express 4-style
|
|
4
|
+
* layers with `.regexp.fast_slash`.
|
|
5
|
+
*
|
|
6
|
+
* In Express 5 (router@2.x), layers use `.slash` (boolean) and `.matchers`
|
|
7
|
+
* (array of functions) instead of `.regexp`.
|
|
8
|
+
*
|
|
9
|
+
* @see https://github.com/wesleytodd/express-openapi/issues/70
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Wraps an Express app's `use` method to record the mount path on each
|
|
13
|
+
* layer added to the router stack. This runs at setup time so that
|
|
14
|
+
* `patchRouterStack` can read the original path later.
|
|
15
|
+
*
|
|
16
|
+
* Must be called before any routes are registered.
|
|
17
|
+
*/
|
|
18
|
+
export declare const patchAppUse: (app: any) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Express middleware that patches the router stack before OpenAPI doc
|
|
21
|
+
* generation. Must be mounted before the openapi middleware.
|
|
22
|
+
*/
|
|
23
|
+
export declare const openApiCompatMiddleware: (req: any, _res: any, next: () => void) => void;
|