@terreno/api 0.18.0 → 0.20.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/CHANGELOG.md +25 -0
- package/dist/api.test.js +18 -8
- package/dist/auth.d.ts +5 -5
- package/dist/auth.js +123 -131
- package/dist/configuration.test.js +289 -10
- package/dist/configurationApp.d.ts +72 -5
- package/dist/configurationApp.js +168 -48
- package/dist/configurationPlugin.d.ts +64 -7
- package/dist/configurationPlugin.js +161 -39
- package/dist/configurationPlugin.test.js +238 -1
- package/dist/expressServer.test.js +0 -1
- package/dist/openApi.d.ts +6 -6
- package/dist/openApi.js +21 -21
- package/dist/populate.test.js +23 -0
- package/dist/realtime/queryMatcher.js +0 -6
- package/dist/realtime/queryStore.js +3 -11
- package/dist/realtime/realtime.test.js +41 -34
- package/dist/secretProviders.d.ts +79 -2
- package/dist/secretProviders.js +177 -9
- package/dist/secretProviders.test.d.ts +1 -0
- package/dist/secretProviders.test.js +391 -0
- package/package.json +1 -1
- package/src/actions.openApi.test.ts +1 -1
- package/src/actions.ts +0 -1
- package/src/api.test.ts +10 -2
- package/src/auth.ts +19 -19
- package/src/configuration.test.ts +171 -7
- package/src/configurationApp.ts +213 -30
- package/src/configurationPlugin.test.ts +174 -2
- package/src/configurationPlugin.ts +157 -28
- package/src/expressServer.test.ts +0 -1
- package/src/openApi.ts +21 -21
- package/src/populate.test.ts +25 -0
- package/src/realtime/queryMatcher.ts +0 -6
- package/src/realtime/queryStore.ts +1 -10
- package/src/realtime/realtime.test.ts +24 -24
- package/src/realtime/realtimeApp.ts +0 -1
- package/src/realtime/registry.ts +0 -1
- package/src/realtime/types.ts +0 -4
- package/src/secretProviders.test.ts +186 -0
- package/src/secretProviders.ts +145 -5
package/dist/openApi.js
CHANGED
|
@@ -39,13 +39,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
39
39
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
40
|
};
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.defaultOpenApiErrorResponses = exports.apiErrorContent = void 0;
|
|
43
|
-
exports.getOpenApiMiddleware = getOpenApiMiddleware;
|
|
44
|
-
exports.listOpenApiMiddleware = listOpenApiMiddleware;
|
|
45
|
-
exports.createOpenApiMiddleware = createOpenApiMiddleware;
|
|
46
|
-
exports.patchOpenApiMiddleware = patchOpenApiMiddleware;
|
|
47
|
-
exports.deleteOpenApiMiddleware = deleteOpenApiMiddleware;
|
|
48
|
-
exports.readOpenApiMiddleware = readOpenApiMiddleware;
|
|
42
|
+
exports.readOpenApiMiddleware = exports.deleteOpenApiMiddleware = exports.patchOpenApiMiddleware = exports.createOpenApiMiddleware = exports.listOpenApiMiddleware = exports.getOpenApiMiddleware = exports.defaultOpenApiErrorResponses = exports.apiErrorContent = void 0;
|
|
49
43
|
var flatten_1 = __importDefault(require("lodash/flatten"));
|
|
50
44
|
var merge_1 = __importDefault(require("lodash/merge"));
|
|
51
45
|
var mongoose_to_swagger_1 = __importDefault(require("mongoose-to-swagger"));
|
|
@@ -83,7 +77,7 @@ exports.defaultOpenApiErrorResponses = {
|
|
|
83
77
|
},
|
|
84
78
|
};
|
|
85
79
|
// We repeat this constantly, so we make it a component so we only have to define it once.
|
|
86
|
-
function
|
|
80
|
+
var createAPIErrorComponent = function (openApi) {
|
|
87
81
|
// Create a schema component called APIError
|
|
88
82
|
openApi === null || openApi === void 0 ? void 0 : openApi.component("schemas", "APIError", {
|
|
89
83
|
properties: {
|
|
@@ -144,8 +138,8 @@ function createAPIErrorComponent(openApi) {
|
|
|
144
138
|
},
|
|
145
139
|
type: "object",
|
|
146
140
|
});
|
|
147
|
-
}
|
|
148
|
-
function
|
|
141
|
+
};
|
|
142
|
+
var getOpenApiMiddleware = function (model, options) {
|
|
149
143
|
var _c, _d, _e, _f, _g;
|
|
150
144
|
createAPIErrorComponent(options.openApi);
|
|
151
145
|
if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
|
|
@@ -175,8 +169,9 @@ function getOpenApiMiddleware(model, options) {
|
|
|
175
169
|
} }, exports.defaultOpenApiErrorResponses),
|
|
176
170
|
tags: [model.collection.collectionName],
|
|
177
171
|
}, (_g = (_f = options.openApiOverwrite) === null || _f === void 0 ? void 0 : _f.get) !== null && _g !== void 0 ? _g : {}));
|
|
178
|
-
}
|
|
179
|
-
|
|
172
|
+
};
|
|
173
|
+
exports.getOpenApiMiddleware = getOpenApiMiddleware;
|
|
174
|
+
var listOpenApiMiddleware = function (model, options) {
|
|
180
175
|
var _c, _d, _e, _f, _g, _h;
|
|
181
176
|
if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
|
|
182
177
|
return noop;
|
|
@@ -316,8 +311,9 @@ function listOpenApiMiddleware(model, options) {
|
|
|
316
311
|
} }, exports.defaultOpenApiErrorResponses),
|
|
317
312
|
tags: [model.collection.collectionName],
|
|
318
313
|
}, (_h = (_g = options.openApiOverwrite) === null || _g === void 0 ? void 0 : _g.list) !== null && _h !== void 0 ? _h : {}));
|
|
319
|
-
}
|
|
320
|
-
|
|
314
|
+
};
|
|
315
|
+
exports.listOpenApiMiddleware = listOpenApiMiddleware;
|
|
316
|
+
var createOpenApiMiddleware = function (model, options) {
|
|
321
317
|
var _c, _d, _e, _f, _g;
|
|
322
318
|
if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
|
|
323
319
|
return noop;
|
|
@@ -355,8 +351,9 @@ function createOpenApiMiddleware(model, options) {
|
|
|
355
351
|
} }, exports.defaultOpenApiErrorResponses),
|
|
356
352
|
tags: [model.collection.collectionName],
|
|
357
353
|
}, (_g = (_f = options.openApiOverwrite) === null || _f === void 0 ? void 0 : _f.create) !== null && _g !== void 0 ? _g : {}));
|
|
358
|
-
}
|
|
359
|
-
|
|
354
|
+
};
|
|
355
|
+
exports.createOpenApiMiddleware = createOpenApiMiddleware;
|
|
356
|
+
var patchOpenApiMiddleware = function (model, options) {
|
|
360
357
|
var _c, _d, _e, _f, _g;
|
|
361
358
|
if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
|
|
362
359
|
return noop;
|
|
@@ -394,8 +391,9 @@ function patchOpenApiMiddleware(model, options) {
|
|
|
394
391
|
} }, exports.defaultOpenApiErrorResponses),
|
|
395
392
|
tags: [model.collection.collectionName],
|
|
396
393
|
}, (_g = (_f = options.openApiOverwrite) === null || _f === void 0 ? void 0 : _f.update) !== null && _g !== void 0 ? _g : {}));
|
|
397
|
-
}
|
|
398
|
-
|
|
394
|
+
};
|
|
395
|
+
exports.patchOpenApiMiddleware = patchOpenApiMiddleware;
|
|
396
|
+
var deleteOpenApiMiddleware = function (model, options) {
|
|
399
397
|
var _c, _d, _e, _f, _g;
|
|
400
398
|
if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
|
|
401
399
|
return noop;
|
|
@@ -409,10 +407,11 @@ function deleteOpenApiMiddleware(model, options) {
|
|
|
409
407
|
} }, exports.defaultOpenApiErrorResponses),
|
|
410
408
|
tags: [model.collection.collectionName],
|
|
411
409
|
}, (_g = (_f = options.openApiOverwrite) === null || _f === void 0 ? void 0 : _f.delete) !== null && _g !== void 0 ? _g : {}));
|
|
412
|
-
}
|
|
410
|
+
};
|
|
411
|
+
exports.deleteOpenApiMiddleware = deleteOpenApiMiddleware;
|
|
413
412
|
// This is a generic OpenAPI wrapper for a read that returns any object described by `properties`.
|
|
414
413
|
// Useful for endpoints that don't directly map to a model.
|
|
415
|
-
function
|
|
414
|
+
var readOpenApiMiddleware = function (options, properties, required, queryParameters) {
|
|
416
415
|
var _c, _d, _e, _f, _g;
|
|
417
416
|
if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
|
|
418
417
|
// Just log this once rather than for each middleware.
|
|
@@ -438,4 +437,5 @@ function readOpenApiMiddleware(options, properties, required, queryParameters) {
|
|
|
438
437
|
} }, exports.defaultOpenApiErrorResponses),
|
|
439
438
|
tags: [],
|
|
440
439
|
}, (_g = (_f = options.openApiOverwrite) === null || _f === void 0 ? void 0 : _f.get) !== null && _g !== void 0 ? _g : {}));
|
|
441
|
-
}
|
|
440
|
+
};
|
|
441
|
+
exports.readOpenApiMiddleware = readOpenApiMiddleware;
|
package/dist/populate.test.js
CHANGED
|
@@ -328,6 +328,29 @@ var tests_1 = require("./tests");
|
|
|
328
328
|
(0, bun_test_1.expect)(detail.properties.displayAmount.type).toBe("any");
|
|
329
329
|
});
|
|
330
330
|
});
|
|
331
|
+
(0, bun_test_1.describe)("getOpenApiSpecForModel populate with existing properties", function () {
|
|
332
|
+
(0, bun_test_1.it)("merges populated properties into a path that already has properties", function () {
|
|
333
|
+
var result = (0, populate_1.getOpenApiSpecForModel)(tests_1.FoodModel, {
|
|
334
|
+
populatePaths: [{ path: "likesIds.userId" }],
|
|
335
|
+
});
|
|
336
|
+
// likesIds is an array subschema with its own properties already;
|
|
337
|
+
// populating userId should merge the user properties into the existing structure.
|
|
338
|
+
(0, bun_test_1.expect)(result.properties.likesIds).toBeDefined();
|
|
339
|
+
var likesIds = result.properties.likesIds;
|
|
340
|
+
var items = likesIds.items;
|
|
341
|
+
(0, bun_test_1.expect)(items.properties.userId).toBeDefined();
|
|
342
|
+
});
|
|
343
|
+
(0, bun_test_1.it)("creates intermediate path structure when navigating to nested populate", function () {
|
|
344
|
+
// eatenBy is defined as [{ ref: "User", type: ObjectId }] - an array of refs.
|
|
345
|
+
// When we populate eatenBy, the openApiPath resolves through items.
|
|
346
|
+
var result = (0, populate_1.getOpenApiSpecForModel)(tests_1.FoodModel, {
|
|
347
|
+
populatePaths: [{ path: "eatenBy" }],
|
|
348
|
+
});
|
|
349
|
+
(0, bun_test_1.expect)(result.properties.eatenBy).toBeDefined();
|
|
350
|
+
var eatenBy = result.properties.eatenBy;
|
|
351
|
+
(0, bun_test_1.expect)(eatenBy.items).toBeDefined();
|
|
352
|
+
});
|
|
353
|
+
});
|
|
331
354
|
(0, bun_test_1.describe)("filterKeys (via getOpenApiSpecForModel populatePaths)", function () {
|
|
332
355
|
(0, bun_test_1.it)("filters populated fields using dot-notation keys", function () {
|
|
333
356
|
var result = (0, populate_1.getOpenApiSpecForModel)(tests_1.FoodModel, {
|
|
@@ -35,7 +35,6 @@ var __read = (this && this.__read) || function (o, n) {
|
|
|
35
35
|
};
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
37
|
exports.matchesQuery = void 0;
|
|
38
|
-
// biome-ignore lint/suspicious/noExplicitAny: traversing arbitrary nested document fields by user-supplied dotted path
|
|
39
38
|
var getNestedValue = function (doc, path) {
|
|
40
39
|
var e_1, _a;
|
|
41
40
|
var parts = path.split(".");
|
|
@@ -58,7 +57,6 @@ var getNestedValue = function (doc, path) {
|
|
|
58
57
|
}
|
|
59
58
|
return current;
|
|
60
59
|
};
|
|
61
|
-
// biome-ignore lint/suspicious/noExplicitAny: value may be any document field type (string, number, ObjectId, etc.)
|
|
62
60
|
var normalize = function (value) {
|
|
63
61
|
var _a;
|
|
64
62
|
if (value === null || value === undefined) {
|
|
@@ -73,7 +71,6 @@ var normalize = function (value) {
|
|
|
73
71
|
}
|
|
74
72
|
return value;
|
|
75
73
|
};
|
|
76
|
-
// biome-ignore lint/suspicious/noExplicitAny: rawValue is an arbitrary document field, condition is an arbitrary user query operand
|
|
77
74
|
var matchesCondition = function (rawValue, condition) {
|
|
78
75
|
var e_2, _a;
|
|
79
76
|
var value = normalize(rawValue);
|
|
@@ -127,7 +124,6 @@ var matchesCondition = function (rawValue, condition) {
|
|
|
127
124
|
return false;
|
|
128
125
|
}
|
|
129
126
|
var inValues = operand.map(normalize);
|
|
130
|
-
// biome-ignore lint/suspicious/noExplicitAny: normalized value of arbitrary document field
|
|
131
127
|
if (!inValues.some(function (v) { return v === value || String(v) === String(value); })) {
|
|
132
128
|
return false;
|
|
133
129
|
}
|
|
@@ -138,7 +134,6 @@ var matchesCondition = function (rawValue, condition) {
|
|
|
138
134
|
return false;
|
|
139
135
|
}
|
|
140
136
|
var ninValues = operand.map(normalize);
|
|
141
|
-
// biome-ignore lint/suspicious/noExplicitAny: normalized value of arbitrary document field
|
|
142
137
|
if (ninValues.some(function (v) { return v === value || String(v) === String(value); })) {
|
|
143
138
|
return false;
|
|
144
139
|
}
|
|
@@ -179,7 +174,6 @@ var matchesCondition = function (rawValue, condition) {
|
|
|
179
174
|
* @param query - MongoDB-style query object
|
|
180
175
|
* @returns true if the document matches all query conditions
|
|
181
176
|
*/
|
|
182
|
-
// biome-ignore lint/suspicious/noExplicitAny: doc is arbitrary; query values are arbitrary user-supplied JSON
|
|
183
177
|
var matchesQuery = function (doc, query) {
|
|
184
178
|
var e_3, _a, e_4, _b, e_5, _c;
|
|
185
179
|
try {
|
|
@@ -40,12 +40,9 @@ exports.clearQueryStore = exports.getQuerySubscriptionsForCollection = exports.r
|
|
|
40
40
|
* Compute a deterministic queryId from collection and query on the server side.
|
|
41
41
|
* This prevents clients from hijacking other subscriptions by providing a colliding queryId.
|
|
42
42
|
*/
|
|
43
|
-
var computeQueryId = function (collection,
|
|
44
|
-
// biome-ignore lint/suspicious/noExplicitAny: MongoDB query filter values are arbitrary user-supplied JSON
|
|
45
|
-
query) {
|
|
43
|
+
var computeQueryId = function (collection, query) {
|
|
46
44
|
var e_1, _a;
|
|
47
45
|
var sortedKeys = Object.keys(query).sort();
|
|
48
|
-
// biome-ignore lint/suspicious/noExplicitAny: mirrors the input query value shape
|
|
49
46
|
var normalized = {};
|
|
50
47
|
try {
|
|
51
48
|
for (var sortedKeys_1 = __values(sortedKeys), sortedKeys_1_1 = sortedKeys_1.next(); !sortedKeys_1_1.done; sortedKeys_1_1 = sortedKeys_1.next()) {
|
|
@@ -71,9 +68,7 @@ var socketQueries = new Map();
|
|
|
71
68
|
* Register a query subscription for a socket.
|
|
72
69
|
* The socket joins the `query:{queryId}` room (handled by the caller).
|
|
73
70
|
*/
|
|
74
|
-
var addQuerySubscription = function (socketId, collection,
|
|
75
|
-
// biome-ignore lint/suspicious/noExplicitAny: MongoDB query filter values are arbitrary user-supplied JSON
|
|
76
|
-
query, queryId) {
|
|
71
|
+
var addQuerySubscription = function (socketId, collection, query, queryId) {
|
|
77
72
|
var _a;
|
|
78
73
|
querySubscriptions.set(queryId, { collection: collection, query: query, queryId: queryId });
|
|
79
74
|
if (!socketQueries.has(socketId)) {
|
|
@@ -161,11 +156,8 @@ exports.removeAllSocketQueries = removeAllSocketQueries;
|
|
|
161
156
|
* Get all unique query subscriptions for a given collection.
|
|
162
157
|
* Used by the change stream watcher to evaluate which query rooms to emit to.
|
|
163
158
|
*/
|
|
164
|
-
var getQuerySubscriptionsForCollection = function (collection
|
|
165
|
-
// biome-ignore lint/suspicious/noExplicitAny: MongoDB query filter values are arbitrary user-supplied JSON
|
|
166
|
-
) {
|
|
159
|
+
var getQuerySubscriptionsForCollection = function (collection) {
|
|
167
160
|
var e_5, _a;
|
|
168
|
-
// biome-ignore lint/suspicious/noExplicitAny: MongoDB query filter values are arbitrary user-supplied JSON
|
|
169
161
|
var result = [];
|
|
170
162
|
try {
|
|
171
163
|
for (var querySubscriptions_1 = __values(querySubscriptions), querySubscriptions_1_1 = querySubscriptions_1.next(); !querySubscriptions_1_1.done; querySubscriptions_1_1 = querySubscriptions_1.next()) {
|
|
@@ -2201,6 +2201,22 @@ var createMockSocket = function (decodedToken) {
|
|
|
2201
2201
|
},
|
|
2202
2202
|
};
|
|
2203
2203
|
};
|
|
2204
|
+
var invokeRegisteredChangeHandler = function (mockStream, event) { return __awaiter(void 0, void 0, void 0, function () {
|
|
2205
|
+
var changeHandler;
|
|
2206
|
+
return __generator(this, function (_a) {
|
|
2207
|
+
switch (_a.label) {
|
|
2208
|
+
case 0:
|
|
2209
|
+
changeHandler = mockStream.listeners.get("change");
|
|
2210
|
+
if (!changeHandler) {
|
|
2211
|
+
throw new Error("expected change handler");
|
|
2212
|
+
}
|
|
2213
|
+
return [4 /*yield*/, changeHandler(event)];
|
|
2214
|
+
case 1:
|
|
2215
|
+
_a.sent();
|
|
2216
|
+
return [2 /*return*/];
|
|
2217
|
+
}
|
|
2218
|
+
});
|
|
2219
|
+
}); };
|
|
2204
2220
|
var createMockIo = function () {
|
|
2205
2221
|
var rooms = new Map();
|
|
2206
2222
|
var sockets = new Map();
|
|
@@ -2272,7 +2288,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2272
2288
|
});
|
|
2273
2289
|
}); });
|
|
2274
2290
|
(0, bun_test_1.it)("handles change events for registered models", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2275
|
-
var mockStream, mockDb, startChangeStreamWatcher, io
|
|
2291
|
+
var mockStream, mockDb, startChangeStreamWatcher, io;
|
|
2276
2292
|
return __generator(this, function (_a) {
|
|
2277
2293
|
switch (_a.label) {
|
|
2278
2294
|
case 0:
|
|
@@ -2304,22 +2320,22 @@ var createMockSocket = function (decodedToken) {
|
|
|
2304
2320
|
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2305
2321
|
io = createMockIo();
|
|
2306
2322
|
startChangeStreamWatcher(io, {}, true);
|
|
2307
|
-
|
|
2308
|
-
(
|
|
2309
|
-
return [4 /*yield*/, changeHandler({
|
|
2323
|
+
// Trigger an insert change event
|
|
2324
|
+
return [4 /*yield*/, invokeRegisteredChangeHandler(mockStream, {
|
|
2310
2325
|
documentKey: { _id: "doc-1" },
|
|
2311
2326
|
fullDocument: { _id: "doc-1", name: "Test Todo" },
|
|
2312
2327
|
ns: { coll: "todos" },
|
|
2313
2328
|
operationType: "insert",
|
|
2314
2329
|
})];
|
|
2315
2330
|
case 2:
|
|
2331
|
+
// Trigger an insert change event
|
|
2316
2332
|
_a.sent();
|
|
2317
2333
|
return [2 /*return*/];
|
|
2318
2334
|
}
|
|
2319
2335
|
});
|
|
2320
2336
|
}); });
|
|
2321
2337
|
(0, bun_test_1.it)("skips events for unregistered collections", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2322
|
-
var mockStream, mockDb, startChangeStreamWatcher, io
|
|
2338
|
+
var mockStream, mockDb, startChangeStreamWatcher, io;
|
|
2323
2339
|
return __generator(this, function (_a) {
|
|
2324
2340
|
switch (_a.label) {
|
|
2325
2341
|
case 0:
|
|
@@ -2333,9 +2349,8 @@ var createMockSocket = function (decodedToken) {
|
|
|
2333
2349
|
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2334
2350
|
io = createMockIo();
|
|
2335
2351
|
startChangeStreamWatcher(io, {}, true);
|
|
2336
|
-
changeHandler = mockStream.listeners.get("change");
|
|
2337
2352
|
// Trigger for an unregistered collection — should not throw
|
|
2338
|
-
return [4 /*yield*/,
|
|
2353
|
+
return [4 /*yield*/, invokeRegisteredChangeHandler(mockStream, {
|
|
2339
2354
|
documentKey: { _id: "doc-1" },
|
|
2340
2355
|
fullDocument: { _id: "doc-1" },
|
|
2341
2356
|
ns: { coll: "unknown_collection" },
|
|
@@ -2349,7 +2364,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2349
2364
|
});
|
|
2350
2365
|
}); });
|
|
2351
2366
|
(0, bun_test_1.it)("skips events when method is not enabled for the model", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2352
|
-
var mockStream, mockDb, startChangeStreamWatcher, io
|
|
2367
|
+
var mockStream, mockDb, startChangeStreamWatcher, io;
|
|
2353
2368
|
return __generator(this, function (_a) {
|
|
2354
2369
|
switch (_a.label) {
|
|
2355
2370
|
case 0:
|
|
@@ -2381,9 +2396,8 @@ var createMockSocket = function (decodedToken) {
|
|
|
2381
2396
|
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2382
2397
|
io = createMockIo();
|
|
2383
2398
|
startChangeStreamWatcher(io, {}, true);
|
|
2384
|
-
changeHandler = mockStream.listeners.get("change");
|
|
2385
2399
|
// Update event should be skipped because "update" not in methods
|
|
2386
|
-
return [4 /*yield*/,
|
|
2400
|
+
return [4 /*yield*/, invokeRegisteredChangeHandler(mockStream, {
|
|
2387
2401
|
documentKey: { _id: "doc-1" },
|
|
2388
2402
|
fullDocument: { _id: "doc-1", name: "Updated" },
|
|
2389
2403
|
ns: { coll: "todos" },
|
|
@@ -2398,7 +2412,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2398
2412
|
});
|
|
2399
2413
|
}); });
|
|
2400
2414
|
(0, bun_test_1.it)("handles delete events for owner-strategy models", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2401
|
-
var mockStream, mockDb, startChangeStreamWatcher, io
|
|
2415
|
+
var mockStream, mockDb, startChangeStreamWatcher, io;
|
|
2402
2416
|
return __generator(this, function (_a) {
|
|
2403
2417
|
switch (_a.label) {
|
|
2404
2418
|
case 0:
|
|
@@ -2430,9 +2444,8 @@ var createMockSocket = function (decodedToken) {
|
|
|
2430
2444
|
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2431
2445
|
io = createMockIo();
|
|
2432
2446
|
startChangeStreamWatcher(io, {}, true);
|
|
2433
|
-
changeHandler = mockStream.listeners.get("change");
|
|
2434
2447
|
// Hard delete (no fullDocument)
|
|
2435
|
-
return [4 /*yield*/,
|
|
2448
|
+
return [4 /*yield*/, invokeRegisteredChangeHandler(mockStream, {
|
|
2436
2449
|
documentKey: { _id: "doc-1" },
|
|
2437
2450
|
ns: { coll: "todos" },
|
|
2438
2451
|
operationType: "delete",
|
|
@@ -2445,7 +2458,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2445
2458
|
});
|
|
2446
2459
|
}); });
|
|
2447
2460
|
(0, bun_test_1.it)("handles delete events for broadcast-strategy models", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2448
|
-
var mockStream, mockDb, startChangeStreamWatcher, io
|
|
2461
|
+
var mockStream, mockDb, startChangeStreamWatcher, io;
|
|
2449
2462
|
return __generator(this, function (_a) {
|
|
2450
2463
|
switch (_a.label) {
|
|
2451
2464
|
case 0:
|
|
@@ -2477,9 +2490,8 @@ var createMockSocket = function (decodedToken) {
|
|
|
2477
2490
|
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2478
2491
|
io = createMockIo();
|
|
2479
2492
|
startChangeStreamWatcher(io, {}, true);
|
|
2480
|
-
changeHandler = mockStream.listeners.get("change");
|
|
2481
2493
|
// Hard delete for broadcast strategy
|
|
2482
|
-
return [4 /*yield*/,
|
|
2494
|
+
return [4 /*yield*/, invokeRegisteredChangeHandler(mockStream, {
|
|
2483
2495
|
documentKey: { _id: "doc-1" },
|
|
2484
2496
|
ns: { coll: "broadcasts" },
|
|
2485
2497
|
operationType: "delete",
|
|
@@ -2492,7 +2504,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2492
2504
|
});
|
|
2493
2505
|
}); });
|
|
2494
2506
|
(0, bun_test_1.it)("includes updatedFields in event for update operations", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2495
|
-
var mockStream, mockDb, startChangeStreamWatcher, io
|
|
2507
|
+
var mockStream, mockDb, startChangeStreamWatcher, io;
|
|
2496
2508
|
return __generator(this, function (_a) {
|
|
2497
2509
|
switch (_a.label) {
|
|
2498
2510
|
case 0:
|
|
@@ -2524,8 +2536,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2524
2536
|
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2525
2537
|
io = createMockIo();
|
|
2526
2538
|
startChangeStreamWatcher(io, {}, true);
|
|
2527
|
-
|
|
2528
|
-
return [4 /*yield*/, changeHandler({
|
|
2539
|
+
return [4 /*yield*/, invokeRegisteredChangeHandler(mockStream, {
|
|
2529
2540
|
documentKey: { _id: "doc-1" },
|
|
2530
2541
|
fullDocument: { _id: "doc-1", name: "Updated", status: "done" },
|
|
2531
2542
|
ns: { coll: "todos" },
|
|
@@ -2563,7 +2574,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2563
2574
|
});
|
|
2564
2575
|
}); });
|
|
2565
2576
|
(0, bun_test_1.it)("respects ignoredOperations config", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2566
|
-
var mockStream, mockDb, startChangeStreamWatcher, io
|
|
2577
|
+
var mockStream, mockDb, startChangeStreamWatcher, io;
|
|
2567
2578
|
return __generator(this, function (_a) {
|
|
2568
2579
|
switch (_a.label) {
|
|
2569
2580
|
case 0:
|
|
@@ -2595,9 +2606,8 @@ var createMockSocket = function (decodedToken) {
|
|
|
2595
2606
|
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2596
2607
|
io = createMockIo();
|
|
2597
2608
|
startChangeStreamWatcher(io, { ignoredOperations: ["insert"] }, true);
|
|
2598
|
-
changeHandler = mockStream.listeners.get("change");
|
|
2599
2609
|
// This insert should be skipped because "insert" is ignored
|
|
2600
|
-
return [4 /*yield*/,
|
|
2610
|
+
return [4 /*yield*/, invokeRegisteredChangeHandler(mockStream, {
|
|
2601
2611
|
documentKey: { _id: "doc-1" },
|
|
2602
2612
|
fullDocument: { _id: "doc-1" },
|
|
2603
2613
|
ns: { coll: "todos" },
|
|
@@ -2611,7 +2621,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2611
2621
|
});
|
|
2612
2622
|
}); });
|
|
2613
2623
|
(0, bun_test_1.it)("skips events with no collectionName or docId", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2614
|
-
var mockStream, mockDb, startChangeStreamWatcher, io
|
|
2624
|
+
var mockStream, mockDb, startChangeStreamWatcher, io;
|
|
2615
2625
|
return __generator(this, function (_a) {
|
|
2616
2626
|
switch (_a.label) {
|
|
2617
2627
|
case 0:
|
|
@@ -2625,9 +2635,8 @@ var createMockSocket = function (decodedToken) {
|
|
|
2625
2635
|
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2626
2636
|
io = createMockIo();
|
|
2627
2637
|
startChangeStreamWatcher(io, {}, true);
|
|
2628
|
-
changeHandler = mockStream.listeners.get("change");
|
|
2629
2638
|
// Missing ns.coll
|
|
2630
|
-
return [4 /*yield*/,
|
|
2639
|
+
return [4 /*yield*/, invokeRegisteredChangeHandler(mockStream, {
|
|
2631
2640
|
documentKey: { _id: "doc-1" },
|
|
2632
2641
|
ns: {},
|
|
2633
2642
|
operationType: "insert",
|
|
@@ -2636,7 +2645,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2636
2645
|
// Missing ns.coll
|
|
2637
2646
|
_a.sent();
|
|
2638
2647
|
// Missing documentKey
|
|
2639
|
-
return [4 /*yield*/,
|
|
2648
|
+
return [4 /*yield*/, invokeRegisteredChangeHandler(mockStream, {
|
|
2640
2649
|
documentKey: {},
|
|
2641
2650
|
ns: { coll: "todos" },
|
|
2642
2651
|
operationType: "insert",
|
|
@@ -2649,7 +2658,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2649
2658
|
});
|
|
2650
2659
|
}); });
|
|
2651
2660
|
(0, bun_test_1.it)("skips non-CRUD operation types", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2652
|
-
var mockStream, mockDb, startChangeStreamWatcher, io
|
|
2661
|
+
var mockStream, mockDb, startChangeStreamWatcher, io;
|
|
2653
2662
|
return __generator(this, function (_a) {
|
|
2654
2663
|
switch (_a.label) {
|
|
2655
2664
|
case 0:
|
|
@@ -2663,9 +2672,8 @@ var createMockSocket = function (decodedToken) {
|
|
|
2663
2672
|
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2664
2673
|
io = createMockIo();
|
|
2665
2674
|
startChangeStreamWatcher(io, {}, true);
|
|
2666
|
-
changeHandler = mockStream.listeners.get("change");
|
|
2667
2675
|
// "drop" is not in our pipeline filter, should be skipped
|
|
2668
|
-
return [4 /*yield*/,
|
|
2676
|
+
return [4 /*yield*/, invokeRegisteredChangeHandler(mockStream, {
|
|
2669
2677
|
operationType: "drop",
|
|
2670
2678
|
})];
|
|
2671
2679
|
case 2:
|
|
@@ -2721,7 +2729,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2721
2729
|
});
|
|
2722
2730
|
}); });
|
|
2723
2731
|
(0, bun_test_1.it)("catches errors thrown in the change handler", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2724
|
-
var mockStream, mockDb, startChangeStreamWatcher, emissions, mockSocket, rooms, sockets, io
|
|
2732
|
+
var mockStream, mockDb, startChangeStreamWatcher, emissions, mockSocket, rooms, sockets, io;
|
|
2725
2733
|
return __generator(this, function (_a) {
|
|
2726
2734
|
switch (_a.label) {
|
|
2727
2735
|
case 0:
|
|
@@ -2776,9 +2784,8 @@ var createMockSocket = function (decodedToken) {
|
|
|
2776
2784
|
to: function () { return ({ emit: function () { } }); },
|
|
2777
2785
|
};
|
|
2778
2786
|
startChangeStreamWatcher(io, {}, true);
|
|
2779
|
-
changeHandler = mockStream.listeners.get("change");
|
|
2780
2787
|
// Should not throw even though permission check throws
|
|
2781
|
-
return [4 /*yield*/,
|
|
2788
|
+
return [4 /*yield*/, invokeRegisteredChangeHandler(mockStream, {
|
|
2782
2789
|
documentKey: { _id: "doc-1" },
|
|
2783
2790
|
fullDocument: { _id: "doc-1", name: "Test" },
|
|
2784
2791
|
ns: { coll: "todos" },
|
|
@@ -2862,7 +2869,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2862
2869
|
});
|
|
2863
2870
|
}); });
|
|
2864
2871
|
var makeServer = function () {
|
|
2865
|
-
var http = require("http");
|
|
2872
|
+
var http = require("node:http");
|
|
2866
2873
|
var server = http.createServer();
|
|
2867
2874
|
servers.push(server);
|
|
2868
2875
|
return server;
|
|
@@ -2925,7 +2932,7 @@ var createMockSocket = function (decodedToken) {
|
|
|
2925
2932
|
});
|
|
2926
2933
|
}); });
|
|
2927
2934
|
var makeServer = function () {
|
|
2928
|
-
var http = require("http");
|
|
2935
|
+
var http = require("node:http");
|
|
2929
2936
|
var server = http.createServer();
|
|
2930
2937
|
servers.push(server);
|
|
2931
2938
|
return server;
|
|
@@ -15,7 +15,11 @@ import type { SecretProvider } from "./configurationPlugin";
|
|
|
15
15
|
*/
|
|
16
16
|
export declare class EnvSecretProvider implements SecretProvider {
|
|
17
17
|
name: string;
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Resolve a secret from an environment variable. Environment variables have no
|
|
20
|
+
* versions, so the optional `version` parameter is ignored.
|
|
21
|
+
*/
|
|
22
|
+
getSecret(secretName: string, _version?: string): Promise<string | null>;
|
|
19
23
|
}
|
|
20
24
|
/**
|
|
21
25
|
* Options for GcpSecretProvider.
|
|
@@ -43,5 +47,78 @@ export declare class GcpSecretProvider implements SecretProvider {
|
|
|
43
47
|
private client;
|
|
44
48
|
constructor(options: GcpSecretProviderOptions);
|
|
45
49
|
private getClient;
|
|
46
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Resolve a secret from Google Cloud Secret Manager.
|
|
52
|
+
*
|
|
53
|
+
* @param secretName - A short secret id (e.g. "openai-api-key") or a full
|
|
54
|
+
* resource path (e.g. "projects/p/secrets/s" or
|
|
55
|
+
* "projects/p/secrets/s/versions/3").
|
|
56
|
+
* @param version - Optional version to resolve when `secretName` is a short id
|
|
57
|
+
* (e.g. "3"). Defaults to "latest". Ignored when `secretName` already
|
|
58
|
+
* contains an explicit `/versions/...` suffix.
|
|
59
|
+
*/
|
|
60
|
+
getSecret(secretName: string, version?: string): Promise<string | null>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Secret provider that delegates to an ordered list of providers, returning the
|
|
64
|
+
* first non-null result.
|
|
65
|
+
*
|
|
66
|
+
* A provider that throws is warn-logged (secret name only — never the value) and
|
|
67
|
+
* resolution falls through to the next provider. This makes it easy to compose a
|
|
68
|
+
* primary provider with a fallback, e.g. GCP with an environment-variable
|
|
69
|
+
* fallback:
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const provider = new CompositeSecretProvider([
|
|
74
|
+
* new GcpSecretProvider({projectId: "my-project"}),
|
|
75
|
+
* new EnvSecretProvider(),
|
|
76
|
+
* ]);
|
|
77
|
+
* const key = await provider.getSecret("openai-api-key");
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare class CompositeSecretProvider implements SecretProvider {
|
|
81
|
+
name: string;
|
|
82
|
+
private providers;
|
|
83
|
+
constructor(providers: SecretProvider[]);
|
|
84
|
+
getSecret(secretName: string, version?: string): Promise<string | null>;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Options for CachingSecretProvider.
|
|
88
|
+
*/
|
|
89
|
+
export interface CachingSecretProviderOptions {
|
|
90
|
+
/** Time-to-live for cached values, in milliseconds. Defaults to 60_000 (1 minute). */
|
|
91
|
+
ttlMs?: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Secret provider that wraps any provider with an in-memory TTL cache.
|
|
95
|
+
*
|
|
96
|
+
* Cache entries are keyed by `secretName@version` so that pinned versions are
|
|
97
|
+
* cached independently. `null` results (secret not found) are cached too, to
|
|
98
|
+
* avoid hammering the underlying provider for missing secrets. Secret values are
|
|
99
|
+
* never logged.
|
|
100
|
+
*
|
|
101
|
+
* Use `clear()` to drop the entire cache (e.g. on rotation) or `clearKey()` to
|
|
102
|
+
* invalidate a single secret.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* const provider = new CachingSecretProvider(
|
|
107
|
+
* new CompositeSecretProvider([gcp, env]),
|
|
108
|
+
* {ttlMs: 30_000}
|
|
109
|
+
* );
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export declare class CachingSecretProvider implements SecretProvider {
|
|
113
|
+
name: string;
|
|
114
|
+
private provider;
|
|
115
|
+
private ttlMs;
|
|
116
|
+
private cache;
|
|
117
|
+
constructor(provider: SecretProvider, options?: CachingSecretProviderOptions);
|
|
118
|
+
private cacheKey;
|
|
119
|
+
getSecret(secretName: string, version?: string): Promise<string | null>;
|
|
120
|
+
/** Clears the entire cache. Useful on secret rotation and in tests. */
|
|
121
|
+
clear(): void;
|
|
122
|
+
/** Invalidates a single cached secret by name (and optional version). */
|
|
123
|
+
clearKey(secretName: string, version?: string): void;
|
|
47
124
|
}
|