@seedprotocol/gateway-hyper 0.7.0 → 0.7.2-next.593.gd5bd4ea

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/README.md CHANGED
@@ -21,10 +21,10 @@ Requires Node 20+ and Holepunch native addons. Prefer Node over Bun.
21
21
 
22
22
  ```bash
23
23
  # Operator
24
- seed gateway tunnel serve --upstream http://127.0.0.1:80 --key-file ./.seed/gateway-tunnel/operator.key.json
24
+ seed-gateway serve --upstream http://127.0.0.1:80 --key-file ./.seed/gateway-tunnel/operator.key.json
25
25
 
26
26
  # Client sidecar (Path A)
27
- seed gateway tunnel connect <z32-key> --port 1984
27
+ seed-gateway connect <z32-key> --port 1984
28
28
  ```
29
29
 
30
30
  ## Library
package/dist/bin.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ import { i as e, s as t } from "./src-CnXam5V8.js";
3
+ import n from "node:path";
4
+ import r from "node:process";
5
+ import { parseArgs as i } from "node:util";
6
+ //#region src/bin.ts
7
+ var a = "Usage:\n seed-gateway serve [--upstream http://127.0.0.1:80] [--key-file <path>]\n Operator: accept Hyper connections and proxy them to a local upstream (Traefik).\n Default --key-file: ./.seed/gateway-tunnel/operator.key.json (created on first run).\n\n seed-gateway connect <key> [--host 127.0.0.1] [--port 1984]\n Client: dial an operator key and expose a localhost HTTP sidecar.";
8
+ function o(e) {
9
+ console.error(`[Seed Protocol] ${e}`), console.error(a), r.exit(1);
10
+ }
11
+ function s() {
12
+ return new Promise((e) => {
13
+ let t = () => {
14
+ r.off("SIGINT", t), r.off("SIGTERM", t), e();
15
+ };
16
+ r.on("SIGINT", t), r.on("SIGTERM", t);
17
+ });
18
+ }
19
+ async function c(r) {
20
+ let [c, ...l] = r;
21
+ if (!c || c === "--help" || c === "-h" || c === "help") {
22
+ console.log(a);
23
+ return;
24
+ }
25
+ let { values: u, positionals: d } = i({
26
+ args: l,
27
+ allowPositionals: !0,
28
+ options: {
29
+ upstream: {
30
+ type: "string",
31
+ default: "http://127.0.0.1:80"
32
+ },
33
+ "key-file": {
34
+ type: "string",
35
+ default: n.join(".seed", "gateway-tunnel", "operator.key.json")
36
+ },
37
+ host: {
38
+ type: "string",
39
+ default: "127.0.0.1"
40
+ },
41
+ port: {
42
+ type: "string",
43
+ default: "1984"
44
+ }
45
+ }
46
+ });
47
+ if (c === "serve") {
48
+ let e = u.upstream.trim(), r = n.resolve(u["key-file"]);
49
+ console.log(`[Seed Protocol] Gateway tunnel upstream: ${e}`), console.log(`[Seed Protocol] Operator key file: ${r}`);
50
+ let i = await t({
51
+ upstream: e,
52
+ keyFile: r
53
+ });
54
+ console.log(`[Seed Protocol] Operator key (z32): ${i.key}`), console.log("[Seed Protocol] Share this key with SDK users (gatewayHyperKey)."), console.log("[Seed Protocol] Press Ctrl+C to stop."), await s(), await i.close(), console.log("[Seed Protocol] Gateway tunnel stopped.");
55
+ } else if (c === "connect") {
56
+ let t = d[0];
57
+ t || o("seed-gateway connect requires an operator public key (z32 or hex)"), console.log(`[Seed Protocol] Connecting to operator ${t}`);
58
+ let n = await e({
59
+ key: t,
60
+ host: u.host,
61
+ port: parseInt(u.port, 10) || 1984
62
+ });
63
+ console.log(`[Seed Protocol] Local sidecar: ${n.baseUrl}`), console.log("[Seed Protocol] Point SDK transport=hyper or hybrid at this URL (default sidecar port 1984)."), console.log("[Seed Protocol] Press Ctrl+C to stop."), await s(), await n.close(), console.log("[Seed Protocol] Gateway sidecar stopped.");
64
+ } else o(`Unknown command: ${c}`);
65
+ }
66
+ c(r.argv.slice(2)).catch((e) => {
67
+ console.error("[Seed Protocol]", e instanceof Error ? e.message : e), r.exit(1);
68
+ });
69
+ //#endregion
70
+
71
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","names":["connectTunnel","serveTunnel","path","process","USAGE","fail","message","waitForSignal","onStop","resolve","main","command","rest","argv","parseArgs","upstream","values","keyFile","session","key","positionals","err"],"sources":["../src/bin.ts"],"sourcesContent":["/**\n * `seed-gateway serve|connect` — HTTP tunnel to Seed gateway + upload API infrastructure over HyperDHT.\n * Run under Node (Holepunch natives may crash under Bun).\n */\nimport path from 'node:path'\nimport process from 'node:process'\nimport { parseArgs } from 'node:util'\nimport { connectTunnel, serveTunnel } from './index'\n\nconst USAGE = `Usage:\n seed-gateway serve [--upstream http://127.0.0.1:80] [--key-file <path>]\n Operator: accept Hyper connections and proxy them to a local upstream (Traefik).\n Default --key-file: ./.seed/gateway-tunnel/operator.key.json (created on first run).\n\n seed-gateway connect <key> [--host 127.0.0.1] [--port 1984]\n Client: dial an operator key and expose a localhost HTTP sidecar.`\n\nfunction fail(message: string): never {\n console.error(`[Seed Protocol] ${message}`)\n console.error(USAGE)\n process.exit(1)\n}\n\nfunction waitForSignal(): Promise<void> {\n return new Promise((resolve) => {\n const onStop = () => {\n process.off('SIGINT', onStop)\n process.off('SIGTERM', onStop)\n resolve()\n }\n process.on('SIGINT', onStop)\n process.on('SIGTERM', onStop)\n })\n}\n\nasync function main(argv: string[]): Promise<void> {\n const [command, ...rest] = argv\n if (!command || command === '--help' || command === '-h' || command === 'help') {\n console.log(USAGE)\n return\n }\n\n const { values, positionals } = parseArgs({\n args: rest,\n allowPositionals: true,\n options: {\n upstream: { type: 'string', default: 'http://127.0.0.1:80' },\n 'key-file': {\n type: 'string',\n default: path.join('.seed', 'gateway-tunnel', 'operator.key.json'),\n },\n host: { type: 'string', default: '127.0.0.1' },\n port: { type: 'string', default: '1984' },\n },\n })\n\n if (command === 'serve') {\n const upstream = values.upstream.trim()\n const keyFile = path.resolve(values['key-file'])\n console.log(`[Seed Protocol] Gateway tunnel upstream: ${upstream}`)\n console.log(`[Seed Protocol] Operator key file: ${keyFile}`)\n\n const session = await serveTunnel({ upstream, keyFile })\n console.log(`[Seed Protocol] Operator key (z32): ${session.key}`)\n console.log('[Seed Protocol] Share this key with SDK users (gatewayHyperKey).')\n console.log('[Seed Protocol] Press Ctrl+C to stop.')\n await waitForSignal()\n await session.close()\n console.log('[Seed Protocol] Gateway tunnel stopped.')\n return\n }\n\n if (command === 'connect') {\n const key = positionals[0]\n if (!key) fail('seed-gateway connect requires an operator public key (z32 or hex)')\n\n console.log(`[Seed Protocol] Connecting to operator ${key}`)\n const session = await connectTunnel({\n key,\n host: values.host,\n port: parseInt(values.port, 10) || 1984,\n })\n console.log(`[Seed Protocol] Local sidecar: ${session.baseUrl}`)\n console.log(\n '[Seed Protocol] Point SDK transport=hyper or hybrid at this URL (default sidecar port 1984).',\n )\n console.log('[Seed Protocol] Press Ctrl+C to stop.')\n await waitForSignal()\n await session.close()\n console.log('[Seed Protocol] Gateway sidecar stopped.')\n return\n }\n\n fail(`Unknown command: ${command}`)\n}\n\nmain(process.argv.slice(2)).catch((err) => {\n console.error('[Seed Protocol]', err instanceof Error ? err.message : err)\n process.exit(1)\n})\n"],"mappings":";;;;;;AASA,IAAMI,IAAQ;AAQd,SAASC,EAAK,GAAwB;CAGpC,AAFA,QAAQ,MAAM,mBAAmBC,GAAS,GAC1C,QAAQ,MAAMF,CAAK,GACnBD,EAAQ,KAAK,CAAC;AAChB;AAEA,SAASI,IAA+B;CACtC,OAAO,IAAI,SAAS,MAAY;EAC9B,IAAMC,UAAe;GAGnB,AAFAL,EAAQ,IAAI,UAAUK,CAAM,GAC5BL,EAAQ,IAAI,WAAWK,CAAM,GAC7BC,EAAQ;EACV;EAEA,AADAN,EAAQ,GAAG,UAAUK,CAAM,GAC3BL,EAAQ,GAAG,WAAWK,CAAM;CAC9B,CAAC;AACH;AAEA,eAAeE,EAAK,GAA+B;CACjD,IAAM,CAACC,GAAS,GAAGC,KAAQC;CAC3B,IAAI,CAACF,KAAWA,MAAY,YAAYA,MAAY,QAAQA,MAAY,QAAQ;EAC9E,QAAQ,IAAIP,CAAK;EACjB;CACF;CAEA,IAAM,EAAE,WAAQ,mBAAgBU,EAAU;EACxC,MAAMF;EACN,kBAAkB;EAClB,SAAS;GACP,UAAU;IAAE,MAAM;IAAU,SAAS;GAAsB;GAC3D,YAAY;IACV,MAAM;IACN,SAASV,EAAK,KAAK,SAAS,kBAAkB,mBAAmB;GACnE;GACA,MAAM;IAAE,MAAM;IAAU,SAAS;GAAY;GAC7C,MAAM;IAAE,MAAM;IAAU,SAAS;GAAO;EAC1C;CACF,CAAC;CAED,IAAIS,MAAY,SAAS;EACvB,IAAMI,IAAWC,EAAO,SAAS,KAAK,GAChCC,IAAUf,EAAK,QAAQc,EAAO,WAAW;EAE/C,AADA,QAAQ,IAAI,4CAA4CD,GAAU,GAClE,QAAQ,IAAI,sCAAsCE,GAAS;EAE3D,IAAMC,IAAU,MAAMjB,EAAY;GAAE;GAAU;EAAQ,CAAC;EAMvD,AALA,QAAQ,IAAI,uCAAuCiB,EAAQ,KAAK,GAChE,QAAQ,IAAI,kEAAkE,GAC9E,QAAQ,IAAI,uCAAuC,GACnD,MAAMX,EAAc,GACpB,MAAMW,EAAQ,MAAM,GACpB,QAAQ,IAAI,yCAAyC;CAEvD,OAEA,IAAIP,MAAY,WAAW;EACzB,IAAMQ,IAAMC,EAAY;EAGxB,AAFKD,KAAKd,EAAK,mEAAmE,GAElF,QAAQ,IAAI,0CAA0Cc,GAAK;EAC3D,IAAMD,IAAU,MAAMlB,EAAc;GAClC;GACA,MAAMgB,EAAO;GACb,MAAM,SAASA,EAAO,MAAM,EAAE,KAAK;EACrC,CAAC;EAQD,AAPA,QAAQ,IAAI,kCAAkCE,EAAQ,SAAS,GAC/D,QAAQ,IACN,8FACF,GACA,QAAQ,IAAI,uCAAuC,GACnD,MAAMX,EAAc,GACpB,MAAMW,EAAQ,MAAM,GACpB,QAAQ,IAAI,0CAA0C;CAExD,OAEA,EAAK,oBAAoBP,GAAS;AACpC;AAEAD,EAAKP,EAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,MAAQ;CAEzC,AADA,QAAQ,MAAM,mBAAmBkB,aAAe,QAAQA,EAAI,UAAUA,CAAG,GACzElB,EAAQ,KAAK,CAAC;AAChB,CAAC"}
package/dist/index.js CHANGED
@@ -1,424 +1 @@
1
- import e from "node:fs";
2
- import t from "node:path";
3
- import n from "hyperdht";
4
- import r from "hypercore-id-encoding";
5
- import i from "node:http";
6
- import { URL as a } from "node:url";
7
- //#region src/keys.ts
8
- function o(e) {
9
- return e.toString("hex");
10
- }
11
- function s(e) {
12
- return Buffer.from(e, "hex");
13
- }
14
- function c(e) {
15
- return r.encode(e);
16
- }
17
- function l(e) {
18
- let t = e.trim();
19
- if (!t) throw Error("Gateway Hyper key is empty");
20
- try {
21
- return Buffer.from(r.decode(t));
22
- } catch {
23
- if (/^[a-fA-F0-9]{64}$/.test(t)) return s(t);
24
- throw Error(`Invalid Gateway Hyper key (expected z32 or 64-char hex): ${t.slice(0, 12)}…`);
25
- }
26
- }
27
- function u(r) {
28
- let i = t.resolve(r);
29
- if (e.existsSync(i)) {
30
- let t = e.readFileSync(i, "utf8"), n = JSON.parse(t);
31
- if (!n.publicKey || !n.secretKey) throw Error(`Invalid key file at ${i}: missing publicKey or secretKey`);
32
- let r = s(n.publicKey);
33
- return {
34
- publicKey: r,
35
- secretKey: s(n.secretKey),
36
- z32: c(r)
37
- };
38
- }
39
- let a = t.dirname(i);
40
- e.mkdirSync(a, { recursive: !0 });
41
- let l = n.keyPair(), u = {
42
- publicKey: o(l.publicKey),
43
- secretKey: o(l.secretKey),
44
- encoding: "hex"
45
- };
46
- return e.writeFileSync(i, `${JSON.stringify(u, null, 2)}\n`, { mode: 384 }), {
47
- publicKey: l.publicKey,
48
- secretKey: l.secretKey,
49
- z32: c(l.publicKey)
50
- };
51
- }
52
- function d() {
53
- let e = n.keyPair();
54
- return {
55
- publicKey: e.publicKey,
56
- secretKey: e.secretKey,
57
- z32: c(e.publicKey)
58
- };
59
- }
60
- //#endregion
61
- //#region src/tunnel/protocol.ts
62
- var f = 67108864, p = class {
63
- stream;
64
- buffer = Buffer.alloc(0);
65
- waiters = [];
66
- ended = !1;
67
- onData;
68
- onError;
69
- onEnd;
70
- constructor(e) {
71
- this.stream = e, this.onData = (e) => {
72
- this.buffer = Buffer.concat([this.buffer, e]), this.drain();
73
- }, this.onError = (e) => {
74
- let t = this.waiters.splice(0);
75
- for (let n of t) n.reject(e);
76
- }, this.onEnd = () => {
77
- if (this.ended = !0, this.drain(), this.waiters.length > 0) {
78
- let e = this.waiters.splice(0);
79
- for (let t of e) t.reject(/* @__PURE__ */ Error(`Unexpected end of stream (expected ${t.length} bytes, got ${this.buffer.length})`));
80
- }
81
- }, e.on("data", this.onData), e.on("error", this.onError), e.on("end", this.onEnd);
82
- }
83
- readExact(e) {
84
- return new Promise((t, n) => {
85
- if (e === 0) {
86
- t(Buffer.alloc(0));
87
- return;
88
- }
89
- if (this.waiters.push({
90
- length: e,
91
- resolve: t,
92
- reject: n
93
- }), this.drain(), this.ended && this.waiters.length > 0) {
94
- let e = this.waiters.splice(0);
95
- for (let t of e) t.reject(/* @__PURE__ */ Error(`Unexpected end of stream (expected ${t.length} bytes, got ${this.buffer.length})`));
96
- }
97
- });
98
- }
99
- drain() {
100
- for (; this.waiters.length > 0;) {
101
- let e = this.waiters[0];
102
- if (!e || this.buffer.length < e.length) break;
103
- this.waiters.shift();
104
- let t = this.buffer.subarray(0, e.length);
105
- this.buffer = this.buffer.subarray(e.length), e.resolve(t);
106
- }
107
- }
108
- }, m = /* @__PURE__ */ new WeakMap();
109
- function h(e) {
110
- let t = m.get(e);
111
- return t || (t = new p(e), m.set(e, t)), t;
112
- }
113
- function g(e, t) {
114
- return h(e).readExact(t);
115
- }
116
- function _(e, t) {
117
- return new Promise((n, r) => {
118
- try {
119
- if (e.write(t)) {
120
- n();
121
- return;
122
- }
123
- let i = () => {
124
- e.off("error", a), n();
125
- }, a = (t) => {
126
- e.off("drain", i), r(t);
127
- };
128
- e.once("drain", i), e.once("error", a);
129
- } catch (e) {
130
- r(e instanceof Error ? e : Error(String(e)));
131
- }
132
- });
133
- }
134
- async function v(e, t) {
135
- if (t.length > 67108864) throw Error(`Frame too large: ${t.length} bytes (max ${f})`);
136
- let n = Buffer.alloc(4);
137
- n.writeUInt32BE(t.length, 0), await _(e, Buffer.concat([n, t]));
138
- }
139
- async function y(e) {
140
- let t = (await g(e, 4)).readUInt32BE(0);
141
- if (t === 0) return Buffer.alloc(0);
142
- if (t > 67108864) throw Error(`Frame too large: ${t} bytes (max ${f})`);
143
- return g(e, t);
144
- }
145
- async function b(e, t, n) {
146
- await v(e, Buffer.from(JSON.stringify(t), "utf8")), await v(e, n);
147
- }
148
- async function x(e) {
149
- let t = await y(e), n = JSON.parse(t.toString("utf8"));
150
- if (!n.method || !n.path) throw Error("Invalid tunnel request meta: missing method or path");
151
- return n.headers = n.headers ?? {}, {
152
- meta: n,
153
- body: await y(e)
154
- };
155
- }
156
- async function S(e, t, n) {
157
- await v(e, Buffer.from(JSON.stringify(t), "utf8")), await v(e, n);
158
- }
159
- async function C(e) {
160
- let t = await y(e), n = JSON.parse(t.toString("utf8"));
161
- if (typeof n.status != "number") throw Error("Invalid tunnel response meta: missing status");
162
- return n.headers = n.headers ?? {}, {
163
- meta: n,
164
- body: await y(e)
165
- };
166
- }
167
- function w(e) {
168
- let t = {};
169
- for (let [n, r] of Object.entries(e)) r != null && (t[n] = Array.isArray(r) ? r.join(", ") : r);
170
- return t;
171
- }
172
- function T(e) {
173
- let t = /* @__PURE__ */ new Set([
174
- "connection",
175
- "keep-alive",
176
- "transfer-encoding",
177
- "upgrade"
178
- ]), n = {};
179
- for (let [r, i] of Object.entries(e)) t.has(r.toLowerCase()) || i != null && (n[r] = Array.isArray(i) ? i.join(", ") : i);
180
- return n;
181
- }
182
- //#endregion
183
- //#region src/tunnel/proxy.ts
184
- async function E(e, t, n) {
185
- let r = e.replace(/\/$/, ""), o = new a(t.path, `${r}/`);
186
- return new Promise((e, r) => {
187
- let a = i.request(o, {
188
- method: t.method,
189
- headers: t.headers
190
- }, (t) => {
191
- let n = [];
192
- t.on("data", (e) => n.push(e)), t.on("end", () => {
193
- e({
194
- status: t.statusCode ?? 502,
195
- headers: T(t.headers),
196
- body: Buffer.concat(n)
197
- });
198
- }), t.on("error", r);
199
- });
200
- a.on("error", r), n.length > 0 && a.write(n), a.end();
201
- });
202
- }
203
- //#endregion
204
- //#region src/tunnel/serve.ts
205
- function D(e, t) {
206
- let n = x(e);
207
- (async () => {
208
- try {
209
- for (;;) {
210
- let { meta: r, body: i } = await n, a = await E(t, r, i);
211
- await S(e, {
212
- status: a.status,
213
- headers: a.headers
214
- }, a.body), n = x(e);
215
- }
216
- } catch {
217
- e.destroy();
218
- }
219
- })();
220
- }
221
- async function O(e) {
222
- let t = e.upstream.replace(/\/$/, ""), r = u(e.keyFile ?? ".seed/gateway-tunnel/operator.key.json"), i = new n(), a = i.createServer((e) => {
223
- D(e, t);
224
- });
225
- return await a.listen(r), {
226
- key: r.z32,
227
- upstream: t,
228
- close: async () => {
229
- await a.close(), await i.destroy();
230
- }
231
- };
232
- }
233
- //#endregion
234
- //#region src/tunnel/session.ts
235
- async function k(e) {
236
- let t = l(e.key), r = d(), i = new n(), a = null, o = null, s = async () => a && !a.destroyed ? a : o || (o = new Promise((e, n) => {
237
- let s = i.connect(t, { keyPair: {
238
- publicKey: r.publicKey,
239
- secretKey: r.secretKey
240
- } }), c = () => {
241
- a = s, o = null, e(s);
242
- };
243
- s.once("open", c), s.once("connect", c), s.once("error", (e) => {
244
- o = null, n(e);
245
- });
246
- }), o), c = Promise.resolve(), u = async (e) => {
247
- let t = c.then(() => s()).then(e);
248
- return c = t.catch(() => {}), t;
249
- };
250
- return {
251
- key: e.key,
252
- runOnTunnel: u,
253
- forwardHttp: async (e, t) => u(async (n) => (await b(n, e, t), C(n))),
254
- close: async () => {
255
- a && !a.destroyed && a.destroy(), await i.destroy();
256
- }
257
- };
258
- }
259
- //#endregion
260
- //#region src/tunnel/connect.ts
261
- async function A(e) {
262
- let t = [];
263
- for await (let n of e) t.push(Buffer.isBuffer(n) ? n : Buffer.from(n));
264
- return Buffer.concat(t);
265
- }
266
- function j(e) {
267
- return i.createServer((t, n) => {
268
- (async () => {
269
- try {
270
- let r = await A(t), i = t.url ?? "/", { meta: a, body: o } = await e({
271
- method: t.method ?? "GET",
272
- path: i,
273
- headers: w(t.headers)
274
- }, r);
275
- n.writeHead(a.status, a.headers), n.end(o);
276
- } catch (e) {
277
- let t = e instanceof Error ? e.message : String(e);
278
- n.headersSent || n.writeHead(502, { "Content-Type": "text/plain; charset=utf-8" }), n.end(`Gateway Hyper tunnel error: ${t}`);
279
- }
280
- })();
281
- });
282
- }
283
- async function M(e) {
284
- let t = e.host ?? "127.0.0.1", n = e.port ?? 1984, r = await k({
285
- key: e.key,
286
- storePath: e.storePath
287
- }), i = j((e, t) => r.forwardHttp(e, t));
288
- await new Promise((e, r) => {
289
- i.once("error", r), i.listen(n, t, () => e());
290
- });
291
- let a = i.address(), o = a && typeof a == "object" ? a.port : n, s = `http://${t}:${o}`;
292
- return {
293
- key: e.key,
294
- host: t,
295
- port: o,
296
- baseUrl: s,
297
- close: async () => {
298
- await new Promise((e) => i.close(() => e())), await r.close();
299
- }
300
- };
301
- }
302
- function N(e, t = "") {
303
- let n = e.replace(/\/$/, "");
304
- return t ? t.startsWith("/") ? `${n}${t}` : `${n}/${t}` : n;
305
- }
306
- //#endregion
307
- //#region src/tunnel/mountPath.ts
308
- function P(e, t) {
309
- let n = e || "/", r = n.indexOf("?"), i = r === -1 ? n : n.slice(0, r), a = r === -1 ? "" : n.slice(r), o = (t || "").replace(/\/$/, "");
310
- if (!o || o === "/") return `${i.startsWith("/") ? i : `/${i}`}${a}` || "/";
311
- if (i === o || i.startsWith(`${o}/`)) {
312
- let e = i.slice(o.length);
313
- return `${e.startsWith("/") ? e : e ? `/${e}` : "/"}${a}`;
314
- }
315
- return `${i.startsWith("/") ? i : `/${i}`}${a}`;
316
- }
317
- //#endregion
318
- //#region src/tunnel/forward.ts
319
- async function F(e) {
320
- let t = [];
321
- for await (let n of e) t.push(Buffer.isBuffer(n) ? n : Buffer.from(n));
322
- return Buffer.concat(t);
323
- }
324
- async function I(e, t, n, r) {
325
- try {
326
- let i = await F(t), a = P(t.url ?? "/", r), o = {
327
- method: t.method ?? "GET",
328
- path: a,
329
- headers: w(t.headers)
330
- }, { meta: s, body: c } = await e.forwardHttp(o, i);
331
- L(n, s, c);
332
- } catch (e) {
333
- let t = e instanceof Error ? e.message : String(e);
334
- n.headersSent || n.writeHead(502, { "Content-Type": "text/plain; charset=utf-8" }), n.end(`Gateway Hyper tunnel error: ${t}`);
335
- }
336
- }
337
- function L(e, t, n) {
338
- e.writeHead(t.status, T(t.headers)), e.end(n);
339
- }
340
- async function R(e, t, n) {
341
- try {
342
- let r = new URL(t.url), i = P(`${r.pathname}${r.search}`, n), a = Buffer.from(await t.arrayBuffer()), o = {};
343
- t.headers.forEach((e, t) => {
344
- o[t] = e;
345
- });
346
- let s = {
347
- method: t.method || "GET",
348
- path: i,
349
- headers: w(o)
350
- }, { meta: c, body: l } = await e.forwardHttp(s, a);
351
- return new Response(l, {
352
- status: c.status,
353
- headers: T(c.headers)
354
- });
355
- } catch (e) {
356
- let t = e instanceof Error ? e.message : String(e);
357
- return new Response(`Gateway Hyper tunnel error: ${t}`, {
358
- status: 502,
359
- headers: { "Content-Type": "text/plain; charset=utf-8" }
360
- });
361
- }
362
- }
363
- //#endregion
364
- //#region src/tunnel/proxyApp.ts
365
- function z(e) {
366
- let t = e.key?.trim() || (typeof process < "u" ? process.env.SEED_GATEWAY_HYPER_KEY?.trim() : "") || "";
367
- if (!t) throw Error("createGatewayProxy requires options.key or SEED_GATEWAY_HYPER_KEY environment variable");
368
- return t;
369
- }
370
- function B(e = {}) {
371
- let t = e.mountPath?.trim() || "/api/seed-gateway", n = z(e), r = null, i = null, a = async () => {
372
- if (r) return r;
373
- if (i) return i;
374
- i = k({
375
- key: n,
376
- storePath: e.storePath
377
- }).then((e) => (r = e, i = null, e));
378
- try {
379
- return await i;
380
- } catch (e) {
381
- throw i = null, e;
382
- }
383
- }, o = {
384
- mountPath: t,
385
- start: async () => {
386
- await a();
387
- },
388
- close: async () => {
389
- if (i) try {
390
- await i;
391
- } catch {}
392
- r &&= (await r.close(), null);
393
- },
394
- handleNode: (e, n) => {
395
- (async () => {
396
- try {
397
- await I(await a(), e, n, t);
398
- } catch (e) {
399
- let t = e instanceof Error ? e.message : String(e);
400
- n.headersSent || n.writeHead(502, { "Content-Type": "text/plain; charset=utf-8" }), n.end(`Gateway Hyper tunnel error: ${t}`);
401
- }
402
- })();
403
- },
404
- handleFetch: async (e) => {
405
- try {
406
- return await R(await a(), e, t);
407
- } catch (e) {
408
- let t = e instanceof Error ? e.message : String(e);
409
- return new Response(`Gateway Hyper tunnel error: ${t}`, {
410
- status: 502,
411
- headers: { "Content-Type": "text/plain; charset=utf-8" }
412
- });
413
- }
414
- }
415
- };
416
- return e.eager && o.start().catch(() => {}), o;
417
- }
418
- //#endregion
419
- //#region src/constants.ts
420
- var V = "";
421
- //#endregion
422
- export { V as DEFAULT_SEED_GATEWAY_HYPER_KEY, f as MAX_FRAME_BYTES, M as connectTunnel, B as createGatewayProxy, k as createTunnelSession, l as decodePublicKey, c as encodePublicKeyZ32, T as filterResponseHeaders, w as flattenRequestHeaders, u as loadOrCreateOperatorKeypair, N as localGatewayUrl, y as readFrame, x as readTunnelRequest, C as readTunnelResponse, O as serveTunnel, P as stripMountPath, v as writeFrame, b as writeTunnelRequest, S as writeTunnelResponse };
423
-
424
- //# sourceMappingURL=index.js.map
1
+ export { t as DEFAULT_SEED_GATEWAY_HYPER_KEY, c as MAX_FRAME_BYTES, i as connectTunnel, n as createGatewayProxy, o as createTunnelSession, _ as decodePublicKey, v as encodePublicKeyZ32, l as filterResponseHeaders, u as flattenRequestHeaders, y as loadOrCreateOperatorKeypair, a as localGatewayUrl, d as readFrame, f as readTunnelRequest, p as readTunnelResponse, s as serveTunnel, r as stripMountPath, m as writeFrame, h as writeTunnelRequest, g as writeTunnelResponse } from "./src-CnXam5V8.js";
@@ -0,0 +1,421 @@
1
+ import e from "node:fs";
2
+ import t from "node:path";
3
+ import n from "hyperdht";
4
+ import r from "hypercore-id-encoding";
5
+ import i from "node:http";
6
+ import { URL as a } from "node:url";
7
+ //#region src/keys.ts
8
+ function o(e) {
9
+ return e.toString("hex");
10
+ }
11
+ function s(e) {
12
+ return Buffer.from(e, "hex");
13
+ }
14
+ function c(e) {
15
+ return r.encode(e);
16
+ }
17
+ function l(e) {
18
+ let t = e.trim();
19
+ if (!t) throw Error("Gateway Hyper key is empty");
20
+ try {
21
+ return Buffer.from(r.decode(t));
22
+ } catch {
23
+ if (/^[a-fA-F0-9]{64}$/.test(t)) return s(t);
24
+ throw Error(`Invalid Gateway Hyper key (expected z32 or 64-char hex): ${t.slice(0, 12)}…`);
25
+ }
26
+ }
27
+ function u(r) {
28
+ let i = t.resolve(r);
29
+ if (e.existsSync(i)) {
30
+ let t = e.readFileSync(i, "utf8"), n = JSON.parse(t);
31
+ if (!n.publicKey || !n.secretKey) throw Error(`Invalid key file at ${i}: missing publicKey or secretKey`);
32
+ let r = s(n.publicKey);
33
+ return {
34
+ publicKey: r,
35
+ secretKey: s(n.secretKey),
36
+ z32: c(r)
37
+ };
38
+ }
39
+ let a = t.dirname(i);
40
+ e.mkdirSync(a, { recursive: !0 });
41
+ let l = n.keyPair(), u = {
42
+ publicKey: o(l.publicKey),
43
+ secretKey: o(l.secretKey),
44
+ encoding: "hex"
45
+ };
46
+ return e.writeFileSync(i, `${JSON.stringify(u, null, 2)}\n`, { mode: 384 }), {
47
+ publicKey: l.publicKey,
48
+ secretKey: l.secretKey,
49
+ z32: c(l.publicKey)
50
+ };
51
+ }
52
+ function d() {
53
+ let e = n.keyPair();
54
+ return {
55
+ publicKey: e.publicKey,
56
+ secretKey: e.secretKey,
57
+ z32: c(e.publicKey)
58
+ };
59
+ }
60
+ //#endregion
61
+ //#region src/tunnel/protocol.ts
62
+ var f = 67108864, p = class {
63
+ stream;
64
+ buffer = Buffer.alloc(0);
65
+ waiters = [];
66
+ ended = !1;
67
+ onData;
68
+ onError;
69
+ onEnd;
70
+ constructor(e) {
71
+ this.stream = e, this.onData = (e) => {
72
+ this.buffer = Buffer.concat([this.buffer, e]), this.drain();
73
+ }, this.onError = (e) => {
74
+ let t = this.waiters.splice(0);
75
+ for (let n of t) n.reject(e);
76
+ }, this.onEnd = () => {
77
+ if (this.ended = !0, this.drain(), this.waiters.length > 0) {
78
+ let e = this.waiters.splice(0);
79
+ for (let t of e) t.reject(/* @__PURE__ */ Error(`Unexpected end of stream (expected ${t.length} bytes, got ${this.buffer.length})`));
80
+ }
81
+ }, e.on("data", this.onData), e.on("error", this.onError), e.on("end", this.onEnd);
82
+ }
83
+ readExact(e) {
84
+ return new Promise((t, n) => {
85
+ if (e === 0) t(Buffer.alloc(0));
86
+ else if (this.waiters.push({
87
+ length: e,
88
+ resolve: t,
89
+ reject: n
90
+ }), this.drain(), this.ended && this.waiters.length > 0) {
91
+ let e = this.waiters.splice(0);
92
+ for (let t of e) t.reject(/* @__PURE__ */ Error(`Unexpected end of stream (expected ${t.length} bytes, got ${this.buffer.length})`));
93
+ }
94
+ });
95
+ }
96
+ drain() {
97
+ for (; this.waiters.length > 0;) {
98
+ let e = this.waiters[0];
99
+ if (!e || this.buffer.length < e.length) break;
100
+ this.waiters.shift();
101
+ let t = this.buffer.subarray(0, e.length);
102
+ this.buffer = this.buffer.subarray(e.length), e.resolve(t);
103
+ }
104
+ }
105
+ }, m = /* @__PURE__ */ new WeakMap();
106
+ function h(e) {
107
+ let t = m.get(e);
108
+ return t || (t = new p(e), m.set(e, t)), t;
109
+ }
110
+ function g(e, t) {
111
+ return h(e).readExact(t);
112
+ }
113
+ function _(e, t) {
114
+ return new Promise((n, r) => {
115
+ try {
116
+ if (e.write(t)) {
117
+ n();
118
+ return;
119
+ }
120
+ let i = () => {
121
+ e.off("error", a), n();
122
+ }, a = (t) => {
123
+ e.off("drain", i), r(t);
124
+ };
125
+ e.once("drain", i), e.once("error", a);
126
+ } catch (e) {
127
+ r(e instanceof Error ? e : Error(String(e)));
128
+ }
129
+ });
130
+ }
131
+ async function v(e, t) {
132
+ if (t.length > 67108864) throw Error(`Frame too large: ${t.length} bytes (max ${f})`);
133
+ let n = Buffer.alloc(4);
134
+ n.writeUInt32BE(t.length, 0), await _(e, Buffer.concat([n, t]));
135
+ }
136
+ async function y(e) {
137
+ let t = (await g(e, 4)).readUInt32BE(0);
138
+ if (t === 0) return Buffer.alloc(0);
139
+ if (t > 67108864) throw Error(`Frame too large: ${t} bytes (max ${f})`);
140
+ return g(e, t);
141
+ }
142
+ async function b(e, t, n) {
143
+ await v(e, Buffer.from(JSON.stringify(t), "utf8")), await v(e, n);
144
+ }
145
+ async function x(e) {
146
+ let t = await y(e), n = JSON.parse(t.toString("utf8"));
147
+ if (!n.method || !n.path) throw Error("Invalid tunnel request meta: missing method or path");
148
+ return n.headers = n.headers ?? {}, {
149
+ meta: n,
150
+ body: await y(e)
151
+ };
152
+ }
153
+ async function S(e, t, n) {
154
+ await v(e, Buffer.from(JSON.stringify(t), "utf8")), await v(e, n);
155
+ }
156
+ async function C(e) {
157
+ let t = await y(e), n = JSON.parse(t.toString("utf8"));
158
+ if (typeof n.status != "number") throw Error("Invalid tunnel response meta: missing status");
159
+ return n.headers = n.headers ?? {}, {
160
+ meta: n,
161
+ body: await y(e)
162
+ };
163
+ }
164
+ function w(e) {
165
+ let t = {};
166
+ for (let [n, r] of Object.entries(e)) r != null && (t[n] = Array.isArray(r) ? r.join(", ") : r);
167
+ return t;
168
+ }
169
+ function T(e) {
170
+ let t = /* @__PURE__ */ new Set([
171
+ "connection",
172
+ "keep-alive",
173
+ "transfer-encoding",
174
+ "upgrade"
175
+ ]), n = {};
176
+ for (let [r, i] of Object.entries(e)) t.has(r.toLowerCase()) || i != null && (n[r] = Array.isArray(i) ? i.join(", ") : i);
177
+ return n;
178
+ }
179
+ //#endregion
180
+ //#region src/tunnel/proxy.ts
181
+ async function E(e, t, n) {
182
+ let r = e.replace(/\/$/, ""), o = new a(t.path, `${r}/`);
183
+ return new Promise((e, r) => {
184
+ let a = i.request(o, {
185
+ method: t.method,
186
+ headers: t.headers
187
+ }, (t) => {
188
+ let n = [];
189
+ t.on("data", (e) => n.push(e)), t.on("end", () => {
190
+ e({
191
+ status: t.statusCode ?? 502,
192
+ headers: T(t.headers),
193
+ body: Buffer.concat(n)
194
+ });
195
+ }), t.on("error", r);
196
+ });
197
+ a.on("error", r), n.length > 0 && a.write(n), a.end();
198
+ });
199
+ }
200
+ //#endregion
201
+ //#region src/tunnel/serve.ts
202
+ function D(e, t) {
203
+ let n = x(e);
204
+ (async () => {
205
+ try {
206
+ for (;;) {
207
+ let { meta: r, body: i } = await n, a = await E(t, r, i);
208
+ await S(e, {
209
+ status: a.status,
210
+ headers: a.headers
211
+ }, a.body), n = x(e);
212
+ }
213
+ } catch {
214
+ e.destroy();
215
+ }
216
+ })();
217
+ }
218
+ async function O(e) {
219
+ let t = e.upstream.replace(/\/$/, ""), r = u(e.keyFile ?? ".seed/gateway-tunnel/operator.key.json"), i = new n(), a = i.createServer((e) => {
220
+ D(e, t);
221
+ });
222
+ return await a.listen(r), {
223
+ key: r.z32,
224
+ upstream: t,
225
+ close: async () => {
226
+ await a.close(), await i.destroy();
227
+ }
228
+ };
229
+ }
230
+ //#endregion
231
+ //#region src/tunnel/session.ts
232
+ async function k(e) {
233
+ let t = l(e.key), r = d(), i = new n(), a = null, o = null, s = async () => a && !a.destroyed ? a : o || (o = new Promise((e, n) => {
234
+ let s = i.connect(t, { keyPair: {
235
+ publicKey: r.publicKey,
236
+ secretKey: r.secretKey
237
+ } }), c = () => {
238
+ a = s, o = null, e(s);
239
+ };
240
+ s.once("open", c), s.once("connect", c), s.once("error", (e) => {
241
+ o = null, n(e);
242
+ });
243
+ }), o), c = Promise.resolve(), u = async (e) => {
244
+ let t = c.then(() => s()).then(e);
245
+ return c = t.catch(() => {}), t;
246
+ };
247
+ return {
248
+ key: e.key,
249
+ runOnTunnel: u,
250
+ forwardHttp: async (e, t) => u(async (n) => (await b(n, e, t), C(n))),
251
+ close: async () => {
252
+ a && !a.destroyed && a.destroy(), await i.destroy();
253
+ }
254
+ };
255
+ }
256
+ //#endregion
257
+ //#region src/tunnel/connect.ts
258
+ async function A(e) {
259
+ let t = [];
260
+ for await (let n of e) t.push(Buffer.isBuffer(n) ? n : Buffer.from(n));
261
+ return Buffer.concat(t);
262
+ }
263
+ function j(e) {
264
+ return i.createServer((t, n) => {
265
+ (async () => {
266
+ try {
267
+ let r = await A(t), i = t.url ?? "/", { meta: a, body: o } = await e({
268
+ method: t.method ?? "GET",
269
+ path: i,
270
+ headers: w(t.headers)
271
+ }, r);
272
+ n.writeHead(a.status, a.headers), n.end(o);
273
+ } catch (e) {
274
+ let t = e instanceof Error ? e.message : String(e);
275
+ n.headersSent || n.writeHead(502, { "Content-Type": "text/plain; charset=utf-8" }), n.end(`Gateway Hyper tunnel error: ${t}`);
276
+ }
277
+ })();
278
+ });
279
+ }
280
+ async function M(e) {
281
+ let t = e.host ?? "127.0.0.1", n = e.port ?? 1984, r = await k({
282
+ key: e.key,
283
+ storePath: e.storePath
284
+ }), i = j((e, t) => r.forwardHttp(e, t));
285
+ await new Promise((e, r) => {
286
+ i.once("error", r), i.listen(n, t, () => e());
287
+ });
288
+ let a = i.address(), o = a && typeof a == "object" ? a.port : n, s = `http://${t}:${o}`;
289
+ return {
290
+ key: e.key,
291
+ host: t,
292
+ port: o,
293
+ baseUrl: s,
294
+ close: async () => {
295
+ await new Promise((e) => i.close(() => e())), await r.close();
296
+ }
297
+ };
298
+ }
299
+ function N(e, t = "") {
300
+ let n = e.replace(/\/$/, "");
301
+ return t ? t.startsWith("/") ? `${n}${t}` : `${n}/${t}` : n;
302
+ }
303
+ //#endregion
304
+ //#region src/tunnel/mountPath.ts
305
+ function P(e, t) {
306
+ let n = e || "/", r = n.indexOf("?"), i = r === -1 ? n : n.slice(0, r), a = r === -1 ? "" : n.slice(r), o = (t || "").replace(/\/$/, "");
307
+ if (!o || o === "/") return `${i.startsWith("/") ? i : `/${i}`}${a}` || "/";
308
+ if (i === o || i.startsWith(`${o}/`)) {
309
+ let e = i.slice(o.length);
310
+ return `${e.startsWith("/") ? e : e ? `/${e}` : "/"}${a}`;
311
+ }
312
+ return `${i.startsWith("/") ? i : `/${i}`}${a}`;
313
+ }
314
+ //#endregion
315
+ //#region src/tunnel/forward.ts
316
+ async function F(e) {
317
+ let t = [];
318
+ for await (let n of e) t.push(Buffer.isBuffer(n) ? n : Buffer.from(n));
319
+ return Buffer.concat(t);
320
+ }
321
+ async function I(e, t, n, r) {
322
+ try {
323
+ let i = await F(t), a = P(t.url ?? "/", r), o = {
324
+ method: t.method ?? "GET",
325
+ path: a,
326
+ headers: w(t.headers)
327
+ }, { meta: s, body: c } = await e.forwardHttp(o, i);
328
+ L(n, s, c);
329
+ } catch (e) {
330
+ let t = e instanceof Error ? e.message : String(e);
331
+ n.headersSent || n.writeHead(502, { "Content-Type": "text/plain; charset=utf-8" }), n.end(`Gateway Hyper tunnel error: ${t}`);
332
+ }
333
+ }
334
+ function L(e, t, n) {
335
+ e.writeHead(t.status, T(t.headers)), e.end(n);
336
+ }
337
+ async function R(e, t, n) {
338
+ try {
339
+ let r = new URL(t.url), i = P(`${r.pathname}${r.search}`, n), a = Buffer.from(await t.arrayBuffer()), o = {};
340
+ t.headers.forEach((e, t) => {
341
+ o[t] = e;
342
+ });
343
+ let s = {
344
+ method: t.method || "GET",
345
+ path: i,
346
+ headers: w(o)
347
+ }, { meta: c, body: l } = await e.forwardHttp(s, a);
348
+ return new Response(l, {
349
+ status: c.status,
350
+ headers: T(c.headers)
351
+ });
352
+ } catch (e) {
353
+ let t = e instanceof Error ? e.message : String(e);
354
+ return new Response(`Gateway Hyper tunnel error: ${t}`, {
355
+ status: 502,
356
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
357
+ });
358
+ }
359
+ }
360
+ //#endregion
361
+ //#region src/tunnel/proxyApp.ts
362
+ function z(e) {
363
+ let t = e.key?.trim() || (typeof process < "u" ? process.env.SEED_GATEWAY_HYPER_KEY?.trim() : "") || "";
364
+ if (!t) throw Error("createGatewayProxy requires options.key or SEED_GATEWAY_HYPER_KEY environment variable");
365
+ return t;
366
+ }
367
+ function B(e = {}) {
368
+ let t = e.mountPath?.trim() || "/api/seed-gateway", n = z(e), r = null, i = null, a = async () => {
369
+ if (r) return r;
370
+ if (i) return i;
371
+ i = k({
372
+ key: n,
373
+ storePath: e.storePath
374
+ }).then((e) => (r = e, i = null, e));
375
+ try {
376
+ return await i;
377
+ } catch (e) {
378
+ throw i = null, e;
379
+ }
380
+ }, o = {
381
+ mountPath: t,
382
+ start: async () => {
383
+ await a();
384
+ },
385
+ close: async () => {
386
+ if (i) try {
387
+ await i;
388
+ } catch {}
389
+ r &&= (await r.close(), null);
390
+ },
391
+ handleNode: (e, n) => {
392
+ (async () => {
393
+ try {
394
+ await I(await a(), e, n, t);
395
+ } catch (e) {
396
+ let t = e instanceof Error ? e.message : String(e);
397
+ n.headersSent || n.writeHead(502, { "Content-Type": "text/plain; charset=utf-8" }), n.end(`Gateway Hyper tunnel error: ${t}`);
398
+ }
399
+ })();
400
+ },
401
+ handleFetch: async (e) => {
402
+ try {
403
+ return await R(await a(), e, t);
404
+ } catch (e) {
405
+ let t = e instanceof Error ? e.message : String(e);
406
+ return new Response(`Gateway Hyper tunnel error: ${t}`, {
407
+ status: 502,
408
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
409
+ });
410
+ }
411
+ }
412
+ };
413
+ return e.eager && o.start().catch(() => {}), o;
414
+ }
415
+ //#endregion
416
+ //#region src/constants.ts
417
+ var V = "";
418
+ //#endregion
419
+ export { l as _, N as a, f as c, y as d, x as f, S as g, b as h, M as i, T as l, v as m, B as n, k as o, C as p, P as r, O as s, V as t, w as u, c as v, u as y };
420
+
421
+ //# sourceMappingURL=src-CnXam5V8.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-CnXam5V8.js","names":["URL","fs","path","HyperDHT","ID","http","URL$1","toHex","buf","fromHex","hex","encodePublicKeyZ32","publicKey","decodePublicKey","trimmed","key","loadOrCreateOperatorKeypair","resolved","keyFile","raw","parsed","dir","kp","persisted","createEphemeralClientKeypair","MAX_FRAME_BYTES","StreamByteReader","stream","chunk","waiters","w","err","length","next","out","readers","getReader","reader","readExact","writeBuffer","onDrain","onError","resolve","reject","writeFrame","payload","header","readFrame","writeTunnelRequest","meta","body","readTunnelRequest","metaBuf","writeTunnelResponse","readTunnelResponse","flattenRequestHeaders","value","headers","filterResponseHeaders","skip","proxyTunnelRequest","base","upstreamBase","targetUrl","req","chunks","res","handleConnection","pendingRequest","socket","result","upstream","serveTunnel","options","keypair","dht","server","createTunnelSession","remotePublicKey","clientKey","activeSocket","connecting","getSocket","onReady","tunnelQueue","runOnTunnel","run","fn","readRequestBody","createLocalServer","responseMeta","responseBody","forwardHttp","message","connectTunnel","host","port","session","address","boundPort","baseUrl","localGatewayUrl","stripMountPath","urlPath","qIndex","pathname","query","mount","mountPath","rest","readNodeBody","forwardNodeRequest","writeNodeResponse","forwardFetchRequest","url","request","bodyBuf","headerRecord","resolveProxyKey","createGatewayProxy","starting","ensureSession","s","proxy","DEFAULT_SEED_GATEWAY_HYPER_KEY"],"sources":["../src/keys.ts","../src/tunnel/protocol.ts","../src/tunnel/proxy.ts","../src/tunnel/serve.ts","../src/tunnel/session.ts","../src/tunnel/connect.ts","../src/tunnel/mountPath.ts","../src/tunnel/forward.ts","../src/tunnel/proxyApp.ts","../src/constants.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport HyperDHT from 'hyperdht'\nimport ID from 'hypercore-id-encoding'\nimport type { OperatorKeyPair } from './types'\n\nexport interface PersistedKeyFile {\n publicKey: string\n secretKey: string\n encoding: 'hex'\n}\n\nfunction toHex(buf: Buffer): string {\n return buf.toString('hex')\n}\n\nfunction fromHex(hex: string): Buffer {\n return Buffer.from(hex, 'hex')\n}\n\nexport function encodePublicKeyZ32(publicKey: Buffer): string {\n return ID.encode(publicKey)\n}\n\nexport function decodePublicKey(key: string): Buffer {\n const trimmed = key.trim()\n if (!trimmed) {\n throw new Error('Gateway Hyper key is empty')\n }\n try {\n return Buffer.from(ID.decode(trimmed))\n } catch {\n if (/^[a-fA-F0-9]{64}$/.test(trimmed)) {\n return fromHex(trimmed)\n }\n throw new Error(`Invalid Gateway Hyper key (expected z32 or 64-char hex): ${trimmed.slice(0, 12)}…`)\n }\n}\n\nexport function loadOrCreateOperatorKeypair(keyFile: string): OperatorKeyPair {\n const resolved = path.resolve(keyFile)\n if (fs.existsSync(resolved)) {\n const raw = fs.readFileSync(resolved, 'utf8')\n const parsed = JSON.parse(raw) as PersistedKeyFile\n if (!parsed.publicKey || !parsed.secretKey) {\n throw new Error(`Invalid key file at ${resolved}: missing publicKey or secretKey`)\n }\n const publicKey = fromHex(parsed.publicKey)\n const secretKey = fromHex(parsed.secretKey)\n return {\n publicKey,\n secretKey,\n z32: encodePublicKeyZ32(publicKey),\n }\n }\n\n const dir = path.dirname(resolved)\n fs.mkdirSync(dir, { recursive: true })\n const kp = HyperDHT.keyPair()\n const persisted: PersistedKeyFile = {\n publicKey: toHex(kp.publicKey),\n secretKey: toHex(kp.secretKey),\n encoding: 'hex',\n }\n fs.writeFileSync(resolved, `${JSON.stringify(persisted, null, 2)}\\n`, { mode: 0o600 })\n return {\n publicKey: kp.publicKey,\n secretKey: kp.secretKey,\n z32: encodePublicKeyZ32(kp.publicKey),\n }\n}\n\nexport function createEphemeralClientKeypair(): OperatorKeyPair {\n const kp = HyperDHT.keyPair()\n return {\n publicKey: kp.publicKey,\n secretKey: kp.secretKey,\n z32: encodePublicKeyZ32(kp.publicKey),\n }\n}\n","import type { Readable, Writable } from 'node:stream'\nimport type { TunnelMeta, TunnelResponseMeta } from '../types'\n\n/** Maximum single frame payload (64 MiB). */\nexport const MAX_FRAME_BYTES = 64 * 1024 * 1024\n\ntype ByteWaiter = {\n length: number\n resolve: (buf: Buffer) => void\n reject: (err: Error) => void\n}\n\n/**\n * Per-stream byte buffer. HyperDHT duplexes do not reliably support `unshift`,\n * so we accumulate and slice locally instead of pushing leftovers back.\n */\nclass StreamByteReader {\n private buffer = Buffer.alloc(0)\n private waiters: ByteWaiter[] = []\n private ended = false\n private readonly onData: (chunk: Buffer) => void\n private readonly onError: (err: Error) => void\n private readonly onEnd: () => void\n\n constructor(private readonly stream: Readable) {\n this.onData = (chunk: Buffer) => {\n this.buffer = Buffer.concat([this.buffer, chunk])\n this.drain()\n }\n this.onError = (err: Error) => {\n const waiters = this.waiters.splice(0)\n for (const w of waiters) w.reject(err)\n }\n this.onEnd = () => {\n this.ended = true\n this.drain()\n if (this.waiters.length > 0) {\n const waiters = this.waiters.splice(0)\n for (const w of waiters) {\n w.reject(\n new Error(\n `Unexpected end of stream (expected ${w.length} bytes, got ${this.buffer.length})`,\n ),\n )\n }\n }\n }\n stream.on('data', this.onData)\n stream.on('error', this.onError)\n stream.on('end', this.onEnd)\n }\n\n readExact(length: number): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n if (length === 0) {\n resolve(Buffer.alloc(0))\n return\n }\n this.waiters.push({ length, resolve, reject })\n this.drain()\n if (this.ended && this.waiters.length > 0) {\n const waiters = this.waiters.splice(0)\n for (const w of waiters) {\n w.reject(\n new Error(\n `Unexpected end of stream (expected ${w.length} bytes, got ${this.buffer.length})`,\n ),\n )\n }\n }\n })\n }\n\n private drain(): void {\n while (this.waiters.length > 0) {\n const next = this.waiters[0]\n if (!next || this.buffer.length < next.length) break\n this.waiters.shift()\n const out = this.buffer.subarray(0, next.length)\n this.buffer = this.buffer.subarray(next.length)\n next.resolve(out)\n }\n }\n}\n\nconst readers = new WeakMap<Readable, StreamByteReader>()\n\nfunction getReader(stream: Readable): StreamByteReader {\n let reader = readers.get(stream)\n if (!reader) {\n reader = new StreamByteReader(stream)\n readers.set(stream, reader)\n }\n return reader\n}\n\nfunction readExact(stream: Readable, length: number): Promise<Buffer> {\n return getReader(stream).readExact(length)\n}\n\nfunction writeBuffer(stream: Writable, buf: Buffer): Promise<void> {\n return new Promise((resolve, reject) => {\n // HyperDHT duplexes often never invoke write(callback). Use return value + drain.\n try {\n const ok = stream.write(buf)\n if (ok) {\n resolve()\n return\n }\n const onDrain = () => {\n stream.off('error', onError)\n resolve()\n }\n const onError = (err: Error) => {\n stream.off('drain', onDrain)\n reject(err)\n }\n stream.once('drain', onDrain)\n stream.once('error', onError)\n } catch (err) {\n reject(err instanceof Error ? err : new Error(String(err)))\n }\n })\n}\n\nexport async function writeFrame(stream: Writable, payload: Buffer): Promise<void> {\n if (payload.length > MAX_FRAME_BYTES) {\n throw new Error(`Frame too large: ${payload.length} bytes (max ${MAX_FRAME_BYTES})`)\n }\n const header = Buffer.alloc(4)\n header.writeUInt32BE(payload.length, 0)\n // Single write — HyperDHT can drop/stall subsequent writes in the same turn.\n await writeBuffer(stream, Buffer.concat([header, payload]))\n}\n\nexport async function readFrame(stream: Readable): Promise<Buffer> {\n const header = await readExact(stream, 4)\n const length = header.readUInt32BE(0)\n if (length === 0) {\n return Buffer.alloc(0)\n }\n if (length > MAX_FRAME_BYTES) {\n throw new Error(`Frame too large: ${length} bytes (max ${MAX_FRAME_BYTES})`)\n }\n return readExact(stream, length)\n}\n\nexport async function writeTunnelRequest(\n stream: Writable,\n meta: TunnelMeta,\n body: Buffer,\n): Promise<void> {\n const metaFrame = Buffer.from(JSON.stringify(meta), 'utf8')\n await writeFrame(stream, metaFrame)\n await writeFrame(stream, body)\n}\n\nexport async function readTunnelRequest(\n stream: Readable,\n): Promise<{ meta: TunnelMeta; body: Buffer }> {\n const metaBuf = await readFrame(stream)\n const meta = JSON.parse(metaBuf.toString('utf8')) as TunnelMeta\n if (!meta.method || !meta.path) {\n throw new Error('Invalid tunnel request meta: missing method or path')\n }\n meta.headers = meta.headers ?? {}\n const body = await readFrame(stream)\n return { meta, body }\n}\n\nexport async function writeTunnelResponse(\n stream: Writable,\n meta: TunnelResponseMeta,\n body: Buffer,\n): Promise<void> {\n const metaFrame = Buffer.from(JSON.stringify(meta), 'utf8')\n await writeFrame(stream, metaFrame)\n await writeFrame(stream, body)\n}\n\nexport async function readTunnelResponse(\n stream: Readable,\n): Promise<{ meta: TunnelResponseMeta; body: Buffer }> {\n const metaBuf = await readFrame(stream)\n const meta = JSON.parse(metaBuf.toString('utf8')) as TunnelResponseMeta\n if (typeof meta.status !== 'number') {\n throw new Error('Invalid tunnel response meta: missing status')\n }\n meta.headers = meta.headers ?? {}\n const body = await readFrame(stream)\n return { meta, body }\n}\n\n/** Normalize header values to strings for tunnel transport. */\nexport function flattenRequestHeaders(\n headers: Record<string, string | string[] | undefined>,\n): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [key, value] of Object.entries(headers)) {\n if (value == null) continue\n out[key] = Array.isArray(value) ? value.join(', ') : value\n }\n return out\n}\n\n/** Pick response headers safe to forward to the local HTTP client. */\nexport function filterResponseHeaders(\n headers: Record<string, string | string[] | undefined>,\n): Record<string, string> {\n const skip = new Set([\n 'connection',\n 'keep-alive',\n 'transfer-encoding',\n 'upgrade',\n ])\n const out: Record<string, string> = {}\n for (const [key, value] of Object.entries(headers)) {\n if (skip.has(key.toLowerCase())) continue\n if (value == null) continue\n out[key] = Array.isArray(value) ? value.join(', ') : value\n }\n return out\n}\n","import http from 'node:http'\nimport { URL } from 'node:url'\nimport { filterResponseHeaders } from './protocol'\nimport type { TunnelMeta } from '../types'\n\nexport async function proxyTunnelRequest(\n upstreamBase: string,\n meta: TunnelMeta,\n body: Buffer,\n): Promise<{ status: number; headers: Record<string, string>; body: Buffer }> {\n const base = upstreamBase.replace(/\\/$/, '')\n const targetUrl = new URL(meta.path, `${base}/`)\n\n return new Promise((resolve, reject) => {\n const req = http.request(\n targetUrl,\n {\n method: meta.method,\n headers: meta.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (chunk: Buffer) => chunks.push(chunk))\n res.on('end', () => {\n resolve({\n status: res.statusCode ?? 502,\n headers: filterResponseHeaders(res.headers as Record<string, string | string[] | undefined>),\n body: Buffer.concat(chunks),\n })\n })\n res.on('error', reject)\n },\n )\n req.on('error', reject)\n if (body.length > 0) {\n req.write(body)\n }\n req.end()\n })\n}\n","import type { Duplex } from 'node:stream'\nimport HyperDHT from 'hyperdht'\nimport { readTunnelRequest, writeTunnelResponse } from './protocol'\nimport { proxyTunnelRequest } from './proxy'\nimport { loadOrCreateOperatorKeypair } from '../keys'\nimport type { ServeTunnelOptions, ServeTunnelResult } from '../types'\n\nfunction handleConnection(\n socket: Duplex,\n upstream: string,\n): void {\n // Attach framed readers synchronously so HyperDHT early bytes are not lost.\n let pendingRequest = readTunnelRequest(socket)\n void (async () => {\n try {\n while (true) {\n const { meta, body } = await pendingRequest\n const result = await proxyTunnelRequest(upstream, meta, body)\n await writeTunnelResponse(\n socket,\n { status: result.status, headers: result.headers },\n result.body,\n )\n pendingRequest = readTunnelRequest(socket)\n }\n } catch {\n socket.destroy()\n }\n })()\n}\n\n/**\n * Operator: accept Hyperswarm/DHT connections and proxy framed HTTP to upstream Traefik.\n */\nexport async function serveTunnel(options: ServeTunnelOptions): Promise<ServeTunnelResult> {\n const upstream = options.upstream.replace(/\\/$/, '')\n const keyFile = options.keyFile ?? '.seed/gateway-tunnel/operator.key.json'\n const keypair = loadOrCreateOperatorKeypair(keyFile)\n\n const dht = new HyperDHT()\n const server = dht.createServer((socket) => {\n handleConnection(socket as Duplex, upstream)\n })\n\n await server.listen(keypair)\n\n return {\n key: keypair.z32,\n upstream,\n close: async () => {\n await server.close()\n await dht.destroy()\n },\n }\n}\n","import type { Duplex } from 'node:stream'\nimport HyperDHT from 'hyperdht'\nimport { createEphemeralClientKeypair, decodePublicKey } from '../keys'\nimport type { TunnelMeta, TunnelResponseMeta } from '../types'\nimport { readTunnelResponse, writeTunnelRequest } from './protocol'\n\nexport type TunnelSessionOptions = {\n /** Operator public key (z32 or hex) */\n key: string\n /** Optional store path for DHT client state */\n storePath?: string\n}\n\nexport type TunnelSession = {\n key: string\n runOnTunnel: <T>(fn: (socket: Duplex) => Promise<T>) => Promise<T>\n forwardHttp: (\n meta: TunnelMeta,\n body: Buffer,\n ) => Promise<{ meta: TunnelResponseMeta; body: Buffer }>\n close: () => Promise<void>\n}\n\n/**\n * Dial the operator HyperDHT key and expose a serialized request/response forwarder.\n */\nexport async function createTunnelSession(options: TunnelSessionOptions): Promise<TunnelSession> {\n const remotePublicKey = decodePublicKey(options.key)\n const clientKey = createEphemeralClientKeypair()\n\n const dht = new HyperDHT()\n let activeSocket: Duplex | null = null\n let connecting: Promise<Duplex> | null = null\n\n const getSocket = async (): Promise<Duplex> => {\n if (activeSocket && !activeSocket.destroyed) {\n return activeSocket\n }\n if (connecting) {\n return connecting\n }\n connecting = new Promise<Duplex>((resolve, reject) => {\n const socket = dht.connect(remotePublicKey, {\n keyPair: { publicKey: clientKey.publicKey, secretKey: clientKey.secretKey },\n }) as Duplex\n const onReady = () => {\n activeSocket = socket\n connecting = null\n resolve(socket)\n }\n socket.once('open', onReady)\n socket.once('connect', onReady)\n socket.once('error', (err: Error) => {\n connecting = null\n reject(err)\n })\n })\n return connecting\n }\n\n /** Serialize tunnel transactions on one persistent socket. */\n let tunnelQueue: Promise<unknown> = Promise.resolve()\n const runOnTunnel = async <T>(fn: (socket: Duplex) => Promise<T>): Promise<T> => {\n const run = tunnelQueue.then(() => getSocket()).then(fn)\n tunnelQueue = run.catch(() => {})\n return run\n }\n\n const forwardHttp = async (\n meta: TunnelMeta,\n body: Buffer,\n ): Promise<{ meta: TunnelResponseMeta; body: Buffer }> => {\n return runOnTunnel(async (socket) => {\n await writeTunnelRequest(socket, meta, body)\n return readTunnelResponse(socket)\n })\n }\n\n return {\n key: options.key,\n runOnTunnel,\n forwardHttp,\n close: async () => {\n if (activeSocket && !activeSocket.destroyed) {\n activeSocket.destroy()\n }\n await dht.destroy()\n },\n }\n}\n","import http from 'node:http'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport {\n flattenRequestHeaders,\n} from './protocol'\nimport { createTunnelSession } from './session'\nimport type { ConnectTunnelOptions, ConnectTunnelResult } from '../types'\n\nasync function readRequestBody(req: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = []\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))\n }\n return Buffer.concat(chunks)\n}\n\nfunction createLocalServer(\n forwardHttp: (\n meta: { method: string; path: string; headers: Record<string, string> },\n body: Buffer,\n ) => Promise<{ meta: { status: number; headers: Record<string, string> }; body: Buffer }>,\n): http.Server {\n return http.createServer((req, res) => {\n void (async () => {\n try {\n const body = await readRequestBody(req)\n const path = req.url ?? '/'\n const meta = {\n method: req.method ?? 'GET',\n path,\n headers: flattenRequestHeaders(req.headers as Record<string, string | string[] | undefined>),\n }\n\n const { meta: responseMeta, body: responseBody } = await forwardHttp(meta, body)\n\n res.writeHead(responseMeta.status, responseMeta.headers)\n res.end(responseBody)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n if (!res.headersSent) {\n res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' })\n }\n res.end(`Gateway Hyper tunnel error: ${message}`)\n }\n })()\n })\n}\n\n/**\n * Client: dial operator key and expose a localhost HTTP server that forwards through the tunnel.\n */\nexport async function connectTunnel(options: ConnectTunnelOptions): Promise<ConnectTunnelResult> {\n const host = options.host ?? '127.0.0.1'\n const port = options.port ?? 1984\n\n const session = await createTunnelSession({\n key: options.key,\n storePath: options.storePath,\n })\n\n const server = createLocalServer((meta, body) => session.forwardHttp(meta, body))\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(port, host, () => resolve())\n })\n\n const address = server.address()\n const boundPort =\n address && typeof address === 'object' ? address.port : port\n\n const baseUrl = `http://${host}:${boundPort}`\n\n return {\n key: options.key,\n host,\n port: boundPort,\n baseUrl,\n close: async () => {\n await new Promise<void>((resolve) => server.close(() => resolve()))\n await session.close()\n },\n }\n}\n\nexport function localGatewayUrl(baseUrl: string, path = ''): string {\n const base = baseUrl.replace(/\\/$/, '')\n if (!path) return base\n return path.startsWith('/') ? `${base}${path}` : `${base}/${path}`\n}\n","/**\n * Strip a mount path prefix from an incoming request URL path (including query string).\n * If the path is already unmounted (framework stripped it), returns it unchanged (with leading `/`).\n */\nexport function stripMountPath(urlPath: string, mountPath: string): string {\n const raw = urlPath || '/'\n const qIndex = raw.indexOf('?')\n const pathname = qIndex === -1 ? raw : raw.slice(0, qIndex)\n const query = qIndex === -1 ? '' : raw.slice(qIndex)\n\n const mount = (mountPath || '').replace(/\\/$/, '')\n if (!mount || mount === '/') {\n const path = pathname.startsWith('/') ? pathname : `/${pathname}`\n return `${path}${query}` || '/'\n }\n\n if (pathname === mount || pathname.startsWith(`${mount}/`)) {\n const rest = pathname.slice(mount.length)\n const path = rest.startsWith('/') ? rest : rest ? `/${rest}` : '/'\n return `${path}${query}`\n }\n\n // Already stripped by the framework (e.g. Express mount)\n const path = pathname.startsWith('/') ? pathname : `/${pathname}`\n return `${path}${query}`\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport {\n filterResponseHeaders,\n flattenRequestHeaders,\n} from './protocol'\nimport { stripMountPath } from './mountPath'\nimport type { TunnelSession } from './session'\nimport type { TunnelMeta, TunnelResponseMeta } from '../types'\n\nasync function readNodeBody(req: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = []\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))\n }\n return Buffer.concat(chunks)\n}\n\nexport async function forwardNodeRequest(\n session: TunnelSession,\n req: IncomingMessage,\n res: ServerResponse,\n mountPath: string,\n): Promise<void> {\n try {\n const body = await readNodeBody(req)\n const path = stripMountPath(req.url ?? '/', mountPath)\n const meta: TunnelMeta = {\n method: req.method ?? 'GET',\n path,\n headers: flattenRequestHeaders(req.headers as Record<string, string | string[] | undefined>),\n }\n const { meta: responseMeta, body: responseBody } = await session.forwardHttp(meta, body)\n writeNodeResponse(res, responseMeta, responseBody)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n if (!res.headersSent) {\n res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' })\n }\n res.end(`Gateway Hyper tunnel error: ${message}`)\n }\n}\n\nfunction writeNodeResponse(\n res: ServerResponse,\n meta: TunnelResponseMeta,\n body: Buffer,\n): void {\n res.writeHead(meta.status, filterResponseHeaders(meta.headers))\n res.end(body)\n}\n\nexport async function forwardFetchRequest(\n session: TunnelSession,\n request: Request,\n mountPath: string,\n): Promise<Response> {\n try {\n const url = new URL(request.url)\n const path = stripMountPath(`${url.pathname}${url.search}`, mountPath)\n const bodyBuf = Buffer.from(await request.arrayBuffer())\n const headerRecord: Record<string, string> = {}\n request.headers.forEach((value, key) => {\n headerRecord[key] = value\n })\n const meta: TunnelMeta = {\n method: request.method || 'GET',\n path,\n headers: flattenRequestHeaders(headerRecord),\n }\n const { meta: responseMeta, body: responseBody } = await session.forwardHttp(meta, bodyBuf)\n return new Response(responseBody, {\n status: responseMeta.status,\n headers: filterResponseHeaders(responseMeta.headers),\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return new Response(`Gateway Hyper tunnel error: ${message}`, {\n status: 502,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n })\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { createTunnelSession, type TunnelSession } from './session'\nimport { forwardFetchRequest, forwardNodeRequest } from './forward'\nimport type { CreateGatewayProxyOptions, GatewayProxy } from '../types'\n\nfunction resolveProxyKey(options: CreateGatewayProxyOptions): string {\n const key =\n options.key?.trim() ||\n (typeof process !== 'undefined' ? process.env.SEED_GATEWAY_HYPER_KEY?.trim() : '') ||\n ''\n if (!key) {\n throw new Error(\n 'createGatewayProxy requires options.key or SEED_GATEWAY_HYPER_KEY environment variable',\n )\n }\n return key\n}\n\n/**\n * App-server Hyper gateway proxy for hosted web apps (Path B).\n *\n * Mount on a Node route (Next.js Node runtime, Express, etc.). Keep the operator\n * Hyper key on the server only — browsers talk HTTP to `proxyBaseUrl`.\n *\n * Prefer Node.js over Bun for Holepunch natives.\n */\nexport function createGatewayProxy(options: CreateGatewayProxyOptions = {}): GatewayProxy {\n const mountPath = options.mountPath?.trim() || '/api/seed-gateway'\n const key = resolveProxyKey(options)\n\n let session: TunnelSession | null = null\n let starting: Promise<TunnelSession> | null = null\n\n const ensureSession = async (): Promise<TunnelSession> => {\n if (session) return session\n if (starting) return starting\n starting = createTunnelSession({ key, storePath: options.storePath }).then((s) => {\n session = s\n starting = null\n return s\n })\n try {\n return await starting\n } catch (err) {\n starting = null\n throw err\n }\n }\n\n const proxy: GatewayProxy = {\n mountPath,\n start: async () => {\n await ensureSession()\n },\n close: async () => {\n if (starting) {\n try {\n await starting\n } catch {\n /* ignore start failure during close */\n }\n }\n if (session) {\n await session.close()\n session = null\n }\n },\n handleNode: (req: IncomingMessage, res: ServerResponse) => {\n void (async () => {\n try {\n const s = await ensureSession()\n await forwardNodeRequest(s, req, res, mountPath)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n if (!res.headersSent) {\n res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' })\n }\n res.end(`Gateway Hyper tunnel error: ${message}`)\n }\n })()\n },\n handleFetch: async (request: Request): Promise<Response> => {\n try {\n const s = await ensureSession()\n return await forwardFetchRequest(s, request, mountPath)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return new Response(`Gateway Hyper tunnel error: ${message}`, {\n status: 502,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n })\n }\n },\n }\n\n if (options.eager) {\n void proxy.start().catch(() => {\n /* first request will surface the error */\n })\n }\n\n return proxy\n}\n","/**\n * Official Seed Protocol gateway Hyper tunnel operator key (z32).\n * Empty until ops generate and back up the first operator keypair.\n */\nexport const DEFAULT_SEED_GATEWAY_HYPER_KEY = ''\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "@seedprotocol/gateway-hyper",
3
- "version": "0.7.0",
3
+ "version": "0.7.2-next.593.gd5bd4ea",
4
4
  "description": "Hyperswarm HTTP tunnel for Seed Protocol gateway + upload API infrastructure",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
+ "bin": {
8
+ "seed-gateway": "./dist/bin.js"
9
+ },
7
10
  "exports": {
8
11
  ".": {
9
12
  "import": {
@@ -39,10 +42,15 @@
39
42
  "rimraf": "^6.0.1",
40
43
  "typescript": "~5.9.3",
41
44
  "vite": "^8.0.0",
42
- "vitest": "^3.0.0"
45
+ "vitest": "^4.1.11"
43
46
  },
44
47
  "author": "Keith Axline <keith@journodao.xyz>",
45
48
  "license": "MIT",
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/JournoLabs/seed-protocol-sdk.git",
52
+ "directory": "packages/gateway-hyper"
53
+ },
46
54
  "publishConfig": {
47
55
  "access": "public"
48
56
  }
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/keys.ts","../src/tunnel/protocol.ts","../src/tunnel/proxy.ts","../src/tunnel/serve.ts","../src/tunnel/session.ts","../src/tunnel/connect.ts","../src/tunnel/mountPath.ts","../src/tunnel/forward.ts","../src/tunnel/proxyApp.ts","../src/constants.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport HyperDHT from 'hyperdht'\nimport ID from 'hypercore-id-encoding'\nimport type { OperatorKeyPair } from './types'\n\nexport interface PersistedKeyFile {\n publicKey: string\n secretKey: string\n encoding: 'hex'\n}\n\nfunction toHex(buf: Buffer): string {\n return buf.toString('hex')\n}\n\nfunction fromHex(hex: string): Buffer {\n return Buffer.from(hex, 'hex')\n}\n\nexport function encodePublicKeyZ32(publicKey: Buffer): string {\n return ID.encode(publicKey)\n}\n\nexport function decodePublicKey(key: string): Buffer {\n const trimmed = key.trim()\n if (!trimmed) {\n throw new Error('Gateway Hyper key is empty')\n }\n try {\n return Buffer.from(ID.decode(trimmed))\n } catch {\n if (/^[a-fA-F0-9]{64}$/.test(trimmed)) {\n return fromHex(trimmed)\n }\n throw new Error(`Invalid Gateway Hyper key (expected z32 or 64-char hex): ${trimmed.slice(0, 12)}…`)\n }\n}\n\nexport function loadOrCreateOperatorKeypair(keyFile: string): OperatorKeyPair {\n const resolved = path.resolve(keyFile)\n if (fs.existsSync(resolved)) {\n const raw = fs.readFileSync(resolved, 'utf8')\n const parsed = JSON.parse(raw) as PersistedKeyFile\n if (!parsed.publicKey || !parsed.secretKey) {\n throw new Error(`Invalid key file at ${resolved}: missing publicKey or secretKey`)\n }\n const publicKey = fromHex(parsed.publicKey)\n const secretKey = fromHex(parsed.secretKey)\n return {\n publicKey,\n secretKey,\n z32: encodePublicKeyZ32(publicKey),\n }\n }\n\n const dir = path.dirname(resolved)\n fs.mkdirSync(dir, { recursive: true })\n const kp = HyperDHT.keyPair()\n const persisted: PersistedKeyFile = {\n publicKey: toHex(kp.publicKey),\n secretKey: toHex(kp.secretKey),\n encoding: 'hex',\n }\n fs.writeFileSync(resolved, `${JSON.stringify(persisted, null, 2)}\\n`, { mode: 0o600 })\n return {\n publicKey: kp.publicKey,\n secretKey: kp.secretKey,\n z32: encodePublicKeyZ32(kp.publicKey),\n }\n}\n\nexport function createEphemeralClientKeypair(): OperatorKeyPair {\n const kp = HyperDHT.keyPair()\n return {\n publicKey: kp.publicKey,\n secretKey: kp.secretKey,\n z32: encodePublicKeyZ32(kp.publicKey),\n }\n}\n","import type { Readable, Writable } from 'node:stream'\nimport type { TunnelMeta, TunnelResponseMeta } from '../types'\n\n/** Maximum single frame payload (64 MiB). */\nexport const MAX_FRAME_BYTES = 64 * 1024 * 1024\n\ntype ByteWaiter = {\n length: number\n resolve: (buf: Buffer) => void\n reject: (err: Error) => void\n}\n\n/**\n * Per-stream byte buffer. HyperDHT duplexes do not reliably support `unshift`,\n * so we accumulate and slice locally instead of pushing leftovers back.\n */\nclass StreamByteReader {\n private buffer = Buffer.alloc(0)\n private waiters: ByteWaiter[] = []\n private ended = false\n private readonly onData: (chunk: Buffer) => void\n private readonly onError: (err: Error) => void\n private readonly onEnd: () => void\n\n constructor(private readonly stream: Readable) {\n this.onData = (chunk: Buffer) => {\n this.buffer = Buffer.concat([this.buffer, chunk])\n this.drain()\n }\n this.onError = (err: Error) => {\n const waiters = this.waiters.splice(0)\n for (const w of waiters) w.reject(err)\n }\n this.onEnd = () => {\n this.ended = true\n this.drain()\n if (this.waiters.length > 0) {\n const waiters = this.waiters.splice(0)\n for (const w of waiters) {\n w.reject(\n new Error(\n `Unexpected end of stream (expected ${w.length} bytes, got ${this.buffer.length})`,\n ),\n )\n }\n }\n }\n stream.on('data', this.onData)\n stream.on('error', this.onError)\n stream.on('end', this.onEnd)\n }\n\n readExact(length: number): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n if (length === 0) {\n resolve(Buffer.alloc(0))\n return\n }\n this.waiters.push({ length, resolve, reject })\n this.drain()\n if (this.ended && this.waiters.length > 0) {\n const waiters = this.waiters.splice(0)\n for (const w of waiters) {\n w.reject(\n new Error(\n `Unexpected end of stream (expected ${w.length} bytes, got ${this.buffer.length})`,\n ),\n )\n }\n }\n })\n }\n\n private drain(): void {\n while (this.waiters.length > 0) {\n const next = this.waiters[0]\n if (!next || this.buffer.length < next.length) break\n this.waiters.shift()\n const out = this.buffer.subarray(0, next.length)\n this.buffer = this.buffer.subarray(next.length)\n next.resolve(out)\n }\n }\n}\n\nconst readers = new WeakMap<Readable, StreamByteReader>()\n\nfunction getReader(stream: Readable): StreamByteReader {\n let reader = readers.get(stream)\n if (!reader) {\n reader = new StreamByteReader(stream)\n readers.set(stream, reader)\n }\n return reader\n}\n\nfunction readExact(stream: Readable, length: number): Promise<Buffer> {\n return getReader(stream).readExact(length)\n}\n\nfunction writeBuffer(stream: Writable, buf: Buffer): Promise<void> {\n return new Promise((resolve, reject) => {\n // HyperDHT duplexes often never invoke write(callback). Use return value + drain.\n try {\n const ok = stream.write(buf)\n if (ok) {\n resolve()\n return\n }\n const onDrain = () => {\n stream.off('error', onError)\n resolve()\n }\n const onError = (err: Error) => {\n stream.off('drain', onDrain)\n reject(err)\n }\n stream.once('drain', onDrain)\n stream.once('error', onError)\n } catch (err) {\n reject(err instanceof Error ? err : new Error(String(err)))\n }\n })\n}\n\nexport async function writeFrame(stream: Writable, payload: Buffer): Promise<void> {\n if (payload.length > MAX_FRAME_BYTES) {\n throw new Error(`Frame too large: ${payload.length} bytes (max ${MAX_FRAME_BYTES})`)\n }\n const header = Buffer.alloc(4)\n header.writeUInt32BE(payload.length, 0)\n // Single write — HyperDHT can drop/stall subsequent writes in the same turn.\n await writeBuffer(stream, Buffer.concat([header, payload]))\n}\n\nexport async function readFrame(stream: Readable): Promise<Buffer> {\n const header = await readExact(stream, 4)\n const length = header.readUInt32BE(0)\n if (length === 0) {\n return Buffer.alloc(0)\n }\n if (length > MAX_FRAME_BYTES) {\n throw new Error(`Frame too large: ${length} bytes (max ${MAX_FRAME_BYTES})`)\n }\n return readExact(stream, length)\n}\n\nexport async function writeTunnelRequest(\n stream: Writable,\n meta: TunnelMeta,\n body: Buffer,\n): Promise<void> {\n const metaFrame = Buffer.from(JSON.stringify(meta), 'utf8')\n await writeFrame(stream, metaFrame)\n await writeFrame(stream, body)\n}\n\nexport async function readTunnelRequest(\n stream: Readable,\n): Promise<{ meta: TunnelMeta; body: Buffer }> {\n const metaBuf = await readFrame(stream)\n const meta = JSON.parse(metaBuf.toString('utf8')) as TunnelMeta\n if (!meta.method || !meta.path) {\n throw new Error('Invalid tunnel request meta: missing method or path')\n }\n meta.headers = meta.headers ?? {}\n const body = await readFrame(stream)\n return { meta, body }\n}\n\nexport async function writeTunnelResponse(\n stream: Writable,\n meta: TunnelResponseMeta,\n body: Buffer,\n): Promise<void> {\n const metaFrame = Buffer.from(JSON.stringify(meta), 'utf8')\n await writeFrame(stream, metaFrame)\n await writeFrame(stream, body)\n}\n\nexport async function readTunnelResponse(\n stream: Readable,\n): Promise<{ meta: TunnelResponseMeta; body: Buffer }> {\n const metaBuf = await readFrame(stream)\n const meta = JSON.parse(metaBuf.toString('utf8')) as TunnelResponseMeta\n if (typeof meta.status !== 'number') {\n throw new Error('Invalid tunnel response meta: missing status')\n }\n meta.headers = meta.headers ?? {}\n const body = await readFrame(stream)\n return { meta, body }\n}\n\n/** Normalize header values to strings for tunnel transport. */\nexport function flattenRequestHeaders(\n headers: Record<string, string | string[] | undefined>,\n): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [key, value] of Object.entries(headers)) {\n if (value == null) continue\n out[key] = Array.isArray(value) ? value.join(', ') : value\n }\n return out\n}\n\n/** Pick response headers safe to forward to the local HTTP client. */\nexport function filterResponseHeaders(\n headers: Record<string, string | string[] | undefined>,\n): Record<string, string> {\n const skip = new Set([\n 'connection',\n 'keep-alive',\n 'transfer-encoding',\n 'upgrade',\n ])\n const out: Record<string, string> = {}\n for (const [key, value] of Object.entries(headers)) {\n if (skip.has(key.toLowerCase())) continue\n if (value == null) continue\n out[key] = Array.isArray(value) ? value.join(', ') : value\n }\n return out\n}\n","import http from 'node:http'\nimport { URL } from 'node:url'\nimport { filterResponseHeaders } from './protocol'\nimport type { TunnelMeta } from '../types'\n\nexport async function proxyTunnelRequest(\n upstreamBase: string,\n meta: TunnelMeta,\n body: Buffer,\n): Promise<{ status: number; headers: Record<string, string>; body: Buffer }> {\n const base = upstreamBase.replace(/\\/$/, '')\n const targetUrl = new URL(meta.path, `${base}/`)\n\n return new Promise((resolve, reject) => {\n const req = http.request(\n targetUrl,\n {\n method: meta.method,\n headers: meta.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (chunk: Buffer) => chunks.push(chunk))\n res.on('end', () => {\n resolve({\n status: res.statusCode ?? 502,\n headers: filterResponseHeaders(res.headers as Record<string, string | string[] | undefined>),\n body: Buffer.concat(chunks),\n })\n })\n res.on('error', reject)\n },\n )\n req.on('error', reject)\n if (body.length > 0) {\n req.write(body)\n }\n req.end()\n })\n}\n","import type { Duplex } from 'node:stream'\nimport HyperDHT from 'hyperdht'\nimport { readTunnelRequest, writeTunnelResponse } from './protocol'\nimport { proxyTunnelRequest } from './proxy'\nimport { loadOrCreateOperatorKeypair } from '../keys'\nimport type { ServeTunnelOptions, ServeTunnelResult } from '../types'\n\nfunction handleConnection(\n socket: Duplex,\n upstream: string,\n): void {\n // Attach framed readers synchronously so HyperDHT early bytes are not lost.\n let pendingRequest = readTunnelRequest(socket)\n void (async () => {\n try {\n while (true) {\n const { meta, body } = await pendingRequest\n const result = await proxyTunnelRequest(upstream, meta, body)\n await writeTunnelResponse(\n socket,\n { status: result.status, headers: result.headers },\n result.body,\n )\n pendingRequest = readTunnelRequest(socket)\n }\n } catch {\n socket.destroy()\n }\n })()\n}\n\n/**\n * Operator: accept Hyperswarm/DHT connections and proxy framed HTTP to upstream Traefik.\n */\nexport async function serveTunnel(options: ServeTunnelOptions): Promise<ServeTunnelResult> {\n const upstream = options.upstream.replace(/\\/$/, '')\n const keyFile = options.keyFile ?? '.seed/gateway-tunnel/operator.key.json'\n const keypair = loadOrCreateOperatorKeypair(keyFile)\n\n const dht = new HyperDHT()\n const server = dht.createServer((socket) => {\n handleConnection(socket as Duplex, upstream)\n })\n\n await server.listen(keypair)\n\n return {\n key: keypair.z32,\n upstream,\n close: async () => {\n await server.close()\n await dht.destroy()\n },\n }\n}\n","import type { Duplex } from 'node:stream'\nimport HyperDHT from 'hyperdht'\nimport { createEphemeralClientKeypair, decodePublicKey } from '../keys'\nimport type { TunnelMeta, TunnelResponseMeta } from '../types'\nimport { readTunnelResponse, writeTunnelRequest } from './protocol'\n\nexport type TunnelSessionOptions = {\n /** Operator public key (z32 or hex) */\n key: string\n /** Optional store path for DHT client state */\n storePath?: string\n}\n\nexport type TunnelSession = {\n key: string\n runOnTunnel: <T>(fn: (socket: Duplex) => Promise<T>) => Promise<T>\n forwardHttp: (\n meta: TunnelMeta,\n body: Buffer,\n ) => Promise<{ meta: TunnelResponseMeta; body: Buffer }>\n close: () => Promise<void>\n}\n\n/**\n * Dial the operator HyperDHT key and expose a serialized request/response forwarder.\n */\nexport async function createTunnelSession(options: TunnelSessionOptions): Promise<TunnelSession> {\n const remotePublicKey = decodePublicKey(options.key)\n const clientKey = createEphemeralClientKeypair()\n\n const dht = new HyperDHT()\n let activeSocket: Duplex | null = null\n let connecting: Promise<Duplex> | null = null\n\n const getSocket = async (): Promise<Duplex> => {\n if (activeSocket && !activeSocket.destroyed) {\n return activeSocket\n }\n if (connecting) {\n return connecting\n }\n connecting = new Promise<Duplex>((resolve, reject) => {\n const socket = dht.connect(remotePublicKey, {\n keyPair: { publicKey: clientKey.publicKey, secretKey: clientKey.secretKey },\n }) as Duplex\n const onReady = () => {\n activeSocket = socket\n connecting = null\n resolve(socket)\n }\n socket.once('open', onReady)\n socket.once('connect', onReady)\n socket.once('error', (err: Error) => {\n connecting = null\n reject(err)\n })\n })\n return connecting\n }\n\n /** Serialize tunnel transactions on one persistent socket. */\n let tunnelQueue: Promise<unknown> = Promise.resolve()\n const runOnTunnel = async <T>(fn: (socket: Duplex) => Promise<T>): Promise<T> => {\n const run = tunnelQueue.then(() => getSocket()).then(fn)\n tunnelQueue = run.catch(() => {})\n return run\n }\n\n const forwardHttp = async (\n meta: TunnelMeta,\n body: Buffer,\n ): Promise<{ meta: TunnelResponseMeta; body: Buffer }> => {\n return runOnTunnel(async (socket) => {\n await writeTunnelRequest(socket, meta, body)\n return readTunnelResponse(socket)\n })\n }\n\n return {\n key: options.key,\n runOnTunnel,\n forwardHttp,\n close: async () => {\n if (activeSocket && !activeSocket.destroyed) {\n activeSocket.destroy()\n }\n await dht.destroy()\n },\n }\n}\n","import http from 'node:http'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport {\n flattenRequestHeaders,\n} from './protocol'\nimport { createTunnelSession } from './session'\nimport type { ConnectTunnelOptions, ConnectTunnelResult } from '../types'\n\nasync function readRequestBody(req: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = []\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))\n }\n return Buffer.concat(chunks)\n}\n\nfunction createLocalServer(\n forwardHttp: (\n meta: { method: string; path: string; headers: Record<string, string> },\n body: Buffer,\n ) => Promise<{ meta: { status: number; headers: Record<string, string> }; body: Buffer }>,\n): http.Server {\n return http.createServer((req, res) => {\n void (async () => {\n try {\n const body = await readRequestBody(req)\n const path = req.url ?? '/'\n const meta = {\n method: req.method ?? 'GET',\n path,\n headers: flattenRequestHeaders(req.headers as Record<string, string | string[] | undefined>),\n }\n\n const { meta: responseMeta, body: responseBody } = await forwardHttp(meta, body)\n\n res.writeHead(responseMeta.status, responseMeta.headers)\n res.end(responseBody)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n if (!res.headersSent) {\n res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' })\n }\n res.end(`Gateway Hyper tunnel error: ${message}`)\n }\n })()\n })\n}\n\n/**\n * Client: dial operator key and expose a localhost HTTP server that forwards through the tunnel.\n */\nexport async function connectTunnel(options: ConnectTunnelOptions): Promise<ConnectTunnelResult> {\n const host = options.host ?? '127.0.0.1'\n const port = options.port ?? 1984\n\n const session = await createTunnelSession({\n key: options.key,\n storePath: options.storePath,\n })\n\n const server = createLocalServer((meta, body) => session.forwardHttp(meta, body))\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(port, host, () => resolve())\n })\n\n const address = server.address()\n const boundPort =\n address && typeof address === 'object' ? address.port : port\n\n const baseUrl = `http://${host}:${boundPort}`\n\n return {\n key: options.key,\n host,\n port: boundPort,\n baseUrl,\n close: async () => {\n await new Promise<void>((resolve) => server.close(() => resolve()))\n await session.close()\n },\n }\n}\n\nexport function localGatewayUrl(baseUrl: string, path = ''): string {\n const base = baseUrl.replace(/\\/$/, '')\n if (!path) return base\n return path.startsWith('/') ? `${base}${path}` : `${base}/${path}`\n}\n","/**\n * Strip a mount path prefix from an incoming request URL path (including query string).\n * If the path is already unmounted (framework stripped it), returns it unchanged (with leading `/`).\n */\nexport function stripMountPath(urlPath: string, mountPath: string): string {\n const raw = urlPath || '/'\n const qIndex = raw.indexOf('?')\n const pathname = qIndex === -1 ? raw : raw.slice(0, qIndex)\n const query = qIndex === -1 ? '' : raw.slice(qIndex)\n\n const mount = (mountPath || '').replace(/\\/$/, '')\n if (!mount || mount === '/') {\n const path = pathname.startsWith('/') ? pathname : `/${pathname}`\n return `${path}${query}` || '/'\n }\n\n if (pathname === mount || pathname.startsWith(`${mount}/`)) {\n const rest = pathname.slice(mount.length)\n const path = rest.startsWith('/') ? rest : rest ? `/${rest}` : '/'\n return `${path}${query}`\n }\n\n // Already stripped by the framework (e.g. Express mount)\n const path = pathname.startsWith('/') ? pathname : `/${pathname}`\n return `${path}${query}`\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport {\n filterResponseHeaders,\n flattenRequestHeaders,\n} from './protocol'\nimport { stripMountPath } from './mountPath'\nimport type { TunnelSession } from './session'\nimport type { TunnelMeta, TunnelResponseMeta } from '../types'\n\nasync function readNodeBody(req: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = []\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))\n }\n return Buffer.concat(chunks)\n}\n\nexport async function forwardNodeRequest(\n session: TunnelSession,\n req: IncomingMessage,\n res: ServerResponse,\n mountPath: string,\n): Promise<void> {\n try {\n const body = await readNodeBody(req)\n const path = stripMountPath(req.url ?? '/', mountPath)\n const meta: TunnelMeta = {\n method: req.method ?? 'GET',\n path,\n headers: flattenRequestHeaders(req.headers as Record<string, string | string[] | undefined>),\n }\n const { meta: responseMeta, body: responseBody } = await session.forwardHttp(meta, body)\n writeNodeResponse(res, responseMeta, responseBody)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n if (!res.headersSent) {\n res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' })\n }\n res.end(`Gateway Hyper tunnel error: ${message}`)\n }\n}\n\nfunction writeNodeResponse(\n res: ServerResponse,\n meta: TunnelResponseMeta,\n body: Buffer,\n): void {\n res.writeHead(meta.status, filterResponseHeaders(meta.headers))\n res.end(body)\n}\n\nexport async function forwardFetchRequest(\n session: TunnelSession,\n request: Request,\n mountPath: string,\n): Promise<Response> {\n try {\n const url = new URL(request.url)\n const path = stripMountPath(`${url.pathname}${url.search}`, mountPath)\n const bodyBuf = Buffer.from(await request.arrayBuffer())\n const headerRecord: Record<string, string> = {}\n request.headers.forEach((value, key) => {\n headerRecord[key] = value\n })\n const meta: TunnelMeta = {\n method: request.method || 'GET',\n path,\n headers: flattenRequestHeaders(headerRecord),\n }\n const { meta: responseMeta, body: responseBody } = await session.forwardHttp(meta, bodyBuf)\n return new Response(responseBody, {\n status: responseMeta.status,\n headers: filterResponseHeaders(responseMeta.headers),\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return new Response(`Gateway Hyper tunnel error: ${message}`, {\n status: 502,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n })\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { createTunnelSession, type TunnelSession } from './session'\nimport { forwardFetchRequest, forwardNodeRequest } from './forward'\nimport type { CreateGatewayProxyOptions, GatewayProxy } from '../types'\n\nfunction resolveProxyKey(options: CreateGatewayProxyOptions): string {\n const key =\n options.key?.trim() ||\n (typeof process !== 'undefined' ? process.env.SEED_GATEWAY_HYPER_KEY?.trim() : '') ||\n ''\n if (!key) {\n throw new Error(\n 'createGatewayProxy requires options.key or SEED_GATEWAY_HYPER_KEY environment variable',\n )\n }\n return key\n}\n\n/**\n * App-server Hyper gateway proxy for hosted web apps (Path B).\n *\n * Mount on a Node route (Next.js Node runtime, Express, etc.). Keep the operator\n * Hyper key on the server only — browsers talk HTTP to `proxyBaseUrl`.\n *\n * Prefer Node.js over Bun for Holepunch natives.\n */\nexport function createGatewayProxy(options: CreateGatewayProxyOptions = {}): GatewayProxy {\n const mountPath = options.mountPath?.trim() || '/api/seed-gateway'\n const key = resolveProxyKey(options)\n\n let session: TunnelSession | null = null\n let starting: Promise<TunnelSession> | null = null\n\n const ensureSession = async (): Promise<TunnelSession> => {\n if (session) return session\n if (starting) return starting\n starting = createTunnelSession({ key, storePath: options.storePath }).then((s) => {\n session = s\n starting = null\n return s\n })\n try {\n return await starting\n } catch (err) {\n starting = null\n throw err\n }\n }\n\n const proxy: GatewayProxy = {\n mountPath,\n start: async () => {\n await ensureSession()\n },\n close: async () => {\n if (starting) {\n try {\n await starting\n } catch {\n /* ignore start failure during close */\n }\n }\n if (session) {\n await session.close()\n session = null\n }\n },\n handleNode: (req: IncomingMessage, res: ServerResponse) => {\n void (async () => {\n try {\n const s = await ensureSession()\n await forwardNodeRequest(s, req, res, mountPath)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n if (!res.headersSent) {\n res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' })\n }\n res.end(`Gateway Hyper tunnel error: ${message}`)\n }\n })()\n },\n handleFetch: async (request: Request): Promise<Response> => {\n try {\n const s = await ensureSession()\n return await forwardFetchRequest(s, request, mountPath)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return new Response(`Gateway Hyper tunnel error: ${message}`, {\n status: 502,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n })\n }\n },\n }\n\n if (options.eager) {\n void proxy.start().catch(() => {\n /* first request will surface the error */\n })\n }\n\n return proxy\n}\n","/**\n * Official Seed Protocol gateway Hyper tunnel operator key (z32).\n * Empty until ops generate and back up the first operator keypair.\n */\nexport const DEFAULT_SEED_GATEWAY_HYPER_KEY = ''\n"],"mappings":"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"}