@terreno/api 0.14.1 → 0.15.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/__tests__/versionCheckPlugin.test.js +36 -0
- package/dist/errors.test.js +25 -0
- package/dist/expressServer.test.js +119 -0
- package/dist/realtime/realtime.test.js +880 -3
- package/package.json +1 -1
- package/src/__tests__/versionCheckPlugin.test.ts +24 -0
- package/src/errors.test.ts +32 -0
- package/src/expressServer.test.ts +79 -0
- package/src/realtime/realtime.test.ts +704 -0
|
@@ -125,12 +125,24 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
125
125
|
}
|
|
126
126
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
127
127
|
};
|
|
128
|
+
var __values = (this && this.__values) || function(o) {
|
|
129
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
130
|
+
if (m) return m.call(o);
|
|
131
|
+
if (o && typeof o.length === "number") return {
|
|
132
|
+
next: function () {
|
|
133
|
+
if (o && i >= o.length) o = void 0;
|
|
134
|
+
return { value: o && o[i++], done: !o };
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
138
|
+
};
|
|
128
139
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
129
140
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
130
141
|
};
|
|
131
142
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
132
143
|
var bun_test_1 = require("bun:test");
|
|
133
144
|
var express_1 = __importDefault(require("express"));
|
|
145
|
+
var mongoose_1 = __importDefault(require("mongoose"));
|
|
134
146
|
var changeStreamWatcher_1 = require("./changeStreamWatcher");
|
|
135
147
|
var queryMatcher_1 = require("./queryMatcher");
|
|
136
148
|
var queryStore_1 = require("./queryStore");
|
|
@@ -2141,6 +2153,868 @@ var createMockSocket = function (decodedToken) {
|
|
|
2141
2153
|
// redactCredentials — Redis URL logging
|
|
2142
2154
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
2143
2155
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
2156
|
+
// startChangeStreamWatcher / stopChangeStreamWatcher — MongoDB change stream
|
|
2157
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2158
|
+
(0, bun_test_1.describe)("startChangeStreamWatcher", function () {
|
|
2159
|
+
var originalDb;
|
|
2160
|
+
(0, bun_test_1.beforeEach)(function () {
|
|
2161
|
+
originalDb = mongoose_1.default.connection.db;
|
|
2162
|
+
(0, registry_1.clearRealtimeRegistry)();
|
|
2163
|
+
});
|
|
2164
|
+
(0, bun_test_1.afterEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2165
|
+
var stop;
|
|
2166
|
+
return __generator(this, function (_a) {
|
|
2167
|
+
switch (_a.label) {
|
|
2168
|
+
case 0:
|
|
2169
|
+
mongoose_1.default.connection.db = originalDb;
|
|
2170
|
+
(0, registry_1.clearRealtimeRegistry)();
|
|
2171
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2172
|
+
case 1:
|
|
2173
|
+
stop = (_a.sent()).stopChangeStreamWatcher;
|
|
2174
|
+
return [4 /*yield*/, stop()];
|
|
2175
|
+
case 2:
|
|
2176
|
+
_a.sent();
|
|
2177
|
+
return [2 /*return*/];
|
|
2178
|
+
}
|
|
2179
|
+
});
|
|
2180
|
+
}); });
|
|
2181
|
+
var createMockChangeStream = function () {
|
|
2182
|
+
var listeners = new Map();
|
|
2183
|
+
return {
|
|
2184
|
+
close: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
2185
|
+
return [2 /*return*/];
|
|
2186
|
+
}); }); }),
|
|
2187
|
+
listeners: listeners,
|
|
2188
|
+
on: function (event, handler) {
|
|
2189
|
+
listeners.set(event, handler);
|
|
2190
|
+
return this;
|
|
2191
|
+
},
|
|
2192
|
+
trigger: function (event) {
|
|
2193
|
+
var args = [];
|
|
2194
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
2195
|
+
args[_i - 1] = arguments[_i];
|
|
2196
|
+
}
|
|
2197
|
+
var handler = listeners.get(event);
|
|
2198
|
+
if (handler) {
|
|
2199
|
+
handler.apply(void 0, __spreadArray([], __read(args), false));
|
|
2200
|
+
}
|
|
2201
|
+
},
|
|
2202
|
+
};
|
|
2203
|
+
};
|
|
2204
|
+
var createMockIo = function () {
|
|
2205
|
+
var rooms = new Map();
|
|
2206
|
+
var sockets = new Map();
|
|
2207
|
+
return {
|
|
2208
|
+
sockets: {
|
|
2209
|
+
adapter: { rooms: rooms },
|
|
2210
|
+
sockets: sockets,
|
|
2211
|
+
},
|
|
2212
|
+
to: function (_room) { return ({
|
|
2213
|
+
emit: function (_event, _data) { },
|
|
2214
|
+
}); },
|
|
2215
|
+
};
|
|
2216
|
+
};
|
|
2217
|
+
(0, bun_test_1.it)("initializes and registers change/error/close/end listeners", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2218
|
+
var mockStream, mockDb, startChangeStreamWatcher, io;
|
|
2219
|
+
return __generator(this, function (_a) {
|
|
2220
|
+
switch (_a.label) {
|
|
2221
|
+
case 0:
|
|
2222
|
+
mockStream = createMockChangeStream();
|
|
2223
|
+
mockDb = {
|
|
2224
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2225
|
+
};
|
|
2226
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2227
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2228
|
+
case 1:
|
|
2229
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2230
|
+
io = createMockIo();
|
|
2231
|
+
startChangeStreamWatcher(io, {}, true);
|
|
2232
|
+
(0, bun_test_1.expect)(mockDb.watch).toHaveBeenCalled();
|
|
2233
|
+
(0, bun_test_1.expect)(mockStream.listeners.has("change")).toBe(true);
|
|
2234
|
+
(0, bun_test_1.expect)(mockStream.listeners.has("error")).toBe(true);
|
|
2235
|
+
(0, bun_test_1.expect)(mockStream.listeners.has("close")).toBe(true);
|
|
2236
|
+
(0, bun_test_1.expect)(mockStream.listeners.has("end")).toBe(true);
|
|
2237
|
+
return [2 /*return*/];
|
|
2238
|
+
}
|
|
2239
|
+
});
|
|
2240
|
+
}); });
|
|
2241
|
+
(0, bun_test_1.it)("throws when mongoose connection db is unavailable", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2242
|
+
var startChangeStreamWatcher, io;
|
|
2243
|
+
return __generator(this, function (_a) {
|
|
2244
|
+
switch (_a.label) {
|
|
2245
|
+
case 0:
|
|
2246
|
+
mongoose_1.default.connection.db = undefined;
|
|
2247
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2248
|
+
case 1:
|
|
2249
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2250
|
+
io = createMockIo();
|
|
2251
|
+
(0, bun_test_1.expect)(function () { return startChangeStreamWatcher(io); }).toThrow("MongoDB connection not available for change stream");
|
|
2252
|
+
return [2 /*return*/];
|
|
2253
|
+
}
|
|
2254
|
+
});
|
|
2255
|
+
}); });
|
|
2256
|
+
(0, bun_test_1.it)("throws when watch returns null", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2257
|
+
var mockDb, startChangeStreamWatcher, io;
|
|
2258
|
+
return __generator(this, function (_a) {
|
|
2259
|
+
switch (_a.label) {
|
|
2260
|
+
case 0:
|
|
2261
|
+
mockDb = {
|
|
2262
|
+
watch: (0, bun_test_1.mock)(function () { return null; }),
|
|
2263
|
+
};
|
|
2264
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2265
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2266
|
+
case 1:
|
|
2267
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2268
|
+
io = createMockIo();
|
|
2269
|
+
(0, bun_test_1.expect)(function () { return startChangeStreamWatcher(io); }).toThrow("Failed to create change stream watcher");
|
|
2270
|
+
return [2 /*return*/];
|
|
2271
|
+
}
|
|
2272
|
+
});
|
|
2273
|
+
}); });
|
|
2274
|
+
(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, changeHandler;
|
|
2276
|
+
return __generator(this, function (_a) {
|
|
2277
|
+
switch (_a.label) {
|
|
2278
|
+
case 0:
|
|
2279
|
+
mockStream = createMockChangeStream();
|
|
2280
|
+
mockDb = {
|
|
2281
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2282
|
+
};
|
|
2283
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2284
|
+
(0, registry_1.registerRealtime)({
|
|
2285
|
+
collectionName: "todos",
|
|
2286
|
+
config: {
|
|
2287
|
+
methods: ["create", "update", "delete"],
|
|
2288
|
+
roomStrategy: "model",
|
|
2289
|
+
},
|
|
2290
|
+
modelName: "Todo",
|
|
2291
|
+
options: {
|
|
2292
|
+
permissions: {
|
|
2293
|
+
create: [function () { return true; }],
|
|
2294
|
+
delete: [function () { return true; }],
|
|
2295
|
+
list: [function () { return true; }],
|
|
2296
|
+
read: [function () { return true; }],
|
|
2297
|
+
update: [function () { return true; }],
|
|
2298
|
+
},
|
|
2299
|
+
},
|
|
2300
|
+
routePath: "/todos",
|
|
2301
|
+
});
|
|
2302
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2303
|
+
case 1:
|
|
2304
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2305
|
+
io = createMockIo();
|
|
2306
|
+
startChangeStreamWatcher(io, {}, true);
|
|
2307
|
+
changeHandler = mockStream.listeners.get("change");
|
|
2308
|
+
(0, bun_test_1.expect)(changeHandler).toBeDefined();
|
|
2309
|
+
return [4 /*yield*/, changeHandler({
|
|
2310
|
+
documentKey: { _id: "doc-1" },
|
|
2311
|
+
fullDocument: { _id: "doc-1", name: "Test Todo" },
|
|
2312
|
+
ns: { coll: "todos" },
|
|
2313
|
+
operationType: "insert",
|
|
2314
|
+
})];
|
|
2315
|
+
case 2:
|
|
2316
|
+
_a.sent();
|
|
2317
|
+
return [2 /*return*/];
|
|
2318
|
+
}
|
|
2319
|
+
});
|
|
2320
|
+
}); });
|
|
2321
|
+
(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, changeHandler;
|
|
2323
|
+
return __generator(this, function (_a) {
|
|
2324
|
+
switch (_a.label) {
|
|
2325
|
+
case 0:
|
|
2326
|
+
mockStream = createMockChangeStream();
|
|
2327
|
+
mockDb = {
|
|
2328
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2329
|
+
};
|
|
2330
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2331
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2332
|
+
case 1:
|
|
2333
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2334
|
+
io = createMockIo();
|
|
2335
|
+
startChangeStreamWatcher(io, {}, true);
|
|
2336
|
+
changeHandler = mockStream.listeners.get("change");
|
|
2337
|
+
// Trigger for an unregistered collection — should not throw
|
|
2338
|
+
return [4 /*yield*/, changeHandler({
|
|
2339
|
+
documentKey: { _id: "doc-1" },
|
|
2340
|
+
fullDocument: { _id: "doc-1" },
|
|
2341
|
+
ns: { coll: "unknown_collection" },
|
|
2342
|
+
operationType: "insert",
|
|
2343
|
+
})];
|
|
2344
|
+
case 2:
|
|
2345
|
+
// Trigger for an unregistered collection — should not throw
|
|
2346
|
+
_a.sent();
|
|
2347
|
+
return [2 /*return*/];
|
|
2348
|
+
}
|
|
2349
|
+
});
|
|
2350
|
+
}); });
|
|
2351
|
+
(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, changeHandler;
|
|
2353
|
+
return __generator(this, function (_a) {
|
|
2354
|
+
switch (_a.label) {
|
|
2355
|
+
case 0:
|
|
2356
|
+
mockStream = createMockChangeStream();
|
|
2357
|
+
mockDb = {
|
|
2358
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2359
|
+
};
|
|
2360
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2361
|
+
(0, registry_1.registerRealtime)({
|
|
2362
|
+
collectionName: "todos",
|
|
2363
|
+
config: {
|
|
2364
|
+
methods: ["create"], // only create enabled
|
|
2365
|
+
roomStrategy: "model",
|
|
2366
|
+
},
|
|
2367
|
+
modelName: "Todo",
|
|
2368
|
+
options: {
|
|
2369
|
+
permissions: {
|
|
2370
|
+
create: [function () { return true; }],
|
|
2371
|
+
delete: [],
|
|
2372
|
+
list: [function () { return true; }],
|
|
2373
|
+
read: [function () { return true; }],
|
|
2374
|
+
update: [],
|
|
2375
|
+
},
|
|
2376
|
+
},
|
|
2377
|
+
routePath: "/todos",
|
|
2378
|
+
});
|
|
2379
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2380
|
+
case 1:
|
|
2381
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2382
|
+
io = createMockIo();
|
|
2383
|
+
startChangeStreamWatcher(io, {}, true);
|
|
2384
|
+
changeHandler = mockStream.listeners.get("change");
|
|
2385
|
+
// Update event should be skipped because "update" not in methods
|
|
2386
|
+
return [4 /*yield*/, changeHandler({
|
|
2387
|
+
documentKey: { _id: "doc-1" },
|
|
2388
|
+
fullDocument: { _id: "doc-1", name: "Updated" },
|
|
2389
|
+
ns: { coll: "todos" },
|
|
2390
|
+
operationType: "update",
|
|
2391
|
+
updateDescription: { updatedFields: { name: "Updated" } },
|
|
2392
|
+
})];
|
|
2393
|
+
case 2:
|
|
2394
|
+
// Update event should be skipped because "update" not in methods
|
|
2395
|
+
_a.sent();
|
|
2396
|
+
return [2 /*return*/];
|
|
2397
|
+
}
|
|
2398
|
+
});
|
|
2399
|
+
}); });
|
|
2400
|
+
(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, changeHandler;
|
|
2402
|
+
return __generator(this, function (_a) {
|
|
2403
|
+
switch (_a.label) {
|
|
2404
|
+
case 0:
|
|
2405
|
+
mockStream = createMockChangeStream();
|
|
2406
|
+
mockDb = {
|
|
2407
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2408
|
+
};
|
|
2409
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2410
|
+
(0, registry_1.registerRealtime)({
|
|
2411
|
+
collectionName: "todos",
|
|
2412
|
+
config: {
|
|
2413
|
+
methods: ["create", "update", "delete"],
|
|
2414
|
+
roomStrategy: "owner",
|
|
2415
|
+
},
|
|
2416
|
+
modelName: "Todo",
|
|
2417
|
+
options: {
|
|
2418
|
+
permissions: {
|
|
2419
|
+
create: [function () { return true; }],
|
|
2420
|
+
delete: [function () { return true; }],
|
|
2421
|
+
list: [function () { return true; }],
|
|
2422
|
+
read: [function () { return true; }],
|
|
2423
|
+
update: [function () { return true; }],
|
|
2424
|
+
},
|
|
2425
|
+
},
|
|
2426
|
+
routePath: "/todos",
|
|
2427
|
+
});
|
|
2428
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2429
|
+
case 1:
|
|
2430
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2431
|
+
io = createMockIo();
|
|
2432
|
+
startChangeStreamWatcher(io, {}, true);
|
|
2433
|
+
changeHandler = mockStream.listeners.get("change");
|
|
2434
|
+
// Hard delete (no fullDocument)
|
|
2435
|
+
return [4 /*yield*/, changeHandler({
|
|
2436
|
+
documentKey: { _id: "doc-1" },
|
|
2437
|
+
ns: { coll: "todos" },
|
|
2438
|
+
operationType: "delete",
|
|
2439
|
+
})];
|
|
2440
|
+
case 2:
|
|
2441
|
+
// Hard delete (no fullDocument)
|
|
2442
|
+
_a.sent();
|
|
2443
|
+
return [2 /*return*/];
|
|
2444
|
+
}
|
|
2445
|
+
});
|
|
2446
|
+
}); });
|
|
2447
|
+
(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, changeHandler;
|
|
2449
|
+
return __generator(this, function (_a) {
|
|
2450
|
+
switch (_a.label) {
|
|
2451
|
+
case 0:
|
|
2452
|
+
mockStream = createMockChangeStream();
|
|
2453
|
+
mockDb = {
|
|
2454
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2455
|
+
};
|
|
2456
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2457
|
+
(0, registry_1.registerRealtime)({
|
|
2458
|
+
collectionName: "broadcasts",
|
|
2459
|
+
config: {
|
|
2460
|
+
methods: ["create", "update", "delete"],
|
|
2461
|
+
roomStrategy: "broadcast",
|
|
2462
|
+
},
|
|
2463
|
+
modelName: "Broadcast",
|
|
2464
|
+
options: {
|
|
2465
|
+
permissions: {
|
|
2466
|
+
create: [function () { return true; }],
|
|
2467
|
+
delete: [function () { return true; }],
|
|
2468
|
+
list: [function () { return true; }],
|
|
2469
|
+
read: [function () { return true; }],
|
|
2470
|
+
update: [function () { return true; }],
|
|
2471
|
+
},
|
|
2472
|
+
},
|
|
2473
|
+
routePath: "/broadcasts",
|
|
2474
|
+
});
|
|
2475
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2476
|
+
case 1:
|
|
2477
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2478
|
+
io = createMockIo();
|
|
2479
|
+
startChangeStreamWatcher(io, {}, true);
|
|
2480
|
+
changeHandler = mockStream.listeners.get("change");
|
|
2481
|
+
// Hard delete for broadcast strategy
|
|
2482
|
+
return [4 /*yield*/, changeHandler({
|
|
2483
|
+
documentKey: { _id: "doc-1" },
|
|
2484
|
+
ns: { coll: "broadcasts" },
|
|
2485
|
+
operationType: "delete",
|
|
2486
|
+
})];
|
|
2487
|
+
case 2:
|
|
2488
|
+
// Hard delete for broadcast strategy
|
|
2489
|
+
_a.sent();
|
|
2490
|
+
return [2 /*return*/];
|
|
2491
|
+
}
|
|
2492
|
+
});
|
|
2493
|
+
}); });
|
|
2494
|
+
(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, changeHandler;
|
|
2496
|
+
return __generator(this, function (_a) {
|
|
2497
|
+
switch (_a.label) {
|
|
2498
|
+
case 0:
|
|
2499
|
+
mockStream = createMockChangeStream();
|
|
2500
|
+
mockDb = {
|
|
2501
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2502
|
+
};
|
|
2503
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2504
|
+
(0, registry_1.registerRealtime)({
|
|
2505
|
+
collectionName: "todos",
|
|
2506
|
+
config: {
|
|
2507
|
+
methods: ["create", "update", "delete"],
|
|
2508
|
+
roomStrategy: "model",
|
|
2509
|
+
},
|
|
2510
|
+
modelName: "Todo",
|
|
2511
|
+
options: {
|
|
2512
|
+
permissions: {
|
|
2513
|
+
create: [function () { return true; }],
|
|
2514
|
+
delete: [function () { return true; }],
|
|
2515
|
+
list: [function () { return true; }],
|
|
2516
|
+
read: [function () { return true; }],
|
|
2517
|
+
update: [function () { return true; }],
|
|
2518
|
+
},
|
|
2519
|
+
},
|
|
2520
|
+
routePath: "/todos",
|
|
2521
|
+
});
|
|
2522
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2523
|
+
case 1:
|
|
2524
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2525
|
+
io = createMockIo();
|
|
2526
|
+
startChangeStreamWatcher(io, {}, true);
|
|
2527
|
+
changeHandler = mockStream.listeners.get("change");
|
|
2528
|
+
return [4 /*yield*/, changeHandler({
|
|
2529
|
+
documentKey: { _id: "doc-1" },
|
|
2530
|
+
fullDocument: { _id: "doc-1", name: "Updated", status: "done" },
|
|
2531
|
+
ns: { coll: "todos" },
|
|
2532
|
+
operationType: "update",
|
|
2533
|
+
updateDescription: { updatedFields: { name: "Updated", status: "done" } },
|
|
2534
|
+
})];
|
|
2535
|
+
case 2:
|
|
2536
|
+
_a.sent();
|
|
2537
|
+
return [2 /*return*/];
|
|
2538
|
+
}
|
|
2539
|
+
});
|
|
2540
|
+
}); });
|
|
2541
|
+
(0, bun_test_1.it)("respects ignoredCollections config", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2542
|
+
var mockStream, mockDb, startChangeStreamWatcher, io, pipeline, matchStage;
|
|
2543
|
+
return __generator(this, function (_a) {
|
|
2544
|
+
switch (_a.label) {
|
|
2545
|
+
case 0:
|
|
2546
|
+
mockStream = createMockChangeStream();
|
|
2547
|
+
mockDb = {
|
|
2548
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2549
|
+
};
|
|
2550
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2551
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2552
|
+
case 1:
|
|
2553
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2554
|
+
io = createMockIo();
|
|
2555
|
+
startChangeStreamWatcher(io, { ignoredCollections: ["audit_logs"] }, true);
|
|
2556
|
+
pipeline = mockDb.watch.mock.calls[0][0];
|
|
2557
|
+
matchStage = pipeline[0].$match;
|
|
2558
|
+
(0, bun_test_1.expect)(matchStage["ns.coll"].$nin).toContain("audit_logs");
|
|
2559
|
+
(0, bun_test_1.expect)(matchStage["ns.coll"].$nin).toContain("socketio");
|
|
2560
|
+
(0, bun_test_1.expect)(matchStage["ns.coll"].$nin).toContain("sessions");
|
|
2561
|
+
return [2 /*return*/];
|
|
2562
|
+
}
|
|
2563
|
+
});
|
|
2564
|
+
}); });
|
|
2565
|
+
(0, bun_test_1.it)("respects ignoredOperations config", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2566
|
+
var mockStream, mockDb, startChangeStreamWatcher, io, changeHandler;
|
|
2567
|
+
return __generator(this, function (_a) {
|
|
2568
|
+
switch (_a.label) {
|
|
2569
|
+
case 0:
|
|
2570
|
+
mockStream = createMockChangeStream();
|
|
2571
|
+
mockDb = {
|
|
2572
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2573
|
+
};
|
|
2574
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2575
|
+
(0, registry_1.registerRealtime)({
|
|
2576
|
+
collectionName: "todos",
|
|
2577
|
+
config: {
|
|
2578
|
+
methods: ["create", "update", "delete"],
|
|
2579
|
+
roomStrategy: "model",
|
|
2580
|
+
},
|
|
2581
|
+
modelName: "Todo",
|
|
2582
|
+
options: {
|
|
2583
|
+
permissions: {
|
|
2584
|
+
create: [function () { return true; }],
|
|
2585
|
+
delete: [function () { return true; }],
|
|
2586
|
+
list: [function () { return true; }],
|
|
2587
|
+
read: [function () { return true; }],
|
|
2588
|
+
update: [function () { return true; }],
|
|
2589
|
+
},
|
|
2590
|
+
},
|
|
2591
|
+
routePath: "/todos",
|
|
2592
|
+
});
|
|
2593
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2594
|
+
case 1:
|
|
2595
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2596
|
+
io = createMockIo();
|
|
2597
|
+
startChangeStreamWatcher(io, { ignoredOperations: ["insert"] }, true);
|
|
2598
|
+
changeHandler = mockStream.listeners.get("change");
|
|
2599
|
+
// This insert should be skipped because "insert" is ignored
|
|
2600
|
+
return [4 /*yield*/, changeHandler({
|
|
2601
|
+
documentKey: { _id: "doc-1" },
|
|
2602
|
+
fullDocument: { _id: "doc-1" },
|
|
2603
|
+
ns: { coll: "todos" },
|
|
2604
|
+
operationType: "insert",
|
|
2605
|
+
})];
|
|
2606
|
+
case 2:
|
|
2607
|
+
// This insert should be skipped because "insert" is ignored
|
|
2608
|
+
_a.sent();
|
|
2609
|
+
return [2 /*return*/];
|
|
2610
|
+
}
|
|
2611
|
+
});
|
|
2612
|
+
}); });
|
|
2613
|
+
(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, changeHandler;
|
|
2615
|
+
return __generator(this, function (_a) {
|
|
2616
|
+
switch (_a.label) {
|
|
2617
|
+
case 0:
|
|
2618
|
+
mockStream = createMockChangeStream();
|
|
2619
|
+
mockDb = {
|
|
2620
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2621
|
+
};
|
|
2622
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2623
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2624
|
+
case 1:
|
|
2625
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2626
|
+
io = createMockIo();
|
|
2627
|
+
startChangeStreamWatcher(io, {}, true);
|
|
2628
|
+
changeHandler = mockStream.listeners.get("change");
|
|
2629
|
+
// Missing ns.coll
|
|
2630
|
+
return [4 /*yield*/, changeHandler({
|
|
2631
|
+
documentKey: { _id: "doc-1" },
|
|
2632
|
+
ns: {},
|
|
2633
|
+
operationType: "insert",
|
|
2634
|
+
})];
|
|
2635
|
+
case 2:
|
|
2636
|
+
// Missing ns.coll
|
|
2637
|
+
_a.sent();
|
|
2638
|
+
// Missing documentKey
|
|
2639
|
+
return [4 /*yield*/, changeHandler({
|
|
2640
|
+
documentKey: {},
|
|
2641
|
+
ns: { coll: "todos" },
|
|
2642
|
+
operationType: "insert",
|
|
2643
|
+
})];
|
|
2644
|
+
case 3:
|
|
2645
|
+
// Missing documentKey
|
|
2646
|
+
_a.sent();
|
|
2647
|
+
return [2 /*return*/];
|
|
2648
|
+
}
|
|
2649
|
+
});
|
|
2650
|
+
}); });
|
|
2651
|
+
(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, changeHandler;
|
|
2653
|
+
return __generator(this, function (_a) {
|
|
2654
|
+
switch (_a.label) {
|
|
2655
|
+
case 0:
|
|
2656
|
+
mockStream = createMockChangeStream();
|
|
2657
|
+
mockDb = {
|
|
2658
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2659
|
+
};
|
|
2660
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2661
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2662
|
+
case 1:
|
|
2663
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2664
|
+
io = createMockIo();
|
|
2665
|
+
startChangeStreamWatcher(io, {}, true);
|
|
2666
|
+
changeHandler = mockStream.listeners.get("change");
|
|
2667
|
+
// "drop" is not in our pipeline filter, should be skipped
|
|
2668
|
+
return [4 /*yield*/, changeHandler({
|
|
2669
|
+
operationType: "drop",
|
|
2670
|
+
})];
|
|
2671
|
+
case 2:
|
|
2672
|
+
// "drop" is not in our pipeline filter, should be skipped
|
|
2673
|
+
_a.sent();
|
|
2674
|
+
return [2 /*return*/];
|
|
2675
|
+
}
|
|
2676
|
+
});
|
|
2677
|
+
}); });
|
|
2678
|
+
(0, bun_test_1.it)("handles error/close/end events gracefully", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2679
|
+
var mockStream, mockDb, startChangeStreamWatcher, io;
|
|
2680
|
+
return __generator(this, function (_a) {
|
|
2681
|
+
switch (_a.label) {
|
|
2682
|
+
case 0:
|
|
2683
|
+
mockStream = createMockChangeStream();
|
|
2684
|
+
mockDb = {
|
|
2685
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2686
|
+
};
|
|
2687
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2688
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2689
|
+
case 1:
|
|
2690
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2691
|
+
io = createMockIo();
|
|
2692
|
+
startChangeStreamWatcher(io, {}, true);
|
|
2693
|
+
// Trigger error, close, end — should not throw
|
|
2694
|
+
mockStream.trigger("error", new Error("test error"));
|
|
2695
|
+
mockStream.trigger("close");
|
|
2696
|
+
mockStream.trigger("end");
|
|
2697
|
+
return [2 /*return*/];
|
|
2698
|
+
}
|
|
2699
|
+
});
|
|
2700
|
+
}); });
|
|
2701
|
+
(0, bun_test_1.it)("uses custom batchSize and fullDocument config", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2702
|
+
var mockStream, mockDb, startChangeStreamWatcher, io, options;
|
|
2703
|
+
return __generator(this, function (_a) {
|
|
2704
|
+
switch (_a.label) {
|
|
2705
|
+
case 0:
|
|
2706
|
+
mockStream = createMockChangeStream();
|
|
2707
|
+
mockDb = {
|
|
2708
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2709
|
+
};
|
|
2710
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2711
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2712
|
+
case 1:
|
|
2713
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2714
|
+
io = createMockIo();
|
|
2715
|
+
startChangeStreamWatcher(io, { batchSize: 100, fullDocument: "whenAvailable" }, true);
|
|
2716
|
+
options = mockDb.watch.mock.calls[0][1];
|
|
2717
|
+
(0, bun_test_1.expect)(options.batchSize).toBe(100);
|
|
2718
|
+
(0, bun_test_1.expect)(options.fullDocument).toBe("whenAvailable");
|
|
2719
|
+
return [2 /*return*/];
|
|
2720
|
+
}
|
|
2721
|
+
});
|
|
2722
|
+
}); });
|
|
2723
|
+
(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, changeHandler;
|
|
2725
|
+
return __generator(this, function (_a) {
|
|
2726
|
+
switch (_a.label) {
|
|
2727
|
+
case 0:
|
|
2728
|
+
mockStream = createMockChangeStream();
|
|
2729
|
+
mockDb = {
|
|
2730
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2731
|
+
};
|
|
2732
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2733
|
+
// Register with a model that will throw during permission check
|
|
2734
|
+
(0, registry_1.registerRealtime)({
|
|
2735
|
+
collectionName: "todos",
|
|
2736
|
+
config: {
|
|
2737
|
+
methods: ["create", "update", "delete"],
|
|
2738
|
+
roomStrategy: "model",
|
|
2739
|
+
},
|
|
2740
|
+
modelName: "Todo",
|
|
2741
|
+
options: {
|
|
2742
|
+
permissions: {
|
|
2743
|
+
create: [function () { return true; }],
|
|
2744
|
+
delete: [function () { return true; }],
|
|
2745
|
+
list: [function () { return true; }],
|
|
2746
|
+
read: [
|
|
2747
|
+
function () {
|
|
2748
|
+
throw new Error("permission check error");
|
|
2749
|
+
},
|
|
2750
|
+
],
|
|
2751
|
+
update: [function () { return true; }],
|
|
2752
|
+
},
|
|
2753
|
+
},
|
|
2754
|
+
routePath: "/todos",
|
|
2755
|
+
});
|
|
2756
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2757
|
+
case 1:
|
|
2758
|
+
startChangeStreamWatcher = (_a.sent()).startChangeStreamWatcher;
|
|
2759
|
+
emissions = [];
|
|
2760
|
+
mockSocket = {
|
|
2761
|
+
decodedToken: { id: "user-1" },
|
|
2762
|
+
emit: function (_event, _data) {
|
|
2763
|
+
emissions.push({ _data: _data, _event: _event });
|
|
2764
|
+
},
|
|
2765
|
+
id: "sock-1",
|
|
2766
|
+
};
|
|
2767
|
+
rooms = new Map();
|
|
2768
|
+
rooms.set("model:todos", new Set(["sock-1"]));
|
|
2769
|
+
sockets = new Map();
|
|
2770
|
+
sockets.set("sock-1", mockSocket);
|
|
2771
|
+
io = {
|
|
2772
|
+
sockets: {
|
|
2773
|
+
adapter: { rooms: rooms },
|
|
2774
|
+
sockets: sockets,
|
|
2775
|
+
},
|
|
2776
|
+
to: function () { return ({ emit: function () { } }); },
|
|
2777
|
+
};
|
|
2778
|
+
startChangeStreamWatcher(io, {}, true);
|
|
2779
|
+
changeHandler = mockStream.listeners.get("change");
|
|
2780
|
+
// Should not throw even though permission check throws
|
|
2781
|
+
return [4 /*yield*/, changeHandler({
|
|
2782
|
+
documentKey: { _id: "doc-1" },
|
|
2783
|
+
fullDocument: { _id: "doc-1", name: "Test" },
|
|
2784
|
+
ns: { coll: "todos" },
|
|
2785
|
+
operationType: "insert",
|
|
2786
|
+
})];
|
|
2787
|
+
case 2:
|
|
2788
|
+
// Should not throw even though permission check throws
|
|
2789
|
+
_a.sent();
|
|
2790
|
+
return [2 /*return*/];
|
|
2791
|
+
}
|
|
2792
|
+
});
|
|
2793
|
+
}); });
|
|
2794
|
+
});
|
|
2795
|
+
(0, bun_test_1.describe)("stopChangeStreamWatcher", function () {
|
|
2796
|
+
(0, bun_test_1.it)("closes and nullifies the active watcher", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2797
|
+
var mockStream, mockDb, originalDb, _a, startChangeStreamWatcher, stopChangeStreamWatcher, io;
|
|
2798
|
+
return __generator(this, function (_b) {
|
|
2799
|
+
switch (_b.label) {
|
|
2800
|
+
case 0:
|
|
2801
|
+
mockStream = {
|
|
2802
|
+
close: (0, bun_test_1.mock)(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
2803
|
+
return [2 /*return*/];
|
|
2804
|
+
}); }); }),
|
|
2805
|
+
on: function () { },
|
|
2806
|
+
};
|
|
2807
|
+
mockDb = {
|
|
2808
|
+
watch: (0, bun_test_1.mock)(function () { return mockStream; }),
|
|
2809
|
+
};
|
|
2810
|
+
originalDb = mongoose_1.default.connection.db;
|
|
2811
|
+
mongoose_1.default.connection.db = mockDb;
|
|
2812
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./changeStreamWatcher")); })];
|
|
2813
|
+
case 1:
|
|
2814
|
+
_a = _b.sent(), startChangeStreamWatcher = _a.startChangeStreamWatcher, stopChangeStreamWatcher = _a.stopChangeStreamWatcher;
|
|
2815
|
+
io = {
|
|
2816
|
+
sockets: {
|
|
2817
|
+
adapter: { rooms: new Map() },
|
|
2818
|
+
sockets: new Map(),
|
|
2819
|
+
},
|
|
2820
|
+
to: function () { return ({ emit: function () { } }); },
|
|
2821
|
+
};
|
|
2822
|
+
startChangeStreamWatcher(io);
|
|
2823
|
+
return [4 /*yield*/, stopChangeStreamWatcher()];
|
|
2824
|
+
case 2:
|
|
2825
|
+
_b.sent();
|
|
2826
|
+
(0, bun_test_1.expect)(mockStream.close).toHaveBeenCalled();
|
|
2827
|
+
// Calling again should be a no-op
|
|
2828
|
+
return [4 /*yield*/, stopChangeStreamWatcher()];
|
|
2829
|
+
case 3:
|
|
2830
|
+
// Calling again should be a no-op
|
|
2831
|
+
_b.sent();
|
|
2832
|
+
mongoose_1.default.connection.db = originalDb;
|
|
2833
|
+
return [2 /*return*/];
|
|
2834
|
+
}
|
|
2835
|
+
});
|
|
2836
|
+
}); });
|
|
2837
|
+
});
|
|
2838
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2839
|
+
// RealtimeApp.onServerCreated / setupAdapter
|
|
2840
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2841
|
+
(0, bun_test_1.describe)("RealtimeApp.onServerCreated", function () {
|
|
2842
|
+
var servers = [];
|
|
2843
|
+
(0, bun_test_1.afterEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2844
|
+
var servers_1, servers_1_1, s;
|
|
2845
|
+
var e_1, _a;
|
|
2846
|
+
return __generator(this, function (_b) {
|
|
2847
|
+
try {
|
|
2848
|
+
for (servers_1 = __values(servers), servers_1_1 = servers_1.next(); !servers_1_1.done; servers_1_1 = servers_1.next()) {
|
|
2849
|
+
s = servers_1_1.value;
|
|
2850
|
+
s.close();
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
2854
|
+
finally {
|
|
2855
|
+
try {
|
|
2856
|
+
if (servers_1_1 && !servers_1_1.done && (_a = servers_1.return)) _a.call(servers_1);
|
|
2857
|
+
}
|
|
2858
|
+
finally { if (e_1) throw e_1.error; }
|
|
2859
|
+
}
|
|
2860
|
+
servers.length = 0;
|
|
2861
|
+
return [2 /*return*/];
|
|
2862
|
+
});
|
|
2863
|
+
}); });
|
|
2864
|
+
var makeServer = function () {
|
|
2865
|
+
var http = require("http");
|
|
2866
|
+
var server = http.createServer();
|
|
2867
|
+
servers.push(server);
|
|
2868
|
+
return server;
|
|
2869
|
+
};
|
|
2870
|
+
(0, bun_test_1.it)("throws when TOKEN_SECRET is missing", function () {
|
|
2871
|
+
var originalSecret = process.env.TOKEN_SECRET;
|
|
2872
|
+
process.env.TOKEN_SECRET = "";
|
|
2873
|
+
var app = new realtimeApp_1.RealtimeApp({ tokenSecret: undefined });
|
|
2874
|
+
var server = makeServer();
|
|
2875
|
+
(0, bun_test_1.expect)(function () { return app.onServerCreated(server); }).toThrow("TOKEN_SECRET is required");
|
|
2876
|
+
process.env.TOKEN_SECRET = originalSecret;
|
|
2877
|
+
});
|
|
2878
|
+
(0, bun_test_1.it)("sets up Socket.io with valid config", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2879
|
+
var app, server, originalDb, mockStream;
|
|
2880
|
+
return __generator(this, function (_a) {
|
|
2881
|
+
switch (_a.label) {
|
|
2882
|
+
case 0:
|
|
2883
|
+
app = new realtimeApp_1.RealtimeApp({
|
|
2884
|
+
adapter: "none",
|
|
2885
|
+
tokenSecret: "test-secret",
|
|
2886
|
+
});
|
|
2887
|
+
server = makeServer();
|
|
2888
|
+
originalDb = mongoose_1.default.connection.db;
|
|
2889
|
+
mockStream = { close: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
2890
|
+
return [2 /*return*/];
|
|
2891
|
+
}); }); }, on: function () { return mockStream; } };
|
|
2892
|
+
mongoose_1.default.connection.db = { watch: function () { return mockStream; } };
|
|
2893
|
+
app.onServerCreated(server);
|
|
2894
|
+
(0, bun_test_1.expect)(app.getIo()).toBeDefined();
|
|
2895
|
+
return [4 /*yield*/, app.close()];
|
|
2896
|
+
case 1:
|
|
2897
|
+
_a.sent();
|
|
2898
|
+
mongoose_1.default.connection.db = originalDb;
|
|
2899
|
+
return [2 /*return*/];
|
|
2900
|
+
}
|
|
2901
|
+
});
|
|
2902
|
+
}); });
|
|
2903
|
+
});
|
|
2904
|
+
(0, bun_test_1.describe)("RealtimeApp.setupAdapter (private, via onServerCreated config)", function () {
|
|
2905
|
+
var servers = [];
|
|
2906
|
+
(0, bun_test_1.afterEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2907
|
+
var servers_2, servers_2_1, s;
|
|
2908
|
+
var e_2, _a;
|
|
2909
|
+
return __generator(this, function (_b) {
|
|
2910
|
+
try {
|
|
2911
|
+
for (servers_2 = __values(servers), servers_2_1 = servers_2.next(); !servers_2_1.done; servers_2_1 = servers_2.next()) {
|
|
2912
|
+
s = servers_2_1.value;
|
|
2913
|
+
s.close();
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
2917
|
+
finally {
|
|
2918
|
+
try {
|
|
2919
|
+
if (servers_2_1 && !servers_2_1.done && (_a = servers_2.return)) _a.call(servers_2);
|
|
2920
|
+
}
|
|
2921
|
+
finally { if (e_2) throw e_2.error; }
|
|
2922
|
+
}
|
|
2923
|
+
servers.length = 0;
|
|
2924
|
+
return [2 /*return*/];
|
|
2925
|
+
});
|
|
2926
|
+
}); });
|
|
2927
|
+
var makeServer = function () {
|
|
2928
|
+
var http = require("http");
|
|
2929
|
+
var server = http.createServer();
|
|
2930
|
+
servers.push(server);
|
|
2931
|
+
return server;
|
|
2932
|
+
};
|
|
2933
|
+
(0, bun_test_1.it)("logs warning when redis adapter requested but no URL found", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2934
|
+
var originalValkey, originalRedis, originalDb, mockStream, app, server;
|
|
2935
|
+
return __generator(this, function (_a) {
|
|
2936
|
+
switch (_a.label) {
|
|
2937
|
+
case 0:
|
|
2938
|
+
originalValkey = process.env.VALKEY_URL;
|
|
2939
|
+
originalRedis = process.env.REDIS_URL;
|
|
2940
|
+
originalDb = mongoose_1.default.connection.db;
|
|
2941
|
+
process.env.VALKEY_URL = "";
|
|
2942
|
+
process.env.REDIS_URL = "";
|
|
2943
|
+
mockStream = { close: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
2944
|
+
return [2 /*return*/];
|
|
2945
|
+
}); }); }, on: function () { return mockStream; } };
|
|
2946
|
+
mongoose_1.default.connection.db = { watch: function () { return mockStream; } };
|
|
2947
|
+
app = new realtimeApp_1.RealtimeApp({
|
|
2948
|
+
adapter: "redis",
|
|
2949
|
+
tokenSecret: "test-secret",
|
|
2950
|
+
});
|
|
2951
|
+
server = makeServer();
|
|
2952
|
+
app.onServerCreated(server);
|
|
2953
|
+
return [4 /*yield*/, app.close()];
|
|
2954
|
+
case 1:
|
|
2955
|
+
_a.sent();
|
|
2956
|
+
process.env.VALKEY_URL = originalValkey;
|
|
2957
|
+
process.env.REDIS_URL = originalRedis;
|
|
2958
|
+
mongoose_1.default.connection.db = originalDb;
|
|
2959
|
+
return [2 /*return*/];
|
|
2960
|
+
}
|
|
2961
|
+
});
|
|
2962
|
+
}); });
|
|
2963
|
+
(0, bun_test_1.it)("logs info when redis adapter has a URL", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2964
|
+
var originalValkey, originalDb, mockStream, app, server;
|
|
2965
|
+
return __generator(this, function (_a) {
|
|
2966
|
+
switch (_a.label) {
|
|
2967
|
+
case 0:
|
|
2968
|
+
originalValkey = process.env.VALKEY_URL;
|
|
2969
|
+
originalDb = mongoose_1.default.connection.db;
|
|
2970
|
+
process.env.VALKEY_URL = "redis://user:pass@localhost:6379/0";
|
|
2971
|
+
mockStream = { close: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
2972
|
+
return [2 /*return*/];
|
|
2973
|
+
}); }); }, on: function () { return mockStream; } };
|
|
2974
|
+
mongoose_1.default.connection.db = { watch: function () { return mockStream; } };
|
|
2975
|
+
app = new realtimeApp_1.RealtimeApp({
|
|
2976
|
+
adapter: "redis",
|
|
2977
|
+
debug: true,
|
|
2978
|
+
tokenSecret: "test-secret",
|
|
2979
|
+
});
|
|
2980
|
+
server = makeServer();
|
|
2981
|
+
app.onServerCreated(server);
|
|
2982
|
+
return [4 /*yield*/, app.close()];
|
|
2983
|
+
case 1:
|
|
2984
|
+
_a.sent();
|
|
2985
|
+
process.env.VALKEY_URL = originalValkey;
|
|
2986
|
+
mongoose_1.default.connection.db = originalDb;
|
|
2987
|
+
return [2 /*return*/];
|
|
2988
|
+
}
|
|
2989
|
+
});
|
|
2990
|
+
}); });
|
|
2991
|
+
(0, bun_test_1.it)("no-op adapter mode 'none'", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2992
|
+
var originalDb, mockStream, app, server;
|
|
2993
|
+
return __generator(this, function (_a) {
|
|
2994
|
+
switch (_a.label) {
|
|
2995
|
+
case 0:
|
|
2996
|
+
originalDb = mongoose_1.default.connection.db;
|
|
2997
|
+
mockStream = { close: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
2998
|
+
return [2 /*return*/];
|
|
2999
|
+
}); }); }, on: function () { return mockStream; } };
|
|
3000
|
+
mongoose_1.default.connection.db = { watch: function () { return mockStream; } };
|
|
3001
|
+
app = new realtimeApp_1.RealtimeApp({
|
|
3002
|
+
adapter: "none",
|
|
3003
|
+
tokenSecret: "test-secret",
|
|
3004
|
+
});
|
|
3005
|
+
server = makeServer();
|
|
3006
|
+
app.onServerCreated(server);
|
|
3007
|
+
(0, bun_test_1.expect)(app.getIo()).toBeDefined();
|
|
3008
|
+
return [4 /*yield*/, app.close()];
|
|
3009
|
+
case 1:
|
|
3010
|
+
_a.sent();
|
|
3011
|
+
mongoose_1.default.connection.db = originalDb;
|
|
3012
|
+
return [2 /*return*/];
|
|
3013
|
+
}
|
|
3014
|
+
});
|
|
3015
|
+
}); });
|
|
3016
|
+
});
|
|
3017
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2144
3018
|
// ensureApiId
|
|
2145
3019
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
2146
3020
|
(0, bun_test_1.describe)("ensureApiId", function () {
|
|
@@ -2278,13 +3152,13 @@ var createMockSocket = function (decodedToken) {
|
|
|
2278
3152
|
// Change streams require a MongoDB replica set. CI (api-ci.yml) runs standalone MongoDB,
|
|
2279
3153
|
// so these tests are skipped when replica sets are not available.
|
|
2280
3154
|
var hasReplicaSet = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2281
|
-
var
|
|
3155
|
+
var mongoose_2, admin, status_1, _a;
|
|
2282
3156
|
return __generator(this, function (_b) {
|
|
2283
3157
|
switch (_b.label) {
|
|
2284
3158
|
case 0:
|
|
2285
3159
|
_b.trys.push([0, 2, , 3]);
|
|
2286
|
-
|
|
2287
|
-
admin =
|
|
3160
|
+
mongoose_2 = require("mongoose");
|
|
3161
|
+
admin = mongoose_2.connection.db.admin();
|
|
2288
3162
|
return [4 /*yield*/, admin.command({ replSetGetStatus: 1 })];
|
|
2289
3163
|
case 1:
|
|
2290
3164
|
status_1 = _b.sent();
|
|
@@ -3048,6 +3922,9 @@ var hasReplicaSet = function () { return __awaiter(void 0, void 0, void 0, funct
|
|
|
3048
3922
|
});
|
|
3049
3923
|
}); });
|
|
3050
3924
|
});
|
|
3925
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3926
|
+
// redactCredentials — Redis URL logging
|
|
3927
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3051
3928
|
(0, bun_test_1.describe)("redactCredentials", function () {
|
|
3052
3929
|
(0, bun_test_1.it)("redacts user:password@ in a redis URL", function () {
|
|
3053
3930
|
(0, bun_test_1.expect)((0, realtimeApp_1.redactCredentials)("redis://user:secret@host:6379/0")).toBe("redis://***@host:6379/0");
|