@opensyber/tokenforge 0.1.2 → 1.1.0

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 (184) hide show
  1. package/LICENSE.md +32 -0
  2. package/README.md +329 -52
  3. package/dist/adapters/astro.d.ts +64 -0
  4. package/dist/adapters/astro.d.ts.map +1 -0
  5. package/dist/adapters/astro.js +104 -0
  6. package/dist/adapters/astro.js.map +1 -0
  7. package/dist/adapters/cloud-v2-bridge.d.ts +8 -0
  8. package/dist/adapters/cloud-v2-bridge.d.ts.map +1 -0
  9. package/dist/adapters/cloud-v2-bridge.js +24 -0
  10. package/dist/adapters/cloud-v2-bridge.js.map +1 -0
  11. package/dist/adapters/express.d.ts +30 -2
  12. package/dist/adapters/express.d.ts.map +1 -1
  13. package/dist/adapters/express.js +65 -0
  14. package/dist/adapters/express.js.map +1 -1
  15. package/dist/adapters/fastify.d.ts +32 -6
  16. package/dist/adapters/fastify.d.ts.map +1 -1
  17. package/dist/adapters/fastify.js +65 -0
  18. package/dist/adapters/fastify.js.map +1 -1
  19. package/dist/adapters/hono.d.ts +13 -1
  20. package/dist/adapters/hono.d.ts.map +1 -1
  21. package/dist/adapters/hono.js +14 -1
  22. package/dist/adapters/hono.js.map +1 -1
  23. package/dist/adapters/index.d.ts +5 -3
  24. package/dist/adapters/index.d.ts.map +1 -1
  25. package/dist/adapters/index.js +5 -3
  26. package/dist/adapters/index.js.map +1 -1
  27. package/dist/adapters/nextjs.d.ts +31 -0
  28. package/dist/adapters/nextjs.d.ts.map +1 -1
  29. package/dist/adapters/nextjs.js +83 -30
  30. package/dist/adapters/nextjs.js.map +1 -1
  31. package/dist/adapters/sveltekit.d.ts +66 -0
  32. package/dist/adapters/sveltekit.d.ts.map +1 -0
  33. package/dist/adapters/sveltekit.js +101 -0
  34. package/dist/adapters/sveltekit.js.map +1 -0
  35. package/dist/client/action-signer.d.ts +53 -0
  36. package/dist/client/action-signer.d.ts.map +1 -0
  37. package/dist/client/action-signer.js +48 -0
  38. package/dist/client/action-signer.js.map +1 -0
  39. package/dist/client/binding.d.ts +24 -7
  40. package/dist/client/binding.d.ts.map +1 -1
  41. package/dist/client/binding.js +17 -6
  42. package/dist/client/binding.js.map +1 -1
  43. package/dist/client/cloud-device.d.ts +54 -0
  44. package/dist/client/cloud-device.d.ts.map +1 -0
  45. package/dist/client/cloud-device.js +301 -0
  46. package/dist/client/cloud-device.js.map +1 -0
  47. package/dist/client/crypto.d.ts.map +1 -1
  48. package/dist/client/crypto.js.map +1 -1
  49. package/dist/client/index.d.ts +14 -0
  50. package/dist/client/index.d.ts.map +1 -1
  51. package/dist/client/index.js +30 -2
  52. package/dist/client/index.js.map +1 -1
  53. package/dist/client/interceptor.d.ts.map +1 -1
  54. package/dist/client/interceptor.js +27 -3
  55. package/dist/client/interceptor.js.map +1 -1
  56. package/dist/client/signer.d.ts +40 -3
  57. package/dist/client/signer.d.ts.map +1 -1
  58. package/dist/client/signer.js +56 -5
  59. package/dist/client/signer.js.map +1 -1
  60. package/dist/client/storage.d.ts.map +1 -1
  61. package/dist/client/storage.js.map +1 -1
  62. package/dist/client/webauthn.d.ts +45 -0
  63. package/dist/client/webauthn.d.ts.map +1 -0
  64. package/dist/client/webauthn.js +118 -0
  65. package/dist/client/webauthn.js.map +1 -0
  66. package/dist/protocol/v2.d.ts +23 -0
  67. package/dist/protocol/v2.d.ts.map +1 -0
  68. package/dist/protocol/v2.js +157 -0
  69. package/dist/protocol/v2.js.map +1 -0
  70. package/dist/react/index.d.ts.map +1 -1
  71. package/dist/react/index.js.map +1 -1
  72. package/dist/react/provider.d.ts.map +1 -1
  73. package/dist/react/provider.js.map +1 -1
  74. package/dist/server/action-verify.d.ts +56 -0
  75. package/dist/server/action-verify.d.ts.map +1 -0
  76. package/dist/server/action-verify.js +47 -0
  77. package/dist/server/action-verify.js.map +1 -0
  78. package/dist/server/activity-histogram.d.ts +47 -0
  79. package/dist/server/activity-histogram.d.ts.map +1 -0
  80. package/dist/server/activity-histogram.js +76 -0
  81. package/dist/server/activity-histogram.js.map +1 -0
  82. package/dist/server/aitm-heuristics.d.ts +57 -0
  83. package/dist/server/aitm-heuristics.d.ts.map +1 -0
  84. package/dist/server/aitm-heuristics.js +120 -0
  85. package/dist/server/aitm-heuristics.js.map +1 -0
  86. package/dist/server/bind-with-id-token.d.ts +55 -0
  87. package/dist/server/bind-with-id-token.d.ts.map +1 -0
  88. package/dist/server/bind-with-id-token.js +70 -0
  89. package/dist/server/bind-with-id-token.js.map +1 -0
  90. package/dist/server/bound-cookie.d.ts +39 -0
  91. package/dist/server/bound-cookie.d.ts.map +1 -0
  92. package/dist/server/bound-cookie.js +59 -0
  93. package/dist/server/bound-cookie.js.map +1 -0
  94. package/dist/server/cbor.d.ts +20 -0
  95. package/dist/server/cbor.d.ts.map +1 -0
  96. package/dist/server/cbor.js +110 -0
  97. package/dist/server/cbor.js.map +1 -0
  98. package/dist/server/cloud-bind.d.ts +42 -0
  99. package/dist/server/cloud-bind.d.ts.map +1 -0
  100. package/dist/server/cloud-bind.js +387 -0
  101. package/dist/server/cloud-bind.js.map +1 -0
  102. package/dist/server/cloud-middleware.d.ts +46 -0
  103. package/dist/server/cloud-middleware.d.ts.map +1 -0
  104. package/dist/server/cloud-middleware.js +344 -0
  105. package/dist/server/cloud-middleware.js.map +1 -0
  106. package/dist/server/cloud-verify.d.ts +30 -0
  107. package/dist/server/cloud-verify.d.ts.map +1 -0
  108. package/dist/server/cloud-verify.js +206 -0
  109. package/dist/server/cloud-verify.js.map +1 -0
  110. package/dist/server/dbsc-challenge.d.ts +51 -0
  111. package/dist/server/dbsc-challenge.d.ts.map +1 -0
  112. package/dist/server/dbsc-challenge.js +78 -0
  113. package/dist/server/dbsc-challenge.js.map +1 -0
  114. package/dist/server/dbsc-endpoint.d.ts +20 -0
  115. package/dist/server/dbsc-endpoint.d.ts.map +1 -0
  116. package/dist/server/dbsc-endpoint.js +85 -0
  117. package/dist/server/dbsc-endpoint.js.map +1 -0
  118. package/dist/server/dbsc-verify.d.ts +32 -0
  119. package/dist/server/dbsc-verify.d.ts.map +1 -0
  120. package/dist/server/dbsc-verify.js +65 -0
  121. package/dist/server/dbsc-verify.js.map +1 -0
  122. package/dist/server/identity-profile.d.ts +18 -0
  123. package/dist/server/identity-profile.d.ts.map +1 -0
  124. package/dist/server/identity-profile.js +113 -0
  125. package/dist/server/identity-profile.js.map +1 -0
  126. package/dist/server/index.d.ts +12 -0
  127. package/dist/server/index.d.ts.map +1 -1
  128. package/dist/server/index.js +7 -0
  129. package/dist/server/index.js.map +1 -1
  130. package/dist/server/jws-verify.d.ts +46 -0
  131. package/dist/server/jws-verify.d.ts.map +1 -0
  132. package/dist/server/jws-verify.js +64 -0
  133. package/dist/server/jws-verify.js.map +1 -0
  134. package/dist/server/middleware.d.ts +24 -0
  135. package/dist/server/middleware.d.ts.map +1 -1
  136. package/dist/server/middleware.js +87 -20
  137. package/dist/server/middleware.js.map +1 -1
  138. package/dist/server/oidc-verify.d.ts +71 -0
  139. package/dist/server/oidc-verify.d.ts.map +1 -0
  140. package/dist/server/oidc-verify.js +115 -0
  141. package/dist/server/oidc-verify.js.map +1 -0
  142. package/dist/server/policy.d.ts +47 -0
  143. package/dist/server/policy.d.ts.map +1 -0
  144. package/dist/server/policy.js +84 -0
  145. package/dist/server/policy.js.map +1 -0
  146. package/dist/server/step-up-policy.d.ts +36 -0
  147. package/dist/server/step-up-policy.d.ts.map +1 -0
  148. package/dist/server/step-up-policy.js +101 -0
  149. package/dist/server/step-up-policy.js.map +1 -0
  150. package/dist/server/storage/index.d.ts +3 -0
  151. package/dist/server/storage/index.d.ts.map +1 -0
  152. package/dist/server/storage/index.js +2 -0
  153. package/dist/server/storage/index.js.map +1 -0
  154. package/dist/server/storage/interface.d.ts +73 -0
  155. package/dist/server/storage/interface.d.ts.map +1 -0
  156. package/dist/server/storage/interface.js +2 -0
  157. package/dist/server/storage/interface.js.map +1 -0
  158. package/dist/server/storage/memory.d.ts +50 -0
  159. package/dist/server/storage/memory.d.ts.map +1 -0
  160. package/dist/server/storage/memory.js +121 -0
  161. package/dist/server/storage/memory.js.map +1 -0
  162. package/dist/server/webauthn-verify.d.ts +41 -0
  163. package/dist/server/webauthn-verify.d.ts.map +1 -0
  164. package/dist/server/webauthn-verify.js +175 -0
  165. package/dist/server/webauthn-verify.js.map +1 -0
  166. package/dist/server/webhooks.d.ts +42 -0
  167. package/dist/server/webhooks.d.ts.map +1 -0
  168. package/dist/server/webhooks.js +77 -0
  169. package/dist/server/webhooks.js.map +1 -0
  170. package/dist/shared/action-hash.d.ts +23 -0
  171. package/dist/shared/action-hash.d.ts.map +1 -0
  172. package/dist/shared/action-hash.js +35 -0
  173. package/dist/shared/action-hash.js.map +1 -0
  174. package/dist/shared/identity.d.ts +45 -0
  175. package/dist/shared/identity.d.ts.map +1 -0
  176. package/dist/shared/identity.js +176 -0
  177. package/dist/shared/identity.js.map +1 -0
  178. package/dist/shared/types-internal.d.ts.map +1 -1
  179. package/dist/shared/types-internal.js.map +1 -1
  180. package/dist/shared/types.d.ts +49 -2
  181. package/dist/shared/types.d.ts.map +1 -1
  182. package/dist/shared/types.js +1 -0
  183. package/dist/shared/types.js.map +1 -1
  184. package/package.json +31 -33
@@ -1,15 +1,48 @@
1
1
  /**
2
2
  * Challenge-response signing protocol.
3
- * Signs: `${sessionId}:${nonce}:${timestamp}` with the device-bound private key.
3
+ *
4
+ * **v2** signs: `${method}:${path}:${bodyHash}:${sessionId}:${nonce}:${timestamp}`
5
+ * where bodyHash is the hex SHA-256 of the request body (empty string for GET/HEAD).
6
+ *
7
+ * **v1** (legacy) signs: `${sessionId}:${nonce}:${timestamp}`.
8
+ *
9
+ * Also exports `isNativeDbscAvailable()` — feature-detect for the W3C
10
+ * Device-Bound Session Credentials API (Chrome 146+). When present, the
11
+ * SDK can defer key generation + binding to the platform; otherwise it
12
+ * continues using the Web Crypto fallback path implemented here.
4
13
  */
14
+ /** Protocol version — determines signature input format. */
15
+ export const TF_PROTOCOL_VERSION = '2';
5
16
  /**
6
- * Sign a challenge payload with the device-bound private key.
17
+ * Compute hex-encoded SHA-256 of arbitrary text.
18
+ * Uses Web Crypto — works in browsers and Cloudflare Workers.
7
19
  */
8
- export async function signChallenge(privateKey, sessionId, nonce, timestamp) {
9
- const payload = `${sessionId}:${nonce}:${timestamp}`;
20
+ export async function sha256Hex(data) {
21
+ const encoded = new TextEncoder().encode(data);
22
+ const hash = await crypto.subtle.digest('SHA-256', encoded);
23
+ const bytes = new Uint8Array(hash);
24
+ return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
25
+ }
26
+ /**
27
+ * Build the v2 signature input that covers HTTP method, path, and body.
28
+ * @returns The string to be signed with ECDSA P-256.
29
+ */
30
+ export async function buildSignatureInput(sessionId, nonce, timestamp, method, path, body) {
31
+ const bodyHash = await sha256Hex(body ?? '');
32
+ return `${method}:${path}:${bodyHash}:${sessionId}:${nonce}:${timestamp}`;
33
+ }
34
+ /**
35
+ * Sign a challenge payload with the device-bound private key (v2 format).
36
+ * Includes HTTP method, URL path, and body hash in the signed payload.
37
+ */
38
+ export async function signChallenge(privateKey, sessionId, nonce, timestamp, method, path, body) {
39
+ const bodyHash = await sha256Hex(body ?? '');
40
+ const payload = method && path
41
+ ? `${method}:${path}:${bodyHash}:${sessionId}:${nonce}:${timestamp}`
42
+ : `${sessionId}:${nonce}:${timestamp}`;
10
43
  const encoded = new TextEncoder().encode(payload);
11
44
  const signature = await crypto.subtle.sign({ name: 'ECDSA', hash: { name: 'SHA-256' } }, privateKey, encoded);
12
- return arrayBufferToBase64Url(signature);
45
+ return { signature: arrayBufferToBase64Url(signature), bodyHash };
13
46
  }
14
47
  /**
15
48
  * Generate a client-side nonce.
@@ -28,4 +61,22 @@ export function arrayBufferToBase64Url(buffer) {
28
61
  }
29
62
  return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
30
63
  }
64
+ /**
65
+ * Feature-detect the W3C Device-Bound Session Credentials API.
66
+ *
67
+ * Returns `true` when `navigator.deviceBoundSession` is a real object the
68
+ * SDK could route through. Treats undefined / null / non-object values
69
+ * (functions, primitives) as unavailable so a downgrade attacker who
70
+ * shadows `navigator` with a truthy primitive does not flip the SDK into
71
+ * thinking native DBSC is present.
72
+ *
73
+ * Spec: https://w3c.github.io/webappsec-dbsc/ (Chrome 146+)
74
+ */
75
+ export function isNativeDbscAvailable() {
76
+ if (typeof navigator === 'undefined')
77
+ return false;
78
+ const nav = navigator;
79
+ const candidate = nav.deviceBoundSession;
80
+ return typeof candidate === 'object' && candidate !== null;
81
+ }
31
82
  //# sourceMappingURL=signer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"signer.js","sourceRoot":"","sources":["../../src/client/signer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,UAAqB,EACrB,SAAiB,EACjB,KAAa,EACb,SAAiB;IAEjB,MAAM,OAAO,GAAG,GAAG,SAAS,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAElD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CACxC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAC5C,UAAU,EACV,OAAO,CACR,CAAC;IAEF,OAAO,sBAAsB,CAAC,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,sBAAsB,CAAC,KAAK,CAAC,MAAqB,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,MAAmB;IACxD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAChF,CAAC"}
1
+ {"version":3,"file":"signer.js","sourceRoot":"../src/","sources":["client/signer.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/client/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAKhE;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAUxE;AAED;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAUjE;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAUrD"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"../src/","sources":["client/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAKhE;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAUxE;AAED;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAUjE;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAUrD"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/client/storage.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,GAAG,YAAY,CAAC;AAC7B,MAAM,UAAU,GAAG,aAAa,CAAC;AAEjC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAoB;IACvD,MAAM,EAAE,GAAG,MAAM,MAAM,EAAE,CAAC;IAC1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACzC,GAAG,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAChC,GAAG,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,EAAE,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,EAAE,GAAG,MAAM,MAAM,EAAE,CAAC;IAC1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjC,GAAG,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC,OAAO,CAAE,GAAG,CAAC,MAAuB,IAAI,IAAI,CAAC,CAAC;QACpE,GAAG,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,EAAE,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,EAAE,GAAG,MAAM,MAAM,EAAE,CAAC;IAC1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QAC1B,GAAG,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAChC,GAAG,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,EAAE,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,MAAM;IACb,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,eAAe,GAAG,GAAG,EAAE;YAC7B,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;QAC/C,CAAC,CAAC;QACF,OAAO,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClD,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"storage.js","sourceRoot":"../src/","sources":["client/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * WebAuthn / FIDO2 client flow — alternative to the ECDSA browser key path.
3
+ *
4
+ * Coexists with the ECDSA flow in binding.ts. Caller opts in via
5
+ * `bindDevice(..., { prefer: 'webauthn' })`. The credential private key is
6
+ * never exposed to JS — it lives on the authenticator (YubiKey, Touch ID,
7
+ * Windows Hello, platform passkey provider).
8
+ *
9
+ * NOTE: WebAuthn signatures are over (authenticatorData || sha256(clientDataJSON)),
10
+ * not the raw `${sessionId}:${nonce}:${timestamp}` payload. The server reconstructs
11
+ * the same expected challenge from session/nonce/timestamp and compares it to
12
+ * the challenge embedded inside clientDataJSON.
13
+ */
14
+ export interface WebAuthnBindResult {
15
+ deviceId: string;
16
+ credentialId: string;
17
+ }
18
+ export interface WebAuthnAssertion {
19
+ signature: string;
20
+ authenticatorData: string;
21
+ clientDataJSON: string;
22
+ credentialId: string;
23
+ }
24
+ /** base64url encode a buffer (no padding, URL-safe alphabet). */
25
+ export declare function bufferToBase64Url(buffer: ArrayBuffer | Uint8Array): string;
26
+ /** base64url decode to ArrayBuffer. */
27
+ export declare function base64UrlToBuffer(b64url: string): ArrayBuffer;
28
+ /**
29
+ * Bind a hardware credential to the active session.
30
+ *
31
+ * Calls navigator.credentials.create with ES256 (alg -7) + EdDSA (alg -8)
32
+ * pubKeyCredParams. Sends the attestation to the server, receives the
33
+ * persisted deviceId.
34
+ */
35
+ export declare function bindDeviceWebAuthn(apiBase: string, sessionId: string, userId: string, displayName: string): Promise<WebAuthnBindResult>;
36
+ /**
37
+ * Sign a per-request challenge with the bound hardware credential.
38
+ *
39
+ * The challenge is `${sessionId}:${nonce}:${timestamp}` — same payload shape
40
+ * as the ECDSA path, but the WebAuthn signature is over
41
+ * (authenticatorData || sha256(clientDataJSON)) where clientDataJSON contains
42
+ * the challenge. The server reconstructs and compares.
43
+ */
44
+ export declare function signChallengeWebAuthn(credentialId: string, sessionId: string, nonce: string, timestamp: number): Promise<WebAuthnAssertion>;
45
+ //# sourceMappingURL=webauthn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webauthn.d.ts","sourceRoot":"../src/","sources":["client/webauthn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,iEAAiE;AACjE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,CAK1E;AAED,uCAAuC;AACvC,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAO7D;AAOD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,kBAAkB,CAAC,CAgD7B;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,CAAC,CA0B5B"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * WebAuthn / FIDO2 client flow — alternative to the ECDSA browser key path.
3
+ *
4
+ * Coexists with the ECDSA flow in binding.ts. Caller opts in via
5
+ * `bindDevice(..., { prefer: 'webauthn' })`. The credential private key is
6
+ * never exposed to JS — it lives on the authenticator (YubiKey, Touch ID,
7
+ * Windows Hello, platform passkey provider).
8
+ *
9
+ * NOTE: WebAuthn signatures are over (authenticatorData || sha256(clientDataJSON)),
10
+ * not the raw `${sessionId}:${nonce}:${timestamp}` payload. The server reconstructs
11
+ * the same expected challenge from session/nonce/timestamp and compares it to
12
+ * the challenge embedded inside clientDataJSON.
13
+ */
14
+ /** base64url encode a buffer (no padding, URL-safe alphabet). */
15
+ export function bufferToBase64Url(buffer) {
16
+ const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
17
+ let binary = '';
18
+ for (const byte of bytes)
19
+ binary += String.fromCharCode(byte);
20
+ return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
21
+ }
22
+ /** base64url decode to ArrayBuffer. */
23
+ export function base64UrlToBuffer(b64url) {
24
+ const base64 = b64url.replace(/-/g, '+').replace(/_/g, '/');
25
+ const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);
26
+ const binary = atob(padded);
27
+ const bytes = new Uint8Array(binary.length);
28
+ for (let i = 0; i < binary.length; i++)
29
+ bytes[i] = binary.charCodeAt(i);
30
+ return bytes.buffer;
31
+ }
32
+ /** SHA-256 → bytes for the WebAuthn challenge derivation. */
33
+ async function sha256(input) {
34
+ return crypto.subtle.digest('SHA-256', new TextEncoder().encode(input));
35
+ }
36
+ /**
37
+ * Bind a hardware credential to the active session.
38
+ *
39
+ * Calls navigator.credentials.create with ES256 (alg -7) + EdDSA (alg -8)
40
+ * pubKeyCredParams. Sends the attestation to the server, receives the
41
+ * persisted deviceId.
42
+ */
43
+ export async function bindDeviceWebAuthn(apiBase, sessionId, userId, displayName) {
44
+ if (typeof navigator === 'undefined' || !navigator.credentials) {
45
+ throw new Error('WebAuthn not available in this environment');
46
+ }
47
+ // Server-bound challenge: derived from sessionId so a stolen challenge
48
+ // can't be replayed against another session.
49
+ const challenge = await sha256(`tf-bind:${sessionId}`);
50
+ const userIdBytes = new TextEncoder().encode(userId);
51
+ const publicKey = {
52
+ challenge,
53
+ rp: { name: 'TokenForge' },
54
+ user: { id: userIdBytes, name: userId, displayName },
55
+ pubKeyCredParams: [
56
+ { type: 'public-key', alg: -7 }, // ES256
57
+ { type: 'public-key', alg: -8 }, // EdDSA
58
+ ],
59
+ authenticatorSelection: { userVerification: 'preferred' },
60
+ timeout: 60_000,
61
+ attestation: 'none',
62
+ };
63
+ const credential = (await navigator.credentials.create({ publicKey }));
64
+ if (!credential)
65
+ throw new Error('WebAuthn credential creation cancelled');
66
+ const response = credential.response;
67
+ const body = {
68
+ sessionId,
69
+ userId,
70
+ credentialId: bufferToBase64Url(credential.rawId),
71
+ attestationObject: bufferToBase64Url(response.attestationObject),
72
+ clientDataJSON: bufferToBase64Url(response.clientDataJSON),
73
+ };
74
+ const httpResponse = await fetch(`${apiBase}/api/tf/bind/webauthn`, {
75
+ method: 'POST',
76
+ headers: { 'Content-Type': 'application/json' },
77
+ credentials: 'include',
78
+ body: JSON.stringify(body),
79
+ });
80
+ if (!httpResponse.ok) {
81
+ throw new Error(`TokenForge WebAuthn binding failed: ${httpResponse.status}`);
82
+ }
83
+ const { deviceId } = (await httpResponse.json());
84
+ return { deviceId, credentialId: body.credentialId };
85
+ }
86
+ /**
87
+ * Sign a per-request challenge with the bound hardware credential.
88
+ *
89
+ * The challenge is `${sessionId}:${nonce}:${timestamp}` — same payload shape
90
+ * as the ECDSA path, but the WebAuthn signature is over
91
+ * (authenticatorData || sha256(clientDataJSON)) where clientDataJSON contains
92
+ * the challenge. The server reconstructs and compares.
93
+ */
94
+ export async function signChallengeWebAuthn(credentialId, sessionId, nonce, timestamp) {
95
+ if (typeof navigator === 'undefined' || !navigator.credentials) {
96
+ throw new Error('WebAuthn not available in this environment');
97
+ }
98
+ const challenge = await sha256(`${sessionId}:${nonce}:${timestamp}`);
99
+ const publicKey = {
100
+ challenge,
101
+ allowCredentials: [
102
+ { id: base64UrlToBuffer(credentialId), type: 'public-key' },
103
+ ],
104
+ userVerification: 'preferred',
105
+ timeout: 60_000,
106
+ };
107
+ const assertion = (await navigator.credentials.get({ publicKey }));
108
+ if (!assertion)
109
+ throw new Error('WebAuthn assertion cancelled');
110
+ const response = assertion.response;
111
+ return {
112
+ signature: bufferToBase64Url(response.signature),
113
+ authenticatorData: bufferToBase64Url(response.authenticatorData),
114
+ clientDataJSON: bufferToBase64Url(response.clientDataJSON),
115
+ credentialId: bufferToBase64Url(assertion.rawId),
116
+ };
117
+ }
118
+ //# sourceMappingURL=webauthn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webauthn.js","sourceRoot":"../src/","sources":["client/webauthn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /** TokenForge request-bound proof protocol. See @opensyber/tokenforge-protocol/v2/request-proof.md. */
2
+ export declare const PROTOCOL_V2: "tf-request-v2";
3
+ export interface RequestProofV2 {
4
+ protocol: typeof PROTOCOL_V2;
5
+ projectId: string;
6
+ deviceId: string;
7
+ sessionId: string;
8
+ method: string;
9
+ path: string;
10
+ query: string;
11
+ bodySha256: string;
12
+ origin: string;
13
+ nonce: string;
14
+ /** Unix time in milliseconds, encoded as an unsigned decimal integer. */
15
+ timestamp: string;
16
+ }
17
+ export declare function canonicalizePath(input: string): string;
18
+ export declare function canonicalizeQuery(input: string): string;
19
+ export declare function canonicalizeOrigin(input: string): string;
20
+ export declare function encodeRequestProof(input: RequestProofV2): Uint8Array;
21
+ export declare function sha256Base64Url(body: BufferSource): Promise<string>;
22
+ export declare function base64Url(bytes: Uint8Array): string;
23
+ //# sourceMappingURL=v2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2.d.ts","sourceRoot":"../src/","sources":["protocol/v2.ts"],"names":[],"mappings":"AAAA,uGAAuG;AACvG,eAAO,MAAM,WAAW,EAAG,eAAwB,CAAC;AAMpD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,OAAO,WAAW,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAiBtD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAmBvD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAgBxD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,UAAU,CA0CpE;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAGzE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAInD"}
@@ -0,0 +1,157 @@
1
+ /** TokenForge request-bound proof protocol. See @opensyber/tokenforge-protocol/v2/request-proof.md. */
2
+ export const PROTOCOL_V2 = 'tf-request-v2';
3
+ const MAGIC = new Uint8Array([0x54, 0x46, 0x56, 0x32, 0x00]); // TFV2\0
4
+ const MAX_FIELD_BYTES = 4096;
5
+ const UNRESERVED = /^[A-Za-z0-9._~-]$/;
6
+ export function canonicalizePath(input) {
7
+ if (!input.startsWith('/'))
8
+ throw new Error('TokenForge path must start with /');
9
+ if (/%(?:2f|5c)/i.test(input))
10
+ throw new Error('TokenForge path contains an encoded separator');
11
+ const decoded = strictPercentDecode(input);
12
+ if (decoded.includes('\\') || decoded.includes('\0')) {
13
+ throw new Error('TokenForge path contains a forbidden separator');
14
+ }
15
+ for (const segment of decoded.split('/')) {
16
+ if (segment === '.' || segment === '..') {
17
+ throw new Error('TokenForge path contains a dot segment');
18
+ }
19
+ }
20
+ const result = percentEncode(decoded, true);
21
+ if (new TextEncoder().encode(result).length > 2048) {
22
+ throw new Error('TokenForge path is too large');
23
+ }
24
+ return result || '/';
25
+ }
26
+ export function canonicalizeQuery(input) {
27
+ if (!input)
28
+ return '';
29
+ const pairs = input.split('&').map((part) => {
30
+ const split = part.indexOf('=');
31
+ const rawKey = split < 0 ? part : part.slice(0, split);
32
+ const rawValue = split < 0 ? '' : part.slice(split + 1);
33
+ return {
34
+ key: strictPercentDecode(rawKey),
35
+ value: strictPercentDecode(rawValue),
36
+ };
37
+ });
38
+ pairs.sort((a, b) => compareUtf8(a.key, b.key) || compareUtf8(a.value, b.value));
39
+ const result = pairs
40
+ .map(({ key, value }) => `${percentEncode(key, false)}=${percentEncode(value, false)}`)
41
+ .join('&');
42
+ if (new TextEncoder().encode(result).length > 4096) {
43
+ throw new Error('TokenForge query is too large');
44
+ }
45
+ return result;
46
+ }
47
+ export function canonicalizeOrigin(input) {
48
+ if (!input)
49
+ return '';
50
+ let url;
51
+ try {
52
+ url = new URL(input);
53
+ }
54
+ catch {
55
+ throw new Error('TokenForge origin is invalid');
56
+ }
57
+ const localhost = url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '[::1]';
58
+ if (url.protocol !== 'https:' && !(localhost && url.protocol === 'http:')) {
59
+ throw new Error('TokenForge origin must use HTTPS');
60
+ }
61
+ if (url.username || url.password || url.search || url.hash || (url.pathname && url.pathname !== '/')) {
62
+ throw new Error('TokenForge origin must not contain credentials, path, query, or fragment');
63
+ }
64
+ return url.origin.toLowerCase();
65
+ }
66
+ export function encodeRequestProof(input) {
67
+ if (input.protocol !== PROTOCOL_V2)
68
+ throw new Error('Unsupported TokenForge protocol');
69
+ const method = input.method.toUpperCase();
70
+ if (!/^[A-Z][A-Z0-9!#$%&'*+.^_`|~-]{0,31}$/.test(method)) {
71
+ throw new Error('TokenForge method is invalid');
72
+ }
73
+ if (!/^[A-Za-z0-9_-]{8,256}$/.test(input.projectId))
74
+ throw new Error('TokenForge project ID is invalid');
75
+ if (!/^[A-Za-z0-9_.:-]{8,256}$/.test(input.deviceId))
76
+ throw new Error('TokenForge device ID is invalid');
77
+ if (!/^[A-Za-z0-9_-]{16,256}$/.test(input.sessionId))
78
+ throw new Error('TokenForge session ID is invalid');
79
+ if (!/^[A-Za-z0-9_-]{43}$/.test(input.bodySha256))
80
+ throw new Error('TokenForge body digest is invalid');
81
+ if (!/^[A-Za-z0-9_-]{22,64}$/.test(input.nonce))
82
+ throw new Error('TokenForge nonce is invalid');
83
+ if (!/^\d{13}$/.test(input.timestamp))
84
+ throw new Error('TokenForge timestamp is invalid');
85
+ const fields = [
86
+ input.protocol,
87
+ input.projectId,
88
+ input.deviceId,
89
+ input.sessionId,
90
+ method,
91
+ canonicalizePath(input.path),
92
+ canonicalizeQuery(input.query),
93
+ input.bodySha256,
94
+ canonicalizeOrigin(input.origin),
95
+ input.nonce,
96
+ input.timestamp,
97
+ ];
98
+ const encoded = fields.map((field) => new TextEncoder().encode(field));
99
+ for (const field of encoded) {
100
+ if (field.length > MAX_FIELD_BYTES)
101
+ throw new Error('TokenForge proof field is too large');
102
+ }
103
+ const size = MAGIC.length + encoded.reduce((total, field) => total + 4 + field.length, 0);
104
+ const output = new Uint8Array(size);
105
+ output.set(MAGIC, 0);
106
+ const view = new DataView(output.buffer);
107
+ let offset = MAGIC.length;
108
+ for (const field of encoded) {
109
+ view.setUint32(offset, field.length, false);
110
+ offset += 4;
111
+ output.set(field, offset);
112
+ offset += field.length;
113
+ }
114
+ return output;
115
+ }
116
+ export async function sha256Base64Url(body) {
117
+ const digest = await crypto.subtle.digest('SHA-256', body);
118
+ return base64Url(new Uint8Array(digest));
119
+ }
120
+ export function base64Url(bytes) {
121
+ let binary = '';
122
+ for (const byte of bytes)
123
+ binary += String.fromCharCode(byte);
124
+ return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
125
+ }
126
+ function strictPercentDecode(input) {
127
+ if (/%(?![0-9A-Fa-f]{2})/.test(input))
128
+ throw new Error('TokenForge percent encoding is invalid');
129
+ try {
130
+ return decodeURIComponent(input);
131
+ }
132
+ catch {
133
+ throw new Error('TokenForge percent encoding is invalid UTF-8');
134
+ }
135
+ }
136
+ function percentEncode(input, preserveSlash) {
137
+ let result = '';
138
+ for (const byte of new TextEncoder().encode(input)) {
139
+ const char = String.fromCharCode(byte);
140
+ if (UNRESERVED.test(char) || (preserveSlash && char === '/'))
141
+ result += char;
142
+ else
143
+ result += `%${byte.toString(16).toUpperCase().padStart(2, '0')}`;
144
+ }
145
+ return result;
146
+ }
147
+ function compareUtf8(a, b) {
148
+ const aa = new TextEncoder().encode(a);
149
+ const bb = new TextEncoder().encode(b);
150
+ const length = Math.min(aa.length, bb.length);
151
+ for (let index = 0; index < length; index += 1) {
152
+ if (aa[index] !== bb[index])
153
+ return aa[index] - bb[index];
154
+ }
155
+ return aa.length - bb.length;
156
+ }
157
+ //# sourceMappingURL=v2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2.js","sourceRoot":"../src/","sources":["protocol/v2.ts"],"names":[],"mappings":"AAAA,uGAAuG;AACvG,MAAM,CAAC,MAAM,WAAW,GAAG,eAAwB,CAAC;AAEpD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;AACvE,MAAM,eAAe,GAAG,IAAI,CAAC;AAC7B,MAAM,UAAU,GAAG,mBAAmB,CAAC;AAiBvC,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACjF,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAChG,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC5C,IAAI,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,MAAM,IAAI,GAAG,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACvD,MAAM,QAAQ,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACxD,OAAO;YACL,GAAG,EAAE,mBAAmB,CAAC,MAAM,CAAC;YAChC,KAAK,EAAE,mBAAmB,CAAC,QAAQ,CAAC;SACrC,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACjF,MAAM,MAAM,GAAG,KAAK;SACjB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,GAAG,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;SACtF,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,IAAI,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC3G,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC,EAAE,CAAC;QAC1E,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,EAAE,CAAC;QACrG,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAqB;IACtD,IAAI,KAAK,CAAC,QAAQ,KAAK,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACvF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;IAC1C,IAAI,CAAC,sCAAsC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACzG,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACzG,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IAC1G,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACxG,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAChG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAE1F,MAAM,MAAM,GAAG;QACb,KAAK,CAAC,QAAQ;QACd,KAAK,CAAC,SAAS;QACf,KAAK,CAAC,QAAQ;QACd,KAAK,CAAC,SAAS;QACf,MAAM;QACN,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC;QAC5B,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC;QAC9B,KAAK,CAAC,UAAU;QAChB,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC;QAChC,KAAK,CAAC,KAAK;QACX,KAAK,CAAC,SAAS;KAChB,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACvE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,MAAM,GAAG,eAAe;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAC7F,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC1F,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACrB,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC1B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC5C,MAAM,IAAI,CAAC,CAAC;QACZ,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;IACzB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAkB;IACtD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC3D,OAAO,SAAS,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAiB;IACzC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAC9D,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAClF,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,IAAI,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACjG,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAa,EAAE,aAAsB;IAC1D,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,KAAK,GAAG,CAAC;YAAE,MAAM,IAAI,IAAI,CAAC;;YACxE,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IACxE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,WAAW,CAAC,CAAS,EAAE,CAAS;IACvC,MAAM,EAAE,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;IAC9C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC/C,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC,KAAK,CAAE,GAAG,EAAE,CAAC,KAAK,CAAE,CAAC;IAC9D,CAAC;IACD,OAAO,EAAE,CAAC,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC;AAC/B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"../src/","sources":["react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"../src/","sources":["react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,UAAU,sBAAsB;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AASD,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,SAAS,CAAC;IACpB,qDAAqD;IACrD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oCAAoC;IACpC,UAAU,EAAE,OAAO,CAAC;IACpB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,SAAS,EACT,UAAU,EACV,OAAO,GACR,EAAE,uBAAuB,2CA8CzB;AAED;;;GAGG;AACH,wBAAgB,aAAa,2BAE5B"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"../src/","sources":["react/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,UAAU,sBAAsB;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AASD,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,SAAS,CAAC;IACpB,qDAAqD;IACrD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oCAAoC;IACpC,UAAU,EAAE,OAAO,CAAC;IACpB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,SAAS,EACT,UAAU,EACV,OAAO,GACR,EAAE,uBAAuB,2CA8CzB;AAED;;;GAGG;AACH,wBAAgB,aAAa,2BAE5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EACL,aAAa,EACb,UAAU,EACV,SAAS,EACT,QAAQ,GAET,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,gBAAgB,EAAmB,MAAM,oBAAoB,CAAC;AASvE,MAAM,iBAAiB,GAAG,aAAa,CAAyB;IAC9D,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,IAAI;IACd,UAAU,EAAE,IAAI;CACjB,CAAC,CAAC;AAYH;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,QAAQ,EACR,SAAS,EACT,UAAU,EACV,OAAO,GACiB;IACxB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAyB;QACzD,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS;YAAE,OAAO;QAEtC,IAAI,EAAE,GAAsB,IAAI,CAAC;QAEjC,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE;YACvB,EAAE,GAAG,gBAAgB,CAAC;gBACpB,OAAO;gBACP,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS;gBAC7B,gBAAgB,EAAE,CAAC,MAAM,EAAE,EAAE;oBAC3B,MAAM,CAAC,aAAa,CAClB,IAAI,WAAW,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAClD,CAAC;gBACJ,CAAC;gBACD,gBAAgB,EAAE,GAAG,EAAE;oBACrB,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,iCAAiC,CAAC;gBAC3D,CAAC;gBACD,aAAa,EAAE,CAAC,QAAQ,EAAE,EAAE;oBAC1B,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;gBACvD,CAAC;aACF,CAAC,CAAC;YAEH,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;YAChB,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7C,CAAC,CAAC;QAEF,KAAK,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAE7B,OAAO,GAAG,EAAE;YACV,EAAE,EAAE,SAAS,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAErC,OAAO,CACL,KAAC,iBAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACrC,QAAQ,GACkB,CAC9B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU,CAAC,iBAAiB,CAAC,CAAC;AACvC,CAAC"}
1
+ {"version":3,"file":"provider.js","sourceRoot":"../src/","sources":["react/provider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EACL,aAAa,EACb,UAAU,EACV,SAAS,EACT,QAAQ,GAET,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,gBAAgB,EAAmB,MAAM,oBAAoB,CAAC;AASvE,MAAM,iBAAiB,GAAG,aAAa,CAAyB;IAC9D,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,IAAI;IACd,UAAU,EAAE,IAAI;CACjB,CAAC,CAAC;AAYH;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,QAAQ,EACR,SAAS,EACT,UAAU,EACV,OAAO,GACiB;IACxB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAyB;QACzD,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS;YAAE,OAAO;QAEtC,IAAI,EAAE,GAAsB,IAAI,CAAC;QAEjC,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE;YACvB,EAAE,GAAG,gBAAgB,CAAC;gBACpB,OAAO;gBACP,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS;gBAC7B,gBAAgB,EAAE,CAAC,MAAM,EAAE,EAAE;oBAC3B,MAAM,CAAC,aAAa,CAClB,IAAI,WAAW,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAClD,CAAC;gBACJ,CAAC;gBACD,gBAAgB,EAAE,GAAG,EAAE;oBACrB,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,iCAAiC,CAAC;gBAC3D,CAAC;gBACD,aAAa,EAAE,CAAC,QAAQ,EAAE,EAAE;oBAC1B,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;gBACvD,CAAC;aACF,CAAC,CAAC;YAEH,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;YAChB,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7C,CAAC,CAAC;QAEF,KAAK,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAE7B,OAAO,GAAG,EAAE;YACV,EAAE,EAAE,SAAS,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAErC,OAAO,CACL,KAAC,iBAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACrC,QAAQ,GACkB,CAC9B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU,CAAC,iBAAiB,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Server-side action-signing verifier (Sprint 39).
3
+ *
4
+ * Wraps `verifyCompactJws` with two extra invariants the client SDK
5
+ * promises:
6
+ * 1. The JWS `action` claim equals the `expectedAction` the route
7
+ * handler is enforcing (e.g. POST /checkout asserts "checkout").
8
+ * 2. The JWS `actionHash` claim equals the SHA-256 of the
9
+ * canonicalized request body. This binds the signature to the
10
+ * payload — replaying the same JWS against a different body
11
+ * (different recipient, amount, etc.) fails.
12
+ *
13
+ * Replay prevention against the SAME body is the caller's
14
+ * responsibility: they should pass `claims.nonce` through
15
+ * `consumeChallenge` (server/dbsc-challenge.ts) so a second submission
16
+ * of the same JWS is rejected even within the maxAgeSeconds window.
17
+ */
18
+ import type { JwsClaims } from './jws-verify.js';
19
+ export interface VerifyActionOptions {
20
+ /** Bound device public key (JWK JSON or PEM SPKI). */
21
+ publicKey: string;
22
+ /** Action verb the route asserts (must equal claims.action). */
23
+ expectedAction: string;
24
+ /** Optional request body — when present, must hash to claims.actionHash. */
25
+ body?: Record<string, unknown> | null;
26
+ /** Maximum age for the JWS in seconds. Default 60. */
27
+ maxAgeSeconds?: number;
28
+ /** Override clock for tests. */
29
+ now?: Date;
30
+ /**
31
+ * RFC 9266 TLS exporter material (hex) extracted from the active TLS
32
+ * connection by the runtime. When provided, claims.tlsExporter MUST
33
+ * match it — protects against replay across a different TLS session.
34
+ * Omit on workerd or any runtime that doesn't expose exporter
35
+ * material; the server emits Sec-TF-Channel-Bound: 0 in that case
36
+ * via the route handler.
37
+ */
38
+ expectedTlsExporter?: string;
39
+ /**
40
+ * If true, reject when claims.tlsExporter is absent. Use this on
41
+ * sensitive routes when running on a runtime that *does* expose the
42
+ * exporter — a missing claim then indicates the client signed
43
+ * without binding the TLS channel.
44
+ */
45
+ requireTlsExporter?: boolean;
46
+ }
47
+ export type VerifyActionResult = {
48
+ ok: true;
49
+ claims: JwsClaims;
50
+ protectedHeader: Record<string, unknown>;
51
+ } | {
52
+ ok: false;
53
+ reason: string;
54
+ };
55
+ export declare function verifyAction(jws: string, opts: VerifyActionOptions): Promise<VerifyActionResult>;
56
+ //# sourceMappingURL=action-verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-verify.d.ts","sourceRoot":"../src/","sources":["server/action-verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,cAAc,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACtC,sDAAsD;IACtD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gCAAgC;IAChC,GAAG,CAAC,EAAE,IAAI,CAAC;IACX;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GACzE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,kBAAkB,CAAC,CA4B7B"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Server-side action-signing verifier (Sprint 39).
3
+ *
4
+ * Wraps `verifyCompactJws` with two extra invariants the client SDK
5
+ * promises:
6
+ * 1. The JWS `action` claim equals the `expectedAction` the route
7
+ * handler is enforcing (e.g. POST /checkout asserts "checkout").
8
+ * 2. The JWS `actionHash` claim equals the SHA-256 of the
9
+ * canonicalized request body. This binds the signature to the
10
+ * payload — replaying the same JWS against a different body
11
+ * (different recipient, amount, etc.) fails.
12
+ *
13
+ * Replay prevention against the SAME body is the caller's
14
+ * responsibility: they should pass `claims.nonce` through
15
+ * `consumeChallenge` (server/dbsc-challenge.ts) so a second submission
16
+ * of the same JWS is rejected even within the maxAgeSeconds window.
17
+ */
18
+ import { verifyCompactJws } from './jws-verify.js';
19
+ import { hashActionPayload } from '../shared/action-hash.js';
20
+ export async function verifyAction(jws, opts) {
21
+ const inner = await verifyCompactJws(jws, {
22
+ publicKey: opts.publicKey,
23
+ maxAgeSeconds: opts.maxAgeSeconds,
24
+ now: opts.now,
25
+ });
26
+ if (!inner.ok)
27
+ return inner;
28
+ if (inner.claims.action !== opts.expectedAction) {
29
+ return { ok: false, reason: 'action_mismatch' };
30
+ }
31
+ if (opts.body !== undefined && opts.body !== null) {
32
+ const expectedHash = await hashActionPayload(opts.body);
33
+ if (inner.claims.actionHash !== expectedHash) {
34
+ return { ok: false, reason: 'action_hash_mismatch' };
35
+ }
36
+ }
37
+ if (opts.expectedTlsExporter !== undefined) {
38
+ if (inner.claims.tlsExporter !== opts.expectedTlsExporter) {
39
+ return { ok: false, reason: 'signature_channel_mismatch' };
40
+ }
41
+ }
42
+ else if (opts.requireTlsExporter && !inner.claims.tlsExporter) {
43
+ return { ok: false, reason: 'tls_exporter_missing' };
44
+ }
45
+ return inner;
46
+ }
47
+ //# sourceMappingURL=action-verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-verify.js","sourceRoot":"../src/","sources":["server/action-verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAmC7D,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAW,EACX,IAAyB;IAEzB,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE;QACxC,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,GAAG,EAAE,IAAI,CAAC,GAAG;KACd,CAAC,CAAC;IACH,IAAI,CAAC,KAAK,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC;IAE5B,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,cAAc,EAAE,CAAC;QAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAClD,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAClD,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,KAAK,CAAC,MAAM,CAAC,UAAU,KAAK,YAAY,EAAE,CAAC;YAC7C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;QACvD,CAAC;IACH,CAAC;IAED,IAAI,IAAI,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;QAC3C,IAAI,KAAK,CAAC,MAAM,CAAC,WAAW,KAAK,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC1D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,4BAA4B,EAAE,CAAC;QAC7D,CAAC;IACH,CAAC;SAAM,IAAI,IAAI,CAAC,kBAAkB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QAChE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACvD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}