@llui/agent 0.0.30 → 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 (93) hide show
  1. package/dist/server/cloudflare/durable-object.d.ts +58 -0
  2. package/dist/server/cloudflare/durable-object.d.ts.map +1 -0
  3. package/dist/server/cloudflare/durable-object.js +33 -0
  4. package/dist/server/cloudflare/durable-object.js.map +1 -0
  5. package/dist/server/cloudflare/index.d.ts +49 -0
  6. package/dist/server/cloudflare/index.d.ts.map +1 -0
  7. package/dist/server/cloudflare/index.js +49 -0
  8. package/dist/server/cloudflare/index.js.map +1 -0
  9. package/dist/server/cloudflare/worker.d.ts +40 -0
  10. package/dist/server/cloudflare/worker.d.ts.map +1 -0
  11. package/dist/server/cloudflare/worker.js +55 -0
  12. package/dist/server/cloudflare/worker.js.map +1 -0
  13. package/dist/server/core-entry.d.ts +27 -0
  14. package/dist/server/core-entry.d.ts.map +1 -0
  15. package/dist/server/core-entry.js +19 -0
  16. package/dist/server/core-entry.js.map +1 -0
  17. package/dist/server/core.d.ts +78 -0
  18. package/dist/server/core.d.ts.map +1 -0
  19. package/dist/server/core.js +84 -0
  20. package/dist/server/core.js.map +1 -0
  21. package/dist/server/factory.d.ts +5 -3
  22. package/dist/server/factory.d.ts.map +1 -1
  23. package/dist/server/factory.js +18 -58
  24. package/dist/server/factory.js.map +1 -1
  25. package/dist/server/http/mint.d.ts.map +1 -1
  26. package/dist/server/http/mint.js +2 -3
  27. package/dist/server/http/mint.js.map +1 -1
  28. package/dist/server/http/resume.js +1 -1
  29. package/dist/server/http/resume.js.map +1 -1
  30. package/dist/server/identity.d.ts +5 -1
  31. package/dist/server/identity.d.ts.map +1 -1
  32. package/dist/server/identity.js +49 -11
  33. package/dist/server/identity.js.map +1 -1
  34. package/dist/server/index.d.ts +16 -1
  35. package/dist/server/index.d.ts.map +1 -1
  36. package/dist/server/index.js +13 -1
  37. package/dist/server/index.js.map +1 -1
  38. package/dist/server/lap/confirm-result.d.ts +2 -2
  39. package/dist/server/lap/confirm-result.d.ts.map +1 -1
  40. package/dist/server/lap/confirm-result.js +1 -1
  41. package/dist/server/lap/confirm-result.js.map +1 -1
  42. package/dist/server/lap/describe.d.ts +4 -4
  43. package/dist/server/lap/describe.d.ts.map +1 -1
  44. package/dist/server/lap/describe.js +4 -4
  45. package/dist/server/lap/describe.js.map +1 -1
  46. package/dist/server/lap/forward.d.ts +2 -2
  47. package/dist/server/lap/forward.d.ts.map +1 -1
  48. package/dist/server/lap/forward.js +1 -1
  49. package/dist/server/lap/forward.js.map +1 -1
  50. package/dist/server/lap/message.d.ts +2 -2
  51. package/dist/server/lap/message.d.ts.map +1 -1
  52. package/dist/server/lap/message.js +1 -1
  53. package/dist/server/lap/message.js.map +1 -1
  54. package/dist/server/lap/observe.d.ts +2 -2
  55. package/dist/server/lap/observe.d.ts.map +1 -1
  56. package/dist/server/lap/observe.js +1 -1
  57. package/dist/server/lap/observe.js.map +1 -1
  58. package/dist/server/lap/wait.d.ts +2 -2
  59. package/dist/server/lap/wait.d.ts.map +1 -1
  60. package/dist/server/lap/wait.js +1 -1
  61. package/dist/server/lap/wait.js.map +1 -1
  62. package/dist/server/options.d.ts +25 -1
  63. package/dist/server/options.d.ts.map +1 -1
  64. package/dist/server/options.js.map +1 -1
  65. package/dist/server/token.d.ts +7 -3
  66. package/dist/server/token.d.ts.map +1 -1
  67. package/dist/server/token.js +66 -26
  68. package/dist/server/token.js.map +1 -1
  69. package/dist/server/web/adapter.d.ts +16 -0
  70. package/dist/server/web/adapter.d.ts.map +1 -0
  71. package/dist/server/web/adapter.js +45 -0
  72. package/dist/server/web/adapter.js.map +1 -0
  73. package/dist/server/web/index.d.ts +12 -0
  74. package/dist/server/web/index.d.ts.map +1 -0
  75. package/dist/server/web/index.js +12 -0
  76. package/dist/server/web/index.js.map +1 -0
  77. package/dist/server/web/upgrade.d.ts +41 -0
  78. package/dist/server/web/upgrade.d.ts.map +1 -0
  79. package/dist/server/web/upgrade.js +96 -0
  80. package/dist/server/web/upgrade.js.map +1 -0
  81. package/dist/server/ws/pairing-registry.d.ts +84 -21
  82. package/dist/server/ws/pairing-registry.d.ts.map +1 -1
  83. package/dist/server/ws/pairing-registry.js +89 -151
  84. package/dist/server/ws/pairing-registry.js.map +1 -1
  85. package/dist/server/ws/rpc.d.ts +39 -0
  86. package/dist/server/ws/rpc.d.ts.map +1 -0
  87. package/dist/server/ws/rpc.js +126 -0
  88. package/dist/server/ws/rpc.js.map +1 -0
  89. package/dist/server/ws/upgrade.d.ts +3 -3
  90. package/dist/server/ws/upgrade.d.ts.map +1 -1
  91. package/dist/server/ws/upgrade.js +2 -2
  92. package/dist/server/ws/upgrade.js.map +1 -1
  93. package/package.json +13 -1
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Durable Object helper for hosting the agent pairing + LAP surface
3
+ * on Cloudflare Workers. One DO instance owns one `tid` — its
4
+ * in-memory `PairingRegistry` survives across Worker isolate
5
+ * invocations because the DO IS persistent.
6
+ *
7
+ * This file exports a class designed to be composed into a real
8
+ * Durable Object in the user's Worker project. We intentionally
9
+ * don't subclass `DurableObject` from `@cloudflare/workers-types` —
10
+ * that dependency belongs to the user's project, not ours. Users
11
+ * wrap an instance of `AgentPairingDurableObject` in their own DO
12
+ * class and forward `fetch` to it.
13
+ *
14
+ * Usage in a Worker project:
15
+ *
16
+ * ```ts
17
+ * // worker.ts
18
+ * import { AgentPairingDurableObject } from '@llui/agent/server/cloudflare'
19
+ *
20
+ * export class AgentDO {
21
+ * private agent: AgentPairingDurableObject
22
+ * constructor(_state: DurableObjectState, env: Env) {
23
+ * this.agent = new AgentPairingDurableObject({
24
+ * signingKey: env.AGENT_SIGNING_KEY,
25
+ * })
26
+ * }
27
+ * fetch(req: Request): Promise<Response> {
28
+ * return this.agent.fetch(req)
29
+ * }
30
+ * }
31
+ *
32
+ * export default {
33
+ * async fetch(req: Request, env: Env): Promise<Response> {
34
+ * return routeToAgentDO(req, env.AGENT_DO, env.AGENT_SIGNING_KEY)
35
+ * },
36
+ * }
37
+ * ```
38
+ *
39
+ * See `./worker.ts` for `routeToAgentDO` and the full wiring.
40
+ */
41
+ import type { CoreOptions, AgentCoreHandle } from '../core.js';
42
+ export type DurableObjectOptions = Omit<CoreOptions, 'registry'>;
43
+ /**
44
+ * Agent server instance scoped to a single Durable Object. All
45
+ * pairing state lives in the DO's in-process memory — which is safe
46
+ * here because the DO is a persistent addressable entity, not a
47
+ * one-shot Worker isolate.
48
+ *
49
+ * Users instantiate one of these inside their DO class's constructor
50
+ * and delegate `fetch` to `agent.fetch(req)`. LAP HTTP routes and
51
+ * WebSocket upgrades both flow through this single entry.
52
+ */
53
+ export declare class AgentPairingDurableObject {
54
+ readonly agent: AgentCoreHandle;
55
+ constructor(opts: DurableObjectOptions);
56
+ fetch(req: Request): Promise<Response>;
57
+ }
58
+ //# sourceMappingURL=durable-object.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-object.d.ts","sourceRoot":"","sources":["../../../src/server/cloudflare/durable-object.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAI9D,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAA;AAEhE;;;;;;;;;GASG;AACH,qBAAa,yBAAyB;IACpC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;gBAEnB,IAAI,EAAE,oBAAoB;IAIhC,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;CAgB7C"}
@@ -0,0 +1,33 @@
1
+ import { createLluiAgentCore } from '../core.js';
2
+ import { handleCloudflareUpgrade } from '../web/upgrade.js';
3
+ /**
4
+ * Agent server instance scoped to a single Durable Object. All
5
+ * pairing state lives in the DO's in-process memory — which is safe
6
+ * here because the DO is a persistent addressable entity, not a
7
+ * one-shot Worker isolate.
8
+ *
9
+ * Users instantiate one of these inside their DO class's constructor
10
+ * and delegate `fetch` to `agent.fetch(req)`. LAP HTTP routes and
11
+ * WebSocket upgrades both flow through this single entry.
12
+ */
13
+ export class AgentPairingDurableObject {
14
+ agent;
15
+ constructor(opts) {
16
+ this.agent = createLluiAgentCore(opts);
17
+ }
18
+ async fetch(req) {
19
+ const url = new URL(req.url);
20
+ // LAP routes (/agent/lap/v1/*, /agent/*). `router` returns null
21
+ // for non-matching paths so we can fall through to the upgrade.
22
+ const lapRes = await this.agent.router(req);
23
+ if (lapRes)
24
+ return lapRes;
25
+ // WebSocket upgrade — uses `WebSocketPair`, which only exists in
26
+ // Cloudflare Workers.
27
+ if (url.pathname === '/agent/ws') {
28
+ return handleCloudflareUpgrade(req, this.agent);
29
+ }
30
+ return new Response('Not Found', { status: 404 });
31
+ }
32
+ }
33
+ //# sourceMappingURL=durable-object.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-object.js","sourceRoot":"","sources":["../../../src/server/cloudflare/durable-object.ts"],"names":[],"mappings":"AAyCA,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAI3D;;;;;;;;;GASG;AACH,MAAM,OAAO,yBAAyB;IAC3B,KAAK,CAAiB;IAE/B,YAAY,IAA0B;QACpC,IAAI,CAAC,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAA;IACxC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,GAAY;QACtB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAE5B,gEAAgE;QAChE,gEAAgE;QAChE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC3C,IAAI,MAAM;YAAE,OAAO,MAAM,CAAA;QAEzB,iEAAiE;QACjE,sBAAsB;QACtB,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;YACjC,OAAO,uBAAuB,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QACjD,CAAC;QAED,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IACnD,CAAC;CACF","sourcesContent":["/**\n * Durable Object helper for hosting the agent pairing + LAP surface\n * on Cloudflare Workers. One DO instance owns one `tid` — its\n * in-memory `PairingRegistry` survives across Worker isolate\n * invocations because the DO IS persistent.\n *\n * This file exports a class designed to be composed into a real\n * Durable Object in the user's Worker project. We intentionally\n * don't subclass `DurableObject` from `@cloudflare/workers-types` —\n * that dependency belongs to the user's project, not ours. Users\n * wrap an instance of `AgentPairingDurableObject` in their own DO\n * class and forward `fetch` to it.\n *\n * Usage in a Worker project:\n *\n * ```ts\n * // worker.ts\n * import { AgentPairingDurableObject } from '@llui/agent/server/cloudflare'\n *\n * export class AgentDO {\n * private agent: AgentPairingDurableObject\n * constructor(_state: DurableObjectState, env: Env) {\n * this.agent = new AgentPairingDurableObject({\n * signingKey: env.AGENT_SIGNING_KEY,\n * })\n * }\n * fetch(req: Request): Promise<Response> {\n * return this.agent.fetch(req)\n * }\n * }\n *\n * export default {\n * async fetch(req: Request, env: Env): Promise<Response> {\n * return routeToAgentDO(req, env.AGENT_DO, env.AGENT_SIGNING_KEY)\n * },\n * }\n * ```\n *\n * See `./worker.ts` for `routeToAgentDO` and the full wiring.\n */\nimport type { CoreOptions, AgentCoreHandle } from '../core.js'\nimport { createLluiAgentCore } from '../core.js'\nimport { handleCloudflareUpgrade } from '../web/upgrade.js'\n\nexport type DurableObjectOptions = Omit<CoreOptions, 'registry'>\n\n/**\n * Agent server instance scoped to a single Durable Object. All\n * pairing state lives in the DO's in-process memory — which is safe\n * here because the DO is a persistent addressable entity, not a\n * one-shot Worker isolate.\n *\n * Users instantiate one of these inside their DO class's constructor\n * and delegate `fetch` to `agent.fetch(req)`. LAP HTTP routes and\n * WebSocket upgrades both flow through this single entry.\n */\nexport class AgentPairingDurableObject {\n readonly agent: AgentCoreHandle\n\n constructor(opts: DurableObjectOptions) {\n this.agent = createLluiAgentCore(opts)\n }\n\n async fetch(req: Request): Promise<Response> {\n const url = new URL(req.url)\n\n // LAP routes (/agent/lap/v1/*, /agent/*). `router` returns null\n // for non-matching paths so we can fall through to the upgrade.\n const lapRes = await this.agent.router(req)\n if (lapRes) return lapRes\n\n // WebSocket upgrade — uses `WebSocketPair`, which only exists in\n // Cloudflare Workers.\n if (url.pathname === '/agent/ws') {\n return handleCloudflareUpgrade(req, this.agent)\n }\n\n return new Response('Not Found', { status: 404 })\n }\n}\n"]}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Cloudflare Workers + Durable Object adapter. Use this sub-path
3
+ * from a Cloudflare Workers project where the agent pairing state
4
+ * lives inside a Durable Object.
5
+ *
6
+ * See the full deployment recipe at
7
+ * https://llui.dev/api/agent#cloudflare-deployment — the short
8
+ * version:
9
+ *
10
+ * ```ts
11
+ * import {
12
+ * AgentPairingDurableObject,
13
+ * routeToAgentDO,
14
+ * } from '@llui/agent/server/cloudflare'
15
+ *
16
+ * export class AgentDO {
17
+ * private agent: AgentPairingDurableObject
18
+ * constructor(_state: DurableObjectState, env: Env) {
19
+ * this.agent = new AgentPairingDurableObject({
20
+ * signingKey: env.AGENT_SIGNING_KEY,
21
+ * })
22
+ * }
23
+ * fetch(req: Request) {
24
+ * return this.agent.fetch(req)
25
+ * }
26
+ * }
27
+ *
28
+ * export default {
29
+ * async fetch(req: Request, env: Env) {
30
+ * return routeToAgentDO(req, env.AGENT_DO, env.AGENT_SIGNING_KEY)
31
+ * },
32
+ * }
33
+ * ```
34
+ *
35
+ * `wrangler.toml`:
36
+ * ```toml
37
+ * [[durable_objects.bindings]]
38
+ * name = "AGENT_DO"
39
+ * class_name = "AgentDO"
40
+ *
41
+ * [[migrations]]
42
+ * tag = "v1"
43
+ * new_classes = ["AgentDO"]
44
+ * ```
45
+ */
46
+ export { AgentPairingDurableObject, type DurableObjectOptions } from './durable-object.js';
47
+ export { routeToAgentDO, type MinimalDurableObjectNamespace, type MinimalDurableObjectId, type MinimalDurableObjectStub, } from './worker.js';
48
+ export { createWHATWGPairingConnection, handleCloudflareUpgrade, extractToken, } from '../web/index.js';
49
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/cloudflare/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,EAAE,yBAAyB,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1F,OAAO,EACL,cAAc,EACd,KAAK,6BAA6B,EAClC,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,GAC9B,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,6BAA6B,EAC7B,uBAAuB,EACvB,YAAY,GACb,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Cloudflare Workers + Durable Object adapter. Use this sub-path
3
+ * from a Cloudflare Workers project where the agent pairing state
4
+ * lives inside a Durable Object.
5
+ *
6
+ * See the full deployment recipe at
7
+ * https://llui.dev/api/agent#cloudflare-deployment — the short
8
+ * version:
9
+ *
10
+ * ```ts
11
+ * import {
12
+ * AgentPairingDurableObject,
13
+ * routeToAgentDO,
14
+ * } from '@llui/agent/server/cloudflare'
15
+ *
16
+ * export class AgentDO {
17
+ * private agent: AgentPairingDurableObject
18
+ * constructor(_state: DurableObjectState, env: Env) {
19
+ * this.agent = new AgentPairingDurableObject({
20
+ * signingKey: env.AGENT_SIGNING_KEY,
21
+ * })
22
+ * }
23
+ * fetch(req: Request) {
24
+ * return this.agent.fetch(req)
25
+ * }
26
+ * }
27
+ *
28
+ * export default {
29
+ * async fetch(req: Request, env: Env) {
30
+ * return routeToAgentDO(req, env.AGENT_DO, env.AGENT_SIGNING_KEY)
31
+ * },
32
+ * }
33
+ * ```
34
+ *
35
+ * `wrangler.toml`:
36
+ * ```toml
37
+ * [[durable_objects.bindings]]
38
+ * name = "AGENT_DO"
39
+ * class_name = "AgentDO"
40
+ *
41
+ * [[migrations]]
42
+ * tag = "v1"
43
+ * new_classes = ["AgentDO"]
44
+ * ```
45
+ */
46
+ export { AgentPairingDurableObject } from './durable-object.js';
47
+ export { routeToAgentDO, } from './worker.js';
48
+ export { createWHATWGPairingConnection, handleCloudflareUpgrade, extractToken, } from '../web/index.js';
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/cloudflare/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,EAAE,yBAAyB,EAA6B,MAAM,qBAAqB,CAAA;AAC1F,OAAO,EACL,cAAc,GAIf,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,6BAA6B,EAC7B,uBAAuB,EACvB,YAAY,GACb,MAAM,iBAAiB,CAAA","sourcesContent":["/**\n * Cloudflare Workers + Durable Object adapter. Use this sub-path\n * from a Cloudflare Workers project where the agent pairing state\n * lives inside a Durable Object.\n *\n * See the full deployment recipe at\n * https://llui.dev/api/agent#cloudflare-deployment — the short\n * version:\n *\n * ```ts\n * import {\n * AgentPairingDurableObject,\n * routeToAgentDO,\n * } from '@llui/agent/server/cloudflare'\n *\n * export class AgentDO {\n * private agent: AgentPairingDurableObject\n * constructor(_state: DurableObjectState, env: Env) {\n * this.agent = new AgentPairingDurableObject({\n * signingKey: env.AGENT_SIGNING_KEY,\n * })\n * }\n * fetch(req: Request) {\n * return this.agent.fetch(req)\n * }\n * }\n *\n * export default {\n * async fetch(req: Request, env: Env) {\n * return routeToAgentDO(req, env.AGENT_DO, env.AGENT_SIGNING_KEY)\n * },\n * }\n * ```\n *\n * `wrangler.toml`:\n * ```toml\n * [[durable_objects.bindings]]\n * name = \"AGENT_DO\"\n * class_name = \"AgentDO\"\n *\n * [[migrations]]\n * tag = \"v1\"\n * new_classes = [\"AgentDO\"]\n * ```\n */\nexport { AgentPairingDurableObject, type DurableObjectOptions } from './durable-object.js'\nexport {\n routeToAgentDO,\n type MinimalDurableObjectNamespace,\n type MinimalDurableObjectId,\n type MinimalDurableObjectStub,\n} from './worker.js'\nexport {\n createWHATWGPairingConnection,\n handleCloudflareUpgrade,\n extractToken,\n} from '../web/index.js'\n"]}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Minimal DurableObjectNamespace surface we need — `idFromName` +
3
+ * `get` returning a `Stub` with `fetch(req)`. Kept structural so we
4
+ * don't depend on `@cloudflare/workers-types` (the user's project has
5
+ * them; we shouldn't duplicate).
6
+ */
7
+ export interface MinimalDurableObjectNamespace {
8
+ idFromName(name: string): MinimalDurableObjectId;
9
+ get(id: MinimalDurableObjectId): MinimalDurableObjectStub;
10
+ }
11
+ export interface MinimalDurableObjectId {
12
+ readonly name?: string;
13
+ }
14
+ export interface MinimalDurableObjectStub {
15
+ fetch(req: Request): Promise<Response>;
16
+ }
17
+ /**
18
+ * Route an incoming Worker `fetch` request to the Durable Object
19
+ * that owns its `tid`.
20
+ *
21
+ * The token travels in three places depending on the route:
22
+ * - LAP HTTP calls: `Authorization: Bearer <token>` header
23
+ * - Mint / resume HTTP calls: no token (identity resolver runs
24
+ * inside the DO via the LAP router; we route by origin or a
25
+ * special `/agent/mint` path — see below)
26
+ * - WebSocket upgrade: `?token=<token>` in the URL
27
+ *
28
+ * Requests that don't carry a tid (mint, resume-list, sessions) are
29
+ * routed to a "root" DO named `__root`, which handles identity /
30
+ * token store operations centrally. LAP and WS calls route to the
31
+ * per-tid DO so the pairing state stays local.
32
+ *
33
+ * This is the recommended entry for Cloudflare Workers deployments;
34
+ * users who need custom routing can write their own and call the
35
+ * underlying primitives (`verifyToken`, `namespace.get`, etc).
36
+ */
37
+ export declare function routeToAgentDO(req: Request, namespace: MinimalDurableObjectNamespace, signingKey: string | Uint8Array, opts?: {
38
+ rootName?: string;
39
+ }): Promise<Response>;
40
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/server/cloudflare/worker.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC5C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,CAAA;IAChD,GAAG,CAAC,EAAE,EAAE,sBAAsB,GAAG,wBAAwB,CAAA;CAC1D;AACD,MAAM,WAAW,sBAAsB;IAErC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AACD,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CACvC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,6BAA6B,EACxC,UAAU,EAAE,MAAM,GAAG,UAAU,EAC/B,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,QAAQ,CAAC,CA4BnB"}
@@ -0,0 +1,55 @@
1
+ import { verifyToken } from '../token.js';
2
+ /**
3
+ * Route an incoming Worker `fetch` request to the Durable Object
4
+ * that owns its `tid`.
5
+ *
6
+ * The token travels in three places depending on the route:
7
+ * - LAP HTTP calls: `Authorization: Bearer <token>` header
8
+ * - Mint / resume HTTP calls: no token (identity resolver runs
9
+ * inside the DO via the LAP router; we route by origin or a
10
+ * special `/agent/mint` path — see below)
11
+ * - WebSocket upgrade: `?token=<token>` in the URL
12
+ *
13
+ * Requests that don't carry a tid (mint, resume-list, sessions) are
14
+ * routed to a "root" DO named `__root`, which handles identity /
15
+ * token store operations centrally. LAP and WS calls route to the
16
+ * per-tid DO so the pairing state stays local.
17
+ *
18
+ * This is the recommended entry for Cloudflare Workers deployments;
19
+ * users who need custom routing can write their own and call the
20
+ * underlying primitives (`verifyToken`, `namespace.get`, etc).
21
+ */
22
+ export async function routeToAgentDO(req, namespace, signingKey, opts = {}) {
23
+ const rootName = opts.rootName ?? '__root';
24
+ const url = new URL(req.url);
25
+ const path = url.pathname;
26
+ // Non-LAP / non-WS management endpoints (mint, resume, sessions,
27
+ // revoke) — there's no per-tid routing; use the root DO which owns
28
+ // the shared token store + identity resolver.
29
+ if (path === '/agent/mint' ||
30
+ path === '/agent/revoke' ||
31
+ path === '/agent/resume/list' ||
32
+ path === '/agent/resume/claim' ||
33
+ path === '/agent/sessions') {
34
+ const stub = namespace.get(namespace.idFromName(rootName));
35
+ return stub.fetch(req);
36
+ }
37
+ // Token-bearing routes (LAP + WS upgrade) — route by tid.
38
+ const token = extractTokenFromRequest(req);
39
+ if (!token)
40
+ return new Response('Unauthorized', { status: 401 });
41
+ const verified = await verifyToken(token, signingKey);
42
+ if (verified.kind !== 'ok')
43
+ return new Response('Unauthorized', { status: 401 });
44
+ const stub = namespace.get(namespace.idFromName(verified.payload.tid));
45
+ return stub.fetch(req);
46
+ }
47
+ function extractTokenFromRequest(req) {
48
+ const auth = req.headers.get('authorization');
49
+ if (auth?.startsWith('Bearer '))
50
+ return auth.slice('Bearer '.length);
51
+ const url = new URL(req.url);
52
+ const q = url.searchParams.get('token');
53
+ return q;
54
+ }
55
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/server/cloudflare/worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAoBzC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAY,EACZ,SAAwC,EACxC,UAA+B,EAC/B,OAA8B,EAAE;IAEhC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAA;IAC1C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5B,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAA;IAEzB,iEAAiE;IACjE,mEAAmE;IACnE,8CAA8C;IAC9C,IACE,IAAI,KAAK,aAAa;QACtB,IAAI,KAAK,eAAe;QACxB,IAAI,KAAK,oBAAoB;QAC7B,IAAI,KAAK,qBAAqB;QAC9B,IAAI,KAAK,iBAAiB,EAC1B,CAAC;QACD,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC1D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACxB,CAAC;IAED,0DAA0D;IAC1D,MAAM,KAAK,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAA;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,QAAQ,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IAEhE,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC,CAAA;IACrD,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,QAAQ,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IAEhF,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;IACtE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;AACxB,CAAC;AAED,SAAS,uBAAuB,CAAC,GAAY;IAC3C,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,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,OAAO,CAAC,CAAA;AACV,CAAC","sourcesContent":["import { verifyToken } from '../token.js'\n\n/**\n * Minimal DurableObjectNamespace surface we need — `idFromName` +\n * `get` returning a `Stub` with `fetch(req)`. Kept structural so we\n * don't depend on `@cloudflare/workers-types` (the user's project has\n * them; we shouldn't duplicate).\n */\nexport interface MinimalDurableObjectNamespace {\n idFromName(name: string): MinimalDurableObjectId\n get(id: MinimalDurableObjectId): MinimalDurableObjectStub\n}\nexport interface MinimalDurableObjectId {\n // Opaque, but DO ids are passed back into `namespace.get()`.\n readonly name?: string\n}\nexport interface MinimalDurableObjectStub {\n fetch(req: Request): Promise<Response>\n}\n\n/**\n * Route an incoming Worker `fetch` request to the Durable Object\n * that owns its `tid`.\n *\n * The token travels in three places depending on the route:\n * - LAP HTTP calls: `Authorization: Bearer <token>` header\n * - Mint / resume HTTP calls: no token (identity resolver runs\n * inside the DO via the LAP router; we route by origin or a\n * special `/agent/mint` path — see below)\n * - WebSocket upgrade: `?token=<token>` in the URL\n *\n * Requests that don't carry a tid (mint, resume-list, sessions) are\n * routed to a \"root\" DO named `__root`, which handles identity /\n * token store operations centrally. LAP and WS calls route to the\n * per-tid DO so the pairing state stays local.\n *\n * This is the recommended entry for Cloudflare Workers deployments;\n * users who need custom routing can write their own and call the\n * underlying primitives (`verifyToken`, `namespace.get`, etc).\n */\nexport async function routeToAgentDO(\n req: Request,\n namespace: MinimalDurableObjectNamespace,\n signingKey: string | Uint8Array,\n opts: { rootName?: string } = {},\n): Promise<Response> {\n const rootName = opts.rootName ?? '__root'\n const url = new URL(req.url)\n const path = url.pathname\n\n // Non-LAP / non-WS management endpoints (mint, resume, sessions,\n // revoke) — there's no per-tid routing; use the root DO which owns\n // the shared token store + identity resolver.\n if (\n path === '/agent/mint' ||\n path === '/agent/revoke' ||\n path === '/agent/resume/list' ||\n path === '/agent/resume/claim' ||\n path === '/agent/sessions'\n ) {\n const stub = namespace.get(namespace.idFromName(rootName))\n return stub.fetch(req)\n }\n\n // Token-bearing routes (LAP + WS upgrade) — route by tid.\n const token = extractTokenFromRequest(req)\n if (!token) return new Response('Unauthorized', { status: 401 })\n\n const verified = await verifyToken(token, signingKey)\n if (verified.kind !== 'ok') return new Response('Unauthorized', { status: 401 })\n\n const stub = namespace.get(namespace.idFromName(verified.payload.tid))\n return stub.fetch(req)\n}\n\nfunction extractTokenFromRequest(req: Request): string | null {\n const auth = req.headers.get('authorization')\n if (auth?.startsWith('Bearer ')) return auth.slice('Bearer '.length)\n const url = new URL(req.url)\n const q = url.searchParams.get('token')\n return q\n}\n"]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Runtime-neutral entry point. Import from `@llui/agent/server/core`
3
+ * when targeting runtimes without the Node `ws` library (Cloudflare
4
+ * Workers, Deno, Bun, Deno Deploy). Pair with
5
+ * `@llui/agent/server/web` for WebSocket upgrade helpers.
6
+ *
7
+ * Node/standard server processes should keep using the default
8
+ * `@llui/agent/server` entry, which includes this plus the `ws`-based
9
+ * upgrade handler.
10
+ */
11
+ export { createLluiAgentCore } from './core.js';
12
+ export type { CoreOptions, AgentCoreHandle, AcceptResult } from './core.js';
13
+ export { InMemoryPairingRegistry } from './ws/pairing-registry.js';
14
+ export type { PairingConnection, PairingRegistry, FrameSubscriber } from './ws/pairing-registry.js';
15
+ export { rpc, waitForConfirm, waitForChange } from './ws/rpc.js';
16
+ export type { RpcOptions, RpcError } from './ws/rpc.js';
17
+ export { InMemoryTokenStore } from './token-store.js';
18
+ export type { TokenStore } from './token-store.js';
19
+ export { defaultIdentityResolver, signCookieValue } from './identity.js';
20
+ export type { IdentityResolver } from './identity.js';
21
+ export { consoleAuditSink } from './audit.js';
22
+ export type { AuditSink } from './audit.js';
23
+ export { defaultRateLimiter } from './rate-limit.js';
24
+ export type { RateLimiter } from './rate-limit.js';
25
+ export { signToken, verifyToken } from './token.js';
26
+ export type { TokenPayload, VerifyResult } from './token.js';
27
+ //# sourceMappingURL=core-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-entry.d.ts","sourceRoot":"","sources":["../../src/server/core-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAC/C,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAClE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AACnG,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACxE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7C,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACpD,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACnD,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Runtime-neutral entry point. Import from `@llui/agent/server/core`
3
+ * when targeting runtimes without the Node `ws` library (Cloudflare
4
+ * Workers, Deno, Bun, Deno Deploy). Pair with
5
+ * `@llui/agent/server/web` for WebSocket upgrade helpers.
6
+ *
7
+ * Node/standard server processes should keep using the default
8
+ * `@llui/agent/server` entry, which includes this plus the `ws`-based
9
+ * upgrade handler.
10
+ */
11
+ export { createLluiAgentCore } from './core.js';
12
+ export { InMemoryPairingRegistry } from './ws/pairing-registry.js';
13
+ export { rpc, waitForConfirm, waitForChange } from './ws/rpc.js';
14
+ export { InMemoryTokenStore } from './token-store.js';
15
+ export { defaultIdentityResolver, signCookieValue } from './identity.js';
16
+ export { consoleAuditSink } from './audit.js';
17
+ export { defaultRateLimiter } from './rate-limit.js';
18
+ export { signToken, verifyToken } from './token.js';
19
+ //# sourceMappingURL=core-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-entry.js","sourceRoot":"","sources":["../../src/server/core-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAE/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAElE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAErD,OAAO,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA","sourcesContent":["/**\n * Runtime-neutral entry point. Import from `@llui/agent/server/core`\n * when targeting runtimes without the Node `ws` library (Cloudflare\n * Workers, Deno, Bun, Deno Deploy). Pair with\n * `@llui/agent/server/web` for WebSocket upgrade helpers.\n *\n * Node/standard server processes should keep using the default\n * `@llui/agent/server` entry, which includes this plus the `ws`-based\n * upgrade handler.\n */\nexport { createLluiAgentCore } from './core.js'\nexport type { CoreOptions, AgentCoreHandle, AcceptResult } from './core.js'\nexport { InMemoryPairingRegistry } from './ws/pairing-registry.js'\nexport type { PairingConnection, PairingRegistry, FrameSubscriber } from './ws/pairing-registry.js'\nexport { rpc, waitForConfirm, waitForChange } from './ws/rpc.js'\nexport type { RpcOptions, RpcError } from './ws/rpc.js'\nexport { InMemoryTokenStore } from './token-store.js'\nexport type { TokenStore } from './token-store.js'\nexport { defaultIdentityResolver, signCookieValue } from './identity.js'\nexport type { IdentityResolver } from './identity.js'\nexport { consoleAuditSink } from './audit.js'\nexport type { AuditSink } from './audit.js'\nexport { defaultRateLimiter } from './rate-limit.js'\nexport type { RateLimiter } from './rate-limit.js'\nexport { signToken, verifyToken } from './token.js'\nexport type { TokenPayload, VerifyResult } from './token.js'\n"]}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Runtime-neutral core of the LLui agent server. Exports everything
3
+ * that works on any runtime with `crypto.subtle` + `Request`/`Response`
4
+ * + long-lived connection primitives — in practice: Node, Bun, Deno,
5
+ * Deno Deploy, Cloudflare Workers + Durable Objects.
6
+ *
7
+ * Intentionally does NOT import the `ws` library or any `node:*`
8
+ * modules. Node-specific wiring lives in `./factory.ts`
9
+ * (`createLluiAgentServer`); web runtimes use `./web/` adapters on
10
+ * top of this core.
11
+ */
12
+ import type { ServerOptions } from './options.js';
13
+ import type { TokenStore } from './token-store.js';
14
+ import type { IdentityResolver } from './identity.js';
15
+ import type { AuditSink } from './audit.js';
16
+ import type { RateLimiter } from './rate-limit.js';
17
+ import type { PairingConnection, PairingRegistry } from './ws/pairing-registry.js';
18
+ /**
19
+ * Options accepted by `createLluiAgentCore`. Strict subset of
20
+ * `ServerOptions` — everything needed to build the router, registry,
21
+ * and accept-connection primitive. The Node factory adds WebSocket
22
+ * upgrade wiring on top.
23
+ */
24
+ export type CoreOptions = {
25
+ signingKey: ServerOptions['signingKey'];
26
+ tokenStore?: TokenStore;
27
+ identityResolver?: IdentityResolver;
28
+ auditSink?: AuditSink;
29
+ rateLimiter?: RateLimiter;
30
+ lapBasePath?: string;
31
+ /**
32
+ * Override the default `InMemoryPairingRegistry`. Web runtimes that
33
+ * need a different pairing implementation (e.g. a Cloudflare
34
+ * Durable Object that persists across isolates) pass it here.
35
+ */
36
+ registry?: PairingRegistry;
37
+ };
38
+ export type AcceptResult = {
39
+ ok: true;
40
+ tid: string;
41
+ } | {
42
+ ok: false;
43
+ status: number;
44
+ code: 'auth-failed' | 'revoked';
45
+ };
46
+ /**
47
+ * Handle returned by `createLluiAgentCore`. Purely runtime-neutral —
48
+ * `router` is a Fetch-style handler, `acceptConnection` is the
49
+ * primitive that runtime-specific WebSocket adapters call after
50
+ * accepting a socket in their native way.
51
+ */
52
+ export type AgentCoreHandle = {
53
+ router: (req: Request) => Promise<Response | null>;
54
+ registry: PairingRegistry;
55
+ tokenStore: TokenStore;
56
+ auditSink: AuditSink;
57
+ /**
58
+ * Validate an agent token and register a `PairingConnection` with
59
+ * the registry. Use this after accepting a WebSocket upgrade via
60
+ * your runtime's native API (e.g. `WebSocketPair` on Cloudflare,
61
+ * `Deno.upgradeWebSocket` on Deno, `server.upgrade` on Bun).
62
+ *
63
+ * On success: marks the token `awaiting-claude`, writes an audit
64
+ * entry, and returns `{ok: true, tid}`. On failure: returns an
65
+ * appropriate HTTP status for the caller to encode into the
66
+ * upgrade response (401 for auth failure, 403 for revoked).
67
+ */
68
+ acceptConnection: (token: string, conn: PairingConnection) => Promise<AcceptResult>;
69
+ };
70
+ /**
71
+ * Compose the runtime-neutral agent server. The returned handle has
72
+ * everything the LAP HTTP routes and the WebSocket acceptance
73
+ * plumbing need; runtime adapters wire the native upgrade API on
74
+ * top (see `@llui/agent/server` for Node, `@llui/agent/server/web`
75
+ * for WHATWG runtimes).
76
+ */
77
+ export declare function createLluiAgentCore(opts: CoreOptions): AgentCoreHandle;
78
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/server/core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAWlF;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,EAAE,aAAa,CAAC,YAAY,CAAC,CAAA;IACvC,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAAA;CAAE,CAAA;AAElE;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAA;IAClD,QAAQ,EAAE,eAAe,CAAA;IACzB,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB;;;;;;;;;;OAUG;IACH,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;CACpF,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,eAAe,CA2EtE"}
@@ -0,0 +1,84 @@
1
+ import { InMemoryTokenStore } from './token-store.js';
2
+ import { consoleAuditSink } from './audit.js';
3
+ import { defaultRateLimiter } from './rate-limit.js';
4
+ import { createHttpRouter } from './http/router.js';
5
+ import { createLapRouter } from './lap/router.js';
6
+ import { InMemoryPairingRegistry } from './ws/pairing-registry.js';
7
+ import { verifyToken } from './token.js';
8
+ const ANONYMOUS_RESOLVER = async () => null;
9
+ /**
10
+ * Compose the runtime-neutral agent server. The returned handle has
11
+ * everything the LAP HTTP routes and the WebSocket acceptance
12
+ * plumbing need; runtime adapters wire the native upgrade API on
13
+ * top (see `@llui/agent/server` for Node, `@llui/agent/server/web`
14
+ * for WHATWG runtimes).
15
+ */
16
+ export function createLluiAgentCore(opts) {
17
+ if (!opts.signingKey) {
18
+ throw new Error('createLluiAgentCore: signingKey is required');
19
+ }
20
+ const tokenStore = opts.tokenStore ?? new InMemoryTokenStore();
21
+ const identityResolver = opts.identityResolver ?? ANONYMOUS_RESOLVER;
22
+ const auditSink = opts.auditSink ?? consoleAuditSink;
23
+ const rateLimiter = opts.rateLimiter ?? defaultRateLimiter({ perBucket: '30/minute' });
24
+ const lapBasePath = opts.lapBasePath ?? '/agent/lap/v1';
25
+ const registry = opts.registry ??
26
+ new InMemoryPairingRegistry({
27
+ onLogAppend: (tid, entry) => {
28
+ void auditSink.write({
29
+ at: entry.at,
30
+ tid,
31
+ uid: null,
32
+ event: 'lap-call',
33
+ detail: {
34
+ source: 'client-log',
35
+ kind: entry.kind,
36
+ variant: entry.variant,
37
+ intent: entry.intent,
38
+ },
39
+ });
40
+ },
41
+ });
42
+ const httpRouter = createHttpRouter({
43
+ signingKey: opts.signingKey,
44
+ tokenStore,
45
+ identityResolver,
46
+ auditSink,
47
+ lapBasePath,
48
+ });
49
+ const lapRouter = createLapRouter({
50
+ signingKey: opts.signingKey,
51
+ tokenStore,
52
+ registry,
53
+ auditSink,
54
+ rateLimiter,
55
+ }, lapBasePath);
56
+ const router = async (req) => {
57
+ const lapRes = await lapRouter(req);
58
+ if (lapRes)
59
+ return lapRes;
60
+ return httpRouter(req);
61
+ };
62
+ const acceptConnection = async (token, conn) => {
63
+ const verified = await verifyToken(token, opts.signingKey);
64
+ if (verified.kind !== 'ok')
65
+ return { ok: false, status: 401, code: 'auth-failed' };
66
+ const { tid } = verified.payload;
67
+ const rec = await tokenStore.findByTid(tid);
68
+ if (!rec || rec.status === 'revoked')
69
+ return { ok: false, status: 403, code: 'revoked' };
70
+ registry.register(tid, conn);
71
+ const nowMs = Date.now();
72
+ await tokenStore.markAwaitingClaude(tid, nowMs);
73
+ await auditSink.write({
74
+ at: nowMs,
75
+ tid,
76
+ uid: null,
77
+ event: 'claim',
78
+ detail: { transport: 'ws' },
79
+ });
80
+ return { ok: true, tid };
81
+ };
82
+ return { router, registry, tokenStore, auditSink, acceptConnection };
83
+ }
84
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/server/core.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Runtime-neutral core of the LLui agent server. Exports everything\n * that works on any runtime with `crypto.subtle` + `Request`/`Response`\n * + long-lived connection primitives — in practice: Node, Bun, Deno,\n * Deno Deploy, Cloudflare Workers + Durable Objects.\n *\n * Intentionally does NOT import the `ws` library or any `node:*`\n * modules. Node-specific wiring lives in `./factory.ts`\n * (`createLluiAgentServer`); web runtimes use `./web/` adapters on\n * top of this core.\n */\nimport type { ServerOptions } from './options.js'\nimport type { TokenStore } from './token-store.js'\nimport type { IdentityResolver } from './identity.js'\nimport type { AuditSink } from './audit.js'\nimport type { RateLimiter } from './rate-limit.js'\nimport type { PairingConnection, PairingRegistry } from './ws/pairing-registry.js'\nimport { InMemoryTokenStore } from './token-store.js'\nimport { consoleAuditSink } from './audit.js'\nimport { defaultRateLimiter } from './rate-limit.js'\nimport { createHttpRouter } from './http/router.js'\nimport { createLapRouter } from './lap/router.js'\nimport { InMemoryPairingRegistry } from './ws/pairing-registry.js'\nimport { verifyToken } from './token.js'\n\nconst ANONYMOUS_RESOLVER: IdentityResolver = async () => null\n\n/**\n * Options accepted by `createLluiAgentCore`. Strict subset of\n * `ServerOptions` — everything needed to build the router, registry,\n * and accept-connection primitive. The Node factory adds WebSocket\n * upgrade wiring on top.\n */\nexport type CoreOptions = {\n signingKey: ServerOptions['signingKey']\n tokenStore?: TokenStore\n identityResolver?: IdentityResolver\n auditSink?: AuditSink\n rateLimiter?: RateLimiter\n lapBasePath?: string\n /**\n * Override the default `InMemoryPairingRegistry`. Web runtimes that\n * need a different pairing implementation (e.g. a Cloudflare\n * Durable Object that persists across isolates) pass it here.\n */\n registry?: PairingRegistry\n}\n\nexport type AcceptResult =\n | { ok: true; tid: string }\n | { ok: false; status: number; code: 'auth-failed' | 'revoked' }\n\n/**\n * Handle returned by `createLluiAgentCore`. Purely runtime-neutral —\n * `router` is a Fetch-style handler, `acceptConnection` is the\n * primitive that runtime-specific WebSocket adapters call after\n * accepting a socket in their native way.\n */\nexport type AgentCoreHandle = {\n router: (req: Request) => Promise<Response | null>\n registry: PairingRegistry\n tokenStore: TokenStore\n auditSink: AuditSink\n /**\n * Validate an agent token and register a `PairingConnection` with\n * the registry. Use this after accepting a WebSocket upgrade via\n * your runtime's native API (e.g. `WebSocketPair` on Cloudflare,\n * `Deno.upgradeWebSocket` on Deno, `server.upgrade` on Bun).\n *\n * On success: marks the token `awaiting-claude`, writes an audit\n * entry, and returns `{ok: true, tid}`. On failure: returns an\n * appropriate HTTP status for the caller to encode into the\n * upgrade response (401 for auth failure, 403 for revoked).\n */\n acceptConnection: (token: string, conn: PairingConnection) => Promise<AcceptResult>\n}\n\n/**\n * Compose the runtime-neutral agent server. The returned handle has\n * everything the LAP HTTP routes and the WebSocket acceptance\n * plumbing need; runtime adapters wire the native upgrade API on\n * top (see `@llui/agent/server` for Node, `@llui/agent/server/web`\n * for WHATWG runtimes).\n */\nexport function createLluiAgentCore(opts: CoreOptions): AgentCoreHandle {\n if (!opts.signingKey) {\n throw new Error('createLluiAgentCore: signingKey is required')\n }\n\n const tokenStore = opts.tokenStore ?? new InMemoryTokenStore()\n const identityResolver = opts.identityResolver ?? ANONYMOUS_RESOLVER\n const auditSink = opts.auditSink ?? consoleAuditSink\n const rateLimiter = opts.rateLimiter ?? defaultRateLimiter({ perBucket: '30/minute' })\n const lapBasePath = opts.lapBasePath ?? '/agent/lap/v1'\n\n const registry: PairingRegistry =\n opts.registry ??\n new InMemoryPairingRegistry({\n onLogAppend: (tid, entry) => {\n void auditSink.write({\n at: entry.at,\n tid,\n uid: null,\n event: 'lap-call',\n detail: {\n source: 'client-log',\n kind: entry.kind,\n variant: entry.variant,\n intent: entry.intent,\n },\n })\n },\n })\n\n const httpRouter = createHttpRouter({\n signingKey: opts.signingKey,\n tokenStore,\n identityResolver,\n auditSink,\n lapBasePath,\n })\n\n const lapRouter = createLapRouter(\n {\n signingKey: opts.signingKey,\n tokenStore,\n registry,\n auditSink,\n rateLimiter,\n },\n lapBasePath,\n )\n\n const router: AgentCoreHandle['router'] = async (req) => {\n const lapRes = await lapRouter(req)\n if (lapRes) return lapRes\n return httpRouter(req)\n }\n\n const acceptConnection: AgentCoreHandle['acceptConnection'] = async (token, conn) => {\n const verified = await verifyToken(token, opts.signingKey)\n if (verified.kind !== 'ok') return { ok: false, status: 401, code: 'auth-failed' }\n const { tid } = verified.payload\n const rec = await tokenStore.findByTid(tid)\n if (!rec || rec.status === 'revoked') return { ok: false, status: 403, code: 'revoked' }\n registry.register(tid, conn)\n const nowMs = Date.now()\n await tokenStore.markAwaitingClaude(tid, nowMs)\n await auditSink.write({\n at: nowMs,\n tid,\n uid: null,\n event: 'claim',\n detail: { transport: 'ws' },\n })\n return { ok: true, tid }\n }\n\n return { router, registry, tokenStore, auditSink, acceptConnection }\n}\n"]}
@@ -1,8 +1,10 @@
1
1
  import type { ServerOptions, AgentServerHandle } from './options.js';
2
2
  /**
3
- * Compose the server from its (defaulted) parts. Returns a handle with a
4
- * `router` that dispatches `/agent/lap/v1/*` (LAP, checked first) then
5
- * `/agent/*` (HTTP management), and a `wsUpgrade` for `/agent/ws`.
3
+ * Node adapter. Wraps the runtime-neutral core with a Node-specific
4
+ * `wsUpgrade` handler that uses the `ws` library. Imports `ws`
5
+ * eagerly, so this module only works where `ws` is available — use
6
+ * `@llui/agent/server/web` for Cloudflare Workers, Deno, or other
7
+ * WHATWG runtimes.
6
8
  *
7
9
  * Spec §10.1, §10.4.
8
10
  */
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/server/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAWpE;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,iBAAiB,CA6D5E"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/server/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAIpE;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,iBAAiB,CAkB5E"}