@llui/agent 0.0.29 → 0.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/dist/client/factory.d.ts.map +1 -1
  2. package/dist/client/factory.js +59 -0
  3. package/dist/client/factory.js.map +1 -1
  4. package/dist/client/rpc/observe.d.ts +20 -0
  5. package/dist/client/rpc/observe.d.ts.map +1 -0
  6. package/dist/client/rpc/observe.js +9 -0
  7. package/dist/client/rpc/observe.js.map +1 -0
  8. package/dist/client/rpc/send-message.d.ts +32 -3
  9. package/dist/client/rpc/send-message.d.ts.map +1 -1
  10. package/dist/client/rpc/send-message.js +94 -4
  11. package/dist/client/rpc/send-message.js.map +1 -1
  12. package/dist/client/ws-client.d.ts +2 -1
  13. package/dist/client/ws-client.d.ts.map +1 -1
  14. package/dist/client/ws-client.js +4 -0
  15. package/dist/client/ws-client.js.map +1 -1
  16. package/dist/protocol.d.ts +64 -1
  17. package/dist/protocol.d.ts.map +1 -1
  18. package/dist/protocol.js.map +1 -1
  19. package/dist/server/cloudflare/durable-object.d.ts +58 -0
  20. package/dist/server/cloudflare/durable-object.d.ts.map +1 -0
  21. package/dist/server/cloudflare/durable-object.js +33 -0
  22. package/dist/server/cloudflare/durable-object.js.map +1 -0
  23. package/dist/server/cloudflare/index.d.ts +49 -0
  24. package/dist/server/cloudflare/index.d.ts.map +1 -0
  25. package/dist/server/cloudflare/index.js +49 -0
  26. package/dist/server/cloudflare/index.js.map +1 -0
  27. package/dist/server/cloudflare/worker.d.ts +40 -0
  28. package/dist/server/cloudflare/worker.d.ts.map +1 -0
  29. package/dist/server/cloudflare/worker.js +55 -0
  30. package/dist/server/cloudflare/worker.js.map +1 -0
  31. package/dist/server/core-entry.d.ts +27 -0
  32. package/dist/server/core-entry.d.ts.map +1 -0
  33. package/dist/server/core-entry.js +19 -0
  34. package/dist/server/core-entry.js.map +1 -0
  35. package/dist/server/core.d.ts +78 -0
  36. package/dist/server/core.d.ts.map +1 -0
  37. package/dist/server/core.js +84 -0
  38. package/dist/server/core.js.map +1 -0
  39. package/dist/server/factory.d.ts +5 -3
  40. package/dist/server/factory.d.ts.map +1 -1
  41. package/dist/server/factory.js +18 -58
  42. package/dist/server/factory.js.map +1 -1
  43. package/dist/server/http/mint.d.ts.map +1 -1
  44. package/dist/server/http/mint.js +2 -3
  45. package/dist/server/http/mint.js.map +1 -1
  46. package/dist/server/http/resume.js +1 -1
  47. package/dist/server/http/resume.js.map +1 -1
  48. package/dist/server/identity.d.ts +5 -1
  49. package/dist/server/identity.d.ts.map +1 -1
  50. package/dist/server/identity.js +49 -11
  51. package/dist/server/identity.js.map +1 -1
  52. package/dist/server/index.d.ts +16 -1
  53. package/dist/server/index.d.ts.map +1 -1
  54. package/dist/server/index.js +13 -1
  55. package/dist/server/index.js.map +1 -1
  56. package/dist/server/lap/confirm-result.d.ts +2 -2
  57. package/dist/server/lap/confirm-result.d.ts.map +1 -1
  58. package/dist/server/lap/confirm-result.js +1 -1
  59. package/dist/server/lap/confirm-result.js.map +1 -1
  60. package/dist/server/lap/describe.d.ts +4 -4
  61. package/dist/server/lap/describe.d.ts.map +1 -1
  62. package/dist/server/lap/describe.js +4 -4
  63. package/dist/server/lap/describe.js.map +1 -1
  64. package/dist/server/lap/forward.d.ts +2 -2
  65. package/dist/server/lap/forward.d.ts.map +1 -1
  66. package/dist/server/lap/forward.js +1 -1
  67. package/dist/server/lap/forward.js.map +1 -1
  68. package/dist/server/lap/message.d.ts +2 -2
  69. package/dist/server/lap/message.d.ts.map +1 -1
  70. package/dist/server/lap/message.js +7 -3
  71. package/dist/server/lap/message.js.map +1 -1
  72. package/dist/server/lap/observe.d.ts +27 -0
  73. package/dist/server/lap/observe.d.ts.map +1 -0
  74. package/dist/server/lap/observe.js +77 -0
  75. package/dist/server/lap/observe.js.map +1 -0
  76. package/dist/server/lap/router.d.ts.map +1 -1
  77. package/dist/server/lap/router.js +3 -0
  78. package/dist/server/lap/router.js.map +1 -1
  79. package/dist/server/lap/wait.d.ts +2 -2
  80. package/dist/server/lap/wait.d.ts.map +1 -1
  81. package/dist/server/lap/wait.js +1 -1
  82. package/dist/server/lap/wait.js.map +1 -1
  83. package/dist/server/options.d.ts +25 -1
  84. package/dist/server/options.d.ts.map +1 -1
  85. package/dist/server/options.js.map +1 -1
  86. package/dist/server/token.d.ts +7 -3
  87. package/dist/server/token.d.ts.map +1 -1
  88. package/dist/server/token.js +66 -26
  89. package/dist/server/token.js.map +1 -1
  90. package/dist/server/web/adapter.d.ts +16 -0
  91. package/dist/server/web/adapter.d.ts.map +1 -0
  92. package/dist/server/web/adapter.js +45 -0
  93. package/dist/server/web/adapter.js.map +1 -0
  94. package/dist/server/web/index.d.ts +12 -0
  95. package/dist/server/web/index.d.ts.map +1 -0
  96. package/dist/server/web/index.js +12 -0
  97. package/dist/server/web/index.js.map +1 -0
  98. package/dist/server/web/upgrade.d.ts +41 -0
  99. package/dist/server/web/upgrade.d.ts.map +1 -0
  100. package/dist/server/web/upgrade.js +96 -0
  101. package/dist/server/web/upgrade.js.map +1 -0
  102. package/dist/server/ws/pairing-registry.d.ts +84 -21
  103. package/dist/server/ws/pairing-registry.d.ts.map +1 -1
  104. package/dist/server/ws/pairing-registry.js +89 -151
  105. package/dist/server/ws/pairing-registry.js.map +1 -1
  106. package/dist/server/ws/rpc.d.ts +39 -0
  107. package/dist/server/ws/rpc.d.ts.map +1 -0
  108. package/dist/server/ws/rpc.js +126 -0
  109. package/dist/server/ws/rpc.js.map +1 -0
  110. package/dist/server/ws/upgrade.d.ts +3 -3
  111. package/dist/server/ws/upgrade.d.ts.map +1 -1
  112. package/dist/server/ws/upgrade.js +2 -2
  113. package/dist/server/ws/upgrade.js.map +1 -1
  114. package/package.json +14 -2
@@ -1,17 +1,54 @@
1
- import { createHmac, timingSafeEqual } from 'node:crypto';
2
1
  const PREFIX = 'llui-agent_';
3
- function toKeyBuffer(key) {
4
- const buf = typeof key === 'string' ? Buffer.from(key, 'utf8') : Buffer.from(key);
5
- if (buf.length < 32)
2
+ /**
3
+ * Normalize key + payload to `Uint8Array<ArrayBuffer>`, the shape
4
+ * WebCrypto wants. Newer TS lib types parameterize `Uint8Array` over the
5
+ * underlying buffer, and `TextEncoder.encode()` returns
6
+ * `Uint8Array<ArrayBufferLike>` — which `crypto.subtle.*` won't accept
7
+ * directly. A one-shot copy is cheap (HMAC inputs are bytes-small) and
8
+ * keeps the types honest without `as BufferSource` scattered at call sites.
9
+ */
10
+ function toBytes(input) {
11
+ const raw = typeof input === 'string' ? new TextEncoder().encode(input) : input;
12
+ const buf = new ArrayBuffer(raw.byteLength);
13
+ const out = new Uint8Array(buf);
14
+ out.set(raw);
15
+ return out;
16
+ }
17
+ function toKeyBytes(key) {
18
+ if (typeof key === 'string') {
19
+ if (key.length < 32)
20
+ throw new Error('signingKey must be at least 32 bytes');
21
+ }
22
+ else if (key.byteLength < 32) {
6
23
  throw new Error('signingKey must be at least 32 bytes');
7
- return buf;
24
+ }
25
+ return toBytes(key);
8
26
  }
9
- function b64url(buf) {
10
- return buf.toString('base64url');
27
+ /**
28
+ * Import a signing key as a WebCrypto `CryptoKey`. Done per call so the
29
+ * caller doesn't have to pre-import and pass it around; the cost is a
30
+ * microtask per sign/verify, which is negligible for our call volume
31
+ * (tokens verified once per LAP HTTP request).
32
+ */
33
+ async function importHmacKey(key, usages) {
34
+ return crypto.subtle.importKey('raw', toKeyBytes(key), { name: 'HMAC', hash: 'SHA-256' }, false, usages);
11
35
  }
12
- function b64urlDecode(s) {
36
+ function toBase64Url(bytes) {
37
+ // btoa needs a binary string; build it manually to avoid ArrayBuffer/Uint8Array quirks.
38
+ let bin = '';
39
+ for (let i = 0; i < bytes.byteLength; i++)
40
+ bin += String.fromCharCode(bytes[i]);
41
+ return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
42
+ }
43
+ function fromBase64Url(s) {
13
44
  try {
14
- return Buffer.from(s, 'base64url');
45
+ const b64 = s.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat((4 - (s.length % 4)) % 4);
46
+ const bin = atob(b64);
47
+ const buf = new ArrayBuffer(bin.length);
48
+ const bytes = new Uint8Array(buf);
49
+ for (let i = 0; i < bin.length; i++)
50
+ bytes[i] = bin.charCodeAt(i);
51
+ return bytes;
15
52
  }
16
53
  catch {
17
54
  return null;
@@ -19,20 +56,24 @@ function b64urlDecode(s) {
19
56
  }
20
57
  /**
21
58
  * Serialize a payload to `llui-agent_<base64url(json)>.<base64url(hmac)>`.
22
- * See spec §6.1.
59
+ * See spec §6.1. Async because WebCrypto's HMAC sign/verify is the
60
+ * cross-runtime standard; Node, Cloudflare, Deno, and Bun all expose
61
+ * `crypto.subtle` identically.
23
62
  */
24
- export function signToken(payload, key) {
25
- const keyBuf = toKeyBuffer(key);
26
- const jsonBuf = Buffer.from(JSON.stringify(payload), 'utf8');
27
- const payloadPart = b64url(jsonBuf);
28
- const mac = createHmac('sha256', keyBuf).update(payloadPart).digest();
29
- const sigPart = b64url(mac);
63
+ export async function signToken(payload, key) {
64
+ const cryptoKey = await importHmacKey(key, ['sign']);
65
+ const jsonBytes = toBytes(JSON.stringify(payload));
66
+ const payloadPart = toBase64Url(jsonBytes);
67
+ const macBuf = await crypto.subtle.sign('HMAC', cryptoKey, toBytes(payloadPart));
68
+ const sigPart = toBase64Url(new Uint8Array(macBuf));
30
69
  return (PREFIX + payloadPart + '.' + sigPart);
31
70
  }
32
71
  /**
33
72
  * Verify the signature, parse the payload, and check expiry.
73
+ * `crypto.subtle.verify` does the constant-time compare internally,
74
+ * so we don't need a separate `timingSafeEqual`.
34
75
  */
35
- export function verifyToken(token, key, nowSec = Math.floor(Date.now() / 1000)) {
76
+ export async function verifyToken(token, key, nowSec = Math.floor(Date.now() / 1000)) {
36
77
  if (!token.startsWith(PREFIX))
37
78
  return { kind: 'invalid', reason: 'malformed' };
38
79
  const body = token.slice(PREFIX.length);
@@ -41,20 +82,19 @@ export function verifyToken(token, key, nowSec = Math.floor(Date.now() / 1000))
41
82
  return { kind: 'invalid', reason: 'malformed' };
42
83
  const payloadPart = body.slice(0, dot);
43
84
  const sigPart = body.slice(dot + 1);
44
- const sigBuf = b64urlDecode(sigPart);
45
- if (!sigBuf)
85
+ const sigBytes = fromBase64Url(sigPart);
86
+ if (!sigBytes)
46
87
  return { kind: 'invalid', reason: 'malformed' };
47
- const keyBuf = toKeyBuffer(key);
48
- const expected = createHmac('sha256', keyBuf).update(payloadPart).digest();
49
- if (expected.length !== sigBuf.length || !timingSafeEqual(expected, sigBuf)) {
88
+ const cryptoKey = await importHmacKey(key, ['verify']);
89
+ const ok = await crypto.subtle.verify('HMAC', cryptoKey, sigBytes, toBytes(payloadPart));
90
+ if (!ok)
50
91
  return { kind: 'invalid', reason: 'bad-signature' };
51
- }
52
- const jsonBuf = b64urlDecode(payloadPart);
53
- if (!jsonBuf)
92
+ const jsonBytes = fromBase64Url(payloadPart);
93
+ if (!jsonBytes)
54
94
  return { kind: 'invalid', reason: 'malformed' };
55
95
  let parsed;
56
96
  try {
57
- parsed = JSON.parse(jsonBuf.toString('utf8'));
97
+ parsed = JSON.parse(new TextDecoder().decode(jsonBytes));
58
98
  }
59
99
  catch {
60
100
  return { kind: 'invalid', reason: 'malformed' };
@@ -1 +1 @@
1
- {"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/server/token.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHmac, timingSafeEqual } from 'node:crypto'\nimport type { AgentToken } from '../protocol.js'\n\nexport type TokenPayload = {\n tid: string\n iat: number\n exp: number\n scope: 'agent'\n}\n\nexport type VerifyResult =\n | { kind: 'ok'; payload: TokenPayload }\n | { kind: 'invalid'; reason: 'malformed' | 'bad-signature' | 'expired' }\n\nconst PREFIX = 'llui-agent_'\n\nfunction toKeyBuffer(key: string | Uint8Array): Buffer {\n const buf = typeof key === 'string' ? Buffer.from(key, 'utf8') : Buffer.from(key)\n if (buf.length < 32) throw new Error('signingKey must be at least 32 bytes')\n return buf\n}\n\nfunction b64url(buf: Buffer): string {\n return buf.toString('base64url')\n}\n\nfunction b64urlDecode(s: string): Buffer | null {\n try {\n return Buffer.from(s, 'base64url')\n } catch {\n return null\n }\n}\n\n/**\n * Serialize a payload to `llui-agent_<base64url(json)>.<base64url(hmac)>`.\n * See spec §6.1.\n */\nexport function signToken(payload: TokenPayload, key: string | Uint8Array): AgentToken {\n const keyBuf = toKeyBuffer(key)\n const jsonBuf = Buffer.from(JSON.stringify(payload), 'utf8')\n const payloadPart = b64url(jsonBuf)\n const mac = createHmac('sha256', keyBuf).update(payloadPart).digest()\n const sigPart = b64url(mac)\n return (PREFIX + payloadPart + '.' + sigPart) as AgentToken\n}\n\n/**\n * Verify the signature, parse the payload, and check expiry.\n */\nexport function verifyToken(\n token: string,\n key: string | Uint8Array,\n nowSec: number = Math.floor(Date.now() / 1000),\n): VerifyResult {\n if (!token.startsWith(PREFIX)) return { kind: 'invalid', reason: 'malformed' }\n const body = token.slice(PREFIX.length)\n const dot = body.indexOf('.')\n if (dot < 0) return { kind: 'invalid', reason: 'malformed' }\n\n const payloadPart = body.slice(0, dot)\n const sigPart = body.slice(dot + 1)\n const sigBuf = b64urlDecode(sigPart)\n if (!sigBuf) return { kind: 'invalid', reason: 'malformed' }\n\n const keyBuf = toKeyBuffer(key)\n const expected = createHmac('sha256', keyBuf).update(payloadPart).digest()\n if (expected.length !== sigBuf.length || !timingSafeEqual(expected, sigBuf)) {\n return { kind: 'invalid', reason: 'bad-signature' }\n }\n\n const jsonBuf = b64urlDecode(payloadPart)\n if (!jsonBuf) return { kind: 'invalid', reason: 'malformed' }\n let parsed: unknown\n try {\n parsed = JSON.parse(jsonBuf.toString('utf8'))\n } catch {\n return { kind: 'invalid', reason: 'malformed' }\n }\n\n if (!isTokenPayload(parsed)) return { kind: 'invalid', reason: 'malformed' }\n if (parsed.exp <= nowSec) return { kind: 'invalid', reason: 'expired' }\n return { kind: 'ok', payload: parsed }\n}\n\nfunction isTokenPayload(x: unknown): x is TokenPayload {\n if (!x || typeof x !== 'object') return false\n const o = x as Record<string, unknown>\n return (\n typeof o.tid === 'string' &&\n typeof o.iat === 'number' &&\n typeof o.exp === 'number' &&\n o.scope === 'agent'\n )\n}\n"]}
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/server/token.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentToken } from '../protocol.js'\n\nexport type TokenPayload = {\n tid: string\n iat: number\n exp: number\n scope: 'agent'\n}\n\nexport type VerifyResult =\n | { kind: 'ok'; payload: TokenPayload }\n | { kind: 'invalid'; reason: 'malformed' | 'bad-signature' | 'expired' }\n\nconst PREFIX = 'llui-agent_'\n\n/**\n * Normalize key + payload to `Uint8Array<ArrayBuffer>`, the shape\n * WebCrypto wants. Newer TS lib types parameterize `Uint8Array` over the\n * underlying buffer, and `TextEncoder.encode()` returns\n * `Uint8Array<ArrayBufferLike>` — which `crypto.subtle.*` won't accept\n * directly. A one-shot copy is cheap (HMAC inputs are bytes-small) and\n * keeps the types honest without `as BufferSource` scattered at call sites.\n */\nfunction toBytes(input: string | Uint8Array): Uint8Array<ArrayBuffer> {\n const raw = typeof input === 'string' ? new TextEncoder().encode(input) : input\n const buf = new ArrayBuffer(raw.byteLength)\n const out = new Uint8Array(buf)\n out.set(raw)\n return out\n}\n\nfunction toKeyBytes(key: string | Uint8Array): Uint8Array<ArrayBuffer> {\n if (typeof key === 'string') {\n if (key.length < 32) throw new Error('signingKey must be at least 32 bytes')\n } else if (key.byteLength < 32) {\n throw new Error('signingKey must be at least 32 bytes')\n }\n return toBytes(key)\n}\n\n/**\n * Import a signing key as a WebCrypto `CryptoKey`. Done per call so the\n * caller doesn't have to pre-import and pass it around; the cost is a\n * microtask per sign/verify, which is negligible for our call volume\n * (tokens verified once per LAP HTTP request).\n */\nasync function importHmacKey(key: string | Uint8Array, usages: KeyUsage[]): Promise<CryptoKey> {\n return crypto.subtle.importKey(\n 'raw',\n toKeyBytes(key),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n usages,\n )\n}\n\nfunction toBase64Url(bytes: Uint8Array): string {\n // btoa needs a binary string; build it manually to avoid ArrayBuffer/Uint8Array quirks.\n let bin = ''\n for (let i = 0; i < bytes.byteLength; i++) bin += String.fromCharCode(bytes[i]!)\n return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nfunction fromBase64Url(s: string): Uint8Array<ArrayBuffer> | null {\n try {\n const b64 = s.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat((4 - (s.length % 4)) % 4)\n const bin = atob(b64)\n const buf = new ArrayBuffer(bin.length)\n const bytes = new Uint8Array(buf)\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i)\n return bytes\n } catch {\n return null\n }\n}\n\n/**\n * Serialize a payload to `llui-agent_<base64url(json)>.<base64url(hmac)>`.\n * See spec §6.1. Async because WebCrypto's HMAC sign/verify is the\n * cross-runtime standard; Node, Cloudflare, Deno, and Bun all expose\n * `crypto.subtle` identically.\n */\nexport async function signToken(\n payload: TokenPayload,\n key: string | Uint8Array,\n): Promise<AgentToken> {\n const cryptoKey = await importHmacKey(key, ['sign'])\n const jsonBytes = toBytes(JSON.stringify(payload))\n const payloadPart = toBase64Url(jsonBytes)\n const macBuf = await crypto.subtle.sign('HMAC', cryptoKey, toBytes(payloadPart))\n const sigPart = toBase64Url(new Uint8Array(macBuf))\n return (PREFIX + payloadPart + '.' + sigPart) as AgentToken\n}\n\n/**\n * Verify the signature, parse the payload, and check expiry.\n * `crypto.subtle.verify` does the constant-time compare internally,\n * so we don't need a separate `timingSafeEqual`.\n */\nexport async function verifyToken(\n token: string,\n key: string | Uint8Array,\n nowSec: number = Math.floor(Date.now() / 1000),\n): Promise<VerifyResult> {\n if (!token.startsWith(PREFIX)) return { kind: 'invalid', reason: 'malformed' }\n const body = token.slice(PREFIX.length)\n const dot = body.indexOf('.')\n if (dot < 0) return { kind: 'invalid', reason: 'malformed' }\n\n const payloadPart = body.slice(0, dot)\n const sigPart = body.slice(dot + 1)\n const sigBytes = fromBase64Url(sigPart)\n if (!sigBytes) return { kind: 'invalid', reason: 'malformed' }\n\n const cryptoKey = await importHmacKey(key, ['verify'])\n const ok = await crypto.subtle.verify('HMAC', cryptoKey, sigBytes, toBytes(payloadPart))\n if (!ok) return { kind: 'invalid', reason: 'bad-signature' }\n\n const jsonBytes = fromBase64Url(payloadPart)\n if (!jsonBytes) return { kind: 'invalid', reason: 'malformed' }\n let parsed: unknown\n try {\n parsed = JSON.parse(new TextDecoder().decode(jsonBytes))\n } catch {\n return { kind: 'invalid', reason: 'malformed' }\n }\n\n if (!isTokenPayload(parsed)) return { kind: 'invalid', reason: 'malformed' }\n if (parsed.exp <= nowSec) return { kind: 'invalid', reason: 'expired' }\n return { kind: 'ok', payload: parsed }\n}\n\nfunction isTokenPayload(x: unknown): x is TokenPayload {\n if (!x || typeof x !== 'object') return false\n const o = x as Record<string, unknown>\n return (\n typeof o.tid === 'string' &&\n typeof o.iat === 'number' &&\n typeof o.exp === 'number' &&\n o.scope === 'agent'\n )\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import type { PairingConnection } from '../ws/pairing-registry.js';
2
+ /**
3
+ * Wrap a WHATWG `WebSocket` in a `PairingConnection`. This is the
4
+ * common denominator across Cloudflare Workers (`WebSocketPair`
5
+ * server half), Deno (`Deno.upgradeWebSocket().socket`), Bun's
6
+ * upgraded socket, and any other runtime that exposes a
7
+ * standards-compliant WebSocket object.
8
+ *
9
+ * The input type is intentionally the browser/global `WebSocket`
10
+ * interface — *not* the Node `ws` library's variant, which uses an
11
+ * EventEmitter API (`on('message', ...)`) rather than
12
+ * `addEventListener('message', ...)`. Use `./node/upgrade.ts` for
13
+ * the `ws` library path.
14
+ */
15
+ export declare function createWHATWGPairingConnection(socket: WebSocket): PairingConnection;
16
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/server/web/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAGlE;;;;;;;;;;;;GAYG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,GAAG,iBAAiB,CA4BlF"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Wrap a WHATWG `WebSocket` in a `PairingConnection`. This is the
3
+ * common denominator across Cloudflare Workers (`WebSocketPair`
4
+ * server half), Deno (`Deno.upgradeWebSocket().socket`), Bun's
5
+ * upgraded socket, and any other runtime that exposes a
6
+ * standards-compliant WebSocket object.
7
+ *
8
+ * The input type is intentionally the browser/global `WebSocket`
9
+ * interface — *not* the Node `ws` library's variant, which uses an
10
+ * EventEmitter API (`on('message', ...)`) rather than
11
+ * `addEventListener('message', ...)`. Use `./node/upgrade.ts` for
12
+ * the `ws` library path.
13
+ */
14
+ export function createWHATWGPairingConnection(socket) {
15
+ return {
16
+ send(frame) {
17
+ socket.send(JSON.stringify(frame));
18
+ },
19
+ onFrame(handler) {
20
+ socket.addEventListener('message', (ev) => {
21
+ const data = ev.data;
22
+ const raw = typeof data === 'string' ? data : new TextDecoder().decode(data);
23
+ try {
24
+ const parsed = JSON.parse(raw);
25
+ handler(parsed);
26
+ }
27
+ catch {
28
+ // Ignore malformed frames — one bad frame shouldn't tear down the pairing.
29
+ }
30
+ });
31
+ },
32
+ onClose(handler) {
33
+ socket.addEventListener('close', () => handler());
34
+ },
35
+ close() {
36
+ try {
37
+ socket.close();
38
+ }
39
+ catch {
40
+ // Some runtimes throw if you close twice; swallow.
41
+ }
42
+ },
43
+ };
44
+ }
45
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/server/web/adapter.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,6BAA6B,CAAC,MAAiB;IAC7D,OAAO;QACL,IAAI,CAAC,KAAkB;YACrB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QACpC,CAAC;QACD,OAAO,CAAC,OAAO;YACb,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE;gBACxC,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,CAAA;gBACpB,MAAM,GAAG,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAmB,CAAC,CAAA;gBAC3F,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAA;oBAC7C,OAAO,CAAC,MAAM,CAAC,CAAA;gBACjB,CAAC;gBAAC,MAAM,CAAC;oBACP,2EAA2E;gBAC7E,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,CAAC,OAAO;YACb,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAA;QACnD,CAAC;QACD,KAAK;YACH,IAAI,CAAC;gBACH,MAAM,CAAC,KAAK,EAAE,CAAA;YAChB,CAAC;YAAC,MAAM,CAAC;gBACP,mDAAmD;YACrD,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC","sourcesContent":["import type { PairingConnection } from '../ws/pairing-registry.js'\nimport type { ClientFrame, ServerFrame } from '../../protocol.js'\n\n/**\n * Wrap a WHATWG `WebSocket` in a `PairingConnection`. This is the\n * common denominator across Cloudflare Workers (`WebSocketPair`\n * server half), Deno (`Deno.upgradeWebSocket().socket`), Bun's\n * upgraded socket, and any other runtime that exposes a\n * standards-compliant WebSocket object.\n *\n * The input type is intentionally the browser/global `WebSocket`\n * interface — *not* the Node `ws` library's variant, which uses an\n * EventEmitter API (`on('message', ...)`) rather than\n * `addEventListener('message', ...)`. Use `./node/upgrade.ts` for\n * the `ws` library path.\n */\nexport function createWHATWGPairingConnection(socket: WebSocket): PairingConnection {\n return {\n send(frame: ServerFrame) {\n socket.send(JSON.stringify(frame))\n },\n onFrame(handler) {\n socket.addEventListener('message', (ev) => {\n const data = ev.data\n const raw = typeof data === 'string' ? data : new TextDecoder().decode(data as ArrayBuffer)\n try {\n const parsed = JSON.parse(raw) as ClientFrame\n handler(parsed)\n } catch {\n // Ignore malformed frames — one bad frame shouldn't tear down the pairing.\n }\n })\n },\n onClose(handler) {\n socket.addEventListener('close', () => handler())\n },\n close() {\n try {\n socket.close()\n } catch {\n // Some runtimes throw if you close twice; swallow.\n }\n },\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Web-runtime adapters. Use this sub-path from Cloudflare Workers,
3
+ * Deno, Bun, or any other runtime that speaks WHATWG `Request` /
4
+ * `Response` and exposes native WebSocket upgrade primitives.
5
+ *
6
+ * Pair with `@llui/agent/server/core`'s `createLluiAgentCore` — that
7
+ * builds the runtime-neutral router and registry; the handlers
8
+ * exported here handle the WebSocket upgrade half.
9
+ */
10
+ export { createWHATWGPairingConnection } from './adapter.js';
11
+ export { handleCloudflareUpgrade, handleDenoUpgrade, extractToken } from './upgrade.js';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/web/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,6BAA6B,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Web-runtime adapters. Use this sub-path from Cloudflare Workers,
3
+ * Deno, Bun, or any other runtime that speaks WHATWG `Request` /
4
+ * `Response` and exposes native WebSocket upgrade primitives.
5
+ *
6
+ * Pair with `@llui/agent/server/core`'s `createLluiAgentCore` — that
7
+ * builds the runtime-neutral router and registry; the handlers
8
+ * exported here handle the WebSocket upgrade half.
9
+ */
10
+ export { createWHATWGPairingConnection } from './adapter.js';
11
+ export { handleCloudflareUpgrade, handleDenoUpgrade, extractToken } from './upgrade.js';
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/web/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,6BAA6B,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA","sourcesContent":["/**\n * Web-runtime adapters. Use this sub-path from Cloudflare Workers,\n * Deno, Bun, or any other runtime that speaks WHATWG `Request` /\n * `Response` and exposes native WebSocket upgrade primitives.\n *\n * Pair with `@llui/agent/server/core`'s `createLluiAgentCore` — that\n * builds the runtime-neutral router and registry; the handlers\n * exported here handle the WebSocket upgrade half.\n */\nexport { createWHATWGPairingConnection } from './adapter.js'\nexport { handleCloudflareUpgrade, handleDenoUpgrade, extractToken } from './upgrade.js'\n"]}
@@ -0,0 +1,41 @@
1
+ import type { AgentCoreHandle } from '../core.js';
2
+ /**
3
+ * Extract the bearer token from a LAP WebSocket upgrade request.
4
+ * Accepts the token on either `?token=` or `Authorization: Bearer` —
5
+ * query-string is the common pattern because browsers can't set
6
+ * arbitrary headers on WebSocket construction.
7
+ */
8
+ export declare function extractToken(req: Request): string | null;
9
+ /**
10
+ * Cloudflare Workers handler. Accepts a WebSocket upgrade using
11
+ * `WebSocketPair`, validates the token via
12
+ * `agent.acceptConnection`, and returns the 101 upgrade Response.
13
+ *
14
+ * Usage:
15
+ * ```ts
16
+ * const agent = createLluiAgentCore({ signingKey: env.AGENT_KEY })
17
+ * export default {
18
+ * async fetch(req, env) {
19
+ * const url = new URL(req.url)
20
+ * if (url.pathname === '/agent/ws') return handleCloudflareUpgrade(req, agent)
21
+ * return (await agent.router(req)) ?? new Response('Not Found', { status: 404 })
22
+ * },
23
+ * }
24
+ * ```
25
+ */
26
+ export declare function handleCloudflareUpgrade(req: Request, agent: AgentCoreHandle): Promise<Response>;
27
+ /**
28
+ * Deno handler. Uses `Deno.upgradeWebSocket(req)` to produce the
29
+ * response + socket pair, then plugs the socket into the registry.
30
+ *
31
+ * Usage:
32
+ * ```ts
33
+ * Deno.serve(async (req) => {
34
+ * const url = new URL(req.url)
35
+ * if (url.pathname === '/agent/ws') return handleDenoUpgrade(req, agent)
36
+ * return (await agent.router(req)) ?? new Response('Not Found', { status: 404 })
37
+ * })
38
+ * ```
39
+ */
40
+ export declare function handleDenoUpgrade(req: Request, agent: AgentCoreHandle): Promise<Response>;
41
+ //# sourceMappingURL=upgrade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../../src/server/web/upgrade.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAGjD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAOxD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,QAAQ,CAAC,CAmCnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,CA+B/F"}
@@ -0,0 +1,96 @@
1
+ import { createWHATWGPairingConnection } from './adapter.js';
2
+ /**
3
+ * Extract the bearer token from a LAP WebSocket upgrade request.
4
+ * Accepts the token on either `?token=` or `Authorization: Bearer` —
5
+ * query-string is the common pattern because browsers can't set
6
+ * arbitrary headers on WebSocket construction.
7
+ */
8
+ export function extractToken(req) {
9
+ const url = new URL(req.url);
10
+ const q = url.searchParams.get('token');
11
+ if (q)
12
+ return q;
13
+ const auth = req.headers.get('authorization');
14
+ if (auth?.startsWith('Bearer '))
15
+ return auth.slice('Bearer '.length);
16
+ return null;
17
+ }
18
+ /**
19
+ * Cloudflare Workers handler. Accepts a WebSocket upgrade using
20
+ * `WebSocketPair`, validates the token via
21
+ * `agent.acceptConnection`, and returns the 101 upgrade Response.
22
+ *
23
+ * Usage:
24
+ * ```ts
25
+ * const agent = createLluiAgentCore({ signingKey: env.AGENT_KEY })
26
+ * export default {
27
+ * async fetch(req, env) {
28
+ * const url = new URL(req.url)
29
+ * if (url.pathname === '/agent/ws') return handleCloudflareUpgrade(req, agent)
30
+ * return (await agent.router(req)) ?? new Response('Not Found', { status: 404 })
31
+ * },
32
+ * }
33
+ * ```
34
+ */
35
+ export async function handleCloudflareUpgrade(req, agent) {
36
+ if (req.headers.get('upgrade') !== 'websocket') {
37
+ return new Response('Expected upgrade: websocket', { status: 426 });
38
+ }
39
+ const token = extractToken(req);
40
+ if (!token)
41
+ return new Response('Unauthorized', { status: 401 });
42
+ // `WebSocketPair` is a Cloudflare Workers global. We reference it
43
+ // through `globalThis` so importing this module in non-CF runtimes
44
+ // (e.g. during type-checking on Node) doesn't crash.
45
+ const Pair = globalThis.WebSocketPair;
46
+ if (!Pair) {
47
+ return new Response('WebSocketPair unavailable in this runtime', { status: 501 });
48
+ }
49
+ const pair = new Pair();
50
+ const client = pair[0];
51
+ const server = pair[1];
52
+ server.accept();
53
+ const conn = createWHATWGPairingConnection(server);
54
+ const result = await agent.acceptConnection(token, conn);
55
+ if (!result.ok) {
56
+ conn.close();
57
+ return new Response(result.code, { status: result.status });
58
+ }
59
+ // `webSocket` on ResponseInit is Cloudflare-specific; cast to satisfy
60
+ // the standard lib types.
61
+ return new Response(null, { status: 101, webSocket: client });
62
+ }
63
+ /**
64
+ * Deno handler. Uses `Deno.upgradeWebSocket(req)` to produce the
65
+ * response + socket pair, then plugs the socket into the registry.
66
+ *
67
+ * Usage:
68
+ * ```ts
69
+ * Deno.serve(async (req) => {
70
+ * const url = new URL(req.url)
71
+ * if (url.pathname === '/agent/ws') return handleDenoUpgrade(req, agent)
72
+ * return (await agent.router(req)) ?? new Response('Not Found', { status: 404 })
73
+ * })
74
+ * ```
75
+ */
76
+ export async function handleDenoUpgrade(req, agent) {
77
+ const token = extractToken(req);
78
+ if (!token)
79
+ return new Response('Unauthorized', { status: 401 });
80
+ const Deno_ = globalThis.Deno;
81
+ if (!Deno_) {
82
+ return new Response('Deno.upgradeWebSocket unavailable in this runtime', { status: 501 });
83
+ }
84
+ const { socket, response } = Deno_.upgradeWebSocket(req);
85
+ const conn = createWHATWGPairingConnection(socket);
86
+ // Deno opens the socket asynchronously; validate the token first,
87
+ // then register on `open` so frames aren't missed.
88
+ socket.addEventListener('open', () => {
89
+ void agent.acceptConnection(token, conn).then((result) => {
90
+ if (!result.ok)
91
+ conn.close();
92
+ });
93
+ }, { once: true });
94
+ return response;
95
+ }
96
+ //# sourceMappingURL=upgrade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../../src/server/web/upgrade.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,cAAc,CAAA;AAE5D;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5B,MAAM,CAAC,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACvC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAA;IACf,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;IAC7C,IAAI,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;IACpE,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,GAAY,EACZ,KAAsB;IAEtB,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,WAAW,EAAE,CAAC;QAC/C,OAAO,IAAI,QAAQ,CAAC,6BAA6B,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IACrE,CAAC;IACD,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;IAC/B,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,QAAQ,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IAEhE,kEAAkE;IAClE,mEAAmE;IACnE,qDAAqD;IACrD,MAAM,IAAI,GACR,UACD,CAAC,aAAa,CAAA;IACf,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,IAAI,QAAQ,CAAC,2CAA2C,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IACnF,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAA;IACvB,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;IACtB,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAE,CAGtB;IAAC,MAA4C,CAAC,MAAM,EAAE,CAAA;IAEvD,MAAM,IAAI,GAAG,6BAA6B,CAAC,MAAM,CAAC,CAAA;IAClD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IACxD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;IAC7D,CAAC;IAED,sEAAsE;IACtE,0BAA0B;IAC1B,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAEzD,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAY,EAAE,KAAsB;IAC1E,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;IAC/B,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,QAAQ,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IAEhE,MAAM,KAAK,GACT,UAKD,CAAC,IAAI,CAAA;IACN,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,QAAQ,CAAC,mDAAmD,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IAC3F,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAA;IACxD,MAAM,IAAI,GAAG,6BAA6B,CAAC,MAAM,CAAC,CAAA;IAElD,kEAAkE;IAClE,mDAAmD;IACnD,MAAM,CAAC,gBAAgB,CACrB,MAAM,EACN,GAAG,EAAE;QACH,KAAK,KAAK,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACvD,IAAI,CAAC,MAAM,CAAC,EAAE;gBAAE,IAAI,CAAC,KAAK,EAAE,CAAA;QAC9B,CAAC,CAAC,CAAA;IACJ,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAA;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC","sourcesContent":["import type { AgentCoreHandle } from '../core.js'\nimport { createWHATWGPairingConnection } from './adapter.js'\n\n/**\n * Extract the bearer token from a LAP WebSocket upgrade request.\n * Accepts the token on either `?token=` or `Authorization: Bearer` —\n * query-string is the common pattern because browsers can't set\n * arbitrary headers on WebSocket construction.\n */\nexport function extractToken(req: Request): string | null {\n const url = new URL(req.url)\n const q = url.searchParams.get('token')\n if (q) return q\n const auth = req.headers.get('authorization')\n if (auth?.startsWith('Bearer ')) return auth.slice('Bearer '.length)\n return null\n}\n\n/**\n * Cloudflare Workers handler. Accepts a WebSocket upgrade using\n * `WebSocketPair`, validates the token via\n * `agent.acceptConnection`, and returns the 101 upgrade Response.\n *\n * Usage:\n * ```ts\n * const agent = createLluiAgentCore({ signingKey: env.AGENT_KEY })\n * export default {\n * async fetch(req, env) {\n * const url = new URL(req.url)\n * if (url.pathname === '/agent/ws') return handleCloudflareUpgrade(req, agent)\n * return (await agent.router(req)) ?? new Response('Not Found', { status: 404 })\n * },\n * }\n * ```\n */\nexport async function handleCloudflareUpgrade(\n req: Request,\n agent: AgentCoreHandle,\n): Promise<Response> {\n if (req.headers.get('upgrade') !== 'websocket') {\n return new Response('Expected upgrade: websocket', { status: 426 })\n }\n const token = extractToken(req)\n if (!token) return new Response('Unauthorized', { status: 401 })\n\n // `WebSocketPair` is a Cloudflare Workers global. We reference it\n // through `globalThis` so importing this module in non-CF runtimes\n // (e.g. during type-checking on Node) doesn't crash.\n const Pair = (\n globalThis as unknown as { WebSocketPair?: new () => { 0: WebSocket; 1: WebSocket } }\n ).WebSocketPair\n if (!Pair) {\n return new Response('WebSocketPair unavailable in this runtime', { status: 501 })\n }\n const pair = new Pair()\n const client = pair[0]\n const server = pair[1]!\n // `accept()` on the server half is Cloudflare-specific — it tells\n // the runtime the Worker will handle the WebSocket itself.\n ;(server as unknown as { accept: () => void }).accept()\n\n const conn = createWHATWGPairingConnection(server)\n const result = await agent.acceptConnection(token, conn)\n if (!result.ok) {\n conn.close()\n return new Response(result.code, { status: result.status })\n }\n\n // `webSocket` on ResponseInit is Cloudflare-specific; cast to satisfy\n // the standard lib types.\n return new Response(null, { status: 101, webSocket: client } as ResponseInit & {\n webSocket: WebSocket\n })\n}\n\n/**\n * Deno handler. Uses `Deno.upgradeWebSocket(req)` to produce the\n * response + socket pair, then plugs the socket into the registry.\n *\n * Usage:\n * ```ts\n * Deno.serve(async (req) => {\n * const url = new URL(req.url)\n * if (url.pathname === '/agent/ws') return handleDenoUpgrade(req, agent)\n * return (await agent.router(req)) ?? new Response('Not Found', { status: 404 })\n * })\n * ```\n */\nexport async function handleDenoUpgrade(req: Request, agent: AgentCoreHandle): Promise<Response> {\n const token = extractToken(req)\n if (!token) return new Response('Unauthorized', { status: 401 })\n\n const Deno_ = (\n globalThis as unknown as {\n Deno?: {\n upgradeWebSocket: (req: Request) => { socket: WebSocket; response: Response }\n }\n }\n ).Deno\n if (!Deno_) {\n return new Response('Deno.upgradeWebSocket unavailable in this runtime', { status: 501 })\n }\n\n const { socket, response } = Deno_.upgradeWebSocket(req)\n const conn = createWHATWGPairingConnection(socket)\n\n // Deno opens the socket asynchronously; validate the token first,\n // then register on `open` so frames aren't missed.\n socket.addEventListener(\n 'open',\n () => {\n void agent.acceptConnection(token, conn).then((result) => {\n if (!result.ok) conn.close()\n })\n },\n { once: true },\n )\n\n return response\n}\n"]}
@@ -1,7 +1,11 @@
1
1
  import type { ClientFrame, ServerFrame, HelloFrame, LogEntry } from '../../protocol.js';
2
+ import { type RpcOptions, type RpcError } from './rpc.js';
3
+ export type { RpcOptions, RpcError };
2
4
  /**
3
- * Thin abstraction over a WebSocket so the registry is testable with
4
- * a fake EventEmitter-style mock.
5
+ * Thin abstraction over a single paired WebSocket. Consumed by the
6
+ * registry implementations; runtime-specific adapters (`ws`-lib,
7
+ * `WebSocketPair`, `Deno.upgradeWebSocket`, `Bun.serve` upgrade) build
8
+ * one of these and pass it to `registry.register()`.
5
9
  */
6
10
  export interface PairingConnection {
7
11
  send(frame: ServerFrame): void;
@@ -9,35 +13,85 @@ export interface PairingConnection {
9
13
  onClose(handler: () => void): void;
10
14
  close(): void;
11
15
  }
12
- export type RpcError = {
13
- code: 'paused' | 'invalid' | 'timeout' | 'schema-error' | 'internal' | string;
14
- detail?: string;
15
- };
16
- export type RpcOptions = {
17
- timeoutMs?: number;
18
- };
19
16
  /**
20
- * Tracks live browser pairings and correlates rpc requests with replies.
21
- * One instance per server; shared by all LAP handlers + the upgrade
22
- * handler. Spec §10.4–§10.5.
17
+ * A per-call frame subscriber. Return `true` to remove this
18
+ * subscriber (one-shot), or `false` to keep receiving. The registry
19
+ * dispatches every inbound `ClientFrame` to every active subscriber
20
+ * for the given `tid`; subscribers filter by `frame.t` + identifiers
21
+ * (correlation id, confirm id, state path) to find the one that
22
+ * belongs to their request.
23
23
  */
24
- export declare class WsPairingRegistry {
24
+ export type FrameSubscriber = (frame: ClientFrame) => boolean;
25
+ /**
26
+ * Registry of live browser pairings. Pure routing + hello cache —
27
+ * request-lifecycle state (in-flight RPC promises, confirm waits,
28
+ * long-polls) lives in the LAP handlers that need it, not here.
29
+ *
30
+ * Two implementations ship today:
31
+ * - `InMemoryPairingRegistry` for long-lived server processes
32
+ * (Node, Bun, Deno, Deno Deploy).
33
+ * - A Cloudflare Durable Object implementation (see
34
+ * `server/cloudflare`) for stateless Worker runtimes.
35
+ *
36
+ * Other runtimes can implement this interface the same way; the
37
+ * contract is intentionally small.
38
+ */
39
+ export interface PairingRegistry {
40
+ register(tid: string, conn: PairingConnection): void;
41
+ unregister(tid: string): void;
42
+ isPaired(tid: string): boolean;
43
+ getHello(tid: string): HelloFrame | null;
44
+ /** Send a frame. No-op when the pairing is absent or closed. */
45
+ send(tid: string, frame: ServerFrame): void;
46
+ /**
47
+ * Subscribe to frames from the paired browser. Returns an
48
+ * unsubscribe function. A subscriber can remove itself mid-dispatch
49
+ * by returning `true` from its callback — useful for one-shot
50
+ * request/response correlation.
51
+ */
52
+ subscribe(tid: string, handler: FrameSubscriber): () => void;
53
+ /**
54
+ * Observe the pairing closing (WebSocket drop, `unregister`, etc.).
55
+ * Handlers registered before close fire; handlers registered after
56
+ * close fire synchronously. Returns an unsubscribe function.
57
+ */
58
+ onClose(tid: string, handler: () => void): () => void;
59
+ /**
60
+ * Send a typed rpc frame and await its matching reply. See
61
+ * `./rpc.ts::rpc` for the full contract.
62
+ */
63
+ rpc(tid: string, tool: string, args: unknown, opts?: RpcOptions): Promise<unknown>;
64
+ /** See `./rpc.ts::waitForConfirm`. */
65
+ waitForConfirm(tid: string, confirmId: string, timeoutMs: number): Promise<{
66
+ outcome: 'confirmed' | 'user-cancelled';
67
+ stateAfter?: unknown;
68
+ }>;
69
+ /** See `./rpc.ts::waitForChange`. */
70
+ waitForChange(tid: string, path: string | undefined, timeoutMs: number): Promise<{
71
+ status: 'changed' | 'timeout';
72
+ stateAfter: unknown;
73
+ }>;
74
+ }
75
+ /**
76
+ * Single-process in-memory registry. Correct for Node/Bun/Deno/Deno
77
+ * Deploy — anywhere the server process can hold a long-lived
78
+ * WebSocket. Not suitable for stateless Worker isolates; use the
79
+ * Durable Object registry for Cloudflare.
80
+ */
81
+ export declare class InMemoryPairingRegistry implements PairingRegistry {
25
82
  private pairings;
26
- private now;
27
83
  private onLogAppend;
28
84
  constructor(opts?: {
29
- now?: () => number;
30
85
  onLogAppend?: (tid: string, entry: LogEntry) => void;
31
86
  });
32
87
  register(tid: string, conn: PairingConnection): void;
33
88
  unregister(tid: string): void;
34
89
  isPaired(tid: string): boolean;
35
- /**
36
- * Send a ServerFrame to the paired browser connection, if one is live.
37
- * No-op when unpaired or closed.
38
- */
39
- notify(tid: string, frame: ServerFrame): void;
40
90
  getHello(tid: string): HelloFrame | null;
91
+ send(tid: string, frame: ServerFrame): void;
92
+ subscribe(tid: string, handler: FrameSubscriber): () => void;
93
+ onClose(tid: string, handler: () => void): () => void;
94
+ private dispatch;
41
95
  rpc(tid: string, tool: string, args: unknown, opts?: RpcOptions): Promise<unknown>;
42
96
  waitForConfirm(tid: string, confirmId: string, timeoutMs: number): Promise<{
43
97
  outcome: 'confirmed' | 'user-cancelled';
@@ -47,7 +101,16 @@ export declare class WsPairingRegistry {
47
101
  status: 'changed' | 'timeout';
48
102
  stateAfter: unknown;
49
103
  }>;
50
- private handleClientFrame;
104
+ /** @deprecated Use `send(tid, frame)` directly; semantics are identical. */
105
+ notify(tid: string, frame: ServerFrame): void;
51
106
  private handleClose;
52
107
  }
108
+ /**
109
+ * Back-compat alias for the prior class name. New code should use
110
+ * `InMemoryPairingRegistry`. Removed in a future major.
111
+ *
112
+ * @deprecated Use `InMemoryPairingRegistry` directly.
113
+ */
114
+ export declare const WsPairingRegistry: typeof InMemoryPairingRegistry;
115
+ export type WsPairingRegistry = InMemoryPairingRegistry;
53
116
  //# sourceMappingURL=pairing-registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pairing-registry.d.ts","sourceRoot":"","sources":["../../../src/server/ws/pairing-registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEvF;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IAC9B,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI,CAAA;IAChD,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;IAClC,KAAK,IAAI,IAAI,CAAA;CACd;AA4BD,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,GAAG,UAAU,GAAG,MAAM,CAAA;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/C;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,GAAG,CAAc;IACzB,OAAO,CAAC,WAAW,CAAiD;gBAGlE,IAAI,GAAE;QACJ,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;QAClB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAA;KAChD;IAMR,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAcpD,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAM7B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAK9B;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI;IAU7C,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAIlC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IA6BtF,cAAc,CAClB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,OAAO,EAAE,WAAW,GAAG,gBAAgB,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAiBvE,aAAa,CACjB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAC;IAiBlE,OAAO,CAAC,iBAAiB;IAmDzB,OAAO,CAAC,WAAW;CAqBpB"}
1
+ {"version":3,"file":"pairing-registry.d.ts","sourceRoot":"","sources":["../../../src/server/ws/pairing-registry.ts"],"names":[],"mappings":"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"}