@genkaku/protocol 0.1.16 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bridge.js CHANGED
@@ -4,7 +4,7 @@
4
4
  // escrow on Base Sepolia. No provider wire code leaks into dsh.
5
5
  import { appendFileSync } from 'node:fs';
6
6
  import { createServer } from 'node:http';
7
- import { applyLoopbackCors } from "./cors.js";
7
+ import { applyPanelCors } from "./cors.js";
8
8
  import { openEscrow, publicClientFor, readWorker, refundSession, settleSession, signReceiptPayload, walletAddress, walletClientFor, } from "./chain.js";
9
9
  import { dialWorkerAny, fetchOffers, requestSettleCosign } from "./dial.js";
10
10
  import { dedupeOffers, toWire } from "./offer.js";
@@ -533,7 +533,7 @@ export async function startOpenAiBridge(opts) {
533
533
  void (async () => {
534
534
  try {
535
535
  const path = (req.url ?? '/').split('?')[0] ?? '/';
536
- if (!applyLoopbackCors(req, res)) {
536
+ if (!applyPanelCors(req, res)) {
537
537
  res.writeHead(403, { 'content-type': 'application/json' });
538
538
  res.end(JSON.stringify({ error: { message: 'origin not allowed' } }));
539
539
  return;
package/dist/cors.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
2
  /**
3
- * Apply CORS headers when the request comes from a loopback origin.
4
- * @returns false when a browser origin outside loopback tried to call us.
3
+ * Apply CORS headers when the request comes from a host allowed to show a panel.
4
+ * @returns false when a browser origin outside that set tried to call us.
5
5
  */
6
- export declare function applyLoopbackCors(req: IncomingMessage, res: ServerResponse): boolean;
6
+ export declare function applyPanelCors(req: IncomingMessage, res: ServerResponse): boolean;
7
7
  //# sourceMappingURL=cors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../src/cors.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAIhE;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAepF"}
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../src/cors.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAOhE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAejF"}
package/dist/cors.js CHANGED
@@ -1,21 +1,32 @@
1
- // GENKAKU: CORS for the loopback control planes.
1
+ // GENKAKU: CORS for the local control planes.
2
2
  //
3
3
  // The bridge and the worker status server answer on 127.0.0.1 and used to send
4
4
  // `access-control-allow-origin: *`. Any website the user visited could then
5
- // read wallet state and, once wallet endpoints existed, key material. Only a
6
- // loopback Origin (the DSH web app) may read these responses.
5
+ // read wallet state and, once wallet endpoints existed, key material. Now only
6
+ // the two hosts that actually render a panel may read these responses:
7
+ //
8
+ // - the DSH web app served from loopback (`dsh web` in a browser), and
9
+ // - the official DSH desktop app, whose renderer runs on `dsh-app://app`.
10
+ // Chromium sends that origin on every cross-origin fetch, and the app's own
11
+ // web route authenticates with the same string.
12
+ //
13
+ // `null` stays rejected. A sandboxed iframe on any website carries that origin,
14
+ // and file:// pages do too, so allowing it would hand every page the key
15
+ // material this gate exists to protect.
7
16
  const LOOPBACK = /^https?:\/\/(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/;
17
+ /** Origin of the official DSH desktop renderer (Electron custom scheme). */
18
+ const DESKTOP_APP = 'dsh-app://app';
8
19
  /**
9
- * Apply CORS headers when the request comes from a loopback origin.
10
- * @returns false when a browser origin outside loopback tried to call us.
20
+ * Apply CORS headers when the request comes from a host allowed to show a panel.
21
+ * @returns false when a browser origin outside that set tried to call us.
11
22
  */
12
- export function applyLoopbackCors(req, res) {
23
+ export function applyPanelCors(req, res) {
13
24
  const origin = req.headers.origin;
14
25
  // curl, the HTML dashboard (same-origin navigation) and node clients send no
15
26
  // Origin; they are not subject to the browser's cross-origin rules.
16
27
  if (origin == null)
17
28
  return true;
18
- if (!LOOPBACK.test(origin))
29
+ if (!LOOPBACK.test(origin) && origin !== DESKTOP_APP)
19
30
  return false;
20
31
  res.setHeader('access-control-allow-origin', origin);
21
32
  res.setHeader('vary', 'origin');
@@ -1 +1 @@
1
- {"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../src/ollama.ts"],"names":[],"mappings":"AAWA,OAAO,EAAe,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE/E,oEAAoE;AACpE,MAAM,MAAM,WAAW,GAAG;IACxB,uDAAuD;IACvD,SAAS,EAAE,OAAO,CAAA;IAClB,2CAA2C;IAC3C,OAAO,EAAE,OAAO,CAAA;IAChB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAA;IACnB,8DAA8D;IAC9D,MAAM,EAAE,SAAS,EAAE,CAAA;IACnB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,4CAA4C;AAC5C,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,MAAM,CAItF;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,WAAW,GAAE,MAAM,CAAC,UAAwB,GAC3C,MAAM,GAAG,SAAS,CAuBpB;AASD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;IACjC,mEAAmE;IACnE,aAAa,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;IACzC,6DAA6D;IAC7D,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClH,wCAAwC;IACxC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACxC,sDAAsD;IACtD,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,gBAAgB,CA0FlG"}
1
+ {"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../src/ollama.ts"],"names":[],"mappings":"AAWA,OAAO,EAAe,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE/E,oEAAoE;AACpE,MAAM,MAAM,WAAW,GAAG;IACxB,uDAAuD;IACvD,SAAS,EAAE,OAAO,CAAA;IAClB,2CAA2C;IAC3C,OAAO,EAAE,OAAO,CAAA;IAChB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAA;IACnB,8DAA8D;IAC9D,MAAM,EAAE,SAAS,EAAE,CAAA;IACnB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,4CAA4C;AAC5C,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,MAAM,CAItF;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,WAAW,GAAE,MAAM,CAAC,UAAwB,GAC3C,MAAM,GAAG,SAAS,CAuBpB;AASD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;IACjC,mEAAmE;IACnE,aAAa,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;IACzC,6DAA6D;IAC7D,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClH,wCAAwC;IACxC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACxC,sDAAsD;IACtD,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,gBAAgB,CA4FlG"}
package/dist/ollama.js CHANGED
@@ -116,6 +116,8 @@ export function createOllamaSupervisor(host, log) {
116
116
  env: { ...process.env, OLLAMA_HOST: url.host },
117
117
  stdio: 'ignore',
118
118
  detached: false,
119
+ // Windows: do not flash a console window when the panel starts Ollama.
120
+ windowsHide: true,
119
121
  });
120
122
  child = spawned;
121
123
  spawned.once('error', (error) => { log(`ollama spawn failed (${error.message})`); });
package/dist/p2pNode.d.ts CHANGED
@@ -26,6 +26,8 @@ export type SidecarOptions = {
26
26
  /** Public relay multiaddrs (the seed VM). Dialed at boot so the circuit
27
27
  * transport can reserve a slot, which makes a NAT'd worker dialable. */
28
28
  relayHints?: string[];
29
+ /** Diagnostic sink (IPv6 fallback, listener warnings). */
30
+ log?: (line: string) => void;
29
31
  };
30
32
  /** One stored (latest) receipt per jobId — the evidence the settle co-sign
31
33
  * defends against (spend == max cumulative receipt the client piped). */ export type StoredReceipt = {
@@ -1 +1 @@
1
- {"version":3,"file":"p2pNode.d.ts","sourceRoot":"","sources":["../src/p2pNode.ts"],"names":[],"mappings":"AAcA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAA;AAClD,OAAO,EAAE,KAAK,GAAG,EAAW,MAAM,MAAM,CAAA;AAIxC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAE5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAGnD,OAAO,EAAoB,KAAK,KAAK,EAAU,MAAM,YAAY,CAAA;AAajE,OAAO,KAAK,EAAgB,YAAY,EAAiB,MAAM,oBAAoB,CAAA;AAGnF,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACzD,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,eAAO,MAAM,iBAAiB,2JAQpB,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,WAAW,CAAA;IACxB,MAAM,EAAE,qBAAqB,CAAA;IAC7B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,2EAA2E;IAC3E,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,+EAA+E;IAC/E,OAAO,EAAE,KAAK,EAAE,CAAA;IAChB,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IACzC,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;kFAC8E;IAC9E,SAAS,CAAC,EAAE,GAAG,CAAA;IACf;6EACyE;IACzE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACtB,CAAA;AAED;0EAC0E,CAAA,MAAM,MAAM,aAAa,GAAG;IACpG,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,SAAS,EAAE,KAAK,MAAM,EAAE,CAAA;IACxB,UAAU,EAAE,KAAK,MAAM,EAAE,CAAA;CAC1B,CAAA;AAkBD,+EAA+E;AAC/E,wBAAsB,cAAc,CAAC,MAAM,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAY3E;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,MAAM,EAAE,CAAA;IACzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACrB,cAAc,EAAE,MAAM,MAAM,CAAA;IAC5B,+DAA+D;IAC/D,SAAS,EAAE,MAAM,MAAM,CAAA;IACvB,qEAAqE;IACrE,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAA;CACtC,CAAA;AAOD,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAggBjF"}
1
+ {"version":3,"file":"p2pNode.d.ts","sourceRoot":"","sources":["../src/p2pNode.ts"],"names":[],"mappings":"AAcA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAA;AAClD,OAAO,EAAE,KAAK,GAAG,EAAW,MAAM,MAAM,CAAA;AAIxC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAE5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAGnD,OAAO,EAAoB,KAAK,KAAK,EAAU,MAAM,YAAY,CAAA;AAajE,OAAO,KAAK,EAAgB,YAAY,EAAiB,MAAM,oBAAoB,CAAA;AAGnF,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACzD,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,eAAO,MAAM,iBAAiB,2JAQpB,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,WAAW,CAAA;IACxB,MAAM,EAAE,qBAAqB,CAAA;IAC7B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,2EAA2E;IAC3E,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,+EAA+E;IAC/E,OAAO,EAAE,KAAK,EAAE,CAAA;IAChB,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IACzC,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;kFAC8E;IAC9E,SAAS,CAAC,EAAE,GAAG,CAAA;IACf;6EACyE;IACzE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,0DAA0D;IAC1D,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B,CAAA;AAED;0EAC0E,CAAA,MAAM,MAAM,aAAa,GAAG;IACpG,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,SAAS,EAAE,KAAK,MAAM,EAAE,CAAA;IACxB,UAAU,EAAE,KAAK,MAAM,EAAE,CAAA;CAC1B,CAAA;AAkBD,+EAA+E;AAC/E,wBAAsB,cAAc,CAAC,MAAM,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAY3E;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,MAAM,EAAE,CAAA;IACzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACrB,cAAc,EAAE,MAAM,MAAM,CAAA;IAC5B,+DAA+D;IAC/D,SAAS,EAAE,MAAM,MAAM,CAAA;IACvB,qEAAqE;IACrE,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAA;CACtC,CAAA;AAOD,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CA8gBjF"}
package/dist/p2pNode.js CHANGED
@@ -111,15 +111,29 @@ export async function createSidecar(opts) {
111
111
  ? privateKeyFromRaw(toBytes(opts.workerKey))
112
112
  : await generateKeyPair('secp256k1');
113
113
  const peerId = peerIdFromPrivateKey(privateKey);
114
- const node = await createLibp2p({
114
+ // The default listen list includes IPv6. A Windows machine (or a Linux box
115
+ // with IPv6 disabled) can refuse that listener; losing the whole worker over
116
+ // a second address family would look like "the plugin does nothing".
117
+ const init = (listen) => ({
115
118
  privateKey,
116
119
  nodeInfo: NODE_INFO,
117
- addresses: { listen: [...new Set([...opts.listen, '/p2p-circuit'])] },
120
+ addresses: { listen: [...new Set([...listen, '/p2p-circuit'])] },
118
121
  transports: [tcp(), circuitRelayTransport()],
119
122
  connectionEncrypters: [noise()],
120
123
  streamMuxers: [yamux()],
121
124
  services: { identify: identify() },
122
125
  });
126
+ let node;
127
+ try {
128
+ node = await createLibp2p(init(opts.listen));
129
+ }
130
+ catch (error) {
131
+ const ipv4 = opts.listen.filter(addr => !addr.startsWith('/ip6/'));
132
+ if (ipv4.length === opts.listen.length || ipv4.length === 0)
133
+ throw error;
134
+ opts.log?.(`IPv6 listen unavailable (${error instanceof Error ? error.message : String(error)}); retrying on IPv4 only`);
135
+ node = await createLibp2p(init(ipv4));
136
+ }
123
137
  // Connect to the public relay up front: the circuit transport reserves a
124
138
  // slot only once a HOP-capable peer is connected. Failures are non-fatal —
125
139
  // a worker with a public address is still directly dialable.
package/dist/status.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // GET /genkaku/status (JSON). Snapshot is called per request so the page and
3
3
  // the JSON always reflect the live sidecar, never a boot-time copy.
4
4
  import { createServer } from 'node:http';
5
- import { applyLoopbackCors } from "./cors.js";
5
+ import { applyPanelCors } from "./cors.js";
6
6
  /** Self-contained dashboard; mirrors the user bridge style and polls the JSON. */
7
7
  const DASHBOARD_HTML = `<!doctype html>
8
8
  <html lang="en">
@@ -171,7 +171,7 @@ export async function startStatusServer(port, snapshot, onCatalog, onMode, ollam
171
171
  void (async () => {
172
172
  try {
173
173
  const path = (req.url ?? '/').split('?')[0] ?? '/';
174
- if (!applyLoopbackCors(req, res)) {
174
+ if (!applyPanelCors(req, res)) {
175
175
  res.writeHead(403, { 'content-type': 'application/json' });
176
176
  res.end(JSON.stringify({ error: { message: 'origin not allowed' } }));
177
177
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genkaku/protocol",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "GenKaKu protocol core: on-chain worker directory, USDC escrow billing, libp2p transport, Ollama lifecycle",
5
5
  "license": "MIT",
6
6
  "type": "module",