@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,89 @@
1
+ /**
2
+ * Durable retention for PDPP ↔ chain grant bindings (scope §6).
3
+ *
4
+ * The binding record is the only thing that crosses the gateway/chain
5
+ * boundary on our side; record payloads stay in PS storage and never enter
6
+ * this store. What is retained here is an identity join — PDPP grant id,
7
+ * chain permission ref, owner, grantee — and nothing about the data itself.
8
+ *
9
+ * ## Append-only by construction
10
+ *
11
+ * The port exposes `put` and `get` but no `update` and no `delete`. That is
12
+ * deliberate, and it is the mechanism that makes §6's revocation semantics
13
+ * correct rather than merely intended:
14
+ *
15
+ * - A binding asserts a *historical* fact ("this consent authorized this
16
+ * permission"), which does not stop being true when the grant is revoked.
17
+ * - Revocation is a *current* fact, and lives on the chain grant, read live
18
+ * at verification time.
19
+ *
20
+ * If revocation were mirrored into this store, the two would have to be kept
21
+ * in sync, and every window where they disagreed would be a window where a
22
+ * revoked grant still read as live. Not storing the status at all removes that
23
+ * class of bug instead of managing it.
24
+ *
25
+ * `putBinding` rejects a conflicting rewrite for the same key rather than
26
+ * overwriting, so a second binding cannot silently retarget an existing PDPP
27
+ * grant at a different permission, owner, or app.
28
+ */
29
+ import { type ChainPermissionRef, type PdppGrantBinding } from "./pdpp-binding.js";
30
+ /**
31
+ * Durable storage for grant bindings.
32
+ *
33
+ * Implementations back this with the deployment's real store (SQLite on
34
+ * desktop, the supplied runtime's durable state in Enclave). The interface is
35
+ * intentionally tiny so both can implement it without sharing a schema.
36
+ */
37
+ export interface PdppGrantBindingStore {
38
+ /**
39
+ * Retain a binding. Idempotent for an identical re-put; throws on a
40
+ * conflicting one.
41
+ */
42
+ putBinding(binding: PdppGrantBinding): void;
43
+ /** Look up by the PDPP grant id (the consent artifact). */
44
+ getByPdppGrantId(pdppGrantId: string): PdppGrantBinding | null;
45
+ /**
46
+ * All bindings recorded against a chain permission, oldest first.
47
+ *
48
+ * Plural and non-unique on purpose: distinct PDPP grants can legitimately
49
+ * bind to the same permission over time (e.g. one consent superseding
50
+ * another at the chain level), and each retains its own observed
51
+ * `grantVersion`. Returning a single "the" binding here would silently
52
+ * pick one and hide the others — callers that need "is any binding for
53
+ * this permission still live" must check every entry themselves.
54
+ */
55
+ getBindingsForPermission(permission: ChainPermissionRef): PdppGrantBinding[];
56
+ }
57
+ /**
58
+ * True when two bindings agree on every field that defines the binding.
59
+ *
60
+ * Both `granteeAddress` (the app's wallet) and `granteeId` (the builder id
61
+ * the chain grant names) are compared, which makes rotation of either an
62
+ * explicit conflict rather than a silent follow. That is deliberate. Context
63
+ * Gateway holds one Privy-custodied wallet per app, keyed `(ownerType,
64
+ * ownerId)` with a DB unique index, and its schema *models* rotation
65
+ * (`isCurrent` plus a partial unique index) although no code path performs
66
+ * one today — so the address is currently immutable per app in practice but
67
+ * not by design.
68
+ *
69
+ * If rotation ever ships, a rotated wallet or builder id is a different
70
+ * grantee, and the owner's existing consent must not transfer to it without
71
+ * a new decision. Rejecting the rewrite surfaces that as a failure instead of
72
+ * quietly repointing a retained grant at an identity the owner never
73
+ * approved.
74
+ */
75
+ export declare function bindingsAgree(a: PdppGrantBinding, b: PdppGrantBinding): boolean;
76
+ export declare function permissionKey(p: ChainPermissionRef): string;
77
+ /** New bindings require a version; only migrated rows may retain null. */
78
+ export declare function assertWritableGrantVersion(binding: PdppGrantBinding): void;
79
+ /**
80
+ * In-memory implementation, used by tests and by callers that have no durable
81
+ * store yet.
82
+ *
83
+ * This is a real implementation of the port's semantics — including the
84
+ * conflict rejection — not a stub that accepts everything. Tests exercising it
85
+ * are therefore testing the actual binding rules; only the persistence medium
86
+ * differs from a deployed store.
87
+ */
88
+ export declare function createInMemoryPdppGrantBindingStore(): PdppGrantBindingStore;
89
+ //# sourceMappingURL=pdpp-binding-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdpp-binding-store.d.ts","sourceRoot":"","sources":["../../src/grants/pdpp-binding-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC5C,2DAA2D;IAC3D,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC/D;;;;;;;;;OASG;IACH,wBAAwB,CAAC,UAAU,EAAE,kBAAkB,GAAG,gBAAgB,EAAE,CAAC;CAC9E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,gBAAgB,EACnB,CAAC,EAAE,gBAAgB,GAClB,OAAO,CAUT;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAE3D;AAED,0EAA0E;AAC1E,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAS1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,mCAAmC,IAAI,qBAAqB,CAyC3E"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Durable retention for PDPP ↔ chain grant bindings (scope §6).
3
+ *
4
+ * The binding record is the only thing that crosses the gateway/chain
5
+ * boundary on our side; record payloads stay in PS storage and never enter
6
+ * this store. What is retained here is an identity join — PDPP grant id,
7
+ * chain permission ref, owner, grantee — and nothing about the data itself.
8
+ *
9
+ * ## Append-only by construction
10
+ *
11
+ * The port exposes `put` and `get` but no `update` and no `delete`. That is
12
+ * deliberate, and it is the mechanism that makes §6's revocation semantics
13
+ * correct rather than merely intended:
14
+ *
15
+ * - A binding asserts a *historical* fact ("this consent authorized this
16
+ * permission"), which does not stop being true when the grant is revoked.
17
+ * - Revocation is a *current* fact, and lives on the chain grant, read live
18
+ * at verification time.
19
+ *
20
+ * If revocation were mirrored into this store, the two would have to be kept
21
+ * in sync, and every window where they disagreed would be a window where a
22
+ * revoked grant still read as live. Not storing the status at all removes that
23
+ * class of bug instead of managing it.
24
+ *
25
+ * `putBinding` rejects a conflicting rewrite for the same key rather than
26
+ * overwriting, so a second binding cannot silently retarget an existing PDPP
27
+ * grant at a different permission, owner, or app.
28
+ */
29
+ import { InvalidSignatureError } from "../errors/catalog.js";
30
+ import { isValidGrantVersion, samePermission, } from "./pdpp-binding.js";
31
+ /**
32
+ * True when two bindings agree on every field that defines the binding.
33
+ *
34
+ * Both `granteeAddress` (the app's wallet) and `granteeId` (the builder id
35
+ * the chain grant names) are compared, which makes rotation of either an
36
+ * explicit conflict rather than a silent follow. That is deliberate. Context
37
+ * Gateway holds one Privy-custodied wallet per app, keyed `(ownerType,
38
+ * ownerId)` with a DB unique index, and its schema *models* rotation
39
+ * (`isCurrent` plus a partial unique index) although no code path performs
40
+ * one today — so the address is currently immutable per app in practice but
41
+ * not by design.
42
+ *
43
+ * If rotation ever ships, a rotated wallet or builder id is a different
44
+ * grantee, and the owner's existing consent must not transfer to it without
45
+ * a new decision. Rejecting the rewrite surfaces that as a failure instead of
46
+ * quietly repointing a retained grant at an identity the owner never
47
+ * approved.
48
+ */
49
+ export function bindingsAgree(a, b) {
50
+ return (a.pdppGrantId === b.pdppGrantId &&
51
+ samePermission(a.permission, b.permission) &&
52
+ a.ownerAddress.toLowerCase() === b.ownerAddress.toLowerCase() &&
53
+ a.granteeAddress.toLowerCase() === b.granteeAddress.toLowerCase() &&
54
+ a.granteeId.toLowerCase() === b.granteeId.toLowerCase() &&
55
+ a.pdppClientId === b.pdppClientId &&
56
+ a.grantVersion === b.grantVersion);
57
+ }
58
+ export function permissionKey(p) {
59
+ return `${p.chainId}:${p.contractAddress.toLowerCase()}:${p.permissionId}`;
60
+ }
61
+ /** New bindings require a version; only migrated rows may retain null. */
62
+ export function assertWritableGrantVersion(binding) {
63
+ if (!isValidGrantVersion(binding.grantVersion)) {
64
+ throw new InvalidSignatureError({
65
+ reason: "grantVersion must be a positive decimal uint256 string for a new binding; null is reserved for a preserved legacy row",
66
+ pdppGrantId: binding.pdppGrantId,
67
+ grantVersion: binding.grantVersion,
68
+ });
69
+ }
70
+ }
71
+ /**
72
+ * In-memory implementation, used by tests and by callers that have no durable
73
+ * store yet.
74
+ *
75
+ * This is a real implementation of the port's semantics — including the
76
+ * conflict rejection — not a stub that accepts everything. Tests exercising it
77
+ * are therefore testing the actual binding rules; only the persistence medium
78
+ * differs from a deployed store.
79
+ */
80
+ export function createInMemoryPdppGrantBindingStore() {
81
+ const byGrantId = new Map();
82
+ const byPermission = new Map();
83
+ return {
84
+ putBinding(binding) {
85
+ const existingByGrant = byGrantId.get(binding.pdppGrantId);
86
+ if (existingByGrant) {
87
+ if (!bindingsAgree(existingByGrant, binding)) {
88
+ throw new InvalidSignatureError({
89
+ reason: "A different binding already exists for this PDPP grant id",
90
+ pdppGrantId: binding.pdppGrantId,
91
+ });
92
+ }
93
+ return;
94
+ }
95
+ assertWritableGrantVersion(binding);
96
+ const key = permissionKey(binding.permission);
97
+ const list = byPermission.get(key) ?? [];
98
+ list.push(binding);
99
+ byPermission.set(key, list);
100
+ byGrantId.set(binding.pdppGrantId, binding);
101
+ },
102
+ getByPdppGrantId(pdppGrantId) {
103
+ return byGrantId.get(pdppGrantId) ?? null;
104
+ },
105
+ getBindingsForPermission(permission) {
106
+ const list = byPermission.get(permissionKey(permission)) ?? [];
107
+ return [...list].sort((a, b) => a.boundAt.localeCompare(b.boundAt) ||
108
+ a.pdppGrantId.localeCompare(b.pdppGrantId));
109
+ },
110
+ };
111
+ }
112
+ //# sourceMappingURL=pdpp-binding-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdpp-binding-store.js","sourceRoot":"","sources":["../../src/grants/pdpp-binding-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Retains the identity join between a PDPP grant and a Vana gateway grant.
3
+ * `permissionId` stores GatewayGrantResponse.id, including hex grant IDs.
4
+ * Builder IDs and wallet addresses are distinct: creation requires a trusted
5
+ * builder lookup, and verification compares each identity with its counterpart.
6
+ * Deployment fields bind the record to the PS configuration; they are not
7
+ * authenticated fields of the gateway response. Revocation is checked live.
8
+ */
9
+ import type { Builder, GatewayGrantResponse } from "@opendatalabs/vana-sdk/browser";
10
+ /**
11
+ * The chain-side identity of a grant. This tuple — and not any derived digest
12
+ * — is the binding key.
13
+ *
14
+ * `chainId` and `contractAddress` are the PS's own deployment configuration,
15
+ * not fields the gateway returns; see the module doc for why they are kept.
16
+ * `permissionId` is `GatewayGrantResponse.id` (see module doc) — keying on it
17
+ * alone, without a deployment tag, would also let a record recorded under one
18
+ * deployment configuration silently authorize a read under another.
19
+ */
20
+ export interface ChainPermissionRef {
21
+ /** EIP-155 chain ID of the deployment the PS was configured against when this was recorded. */
22
+ chainId: number;
23
+ /** The gateway/contract address the PS was configured against when this was recorded. */
24
+ contractAddress: `0x${string}`;
25
+ /** `GatewayGrantResponse.id` — the gateway's grant id (may be hex). */
26
+ permissionId: string;
27
+ }
28
+ /** The builder evidence a caller must resolve before creating or checking a binding. */
29
+ export type ResolvedBuilder = Pick<Builder, "id" | "granteeAddress">;
30
+ /**
31
+ * An immutable binding between one resolved PDPP grant and one chain
32
+ * permission.
33
+ *
34
+ * Immutability is the point: this record is written once, at grant creation,
35
+ * and is never mutated — not even on revocation. Revocation is a *live* fact
36
+ * read from the chain grant (`revokedAt`), never a field edited here. Copying
37
+ * a mutable status into an immutable record is how a stale "still valid" claim
38
+ * survives a revocation, so the two are kept strictly apart.
39
+ */
40
+ export interface PdppGrantBinding {
41
+ /** `grant_id` of the resolved PDPP grant (the consent artifact). */
42
+ pdppGrantId: string;
43
+ /** Chain identity of the permission that authorizes reads for this grant. */
44
+ permission: ChainPermissionRef;
45
+ /**
46
+ * The data owner. Must equal both the chain grant's `grantorAddress` and the
47
+ * PS's configured `serverOwner` at read time.
48
+ */
49
+ ownerAddress: `0x${string}`;
50
+ /**
51
+ * The grantee app's wallet address — the app's *existing* identity, carried
52
+ * through unchanged.
53
+ *
54
+ * §6 requires one grantee identity per Context Gateway builder/app: the
55
+ * PDPP `client_id`, the issued grant, the ledger grant, and the access-history
56
+ * grantee must all resolve to this one address. We record the address the app
57
+ * already has; we do not allocate one.
58
+ */
59
+ granteeAddress: `0x${string}`;
60
+ /** The PDPP OAuth `client_id` that the above address belongs to. */
61
+ pdppClientId: string;
62
+ /**
63
+ * The resolved builder's id (`Builder.id`), as the chain grant's
64
+ * `granteeId` reports it. This is a distinct bytes32-shaped identifier,
65
+ * NOT the wallet address above — see the module doc.
66
+ */
67
+ granteeId: string;
68
+ /** Gateway version verified at binding time. Later versions invalidate this consent.
69
+ * `null` denotes a preserved legacy row and always denies access.
70
+ */
71
+ grantVersion: string | null;
72
+ /** When the binding was recorded (ISO 8601). Provenance, not status. */
73
+ boundAt: string;
74
+ }
75
+ export declare function isValidGrantVersion(value: unknown): value is string;
76
+ /** Re-registration can clear revocation, so even a newer version requires new consent. */
77
+ export declare function grantVersionStillAuthorizes(retainedVersion: string | null, liveVersion: unknown): boolean;
78
+ /**
79
+ * Compare two chain permission references. All three components must match —
80
+ * see `ChainPermissionRef` for why the address and chain ID are load-bearing.
81
+ */
82
+ export declare function samePermission(a: ChainPermissionRef, b: ChainPermissionRef): boolean;
83
+ export interface CreateBindingInput {
84
+ pdppGrantId: string;
85
+ permission: ChainPermissionRef;
86
+ /** The PS's configured owner address. */
87
+ serverOwner: `0x${string}`;
88
+ /** The app's existing grantee wallet address. */
89
+ granteeAddress: `0x${string}`;
90
+ pdppClientId: string;
91
+ /**
92
+ * Trusted, already-resolved builder evidence for `granteeAddress` — e.g.
93
+ * `await gateway.getBuilder(granteeAddress)`. This is what lets the binding
94
+ * check the chain grant's `granteeId` (a builder id) against the right
95
+ * counterpart instead of against the wallet address directly.
96
+ */
97
+ resolvedBuilder: ResolvedBuilder;
98
+ /** The chain grant this PDPP grant is being bound to, as the gateway reports it. */
99
+ chainGrant: GatewayGrantResponse;
100
+ now?: Date;
101
+ }
102
+ /**
103
+ * Create the binding at grant-creation time, refusing to record one that is
104
+ * already inconsistent.
105
+ *
106
+ * This is the *creation* boundary check. It is deliberately strict: a binding
107
+ * written now is trusted later, so anything we fail to verify here becomes an
108
+ * unverifiable assertion at read time. Specifically it rejects:
109
+ *
110
+ * - a chain grant whose `grantorAddress` is not this server's owner (binding
111
+ * another owner's grant to our PDPP consent),
112
+ * - a `resolvedBuilder` whose wallet is not the app's requested address
113
+ * (the caller resolved the wrong builder),
114
+ * - a chain grant whose `granteeId` is not the resolved builder's id
115
+ * (binding a grant issued to a *different* app),
116
+ * - a chain grant that is already revoked (never record a dead grant as live),
117
+ * - a chain grant whose id does not match the permission being bound,
118
+ * - a chain grant whose `grantVersion` is missing or not a valid positive
119
+ * decimal uint256 string (a new binding must pin a real version; `null`
120
+ * is reserved for legacy rows a schema migration preserved, never for
121
+ * something created through this function).
122
+ */
123
+ export declare function createPdppGrantBinding(input: CreateBindingInput): PdppGrantBinding;
124
+ export interface VerifyBindingInput {
125
+ /** The retained, immutable binding record. */
126
+ binding: PdppGrantBinding;
127
+ /** The PDPP grant id presented by the caller. */
128
+ pdppGrantId: string;
129
+ /** The PS's configured owner address, at read time. */
130
+ serverOwner: `0x${string}`;
131
+ /** The address that signed this request (the app's grantee wallet). */
132
+ requestSigner: `0x${string}`;
133
+ /**
134
+ * The chain grant as read *now*. Revocation is read live from here; it is
135
+ * never taken from the binding record.
136
+ */
137
+ chainGrant: GatewayGrantResponse | null;
138
+ /** The deployment the PS is configured against, at read time. */
139
+ deployment: {
140
+ chainId: number;
141
+ contractAddress: `0x${string}`;
142
+ };
143
+ }
144
+ /**
145
+ * Verify a binding at read time.
146
+ *
147
+ * Every axis §6 names is checked against the *retained* binding, so a
148
+ * mismatch on any one of owner, app, chain/contract, or record fails closed:
149
+ *
150
+ * - **record**: the presented PDPP grant id must be the one bound,
151
+ * - **chain/contract**: the binding must have been recorded under the same
152
+ * deployment configuration the PS is running under now (see module doc —
153
+ * this is an operator-misconfiguration guard, not gateway-supplied
154
+ * evidence, since the gateway response carries no chain/contract fields),
155
+ * - **owner**: the binding's owner must still be this server's owner, and the
156
+ * live chain grant's grantor must agree,
157
+ * - **app**: the request signer (a wallet) must be the bound grantee
158
+ * address, and the live chain grant's `granteeId` (a builder id) must
159
+ * still agree with the `granteeId` retained on the binding — these two
160
+ * checks are deliberately against different fields, because a wallet and
161
+ * a builder id are different values,
162
+ * - **revocation**: the live chain grant must exist and be unrevoked.
163
+ *
164
+ * No chain I/O happens in this function — the caller supplies the already-read
165
+ * `chainGrant`. That keeps this usable on the hot read path without adding a
166
+ * network round trip per request.
167
+ */
168
+ export declare function verifyPdppGrantBinding(input: VerifyBindingInput): void;
169
+ //# sourceMappingURL=pdpp-binding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdpp-binding.d.ts","sourceRoot":"","sources":["../../src/grants/pdpp-binding.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,KAAK,EACV,OAAO,EACP,oBAAoB,EACrB,MAAM,gCAAgC,CAAC;AAExC;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC,+FAA+F;IAC/F,OAAO,EAAE,MAAM,CAAC;IAChB,yFAAyF;IACzF,eAAe,EAAE,KAAK,MAAM,EAAE,CAAC;IAC/B,uEAAuE;IACvE,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wFAAwF;AACxF,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,gBAAgB,CAAC,CAAC;AAErE;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,UAAU,EAAE,kBAAkB,CAAC;IAC/B;;;OAGG;IACH,YAAY,EAAE,KAAK,MAAM,EAAE,CAAC;IAC5B;;;;;;;;OAQG;IACH,cAAc,EAAE,KAAK,MAAM,EAAE,CAAC;IAC9B,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAInE;AAED,0FAA0F;AAC1F,wBAAgB,2BAA2B,CACzC,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,WAAW,EAAE,OAAO,GACnB,OAAO,CAIT;AAOD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,CAAC,EAAE,kBAAkB,EACrB,CAAC,EAAE,kBAAkB,GACpB,OAAO,CAMT;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,yCAAyC;IACzC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;IAC3B,iDAAiD;IACjD,cAAc,EAAE,KAAK,MAAM,EAAE,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,eAAe,EAAE,eAAe,CAAC;IACjC,oFAAoF;IACpF,UAAU,EAAE,oBAAoB,CAAC;IACjC,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,kBAAkB,GACxB,gBAAgB,CAsElB;AAED,MAAM,WAAW,kBAAkB;IACjC,8CAA8C;IAC9C,OAAO,EAAE,gBAAgB,CAAC;IAC1B,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;IAC3B,uEAAuE;IACvE,aAAa,EAAE,KAAK,MAAM,EAAE,CAAC;IAC7B;;;OAGG;IACH,UAAU,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACxC,iEAAiE;IACjE,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,KAAK,MAAM,EAAE,CAAA;KAAE,CAAC;CACjE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CA0GtE"}
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Retains the identity join between a PDPP grant and a Vana gateway grant.
3
+ * `permissionId` stores GatewayGrantResponse.id, including hex grant IDs.
4
+ * Builder IDs and wallet addresses are distinct: creation requires a trusted
5
+ * builder lookup, and verification compares each identity with its counterpart.
6
+ * Deployment fields bind the record to the PS configuration; they are not
7
+ * authenticated fields of the gateway response. Revocation is checked live.
8
+ */
9
+ import { GrantOwnerMismatchError, GrantRevokedError, InvalidSignatureError, ScopeMismatchError, } from "../errors/catalog.js";
10
+ /** Gateway versions are positive decimal uint256 strings without leading zeros. */
11
+ const POSITIVE_DECIMAL_UINT256 = /^(0|[1-9][0-9]*)$/;
12
+ const UINT256_MAX = 2n ** 256n - 1n;
13
+ export function isValidGrantVersion(value) {
14
+ if (typeof value !== "string")
15
+ return false;
16
+ if (!POSITIVE_DECIMAL_UINT256.test(value) || value === "0")
17
+ return false;
18
+ return BigInt(value) <= UINT256_MAX;
19
+ }
20
+ /** Re-registration can clear revocation, so even a newer version requires new consent. */
21
+ export function grantVersionStillAuthorizes(retainedVersion, liveVersion) {
22
+ if (retainedVersion === null)
23
+ return false;
24
+ if (!isValidGrantVersion(liveVersion))
25
+ return false;
26
+ return retainedVersion === liveVersion;
27
+ }
28
+ /** Case-insensitive comparison for hex-ish strings (addresses or bytes32 ids). */
29
+ function sameHex(a, b) {
30
+ return typeof a === "string" && a.toLowerCase() === b.toLowerCase();
31
+ }
32
+ /**
33
+ * Compare two chain permission references. All three components must match —
34
+ * see `ChainPermissionRef` for why the address and chain ID are load-bearing.
35
+ */
36
+ export function samePermission(a, b) {
37
+ return (a.chainId === b.chainId &&
38
+ a.contractAddress.toLowerCase() === b.contractAddress.toLowerCase() &&
39
+ a.permissionId === b.permissionId);
40
+ }
41
+ /**
42
+ * Create the binding at grant-creation time, refusing to record one that is
43
+ * already inconsistent.
44
+ *
45
+ * This is the *creation* boundary check. It is deliberately strict: a binding
46
+ * written now is trusted later, so anything we fail to verify here becomes an
47
+ * unverifiable assertion at read time. Specifically it rejects:
48
+ *
49
+ * - a chain grant whose `grantorAddress` is not this server's owner (binding
50
+ * another owner's grant to our PDPP consent),
51
+ * - a `resolvedBuilder` whose wallet is not the app's requested address
52
+ * (the caller resolved the wrong builder),
53
+ * - a chain grant whose `granteeId` is not the resolved builder's id
54
+ * (binding a grant issued to a *different* app),
55
+ * - a chain grant that is already revoked (never record a dead grant as live),
56
+ * - a chain grant whose id does not match the permission being bound,
57
+ * - a chain grant whose `grantVersion` is missing or not a valid positive
58
+ * decimal uint256 string (a new binding must pin a real version; `null`
59
+ * is reserved for legacy rows a schema migration preserved, never for
60
+ * something created through this function).
61
+ */
62
+ export function createPdppGrantBinding(input) {
63
+ const { chainGrant, serverOwner, granteeAddress, resolvedBuilder, permission, } = input;
64
+ if (chainGrant.id !== permission.permissionId) {
65
+ throw new InvalidSignatureError({
66
+ reason: "Chain grant id does not match the permission being bound",
67
+ expected: permission.permissionId,
68
+ actual: chainGrant.id,
69
+ });
70
+ }
71
+ if (!sameHex(chainGrant.grantorAddress, serverOwner)) {
72
+ throw new GrantOwnerMismatchError({
73
+ grantId: chainGrant.id,
74
+ expected: serverOwner,
75
+ actual: chainGrant.grantorAddress ?? null,
76
+ });
77
+ }
78
+ // The caller's resolved builder must actually BE the requested app's
79
+ // wallet — otherwise everything below verifies the wrong builder.
80
+ if (!sameHex(resolvedBuilder.granteeAddress, granteeAddress)) {
81
+ throw new InvalidSignatureError({
82
+ reason: "Resolved builder wallet does not match the requested app address",
83
+ expected: granteeAddress,
84
+ actual: resolvedBuilder.granteeAddress,
85
+ });
86
+ }
87
+ // Bind to the app's EXISTING grantee identity. If the chain grant was
88
+ // issued to a different builder, this PDPP consent does not describe it.
89
+ // `granteeId` is the builder's bytes32 id, NOT its wallet address — compare
90
+ // against `resolvedBuilder.id`, never against `granteeAddress` directly.
91
+ if (!sameHex(chainGrant.granteeId, resolvedBuilder.id)) {
92
+ throw new InvalidSignatureError({
93
+ reason: "Chain grant grantee does not match the app's builder id",
94
+ expected: resolvedBuilder.id,
95
+ actual: chainGrant.granteeId,
96
+ });
97
+ }
98
+ if (chainGrant.revokedAt !== null && chainGrant.revokedAt !== undefined) {
99
+ throw new GrantRevokedError({ grantId: chainGrant.id });
100
+ }
101
+ if (!isValidGrantVersion(chainGrant.grantVersion)) {
102
+ throw new InvalidSignatureError({
103
+ reason: "Chain grant grantVersion is missing or malformed",
104
+ grantId: chainGrant.id,
105
+ actual: chainGrant.grantVersion,
106
+ });
107
+ }
108
+ return Object.freeze({
109
+ pdppGrantId: input.pdppGrantId,
110
+ permission,
111
+ ownerAddress: serverOwner,
112
+ granteeAddress,
113
+ pdppClientId: input.pdppClientId,
114
+ granteeId: chainGrant.granteeId,
115
+ grantVersion: chainGrant.grantVersion,
116
+ boundAt: (input.now ?? new Date()).toISOString(),
117
+ });
118
+ }
119
+ /**
120
+ * Verify a binding at read time.
121
+ *
122
+ * Every axis §6 names is checked against the *retained* binding, so a
123
+ * mismatch on any one of owner, app, chain/contract, or record fails closed:
124
+ *
125
+ * - **record**: the presented PDPP grant id must be the one bound,
126
+ * - **chain/contract**: the binding must have been recorded under the same
127
+ * deployment configuration the PS is running under now (see module doc —
128
+ * this is an operator-misconfiguration guard, not gateway-supplied
129
+ * evidence, since the gateway response carries no chain/contract fields),
130
+ * - **owner**: the binding's owner must still be this server's owner, and the
131
+ * live chain grant's grantor must agree,
132
+ * - **app**: the request signer (a wallet) must be the bound grantee
133
+ * address, and the live chain grant's `granteeId` (a builder id) must
134
+ * still agree with the `granteeId` retained on the binding — these two
135
+ * checks are deliberately against different fields, because a wallet and
136
+ * a builder id are different values,
137
+ * - **revocation**: the live chain grant must exist and be unrevoked.
138
+ *
139
+ * No chain I/O happens in this function — the caller supplies the already-read
140
+ * `chainGrant`. That keeps this usable on the hot read path without adding a
141
+ * network round trip per request.
142
+ */
143
+ export function verifyPdppGrantBinding(input) {
144
+ const { binding, chainGrant, deployment } = input;
145
+ // Record binding: the consent artifact presented must be the bound one.
146
+ if (binding.pdppGrantId !== input.pdppGrantId) {
147
+ throw new ScopeMismatchError({
148
+ requestedScope: "pdpp:binding",
149
+ reason: "PDPP grant id does not match the binding record",
150
+ expected: binding.pdppGrantId,
151
+ actual: input.pdppGrantId,
152
+ });
153
+ }
154
+ // Deployment binding: a record from another PS deployment configuration is
155
+ // not evidence here. See module doc — this cannot be checked against the
156
+ // gateway response (it carries no chain/contract fields); it guards
157
+ // against the PS itself being reconfigured to a different deployment
158
+ // between when the binding was recorded and when it is read.
159
+ if (binding.permission.chainId !== deployment.chainId ||
160
+ binding.permission.contractAddress.toLowerCase() !==
161
+ deployment.contractAddress.toLowerCase()) {
162
+ throw new ScopeMismatchError({
163
+ requestedScope: "pdpp:binding",
164
+ reason: "Binding is for a different chain deployment",
165
+ expected: `${deployment.chainId}:${deployment.contractAddress}`,
166
+ actual: `${binding.permission.chainId}:${binding.permission.contractAddress}`,
167
+ });
168
+ }
169
+ // Owner binding, against the server's current configuration.
170
+ if (!sameHex(binding.ownerAddress, input.serverOwner)) {
171
+ throw new GrantOwnerMismatchError({
172
+ grantId: binding.permission.permissionId,
173
+ expected: input.serverOwner,
174
+ actual: binding.ownerAddress,
175
+ });
176
+ }
177
+ // App binding: the caller must BE the bound grantee wallet, not merely
178
+ // know its grant id.
179
+ if (!sameHex(input.requestSigner, binding.granteeAddress)) {
180
+ throw new InvalidSignatureError({
181
+ reason: "Request signer is not the bound grantee for this PDPP grant",
182
+ expected: binding.granteeAddress,
183
+ actual: input.requestSigner,
184
+ });
185
+ }
186
+ // Revocation is read live. A missing chain grant is treated as revoked
187
+ // rather than as "unknown": failing open here would let a deleted or
188
+ // unreachable permission authorize reads.
189
+ if (!chainGrant) {
190
+ throw new GrantRevokedError({
191
+ grantId: binding.permission.permissionId,
192
+ reason: "Chain grant not found",
193
+ });
194
+ }
195
+ if (chainGrant.id !== binding.permission.permissionId) {
196
+ throw new ScopeMismatchError({
197
+ requestedScope: "pdpp:binding",
198
+ reason: "Chain grant id does not match the binding record",
199
+ expected: binding.permission.permissionId,
200
+ actual: chainGrant.id,
201
+ });
202
+ }
203
+ if (chainGrant.revokedAt !== null && chainGrant.revokedAt !== undefined) {
204
+ throw new GrantRevokedError({ grantId: chainGrant.id });
205
+ }
206
+ if (!grantVersionStillAuthorizes(binding.grantVersion, chainGrant.grantVersion)) {
207
+ throw new InvalidSignatureError({
208
+ reason: "Chain grant version no longer matches the bound grantVersion",
209
+ expected: binding.grantVersion,
210
+ actual: chainGrant.grantVersion,
211
+ });
212
+ }
213
+ // The live chain grant must still agree with the binding on both parties.
214
+ // These can diverge from the record only if the gateway is serving a
215
+ // different grant under the same id, which we must not paper over.
216
+ if (!sameHex(chainGrant.grantorAddress, binding.ownerAddress)) {
217
+ throw new GrantOwnerMismatchError({
218
+ grantId: chainGrant.id,
219
+ expected: binding.ownerAddress,
220
+ actual: chainGrant.grantorAddress ?? null,
221
+ });
222
+ }
223
+ // Compare the live grant's builder id (`granteeId`) against the builder id
224
+ // retained on the binding (`binding.granteeId`) — NOT against
225
+ // `binding.granteeAddress`, which is a wallet. The wallet is what
226
+ // `requestSigner` proves above; this checks the separate, gateway-reported
227
+ // builder-id axis has not drifted.
228
+ if (!sameHex(chainGrant.granteeId, binding.granteeId)) {
229
+ throw new InvalidSignatureError({
230
+ reason: "Chain grant grantee no longer matches the bound grantee",
231
+ expected: binding.granteeId,
232
+ actual: chainGrant.granteeId,
233
+ });
234
+ }
235
+ }
236
+ //# sourceMappingURL=pdpp-binding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdpp-binding.js","sourceRoot":"","sources":["../../src/grants/pdpp-binding.ts"],"names":[],"mappings":"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"}