anchordb-relay 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +101 -0
  3. package/dist/cjs/cli.d.ts +3 -0
  4. package/dist/cjs/cli.d.ts.map +1 -0
  5. package/dist/cjs/cli.js +57 -0
  6. package/dist/cjs/cli.js.map +1 -0
  7. package/dist/cjs/index.d.ts +7 -0
  8. package/dist/cjs/index.d.ts.map +1 -0
  9. package/dist/cjs/index.js +10 -0
  10. package/dist/cjs/index.js.map +1 -0
  11. package/dist/cjs/mongo-bridge.d.ts +65 -0
  12. package/dist/cjs/mongo-bridge.d.ts.map +1 -0
  13. package/dist/cjs/mongo-bridge.js +289 -0
  14. package/dist/cjs/mongo-bridge.js.map +1 -0
  15. package/dist/cjs/package.json +3 -0
  16. package/dist/cjs/relay.d.ts +78 -0
  17. package/dist/cjs/relay.d.ts.map +1 -0
  18. package/dist/cjs/relay.js +117 -0
  19. package/dist/cjs/relay.js.map +1 -0
  20. package/dist/cjs/server.d.ts +30 -0
  21. package/dist/cjs/server.d.ts.map +1 -0
  22. package/dist/cjs/server.js +97 -0
  23. package/dist/cjs/server.js.map +1 -0
  24. package/dist/esm/cli.d.ts +3 -0
  25. package/dist/esm/cli.d.ts.map +1 -0
  26. package/dist/esm/cli.js +55 -0
  27. package/dist/esm/cli.js.map +1 -0
  28. package/dist/esm/index.d.ts +7 -0
  29. package/dist/esm/index.d.ts.map +1 -0
  30. package/dist/esm/index.js +4 -0
  31. package/dist/esm/index.js.map +1 -0
  32. package/dist/esm/mongo-bridge.d.ts +65 -0
  33. package/dist/esm/mongo-bridge.d.ts.map +1 -0
  34. package/dist/esm/mongo-bridge.js +252 -0
  35. package/dist/esm/mongo-bridge.js.map +1 -0
  36. package/dist/esm/package.json +3 -0
  37. package/dist/esm/relay.d.ts +78 -0
  38. package/dist/esm/relay.d.ts.map +1 -0
  39. package/dist/esm/relay.js +113 -0
  40. package/dist/esm/relay.js.map +1 -0
  41. package/dist/esm/server.d.ts +30 -0
  42. package/dist/esm/server.d.ts.map +1 -0
  43. package/dist/esm/server.js +61 -0
  44. package/dist/esm/server.js.map +1 -0
  45. package/package.json +65 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AnchorDB contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # anchordb-relay
2
+
3
+ Development-only relay that connects an app running [AnchorDB](https://www.npmjs.com/package/anchordb)
4
+ to Anchor Lens.
5
+
6
+ ```bash
7
+ npx anchor-relay
8
+ ```
9
+
10
+ ```
11
+ Anchor Inspector Relay
12
+ ──────────────────────
13
+ listening ws://127.0.0.1:9440
14
+ room k3Jf9Xq2mNp4
15
+ agent URL ws://127.0.0.1:9440/relay?room=k3Jf9Xq2mNp4&role=agent
16
+ Lens link anchor-lens://connect?relay=...&room=k3Jf9Xq2mNp4
17
+ MongoDB off — start with --mongo-bridge to sync collections to a real MongoDB
18
+ ```
19
+
20
+ ## Why a relay exists
21
+
22
+ React Native and browsers can open a WebSocket **client** but cannot **listen** without a native TCP
23
+ module — which would force an Expo dev build and rule out Expo Go entirely. So both the app and Lens
24
+ dial out to this small Node process, which pairs them by room and copies frames across.
25
+
26
+ It is a dumb pipe on purpose: it never parses the inspector protocol, so the protocol can change
27
+ without the relay ever needing an update.
28
+
29
+ ## What it deliberately does not do
30
+
31
+ It **does not authenticate the inspector session.** Pairing is end-to-end between the app and Lens
32
+ (an HMAC over a challenge), so a compromised or malicious relay still cannot issue itself a session.
33
+ The room id only decides who is connected to whom; it is not the security boundary.
34
+
35
+ The QR payload carries the relay address and room — **never the pairing code**, which the app
36
+ displays separately. Photographing the screen is therefore not enough to pair.
37
+
38
+ ## The MongoDB bridge
39
+
40
+ ```bash
41
+ npm install mongodb # an optional dependency, installed where the relay runs
42
+ npx anchor-relay --mongo-bridge
43
+ ```
44
+
45
+ Anchor Lens can move collections between a device and a real MongoDB, but it cannot open the
46
+ connection itself: the driver needs raw TCP and TLS sockets, and React Native has neither. So the
47
+ driver runs here, and Lens drives it over `/bridge`:
48
+
49
+ ```
50
+ pull: relay reads MongoDB ──Extended JSON──► agent.importCollection()
51
+ push: agent.exportCollection() ──Extended JSON──► relay writes MongoDB
52
+ ```
53
+
54
+ Both hops carry Extended JSON — the interchange format `anchordb` already cross-validates
55
+ against the official `bson` package — so an ObjectId is still an ObjectId at the far end. Anchor's
56
+ codec encodes on the Anchor side and MongoDB's own codec decodes on the MongoDB side; there is no
57
+ third interpretation anywhere.
58
+
59
+ ### Three restrictions, and why
60
+
61
+ - **Off unless you ask for it.** A relay that will dial any MongoDB on request is a confused deputy:
62
+ every process on the machine could use it to reach a database it has no credentials for.
63
+ `--mongo-bridge` is the opt-in.
64
+ - **The room is the token.** A bridge socket must present the room id the relay printed, so knowing
65
+ the port is not enough.
66
+ - **The connection string is never stored and never logged.** It lives in one `MongoClient` for the
67
+ life of one socket and dies with it. Every log line and every error message — including connection
68
+ failures, where a URI is most likely to escape — goes through `redactMongoUri`.
69
+
70
+ `--host 0.0.0.0` together with `--mongo-bridge` is a combination worth thinking twice about.
71
+
72
+ ## Safety
73
+
74
+ Binds to `127.0.0.1` by default. A relay reachable from the whole network is a database reachable
75
+ from the whole network, so `--host 0.0.0.0` is a deliberate opt-in and prints a warning.
76
+
77
+ Development only. Never run this in production.
78
+
79
+ ## API
80
+
81
+ ```ts
82
+ import { InspectorRelay, startRelayServer } from "anchordb-relay";
83
+
84
+ const server = await startRelayServer({ port: 9440 });
85
+ const room = server.relay.createRoom("MyApp");
86
+ ```
87
+
88
+ `InspectorRelay` is transport-agnostic and has no `ws` dependency, so the routing logic can be
89
+ driven by any socket implementation — or tested without opening a port.
90
+
91
+ ## Status
92
+
93
+ **0.2.0.** MIT.
94
+
95
+ **37 tests.** Room routing and isolation, frame limits, and the MongoDB bridge: access control,
96
+ streamed reads, all three write modes, session lifetime, and that a password reaches neither a log
97
+ line nor an error message.
98
+
99
+ The bridge is tested against an injected fake driver — that seam is why `MongoDriver` exists.
100
+ Everything above the driver is exercised for real; **the driver calls themselves have never run
101
+ against a live MongoDB**, because there is none on the machine this was built on.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const server_ts_1 = require("./server.js");
5
+ /**
6
+ * `npx anchor-relay`
7
+ *
8
+ * Prints the room and the QR payload a developer scans. Binds to 127.0.0.1 by default: a relay
9
+ * reachable from the whole network is a database reachable from the whole network, so opening it
10
+ * up has to be a deliberate `--host 0.0.0.0`.
11
+ */
12
+ const args = process.argv.slice(2);
13
+ const readFlag = (name, fallback) => {
14
+ const i = args.indexOf(`--${name}`);
15
+ return i >= 0 && args[i + 1] ? args[i + 1] : fallback;
16
+ };
17
+ const readSwitch = (name) => args.includes(`--${name}`);
18
+ const port = Number(readFlag("port", "9440"));
19
+ const host = readFlag("host", "127.0.0.1");
20
+ const mongoBridge = readSwitch("mongo-bridge");
21
+ // Wrapped in a function rather than using top-level await: this file is emitted as both ESM and
22
+ // CommonJS, and top-level await cannot be expressed in CJS at all.
23
+ async function main() {
24
+ const server = await (0, server_ts_1.startRelayServer)({ port, host, mongoBridge, onLog: (m) => console.log(` ${m}`) });
25
+ const room = server.relay.createRoom("AnchorDB");
26
+ const info = server.relay.connectionInfo(host, port, room);
27
+ console.log("\nAnchor Inspector Relay");
28
+ console.log("──────────────────────");
29
+ console.log(` listening ws://${host}:${port}`);
30
+ console.log(` room ${room}`);
31
+ console.log(` agent URL ws://${host}:${port}/relay?room=${room}&role=agent`);
32
+ console.log(` Lens link ${info.deepLink}`);
33
+ if (mongoBridge) {
34
+ console.log(` MongoDB ws://${host}:${port}/bridge?room=${room}`);
35
+ console.log("\n \x1b[33m! The MongoDB bridge is ON. Anything that can reach this relay and knows the\x1b[0m");
36
+ console.log(" \x1b[33m room can use this machine to reach a database you connect to.\x1b[0m");
37
+ console.log(" Connection strings are never stored or logged — they live only while Lens is connected.");
38
+ }
39
+ else {
40
+ console.log(" MongoDB off — start with --mongo-bridge to sync collections to a real MongoDB");
41
+ }
42
+ if (host !== "127.0.0.1") {
43
+ console.log("\n \x1b[33m! Bound beyond localhost — anyone on this network can reach the relay.\x1b[0m");
44
+ }
45
+ console.log("\n The pairing code is shown by the APP, not here: the QR alone must not be enough to pair.\n");
46
+ const shutdown = async () => {
47
+ await server.close();
48
+ process.exit(0);
49
+ };
50
+ process.on("SIGINT", shutdown);
51
+ process.on("SIGTERM", shutdown);
52
+ }
53
+ main().catch((err) => {
54
+ console.error("anchor-relay failed to start:", err);
55
+ process.exit(1);
56
+ });
57
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { InspectorRelay } from "./relay.js";
2
+ export type { RelayOptions, RelayRole, RelaySocket, RoomInfo } from "./relay.js";
3
+ export { MongoBridge } from "./mongo-bridge.js";
4
+ export type { MongoBridgeOptions, MongoConnection, MongoDriver } from "./mongo-bridge.js";
5
+ export { startRelayServer } from "./server.js";
6
+ export type { RelayServer, RelayServerOptions } from "./server.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startRelayServer = exports.MongoBridge = exports.InspectorRelay = void 0;
4
+ var relay_ts_1 = require("./relay.js");
5
+ Object.defineProperty(exports, "InspectorRelay", { enumerable: true, get: function () { return relay_ts_1.InspectorRelay; } });
6
+ var mongo_bridge_ts_1 = require("./mongo-bridge.js");
7
+ Object.defineProperty(exports, "MongoBridge", { enumerable: true, get: function () { return mongo_bridge_ts_1.MongoBridge; } });
8
+ var server_ts_1 = require("./server.js");
9
+ Object.defineProperty(exports, "startRelayServer", { enumerable: true, get: function () { return server_ts_1.startRelayServer; } });
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,uCAA4C;AAAnC,0GAAA,cAAc,OAAA;AAEvB,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AAEpB,yCAA+C;AAAtC,6GAAA,gBAAgB,OAAA"}
@@ -0,0 +1,65 @@
1
+ import { type BridgeWriteMode, type MongoCollectionInfo } from "anchordb";
2
+ import type { RelaySocket } from "./relay.js";
3
+ /**
4
+ * The MongoDB half of the bridge.
5
+ *
6
+ * Anchor Lens cannot open a MongoDB connection — React Native has no TCP sockets — so the driver
7
+ * runs here, in the relay, and Lens drives it. See `bridge.ts` in `anchordb` for the protocol
8
+ * and the reasoning.
9
+ *
10
+ * ## Three deliberate restrictions
11
+ *
12
+ * 1. **Off by default.** A relay that will dial any MongoDB on request is a confused deputy: every
13
+ * local process could use it to reach a database it has no credentials for. It takes
14
+ * `--mongo-bridge` to turn on.
15
+ * 2. **The room is the token.** A bridge socket must present the room id the relay printed, so
16
+ * knowing the port is not enough.
17
+ * 3. **The connection string is never stored and never logged.** It lives in one `MongoClient` for
18
+ * the life of one socket, and every log line and error message goes through `redactMongoUri`.
19
+ *
20
+ * Even so, this is a development tool on a developer's machine. It is not built to be exposed, and
21
+ * `--host 0.0.0.0` plus `--mongo-bridge` is a combination worth thinking twice about.
22
+ */
23
+ /** The slice of the MongoDB driver this uses, so tests can supply a fake instead of a server. */
24
+ export interface MongoDriver {
25
+ connect(uri: string): Promise<MongoConnection>;
26
+ /** MongoDB's own Extended JSON codec — never a second implementation. */
27
+ stringifyEJSON(value: unknown): string;
28
+ parseEJSON(text: string): unknown;
29
+ }
30
+ export interface MongoConnection {
31
+ serverVersion(): Promise<string>;
32
+ listCollections(database: string): Promise<MongoCollectionInfo[]>;
33
+ find(database: string, collection: string, batchSize: number): AsyncIterable<unknown[]>;
34
+ write(database: string, collection: string, documents: unknown[], mode: BridgeWriteMode): Promise<{
35
+ inserted: number;
36
+ updated: number;
37
+ skipped: number;
38
+ }>;
39
+ close(): Promise<void>;
40
+ }
41
+ export interface MongoBridgeOptions {
42
+ enabled: boolean;
43
+ /** Returns the driver. Defaults to a lazy `import("mongodb")`. */
44
+ driver?: () => Promise<MongoDriver>;
45
+ onLog?: (message: string) => void;
46
+ }
47
+ export declare class MongoBridge {
48
+ private readonly enabled;
49
+ private readonly loadDriver;
50
+ private readonly onLog;
51
+ /** One MongoDB connection per socket, closed with it. */
52
+ private readonly sessions;
53
+ constructor(options: MongoBridgeOptions);
54
+ /** Attach a socket that dialled `/bridge`. */
55
+ join(socket: RelaySocket, room: string | null, validRoom: (room: string) => boolean): void;
56
+ private release;
57
+ private send;
58
+ private handle;
59
+ private connect;
60
+ private session;
61
+ /** Stream a collection out as newline-delimited Extended JSON. */
62
+ private read;
63
+ private write;
64
+ }
65
+ //# sourceMappingURL=mongo-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongo-bridge.d.ts","sourceRoot":"","sources":["../../src/mongo-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACzB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,iGAAiG;AACjG,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC/C,yEAAyE;IACzE,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACvC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAClE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACxF,KAAK,CACH,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,OAAO,EAAE,EACpB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAKD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;IACpC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAUD,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IACxD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAClD,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6E;gBAE1F,OAAO,EAAE,kBAAkB;IAMvC,8CAA8C;IAC9C,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI;YAmB5E,OAAO;IASrB,OAAO,CAAC,IAAI;YAIE,MAAM;YAsCN,OAAO;IAwCrB,OAAO,CAAC,OAAO;IAMf,kEAAkE;YACpD,IAAI;YA0BJ,KAAK;CA4BpB"}
@@ -0,0 +1,289 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.MongoBridge = void 0;
37
+ const anchordb_1 = require("anchordb");
38
+ /** Documents per streamed frame. Large enough to be efficient, small enough to stay under limits. */
39
+ const READ_BATCH = 200;
40
+ class BridgeFailure extends Error {
41
+ constructor(code, message) {
42
+ super(message);
43
+ this.code = code;
44
+ }
45
+ }
46
+ class MongoBridge {
47
+ constructor(options) {
48
+ /** One MongoDB connection per socket, closed with it. */
49
+ this.sessions = new Map();
50
+ this.enabled = options.enabled;
51
+ this.loadDriver = options.driver ?? loadMongoDriver;
52
+ this.onLog = options.onLog ?? (() => undefined);
53
+ }
54
+ /** Attach a socket that dialled `/bridge`. */
55
+ join(socket, room, validRoom) {
56
+ if (!this.enabled) {
57
+ socket.close(4403, "the MongoDB bridge is disabled; start the relay with --mongo-bridge");
58
+ return;
59
+ }
60
+ if (!room || !validRoom(room)) {
61
+ socket.close(4404, "a valid room is required to use the bridge");
62
+ return;
63
+ }
64
+ this.onLog("bridge: client joined");
65
+ socket.on("message", (raw) => {
66
+ void this.handle(socket, String(raw));
67
+ });
68
+ socket.on("close", () => {
69
+ void this.release(socket);
70
+ });
71
+ }
72
+ async release(socket) {
73
+ const session = this.sessions.get(socket);
74
+ if (!session)
75
+ return;
76
+ this.sessions.delete(socket);
77
+ // The credential dies with the socket — there is nowhere else it is held.
78
+ await session.connection.close().catch(() => undefined);
79
+ this.onLog("bridge: connection closed");
80
+ }
81
+ send(socket, response) {
82
+ socket.send(JSON.stringify(response));
83
+ }
84
+ async handle(socket, raw) {
85
+ let request;
86
+ try {
87
+ request = JSON.parse(raw);
88
+ }
89
+ catch {
90
+ return; // not a bridge frame
91
+ }
92
+ if (!request || typeof request.id !== "string" || typeof request.op !== "string")
93
+ return;
94
+ const base = { v: anchordb_1.BRIDGE_PROTOCOL_VERSION, id: request.id };
95
+ try {
96
+ switch (request.op) {
97
+ case "connect":
98
+ this.send(socket, { ...base, ok: true, result: await this.connect(socket, request) });
99
+ return;
100
+ case "read":
101
+ await this.read(socket, request, base);
102
+ return;
103
+ case "write":
104
+ this.send(socket, { ...base, ok: true, result: await this.write(socket, request) });
105
+ return;
106
+ case "disconnect":
107
+ await this.release(socket);
108
+ this.send(socket, { ...base, ok: true, result: { closed: true } });
109
+ return;
110
+ default:
111
+ throw new BridgeFailure("bad_request", `Unknown bridge operation "${String(request.op)}"`);
112
+ }
113
+ }
114
+ catch (err) {
115
+ const failure = err instanceof BridgeFailure
116
+ ? err
117
+ : new BridgeFailure("failed", err.message ?? "The bridge failed.");
118
+ this.onLog(`bridge: ${request.op} failed — ${failure.message}`);
119
+ this.send(socket, { ...base, ok: false, error: { code: failure.code, message: failure.message } });
120
+ }
121
+ }
122
+ async connect(socket, request) {
123
+ const uri = String(request.uri ?? "");
124
+ const database = String(request.database ?? "");
125
+ if (!uri || !database) {
126
+ throw new BridgeFailure("bad_request", "A connection string and a database name are required.");
127
+ }
128
+ let driver;
129
+ try {
130
+ driver = await this.loadDriver();
131
+ }
132
+ catch {
133
+ throw new BridgeFailure("driver_missing", "The mongodb driver is not installed. Run `npm install mongodb` where the relay runs.");
134
+ }
135
+ await this.release(socket); // one connection per socket; a second connect replaces the first
136
+ let connection;
137
+ try {
138
+ connection = await driver.connect(uri);
139
+ }
140
+ catch (err) {
141
+ // The URI is in scope here and must not reach the message.
142
+ throw new BridgeFailure("connect_failed", `Could not connect to ${(0, anchordb_1.redactMongoUri)(uri)} — ${err.message}`);
143
+ }
144
+ this.sessions.set(socket, { connection, database });
145
+ this.onLog(`bridge: connected to ${(0, anchordb_1.redactMongoUri)(uri)}`);
146
+ return {
147
+ database,
148
+ serverVersion: await connection.serverVersion(),
149
+ collections: await connection.listCollections(database),
150
+ };
151
+ }
152
+ session(socket) {
153
+ const session = this.sessions.get(socket);
154
+ if (!session)
155
+ throw new BridgeFailure("not_connected", "Connect to a MongoDB first.");
156
+ return session;
157
+ }
158
+ /** Stream a collection out as newline-delimited Extended JSON. */
159
+ async read(socket, request, base) {
160
+ const { connection, database } = this.session(socket);
161
+ const collection = String(request.collection ?? "");
162
+ if (!collection)
163
+ throw new BridgeFailure("bad_request", "A collection name is required.");
164
+ const driver = await this.loadDriver();
165
+ let sent = 0;
166
+ // Batched rather than one frame: a large collection would exceed any sane frame limit, and
167
+ // holding the whole thing as a single string on both sides at once is avoidable.
168
+ for await (const batch of connection.find(database, collection, READ_BATCH)) {
169
+ const chunk = batch.map((doc) => driver.stringifyEJSON(doc)).join("\n");
170
+ sent += batch.length;
171
+ this.send(socket, { ...base, ok: true, chunk, done: false, sent });
172
+ }
173
+ this.send(socket, {
174
+ ...base,
175
+ ok: true,
176
+ chunk: "",
177
+ done: true,
178
+ sent,
179
+ result: { collection, count: sent },
180
+ });
181
+ }
182
+ async write(socket, request) {
183
+ const { connection, database } = this.session(socket);
184
+ const collection = String(request.collection ?? "");
185
+ if (!collection)
186
+ throw new BridgeFailure("bad_request", "A collection name is required.");
187
+ const mode = (request.mode ?? "insert");
188
+ const driver = await this.loadDriver();
189
+ // Decoded with MongoDB's own Extended JSON codec, so an $oid becomes a real driver ObjectId
190
+ // rather than something that would land in the database as a string.
191
+ const documents = String(request.data ?? "")
192
+ .split("\n")
193
+ .map((line) => line.trim())
194
+ .filter(Boolean)
195
+ .map((line, index) => {
196
+ try {
197
+ return driver.parseEJSON(line);
198
+ }
199
+ catch (err) {
200
+ throw new BridgeFailure("bad_request", `Malformed Extended JSON on line ${index + 1}: ${err.message}`);
201
+ }
202
+ });
203
+ if (documents.length === 0)
204
+ return { collection, inserted: 0, updated: 0, skipped: 0 };
205
+ const result = await connection.write(database, collection, documents, mode);
206
+ this.onLog(`bridge: wrote ${documents.length} document(s) to ${collection}`);
207
+ return { collection, ...result };
208
+ }
209
+ }
210
+ exports.MongoBridge = MongoBridge;
211
+ /**
212
+ * Load the real driver.
213
+ *
214
+ * A lazy import so the relay stays usable — and installable — without `mongodb`. It is an optional
215
+ * dependency: most people running `npx anchor-relay` only want the inspector.
216
+ */
217
+ async function loadMongoDriver() {
218
+ // mongodb is an OPTIONAL dependency: the relay must install and run without it, and most
219
+ // people running the inspector never want the driver. MongoModule above types the slice used
220
+ // here, so absence is a runtime condition rather than a compile error.
221
+ // @ts-ignore -- resolved at runtime; may legitimately not be installed
222
+ const mongo = (await Promise.resolve().then(() => __importStar(require("mongodb"))));
223
+ const EJSON = mongo.EJSON ?? mongo.BSON?.EJSON;
224
+ if (!EJSON)
225
+ throw new Error("This mongodb driver does not expose Extended JSON.");
226
+ return {
227
+ stringifyEJSON: (value) => EJSON.stringify(value, { relaxed: false }),
228
+ parseEJSON: (text) => EJSON.parse(text, { relaxed: false }),
229
+ async connect(uri) {
230
+ const client = new mongo.MongoClient(uri, { serverSelectionTimeoutMS: 10_000 });
231
+ await client.connect();
232
+ return {
233
+ async serverVersion() {
234
+ const info = (await client.db("admin").command({ buildInfo: 1 }));
235
+ return info.version ?? "unknown";
236
+ },
237
+ async listCollections(database) {
238
+ const db = client.db(database);
239
+ const names = await db.listCollections({}, { nameOnly: true }).toArray();
240
+ const out = [];
241
+ for (const { name } of names) {
242
+ // Estimated: instant, where an exact count is a full scan on a large collection.
243
+ out.push({ name, count: await db.collection(name).estimatedDocumentCount() });
244
+ }
245
+ return out.sort((a, b) => a.name.localeCompare(b.name));
246
+ },
247
+ async *find(database, collection, batchSize) {
248
+ const cursor = client.db(database).collection(collection).find({}, { batchSize });
249
+ let batch = [];
250
+ for await (const doc of cursor) {
251
+ batch.push(doc);
252
+ if (batch.length >= batchSize) {
253
+ yield batch;
254
+ batch = [];
255
+ }
256
+ }
257
+ if (batch.length > 0)
258
+ yield batch;
259
+ },
260
+ async write(database, collection, documents, mode) {
261
+ const target = client.db(database).collection(collection);
262
+ if (mode === "replace")
263
+ await target.deleteMany({});
264
+ const summary = { inserted: 0, updated: 0, skipped: 0 };
265
+ const withId = documents;
266
+ if (mode === "insert") {
267
+ // $setOnInsert leaves an existing document untouched, which is "skip" without needing a
268
+ // read first or a thrown duplicate-key error to catch.
269
+ const result = await target.bulkWrite(withId.map((doc) => ({
270
+ updateOne: { filter: { _id: doc._id }, update: { $setOnInsert: doc }, upsert: true },
271
+ })), { ordered: false });
272
+ summary.inserted = result.upsertedCount ?? 0;
273
+ summary.skipped = (result.matchedCount ?? 0);
274
+ }
275
+ else {
276
+ const result = await target.bulkWrite(withId.map((doc) => ({
277
+ replaceOne: { filter: { _id: doc._id }, replacement: doc, upsert: true },
278
+ })), { ordered: false });
279
+ summary.inserted = result.upsertedCount ?? 0;
280
+ summary.updated = result.modifiedCount ?? 0;
281
+ }
282
+ return summary;
283
+ },
284
+ close: () => client.close(),
285
+ };
286
+ },
287
+ };
288
+ }
289
+ //# sourceMappingURL=mongo-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongo-bridge.js","sourceRoot":"","sources":["../../src/mongo-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }