@llui/agent 0.0.32 → 0.0.35

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 (145) hide show
  1. package/README.md +82 -1
  2. package/dist/client/agentConfirm.d.ts +48 -18
  3. package/dist/client/agentConfirm.d.ts.map +1 -1
  4. package/dist/client/agentConfirm.js +28 -25
  5. package/dist/client/agentConfirm.js.map +1 -1
  6. package/dist/client/agentConnect.d.ts +95 -34
  7. package/dist/client/agentConnect.d.ts.map +1 -1
  8. package/dist/client/agentConnect.js +85 -47
  9. package/dist/client/agentConnect.js.map +1 -1
  10. package/dist/client/agentLog.d.ts +31 -14
  11. package/dist/client/agentLog.d.ts.map +1 -1
  12. package/dist/client/agentLog.js +39 -20
  13. package/dist/client/agentLog.js.map +1 -1
  14. package/dist/client/effect-handler.d.ts +23 -0
  15. package/dist/client/effect-handler.d.ts.map +1 -1
  16. package/dist/client/effect-handler.js +185 -126
  17. package/dist/client/effect-handler.js.map +1 -1
  18. package/dist/client/effects.d.ts +13 -2
  19. package/dist/client/effects.d.ts.map +1 -1
  20. package/dist/client/effects.js.map +1 -1
  21. package/dist/client/factory.d.ts +55 -3
  22. package/dist/client/factory.d.ts.map +1 -1
  23. package/dist/client/factory.js +30 -5
  24. package/dist/client/factory.js.map +1 -1
  25. package/dist/client/rpc/describe-visible-content.d.ts +18 -5
  26. package/dist/client/rpc/describe-visible-content.d.ts.map +1 -1
  27. package/dist/client/rpc/describe-visible-content.js +112 -7
  28. package/dist/client/rpc/describe-visible-content.js.map +1 -1
  29. package/dist/client/rpc/list-actions.d.ts +52 -2
  30. package/dist/client/rpc/list-actions.d.ts.map +1 -1
  31. package/dist/client/rpc/list-actions.js +187 -5
  32. package/dist/client/rpc/list-actions.js.map +1 -1
  33. package/dist/client/rpc/query-state.d.ts +32 -0
  34. package/dist/client/rpc/query-state.d.ts.map +1 -0
  35. package/dist/client/rpc/query-state.js +82 -0
  36. package/dist/client/rpc/query-state.js.map +1 -0
  37. package/dist/client/rpc/send-message.d.ts +2 -0
  38. package/dist/client/rpc/send-message.d.ts.map +1 -1
  39. package/dist/client/rpc/send-message.js +119 -9
  40. package/dist/client/rpc/send-message.js.map +1 -1
  41. package/dist/client/rpc/would-dispatch.d.ts +66 -0
  42. package/dist/client/rpc/would-dispatch.d.ts.map +1 -0
  43. package/dist/client/rpc/would-dispatch.js +21 -0
  44. package/dist/client/rpc/would-dispatch.js.map +1 -0
  45. package/dist/client/ws-client.d.ts +3 -1
  46. package/dist/client/ws-client.d.ts.map +1 -1
  47. package/dist/client/ws-client.js +29 -0
  48. package/dist/client/ws-client.js.map +1 -1
  49. package/dist/codecs.d.ts +107 -0
  50. package/dist/codecs.d.ts.map +1 -0
  51. package/dist/codecs.js +166 -0
  52. package/dist/codecs.js.map +1 -0
  53. package/dist/protocol.d.ts +172 -12
  54. package/dist/protocol.d.ts.map +1 -1
  55. package/dist/protocol.js +7 -1
  56. package/dist/protocol.js.map +1 -1
  57. package/dist/server/cloudflare/durable-object.d.ts +11 -4
  58. package/dist/server/cloudflare/durable-object.d.ts.map +1 -1
  59. package/dist/server/cloudflare/durable-object.js.map +1 -1
  60. package/dist/server/cloudflare/index.d.ts +8 -4
  61. package/dist/server/cloudflare/index.d.ts.map +1 -1
  62. package/dist/server/cloudflare/index.js +8 -4
  63. package/dist/server/cloudflare/index.js.map +1 -1
  64. package/dist/server/cloudflare/worker.d.ts +10 -2
  65. package/dist/server/cloudflare/worker.d.ts.map +1 -1
  66. package/dist/server/cloudflare/worker.js +13 -6
  67. package/dist/server/cloudflare/worker.js.map +1 -1
  68. package/dist/server/core-entry.d.ts +2 -2
  69. package/dist/server/core-entry.d.ts.map +1 -1
  70. package/dist/server/core-entry.js +1 -1
  71. package/dist/server/core-entry.js.map +1 -1
  72. package/dist/server/core.d.ts +1 -3
  73. package/dist/server/core.d.ts.map +1 -1
  74. package/dist/server/core.js +13 -12
  75. package/dist/server/core.js.map +1 -1
  76. package/dist/server/factory.d.ts +1 -1
  77. package/dist/server/factory.d.ts.map +1 -1
  78. package/dist/server/factory.js +1 -2
  79. package/dist/server/factory.js.map +1 -1
  80. package/dist/server/http/mint.d.ts +6 -1
  81. package/dist/server/http/mint.d.ts.map +1 -1
  82. package/dist/server/http/mint.js +14 -6
  83. package/dist/server/http/mint.js.map +1 -1
  84. package/dist/server/http/resume.d.ts +3 -1
  85. package/dist/server/http/resume.d.ts.map +1 -1
  86. package/dist/server/http/resume.js +9 -7
  87. package/dist/server/http/resume.js.map +1 -1
  88. package/dist/server/index.d.ts +2 -2
  89. package/dist/server/index.d.ts.map +1 -1
  90. package/dist/server/index.js +1 -1
  91. package/dist/server/index.js.map +1 -1
  92. package/dist/server/lap/confirm-result.d.ts +0 -1
  93. package/dist/server/lap/confirm-result.d.ts.map +1 -1
  94. package/dist/server/lap/confirm-result.js +1 -1
  95. package/dist/server/lap/confirm-result.js.map +1 -1
  96. package/dist/server/lap/describe.d.ts +13 -2
  97. package/dist/server/lap/describe.d.ts.map +1 -1
  98. package/dist/server/lap/describe.js +23 -6
  99. package/dist/server/lap/describe.js.map +1 -1
  100. package/dist/server/lap/forward.d.ts +13 -1
  101. package/dist/server/lap/forward.d.ts.map +1 -1
  102. package/dist/server/lap/forward.js +75 -1
  103. package/dist/server/lap/forward.js.map +1 -1
  104. package/dist/server/lap/message.d.ts +0 -1
  105. package/dist/server/lap/message.d.ts.map +1 -1
  106. package/dist/server/lap/message.js +1 -1
  107. package/dist/server/lap/message.js.map +1 -1
  108. package/dist/server/lap/observe.d.ts +0 -1
  109. package/dist/server/lap/observe.d.ts.map +1 -1
  110. package/dist/server/lap/observe.js +1 -1
  111. package/dist/server/lap/observe.js.map +1 -1
  112. package/dist/server/lap/router.d.ts.map +1 -1
  113. package/dist/server/lap/router.js +7 -1
  114. package/dist/server/lap/router.js.map +1 -1
  115. package/dist/server/lap/wait.d.ts +0 -1
  116. package/dist/server/lap/wait.d.ts.map +1 -1
  117. package/dist/server/lap/wait.js +1 -1
  118. package/dist/server/lap/wait.js.map +1 -1
  119. package/dist/server/options.d.ts +7 -5
  120. package/dist/server/options.d.ts.map +1 -1
  121. package/dist/server/options.js.map +1 -1
  122. package/dist/server/token-store.d.ts +22 -0
  123. package/dist/server/token-store.d.ts.map +1 -1
  124. package/dist/server/token-store.js +24 -0
  125. package/dist/server/token-store.js.map +1 -1
  126. package/dist/server/token.d.ts +32 -17
  127. package/dist/server/token.d.ts.map +1 -1
  128. package/dist/server/token.js +40 -103
  129. package/dist/server/token.js.map +1 -1
  130. package/dist/server/web/upgrade.d.ts +1 -1
  131. package/dist/server/web/upgrade.js +1 -1
  132. package/dist/server/web/upgrade.js.map +1 -1
  133. package/dist/server/ws/pairing-registry.d.ts +22 -6
  134. package/dist/server/ws/pairing-registry.d.ts.map +1 -1
  135. package/dist/server/ws/pairing-registry.js +49 -0
  136. package/dist/server/ws/pairing-registry.js.map +1 -1
  137. package/dist/server/ws/upgrade.d.ts +0 -1
  138. package/dist/server/ws/upgrade.d.ts.map +1 -1
  139. package/dist/server/ws/upgrade.js +12 -4
  140. package/dist/server/ws/upgrade.js.map +1 -1
  141. package/dist/state-diff.d.ts +52 -0
  142. package/dist/state-diff.d.ts.map +1 -0
  143. package/dist/state-diff.js +119 -0
  144. package/dist/state-diff.js.map +1 -0
  145. package/package.json +7 -3
@@ -22,6 +22,6 @@ export { consoleAuditSink } from './audit.js';
22
22
  export type { AuditSink } from './audit.js';
23
23
  export { defaultRateLimiter } from './rate-limit.js';
24
24
  export type { RateLimiter } from './rate-limit.js';
25
- export { signToken, verifyToken } from './token.js';
26
- export type { TokenPayload, VerifyResult } from './token.js';
25
+ export { mintToken, tokenHashOf } from './token.js';
26
+ export type { VerifyResult } from './token.js';
27
27
  //# sourceMappingURL=core-entry.d.ts.map
@@ -1 +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"}
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,MAAM,YAAY,CAAA"}
@@ -15,5 +15,5 @@ export { InMemoryTokenStore } from './token-store.js';
15
15
  export { defaultIdentityResolver, signCookieValue } from './identity.js';
16
16
  export { consoleAuditSink } from './audit.js';
17
17
  export { defaultRateLimiter } from './rate-limit.js';
18
- export { signToken, verifyToken } from './token.js';
18
+ export { mintToken, tokenHashOf } from './token.js';
19
19
  //# sourceMappingURL=core-entry.js.map
@@ -1 +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"]}
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 { mintToken, tokenHashOf } from './token.js'\nexport type { VerifyResult } from './token.js'\n"]}
@@ -9,7 +9,6 @@
9
9
  * (`createLluiAgentServer`); web runtimes use `./web/` adapters on
10
10
  * top of this core.
11
11
  */
12
- import type { ServerOptions } from './options.js';
13
12
  import type { TokenStore } from './token-store.js';
14
13
  import type { IdentityResolver } from './identity.js';
15
14
  import type { AuditSink } from './audit.js';
@@ -22,7 +21,6 @@ import type { PairingConnection, PairingRegistry } from './ws/pairing-registry.j
22
21
  * upgrade wiring on top.
23
22
  */
24
23
  export type CoreOptions = {
25
- signingKey: ServerOptions['signingKey'];
26
24
  tokenStore?: TokenStore;
27
25
  identityResolver?: IdentityResolver;
28
26
  auditSink?: AuditSink;
@@ -74,5 +72,5 @@ export type AgentCoreHandle = {
74
72
  * top (see `@llui/agent/server` for Node, `@llui/agent/server/web`
75
73
  * for WHATWG runtimes).
76
74
  */
77
- export declare function createLluiAgentCore(opts: CoreOptions): AgentCoreHandle;
75
+ export declare function createLluiAgentCore(opts?: CoreOptions): AgentCoreHandle;
78
76
  //# sourceMappingURL=core.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/server/core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,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,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,GAAE,WAAgB,GAAG,eAAe,CAyE3E"}
@@ -4,7 +4,7 @@ import { defaultRateLimiter } from './rate-limit.js';
4
4
  import { createHttpRouter } from './http/router.js';
5
5
  import { createLapRouter } from './lap/router.js';
6
6
  import { InMemoryPairingRegistry } from './ws/pairing-registry.js';
7
- import { verifyToken } from './token.js';
7
+ import { tokenHashOf } from './token.js';
8
8
  const ANONYMOUS_RESOLVER = async () => null;
9
9
  /**
10
10
  * Compose the runtime-neutral agent server. The returned handle has
@@ -13,10 +13,7 @@ const ANONYMOUS_RESOLVER = async () => null;
13
13
  * top (see `@llui/agent/server` for Node, `@llui/agent/server/web`
14
14
  * for WHATWG runtimes).
15
15
  */
16
- export function createLluiAgentCore(opts) {
17
- if (!opts.signingKey) {
18
- throw new Error('createLluiAgentCore: signingKey is required');
19
- }
16
+ export function createLluiAgentCore(opts = {}) {
20
17
  const tokenStore = opts.tokenStore ?? new InMemoryTokenStore();
21
18
  const identityResolver = opts.identityResolver ?? ANONYMOUS_RESOLVER;
22
19
  const auditSink = opts.auditSink ?? consoleAuditSink;
@@ -40,14 +37,12 @@ export function createLluiAgentCore(opts) {
40
37
  },
41
38
  });
42
39
  const httpRouter = createHttpRouter({
43
- signingKey: opts.signingKey,
44
40
  tokenStore,
45
41
  identityResolver,
46
42
  auditSink,
47
43
  lapBasePath,
48
44
  });
49
45
  const lapRouter = createLapRouter({
50
- signingKey: opts.signingKey,
51
46
  tokenStore,
52
47
  registry,
53
48
  auditSink,
@@ -60,13 +55,19 @@ export function createLluiAgentCore(opts) {
60
55
  return httpRouter(req);
61
56
  };
62
57
  const acceptConnection = async (token, conn) => {
63
- const verified = await verifyToken(token, opts.signingKey);
64
- if (verified.kind !== 'ok')
58
+ // Same hash-lookup path as the LAP HTTP routes — keeps the auth
59
+ // story uniform across HTTP and WS surfaces.
60
+ const hash = await tokenHashOf(token);
61
+ if (!hash)
65
62
  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')
63
+ const rec = await tokenStore.findByTokenHash(hash);
64
+ if (!rec)
65
+ return { ok: false, status: 401, code: 'auth-failed' };
66
+ if (rec.expiresAt <= Date.now())
67
+ return { ok: false, status: 401, code: 'auth-failed' };
68
+ if (rec.status === 'revoked')
69
69
  return { ok: false, status: 403, code: 'revoked' };
70
+ const tid = rec.tid;
70
71
  registry.register(tid, conn);
71
72
  const nowMs = Date.now();
72
73
  await tokenStore.markAwaitingClaude(tid, nowMs);
@@ -1 +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
+ {"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 { 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 { tokenHashOf } 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 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 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 tokenStore,\n identityResolver,\n auditSink,\n lapBasePath,\n })\n\n const lapRouter = createLapRouter(\n {\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 // Same hash-lookup path as the LAP HTTP routes — keeps the auth\n // story uniform across HTTP and WS surfaces.\n const hash = await tokenHashOf(token)\n if (!hash) return { ok: false, status: 401, code: 'auth-failed' }\n const rec = await tokenStore.findByTokenHash(hash)\n if (!rec) return { ok: false, status: 401, code: 'auth-failed' }\n if (rec.expiresAt <= Date.now()) return { ok: false, status: 401, code: 'auth-failed' }\n if (rec.status === 'revoked') return { ok: false, status: 403, code: 'revoked' }\n const tid = rec.tid\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"]}
@@ -8,5 +8,5 @@ import type { ServerOptions, AgentServerHandle } from './options.js';
8
8
  *
9
9
  * Spec §10.1, §10.4.
10
10
  */
11
- export declare function createLluiAgentServer(opts: ServerOptions): AgentServerHandle;
11
+ export declare function createLluiAgentServer(opts?: ServerOptions): AgentServerHandle;
12
12
  //# sourceMappingURL=factory.d.ts.map
@@ -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;AAIpE;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,iBAAiB,CAkB5E"}
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,GAAE,aAAkB,GAAG,iBAAiB,CAiBjF"}
@@ -9,10 +9,9 @@ import { createWsUpgradeHandler } from './ws/upgrade.js';
9
9
  *
10
10
  * Spec §10.1, §10.4.
11
11
  */
12
- export function createLluiAgentServer(opts) {
12
+ export function createLluiAgentServer(opts = {}) {
13
13
  const core = createLluiAgentCore(opts);
14
14
  const wsUpgrade = createWsUpgradeHandler({
15
- signingKey: opts.signingKey,
16
15
  tokenStore: core.tokenStore,
17
16
  registry: core.registry,
18
17
  auditSink: core.auditSink,
@@ -1 +1 @@
1
- {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/server/factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAExD;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAmB;IACvD,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAEtC,MAAM,SAAS,GAAG,sBAAsB,CAAC;QACvC,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC,CAAA;IAEF,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS;QACT,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;KACxC,CAAA;AACH,CAAC","sourcesContent":["import type { ServerOptions, AgentServerHandle } from './options.js'\nimport { createLluiAgentCore } from './core.js'\nimport { createWsUpgradeHandler } from './ws/upgrade.js'\n\n/**\n * Node adapter. Wraps the runtime-neutral core with a Node-specific\n * `wsUpgrade` handler that uses the `ws` library. Imports `ws`\n * eagerly, so this module only works where `ws` is available — use\n * `@llui/agent/server/web` for Cloudflare Workers, Deno, or other\n * WHATWG runtimes.\n *\n * Spec §10.1, §10.4.\n */\nexport function createLluiAgentServer(opts: ServerOptions): AgentServerHandle {\n const core = createLluiAgentCore(opts)\n\n const wsUpgrade = createWsUpgradeHandler({\n signingKey: opts.signingKey,\n tokenStore: core.tokenStore,\n registry: core.registry,\n auditSink: core.auditSink,\n })\n\n return {\n router: core.router,\n wsUpgrade,\n registry: core.registry,\n tokenStore: core.tokenStore,\n auditSink: core.auditSink,\n acceptConnection: core.acceptConnection,\n }\n}\n"]}
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/server/factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAExD;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAsB,EAAE;IAC5D,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAEtC,MAAM,SAAS,GAAG,sBAAsB,CAAC;QACvC,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC,CAAA;IAEF,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS;QACT,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;KACxC,CAAA;AACH,CAAC","sourcesContent":["import type { ServerOptions, AgentServerHandle } from './options.js'\nimport { createLluiAgentCore } from './core.js'\nimport { createWsUpgradeHandler } from './ws/upgrade.js'\n\n/**\n * Node adapter. Wraps the runtime-neutral core with a Node-specific\n * `wsUpgrade` handler that uses the `ws` library. Imports `ws`\n * eagerly, so this module only works where `ws` is available — use\n * `@llui/agent/server/web` for Cloudflare Workers, Deno, or other\n * WHATWG runtimes.\n *\n * Spec §10.1, §10.4.\n */\nexport function createLluiAgentServer(opts: ServerOptions = {}): AgentServerHandle {\n const core = createLluiAgentCore(opts)\n\n const wsUpgrade = createWsUpgradeHandler({\n tokenStore: core.tokenStore,\n registry: core.registry,\n auditSink: core.auditSink,\n })\n\n return {\n router: core.router,\n wsUpgrade,\n registry: core.registry,\n tokenStore: core.tokenStore,\n auditSink: core.auditSink,\n acceptConnection: core.acceptConnection,\n }\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  import type { TokenStore } from '../token-store.js';
2
2
  import type { IdentityResolver } from '../identity.js';
3
3
  import type { AuditSink } from '../audit.js';
4
+ import { mintToken } from '../token.js';
4
5
  export type MintDeps = {
5
- signingKey: string | Uint8Array;
6
6
  tokenStore: TokenStore;
7
7
  identityResolver: IdentityResolver;
8
8
  auditSink: AuditSink;
@@ -13,6 +13,11 @@ export type MintDeps = {
13
13
  uuid?: () => string;
14
14
  /** Hard-expiry window, default 24 h. */
15
15
  hardExpiryMs?: number;
16
+ /**
17
+ * Override the token mint primitive (for tests that need a known
18
+ * token value). Production uses the default opaque mint.
19
+ */
20
+ mint?: typeof mintToken;
16
21
  };
17
22
  /**
18
23
  * POST /agent/mint — creates a pairing record and returns the mint
@@ -1 +1 @@
1
- {"version":3,"file":"mint.d.ts","sourceRoot":"","sources":["../../../src/server/http/mint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAI5C,MAAM,MAAM,QAAQ,GAAG;IACrB,UAAU,EAAE,MAAM,GAAG,UAAU,CAAA;IAC/B,UAAU,EAAE,UAAU,CAAA;IACtB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,MAAM,CAAA;IACnB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwDhF"}
1
+ {"version":3,"file":"mint.d.ts","sourceRoot":"","sources":["../../../src/server/http/mint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAGvC,MAAM,MAAM,QAAQ,GAAG;IACrB,UAAU,EAAE,UAAU,CAAA;IACtB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,MAAM,CAAA;IACnB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,SAAS,CAAA;CACxB,CAAA;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAgEhF"}
@@ -1,4 +1,4 @@
1
- import { signToken } from '../token.js';
1
+ import { mintToken } from '../token.js';
2
2
  /**
3
3
  * POST /agent/mint — creates a pairing record and returns the mint
4
4
  * response. See spec §6.2. The caller is responsible for routing
@@ -17,16 +17,21 @@ export async function handleMint(req, deps) {
17
17
  const uid = await deps.identityResolver(req);
18
18
  const tid = uuid();
19
19
  const nowMs = now();
20
- const iat = Math.floor(nowMs / 1000);
21
- const exp = Math.floor((nowMs + hardExpiryMs) / 1000);
20
+ const expiresAt = nowMs + hardExpiryMs;
22
21
  const origin = new URL(req.url).origin;
23
- const payload = { tid, iat, exp, scope: 'agent' };
24
- const token = await signToken(payload, deps.signingKey);
22
+ // Mint an opaque random token + the SHA-256 hash we'll persist. The
23
+ // plaintext token is returned to the caller in this single HTTP
24
+ // response; from this point on, the server only knows the hash. See
25
+ // token.ts for the security rationale.
26
+ const mint = deps.mint ?? mintToken;
27
+ const { token, tokenHash } = await mint();
25
28
  const record = {
26
29
  tid,
30
+ tokenHash,
27
31
  uid,
28
32
  status: 'awaiting-ws',
29
33
  createdAt: nowMs,
34
+ expiresAt,
30
35
  lastSeenAt: nowMs,
31
36
  pendingResumeUntil: null,
32
37
  origin,
@@ -47,7 +52,10 @@ export async function handleMint(req, deps) {
47
52
  tid,
48
53
  wsUrl,
49
54
  lapUrl,
50
- expiresAt: exp,
55
+ // Wire format keeps the seconds-since-epoch convention from the
56
+ // pre-0.0.35 JWT-payload `exp` so existing clients reading
57
+ // `expiresAt` see the same units.
58
+ expiresAt: Math.floor(expiresAt / 1000),
51
59
  };
52
60
  return new Response(JSON.stringify(body), {
53
61
  status: 200,
@@ -1 +1 @@
1
- {"version":3,"file":"mint.js","sourceRoot":"","sources":["../../../src/server/http/mint.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TokenStore } from '../token-store.js'\nimport type { IdentityResolver } from '../identity.js'\nimport type { AuditSink } from '../audit.js'\nimport { signToken } from '../token.js'\nimport type { MintResponse, TokenPayload, TokenRecord } from '../../protocol.js'\n\nexport type MintDeps = {\n signingKey: string | Uint8Array\n tokenStore: TokenStore\n identityResolver: IdentityResolver\n auditSink: AuditSink\n lapBasePath: string\n /** Wall-clock in milliseconds; injectable for tests. */\n now?: () => number\n /** UUID generator; injectable for tests. */\n uuid?: () => string\n /** Hard-expiry window, default 24 h. */\n hardExpiryMs?: number\n}\n\n/**\n * POST /agent/mint — creates a pairing record and returns the mint\n * response. See spec §6.2. The caller is responsible for routing\n * `/agent/mint` requests to this handler; `router.ts` composes that.\n */\nexport async function handleMint(req: Request, deps: MintDeps): Promise<Response> {\n if (req.method !== 'POST') {\n return new Response(JSON.stringify({ error: { code: 'method-not-allowed' } }), {\n status: 405,\n headers: { 'content-type': 'application/json' },\n })\n }\n\n const now = deps.now ?? (() => Date.now())\n const uuid = deps.uuid ?? (() => crypto.randomUUID())\n const hardExpiryMs = deps.hardExpiryMs ?? 24 * 60 * 60 * 1000\n\n const uid = await deps.identityResolver(req)\n const tid = uuid()\n const nowMs = now()\n const iat = Math.floor(nowMs / 1000)\n const exp = Math.floor((nowMs + hardExpiryMs) / 1000)\n const origin = new URL(req.url).origin\n\n const payload: TokenPayload = { tid, iat, exp, scope: 'agent' }\n const token = await signToken(payload, deps.signingKey)\n\n const record: TokenRecord = {\n tid,\n uid,\n status: 'awaiting-ws',\n createdAt: nowMs,\n lastSeenAt: nowMs,\n pendingResumeUntil: null,\n origin,\n label: null,\n }\n await deps.tokenStore.create(record)\n\n await deps.auditSink.write({\n at: nowMs,\n tid,\n uid,\n event: 'mint',\n detail: { origin },\n })\n\n const wsUrl = toWsUrl(new URL(req.url).origin) + '/agent/ws'\n const lapUrl = new URL(deps.lapBasePath, origin).toString()\n\n const body: MintResponse = {\n token,\n tid,\n wsUrl,\n lapUrl,\n expiresAt: exp,\n }\n return new Response(JSON.stringify(body), {\n status: 200,\n headers: { 'content-type': 'application/json' },\n })\n}\n\nfunction toWsUrl(httpOrigin: string): string {\n return httpOrigin.startsWith('https://')\n ? 'wss://' + httpOrigin.slice('https://'.length)\n : 'ws://' + httpOrigin.slice('http://'.length)\n}\n"]}
1
+ {"version":3,"file":"mint.js","sourceRoot":"","sources":["../../../src/server/http/mint.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TokenStore } from '../token-store.js'\nimport type { IdentityResolver } from '../identity.js'\nimport type { AuditSink } from '../audit.js'\nimport { mintToken } from '../token.js'\nimport type { MintResponse, TokenRecord } from '../../protocol.js'\n\nexport type MintDeps = {\n tokenStore: TokenStore\n identityResolver: IdentityResolver\n auditSink: AuditSink\n lapBasePath: string\n /** Wall-clock in milliseconds; injectable for tests. */\n now?: () => number\n /** UUID generator; injectable for tests. */\n uuid?: () => string\n /** Hard-expiry window, default 24 h. */\n hardExpiryMs?: number\n /**\n * Override the token mint primitive (for tests that need a known\n * token value). Production uses the default opaque mint.\n */\n mint?: typeof mintToken\n}\n\n/**\n * POST /agent/mint — creates a pairing record and returns the mint\n * response. See spec §6.2. The caller is responsible for routing\n * `/agent/mint` requests to this handler; `router.ts` composes that.\n */\nexport async function handleMint(req: Request, deps: MintDeps): Promise<Response> {\n if (req.method !== 'POST') {\n return new Response(JSON.stringify({ error: { code: 'method-not-allowed' } }), {\n status: 405,\n headers: { 'content-type': 'application/json' },\n })\n }\n\n const now = deps.now ?? (() => Date.now())\n const uuid = deps.uuid ?? (() => crypto.randomUUID())\n const hardExpiryMs = deps.hardExpiryMs ?? 24 * 60 * 60 * 1000\n\n const uid = await deps.identityResolver(req)\n const tid = uuid()\n const nowMs = now()\n const expiresAt = nowMs + hardExpiryMs\n const origin = new URL(req.url).origin\n\n // Mint an opaque random token + the SHA-256 hash we'll persist. The\n // plaintext token is returned to the caller in this single HTTP\n // response; from this point on, the server only knows the hash. See\n // token.ts for the security rationale.\n const mint = deps.mint ?? mintToken\n const { token, tokenHash } = await mint()\n\n const record: TokenRecord = {\n tid,\n tokenHash,\n uid,\n status: 'awaiting-ws',\n createdAt: nowMs,\n expiresAt,\n lastSeenAt: nowMs,\n pendingResumeUntil: null,\n origin,\n label: null,\n }\n await deps.tokenStore.create(record)\n\n await deps.auditSink.write({\n at: nowMs,\n tid,\n uid,\n event: 'mint',\n detail: { origin },\n })\n\n const wsUrl = toWsUrl(new URL(req.url).origin) + '/agent/ws'\n const lapUrl = new URL(deps.lapBasePath, origin).toString()\n\n const body: MintResponse = {\n token,\n tid,\n wsUrl,\n lapUrl,\n // Wire format keeps the seconds-since-epoch convention from the\n // pre-0.0.35 JWT-payload `exp` so existing clients reading\n // `expiresAt` see the same units.\n expiresAt: Math.floor(expiresAt / 1000),\n }\n return new Response(JSON.stringify(body), {\n status: 200,\n headers: { 'content-type': 'application/json' },\n })\n}\n\nfunction toWsUrl(httpOrigin: string): string {\n return httpOrigin.startsWith('https://')\n ? 'wss://' + httpOrigin.slice('https://'.length)\n : 'ws://' + httpOrigin.slice('http://'.length)\n}\n"]}
@@ -1,13 +1,15 @@
1
1
  import type { TokenStore } from '../token-store.js';
2
2
  import type { IdentityResolver } from '../identity.js';
3
3
  import type { AuditSink } from '../audit.js';
4
+ import { mintToken } from '../token.js';
4
5
  export type ResumeDeps = {
5
6
  tokenStore: TokenStore;
6
7
  identityResolver: IdentityResolver;
7
8
  auditSink: AuditSink;
8
- signingKey?: string | Uint8Array;
9
9
  now?: () => number;
10
10
  hardExpiryMs?: number;
11
+ /** Override mint primitive for tests. */
12
+ mint?: typeof mintToken;
11
13
  };
12
14
  export declare function handleResumeList(req: Request, deps: ResumeDeps): Promise<Response>;
13
15
  export declare function handleResumeClaim(req: Request, deps: ResumeDeps): Promise<Response>;
@@ -1 +1 @@
1
- {"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../../src/server/http/resume.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAW5C,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,EAAE,UAAU,CAAA;IACtB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,SAAS,EAAE,SAAS,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,UAAU,CAAA;IAChC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyBxF;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoCzF"}
1
+ {"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../../src/server/http/resume.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AASvC,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,EAAE,UAAU,CAAA;IACtB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,SAAS,EAAE,SAAS,CAAA;IACpB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,yCAAyC;IACzC,IAAI,CAAC,EAAE,OAAO,SAAS,CAAA;CACxB,CAAA;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyBxF;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAuCzF"}
@@ -1,4 +1,4 @@
1
- import { signToken } from '../token.js';
1
+ import { mintToken } from '../token.js';
2
2
  export async function handleResumeList(req, deps) {
3
3
  if (req.method !== 'POST')
4
4
  return methodNotAllowed();
@@ -32,8 +32,6 @@ export async function handleResumeList(req, deps) {
32
32
  export async function handleResumeClaim(req, deps) {
33
33
  if (req.method !== 'POST')
34
34
  return methodNotAllowed();
35
- if (!deps.signingKey)
36
- return new Response(null, { status: 500 });
37
35
  const body = (await req.json().catch(() => null));
38
36
  if (!body || typeof body.tid !== 'string')
39
37
  return badRequest();
@@ -50,10 +48,14 @@ export async function handleResumeClaim(req, deps) {
50
48
  return forbidden();
51
49
  const nowMs = (deps.now ?? (() => Date.now()))();
52
50
  const hardExpiryMs = deps.hardExpiryMs ?? 24 * 60 * 60 * 1000;
53
- const iat = Math.floor(nowMs / 1000);
54
- const exp = Math.floor((nowMs + hardExpiryMs) / 1000);
55
- const payload = { tid: rec.tid, iat, exp, scope: 'agent' };
56
- const token = await signToken(payload, deps.signingKey);
51
+ const expiresAt = nowMs + hardExpiryMs;
52
+ // Resume mints a fresh opaque token bound to the existing `tid` and
53
+ // rotates the stored hash. The previous bearer is dropped from the
54
+ // hash index immediately, so a leaked old token can't continue
55
+ // using the resumed session. Same record, new bearer.
56
+ const mint = deps.mint ?? mintToken;
57
+ const { token, tokenHash } = await mint();
58
+ await deps.tokenStore.rotateTokenHash(rec.tid, tokenHash, expiresAt);
57
59
  await deps.tokenStore.markActive(rec.tid, rec.label ?? '(resumed)', nowMs);
58
60
  await deps.auditSink.write({
59
61
  at: nowMs,
@@ -1 +1 @@
1
- {"version":3,"file":"resume.js","sourceRoot":"","sources":["../../../src/server/http/resume.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TokenStore } from '../token-store.js'\nimport type { IdentityResolver } from '../identity.js'\nimport type { AuditSink } from '../audit.js'\nimport { signToken } from '../token.js'\nimport type {\n ResumeListRequest,\n ResumeListResponse,\n ResumeClaimRequest,\n ResumeClaimResponse,\n TokenPayload,\n AgentSession,\n} from '../../protocol.js'\n\nexport type ResumeDeps = {\n tokenStore: TokenStore\n identityResolver: IdentityResolver\n auditSink: AuditSink\n signingKey?: string | Uint8Array\n now?: () => number\n hardExpiryMs?: number\n}\n\nexport async function handleResumeList(req: Request, deps: ResumeDeps): Promise<Response> {\n if (req.method !== 'POST') return methodNotAllowed()\n const body = (await req.json().catch(() => null)) as ResumeListRequest | null\n if (!body || !Array.isArray(body.tids)) return badRequest()\n\n const uid = await deps.identityResolver(req)\n const nowMs = (deps.now ?? (() => Date.now()))()\n const out: AgentSession[] = []\n for (const tid of body.tids) {\n const rec = await deps.tokenStore.findByTid(tid)\n if (!rec) continue\n if (rec.uid !== uid) continue\n if (rec.status !== 'pending-resume') continue\n if (rec.pendingResumeUntil === null || rec.pendingResumeUntil < nowMs) continue\n out.push({\n tid: rec.tid,\n label: rec.label ?? '(unknown)',\n status: 'pending-resume',\n createdAt: rec.createdAt,\n lastSeenAt: rec.lastSeenAt,\n })\n }\n\n const payload: ResumeListResponse = { sessions: out }\n return jsonResponse(payload, 200)\n}\n\nexport async function handleResumeClaim(req: Request, deps: ResumeDeps): Promise<Response> {\n if (req.method !== 'POST') return methodNotAllowed()\n if (!deps.signingKey) return new Response(null, { status: 500 })\n\n const body = (await req.json().catch(() => null)) as ResumeClaimRequest | null\n if (!body || typeof body.tid !== 'string') return badRequest()\n\n const uid = await deps.identityResolver(req)\n const rec = await deps.tokenStore.findByTid(body.tid)\n if (!rec) return forbidden()\n if (rec.uid !== uid) return forbidden()\n if (rec.status !== 'pending-resume') return forbidden()\n\n const origin = new URL(req.url).origin\n if (rec.origin !== origin) return forbidden()\n\n const nowMs = (deps.now ?? (() => Date.now()))()\n const hardExpiryMs = deps.hardExpiryMs ?? 24 * 60 * 60 * 1000\n const iat = Math.floor(nowMs / 1000)\n const exp = Math.floor((nowMs + hardExpiryMs) / 1000)\n const payload: TokenPayload = { tid: rec.tid, iat, exp, scope: 'agent' }\n const token = await signToken(payload, deps.signingKey)\n\n await deps.tokenStore.markActive(rec.tid, rec.label ?? '(resumed)', nowMs)\n\n await deps.auditSink.write({\n at: nowMs,\n tid: rec.tid,\n uid: rec.uid,\n event: 'claim',\n detail: { origin },\n })\n\n const wsUrl = toWsUrl(origin) + '/agent/ws'\n const out: ResumeClaimResponse = { token, wsUrl }\n return jsonResponse(out, 200)\n}\n\nfunction jsonResponse(body: unknown, status: number): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n}\n\nfunction methodNotAllowed(): Response {\n return jsonResponse({ error: { code: 'method-not-allowed' } }, 405)\n}\n\nfunction badRequest(): Response {\n return jsonResponse({ error: { code: 'invalid' } }, 400)\n}\n\nfunction forbidden(): Response {\n return jsonResponse({ error: { code: 'revoked' } }, 403)\n}\n\nfunction toWsUrl(httpOrigin: string): string {\n return httpOrigin.startsWith('https://')\n ? 'wss://' + httpOrigin.slice('https://'.length)\n : 'ws://' + httpOrigin.slice('http://'.length)\n}\n"]}
1
+ {"version":3,"file":"resume.js","sourceRoot":"","sources":["../../../src/server/http/resume.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TokenStore } from '../token-store.js'\nimport type { IdentityResolver } from '../identity.js'\nimport type { AuditSink } from '../audit.js'\nimport { mintToken } from '../token.js'\nimport type {\n ResumeListRequest,\n ResumeListResponse,\n ResumeClaimRequest,\n ResumeClaimResponse,\n AgentSession,\n} from '../../protocol.js'\n\nexport type ResumeDeps = {\n tokenStore: TokenStore\n identityResolver: IdentityResolver\n auditSink: AuditSink\n now?: () => number\n hardExpiryMs?: number\n /** Override mint primitive for tests. */\n mint?: typeof mintToken\n}\n\nexport async function handleResumeList(req: Request, deps: ResumeDeps): Promise<Response> {\n if (req.method !== 'POST') return methodNotAllowed()\n const body = (await req.json().catch(() => null)) as ResumeListRequest | null\n if (!body || !Array.isArray(body.tids)) return badRequest()\n\n const uid = await deps.identityResolver(req)\n const nowMs = (deps.now ?? (() => Date.now()))()\n const out: AgentSession[] = []\n for (const tid of body.tids) {\n const rec = await deps.tokenStore.findByTid(tid)\n if (!rec) continue\n if (rec.uid !== uid) continue\n if (rec.status !== 'pending-resume') continue\n if (rec.pendingResumeUntil === null || rec.pendingResumeUntil < nowMs) continue\n out.push({\n tid: rec.tid,\n label: rec.label ?? '(unknown)',\n status: 'pending-resume',\n createdAt: rec.createdAt,\n lastSeenAt: rec.lastSeenAt,\n })\n }\n\n const payload: ResumeListResponse = { sessions: out }\n return jsonResponse(payload, 200)\n}\n\nexport async function handleResumeClaim(req: Request, deps: ResumeDeps): Promise<Response> {\n if (req.method !== 'POST') return methodNotAllowed()\n\n const body = (await req.json().catch(() => null)) as ResumeClaimRequest | null\n if (!body || typeof body.tid !== 'string') return badRequest()\n\n const uid = await deps.identityResolver(req)\n const rec = await deps.tokenStore.findByTid(body.tid)\n if (!rec) return forbidden()\n if (rec.uid !== uid) return forbidden()\n if (rec.status !== 'pending-resume') return forbidden()\n\n const origin = new URL(req.url).origin\n if (rec.origin !== origin) return forbidden()\n\n const nowMs = (deps.now ?? (() => Date.now()))()\n const hardExpiryMs = deps.hardExpiryMs ?? 24 * 60 * 60 * 1000\n const expiresAt = nowMs + hardExpiryMs\n\n // Resume mints a fresh opaque token bound to the existing `tid` and\n // rotates the stored hash. The previous bearer is dropped from the\n // hash index immediately, so a leaked old token can't continue\n // using the resumed session. Same record, new bearer.\n const mint = deps.mint ?? mintToken\n const { token, tokenHash } = await mint()\n await deps.tokenStore.rotateTokenHash(rec.tid, tokenHash, expiresAt)\n await deps.tokenStore.markActive(rec.tid, rec.label ?? '(resumed)', nowMs)\n\n await deps.auditSink.write({\n at: nowMs,\n tid: rec.tid,\n uid: rec.uid,\n event: 'claim',\n detail: { origin },\n })\n\n const wsUrl = toWsUrl(origin) + '/agent/ws'\n const out: ResumeClaimResponse = { token, wsUrl }\n return jsonResponse(out, 200)\n}\n\nfunction jsonResponse(body: unknown, status: number): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n}\n\nfunction methodNotAllowed(): Response {\n return jsonResponse({ error: { code: 'method-not-allowed' } }, 405)\n}\n\nfunction badRequest(): Response {\n return jsonResponse({ error: { code: 'invalid' } }, 400)\n}\n\nfunction forbidden(): Response {\n return jsonResponse({ error: { code: 'revoked' } }, 403)\n}\n\nfunction toWsUrl(httpOrigin: string): string {\n return httpOrigin.startsWith('https://')\n ? 'wss://' + httpOrigin.slice('https://'.length)\n : 'ws://' + httpOrigin.slice('http://'.length)\n}\n"]}
@@ -21,6 +21,6 @@ export { consoleAuditSink } from './audit.js';
21
21
  export type { AuditSink } from './audit.js';
22
22
  export { defaultRateLimiter } from './rate-limit.js';
23
23
  export type { RateLimiter } from './rate-limit.js';
24
- export { signToken, verifyToken } from './token.js';
25
- export type { TokenPayload, VerifyResult } from './token.js';
24
+ export { mintToken, tokenHashOf } from './token.js';
25
+ export type { VerifyResult } from './token.js';
26
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEpE,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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEpE,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,MAAM,YAAY,CAAA"}
@@ -14,5 +14,5 @@ export { InMemoryTokenStore } from './token-store.js';
14
14
  export { defaultIdentityResolver, signCookieValue } from './identity.js';
15
15
  export { consoleAuditSink } from './audit.js';
16
16
  export { defaultRateLimiter } from './rate-limit.js';
17
- export { signToken, verifyToken } from './token.js';
17
+ export { mintToken, tokenHashOf } from './token.js';
18
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAEpD,+EAA+E;AAC/E,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 * Default entry for Node server processes. Bundles the runtime-neutral\n * core with a `ws`-library-based WebSocket upgrade handler. For web\n * runtimes (Cloudflare Workers, Deno, Bun) where `ws` isn't\n * available, use `@llui/agent/server/core` + `@llui/agent/server/web`\n * instead.\n */\nexport { createLluiAgentServer } from './factory.js'\nexport type { ServerOptions, AgentServerHandle } from './options.js'\n// Runtime-neutral core — re-exported so Node users don't need a second import.\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"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAEpD,+EAA+E;AAC/E,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 * Default entry for Node server processes. Bundles the runtime-neutral\n * core with a `ws`-library-based WebSocket upgrade handler. For web\n * runtimes (Cloudflare Workers, Deno, Bun) where `ws` isn't\n * available, use `@llui/agent/server/core` + `@llui/agent/server/web`\n * instead.\n */\nexport { createLluiAgentServer } from './factory.js'\nexport type { ServerOptions, AgentServerHandle } from './options.js'\n// Runtime-neutral core — re-exported so Node users don't need a second import.\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 { mintToken, tokenHashOf } from './token.js'\nexport type { VerifyResult } from './token.js'\n"]}
@@ -3,7 +3,6 @@ import type { PairingRegistry } from '../ws/pairing-registry.js';
3
3
  import type { AuditSink } from '../audit.js';
4
4
  import type { RateLimiter } from '../rate-limit.js';
5
5
  export type LapConfirmResultDeps = {
6
- signingKey: string | Uint8Array;
7
6
  tokenStore: TokenStore;
8
7
  registry: PairingRegistry;
9
8
  auditSink: AuditSink;
@@ -1 +1 @@
1
- {"version":3,"file":"confirm-result.d.ts","sourceRoot":"","sources":["../../../src/server/lap/confirm-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAInD,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,EAAE,MAAM,GAAG,UAAU,CAAA;IAC/B,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,EAAE,eAAe,CAAA;IACzB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,WAAW,CAAA;IACxB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB,CAAA;AAED,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,QAAQ,CAAC,CA0DnB"}
1
+ {"version":3,"file":"confirm-result.d.ts","sourceRoot":"","sources":["../../../src/server/lap/confirm-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAInD,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,EAAE,eAAe,CAAA;IACzB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,WAAW,CAAA;IACxB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB,CAAA;AAED,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,QAAQ,CAAC,CA0DnB"}
@@ -1,6 +1,6 @@
1
1
  import { verifyAndReadTid } from './describe.js';
2
2
  export async function handleLapConfirmResult(req, deps) {
3
- const auth = await verifyAndReadTid(req, deps.signingKey);
3
+ const auth = await verifyAndReadTid(req, deps.tokenStore);
4
4
  if (!auth.ok)
5
5
  return json({ error: { code: auth.code } }, auth.status);
6
6
  const rec = await deps.tokenStore.findByTid(auth.tid);
@@ -1 +1 @@
1
- {"version":3,"file":"confirm-result.js","sourceRoot":"","sources":["../../../src/server/lap/confirm-result.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TokenStore } from '../token-store.js'\nimport type { PairingRegistry } from '../ws/pairing-registry.js'\nimport type { AuditSink } from '../audit.js'\nimport type { RateLimiter } from '../rate-limit.js'\nimport { verifyAndReadTid } from './describe.js'\nimport type { LapConfirmResultRequest, LapConfirmResultResponse } from '../../protocol.js'\n\nexport type LapConfirmResultDeps = {\n signingKey: string | Uint8Array\n tokenStore: TokenStore\n registry: PairingRegistry\n auditSink: AuditSink\n rateLimiter: RateLimiter\n now?: () => number\n}\n\nexport async function handleLapConfirmResult(\n req: Request,\n deps: LapConfirmResultDeps,\n): Promise<Response> {\n const auth = await verifyAndReadTid(req, deps.signingKey)\n if (!auth.ok) return json({ error: { code: auth.code } }, auth.status)\n\n const rec = await deps.tokenStore.findByTid(auth.tid)\n if (!rec || rec.status === 'revoked') return json({ error: { code: 'revoked' } }, 403)\n if (!deps.registry.isPaired(auth.tid)) return json({ error: { code: 'paused' } }, 503)\n\n const rlCheck = await deps.rateLimiter.check(auth.tid, 'token')\n if (!rlCheck.allowed) {\n return json({ error: { code: 'rate-limited', retryAfterMs: rlCheck.retryAfterMs } }, 429)\n }\n\n const body = (await req.json().catch(() => null)) as LapConfirmResultRequest | null\n if (!body || typeof body.confirmId !== 'string') return json({ error: { code: 'invalid' } }, 400)\n const timeoutMs = body.timeoutMs ?? 5_000\n\n // Spec: if the confirm was already resolved during the earlier long-poll on\n // /message, there's no second resolution to wait for. In the current design\n // /confirm-result is ONLY used when /message bailed out early with\n // pending-confirmation. So we call waitForConfirm with the given timeoutMs.\n // If no resolution arrives in time, we surface 'still-pending'.\n const result = await deps.registry.waitForConfirm(auth.tid, body.confirmId, timeoutMs)\n\n const nowMs = (deps.now ?? (() => Date.now()))()\n if (result.outcome === 'confirmed') {\n await deps.auditSink.write({\n at: nowMs,\n tid: auth.tid,\n uid: rec.uid,\n event: 'confirm-approved',\n detail: { confirmId: body.confirmId },\n })\n return json(\n { status: 'confirmed', stateAfter: result.stateAfter } satisfies LapConfirmResultResponse,\n 200,\n )\n }\n // user-cancelled OR timeout. WsPairingRegistry returns user-cancelled on timeout too;\n // we distinguish by checking whether the confirm is still in registry.pendingConfirm —\n // but pendingConfirm cleanup happens inside waitForConfirm's timer, so we can't peek.\n // For v1: treat user-cancelled as user-cancelled; treat explicit timeout as timeout by\n // comparing elapsed vs. timeoutMs. Simpler: just return 'still-pending' on the timeout\n // branch to let Claude poll again. Registry returns {outcome: 'user-cancelled'} on\n // both timer and actual cancel — so we can't distinguish. Punt: return 'user-cancelled'\n // (matches registry semantics). Spec §8.2 get_confirm_result allows 'user-cancelled' |\n // 'timeout' | 'still-pending' — a refinement to distinguish is follow-up work.\n await deps.auditSink.write({\n at: nowMs,\n tid: auth.tid,\n uid: rec.uid,\n event: 'confirm-rejected',\n detail: { confirmId: body.confirmId },\n })\n return json(\n { status: 'rejected', reason: 'user-cancelled' } satisfies LapConfirmResultResponse,\n 200,\n )\n}\n\nfunction json(b: unknown, s: number): Response {\n return new Response(JSON.stringify(b), {\n status: s,\n headers: { 'content-type': 'application/json' },\n })\n}\n"]}
1
+ {"version":3,"file":"confirm-result.js","sourceRoot":"","sources":["../../../src/server/lap/confirm-result.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TokenStore } from '../token-store.js'\nimport type { PairingRegistry } from '../ws/pairing-registry.js'\nimport type { AuditSink } from '../audit.js'\nimport type { RateLimiter } from '../rate-limit.js'\nimport { verifyAndReadTid } from './describe.js'\nimport type { LapConfirmResultRequest, LapConfirmResultResponse } from '../../protocol.js'\n\nexport type LapConfirmResultDeps = {\n tokenStore: TokenStore\n registry: PairingRegistry\n auditSink: AuditSink\n rateLimiter: RateLimiter\n now?: () => number\n}\n\nexport async function handleLapConfirmResult(\n req: Request,\n deps: LapConfirmResultDeps,\n): Promise<Response> {\n const auth = await verifyAndReadTid(req, deps.tokenStore)\n if (!auth.ok) return json({ error: { code: auth.code } }, auth.status)\n\n const rec = await deps.tokenStore.findByTid(auth.tid)\n if (!rec || rec.status === 'revoked') return json({ error: { code: 'revoked' } }, 403)\n if (!deps.registry.isPaired(auth.tid)) return json({ error: { code: 'paused' } }, 503)\n\n const rlCheck = await deps.rateLimiter.check(auth.tid, 'token')\n if (!rlCheck.allowed) {\n return json({ error: { code: 'rate-limited', retryAfterMs: rlCheck.retryAfterMs } }, 429)\n }\n\n const body = (await req.json().catch(() => null)) as LapConfirmResultRequest | null\n if (!body || typeof body.confirmId !== 'string') return json({ error: { code: 'invalid' } }, 400)\n const timeoutMs = body.timeoutMs ?? 5_000\n\n // Spec: if the confirm was already resolved during the earlier long-poll on\n // /message, there's no second resolution to wait for. In the current design\n // /confirm-result is ONLY used when /message bailed out early with\n // pending-confirmation. So we call waitForConfirm with the given timeoutMs.\n // If no resolution arrives in time, we surface 'still-pending'.\n const result = await deps.registry.waitForConfirm(auth.tid, body.confirmId, timeoutMs)\n\n const nowMs = (deps.now ?? (() => Date.now()))()\n if (result.outcome === 'confirmed') {\n await deps.auditSink.write({\n at: nowMs,\n tid: auth.tid,\n uid: rec.uid,\n event: 'confirm-approved',\n detail: { confirmId: body.confirmId },\n })\n return json(\n { status: 'confirmed', stateAfter: result.stateAfter } satisfies LapConfirmResultResponse,\n 200,\n )\n }\n // user-cancelled OR timeout. WsPairingRegistry returns user-cancelled on timeout too;\n // we distinguish by checking whether the confirm is still in registry.pendingConfirm —\n // but pendingConfirm cleanup happens inside waitForConfirm's timer, so we can't peek.\n // For v1: treat user-cancelled as user-cancelled; treat explicit timeout as timeout by\n // comparing elapsed vs. timeoutMs. Simpler: just return 'still-pending' on the timeout\n // branch to let Claude poll again. Registry returns {outcome: 'user-cancelled'} on\n // both timer and actual cancel — so we can't distinguish. Punt: return 'user-cancelled'\n // (matches registry semantics). Spec §8.2 get_confirm_result allows 'user-cancelled' |\n // 'timeout' | 'still-pending' — a refinement to distinguish is follow-up work.\n await deps.auditSink.write({\n at: nowMs,\n tid: auth.tid,\n uid: rec.uid,\n event: 'confirm-rejected',\n detail: { confirmId: body.confirmId },\n })\n return json(\n { status: 'rejected', reason: 'user-cancelled' } satisfies LapConfirmResultResponse,\n 200,\n )\n}\n\nfunction json(b: unknown, s: number): Response {\n return new Response(JSON.stringify(b), {\n status: s,\n headers: { 'content-type': 'application/json' },\n })\n}\n"]}
@@ -3,7 +3,6 @@ import type { PairingRegistry } from '../ws/pairing-registry.js';
3
3
  import type { AuditSink } from '../audit.js';
4
4
  import type { RateLimiter } from '../rate-limit.js';
5
5
  export type LapDescribeDeps = {
6
- signingKey: string | Uint8Array;
7
6
  tokenStore: TokenStore;
8
7
  registry: PairingRegistry;
9
8
  auditSink: AuditSink;
@@ -11,7 +10,19 @@ export type LapDescribeDeps = {
11
10
  now?: () => number;
12
11
  };
13
12
  export declare function handleLapDescribe(req: Request, deps: LapDescribeDeps): Promise<Response>;
14
- export declare function verifyAndReadTid(req: Request, key: string | Uint8Array): Promise<{
13
+ /**
14
+ * Resolve the bearer token on a request to a `tid`. The opaque-token
15
+ * scheme means "verify" is "look up the SHA-256 hash in the store and
16
+ * check expiry." A missing prefix, an unknown hash, or an expired
17
+ * record all collapse to the same `auth-failed` so a probe-by-hash
18
+ * leak surface is uniform.
19
+ *
20
+ * Status check (revoked / paused / etc.) is the caller's job — every
21
+ * LAP handler does its own follow-up `findByTid` to read the current
22
+ * status. This function only cares whether the bearer is one of ours
23
+ * and unexpired.
24
+ */
25
+ export declare function verifyAndReadTid(req: Request, tokenStore: TokenStore, nowMs?: number): Promise<{
15
26
  ok: true;
16
27
  tid: string;
17
28
  } | {
@@ -1 +1 @@
1
- {"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../../src/server/lap/describe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAGnD,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,MAAM,GAAG,UAAU,CAAA;IAC/B,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,EAAE,eAAe,CAAA;IACzB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,WAAW,CAAA;IACxB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB,CAAA;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoD9F;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,MAAM,GAAG,UAAU,GACvB,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAOlF"}
1
+ {"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../../src/server/lap/describe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAGnD,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,EAAE,eAAe,CAAA;IACzB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,WAAW,CAAA;IACxB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB,CAAA;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoD9F;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,EACZ,UAAU,EAAE,UAAU,EACtB,KAAK,GAAE,MAAmB,GACzB,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAUlF"}