@opendatalabs/personal-server-ts-core 1.33.7 → 1.34.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 (341) 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 +3 -1
  87. package/dist/legacy-projection/index.d.ts.map +1 -1
  88. package/dist/legacy-projection/index.js +49 -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/connection-api.d.ts.map +1 -1
  96. package/dist/mcp/connection-api.js +4 -0
  97. package/dist/mcp/connection-api.js.map +1 -1
  98. package/dist/mcp/index.d.ts +1 -0
  99. package/dist/mcp/index.d.ts.map +1 -1
  100. package/dist/mcp/index.js +1 -0
  101. package/dist/mcp/index.js.map +1 -1
  102. package/dist/mcp/oauth-redirect.d.ts +14 -0
  103. package/dist/mcp/oauth-redirect.d.ts.map +1 -0
  104. package/dist/mcp/oauth-redirect.js +51 -0
  105. package/dist/mcp/oauth-redirect.js.map +1 -0
  106. package/dist/mcp/resources.d.ts.map +1 -1
  107. package/dist/mcp/resources.js +3 -0
  108. package/dist/mcp/resources.js.map +1 -1
  109. package/dist/mcp/tools.d.ts.map +1 -1
  110. package/dist/mcp/tools.js +11 -2
  111. package/dist/mcp/tools.js.map +1 -1
  112. package/dist/pdpp/approval.d.ts +271 -0
  113. package/dist/pdpp/approval.d.ts.map +1 -0
  114. package/dist/pdpp/approval.js +467 -0
  115. package/dist/pdpp/approval.js.map +1 -0
  116. package/dist/pdpp/client-identity.d.ts +88 -0
  117. package/dist/pdpp/client-identity.d.ts.map +1 -0
  118. package/dist/pdpp/client-identity.js +196 -0
  119. package/dist/pdpp/client-identity.js.map +1 -0
  120. package/dist/pdpp/client-metadata.d.ts +95 -0
  121. package/dist/pdpp/client-metadata.d.ts.map +1 -0
  122. package/dist/pdpp/client-metadata.js +96 -0
  123. package/dist/pdpp/client-metadata.js.map +1 -0
  124. package/dist/pdpp/commitments.d.ts +75 -0
  125. package/dist/pdpp/commitments.d.ts.map +1 -0
  126. package/dist/pdpp/commitments.js +113 -0
  127. package/dist/pdpp/commitments.js.map +1 -0
  128. package/dist/pdpp/declaration.d.ts +118 -0
  129. package/dist/pdpp/declaration.d.ts.map +1 -0
  130. package/dist/pdpp/declaration.js +836 -0
  131. package/dist/pdpp/declaration.js.map +1 -0
  132. package/dist/pdpp/index.d.ts +37 -0
  133. package/dist/pdpp/index.d.ts.map +1 -0
  134. package/dist/pdpp/index.js +23 -0
  135. package/dist/pdpp/index.js.map +1 -0
  136. package/dist/pdpp/issuance.d.ts +126 -0
  137. package/dist/pdpp/issuance.d.ts.map +1 -0
  138. package/dist/pdpp/issuance.js +180 -0
  139. package/dist/pdpp/issuance.js.map +1 -0
  140. package/dist/pdpp/pkce.d.ts +53 -0
  141. package/dist/pdpp/pkce.d.ts.map +1 -0
  142. package/dist/pdpp/pkce.js +109 -0
  143. package/dist/pdpp/pkce.js.map +1 -0
  144. package/dist/pdpp/redirect.d.ts +60 -0
  145. package/dist/pdpp/redirect.d.ts.map +1 -0
  146. package/dist/pdpp/redirect.js +125 -0
  147. package/dist/pdpp/redirect.js.map +1 -0
  148. package/dist/pdpp/resolve.d.ts +109 -0
  149. package/dist/pdpp/resolve.d.ts.map +1 -0
  150. package/dist/pdpp/resolve.js +393 -0
  151. package/dist/pdpp/resolve.js.map +1 -0
  152. package/dist/pdpp/review.d.ts +280 -0
  153. package/dist/pdpp/review.d.ts.map +1 -0
  154. package/dist/pdpp/review.js +205 -0
  155. package/dist/pdpp/review.js.map +1 -0
  156. package/dist/pdpp/selection.d.ts +50 -0
  157. package/dist/pdpp/selection.d.ts.map +1 -0
  158. package/dist/pdpp/selection.js +442 -0
  159. package/dist/pdpp/selection.js.map +1 -0
  160. package/dist/pdpp/store.d.ts +228 -0
  161. package/dist/pdpp/store.d.ts.map +1 -0
  162. package/dist/pdpp/store.js +542 -0
  163. package/dist/pdpp/store.js.map +1 -0
  164. package/dist/pdpp/tokens.d.ts +181 -0
  165. package/dist/pdpp/tokens.d.ts.map +1 -0
  166. package/dist/pdpp/tokens.js +419 -0
  167. package/dist/pdpp/tokens.js.map +1 -0
  168. package/dist/pdpp/types.d.ts +441 -0
  169. package/dist/pdpp/types.d.ts.map +1 -0
  170. package/dist/pdpp/types.js +61 -0
  171. package/dist/pdpp/types.js.map +1 -0
  172. package/dist/pdpp-version.d.ts +28 -0
  173. package/dist/pdpp-version.d.ts.map +1 -0
  174. package/dist/pdpp-version.js +28 -0
  175. package/dist/pdpp-version.js.map +1 -0
  176. package/dist/policy/data-read.d.ts +24 -0
  177. package/dist/policy/data-read.d.ts.map +1 -1
  178. package/dist/policy/data-read.js +60 -3
  179. package/dist/policy/data-read.js.map +1 -1
  180. package/dist/policy/data-write.d.ts.map +1 -1
  181. package/dist/policy/data-write.js +3 -0
  182. package/dist/policy/data-write.js.map +1 -1
  183. package/dist/policy/index.d.ts +1 -0
  184. package/dist/policy/index.d.ts.map +1 -1
  185. package/dist/policy/index.js +1 -0
  186. package/dist/policy/index.js.map +1 -1
  187. package/dist/policy/reserved-scopes.d.ts +3 -0
  188. package/dist/policy/reserved-scopes.d.ts.map +1 -0
  189. package/dist/policy/reserved-scopes.js +5 -0
  190. package/dist/policy/reserved-scopes.js.map +1 -0
  191. package/dist/ports/index.d.ts +63 -0
  192. package/dist/ports/index.d.ts.map +1 -1
  193. package/dist/ports/index.js.map +1 -1
  194. package/dist/ports/pdpp-auth.d.ts +129 -0
  195. package/dist/ports/pdpp-auth.d.ts.map +1 -0
  196. package/dist/ports/pdpp-auth.js +60 -0
  197. package/dist/ports/pdpp-auth.js.map +1 -0
  198. package/dist/ports/pdpp-auth.test-utils.d.ts +9 -0
  199. package/dist/ports/pdpp-auth.test-utils.d.ts.map +1 -0
  200. package/dist/ports/pdpp-auth.test-utils.js +18 -0
  201. package/dist/ports/pdpp-auth.test-utils.js.map +1 -0
  202. package/dist/schemas/server-config.d.ts +44 -0
  203. package/dist/schemas/server-config.d.ts.map +1 -1
  204. package/dist/schemas/server-config.js +91 -0
  205. package/dist/schemas/server-config.js.map +1 -1
  206. package/dist/signing/request-signer.d.ts +2 -0
  207. package/dist/signing/request-signer.d.ts.map +1 -1
  208. package/dist/signing/request-signer.js +1 -0
  209. package/dist/signing/request-signer.js.map +1 -1
  210. package/dist/storage/adapters/interface.d.ts +3 -0
  211. package/dist/storage/adapters/interface.d.ts.map +1 -1
  212. package/dist/storage/adapters/vana-audience.d.ts +12 -0
  213. package/dist/storage/adapters/vana-audience.d.ts.map +1 -0
  214. package/dist/storage/adapters/vana-audience.js +72 -0
  215. package/dist/storage/adapters/vana-audience.js.map +1 -0
  216. package/dist/storage/adapters/vana.d.ts +2 -0
  217. package/dist/storage/adapters/vana.d.ts.map +1 -1
  218. package/dist/storage/adapters/vana.js +53 -20
  219. package/dist/storage/adapters/vana.js.map +1 -1
  220. package/dist/storage/canonical-legacy-projection.d.ts +262 -0
  221. package/dist/storage/canonical-legacy-projection.d.ts.map +1 -0
  222. package/dist/storage/canonical-legacy-projection.js +761 -0
  223. package/dist/storage/canonical-legacy-projection.js.map +1 -0
  224. package/dist/storage/index/manager.d.ts +29 -2
  225. package/dist/storage/index/manager.d.ts.map +1 -1
  226. package/dist/storage/index/schema.d.ts +1 -1
  227. package/dist/storage/index/schema.js +1 -1
  228. package/dist/storage/index/types.d.ts +7 -1
  229. package/dist/storage/index/types.d.ts.map +1 -1
  230. package/dist/storage/legacy-projection.d.ts +4 -3
  231. package/dist/storage/legacy-projection.d.ts.map +1 -1
  232. package/dist/storage/legacy-projection.js +145 -42
  233. package/dist/storage/legacy-projection.js.map +1 -1
  234. package/dist/storage/legacy-scope-coverage-exceptions.d.ts +8 -0
  235. package/dist/storage/legacy-scope-coverage-exceptions.d.ts.map +1 -0
  236. package/dist/storage/legacy-scope-coverage-exceptions.js +10 -0
  237. package/dist/storage/legacy-scope-coverage-exceptions.js.map +1 -0
  238. package/dist/storage/legacy-scope-coverage.d.ts +53 -0
  239. package/dist/storage/legacy-scope-coverage.d.ts.map +1 -0
  240. package/dist/storage/legacy-scope-coverage.js +403 -0
  241. package/dist/storage/legacy-scope-coverage.js.map +1 -0
  242. package/dist/storage/legacy-scope-entity-keys.d.ts +4 -0
  243. package/dist/storage/legacy-scope-entity-keys.d.ts.map +1 -0
  244. package/dist/storage/legacy-scope-entity-keys.js +92 -0
  245. package/dist/storage/legacy-scope-entity-keys.js.map +1 -0
  246. package/dist/storage/legacy-scope-view.d.ts +154 -0
  247. package/dist/storage/legacy-scope-view.d.ts.map +1 -0
  248. package/dist/storage/legacy-scope-view.js +735 -0
  249. package/dist/storage/legacy-scope-view.js.map +1 -0
  250. package/dist/storage/pdpp-records/completion.d.ts +91 -0
  251. package/dist/storage/pdpp-records/completion.d.ts.map +1 -0
  252. package/dist/storage/pdpp-records/completion.js +170 -0
  253. package/dist/storage/pdpp-records/completion.js.map +1 -0
  254. package/dist/storage/pdpp-records/cursor.d.ts +41 -0
  255. package/dist/storage/pdpp-records/cursor.d.ts.map +1 -0
  256. package/dist/storage/pdpp-records/cursor.js +49 -0
  257. package/dist/storage/pdpp-records/cursor.js.map +1 -0
  258. package/dist/storage/pdpp-records/declaration-witness.d.ts +58 -0
  259. package/dist/storage/pdpp-records/declaration-witness.d.ts.map +1 -0
  260. package/dist/storage/pdpp-records/declaration-witness.js +230 -0
  261. package/dist/storage/pdpp-records/declaration-witness.js.map +1 -0
  262. package/dist/storage/pdpp-records/enforcement.d.ts +52 -0
  263. package/dist/storage/pdpp-records/enforcement.d.ts.map +1 -0
  264. package/dist/storage/pdpp-records/enforcement.js +116 -0
  265. package/dist/storage/pdpp-records/enforcement.js.map +1 -0
  266. package/dist/storage/pdpp-records/index.d.ts +5 -0
  267. package/dist/storage/pdpp-records/index.d.ts.map +1 -0
  268. package/dist/storage/pdpp-records/index.js +5 -0
  269. package/dist/storage/pdpp-records/index.js.map +1 -0
  270. package/dist/storage/pdpp-records/ingest-plan.d.ts +39 -0
  271. package/dist/storage/pdpp-records/ingest-plan.d.ts.map +1 -0
  272. package/dist/storage/pdpp-records/ingest-plan.js +103 -0
  273. package/dist/storage/pdpp-records/ingest-plan.js.map +1 -0
  274. package/dist/storage/pdpp-records/interface.d.ts +104 -0
  275. package/dist/storage/pdpp-records/interface.d.ts.map +1 -0
  276. package/dist/storage/pdpp-records/interface.js +2 -0
  277. package/dist/storage/pdpp-records/interface.js.map +1 -0
  278. package/dist/storage/pdpp-records/memory-store.d.ts +9 -0
  279. package/dist/storage/pdpp-records/memory-store.d.ts.map +1 -0
  280. package/dist/storage/pdpp-records/memory-store.js +466 -0
  281. package/dist/storage/pdpp-records/memory-store.js.map +1 -0
  282. package/dist/storage/pdpp-records/portable.d.ts +9 -0
  283. package/dist/storage/pdpp-records/portable.d.ts.map +1 -0
  284. package/dist/storage/pdpp-records/portable.js +8 -0
  285. package/dist/storage/pdpp-records/portable.js.map +1 -0
  286. package/dist/storage/pdpp-records/read-port.d.ts +44 -0
  287. package/dist/storage/pdpp-records/read-port.d.ts.map +1 -0
  288. package/dist/storage/pdpp-records/read-port.js +22 -0
  289. package/dist/storage/pdpp-records/read-port.js.map +1 -0
  290. package/dist/storage/pdpp-records/record-key.d.ts +52 -0
  291. package/dist/storage/pdpp-records/record-key.d.ts.map +1 -0
  292. package/dist/storage/pdpp-records/record-key.js +97 -0
  293. package/dist/storage/pdpp-records/record-key.js.map +1 -0
  294. package/dist/storage/pdpp-records/schema.d.ts +41 -0
  295. package/dist/storage/pdpp-records/schema.d.ts.map +1 -0
  296. package/dist/storage/pdpp-records/schema.js +153 -0
  297. package/dist/storage/pdpp-records/schema.js.map +1 -0
  298. package/dist/storage/pdpp-records/stream-declaration.d.ts +88 -0
  299. package/dist/storage/pdpp-records/stream-declaration.d.ts.map +1 -0
  300. package/dist/storage/pdpp-records/stream-declaration.js +57 -0
  301. package/dist/storage/pdpp-records/stream-declaration.js.map +1 -0
  302. package/dist/storage/pdpp-records/types.d.ts +138 -0
  303. package/dist/storage/pdpp-records/types.d.ts.map +1 -0
  304. package/dist/storage/pdpp-records/types.js +38 -0
  305. package/dist/storage/pdpp-records/types.js.map +1 -0
  306. package/dist/sync/data-point-feed.d.ts +3 -0
  307. package/dist/sync/data-point-feed.d.ts.map +1 -1
  308. package/dist/sync/data-point-feed.js +17 -1
  309. package/dist/sync/data-point-feed.js.map +1 -1
  310. package/dist/sync/delete-data-port.d.ts +2 -0
  311. package/dist/sync/delete-data-port.d.ts.map +1 -1
  312. package/dist/sync/delete-data-port.js +1 -1
  313. package/dist/sync/delete-data-port.js.map +1 -1
  314. package/dist/sync/engine/sync-manager.d.ts.map +1 -1
  315. package/dist/sync/engine/sync-manager.js +5 -2
  316. package/dist/sync/engine/sync-manager.js.map +1 -1
  317. package/dist/sync/index.d.ts +3 -1
  318. package/dist/sync/index.d.ts.map +1 -1
  319. package/dist/sync/index.js +4 -0
  320. package/dist/sync/index.js.map +1 -1
  321. package/dist/sync/pdpp-import.d.ts +192 -0
  322. package/dist/sync/pdpp-import.d.ts.map +1 -0
  323. package/dist/sync/pdpp-import.js +441 -0
  324. package/dist/sync/pdpp-import.js.map +1 -0
  325. package/dist/sync/scope-deletions.d.ts +10 -0
  326. package/dist/sync/scope-deletions.d.ts.map +1 -1
  327. package/dist/sync/scope-deletions.js +40 -7
  328. package/dist/sync/scope-deletions.js.map +1 -1
  329. package/dist/sync/workers/download.d.ts +14 -0
  330. package/dist/sync/workers/download.d.ts.map +1 -1
  331. package/dist/sync/workers/download.js +149 -13
  332. package/dist/sync/workers/download.js.map +1 -1
  333. package/dist/sync/workers/upload.d.ts +2 -0
  334. package/dist/sync/workers/upload.d.ts.map +1 -1
  335. package/dist/sync/workers/upload.js +7 -0
  336. package/dist/sync/workers/upload.js.map +1 -1
  337. package/dist/test-utils/memory-storage.d.ts +1 -1
  338. package/dist/test-utils/memory-storage.d.ts.map +1 -1
  339. package/dist/test-utils/memory-storage.js +11 -5
  340. package/dist/test-utils/memory-storage.js.map +1 -1
  341. package/package.json +54 -4
@@ -0,0 +1,196 @@
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 { checkDeclarationUrl, } from "./declaration.js";
34
+ import { verifyClientIdDocument, } from "./client-metadata.js";
35
+ /** Bodies larger than this are refused rather than buffered. */
36
+ export const MAX_CLIENT_DOCUMENT_BYTES = 64 * 1024;
37
+ /**
38
+ * Resolve a `client_id` URL into a redirect policy the AS can enforce.
39
+ *
40
+ * Returns the same `RegisteredRedirectPolicy` shape a config registration
41
+ * produces, so the caller's redirect validation is unchanged — a URL-hosted
42
+ * client is subject to exactly the same exact-match redirect rule as a
43
+ * registered one, rather than a looser path.
44
+ */
45
+ export async function resolveUrlHostedClientIdentity(options) {
46
+ const { clientId, fetcher, policy } = options;
47
+ // A non-URL client_id is not a URL-hosted identity. Not an error here —
48
+ // the caller falls back to registration-only behavior.
49
+ let parsed;
50
+ try {
51
+ parsed = new URL(clientId);
52
+ }
53
+ catch {
54
+ return {
55
+ ok: false,
56
+ failure: {
57
+ code: "untrusted_client_url",
58
+ message: "client_id is not a URL-hosted identity",
59
+ },
60
+ };
61
+ }
62
+ // The SSRF gate, before any network call.
63
+ const urlProblem = checkDeclarationUrl(parsed.toString(), policy);
64
+ if (urlProblem) {
65
+ return {
66
+ ok: false,
67
+ failure: {
68
+ code: "untrusted_client_url",
69
+ message: urlProblem.message,
70
+ },
71
+ };
72
+ }
73
+ let retrieved;
74
+ try {
75
+ retrieved = await fetcher(parsed.toString());
76
+ }
77
+ catch (err) {
78
+ return {
79
+ ok: false,
80
+ failure: {
81
+ code: "fetch_failed",
82
+ message: err instanceof Error ? err.message : String(err),
83
+ },
84
+ };
85
+ }
86
+ if (!retrieved || retrieved.status !== 200) {
87
+ return {
88
+ ok: false,
89
+ failure: {
90
+ code: "fetch_failed",
91
+ message: `client_id document returned ${retrieved?.status ?? "no response"}`,
92
+ },
93
+ };
94
+ }
95
+ if (retrieved.body.length > MAX_CLIENT_DOCUMENT_BYTES) {
96
+ return {
97
+ ok: false,
98
+ failure: {
99
+ code: "too_large",
100
+ message: `client_id document exceeds ${MAX_CLIENT_DOCUMENT_BYTES} bytes`,
101
+ },
102
+ };
103
+ }
104
+ // A redirect may not escape the gate: re-check where we actually landed.
105
+ const finalProblem = checkDeclarationUrl(retrieved.finalUrl, policy);
106
+ if (finalProblem) {
107
+ return {
108
+ ok: false,
109
+ failure: {
110
+ code: "untrusted_client_url",
111
+ message: `client_id document redirected to an untrusted location: ${finalProblem.message}`,
112
+ },
113
+ };
114
+ }
115
+ let parsedJson;
116
+ try {
117
+ parsedJson = JSON.parse(retrieved.body);
118
+ }
119
+ catch {
120
+ return {
121
+ ok: false,
122
+ failure: {
123
+ code: "invalid_document",
124
+ message: "client_id document is not valid JSON",
125
+ },
126
+ };
127
+ }
128
+ // A JSON document need not be an object — `null`, an array, or a bare
129
+ // primitive all parse without error, and none of them can carry the
130
+ // fields below.
131
+ if (typeof parsedJson !== "object" || parsedJson === null) {
132
+ return {
133
+ ok: false,
134
+ failure: {
135
+ code: "invalid_document",
136
+ message: "client_id document is not a JSON object",
137
+ },
138
+ };
139
+ }
140
+ const document = parsedJson;
141
+ if (!Array.isArray(document.redirect_uris)) {
142
+ return {
143
+ ok: false,
144
+ failure: {
145
+ code: "invalid_document",
146
+ message: "client_id document declares no redirect_uris",
147
+ },
148
+ };
149
+ }
150
+ // A document that declares no usable name gets none, rather than an empty
151
+ // one. `resolveRequesterIdentity` falls back through inline metadata to the
152
+ // client_id itself, so an absent name must be absent -- a `{ name: "" }`
153
+ // would outrank the inline display and render a blank requester.
154
+ const documentName = typeof document.client_name === "string" && document.client_name.length > 0
155
+ ? document.client_name
156
+ : undefined;
157
+ // The identity check: the document must assert the URL it came from.
158
+ // Without this, any host could publish a document claiming to be someone
159
+ // else's client_id.
160
+ const candidate = {
161
+ client_id: String(document.client_id ?? ""),
162
+ ...(documentName && { display: { name: documentName } }),
163
+ https: true,
164
+ retrieved_from: retrieved.finalUrl,
165
+ };
166
+ const verified = verifyClientIdDocument(candidate);
167
+ if (!verified) {
168
+ return {
169
+ ok: false,
170
+ failure: {
171
+ code: "client_id_mismatch",
172
+ message: "client_id document does not assert the URL it was retrieved from",
173
+ },
174
+ };
175
+ }
176
+ const redirectUris = document.redirect_uris.filter((uri) => typeof uri === "string" && uri.length > 0);
177
+ if (redirectUris.length === 0) {
178
+ return {
179
+ ok: false,
180
+ failure: {
181
+ code: "invalid_document",
182
+ message: "client_id document declares no usable redirect_uris",
183
+ },
184
+ };
185
+ }
186
+ return {
187
+ ok: true,
188
+ policy: { client_id: clientId, redirect_uris: redirectUris },
189
+ verifiedDomain: verified.verifiedDomain,
190
+ // The same document that earned redirect admission, so the caller can
191
+ // resolve the displayed requester identity from it rather than from the
192
+ // client's inline assertion.
193
+ document: candidate,
194
+ };
195
+ }
196
+ //# sourceMappingURL=client-identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-identity.js","sourceRoot":"","sources":["../../src/pdpp/client-identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * PDPP Core §6 requester-identity resolution.
3
+ *
4
+ * Two things the spec insists on keeping apart, and which are easy to conflate:
5
+ *
6
+ * - **Verified domain control** means the AS retrieved this client's metadata
7
+ * from the client_id URL over HTTPS and the document identified the same
8
+ * client. It says the operator of that domain published this metadata. It
9
+ * says nothing about the client's conduct or data practices.
10
+ * - **App approval** means a local registration or trust-registry admission
11
+ * decision — someone actually vetted the client.
12
+ *
13
+ * §6 obligation 5 requires the first to be rendered as a *named domain*
14
+ * ("Verified domain: example.com"), never as an unqualified "Verified app".
15
+ * `RequesterIdentity` therefore carries them as two separate fields, so a
16
+ * consent surface cannot render one as the other by accident.
17
+ */
18
+ import type { RequesterIdentity } from "./review.js";
19
+ import type { ClientDisplay } from "./types.js";
20
+ /** Metadata the deployment holds locally, or a trust registry supplied. */
21
+ export interface RegisteredClientMetadata {
22
+ client_id: string;
23
+ display: ClientDisplay;
24
+ /** True only when an admission decision was actually made. */
25
+ approved: boolean;
26
+ }
27
+ /**
28
+ * A client ID metadata document retrieved from the client_id URL.
29
+ *
30
+ * §6: the document is *valid* only when it was retrieved over HTTPS from the
31
+ * client_id URL itself and the `client_id` inside it is identical to that URL.
32
+ * That last check is what stops a document claiming to be a different client.
33
+ */
34
+ export interface ClientIdMetadataDocument {
35
+ /** The URL the document was retrieved from. */
36
+ retrieved_from: string;
37
+ /** The client_id the document asserts. */
38
+ client_id: string;
39
+ /**
40
+ * Optional: a document may validly declare redirect_uris and no name. An
41
+ * absent name must stay absent rather than become `{ name: "" }`, which
42
+ * would outrank inline metadata in §6 precedence and render a blank
43
+ * requester on the consent surface.
44
+ */
45
+ display?: ClientDisplay;
46
+ /** Whether retrieval used HTTPS. */
47
+ https: boolean;
48
+ }
49
+ export interface ResolveRequesterInput {
50
+ client_id: string;
51
+ /** Highest precedence: local registration or trust registry. */
52
+ registered?: RegisteredClientMetadata;
53
+ /** Validated binding metadata, when the binding supplied one. */
54
+ document?: ClientIdMetadataDocument;
55
+ /** Lowest precedence: the client's own inline assertion. */
56
+ inline?: ClientDisplay;
57
+ }
58
+ /**
59
+ * Validate a client ID metadata document per §6.
60
+ *
61
+ * Returns the verified domain when all three conditions hold, otherwise null.
62
+ * A null result is not a rejection of the client — §6's interoperability
63
+ * obligation forbids rejecting a valid document merely for being
64
+ * unpreregistered, and a document that fails validation just means we fall
65
+ * through to a lower-precedence metadata source.
66
+ */
67
+ export declare function verifyClientIdDocument(doc: ClientIdMetadataDocument): {
68
+ verifiedDomain: string;
69
+ } | null;
70
+ /**
71
+ * Resolve requester identity under §6's precedence:
72
+ *
73
+ * local registration / trust registry
74
+ * > validated software statement (not supported in this build)
75
+ * > validated binding metadata (the client ID metadata document)
76
+ * > inline `client_display`
77
+ * > `client_id` fallback
78
+ *
79
+ * The display name always resolves to something: §6 obligation 2 requires the
80
+ * AS to display `client_id` when no name is available, so the consent surface
81
+ * is never left with nothing to render.
82
+ */
83
+ export declare function resolveRequesterIdentity(input: ResolveRequesterInput): RequesterIdentity;
84
+ /**
85
+ * Whether a client-supplied remote logo may be rendered directly.
86
+ *
87
+ * §6 obligation 6: `logo_uri` is untrusted content. An unverified client's
88
+ * remote logo must not be fetched into the consent UI — the surface generates
89
+ * a monogram from the display name instead. Proxied-and-approved assets are a
90
+ * deployment concern the caller signals explicitly.
91
+ */
92
+ export declare function mayRenderRemoteLogo(identity: RequesterIdentity, options?: {
93
+ assetProxiedAndApproved?: boolean;
94
+ }): boolean;
95
+ //# sourceMappingURL=client-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-metadata.d.ts","sourceRoot":"","sources":["../../src/pdpp/client-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,2EAA2E;AAC3E,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,aAAa,CAAC;IACvB,8DAA8D;IAC9D,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACvC,+CAA+C;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,oCAAoC;IACpC,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,UAAU,CAAC,EAAE,wBAAwB,CAAC;IACtC,iEAAiE;IACjE,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,4DAA4D;IAC5D,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,wBAAwB,GAC5B;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAsBnC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,qBAAqB,GAC3B,iBAAiB,CAoBnB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,GAAE;IAAE,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAAO,GAClD,OAAO,CAGT"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * PDPP Core §6 requester-identity resolution.
3
+ *
4
+ * Two things the spec insists on keeping apart, and which are easy to conflate:
5
+ *
6
+ * - **Verified domain control** means the AS retrieved this client's metadata
7
+ * from the client_id URL over HTTPS and the document identified the same
8
+ * client. It says the operator of that domain published this metadata. It
9
+ * says nothing about the client's conduct or data practices.
10
+ * - **App approval** means a local registration or trust-registry admission
11
+ * decision — someone actually vetted the client.
12
+ *
13
+ * §6 obligation 5 requires the first to be rendered as a *named domain*
14
+ * ("Verified domain: example.com"), never as an unqualified "Verified app".
15
+ * `RequesterIdentity` therefore carries them as two separate fields, so a
16
+ * consent surface cannot render one as the other by accident.
17
+ */
18
+ /**
19
+ * Validate a client ID metadata document per §6.
20
+ *
21
+ * Returns the verified domain when all three conditions hold, otherwise null.
22
+ * A null result is not a rejection of the client — §6's interoperability
23
+ * obligation forbids rejecting a valid document merely for being
24
+ * unpreregistered, and a document that fails validation just means we fall
25
+ * through to a lower-precedence metadata source.
26
+ */
27
+ export function verifyClientIdDocument(doc) {
28
+ if (!doc.https)
29
+ return null;
30
+ let retrievedUrl;
31
+ try {
32
+ retrievedUrl = new URL(doc.retrieved_from);
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ if (retrievedUrl.protocol !== "https:")
38
+ return null;
39
+ // The identity check: the document's client_id must be the URL it came from.
40
+ // Compared as URLs so a trailing-slash difference is not a false negative.
41
+ let assertedUrl;
42
+ try {
43
+ assertedUrl = new URL(doc.client_id);
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ if (assertedUrl.toString() !== retrievedUrl.toString())
49
+ return null;
50
+ return { verifiedDomain: retrievedUrl.hostname };
51
+ }
52
+ /**
53
+ * Resolve requester identity under §6's precedence:
54
+ *
55
+ * local registration / trust registry
56
+ * > validated software statement (not supported in this build)
57
+ * > validated binding metadata (the client ID metadata document)
58
+ * > inline `client_display`
59
+ * > `client_id` fallback
60
+ *
61
+ * The display name always resolves to something: §6 obligation 2 requires the
62
+ * AS to display `client_id` when no name is available, so the consent surface
63
+ * is never left with nothing to render.
64
+ */
65
+ export function resolveRequesterIdentity(input) {
66
+ const verification = input.document
67
+ ? verifyClientIdDocument(input.document)
68
+ : null;
69
+ // Precedence order, highest first.
70
+ const display = input.registered?.display ??
71
+ (verification ? input.document?.display : undefined) ??
72
+ input.inline;
73
+ return {
74
+ client_id: input.client_id,
75
+ display_name: display?.name ?? input.client_id,
76
+ ...(display && { display }),
77
+ // Named, not asserted as blanket verification.
78
+ ...(verification && { verified_domain: verification.verifiedDomain }),
79
+ // Only a real admission decision counts. Domain control is not approval.
80
+ app_approved: input.registered?.approved ?? false,
81
+ };
82
+ }
83
+ /**
84
+ * Whether a client-supplied remote logo may be rendered directly.
85
+ *
86
+ * §6 obligation 6: `logo_uri` is untrusted content. An unverified client's
87
+ * remote logo must not be fetched into the consent UI — the surface generates
88
+ * a monogram from the display name instead. Proxied-and-approved assets are a
89
+ * deployment concern the caller signals explicitly.
90
+ */
91
+ export function mayRenderRemoteLogo(identity, options = {}) {
92
+ if (options.assetProxiedAndApproved === true)
93
+ return true;
94
+ return identity.app_approved || identity.verified_domain !== undefined;
95
+ }
96
+ //# sourceMappingURL=client-metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-metadata.js","sourceRoot":"","sources":["../../src/pdpp/client-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AA8CH;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CACpC,GAA6B;IAE7B,IAAI,CAAC,GAAG,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAE5B,IAAI,YAAiB,CAAC;IACtB,IAAI,CAAC;QACH,YAAY,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,YAAY,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEpD,6EAA6E;IAC7E,2EAA2E;IAC3E,IAAI,WAAgB,CAAC;IACrB,IAAI,CAAC;QACH,WAAW,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,WAAW,CAAC,QAAQ,EAAE,KAAK,YAAY,CAAC,QAAQ,EAAE;QAAE,OAAO,IAAI,CAAC;IAEpE,OAAO,EAAE,cAAc,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,wBAAwB,CACtC,KAA4B;IAE5B,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ;QACjC,CAAC,CAAC,sBAAsB,CAAC,KAAK,CAAC,QAAQ,CAAC;QACxC,CAAC,CAAC,IAAI,CAAC;IAET,mCAAmC;IACnC,MAAM,OAAO,GACX,KAAK,CAAC,UAAU,EAAE,OAAO;QACzB,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QACpD,KAAK,CAAC,MAAM,CAAC;IAEf,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,YAAY,EAAE,OAAO,EAAE,IAAI,IAAI,KAAK,CAAC,SAAS;QAC9C,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;QAC3B,+CAA+C;QAC/C,GAAG,CAAC,YAAY,IAAI,EAAE,eAAe,EAAE,YAAY,CAAC,cAAc,EAAE,CAAC;QACrE,yEAAyE;QACzE,YAAY,EAAE,KAAK,CAAC,UAAU,EAAE,QAAQ,IAAI,KAAK;KAClD,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAA2B,EAC3B,UAAiD,EAAE;IAEnD,IAAI,OAAO,CAAC,uBAAuB,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC1D,OAAO,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS,CAAC;AACzE,CAAC"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * PDPP v0.2 recipient commitments: resolving purpose and retention before the
3
+ * owner approves.
4
+ *
5
+ * The section this implements exists because of one asymmetry. An owner
6
+ * narrowing what they share is acting entirely within their own authority —
7
+ * nobody else has to agree to receive less. An owner *changing the terms of
8
+ * use* is proposing an obligation the recipient has to carry, and no amount of
9
+ * owner authority makes the recipient agree to it. v0.2 keeps those two apart
10
+ * deliberately: "The AS MUST NOT interpret narrower access as recipient
11
+ * acceptance of a new purpose or retention obligation."
12
+ *
13
+ * So commitments resolve from exactly two places — the client's own request,
14
+ * or standing terms the recipient authorized — and an owner condition covered
15
+ * by neither refuses issuance rather than being carried as though agreed.
16
+ *
17
+ * The important non-obvious case: a condition *favourable* to the owner is
18
+ * still a condition. An owner asking for a 7-day retention when the client
19
+ * requested 30 is asking for less, but it is still a term the recipient never
20
+ * accepted, and recording it as a grant constraint would claim an acceptance
21
+ * that does not exist. PDPP carries commitments; it cannot enforce the
22
+ * recipient's behavior after disclosure, which is exactly why the record of
23
+ * what they actually agreed to has to be honest.
24
+ */
25
+ import type { OwnerConditions, RecipientTerms, Retention, SelectionRequest } from "./types.js";
26
+ /**
27
+ * Sentinel terms identity for commitments that came from the selection request
28
+ * itself.
29
+ *
30
+ * The request *is* recipient authority — the client wrote it — so this is a
31
+ * real answer rather than a missing one. Recording it explicitly, rather than
32
+ * leaving the evidence absent, is what makes "no terms were consulted"
33
+ * distinguishable from "the evidence was never written".
34
+ */
35
+ export declare const REQUEST_TERMS_ID = "urn:pdpp:recipient-terms:selection-request";
36
+ /** The commitments that will be shown to the owner and written into the grant. */
37
+ export interface ResolvedCommitments {
38
+ purpose_code: string;
39
+ purpose_description?: string;
40
+ retention?: Retention;
41
+ /** Identity and version of the authority these came from. */
42
+ evidence: {
43
+ id: string;
44
+ version: string;
45
+ };
46
+ }
47
+ export interface CommitmentsFailure {
48
+ code: "recipient_terms_unsupported";
49
+ message: string;
50
+ }
51
+ export type CommitmentsResult = {
52
+ ok: true;
53
+ commitments: ResolvedCommitments;
54
+ } | {
55
+ ok: false;
56
+ failure: CommitmentsFailure;
57
+ };
58
+ export interface ResolveCommitmentsInput {
59
+ request: SelectionRequest;
60
+ /** Conditions the owner attached to their approval. */
61
+ ownerConditions?: OwnerConditions;
62
+ /** Standing terms the recipient authorized, when the deployment tracks them. */
63
+ standingTerms?: RecipientTerms;
64
+ /** The declaration revision, used as the request's own evidence version. */
65
+ declarationVersion: string;
66
+ }
67
+ /**
68
+ * Resolve purpose and retention from the request or applicable standing terms.
69
+ *
70
+ * Runs before the owner approves, never after: v0.2 requires the owner to see
71
+ * the resolved commitments in the final review, so a commitment resolved at
72
+ * issuance time would be one the owner never saw.
73
+ */
74
+ export declare function resolveCommitments(input: ResolveCommitmentsInput): CommitmentsResult;
75
+ //# sourceMappingURL=commitments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commitments.d.ts","sourceRoot":"","sources":["../../src/pdpp/commitments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,+CAA+C,CAAC;AAE7E,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,6BAA6B,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,mBAAmB,CAAA;CAAE,GAC9C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAM/C,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,uDAAuD;IACvD,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,gFAAgF;IAChF,aAAa,CAAC,EAAE,cAAc,CAAC;IAC/B,4EAA4E;IAC5E,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,uBAAuB,GAC7B,iBAAiB,CAyEnB"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * PDPP v0.2 recipient commitments: resolving purpose and retention before the
3
+ * owner approves.
4
+ *
5
+ * The section this implements exists because of one asymmetry. An owner
6
+ * narrowing what they share is acting entirely within their own authority —
7
+ * nobody else has to agree to receive less. An owner *changing the terms of
8
+ * use* is proposing an obligation the recipient has to carry, and no amount of
9
+ * owner authority makes the recipient agree to it. v0.2 keeps those two apart
10
+ * deliberately: "The AS MUST NOT interpret narrower access as recipient
11
+ * acceptance of a new purpose or retention obligation."
12
+ *
13
+ * So commitments resolve from exactly two places — the client's own request,
14
+ * or standing terms the recipient authorized — and an owner condition covered
15
+ * by neither refuses issuance rather than being carried as though agreed.
16
+ *
17
+ * The important non-obvious case: a condition *favourable* to the owner is
18
+ * still a condition. An owner asking for a 7-day retention when the client
19
+ * requested 30 is asking for less, but it is still a term the recipient never
20
+ * accepted, and recording it as a grant constraint would claim an acceptance
21
+ * that does not exist. PDPP carries commitments; it cannot enforce the
22
+ * recipient's behavior after disclosure, which is exactly why the record of
23
+ * what they actually agreed to has to be honest.
24
+ */
25
+ /**
26
+ * Sentinel terms identity for commitments that came from the selection request
27
+ * itself.
28
+ *
29
+ * The request *is* recipient authority — the client wrote it — so this is a
30
+ * real answer rather than a missing one. Recording it explicitly, rather than
31
+ * leaving the evidence absent, is what makes "no terms were consulted"
32
+ * distinguishable from "the evidence was never written".
33
+ */
34
+ export const REQUEST_TERMS_ID = "urn:pdpp:recipient-terms:selection-request";
35
+ function sameRetention(a, b) {
36
+ return a.max_duration === b.max_duration && a.on_expiry === b.on_expiry;
37
+ }
38
+ /**
39
+ * Resolve purpose and retention from the request or applicable standing terms.
40
+ *
41
+ * Runs before the owner approves, never after: v0.2 requires the owner to see
42
+ * the resolved commitments in the final review, so a commitment resolved at
43
+ * issuance time would be one the owner never saw.
44
+ */
45
+ export function resolveCommitments(input) {
46
+ const { request, ownerConditions, standingTerms } = input;
47
+ // Absent any owner condition, the request's own terms stand and the client
48
+ // is self-evidently the authority for them.
49
+ let evidence = {
50
+ id: REQUEST_TERMS_ID,
51
+ version: input.declarationVersion,
52
+ };
53
+ let purposeCode = request.purpose_code;
54
+ let retention = request.retention;
55
+ // Error text is deliberately generic. v0.2: "Error descriptions MUST NOT
56
+ // reveal unapproved source, instance, record, or field existence." A
57
+ // rejection is a fine place to leak an inventory if the message names what
58
+ // the request touched, so this one names only the term class.
59
+ const refuse = (what) => ({
60
+ ok: false,
61
+ failure: {
62
+ code: "recipient_terms_unsupported",
63
+ message: `the requested ${what} is not covered by the recipient's applicable authority`,
64
+ },
65
+ });
66
+ if (ownerConditions?.purpose_code !== undefined) {
67
+ const proposed = ownerConditions.purpose_code;
68
+ const covered = proposed === request.purpose_code ||
69
+ standingTerms?.accepted_purpose_codes?.includes(proposed) === true;
70
+ if (!covered)
71
+ return refuse("purpose");
72
+ purposeCode = proposed;
73
+ // A purpose description authored for the client's own purpose code does
74
+ // not describe a different one. Dropping it is the honest outcome; the
75
+ // surface falls back to the code or its registry entry.
76
+ if (proposed !== request.purpose_code) {
77
+ evidence = termsEvidence(standingTerms, evidence);
78
+ }
79
+ }
80
+ if (ownerConditions?.retention !== undefined) {
81
+ const proposed = ownerConditions.retention;
82
+ const covered = (request.retention !== undefined &&
83
+ sameRetention(proposed, request.retention)) ||
84
+ standingTerms?.accepted_retention?.some((accepted) => sameRetention(proposed, accepted)) === true;
85
+ if (!covered)
86
+ return refuse("retention term");
87
+ retention = proposed;
88
+ if (request.retention === undefined ||
89
+ !sameRetention(proposed, request.retention)) {
90
+ evidence = termsEvidence(standingTerms, evidence);
91
+ }
92
+ }
93
+ const purposeDescription = purposeCode === request.purpose_code
94
+ ? request.purpose_description
95
+ : undefined;
96
+ return {
97
+ ok: true,
98
+ commitments: {
99
+ purpose_code: purposeCode,
100
+ ...(purposeDescription !== undefined && {
101
+ purpose_description: purposeDescription,
102
+ }),
103
+ ...(retention !== undefined && { retention }),
104
+ evidence,
105
+ },
106
+ };
107
+ }
108
+ function termsEvidence(standingTerms, fallback) {
109
+ if (!standingTerms)
110
+ return fallback;
111
+ return { id: standingTerms.id, version: standingTerms.version };
112
+ }
113
+ //# sourceMappingURL=commitments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commitments.js","sourceRoot":"","sources":["../../src/pdpp/commitments.ts"],"names":[],"mappings":"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"}