@opendatalabs/personal-server-ts-core 1.33.8 → 1.34.1

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 (333) hide show
  1. package/dist/additions/budget.d.ts +28 -0
  2. package/dist/additions/budget.d.ts.map +1 -0
  3. package/dist/additions/budget.js +119 -0
  4. package/dist/additions/budget.js.map +1 -0
  5. package/dist/additions/durable.d.ts +64 -0
  6. package/dist/additions/durable.d.ts.map +1 -0
  7. package/dist/additions/durable.js +591 -0
  8. package/dist/additions/durable.js.map +1 -0
  9. package/dist/additions/first-added.d.ts +32 -48
  10. package/dist/additions/first-added.d.ts.map +1 -1
  11. package/dist/additions/first-added.js +68 -123
  12. package/dist/additions/first-added.js.map +1 -1
  13. package/dist/additions/index.d.ts +3 -0
  14. package/dist/additions/index.d.ts.map +1 -1
  15. package/dist/additions/index.js +3 -0
  16. package/dist/additions/index.js.map +1 -1
  17. package/dist/additions/ledger-store.js +1 -1
  18. package/dist/additions/record-rules.d.ts.map +1 -1
  19. package/dist/additions/record-rules.js +7 -0
  20. package/dist/additions/record-rules.js.map +1 -1
  21. package/dist/additions/summary.d.ts +88 -1
  22. package/dist/additions/summary.d.ts.map +1 -1
  23. package/dist/additions/summary.js +173 -8
  24. package/dist/additions/summary.js.map +1 -1
  25. package/dist/additions/version-inventory.d.ts +80 -0
  26. package/dist/additions/version-inventory.d.ts.map +1 -0
  27. package/dist/additions/version-inventory.js +232 -0
  28. package/dist/additions/version-inventory.js.map +1 -0
  29. package/dist/api/index.d.ts +70 -2
  30. package/dist/api/index.d.ts.map +1 -1
  31. package/dist/api/index.js +506 -79
  32. package/dist/api/index.js.map +1 -1
  33. package/dist/auth/index.d.ts +1 -1
  34. package/dist/auth/index.d.ts.map +1 -1
  35. package/dist/auth/index.js +1 -1
  36. package/dist/auth/index.js.map +1 -1
  37. package/dist/auth/request.d.ts +6 -0
  38. package/dist/auth/request.d.ts.map +1 -1
  39. package/dist/auth/request.js +66 -4
  40. package/dist/auth/request.js.map +1 -1
  41. package/dist/contracts/data.d.ts +54 -8
  42. package/dist/contracts/data.d.ts.map +1 -1
  43. package/dist/contracts/data.js +178 -35
  44. package/dist/contracts/data.js.map +1 -1
  45. package/dist/contracts/index.d.ts +1 -1
  46. package/dist/contracts/index.d.ts.map +1 -1
  47. package/dist/derivatives/registration.d.ts +0 -5
  48. package/dist/derivatives/registration.d.ts.map +1 -1
  49. package/dist/derivatives/registration.js +2 -1
  50. package/dist/derivatives/registration.js.map +1 -1
  51. package/dist/errors/pdpp-catalog.d.ts +36 -0
  52. package/dist/errors/pdpp-catalog.d.ts.map +1 -0
  53. package/dist/errors/pdpp-catalog.js +86 -0
  54. package/dist/errors/pdpp-catalog.js.map +1 -0
  55. package/dist/grants/index.d.ts +2 -0
  56. package/dist/grants/index.d.ts.map +1 -1
  57. package/dist/grants/index.js +4 -0
  58. package/dist/grants/index.js.map +1 -1
  59. package/dist/grants/pdpp-binding-store.d.ts +89 -0
  60. package/dist/grants/pdpp-binding-store.d.ts.map +1 -0
  61. package/dist/grants/pdpp-binding-store.js +112 -0
  62. package/dist/grants/pdpp-binding-store.js.map +1 -0
  63. package/dist/grants/pdpp-binding.d.ts +169 -0
  64. package/dist/grants/pdpp-binding.d.ts.map +1 -0
  65. package/dist/grants/pdpp-binding.js +236 -0
  66. package/dist/grants/pdpp-binding.js.map +1 -0
  67. package/dist/legacy-projection/bindings.d.ts +28 -1
  68. package/dist/legacy-projection/bindings.d.ts.map +1 -1
  69. package/dist/legacy-projection/bindings.js +622 -189
  70. package/dist/legacy-projection/bindings.js.map +1 -1
  71. package/dist/legacy-projection/claude-source-record.d.ts +22 -0
  72. package/dist/legacy-projection/claude-source-record.d.ts.map +1 -0
  73. package/dist/legacy-projection/claude-source-record.js +360 -0
  74. package/dist/legacy-projection/claude-source-record.js.map +1 -0
  75. package/dist/legacy-projection/declared-text.d.ts +41 -0
  76. package/dist/legacy-projection/declared-text.d.ts.map +1 -0
  77. package/dist/legacy-projection/declared-text.js +199 -0
  78. package/dist/legacy-projection/declared-text.js.map +1 -0
  79. package/dist/legacy-projection/github-browser-bindings.d.ts.map +1 -1
  80. package/dist/legacy-projection/github-browser-bindings.js +89 -5
  81. package/dist/legacy-projection/github-browser-bindings.js.map +1 -1
  82. package/dist/legacy-projection/github-legacy-fields.d.ts +6 -0
  83. package/dist/legacy-projection/github-legacy-fields.d.ts.map +1 -0
  84. package/dist/legacy-projection/github-legacy-fields.js +202 -0
  85. package/dist/legacy-projection/github-legacy-fields.js.map +1 -0
  86. package/dist/legacy-projection/index.d.ts +5 -1
  87. package/dist/legacy-projection/index.d.ts.map +1 -1
  88. package/dist/legacy-projection/index.js +55 -1
  89. package/dist/legacy-projection/index.js.map +1 -1
  90. package/dist/legacy-projection/oura-browser-bindings.d.ts.map +1 -1
  91. package/dist/legacy-projection/oura-browser-bindings.js +43 -41
  92. package/dist/legacy-projection/oura-browser-bindings.js.map +1 -1
  93. package/dist/legacy-projection/types.d.ts +38 -2
  94. package/dist/legacy-projection/types.d.ts.map +1 -1
  95. package/dist/mcp/read-client.d.ts.map +1 -1
  96. package/dist/mcp/read-client.js +10 -1
  97. package/dist/mcp/read-client.js.map +1 -1
  98. package/dist/mcp/resources.d.ts.map +1 -1
  99. package/dist/mcp/resources.js +3 -0
  100. package/dist/mcp/resources.js.map +1 -1
  101. package/dist/mcp/tools.d.ts.map +1 -1
  102. package/dist/mcp/tools.js +11 -2
  103. package/dist/mcp/tools.js.map +1 -1
  104. package/dist/pdpp/approval.d.ts +271 -0
  105. package/dist/pdpp/approval.d.ts.map +1 -0
  106. package/dist/pdpp/approval.js +467 -0
  107. package/dist/pdpp/approval.js.map +1 -0
  108. package/dist/pdpp/client-identity.d.ts +88 -0
  109. package/dist/pdpp/client-identity.d.ts.map +1 -0
  110. package/dist/pdpp/client-identity.js +196 -0
  111. package/dist/pdpp/client-identity.js.map +1 -0
  112. package/dist/pdpp/client-metadata.d.ts +95 -0
  113. package/dist/pdpp/client-metadata.d.ts.map +1 -0
  114. package/dist/pdpp/client-metadata.js +96 -0
  115. package/dist/pdpp/client-metadata.js.map +1 -0
  116. package/dist/pdpp/commitments.d.ts +75 -0
  117. package/dist/pdpp/commitments.d.ts.map +1 -0
  118. package/dist/pdpp/commitments.js +113 -0
  119. package/dist/pdpp/commitments.js.map +1 -0
  120. package/dist/pdpp/declaration.d.ts +118 -0
  121. package/dist/pdpp/declaration.d.ts.map +1 -0
  122. package/dist/pdpp/declaration.js +836 -0
  123. package/dist/pdpp/declaration.js.map +1 -0
  124. package/dist/pdpp/index.d.ts +37 -0
  125. package/dist/pdpp/index.d.ts.map +1 -0
  126. package/dist/pdpp/index.js +23 -0
  127. package/dist/pdpp/index.js.map +1 -0
  128. package/dist/pdpp/issuance.d.ts +126 -0
  129. package/dist/pdpp/issuance.d.ts.map +1 -0
  130. package/dist/pdpp/issuance.js +180 -0
  131. package/dist/pdpp/issuance.js.map +1 -0
  132. package/dist/pdpp/pkce.d.ts +53 -0
  133. package/dist/pdpp/pkce.d.ts.map +1 -0
  134. package/dist/pdpp/pkce.js +109 -0
  135. package/dist/pdpp/pkce.js.map +1 -0
  136. package/dist/pdpp/redirect.d.ts +60 -0
  137. package/dist/pdpp/redirect.d.ts.map +1 -0
  138. package/dist/pdpp/redirect.js +125 -0
  139. package/dist/pdpp/redirect.js.map +1 -0
  140. package/dist/pdpp/resolve.d.ts +109 -0
  141. package/dist/pdpp/resolve.d.ts.map +1 -0
  142. package/dist/pdpp/resolve.js +393 -0
  143. package/dist/pdpp/resolve.js.map +1 -0
  144. package/dist/pdpp/review.d.ts +280 -0
  145. package/dist/pdpp/review.d.ts.map +1 -0
  146. package/dist/pdpp/review.js +205 -0
  147. package/dist/pdpp/review.js.map +1 -0
  148. package/dist/pdpp/selection.d.ts +50 -0
  149. package/dist/pdpp/selection.d.ts.map +1 -0
  150. package/dist/pdpp/selection.js +442 -0
  151. package/dist/pdpp/selection.js.map +1 -0
  152. package/dist/pdpp/store.d.ts +228 -0
  153. package/dist/pdpp/store.d.ts.map +1 -0
  154. package/dist/pdpp/store.js +542 -0
  155. package/dist/pdpp/store.js.map +1 -0
  156. package/dist/pdpp/tokens.d.ts +181 -0
  157. package/dist/pdpp/tokens.d.ts.map +1 -0
  158. package/dist/pdpp/tokens.js +419 -0
  159. package/dist/pdpp/tokens.js.map +1 -0
  160. package/dist/pdpp/types.d.ts +441 -0
  161. package/dist/pdpp/types.d.ts.map +1 -0
  162. package/dist/pdpp/types.js +61 -0
  163. package/dist/pdpp/types.js.map +1 -0
  164. package/dist/pdpp-version.d.ts +28 -0
  165. package/dist/pdpp-version.d.ts.map +1 -0
  166. package/dist/pdpp-version.js +28 -0
  167. package/dist/pdpp-version.js.map +1 -0
  168. package/dist/policy/data-read.d.ts +24 -0
  169. package/dist/policy/data-read.d.ts.map +1 -1
  170. package/dist/policy/data-read.js +60 -3
  171. package/dist/policy/data-read.js.map +1 -1
  172. package/dist/policy/data-write.d.ts.map +1 -1
  173. package/dist/policy/data-write.js +3 -0
  174. package/dist/policy/data-write.js.map +1 -1
  175. package/dist/policy/index.d.ts +1 -0
  176. package/dist/policy/index.d.ts.map +1 -1
  177. package/dist/policy/index.js +1 -0
  178. package/dist/policy/index.js.map +1 -1
  179. package/dist/policy/reserved-scopes.d.ts +3 -0
  180. package/dist/policy/reserved-scopes.d.ts.map +1 -0
  181. package/dist/policy/reserved-scopes.js +5 -0
  182. package/dist/policy/reserved-scopes.js.map +1 -0
  183. package/dist/ports/index.d.ts +63 -0
  184. package/dist/ports/index.d.ts.map +1 -1
  185. package/dist/ports/index.js.map +1 -1
  186. package/dist/ports/pdpp-auth.d.ts +129 -0
  187. package/dist/ports/pdpp-auth.d.ts.map +1 -0
  188. package/dist/ports/pdpp-auth.js +60 -0
  189. package/dist/ports/pdpp-auth.js.map +1 -0
  190. package/dist/ports/pdpp-auth.test-utils.d.ts +9 -0
  191. package/dist/ports/pdpp-auth.test-utils.d.ts.map +1 -0
  192. package/dist/ports/pdpp-auth.test-utils.js +18 -0
  193. package/dist/ports/pdpp-auth.test-utils.js.map +1 -0
  194. package/dist/schemas/server-config.d.ts +44 -0
  195. package/dist/schemas/server-config.d.ts.map +1 -1
  196. package/dist/schemas/server-config.js +91 -0
  197. package/dist/schemas/server-config.js.map +1 -1
  198. package/dist/signing/request-signer.d.ts +2 -0
  199. package/dist/signing/request-signer.d.ts.map +1 -1
  200. package/dist/signing/request-signer.js +1 -0
  201. package/dist/signing/request-signer.js.map +1 -1
  202. package/dist/storage/adapters/interface.d.ts +3 -0
  203. package/dist/storage/adapters/interface.d.ts.map +1 -1
  204. package/dist/storage/adapters/vana-audience.d.ts +12 -0
  205. package/dist/storage/adapters/vana-audience.d.ts.map +1 -0
  206. package/dist/storage/adapters/vana-audience.js +72 -0
  207. package/dist/storage/adapters/vana-audience.js.map +1 -0
  208. package/dist/storage/adapters/vana.d.ts +2 -0
  209. package/dist/storage/adapters/vana.d.ts.map +1 -1
  210. package/dist/storage/adapters/vana.js +53 -20
  211. package/dist/storage/adapters/vana.js.map +1 -1
  212. package/dist/storage/canonical-legacy-projection.d.ts +262 -0
  213. package/dist/storage/canonical-legacy-projection.d.ts.map +1 -0
  214. package/dist/storage/canonical-legacy-projection.js +761 -0
  215. package/dist/storage/canonical-legacy-projection.js.map +1 -0
  216. package/dist/storage/index/manager.d.ts +29 -2
  217. package/dist/storage/index/manager.d.ts.map +1 -1
  218. package/dist/storage/index/schema.d.ts +1 -1
  219. package/dist/storage/index/schema.js +1 -1
  220. package/dist/storage/index/types.d.ts +7 -1
  221. package/dist/storage/index/types.d.ts.map +1 -1
  222. package/dist/storage/legacy-projection.d.ts +13 -10
  223. package/dist/storage/legacy-projection.d.ts.map +1 -1
  224. package/dist/storage/legacy-projection.js +269 -74
  225. package/dist/storage/legacy-projection.js.map +1 -1
  226. package/dist/storage/legacy-scope-coverage-exceptions.d.ts +8 -0
  227. package/dist/storage/legacy-scope-coverage-exceptions.d.ts.map +1 -0
  228. package/dist/storage/legacy-scope-coverage-exceptions.js +10 -0
  229. package/dist/storage/legacy-scope-coverage-exceptions.js.map +1 -0
  230. package/dist/storage/legacy-scope-coverage.d.ts +53 -0
  231. package/dist/storage/legacy-scope-coverage.d.ts.map +1 -0
  232. package/dist/storage/legacy-scope-coverage.js +403 -0
  233. package/dist/storage/legacy-scope-coverage.js.map +1 -0
  234. package/dist/storage/legacy-scope-entity-keys.d.ts +4 -0
  235. package/dist/storage/legacy-scope-entity-keys.d.ts.map +1 -0
  236. package/dist/storage/legacy-scope-entity-keys.js +92 -0
  237. package/dist/storage/legacy-scope-entity-keys.js.map +1 -0
  238. package/dist/storage/legacy-scope-view.d.ts +154 -0
  239. package/dist/storage/legacy-scope-view.d.ts.map +1 -0
  240. package/dist/storage/legacy-scope-view.js +735 -0
  241. package/dist/storage/legacy-scope-view.js.map +1 -0
  242. package/dist/storage/pdpp-records/completion.d.ts +91 -0
  243. package/dist/storage/pdpp-records/completion.d.ts.map +1 -0
  244. package/dist/storage/pdpp-records/completion.js +170 -0
  245. package/dist/storage/pdpp-records/completion.js.map +1 -0
  246. package/dist/storage/pdpp-records/cursor.d.ts +41 -0
  247. package/dist/storage/pdpp-records/cursor.d.ts.map +1 -0
  248. package/dist/storage/pdpp-records/cursor.js +49 -0
  249. package/dist/storage/pdpp-records/cursor.js.map +1 -0
  250. package/dist/storage/pdpp-records/declaration-witness.d.ts +58 -0
  251. package/dist/storage/pdpp-records/declaration-witness.d.ts.map +1 -0
  252. package/dist/storage/pdpp-records/declaration-witness.js +230 -0
  253. package/dist/storage/pdpp-records/declaration-witness.js.map +1 -0
  254. package/dist/storage/pdpp-records/enforcement.d.ts +52 -0
  255. package/dist/storage/pdpp-records/enforcement.d.ts.map +1 -0
  256. package/dist/storage/pdpp-records/enforcement.js +116 -0
  257. package/dist/storage/pdpp-records/enforcement.js.map +1 -0
  258. package/dist/storage/pdpp-records/index.d.ts +5 -0
  259. package/dist/storage/pdpp-records/index.d.ts.map +1 -0
  260. package/dist/storage/pdpp-records/index.js +5 -0
  261. package/dist/storage/pdpp-records/index.js.map +1 -0
  262. package/dist/storage/pdpp-records/ingest-plan.d.ts +39 -0
  263. package/dist/storage/pdpp-records/ingest-plan.d.ts.map +1 -0
  264. package/dist/storage/pdpp-records/ingest-plan.js +103 -0
  265. package/dist/storage/pdpp-records/ingest-plan.js.map +1 -0
  266. package/dist/storage/pdpp-records/interface.d.ts +104 -0
  267. package/dist/storage/pdpp-records/interface.d.ts.map +1 -0
  268. package/dist/storage/pdpp-records/interface.js +2 -0
  269. package/dist/storage/pdpp-records/interface.js.map +1 -0
  270. package/dist/storage/pdpp-records/memory-store.d.ts +9 -0
  271. package/dist/storage/pdpp-records/memory-store.d.ts.map +1 -0
  272. package/dist/storage/pdpp-records/memory-store.js +466 -0
  273. package/dist/storage/pdpp-records/memory-store.js.map +1 -0
  274. package/dist/storage/pdpp-records/portable.d.ts +9 -0
  275. package/dist/storage/pdpp-records/portable.d.ts.map +1 -0
  276. package/dist/storage/pdpp-records/portable.js +8 -0
  277. package/dist/storage/pdpp-records/portable.js.map +1 -0
  278. package/dist/storage/pdpp-records/read-port.d.ts +44 -0
  279. package/dist/storage/pdpp-records/read-port.d.ts.map +1 -0
  280. package/dist/storage/pdpp-records/read-port.js +22 -0
  281. package/dist/storage/pdpp-records/read-port.js.map +1 -0
  282. package/dist/storage/pdpp-records/record-key.d.ts +52 -0
  283. package/dist/storage/pdpp-records/record-key.d.ts.map +1 -0
  284. package/dist/storage/pdpp-records/record-key.js +97 -0
  285. package/dist/storage/pdpp-records/record-key.js.map +1 -0
  286. package/dist/storage/pdpp-records/schema.d.ts +41 -0
  287. package/dist/storage/pdpp-records/schema.d.ts.map +1 -0
  288. package/dist/storage/pdpp-records/schema.js +153 -0
  289. package/dist/storage/pdpp-records/schema.js.map +1 -0
  290. package/dist/storage/pdpp-records/stream-declaration.d.ts +88 -0
  291. package/dist/storage/pdpp-records/stream-declaration.d.ts.map +1 -0
  292. package/dist/storage/pdpp-records/stream-declaration.js +57 -0
  293. package/dist/storage/pdpp-records/stream-declaration.js.map +1 -0
  294. package/dist/storage/pdpp-records/types.d.ts +138 -0
  295. package/dist/storage/pdpp-records/types.d.ts.map +1 -0
  296. package/dist/storage/pdpp-records/types.js +38 -0
  297. package/dist/storage/pdpp-records/types.js.map +1 -0
  298. package/dist/sync/data-point-feed.d.ts +3 -0
  299. package/dist/sync/data-point-feed.d.ts.map +1 -1
  300. package/dist/sync/data-point-feed.js +17 -1
  301. package/dist/sync/data-point-feed.js.map +1 -1
  302. package/dist/sync/delete-data-port.d.ts +2 -0
  303. package/dist/sync/delete-data-port.d.ts.map +1 -1
  304. package/dist/sync/delete-data-port.js +1 -1
  305. package/dist/sync/delete-data-port.js.map +1 -1
  306. package/dist/sync/engine/sync-manager.d.ts.map +1 -1
  307. package/dist/sync/engine/sync-manager.js +5 -2
  308. package/dist/sync/engine/sync-manager.js.map +1 -1
  309. package/dist/sync/index.d.ts +3 -1
  310. package/dist/sync/index.d.ts.map +1 -1
  311. package/dist/sync/index.js +4 -0
  312. package/dist/sync/index.js.map +1 -1
  313. package/dist/sync/pdpp-import.d.ts +192 -0
  314. package/dist/sync/pdpp-import.d.ts.map +1 -0
  315. package/dist/sync/pdpp-import.js +441 -0
  316. package/dist/sync/pdpp-import.js.map +1 -0
  317. package/dist/sync/scope-deletions.d.ts +10 -0
  318. package/dist/sync/scope-deletions.d.ts.map +1 -1
  319. package/dist/sync/scope-deletions.js +40 -7
  320. package/dist/sync/scope-deletions.js.map +1 -1
  321. package/dist/sync/workers/download.d.ts +14 -0
  322. package/dist/sync/workers/download.d.ts.map +1 -1
  323. package/dist/sync/workers/download.js +149 -13
  324. package/dist/sync/workers/download.js.map +1 -1
  325. package/dist/sync/workers/upload.d.ts +2 -0
  326. package/dist/sync/workers/upload.d.ts.map +1 -1
  327. package/dist/sync/workers/upload.js +7 -0
  328. package/dist/sync/workers/upload.js.map +1 -1
  329. package/dist/test-utils/memory-storage.d.ts +1 -1
  330. package/dist/test-utils/memory-storage.d.ts.map +1 -1
  331. package/dist/test-utils/memory-storage.js +11 -5
  332. package/dist/test-utils/memory-storage.js.map +1 -1
  333. package/package.json +54 -4
@@ -0,0 +1,467 @@
1
+ /**
2
+ * Authorization sessions and authenticated owner approval.
3
+ *
4
+ * This is the module that decides whether a consent decision is real. The
5
+ * threat it exists to stop is an approval that looks right — correct session,
6
+ * correct review digest, arriving from the first-party consent UI — but that
7
+ * no authenticated owner actually made.
8
+ *
9
+ * The rule: **affiliation is not authentication.** The AS does not accept an
10
+ * approval because it came from an allowlisted origin, a first-party console,
11
+ * a shared UI/server secret, or a signed assertion from the consent broker
12
+ * saying "the owner agreed". Each of those authenticates a *channel* or
13
+ * delegates the decision to a browser-reachable component; compromise it and
14
+ * it mints approvals for any subject. Instead, the owner authenticates to the
15
+ * PS itself, and the resulting owner token — resolved through the same token
16
+ * service the RS uses — is what authorizes the decision. The consent UI
17
+ * forwards that token; it can never substitute for it.
18
+ *
19
+ * Two independent checks must both pass, and neither implies the other:
20
+ *
21
+ * 1. The caller presents an active token with `pdpp_token_kind: "owner"`
22
+ * whose `subject_id` equals the session's subject. Possession of the
23
+ * session id is not authority over it.
24
+ * 2. The presented `review_digest` matches a re-derivation over what is
25
+ * about to be issued (§7 staleness). Authenticating the owner does not
26
+ * excuse approving something other than what they reviewed.
27
+ */
28
+ import { randomBytes } from "node:crypto";
29
+ import { buildConsentReview, } from "./review.js";
30
+ import { issueGrant } from "./issuance.js";
31
+ import { expandSelections, resolveSelection, } from "./resolve.js";
32
+ import { resolveCommitments } from "./commitments.js";
33
+ /** How long an owner has to act on a consent screen before it goes stale. */
34
+ export const REVIEW_SESSION_TTL_SECONDS = 10 * 60;
35
+ /**
36
+ * In-memory pending-session store. Sessions are short-lived and pre-decision,
37
+ * so they hold no issued authority — losing them on restart costs an owner a
38
+ * re-click, not a grant. Issued grants and tokens go to SQLite, where
39
+ * durability actually matters.
40
+ */
41
+ export class AuthorizationSessionStore {
42
+ sessions = new Map();
43
+ create(input) {
44
+ const now = input.now ?? new Date();
45
+ const session = {
46
+ session_id: `as_${randomBytes(16).toString("hex")}`,
47
+ subject_id: input.subjectId,
48
+ request: input.request,
49
+ snapshot: input.snapshot,
50
+ requester: input.requester,
51
+ redirect_uri: input.redirectUri,
52
+ ...(input.stateParam && { state_param: input.stateParam }),
53
+ ...(input.codeChallenge && { code_challenge: input.codeChallenge }),
54
+ ...(input.codeChallengeMethod && {
55
+ code_challenge_method: input.codeChallengeMethod,
56
+ }),
57
+ expires_at: new Date(now.getTime() + REVIEW_SESSION_TTL_SECONDS * 1000).toISOString(),
58
+ status: "pending",
59
+ ...(input.grantExpiresAt && { grant_expires_at: input.grantExpiresAt }),
60
+ ...(input.streamDescriptions && {
61
+ stream_descriptions: input.streamDescriptions,
62
+ }),
63
+ };
64
+ this.sessions.set(session.session_id, session);
65
+ return session;
66
+ }
67
+ get(sessionId) {
68
+ return this.sessions.get(sessionId) ?? null;
69
+ }
70
+ setStatus(sessionId, status) {
71
+ const session = this.sessions.get(sessionId);
72
+ if (session)
73
+ session.status = status;
74
+ }
75
+ /**
76
+ * Retain the owner's reason for denying, beside the denial itself.
77
+ *
78
+ * Kept on the session rather than in the grant store because there is no
79
+ * grant: a denial produces no authorization, and the reason is the owner's
80
+ * note about a decision, not a term of one.
81
+ */
82
+ setDenialReason(sessionId, reason) {
83
+ const session = this.sessions.get(sessionId);
84
+ if (session)
85
+ session.denial_reason = reason;
86
+ }
87
+ }
88
+ /**
89
+ * Authenticate the caller as the owner of a session.
90
+ *
91
+ * Returns the session only when the token is an active *owner* token for that
92
+ * exact subject. Every failure collapses to `session_not_found` rather than a
93
+ * distinguishable "wrong owner" — otherwise a caller holding any valid owner
94
+ * token could probe session ids to learn which ones exist and whose they are.
95
+ */
96
+ function authenticateOwner(sessions, tokens, sessionId, ownerToken, now) {
97
+ if (!ownerToken) {
98
+ return {
99
+ ok: false,
100
+ failure: {
101
+ code: "unauthorized",
102
+ message: "an authenticated owner session is required to decide an authorization",
103
+ },
104
+ };
105
+ }
106
+ const context = tokens.resolveToken(ownerToken, now);
107
+ // A client token must never approve a grant — that would let the requesting
108
+ // application authorize itself.
109
+ if (!context.active || context.tokenKind !== "owner" || !context.subjectId) {
110
+ return {
111
+ ok: false,
112
+ failure: {
113
+ code: "unauthorized",
114
+ message: "owner token is missing, inactive, or not an owner token",
115
+ },
116
+ };
117
+ }
118
+ const session = sessions.get(sessionId);
119
+ if (!session) {
120
+ return {
121
+ ok: false,
122
+ failure: {
123
+ code: "session_not_found",
124
+ message: "authorization session not found",
125
+ },
126
+ };
127
+ }
128
+ // The binding that matters: this owner must be *this session's* owner.
129
+ if (session.subject_id !== context.subjectId) {
130
+ return {
131
+ ok: false,
132
+ failure: {
133
+ code: "session_not_found",
134
+ message: "authorization session not found",
135
+ },
136
+ };
137
+ }
138
+ if (Date.parse(session.expires_at) <= now.getTime()) {
139
+ return {
140
+ ok: false,
141
+ failure: {
142
+ code: "session_not_found",
143
+ message: "authorization session has expired",
144
+ },
145
+ };
146
+ }
147
+ return { ok: true, session };
148
+ }
149
+ /**
150
+ * Overlay the owner's explicit instance picks onto the inventory.
151
+ *
152
+ * A pick narrows the eligible set for that stream to exactly what the owner
153
+ * chose — it never widens it. Intersecting with the real inventory is what
154
+ * stops a caller from "choosing" a handle the owner has not connected, so an
155
+ * owner choice cannot become an escalation path.
156
+ */
157
+ function withInstanceChoices(inventory, choices) {
158
+ if (!choices)
159
+ return inventory;
160
+ return {
161
+ eligibleFor(streamName) {
162
+ const eligible = inventory.eligibleFor(streamName);
163
+ const chosen = choices[streamName];
164
+ if (!chosen || chosen.length === 0)
165
+ return eligible;
166
+ return chosen.filter((handle) => eligible.includes(handle));
167
+ },
168
+ };
169
+ }
170
+ /**
171
+ * Find every stream that needs an owner choice, rather than stopping at the
172
+ * first. A UI that asked about one stream at a time would make the owner
173
+ * approve a moving target across several round trips.
174
+ *
175
+ * The streams are expanded by `expandSelections` — the same function
176
+ * resolution uses — so the three ways of naming streams (an explicit list, a
177
+ * wildcard, a `selection_preset`) all reach this step. They must: "omission
178
+ * is not fan-in, the owner picks" is a property of the request, not of the
179
+ * syntax it was written in.
180
+ *
181
+ * Deriving the list here instead let a preset expand to nothing, so the owner
182
+ * was never offered a choice, while resolution expanded it to a stream with
183
+ * two eligible instances and returned `instance_choice_required` — which this
184
+ * module then reported as an invalid request. A valid preset was unapprovable
185
+ * on any source with two connected instances, and the owner had no way to
186
+ * move. Sharing the expansion is what makes that class of divergence
187
+ * impossible rather than merely fixed.
188
+ */
189
+ function pendingInstanceChoices(session, inventory) {
190
+ const choices = [];
191
+ for (const stream of expandSelections(session.request, session.snapshot)) {
192
+ // An explicitly named handle set is already a decision; no choice needed.
193
+ if (stream.instance_ids && stream.instance_ids.length > 0)
194
+ continue;
195
+ const eligible = inventory.eligibleFor(stream.name);
196
+ if (eligible.length > 1) {
197
+ choices.push({ stream: stream.name, candidates: eligible });
198
+ }
199
+ }
200
+ return choices;
201
+ }
202
+ /**
203
+ * This client's currently-active grants for this owner, newest first —
204
+ * excludes revoked, expired, and consumed single-use grants, and never
205
+ * carries tokens, consent evidence, or review digests: informational only.
206
+ */
207
+ function existingActiveGrantsForClient(store, subjectId, clientId, now, instanceIds) {
208
+ return store
209
+ .listGrantsForSubject(subjectId)
210
+ .filter((stored) => stored.clientId === clientId)
211
+ .filter((stored) => store.grantStatus(stored, now) === "active" &&
212
+ !(stored.grant.access_mode === "single_use" && stored.consumedAt))
213
+ .filter((stored) => instanceIds
214
+ ? stored.grant.streams.every((stream) => stream.instance_ids.every((instanceId) => instanceIds.includes(instanceId)))
215
+ : true)
216
+ .map((stored) => ({
217
+ grant_id: stored.grant.grant_id,
218
+ issued_at: stored.grant.issued_at,
219
+ ...(stored.grant.expires_at && { expires_at: stored.grant.expires_at }),
220
+ access_mode: stored.grant.access_mode,
221
+ purpose_code: stored.grant.purpose_code,
222
+ streams: stored.grant.streams.map((s) => ({
223
+ name: s.name,
224
+ fields: s.fields,
225
+ })),
226
+ }));
227
+ }
228
+ /**
229
+ * Build the review an authenticated owner sees.
230
+ *
231
+ * Resolution runs here against current inventory, so the digest the owner is
232
+ * handed reflects the world as it is right now. If it changes before they
233
+ * approve, `approveAuthorization` will re-derive a different digest and reject.
234
+ */
235
+ export function fetchReview(input) {
236
+ const now = input.now ?? new Date();
237
+ const auth = authenticateOwner(input.sessions, input.tokens, input.sessionId, input.ownerToken, now);
238
+ if (!auth.ok)
239
+ return auth;
240
+ const { session } = auth;
241
+ if (session.status !== "pending") {
242
+ return {
243
+ ok: false,
244
+ failure: {
245
+ code: "access_denied",
246
+ message: "authorization session is already decided",
247
+ },
248
+ };
249
+ }
250
+ if (requestsFanIn(session.request, session.snapshot, input.instanceChoices)) {
251
+ return {
252
+ ok: false,
253
+ failure: {
254
+ code: "unsupported_instance_fan_in",
255
+ message: "Select one connection per stream",
256
+ },
257
+ };
258
+ }
259
+ const inventory = withInstanceChoices(input.inventory, input.instanceChoices);
260
+ // Surface outstanding choices before attempting resolution: an unresolvable
261
+ // instance is a consent step, not an error the owner can do nothing about.
262
+ const choices = pendingInstanceChoices(session, inventory);
263
+ if (choices.length > 0) {
264
+ return {
265
+ ok: true,
266
+ result: {
267
+ session_id: session.session_id,
268
+ instance_choice_required: choices,
269
+ expires_at: session.expires_at,
270
+ },
271
+ };
272
+ }
273
+ const resolution = resolveSelection(session.request, session.snapshot, inventory, input.ownerChoices);
274
+ if (!resolution.ok) {
275
+ // A narrowing incompatible with the request's own requirements is the
276
+ // owner's choice colliding with the client's floor, not a malformed
277
+ // request. Reporting it as `access_denied` is what lets the consent UI
278
+ // say "this combination cannot be approved" and let the owner adjust,
279
+ // rather than routing them to a bug report.
280
+ const refused = resolution.failure.code === "minimum_not_met" ||
281
+ resolution.failure.code === "required_stream_declined" ||
282
+ resolution.failure.code === "no_streams_approved";
283
+ return {
284
+ ok: false,
285
+ failure: {
286
+ code: refused ? "selection_refused" : "invalid_request",
287
+ message: resolution.failure.message,
288
+ },
289
+ };
290
+ }
291
+ // Resolved before the review is built, so an uncovered owner condition is
292
+ // reported to the surface rather than thrown out of `buildConsentReview`.
293
+ // v0.2 requires the owner to see the resolved commitments before approving,
294
+ // which means there is no review to show when they cannot be resolved.
295
+ const commitments = resolveCommitments({
296
+ request: session.request,
297
+ ownerConditions: input.ownerConditions,
298
+ standingTerms: input.standingTerms,
299
+ declarationVersion: session.snapshot.version,
300
+ });
301
+ if (!commitments.ok) {
302
+ return {
303
+ ok: false,
304
+ failure: {
305
+ code: "recipient_terms_unsupported",
306
+ message: commitments.failure.message,
307
+ },
308
+ };
309
+ }
310
+ const review = buildConsentReview({
311
+ commitments: commitments.commitments,
312
+ subjectId: session.subject_id,
313
+ request: session.request,
314
+ snapshot: session.snapshot,
315
+ resolvedStreams: resolution.streams,
316
+ omittedStreams: resolution.omittedStreams,
317
+ requestedStreams: resolution.requestedStreams,
318
+ requester: session.requester,
319
+ expiresAt: session.grant_expires_at,
320
+ streamDescriptions: session.stream_descriptions,
321
+ existingGrants: input.store
322
+ ? existingActiveGrantsForClient(input.store, session.subject_id, session.requester.client_id, now, input.existingGrantInstanceIds)
323
+ : undefined,
324
+ });
325
+ return {
326
+ ok: true,
327
+ result: {
328
+ session_id: session.session_id,
329
+ review,
330
+ expires_at: session.expires_at,
331
+ },
332
+ };
333
+ }
334
+ /**
335
+ * Approve an authorization: authenticate the owner, then issue.
336
+ *
337
+ * Order is deliberate. Authentication runs before anything else, so an
338
+ * unauthenticated caller cannot learn from the error whether their digest was
339
+ * fresh — a spoofed approval with a perfectly valid digest gets the same
340
+ * `unauthorized` as one with a garbage digest.
341
+ *
342
+ * This function does not mark the session `"approved"` — it only decides
343
+ * whether the review is valid and computes what to issue. The session
344
+ * transitions to `"approved"` only once the caller has durably persisted the
345
+ * grant and its authorization code (see `pdpp-auth.ts`'s approve route). A
346
+ * session marked approved before that write lands would leave a caller whose
347
+ * persistence failed with no way to retry: the session is already terminal
348
+ * (`status !== "pending"` above), so a retry of the same reviewed approval
349
+ * would be rejected as already-decided even though nothing durable exists.
350
+ */
351
+ export function approveAuthorization(input) {
352
+ const now = input.now ?? new Date();
353
+ const auth = authenticateOwner(input.sessions, input.tokens, input.sessionId, input.ownerToken, now);
354
+ if (!auth.ok)
355
+ return auth;
356
+ const { session } = auth;
357
+ if (session.status !== "pending") {
358
+ return {
359
+ ok: false,
360
+ failure: {
361
+ code: "access_denied",
362
+ message: "authorization session is already decided",
363
+ },
364
+ };
365
+ }
366
+ if (requestsFanIn(session.request, session.snapshot, input.instanceChoices)) {
367
+ return {
368
+ ok: false,
369
+ failure: {
370
+ code: "unsupported_instance_fan_in",
371
+ message: "Select one connection per stream",
372
+ },
373
+ };
374
+ }
375
+ if (!input.reviewDigest) {
376
+ return {
377
+ ok: false,
378
+ failure: {
379
+ code: "invalid_request",
380
+ message: "review_digest is required",
381
+ },
382
+ };
383
+ }
384
+ const issuance = issueGrant({
385
+ subjectId: session.subject_id,
386
+ request: session.request,
387
+ snapshot: session.snapshot,
388
+ inventory: withInstanceChoices(input.inventory, input.instanceChoices),
389
+ ownerChoices: input.ownerChoices,
390
+ ownerConditions: input.ownerConditions,
391
+ standingTerms: input.standingTerms,
392
+ requester: session.requester,
393
+ approvedReviewDigest: input.reviewDigest,
394
+ explicitAiTrainingConsent: input.explicitAiTrainingConsent,
395
+ expiresAt: session.grant_expires_at,
396
+ streamDescriptions: session.stream_descriptions,
397
+ now,
398
+ });
399
+ if (!issuance.ok) {
400
+ // `resolution_failed` at APPROVAL time is staleness, not a bad request.
401
+ // The selection already resolved once — that is how the owner got a review
402
+ // to approve. If it no longer resolves, the world changed underneath them:
403
+ // most commonly a second instance was connected while the consent screen
404
+ // was open, which under §6 means the AS can no longer auto-resolve and the
405
+ // owner has a new choice to make.
406
+ //
407
+ // The distinction is load-bearing for the consent UI: `stale_review` routes
408
+ // to re-fetch and re-render, so the owner sees the new choice and decides
409
+ // again; `invalid_request` routes to "report a bug" and strands them. The
410
+ // canonical §6 drift case must land on the first.
411
+ const code = issuance.failure.code === "stale_approval" ||
412
+ issuance.failure.code === "resolution_failed"
413
+ ? "stale_review"
414
+ : issuance.failure.code === "ai_training_consent_required"
415
+ ? "ai_training_consent_required"
416
+ : // v0.2 names `access_denied` for a refused issuance: a required
417
+ // stream declined, a required minimum the narrowing cannot meet,
418
+ // or an empty approval. It is not staleness — re-reviewing
419
+ // changes nothing while the same choices stand — and not an
420
+ // invalid request, since the client sent a well-formed one.
421
+ issuance.failure.code === "access_denied"
422
+ ? "selection_refused"
423
+ : issuance.failure.code === "recipient_terms_unsupported"
424
+ ? "recipient_terms_unsupported"
425
+ : "invalid_request";
426
+ return { ok: false, failure: { code, message: issuance.failure.message } };
427
+ }
428
+ return {
429
+ ok: true,
430
+ grant: issuance.grant,
431
+ consentEvidence: issuance.consentEvidence,
432
+ };
433
+ }
434
+ function requestsFanIn(request, snapshot, choices) {
435
+ return expandSelections(request, snapshot).some((stream) => {
436
+ const ids = choices?.[stream.name] ?? stream.instance_ids ?? [];
437
+ return new Set(ids).size > 1;
438
+ });
439
+ }
440
+ /**
441
+ * Deny an authorization. Terminal, and retains no consent evidence — there is
442
+ * nothing the owner consented to, so there is nothing to hold evidence of.
443
+ */
444
+ export function denyAuthorization(input) {
445
+ const now = input.now ?? new Date();
446
+ const auth = authenticateOwner(input.sessions, input.tokens, input.sessionId, input.ownerToken, now);
447
+ if (!auth.ok)
448
+ return auth;
449
+ if (auth.session.status !== "pending") {
450
+ return {
451
+ ok: false,
452
+ failure: {
453
+ code: "access_denied",
454
+ message: "authorization session is already decided",
455
+ },
456
+ };
457
+ }
458
+ input.sessions.setStatus(auth.session.session_id, "denied");
459
+ // Trimmed, and only when it carries something: an empty box is not a reason,
460
+ // and retaining "" would make a denial look annotated when it was not.
461
+ const reason = input.reason?.trim();
462
+ if (reason) {
463
+ input.sessions.setDenialReason(auth.session.session_id, reason);
464
+ }
465
+ return { ok: true };
466
+ }
467
+ //# sourceMappingURL=approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.js","sourceRoot":"","sources":["../../src/pdpp/approval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EACL,kBAAkB,GAInB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAwB,MAAM,eAAe,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,gBAAgB,GAGjB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAStD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,EAAE,CAAC;AA8DlD;;;;;GAKG;AACH,MAAM,OAAO,yBAAyB;IACnB,QAAQ,GAAG,IAAI,GAAG,EAAgC,CAAC;IAEpE,MAAM,CAAC,KAYN;QACC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;QACpC,MAAM,OAAO,GAAyB;YACpC,UAAU,EAAE,MAAM,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;YACnD,UAAU,EAAE,KAAK,CAAC,SAAS;YAC3B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,YAAY,EAAE,KAAK,CAAC,WAAW;YAC/B,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC;YAC1D,GAAG,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,cAAc,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC;YACnE,GAAG,CAAC,KAAK,CAAC,mBAAmB,IAAI;gBAC/B,qBAAqB,EAAE,KAAK,CAAC,mBAAmB;aACjD,CAAC;YACF,UAAU,EAAE,IAAI,IAAI,CAClB,GAAG,CAAC,OAAO,EAAE,GAAG,0BAA0B,GAAG,IAAI,CAClD,CAAC,WAAW,EAAE;YACf,MAAM,EAAE,SAAS;YACjB,GAAG,CAAC,KAAK,CAAC,cAAc,IAAI,EAAE,gBAAgB,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC;YACvE,GAAG,CAAC,KAAK,CAAC,kBAAkB,IAAI;gBAC9B,mBAAmB,EAAE,KAAK,CAAC,kBAAkB;aAC9C,CAAC;SACH,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,GAAG,CAAC,SAAiB;QACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;IAC9C,CAAC;IAED,SAAS,CAAC,SAAiB,EAAE,MAAoB;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,OAAO;YAAE,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;IACvC,CAAC;IAED;;;;;;OAMG;IACH,eAAe,CAAC,SAAiB,EAAE,MAAc;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,OAAO;YAAE,OAAO,CAAC,aAAa,GAAG,MAAM,CAAC;IAC9C,CAAC;CACF;AAED;;;;;;;GAOG;AACH,SAAS,iBAAiB,CACxB,QAAmC,EACnC,MAAwB,EACxB,SAAiB,EACjB,UAA8B,EAC9B,GAAS;IAIT,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,cAAc;gBACpB,OAAO,EACL,uEAAuE;aAC1E;SACF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACrD,4EAA4E;IAC5E,gCAAgC;IAChC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,SAAS,KAAK,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QAC3E,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,yDAAyD;aACnE;SACF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,mBAAmB;gBACzB,OAAO,EAAE,iCAAiC;aAC3C;SACF,CAAC;IACJ,CAAC;IAED,uEAAuE;IACvE,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC;QAC7C,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,mBAAmB;gBACzB,OAAO,EAAE,iCAAiC;aAC3C;SACF,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;QACpD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,mBAAmB;gBACzB,OAAO,EAAE,mCAAmC;aAC7C;SACF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC;AA6BD;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAC1B,SAA4B,EAC5B,OAA6C;IAE7C,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,OAAO;QACL,WAAW,CAAC,UAAkB;YAC5B,MAAM,QAAQ,GAAG,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;YACnD,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;YACnC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,QAAQ,CAAC;YACpD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9D,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAS,sBAAsB,CAC7B,OAA6B,EAC7B,SAA4B;IAE5B,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,KAAK,MAAM,MAAM,IAAI,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzE,0EAA0E;QAC1E,IAAI,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QACpE,MAAM,QAAQ,GAAG,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACpD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,SAAS,6BAA6B,CACpC,KAAoB,EACpB,SAAiB,EACjB,QAAgB,EAChB,GAAS,EACT,WAAsB;IAEtB,OAAO,KAAK;SACT,oBAAoB,CAAC,SAAS,CAAC;SAC/B,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC;SAChD,MAAM,CACL,CAAC,MAAM,EAAE,EAAE,CACT,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,QAAQ;QAC3C,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,KAAK,YAAY,IAAI,MAAM,CAAC,UAAU,CAAC,CACpE;SACA,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CACjB,WAAW;QACT,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CACpC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,EAAE,CACvC,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CACjC,CACF;QACH,CAAC,CAAC,IAAI,CACT;SACA,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ;QAC/B,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS;QACjC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QACvE,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW;QACrC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY;QACvC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;SACjB,CAAC,CAAC;KACJ,CAAC,CAAC,CAAC;AACR,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,KAgC3B;IAGC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,iBAAiB,CAC5B,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,UAAU,EAChB,GAAG,CACJ,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACzB,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,0CAA0C;aACpD;SACF,CAAC;IACJ,CAAC;IAED,IAAI,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC;QAC5E,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,6BAA6B;gBACnC,OAAO,EAAE,kCAAkC;aAC5C;SACF,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,mBAAmB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IAE9E,4EAA4E;IAC5E,2EAA2E;IAC3E,MAAM,OAAO,GAAG,sBAAsB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC3D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,EAAE,EAAE,IAAI;YACR,MAAM,EAAE;gBACN,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,wBAAwB,EAAE,OAAO;gBACjC,UAAU,EAAE,OAAO,CAAC,UAAU;aAC/B;SACF,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,gBAAgB,CACjC,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,QAAQ,EAChB,SAAS,EACT,KAAK,CAAC,YAAY,CACnB,CAAC;IACF,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QACnB,sEAAsE;QACtE,oEAAoE;QACpE,uEAAuE;QACvE,sEAAsE;QACtE,4CAA4C;QAC5C,MAAM,OAAO,GACX,UAAU,CAAC,OAAO,CAAC,IAAI,KAAK,iBAAiB;YAC7C,UAAU,CAAC,OAAO,CAAC,IAAI,KAAK,0BAA0B;YACtD,UAAU,CAAC,OAAO,CAAC,IAAI,KAAK,qBAAqB,CAAC;QACpD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,iBAAiB;gBACvD,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,OAAO;aACpC;SACF,CAAC;IACJ,CAAC;IAED,0EAA0E;IAC1E,0EAA0E;IAC1E,4EAA4E;IAC5E,uEAAuE;IACvE,MAAM,WAAW,GAAG,kBAAkB,CAAC;QACrC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,kBAAkB,EAAE,OAAO,CAAC,QAAQ,CAAC,OAAO;KAC7C,CAAC,CAAC;IACH,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;QACpB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,6BAA6B;gBACnC,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO;aACrC;SACF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,kBAAkB,CAAC;QAChC,WAAW,EAAE,WAAW,CAAC,WAAW;QACpC,SAAS,EAAE,OAAO,CAAC,UAAU;QAC7B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,eAAe,EAAE,UAAU,CAAC,OAAO;QACnC,cAAc,EAAE,UAAU,CAAC,cAAc;QACzC,gBAAgB,EAAE,UAAU,CAAC,gBAAgB;QAC7C,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,SAAS,EAAE,OAAO,CAAC,gBAAgB;QACnC,kBAAkB,EAAE,OAAO,CAAC,mBAAmB;QAC/C,cAAc,EAAE,KAAK,CAAC,KAAK;YACzB,CAAC,CAAC,6BAA6B,CAC3B,KAAK,CAAC,KAAK,EACX,OAAO,CAAC,UAAU,EAClB,OAAO,CAAC,SAAS,CAAC,SAAS,EAC3B,GAAG,EACH,KAAK,CAAC,wBAAwB,CAC/B;YACH,CAAC,CAAC,SAAS;KACd,CAAC,CAAC;IAEH,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE;YACN,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,MAAM;YACN,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,oBAAoB,CAAC,KA8BpC;IACC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IAEpC,MAAM,IAAI,GAAG,iBAAiB,CAC5B,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,UAAU,EAChB,GAAG,CACJ,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACzB,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,0CAA0C;aACpD;SACF,CAAC;IACJ,CAAC;IAED,IAAI,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC;QAC5E,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,6BAA6B;gBACnC,OAAO,EAAE,kCAAkC;aAC5C;SACF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QACxB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,iBAAiB;gBACvB,OAAO,EAAE,2BAA2B;aACrC;SACF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC;QAC1B,SAAS,EAAE,OAAO,CAAC,UAAU;QAC7B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,SAAS,EAAE,mBAAmB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,eAAe,CAAC;QACtE,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,oBAAoB,EAAE,KAAK,CAAC,YAAY;QACxC,yBAAyB,EAAE,KAAK,CAAC,yBAAyB;QAC1D,SAAS,EAAE,OAAO,CAAC,gBAAgB;QACnC,kBAAkB,EAAE,OAAO,CAAC,mBAAmB;QAC/C,GAAG;KACJ,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,wEAAwE;QACxE,2EAA2E;QAC3E,2EAA2E;QAC3E,yEAAyE;QACzE,2EAA2E;QAC3E,kCAAkC;QAClC,EAAE;QACF,4EAA4E;QAC5E,0EAA0E;QAC1E,0EAA0E;QAC1E,kDAAkD;QAClD,MAAM,IAAI,GACR,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,gBAAgB;YAC1C,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,mBAAmB;YAC3C,CAAC,CAAC,cAAc;YAChB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,8BAA8B;gBACxD,CAAC,CAAC,8BAA8B;gBAChC,CAAC,CAAC,gEAAgE;oBAChE,iEAAiE;oBACjE,2DAA2D;oBAC3D,4DAA4D;oBAC5D,4DAA4D;oBAC5D,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,eAAe;wBACzC,CAAC,CAAC,mBAAmB;wBACrB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,6BAA6B;4BACvD,CAAC,CAAC,6BAA6B;4BAC/B,CAAC,CAAC,iBAAiB,CAAC;QAC9B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;IAC7E,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,eAAe,EAAE,QAAQ,CAAC,eAAe;KAC1C,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CACpB,OAAyB,EACzB,QAA6B,EAC7B,OAA6C;IAE7C,OAAO,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QACzD,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC;QAChE,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAmBjC;IACC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,iBAAiB,CAC5B,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,UAAU,EAChB,GAAG,CACJ,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAE1B,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,0CAA0C;aACpD;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC5D,6EAA6E;IAC7E,uEAAuE;IACvE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IACpC,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Resolving a URL-hosted client identity, under a bounded fetch policy.
3
+ *
4
+ * §6 says a conforming AS MUST NOT reject a valid client ID metadata document
5
+ * solely because the client is not preregistered, and MUST accept a valid
6
+ * URL-hosted client identity unless local policy denies authorization. Before
7
+ * this, the AS validated `redirect_uri` only against a config-supplied
8
+ * registration, so an unregistered-but-valid client was refused for the one
9
+ * reason the spec names as insufficient.
10
+ *
11
+ * ── Why this is not just "fetch the client_id" ──────────────────────────────
12
+ *
13
+ * The AS is being handed a URL by an untrusted caller and asked to fetch it.
14
+ * That is a server-side request forgery primitive: without bounds, a client_id
15
+ * of `http://169.254.169.254/...` turns the AS into a proxy for whatever the
16
+ * deployment can reach. So this reuses `checkDeclarationUrl`, the same guard
17
+ * the declaration retrieval path already applies — https-only, no private or
18
+ * loopback literals, and the deployment's host allowlist unless it has
19
+ * explicitly opted into any HTTPS host.
20
+ *
21
+ * The response is size-capped and redirect-bounded for the same reason: an
22
+ * unbounded body is a memory exhaustion vector, and unbounded redirects defeat
23
+ * the host check by hopping somewhere it would have refused.
24
+ *
25
+ * ── Registration still wins ────────────────────────────────────────────────
26
+ *
27
+ * A locally registered client is resolved from config without any fetch at
28
+ * all. This path exists only for clients the deployment has NOT registered,
29
+ * and a deployment that wants registration-only behavior gets it by leaving
30
+ * the fetcher unset — in which case nothing here runs and the previous
31
+ * behavior is preserved exactly.
32
+ */
33
+ import { type DeclarationTrustPolicy } from "./declaration.js";
34
+ import { type ClientIdMetadataDocument } from "./client-metadata.js";
35
+ import type { RegisteredRedirectPolicy } from "./redirect.js";
36
+ /** Bodies larger than this are refused rather than buffered. */
37
+ export declare const MAX_CLIENT_DOCUMENT_BYTES: number;
38
+ export type ClientIdentityFailureCode = "untrusted_client_url" | "fetch_failed" | "invalid_document" | "client_id_mismatch" | "too_large";
39
+ export interface ClientIdentityFailure {
40
+ code: ClientIdentityFailureCode;
41
+ message: string;
42
+ }
43
+ /**
44
+ * Retrieves a client ID metadata document. Injected so the deployment owns
45
+ * the transport, and so that leaving it unset disables this path entirely.
46
+ */
47
+ export type ClientDocumentFetcher = (url: string) => Promise<{
48
+ status: number;
49
+ body: string;
50
+ finalUrl: string;
51
+ } | null>;
52
+ export interface ResolveClientIdentityOptions {
53
+ clientId: string;
54
+ fetcher: ClientDocumentFetcher;
55
+ /** Reuses the declaration trust policy; same bounds, same allowlist. */
56
+ policy: DeclarationTrustPolicy;
57
+ }
58
+ export type ClientIdentityResult = {
59
+ ok: true;
60
+ policy: RegisteredRedirectPolicy;
61
+ verifiedDomain: string;
62
+ /**
63
+ * The validated document itself, so the caller can resolve the requester
64
+ * identity from it.
65
+ *
66
+ * Returning this is what keeps redirect trust and displayed identity in
67
+ * agreement. The document is what earned the client its redirect
68
+ * admission; if the AS then rendered the client's inline
69
+ * `client_display` instead, the owner could be shown a name the verified
70
+ * domain never asserted. §6 ranks validated binding metadata above
71
+ * inline metadata, and the caller can only honor that ranking if it is
72
+ * handed the metadata.
73
+ */
74
+ document: ClientIdMetadataDocument;
75
+ } | {
76
+ ok: false;
77
+ failure: ClientIdentityFailure;
78
+ };
79
+ /**
80
+ * Resolve a `client_id` URL into a redirect policy the AS can enforce.
81
+ *
82
+ * Returns the same `RegisteredRedirectPolicy` shape a config registration
83
+ * produces, so the caller's redirect validation is unchanged — a URL-hosted
84
+ * client is subject to exactly the same exact-match redirect rule as a
85
+ * registered one, rather than a looser path.
86
+ */
87
+ export declare function resolveUrlHostedClientIdentity(options: ResolveClientIdentityOptions): Promise<ClientIdentityResult>;
88
+ //# sourceMappingURL=client-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-identity.d.ts","sourceRoot":"","sources":["../../src/pdpp/client-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAE9D,gEAAgE;AAChE,eAAO,MAAM,yBAAyB,QAAY,CAAC;AAEnD,MAAM,MAAM,yBAAyB,GACjC,sBAAsB,GACtB,cAAc,GACd,kBAAkB,GAClB,oBAAoB,GACpB,WAAW,CAAC;AAEhB,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,yBAAyB,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAClC,GAAG,EAAE,MAAM,KACR,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAAC;AAExE,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,qBAAqB,CAAC;IAC/B,wEAAwE;IACxE,MAAM,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,MAAM,oBAAoB,GAC5B;IACE,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,wBAAwB,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;OAWG;IACH,QAAQ,EAAE,wBAAwB,CAAC;CACpC,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAElD;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,oBAAoB,CAAC,CAyK/B"}