@hraness/ghostget 0.17.2

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 (500) hide show
  1. package/CHANGELOG.md +458 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1359 -0
  4. package/bunfig.toml +2 -0
  5. package/dist/apple-photos-client.js +704 -0
  6. package/dist/beeper-client.js +4602 -0
  7. package/dist/client.js +1605 -0
  8. package/dist/index-26yq8q16.js +31 -0
  9. package/dist/index-9t13b4k7.js +508 -0
  10. package/dist/index-axwm9b3v.js +5 -0
  11. package/dist/index-gwk7rbyj.js +30 -0
  12. package/dist/index.js +701 -0
  13. package/dist/messaging.js +1130 -0
  14. package/dist/omni-client.js +1406 -0
  15. package/dist/whatsapp-client.js +355 -0
  16. package/docs/imessage-direct-provider.md +106 -0
  17. package/docs/rental-listings.md +94 -0
  18. package/package.json +600 -0
  19. package/skills/ghostget/SKILL.md +251 -0
  20. package/skills/ghostget/agents/openai.yaml +4 -0
  21. package/skills/ghostget/references/adapter-contract.md +181 -0
  22. package/skills/ghostget/references/apple-photos.md +115 -0
  23. package/skills/ghostget/references/article-drafts.md +235 -0
  24. package/skills/ghostget/references/code-owned-provider-scaffold.md +134 -0
  25. package/skills/ghostget/references/cross-posting-video.md +139 -0
  26. package/skills/ghostget/references/cross-posting.md +82 -0
  27. package/skills/ghostget/references/derivation.md +390 -0
  28. package/skills/ghostget/references/hraness-social-profile-stats.json +269 -0
  29. package/skills/ghostget/references/install.md +66 -0
  30. package/skills/ghostget/references/linkedin-adapter.md +442 -0
  31. package/skills/ghostget/references/messaging.md +168 -0
  32. package/skills/ghostget/references/meta-comet-contract.md +153 -0
  33. package/skills/ghostget/references/platform-patterns.md +122 -0
  34. package/skills/ghostget/references/provider-plugins.md +496 -0
  35. package/skills/ghostget/references/reddit-flair.md +78 -0
  36. package/skills/ghostget/references/safety-and-state.md +214 -0
  37. package/skills/ghostget/references/settlement-and-duplicate-cleanup.md +79 -0
  38. package/skills/ghostget/references/social-platform-routing.md +66 -0
  39. package/skills/ghostget/references/social-profile-stats.md +195 -0
  40. package/skills/ghostget/references/social-video-platform-routing.md +89 -0
  41. package/skills/ghostget/references/whatsapp-adapter.md +101 -0
  42. package/skills/ghostget/references/x-adapter.md +332 -0
  43. package/skills/ghostget/references/x-ai-disclosure.md +71 -0
  44. package/src/apple-photos-cli.ts +639 -0
  45. package/src/apple-photos-client-types.ts +168 -0
  46. package/src/apple-photos-client.ts +201 -0
  47. package/src/apple-photos-contact-evidence.ts +838 -0
  48. package/src/apple-photos-local-source.ts +1131 -0
  49. package/src/args.ts +2053 -0
  50. package/src/article-draft-document.ts +417 -0
  51. package/src/article-draft-embeds.ts +123 -0
  52. package/src/article-draft-images.ts +214 -0
  53. package/src/assets/adapter-template/wrench-adapter.json +40 -0
  54. package/src/assets/adapters/beeper/wrench-web-adapter.json +1500 -0
  55. package/src/assets/adapters/beeper/wrench-web-adapter.v1.0.0.json +129 -0
  56. package/src/assets/adapters/beeper/wrench-web-adapter.v1.1.0.json +207 -0
  57. package/src/assets/adapters/beeper/wrench-web-adapter.v2.0.0.json +1463 -0
  58. package/src/assets/adapters/beeper/wrench-web-adapter.v2.1.0.json +1463 -0
  59. package/src/assets/adapters/beeper/wrench-web-adapter.v2.2.0.json +1475 -0
  60. package/src/assets/adapters/beeper/wrench-web-adapter.v2.3.0.json +1488 -0
  61. package/src/assets/adapters/bluesky/wrench-web-adapter.json +684 -0
  62. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.0.0.json +581 -0
  63. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.1.0.json +581 -0
  64. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.2.0.json +581 -0
  65. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.3.0.json +615 -0
  66. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.4.0.json +684 -0
  67. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.5.0.json +684 -0
  68. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.6.0.json +684 -0
  69. package/src/assets/adapters/clasificados/wrench-web-adapter.json +54 -0
  70. package/src/assets/adapters/facebook/wrench-web-adapter.json +750 -0
  71. package/src/assets/adapters/facebook/wrench-web-adapter.v1.0.0.json +706 -0
  72. package/src/assets/adapters/facebook/wrench-web-adapter.v1.1.0.json +703 -0
  73. package/src/assets/adapters/facebook/wrench-web-adapter.v1.2.0.json +750 -0
  74. package/src/assets/adapters/facebook-group/wrench-web-adapter.json +682 -0
  75. package/src/assets/adapters/facebook-group/wrench-web-adapter.v1.0.0.json +583 -0
  76. package/src/assets/adapters/facebook-group/wrench-web-adapter.v1.1.0.json +682 -0
  77. package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.json +437 -0
  78. package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.0.0.json +383 -0
  79. package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.1.0.json +437 -0
  80. package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.1.1.json +437 -0
  81. package/src/assets/adapters/facebook-page/wrench-web-adapter.json +880 -0
  82. package/src/assets/adapters/facebook-page/wrench-web-adapter.v1.0.0.json +740 -0
  83. package/src/assets/adapters/facebook-page/wrench-web-adapter.v1.1.0.json +880 -0
  84. package/src/assets/adapters/github/wrench-web-adapter.json +69 -0
  85. package/src/assets/adapters/github/wrench-web-adapter.v1.0.0.json +42 -0
  86. package/src/assets/adapters/github/wrench-web-adapter.v1.1.0.json +69 -0
  87. package/src/assets/adapters/gmail/wrench-adapter.json +161 -0
  88. package/src/assets/adapters/gmail/wrench-adapter.v1.2.0.json +157 -0
  89. package/src/assets/adapters/hacker-news/wrench-web-adapter.json +315 -0
  90. package/src/assets/adapters/hacker-news/wrench-web-adapter.v1.0.0.json +315 -0
  91. package/src/assets/adapters/imessage/wrench-web-adapter.json +236 -0
  92. package/src/assets/adapters/instagram/wrench-web-adapter.json +719 -0
  93. package/src/assets/adapters/instagram/wrench-web-adapter.v1.0.0.json +627 -0
  94. package/src/assets/adapters/instagram/wrench-web-adapter.v1.1.0.json +609 -0
  95. package/src/assets/adapters/instagram/wrench-web-adapter.v1.2.0.json +640 -0
  96. package/src/assets/adapters/instagram/wrench-web-adapter.v1.3.0.json +671 -0
  97. package/src/assets/adapters/instagram/wrench-web-adapter.v1.4.0.json +710 -0
  98. package/src/assets/adapters/instagram/wrench-web-adapter.v1.5.0.json +710 -0
  99. package/src/assets/adapters/instagram/wrench-web-adapter.v1.6.0.json +719 -0
  100. package/src/assets/adapters/instagram/wrench-web-adapter.v1.7.0.json +719 -0
  101. package/src/assets/adapters/linkedin/wrench-adapter.json +442 -0
  102. package/src/assets/adapters/linkedin/wrench-adapter.v0.4.0.json +124 -0
  103. package/src/assets/adapters/linkedin/wrench-adapter.v1.0.0.json +411 -0
  104. package/src/assets/adapters/linkedin/wrench-web-adapter.json +914 -0
  105. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.0.0.json +604 -0
  106. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.1.0.json +604 -0
  107. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.10.0.json +809 -0
  108. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.11.0.json +809 -0
  109. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.12.0.json +820 -0
  110. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.13.0.json +819 -0
  111. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.14.0.json +819 -0
  112. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.15.0.json +819 -0
  113. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.16.0.json +874 -0
  114. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.17.0.json +874 -0
  115. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.18.0.json +874 -0
  116. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.19.0.json +874 -0
  117. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.2.0.json +731 -0
  118. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.3.0.json +768 -0
  119. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.4.0.json +808 -0
  120. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.5.0.json +808 -0
  121. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.6.0.json +808 -0
  122. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.7.0.json +825 -0
  123. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.8.0.json +792 -0
  124. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.9.0.json +809 -0
  125. package/src/assets/adapters/reddit/wrench-web-adapter.json +855 -0
  126. package/src/assets/adapters/reddit/wrench-web-adapter.v1.0.0.json +577 -0
  127. package/src/assets/adapters/reddit/wrench-web-adapter.v1.1.0.json +604 -0
  128. package/src/assets/adapters/reddit/wrench-web-adapter.v1.10.0.json +712 -0
  129. package/src/assets/adapters/reddit/wrench-web-adapter.v1.11.0.json +712 -0
  130. package/src/assets/adapters/reddit/wrench-web-adapter.v1.12.0.json +712 -0
  131. package/src/assets/adapters/reddit/wrench-web-adapter.v1.2.0.json +653 -0
  132. package/src/assets/adapters/reddit/wrench-web-adapter.v1.3.0.json +712 -0
  133. package/src/assets/adapters/reddit/wrench-web-adapter.v1.4.0.json +713 -0
  134. package/src/assets/adapters/reddit/wrench-web-adapter.v1.5.0.json +712 -0
  135. package/src/assets/adapters/reddit/wrench-web-adapter.v1.6.0.json +713 -0
  136. package/src/assets/adapters/reddit/wrench-web-adapter.v1.7.0.json +713 -0
  137. package/src/assets/adapters/reddit/wrench-web-adapter.v1.8.0.json +713 -0
  138. package/src/assets/adapters/reddit/wrench-web-adapter.v1.9.0.json +713 -0
  139. package/src/assets/adapters/substack/wrench-web-adapter.json +936 -0
  140. package/src/assets/adapters/substack/wrench-web-adapter.v1.0.0.json +817 -0
  141. package/src/assets/adapters/substack/wrench-web-adapter.v1.1.0.json +812 -0
  142. package/src/assets/adapters/substack/wrench-web-adapter.v1.2.0.json +812 -0
  143. package/src/assets/adapters/substack/wrench-web-adapter.v1.3.0.json +902 -0
  144. package/src/assets/adapters/substack/wrench-web-adapter.v1.4.0.json +936 -0
  145. package/src/assets/adapters/substack/wrench-web-adapter.v1.5.0.json +936 -0
  146. package/src/assets/adapters/substack/wrench-web-adapter.v1.6.0.json +936 -0
  147. package/src/assets/adapters/threads/wrench-web-adapter.json +692 -0
  148. package/src/assets/adapters/threads/wrench-web-adapter.v1.0.0.json +629 -0
  149. package/src/assets/adapters/threads/wrench-web-adapter.v1.1.0.json +623 -0
  150. package/src/assets/adapters/threads/wrench-web-adapter.v1.2.0.json +622 -0
  151. package/src/assets/adapters/threads/wrench-web-adapter.v1.3.0.json +622 -0
  152. package/src/assets/adapters/threads/wrench-web-adapter.v1.4.0.json +622 -0
  153. package/src/assets/adapters/threads/wrench-web-adapter.v1.5.0.json +699 -0
  154. package/src/assets/adapters/threads/wrench-web-adapter.v1.6.0.json +693 -0
  155. package/src/assets/adapters/threads/wrench-web-adapter.v1.7.0.json +692 -0
  156. package/src/assets/adapters/tiktok/wrench-web-adapter.json +762 -0
  157. package/src/assets/adapters/tiktok/wrench-web-adapter.v1.0.0.json +681 -0
  158. package/src/assets/adapters/tiktok/wrench-web-adapter.v1.1.0.json +708 -0
  159. package/src/assets/adapters/tiktok/wrench-web-adapter.v1.2.0.json +762 -0
  160. package/src/assets/adapters/tiktok/wrench-web-adapter.v1.3.0.json +762 -0
  161. package/src/assets/adapters/twitch/wrench-web-adapter.json +42 -0
  162. package/src/assets/adapters/twitch/wrench-web-adapter.v1.0.0.json +42 -0
  163. package/src/assets/adapters/whatsapp/wrench-web-adapter.json +400 -0
  164. package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.0.0.json +355 -0
  165. package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.1.0.json +386 -0
  166. package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.2.0.json +386 -0
  167. package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.3.0.json +400 -0
  168. package/src/assets/adapters/x/wrench-adapter.json +749 -0
  169. package/src/assets/adapters/x/wrench-adapter.v1.0.0.json +700 -0
  170. package/src/assets/adapters/x/wrench-adapter.v1.1.0.json +707 -0
  171. package/src/assets/adapters/x/wrench-web-adapter.json +712 -0
  172. package/src/assets/adapters/x/wrench-web-adapter.v1.1.0.json +579 -0
  173. package/src/assets/adapters/x/wrench-web-adapter.v1.10.0.json +685 -0
  174. package/src/assets/adapters/x/wrench-web-adapter.v1.11.0.json +712 -0
  175. package/src/assets/adapters/x/wrench-web-adapter.v1.12.0.json +712 -0
  176. package/src/assets/adapters/x/wrench-web-adapter.v1.13.0.json +712 -0
  177. package/src/assets/adapters/x/wrench-web-adapter.v1.2.0.json +578 -0
  178. package/src/assets/adapters/x/wrench-web-adapter.v1.3.0.json +610 -0
  179. package/src/assets/adapters/x/wrench-web-adapter.v1.4.0.json +617 -0
  180. package/src/assets/adapters/x/wrench-web-adapter.v1.5.0.json +634 -0
  181. package/src/assets/adapters/x/wrench-web-adapter.v1.6.0.json +632 -0
  182. package/src/assets/adapters/x/wrench-web-adapter.v1.7.0.json +649 -0
  183. package/src/assets/adapters/x/wrench-web-adapter.v1.8.0.json +649 -0
  184. package/src/assets/adapters/x/wrench-web-adapter.v1.9.0.json +683 -0
  185. package/src/assets/adapters/youtube/wrench-web-adapter.json +561 -0
  186. package/src/assets/adapters/youtube/wrench-web-adapter.v1.0.0.json +465 -0
  187. package/src/assets/adapters/youtube/wrench-web-adapter.v1.1.0.json +519 -0
  188. package/src/assets/adapters/youtube/wrench-web-adapter.v1.2.0.json +561 -0
  189. package/src/assets/adapters/youtube/wrench-web-adapter.v1.3.0.json +561 -0
  190. package/src/assets/code-owned-provider-template/plugin.test.ts.template +54 -0
  191. package/src/assets/code-owned-provider-template/plugin.ts.template +102 -0
  192. package/src/assets/code-owned-provider-template/runtime.internal.test.ts.template +44 -0
  193. package/src/assets/code-owned-provider-template/runtime.ts.template +59 -0
  194. package/src/assets/code-owned-provider-template/wrench-adapter.json.template +33 -0
  195. package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
  196. package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
  197. package/src/assets/fonts/nebula-sans/PROVENANCE.md +14 -0
  198. package/src/assets.d.ts +4 -0
  199. package/src/auth.ts +1157 -0
  200. package/src/beeper-client-types.ts +169 -0
  201. package/src/beeper-client.ts +250 -0
  202. package/src/beeper-contact-interactions-cli.ts +180 -0
  203. package/src/beeper-contact-interactions.ts +1612 -0
  204. package/src/beeper-message-bundle-v1.ts +257 -0
  205. package/src/beeper-message-like-me-cli.ts +84 -0
  206. package/src/beeper-message-like-me-export.ts +2274 -0
  207. package/src/beeper-message-like-me-recovery.ts +931 -0
  208. package/src/beeper-message-like-me-source.ts +4034 -0
  209. package/src/browser-admission.ts +928 -0
  210. package/src/browser-snapshots.ts +260 -0
  211. package/src/browser.ts +3873 -0
  212. package/src/canonical-json.ts +60 -0
  213. package/src/catalog-cli.ts +638 -0
  214. package/src/cli.ts +208 -0
  215. package/src/client-types.ts +301 -0
  216. package/src/client.ts +2726 -0
  217. package/src/confirmed-write-failure.ts +44 -0
  218. package/src/confirmed-write-model.ts +72 -0
  219. package/src/confirmed-write-platform.ts +1055 -0
  220. package/src/confirmed-write-program.ts +224 -0
  221. package/src/confirmed-write-runtime.ts +16 -0
  222. package/src/cursor-token.ts +228 -0
  223. package/src/derivation-dnr-readiness.ts +367 -0
  224. package/src/derivation-file-chooser.ts +384 -0
  225. package/src/derivation-network-boundary.ts +835 -0
  226. package/src/derivation-network-guard.ts +782 -0
  227. package/src/derivation-network-proxy-helper.ts +440 -0
  228. package/src/derivation-network-proxy.ts +385 -0
  229. package/src/derive-command-helper.ts +693 -0
  230. package/src/derive-fixtures.ts +343 -0
  231. package/src/derive-review.ts +980 -0
  232. package/src/derive.ts +4754 -0
  233. package/src/fixtures/beeper-message-like-me-v1/accounts.ndjson +2 -0
  234. package/src/fixtures/beeper-message-like-me-v1/conversations.ndjson +1 -0
  235. package/src/fixtures/beeper-message-like-me-v1/manifest.json +1 -0
  236. package/src/fixtures/beeper-message-like-me-v1/messages.ndjson +2 -0
  237. package/src/fixtures/beeper-message-like-me-v1/participants.ndjson +3 -0
  238. package/src/fixtures/beeper-message-like-me-v1/reactions.ndjson +1 -0
  239. package/src/fixtures/beeper-message-like-me-v1/tombstones.ndjson +1 -0
  240. package/src/ghostget.ts +3672 -0
  241. package/src/gmail-capture.ts +1244 -0
  242. package/src/har-internal.ts +1242 -0
  243. package/src/har.ts +743 -0
  244. package/src/index.ts +218 -0
  245. package/src/invocation-read-platform.ts +55 -0
  246. package/src/invocation-read-program.ts +93 -0
  247. package/src/invocation-read-runtime.ts +11 -0
  248. package/src/linked-device-lifecycle-admission.ts +450 -0
  249. package/src/linked-device-lifecycle-journal.ts +1560 -0
  250. package/src/linked-device-lifecycle-runtime.ts +1602 -0
  251. package/src/local-cli-admission.ts +135 -0
  252. package/src/local-cli-contracts.ts +271 -0
  253. package/src/local-cli-execution.ts +98 -0
  254. package/src/local-cli-surface-contract.ts +1510 -0
  255. package/src/local-cli-tool-identity.ts +336 -0
  256. package/src/media/archive.ts +2325 -0
  257. package/src/media/args.ts +303 -0
  258. package/src/media/cli.ts +287 -0
  259. package/src/media/doctor.ts +475 -0
  260. package/src/media/ffmpeg.ts +1330 -0
  261. package/src/media/http-capture.ts +711 -0
  262. package/src/media/http-probe.ts +593 -0
  263. package/src/media/http.ts +387 -0
  264. package/src/media/index.ts +10 -0
  265. package/src/media/local-transcription.ts +613 -0
  266. package/src/media/lock.ts +321 -0
  267. package/src/media/manifest.ts +1712 -0
  268. package/src/media/metadata.ts +906 -0
  269. package/src/media/process.ts +723 -0
  270. package/src/media/revision.ts +166 -0
  271. package/src/media/runtime-closure.ts +1063 -0
  272. package/src/media/source-router.ts +187 -0
  273. package/src/media/transcriber-config.ts +1122 -0
  274. package/src/media/transcript-persistence-model.ts +15 -0
  275. package/src/media/transcript-persistence-platform.ts +89 -0
  276. package/src/media/transcript-persistence-program.ts +39 -0
  277. package/src/media/transcript-persistence-runtime.ts +24 -0
  278. package/src/media/transcript.ts +616 -0
  279. package/src/media/utf8-order.ts +30 -0
  280. package/src/media/whisper-cpp.ts +464 -0
  281. package/src/media/whisper-language.ts +58 -0
  282. package/src/media/yt-dlp.ts +439 -0
  283. package/src/message-like-me-agentic-messaging.ts +882 -0
  284. package/src/messaging-action-store.ts +793 -0
  285. package/src/messaging-runtime.ts +2136 -0
  286. package/src/messaging-store.ts +539 -0
  287. package/src/messaging-types.ts +1663 -0
  288. package/src/messaging.ts +334 -0
  289. package/src/model.ts +2671 -0
  290. package/src/oauth-google.ts +888 -0
  291. package/src/omni-client-types.ts +306 -0
  292. package/src/omni-client.ts +2225 -0
  293. package/src/omni-limits.ts +34 -0
  294. package/src/omni-model.ts +1614 -0
  295. package/src/omni-request.ts +379 -0
  296. package/src/omni-runtime.ts +1632 -0
  297. package/src/operation-deadline.ts +189 -0
  298. package/src/path-helper.ts +1656 -0
  299. package/src/pinned-https.ts +194 -0
  300. package/src/plan-assets.ts +832 -0
  301. package/src/platform-catalog.ts +1832 -0
  302. package/src/plugins/beeper-linked-device/plugin.ts +310 -0
  303. package/src/plugins/bluesky-web/plugin.ts +178 -0
  304. package/src/plugins/clasificados-web/plugin.ts +66 -0
  305. package/src/plugins/github-web/plugin.ts +80 -0
  306. package/src/plugins/gmail-official/plugin.ts +110 -0
  307. package/src/plugins/hacker-news-web/plugin.ts +52 -0
  308. package/src/plugins/imessage-direct/plugin.ts +195 -0
  309. package/src/plugins/imessage-direct/vendor/0001-fix-keep-AppleScript-send-payloads-out-of-child-argv.patch +1430 -0
  310. package/src/plugins/imessage-direct/vendor/0002-feat-rpc-add-exact-chat-lookup.patch +225 -0
  311. package/src/plugins/imessage-direct/vendor/provenance.json +80 -0
  312. package/src/plugins/linkedin-official/plugin.ts +84 -0
  313. package/src/plugins/linkedin-web/plugin.ts +412 -0
  314. package/src/plugins/meta-web/plugin.ts +317 -0
  315. package/src/plugins/reddit-web/flair.ts +492 -0
  316. package/src/plugins/reddit-web/plugin.ts +477 -0
  317. package/src/plugins/substack-web/plugin.ts +124 -0
  318. package/src/plugins/tiktok-web/plugin.ts +67 -0
  319. package/src/plugins/twitch-web/plugin.ts +54 -0
  320. package/src/plugins/whatsapp-linked-device/plugin.ts +105 -0
  321. package/src/plugins/x-official/plugin.ts +64 -0
  322. package/src/plugins/x-web/plugin.ts +488 -0
  323. package/src/plugins/youtube-web/plugin.ts +101 -0
  324. package/src/portable-run-recovery.ts +466 -0
  325. package/src/process-identity.ts +501 -0
  326. package/src/profile-clone-helper.ts +104 -0
  327. package/src/provider-catalog-views.ts +51 -0
  328. package/src/provider-context.ts +69 -0
  329. package/src/provider-contract-definitions-x.ts +45 -0
  330. package/src/provider-contract-definitions.ts +948 -0
  331. package/src/provider-contract-input-gmail.ts +176 -0
  332. package/src/provider-contract-input-linkedin.ts +77 -0
  333. package/src/provider-contract-input-x.ts +304 -0
  334. package/src/provider-contract-planning.ts +23 -0
  335. package/src/provider-contract-semantic-identity.ts +54 -0
  336. package/src/provider-contracts.ts +251 -0
  337. package/src/provider-http.ts +723 -0
  338. package/src/provider-plugin-auth.ts +36 -0
  339. package/src/provider-plugin-builtins.ts +229 -0
  340. package/src/provider-plugin-cleanup-barrier.ts +229 -0
  341. package/src/provider-plugin-cleanup-execution.ts +79 -0
  342. package/src/provider-plugin-cleanup-resource.ts +470 -0
  343. package/src/provider-plugin-contract-identity.ts +707 -0
  344. package/src/provider-plugin-host.ts +1972 -0
  345. package/src/provider-plugin-identifiers.ts +60 -0
  346. package/src/provider-plugin-invocation-lease.ts +889 -0
  347. package/src/provider-plugin-lifecycle-kernel.ts +566 -0
  348. package/src/provider-plugin-lifecycle.ts +1455 -0
  349. package/src/provider-plugin-module-analysis.ts +336 -0
  350. package/src/provider-plugin-package.ts +2530 -0
  351. package/src/provider-plugin-portable-authority.ts +106 -0
  352. package/src/provider-plugin-portable-catalog.ts +94 -0
  353. package/src/provider-plugin-portable-identity.ts +315 -0
  354. package/src/provider-plugin-portable-runtime.ts +2057 -0
  355. package/src/provider-plugin-protocol.ts +1625 -0
  356. package/src/provider-plugin-registry.ts +3342 -0
  357. package/src/provider-plugin-store.ts +2155 -0
  358. package/src/provider-plugin-test-fixture.ts +5 -0
  359. package/src/provider-plugin.ts +4907 -0
  360. package/src/provider-plugins.generated.ts +43 -0
  361. package/src/provider-plugins.ts +8 -0
  362. package/src/provider-subject.ts +41 -0
  363. package/src/provider.ts +315 -0
  364. package/src/providers/beeper-local-runtime.ts +5426 -0
  365. package/src/providers/beeper-local.ts +2739 -0
  366. package/src/providers/beeper-messaging.ts +462 -0
  367. package/src/providers/beeper-omni.ts +1159 -0
  368. package/src/providers/bluesky-web-runtime.ts +2895 -0
  369. package/src/providers/bluesky-web.ts +1614 -0
  370. package/src/providers/clasificados-web-runtime.ts +255 -0
  371. package/src/providers/clasificados-web.ts +503 -0
  372. package/src/providers/contact-projection.ts +301 -0
  373. package/src/providers/github-read-model.ts +94 -0
  374. package/src/providers/github-read-platform.ts +165 -0
  375. package/src/providers/github-read-program.ts +97 -0
  376. package/src/providers/github-web-runtime.ts +320 -0
  377. package/src/providers/github-web.ts +403 -0
  378. package/src/providers/gmail-api.ts +2834 -0
  379. package/src/providers/gmail-omni.ts +830 -0
  380. package/src/providers/gmail.ts +1130 -0
  381. package/src/providers/hacker-news-web-runtime.ts +220 -0
  382. package/src/providers/hacker-news-web.ts +809 -0
  383. package/src/providers/imessage-direct-install.ts +354 -0
  384. package/src/providers/imessage-direct-messaging.ts +532 -0
  385. package/src/providers/imessage-direct-omni.ts +400 -0
  386. package/src/providers/imessage-direct-runtime.ts +1498 -0
  387. package/src/providers/imessage-direct.ts +351 -0
  388. package/src/providers/instagram-video-foundations.ts +913 -0
  389. package/src/providers/instagram-web-profile-browser.ts +600 -0
  390. package/src/providers/iso-bmff.ts +338 -0
  391. package/src/providers/linkedin-company-platform.ts +42 -0
  392. package/src/providers/linkedin-company-program.ts +88 -0
  393. package/src/providers/linkedin-contact-failure.ts +84 -0
  394. package/src/providers/linkedin-contact-platform.ts +45 -0
  395. package/src/providers/linkedin-contact-program.ts +91 -0
  396. package/src/providers/linkedin-profile-activity-failure.ts +76 -0
  397. package/src/providers/linkedin-profile-activity-platform.ts +41 -0
  398. package/src/providers/linkedin-profile-activity-program.ts +67 -0
  399. package/src/providers/linkedin-read-failure.ts +52 -0
  400. package/src/providers/linkedin-self-platform.ts +53 -0
  401. package/src/providers/linkedin-self-program.ts +122 -0
  402. package/src/providers/linkedin-web-article-browser.ts +794 -0
  403. package/src/providers/linkedin-web-bootstrap.ts +146 -0
  404. package/src/providers/linkedin-web-contact.ts +830 -0
  405. package/src/providers/linkedin-web-feed-browser.ts +832 -0
  406. package/src/providers/linkedin-web-feed.ts +864 -0
  407. package/src/providers/linkedin-web-post-browser.ts +653 -0
  408. package/src/providers/linkedin-web-profile-browser.ts +683 -0
  409. package/src/providers/linkedin-web-runtime.ts +2388 -0
  410. package/src/providers/linkedin-web.ts +3305 -0
  411. package/src/providers/linkedin.ts +1885 -0
  412. package/src/providers/meta-bootstrap.ts +1043 -0
  413. package/src/providers/meta-facebook-group.ts +690 -0
  414. package/src/providers/meta-marketplace-relay.ts +747 -0
  415. package/src/providers/meta-omni.ts +373 -0
  416. package/src/providers/meta-relay-bundle.ts +1049 -0
  417. package/src/providers/meta-web-descriptors.ts +1740 -0
  418. package/src/providers/meta-web-runtime.ts +3388 -0
  419. package/src/providers/meta-web.ts +2931 -0
  420. package/src/providers/read-failure.ts +139 -0
  421. package/src/providers/reddit-omni.ts +462 -0
  422. package/src/providers/reddit-web-runtime.ts +1929 -0
  423. package/src/providers/reddit-web.ts +1611 -0
  424. package/src/providers/rental-listings.ts +460 -0
  425. package/src/providers/substack-omni.ts +406 -0
  426. package/src/providers/substack-video-mp4.ts +33 -0
  427. package/src/providers/substack-web-runtime.ts +2812 -0
  428. package/src/providers/substack-web.ts +1502 -0
  429. package/src/providers/tiktok-video-mp4.ts +33 -0
  430. package/src/providers/tiktok-web-runtime.ts +770 -0
  431. package/src/providers/tiktok-web.ts +2786 -0
  432. package/src/providers/twitch-web-runtime.ts +226 -0
  433. package/src/providers/twitch-web.ts +274 -0
  434. package/src/providers/whatsapp-account-identity.ts +55 -0
  435. package/src/providers/whatsapp-contact-projection-helper.ts +874 -0
  436. package/src/providers/whatsapp-contact-projection-protocol.ts +403 -0
  437. package/src/providers/whatsapp-interaction-projection-helper.ts +1452 -0
  438. package/src/providers/whatsapp-interaction-projection-protocol.ts +462 -0
  439. package/src/providers/whatsapp-message-export-projection-protocol.ts +532 -0
  440. package/src/providers/whatsapp-messaging.ts +132 -0
  441. package/src/providers/whatsapp-omni.ts +586 -0
  442. package/src/providers/whatsapp-web-runtime.ts +3108 -0
  443. package/src/providers/whatsapp-web.ts +1037 -0
  444. package/src/providers/x-image-provenance.ts +523 -0
  445. package/src/providers/x-made-with-ai.ts +106 -0
  446. package/src/providers/x-transaction-id.ts +413 -0
  447. package/src/providers/x-web-runtime.ts +3485 -0
  448. package/src/providers/x-web.ts +2332 -0
  449. package/src/providers/x.ts +1889 -0
  450. package/src/providers/youtube-web-runtime.ts +1400 -0
  451. package/src/providers/youtube-web.ts +1221 -0
  452. package/src/read-admission-runtime.ts +91 -0
  453. package/src/read-client.ts +521 -0
  454. package/src/read-effect-platform.ts +7 -0
  455. package/src/read-effect-runtime.ts +14 -0
  456. package/src/read-effect.ts +52 -0
  457. package/src/read-projection-admission.ts +866 -0
  458. package/src/read-projections.ts +3151 -0
  459. package/src/recovery.ts +1492 -0
  460. package/src/reviewed-template.ts +146 -0
  461. package/src/run-journal.ts +1272 -0
  462. package/src/runtime.ts +5116 -0
  463. package/src/scripts/generate-provider-plugin-catalog.ts +121 -0
  464. package/src/scripts/install-whatsapp-protocol.sh +232 -0
  465. package/src/scripts/recover-install-stages.ts +1491 -0
  466. package/src/scripts/resolve-state-home.ts +30 -0
  467. package/src/scripts/scaffold-web-provider.ts +973 -0
  468. package/src/scripts/sync-bundled-adapters.ts +695 -0
  469. package/src/session-secrets.ts +1183 -0
  470. package/src/state-helper.bunfig.toml +2 -0
  471. package/src/state-helper.ts +2914 -0
  472. package/src/storage.ts +3842 -0
  473. package/src/transport-policy.ts +2 -0
  474. package/src/usage.ts +182 -0
  475. package/src/version.ts +2 -0
  476. package/src/web-session-authentication-policy.ts +136 -0
  477. package/src/web-session-cleanup-admission.ts +2344 -0
  478. package/src/web-session-cleanup-join.ts +99 -0
  479. package/src/web-session-client.ts +996 -0
  480. package/src/web-session-contract-definitions.ts +820 -0
  481. package/src/web-session-contract-planning.ts +42 -0
  482. package/src/web-session-contracts.ts +228 -0
  483. package/src/web-session-cookies.ts +500 -0
  484. package/src/web-session-execution.ts +385 -0
  485. package/src/web-session-http.ts +373 -0
  486. package/src/web-session-read-errors.ts +19 -0
  487. package/src/web-session-read-runtime.ts +124 -0
  488. package/src/web-session-recovery.ts +818 -0
  489. package/src/web-session-sites.ts +58 -0
  490. package/src/web-session-template.ts +994 -0
  491. package/src/web-session.ts +93 -0
  492. package/src/whatsapp-client-binding.ts +21 -0
  493. package/src/whatsapp-client-types.ts +75 -0
  494. package/src/whatsapp-client.ts +395 -0
  495. package/src/whatsapp-export-coordinate.ts +17 -0
  496. package/src/whatsapp-message-bundle-v2.ts +195 -0
  497. package/src/whatsapp-message-like-me-cli.ts +195 -0
  498. package/src/whatsapp-message-like-me-export.ts +1072 -0
  499. package/src/whatsapp-message-like-me-source.ts +1012 -0
  500. package/tsconfig.json +67 -0
@@ -0,0 +1,793 @@
1
+ import { join } from "node:path";
2
+
3
+ import { canonicalJson, sha256 } from "./canonical-json";
4
+ import {
5
+ MESSAGING_RECEIPT_BINDING_CONTRACT_HASH,
6
+ MESSAGING_RECEIPT_BINDING_CONTRACT_ID,
7
+ MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH,
8
+ MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID,
9
+ parseMessagingReceiptBindingV1,
10
+ parseMessagingReceiptBindingV2,
11
+ type MessagingPartJournalStateV1,
12
+ type MessagingPrivateProviderOutcomeV1,
13
+ type MessagingReceiptBinding,
14
+ type MessagingRunReceipt,
15
+ type MessagingRunV1,
16
+ } from "./messaging-types";
17
+ import type { ProviderPluginMessagingExpectedOwnPrefixV1 } from "./provider-plugin";
18
+ import type { MessagingCompositeInvocationPlanV1 } from "./runtime";
19
+ import {
20
+ openAuthenticatedPrivatePayload,
21
+ sealAuthenticatedPrivatePayload,
22
+ } from "./read-projections";
23
+ import {
24
+ createPrivateJsonIfAbsent,
25
+ ensurePrivateStateDirectory,
26
+ readPrivateStateFileIfPresent,
27
+ ghostgetStateHome,
28
+ writePrivateJsonIfUnchanged,
29
+ } from "./storage";
30
+
31
+ type Environment = Readonly<Record<string, string | undefined>>;
32
+
33
+ const MAX_PLAINTEXT_BYTES = 1024 * 1024;
34
+ const MAX_ENCRYPTED_BYTES = 2 * 1024 * 1024;
35
+
36
+ export type MessagingRunSnapshotV1 = {
37
+ readonly run: MessagingRunV1;
38
+ readonly contentSha256: string;
39
+ };
40
+
41
+ export type MessagingRunEventV1 =
42
+ | {
43
+ readonly type: "claimed";
44
+ readonly index: number;
45
+ readonly observedAcceptedPrefixCount: number;
46
+ readonly at: string;
47
+ }
48
+ | { readonly type: "dispatching"; readonly index: number; readonly at: string }
49
+ | {
50
+ readonly type: "accepted";
51
+ readonly index: number;
52
+ readonly providerMessageId: string;
53
+ readonly providerRevision: string | null;
54
+ readonly at: string;
55
+ }
56
+ | {
57
+ readonly type: "categorical-stop";
58
+ readonly index: number;
59
+ readonly partState: "failed-before-dispatch" | "failed-permanent";
60
+ readonly reason:
61
+ | "context-drift"
62
+ | "prefix-freshness-unproven"
63
+ | "provider-failed-before-dispatch"
64
+ | "journal-recovery-required";
65
+ readonly at: string;
66
+ }
67
+ | {
68
+ readonly type: "indeterminate";
69
+ readonly index: number;
70
+ readonly reason: "provider-result-indeterminate";
71
+ readonly privateProviderOutcome: MessagingPrivateProviderOutcomeV1 | null;
72
+ readonly at: string;
73
+ }
74
+ | {
75
+ readonly type: "indeterminate";
76
+ readonly index: number;
77
+ readonly reason: "journal-recovery-required";
78
+ readonly at: string;
79
+ };
80
+
81
+ function root(environment: Environment): string {
82
+ return join(ghostgetStateHome(environment), "messaging", "runs");
83
+ }
84
+
85
+ function path(runId: string, environment: Environment): string {
86
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u.test(runId)) {
87
+ throw new Error("messaging run ID is malformed");
88
+ }
89
+ return join(root(environment), `${runId}.json`);
90
+ }
91
+
92
+ function domain(runId: string): string {
93
+ return `wrench-messaging-run-v1:${runId}`;
94
+ }
95
+
96
+ function timestamp(value: string): string {
97
+ if (
98
+ !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(value)
99
+ || !Number.isFinite(Date.parse(value))
100
+ || new Date(value).toISOString() !== value
101
+ ) {
102
+ throw new Error("messaging run timestamp is malformed");
103
+ }
104
+ return value;
105
+ }
106
+
107
+ function record(value: unknown, label: string): Record<string, unknown> {
108
+ if (
109
+ typeof value !== "object"
110
+ || value === null
111
+ || Array.isArray(value)
112
+ || Object.getPrototypeOf(value) !== Object.prototype
113
+ ) throw new Error(`${label} is malformed`);
114
+ return value as Record<string, unknown>;
115
+ }
116
+
117
+ function exactKeys(value: Record<string, unknown>, keys: readonly string[], label: string): void {
118
+ const actual = Object.keys(value).sort();
119
+ const expected = [...keys].sort();
120
+ if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
121
+ throw new Error(`${label} has unsupported fields`);
122
+ }
123
+ }
124
+
125
+ function digest(value: unknown, label: string): string {
126
+ if (typeof value !== "string" || !/^[a-f0-9]{64}$/u.test(value)) {
127
+ throw new Error(`${label} is malformed`);
128
+ }
129
+ return value;
130
+ }
131
+
132
+ function boundedText(value: unknown, label: string, maximum: number): string {
133
+ if (
134
+ typeof value !== "string"
135
+ || value.length < 1
136
+ || Buffer.byteLength(value, "utf8") > maximum
137
+ || value.includes("\0")
138
+ ) throw new Error(`${label} is malformed`);
139
+ return value;
140
+ }
141
+
142
+ function parsePrivateProviderOutcome(
143
+ value: unknown,
144
+ ): MessagingPrivateProviderOutcomeV1 {
145
+ const source = record(value, "messaging private provider outcome");
146
+ exactKeys(source, [
147
+ "schemaVersion", "messagingContractId", "code",
148
+ ], "messaging private provider outcome");
149
+ const messagingContractId = boundedText(
150
+ source.messagingContractId,
151
+ "messaging private provider outcome contract ID",
152
+ 256,
153
+ );
154
+ const code = boundedText(
155
+ source.code,
156
+ "messaging private provider outcome code",
157
+ 64,
158
+ );
159
+ if (
160
+ source.schemaVersion !== 1
161
+ || !/^[a-z][a-z0-9.-]{0,255}$/u.test(messagingContractId)
162
+ || !/^[a-z][a-z0-9_-]{0,63}$/u.test(code)
163
+ ) throw new Error("messaging private provider outcome is malformed");
164
+ return Object.freeze({ schemaVersion: 1, messagingContractId, code });
165
+ }
166
+
167
+ function denseArray(value: unknown, label: string, maximum: number): readonly unknown[] {
168
+ if (
169
+ !Array.isArray(value)
170
+ || Object.getPrototypeOf(value) !== Array.prototype
171
+ || value.length < 1
172
+ || value.length > maximum
173
+ ) throw new Error(`${label} is malformed`);
174
+ const expected = new Set<PropertyKey>([
175
+ "length",
176
+ ...Array.from({ length: value.length }, (_unused, index) => String(index)),
177
+ ]);
178
+ const keys = Reflect.ownKeys(value);
179
+ if (keys.length !== expected.size || keys.some((key) => !expected.has(key))) {
180
+ throw new Error(`${label} must be a dense array without extra fields`);
181
+ }
182
+ return value;
183
+ }
184
+
185
+ function assertRun(run: MessagingRunV1): void {
186
+ const acceptedProviderMessageIds = run.parts
187
+ .slice(0, run.provenPartCount)
188
+ .map((part) => part.providerMessageId);
189
+ if (
190
+ run.schemaVersion !== 1
191
+ || run.format !== "wrench.messaging-run"
192
+ || run.parts.length < 1
193
+ || run.parts.length > 8
194
+ || run.partCount !== run.parts.length
195
+ || run.provenPartCount < 0
196
+ || run.provenPartCount > run.partCount
197
+ || !Number.isSafeInteger(run.observedAcceptedPrefixCount)
198
+ || run.observedAcceptedPrefixCount < 0
199
+ || run.observedAcceptedPrefixCount > run.provenPartCount
200
+ || run.parts.slice(0, run.provenPartCount).some((part) => part.state !== "accepted")
201
+ || acceptedProviderMessageIds.some((providerMessageId) => providerMessageId === null)
202
+ || new Set(acceptedProviderMessageIds).size !== acceptedProviderMessageIds.length
203
+ || run.parts.slice(run.provenPartCount).some((part, offset) =>
204
+ offset > 0 && part.state !== "unattempted")
205
+ ) throw new Error("messaging run violates its ordered-prefix invariant");
206
+ const active = run.parts[run.provenPartCount];
207
+ if (
208
+ run.privateProviderOutcome !== null
209
+ && (
210
+ run.state !== "indeterminate"
211
+ || run.terminalReason !== "provider-result-indeterminate"
212
+ || run.possibleSubmittedPartIndex !== run.provenPartCount
213
+ || active?.state !== "indeterminate"
214
+ )
215
+ ) throw new Error("messaging run private provider outcome is contradictory");
216
+ if (run.state === "pending") {
217
+ if (
218
+ run.provenPartCount === run.partCount
219
+ || run.possibleSubmittedPartIndex !== null
220
+ || run.terminalReason !== null
221
+ || active === undefined
222
+ || !["unattempted", "claimed", "dispatching"].includes(active.state)
223
+ ) throw new Error("pending messaging run has contradictory state");
224
+ return;
225
+ }
226
+ if (run.state === "submitted") {
227
+ if (
228
+ run.provenPartCount !== run.partCount
229
+ || run.possibleSubmittedPartIndex !== null
230
+ || run.terminalReason !== null
231
+ ) throw new Error("submitted messaging run has contradictory state");
232
+ return;
233
+ }
234
+ if (run.state === "failed") {
235
+ if (
236
+ run.provenPartCount !== 0
237
+ || run.possibleSubmittedPartIndex !== null
238
+ || run.terminalReason !== "context-drift"
239
+ && run.terminalReason !== "prefix-freshness-unproven"
240
+ && run.terminalReason !== "provider-failed-before-dispatch"
241
+ && run.terminalReason !== "journal-recovery-required"
242
+ || active === undefined
243
+ || active.state !== "failed-before-dispatch" && active.state !== "failed-permanent"
244
+ ) throw new Error("failed messaging run has contradictory state");
245
+ return;
246
+ }
247
+ if (run.state === "partial") {
248
+ if (
249
+ run.provenPartCount < 1
250
+ || run.provenPartCount >= run.partCount
251
+ || run.possibleSubmittedPartIndex !== null
252
+ || run.terminalReason !== "context-drift"
253
+ && run.terminalReason !== "prefix-freshness-unproven"
254
+ && run.terminalReason !== "provider-failed-before-dispatch"
255
+ && run.terminalReason !== "journal-recovery-required"
256
+ || active === undefined
257
+ || active.state !== "failed-before-dispatch" && active.state !== "failed-permanent"
258
+ ) throw new Error("partial messaging run has contradictory state");
259
+ return;
260
+ }
261
+ if (
262
+ run.state !== "indeterminate"
263
+ || run.provenPartCount >= run.partCount
264
+ || run.possibleSubmittedPartIndex !== run.provenPartCount
265
+ || run.terminalReason !== "provider-result-indeterminate"
266
+ && run.terminalReason !== "journal-recovery-required"
267
+ || active?.state !== "indeterminate"
268
+ ) throw new Error("indeterminate messaging run has contradictory state");
269
+ }
270
+
271
+ function parseRun(value: unknown): MessagingRunV1 {
272
+ const source = record(value, "messaging run");
273
+ const hasObservedAcceptedPrefixCount = Object.hasOwn(
274
+ source,
275
+ "observedAcceptedPrefixCount",
276
+ );
277
+ const hasPrivateProviderOutcome = Object.hasOwn(
278
+ source,
279
+ "privateProviderOutcome",
280
+ );
281
+ const hasContextBinding = Object.hasOwn(source, "contextBindingSha256");
282
+ const hasSourceCoordinate = Object.hasOwn(
283
+ source,
284
+ "sourceConversationCoordinateSha256",
285
+ );
286
+ if (hasContextBinding !== hasSourceCoordinate) {
287
+ throw new Error("messaging run has partial context evidence");
288
+ }
289
+ const hasCurrentContextEvidence = hasContextBinding
290
+ && source.contextBindingSha256 !== null;
291
+ if (
292
+ hasContextBinding
293
+ && ((source.contextBindingSha256 === null)
294
+ !== (source.sourceConversationCoordinateSha256 === null))
295
+ ) throw new Error("messaging run has partial context evidence");
296
+ if (!hasObservedAcceptedPrefixCount && hasPrivateProviderOutcome) {
297
+ throw new Error("messaging run has unsupported fields");
298
+ }
299
+ exactKeys(source, [
300
+ "schemaVersion", "format", "runId", "planDigest", "routeRef", "contextRef",
301
+ "clientIntentSha256",
302
+ ...(hasContextBinding
303
+ ? ["contextBindingSha256", "sourceConversationCoordinateSha256"]
304
+ : []),
305
+ "turnDigest", "previewDigest",
306
+ "state", "partCount",
307
+ "provenPartCount",
308
+ ...(hasObservedAcceptedPrefixCount ? ["observedAcceptedPrefixCount"] : []),
309
+ "possibleSubmittedPartIndex",
310
+ "terminalReason", "parts",
311
+ ...(hasPrivateProviderOutcome ? ["privateProviderOutcome"] : []),
312
+ "startedAt", "recordedAt",
313
+ ], "messaging run");
314
+ if (
315
+ source.schemaVersion !== 1
316
+ || source.format !== "wrench.messaging-run"
317
+ || typeof source.runId !== "string"
318
+ || !/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u.test(source.runId)
319
+ || typeof source.routeRef !== "string"
320
+ || !/^wmroute_[A-Za-z0-9_-]{22}$/u.test(source.routeRef)
321
+ || typeof source.contextRef !== "string"
322
+ || !/^wmcontext_[A-Za-z0-9_-]{22}$/u.test(source.contextRef)
323
+ || source.state !== "pending"
324
+ && source.state !== "submitted"
325
+ && source.state !== "failed"
326
+ && source.state !== "partial"
327
+ && source.state !== "indeterminate"
328
+ || typeof source.partCount !== "number"
329
+ || !Number.isSafeInteger(source.partCount)
330
+ || source.partCount < 1
331
+ || source.partCount > 8
332
+ || typeof source.provenPartCount !== "number"
333
+ || !Number.isSafeInteger(source.provenPartCount)
334
+ || source.provenPartCount < 0
335
+ || source.provenPartCount > source.partCount
336
+ || hasObservedAcceptedPrefixCount
337
+ && (typeof source.observedAcceptedPrefixCount !== "number"
338
+ || !Number.isSafeInteger(source.observedAcceptedPrefixCount)
339
+ || source.observedAcceptedPrefixCount < 0
340
+ || source.observedAcceptedPrefixCount > source.provenPartCount)
341
+ || source.possibleSubmittedPartIndex !== null
342
+ && (typeof source.possibleSubmittedPartIndex !== "number"
343
+ || !Number.isSafeInteger(source.possibleSubmittedPartIndex)
344
+ || source.possibleSubmittedPartIndex < 0
345
+ || source.possibleSubmittedPartIndex >= source.partCount)
346
+ ) throw new Error("messaging run is malformed");
347
+ const sourceParts = denseArray(source.parts, "messaging run parts", 8);
348
+ if (sourceParts.length !== source.partCount) throw new Error("messaging run is malformed");
349
+ const terminalReasons = new Set<MessagingRunV1["terminalReason"]>([
350
+ null,
351
+ "context-drift",
352
+ "prefix-freshness-unproven",
353
+ "provider-failed-before-dispatch",
354
+ "provider-result-indeterminate",
355
+ "journal-recovery-required",
356
+ ]);
357
+ if (!terminalReasons.has(source.terminalReason as MessagingRunV1["terminalReason"])) {
358
+ throw new Error("messaging run terminal reason is malformed");
359
+ }
360
+ const partStates = new Set<MessagingPartJournalStateV1>([
361
+ "unattempted", "claimed", "dispatching", "accepted",
362
+ "failed-before-dispatch", "failed-permanent", "indeterminate",
363
+ ]);
364
+ const seen = new Set<string>();
365
+ const parts = sourceParts.map((value_, index) => {
366
+ const part = record(value_, `messaging run part ${index + 1}`);
367
+ exactKeys(part, [
368
+ "partId", "text", "replyRef", "replyToProviderId", "direction", "bodySha256",
369
+ "state", "providerMessageId", "providerRevision", "delivery", "read",
370
+ ], `messaging run part ${index + 1}`);
371
+ const partId = boundedText(part.partId, "messaging run part ID", 64);
372
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u.test(partId) || seen.has(partId)) {
373
+ throw new Error("messaging run part ID is malformed or repeated");
374
+ }
375
+ seen.add(partId);
376
+ if (
377
+ !partStates.has(part.state as MessagingPartJournalStateV1)
378
+ || part.replyRef !== null
379
+ && (typeof part.replyRef !== "string" || !/^wmreply_[A-Za-z0-9_-]{22}$/u.test(part.replyRef))
380
+ || part.replyToProviderId !== null
381
+ && (typeof part.replyToProviderId !== "string" || part.replyToProviderId.length < 1 || part.replyToProviderId.length > 4_096)
382
+ || part.direction !== "outgoing"
383
+ || part.providerMessageId !== null
384
+ && (typeof part.providerMessageId !== "string" || part.providerMessageId.length < 1 || part.providerMessageId.length > 4_096)
385
+ || part.providerRevision !== null
386
+ && (typeof part.providerRevision !== "string" || part.providerRevision.length < 1 || part.providerRevision.length > 4_096)
387
+ || part.state === "accepted" && part.providerMessageId === null
388
+ || part.state !== "accepted" && part.providerMessageId !== null
389
+ || part.state !== "accepted" && part.providerRevision !== null
390
+ || part.delivery !== "unknown" && part.delivery !== "delivered" && part.delivery !== "failed"
391
+ || part.read !== "unknown" && part.read !== "read"
392
+ ) throw new Error("messaging run part is malformed");
393
+ const text = boundedText(part.text, "messaging run part text", 65_536);
394
+ const bodySha256 = digest(part.bodySha256, "messaging run part body digest");
395
+ if (sha256(text) !== bodySha256) {
396
+ throw new Error("messaging run part body digest disagrees");
397
+ }
398
+ return Object.freeze({
399
+ partId,
400
+ text,
401
+ replyRef: part.replyRef as string | null,
402
+ replyToProviderId: part.replyToProviderId as string | null,
403
+ direction: "outgoing" as const,
404
+ bodySha256,
405
+ state: part.state as MessagingPartJournalStateV1,
406
+ providerMessageId: part.providerMessageId as string | null,
407
+ providerRevision: part.providerRevision as string | null,
408
+ delivery: part.delivery as "unknown" | "delivered" | "failed",
409
+ read: part.read as "unknown" | "read",
410
+ });
411
+ });
412
+ const startedAt = timestamp(boundedText(source.startedAt, "messaging run start", 64));
413
+ const recordedAt = timestamp(boundedText(source.recordedAt, "messaging run record time", 64));
414
+ if (Date.parse(recordedAt) < Date.parse(startedAt)) throw new Error("messaging run time moved backward");
415
+ const parsed: MessagingRunV1 = Object.freeze({
416
+ schemaVersion: 1,
417
+ format: "wrench.messaging-run",
418
+ runId: source.runId,
419
+ planDigest: digest(source.planDigest, "messaging run plan digest"),
420
+ routeRef: source.routeRef,
421
+ contextRef: source.contextRef,
422
+ clientIntentSha256: digest(source.clientIntentSha256, "messaging run client intent"),
423
+ contextBindingSha256: hasCurrentContextEvidence
424
+ ? digest(
425
+ source.contextBindingSha256,
426
+ "messaging run context binding",
427
+ )
428
+ : null,
429
+ sourceConversationCoordinateSha256: hasCurrentContextEvidence
430
+ ? digest(
431
+ source.sourceConversationCoordinateSha256,
432
+ "messaging run source conversation coordinate",
433
+ )
434
+ : null,
435
+ turnDigest: digest(source.turnDigest, "messaging run turn digest"),
436
+ previewDigest: digest(source.previewDigest, "messaging run preview digest"),
437
+ state: source.state,
438
+ partCount: source.partCount,
439
+ provenPartCount: source.provenPartCount,
440
+ observedAcceptedPrefixCount: hasObservedAcceptedPrefixCount
441
+ ? source.observedAcceptedPrefixCount as number
442
+ : source.provenPartCount,
443
+ possibleSubmittedPartIndex: source.possibleSubmittedPartIndex as number | null,
444
+ privateProviderOutcome: hasPrivateProviderOutcome
445
+ ? source.privateProviderOutcome === null
446
+ ? null
447
+ : parsePrivateProviderOutcome(source.privateProviderOutcome)
448
+ : null,
449
+ terminalReason: source.terminalReason as MessagingRunV1["terminalReason"],
450
+ parts: Object.freeze(parts),
451
+ startedAt,
452
+ recordedAt,
453
+ });
454
+ assertRun(parsed);
455
+ return parsed;
456
+ }
457
+
458
+ /** Strict foreign-value parser used by encrypted storage and contract tests. */
459
+ export function parseMessagingRunV1(value: unknown): MessagingRunV1 {
460
+ return parseRun(value);
461
+ }
462
+
463
+ /** Exact proof material retained durably for a future checked provider reread. */
464
+ export function messagingExpectedOwnPrefix(
465
+ run: MessagingRunV1,
466
+ ): ProviderPluginMessagingExpectedOwnPrefixV1["accepted"] {
467
+ assertRun(run);
468
+ return Object.freeze(run.parts.slice(0, run.provenPartCount).map((part) => {
469
+ if (part.state !== "accepted" || part.providerMessageId === null) {
470
+ throw new Error("messaging run accepted prefix is incomplete");
471
+ }
472
+ return Object.freeze({
473
+ providerMessageId: part.providerMessageId,
474
+ providerRevision: part.providerRevision,
475
+ direction: part.direction,
476
+ bodySha256: part.bodySha256,
477
+ replyToProviderId: part.replyToProviderId,
478
+ });
479
+ }));
480
+ }
481
+
482
+ function sealed(run: MessagingRunV1, environment: Environment): unknown {
483
+ return sealAuthenticatedPrivatePayload(
484
+ run,
485
+ domain(run.runId),
486
+ environment,
487
+ MAX_PLAINTEXT_BYTES,
488
+ );
489
+ }
490
+
491
+ export function initializeMessagingRun(
492
+ runId: string,
493
+ planDigest: string,
494
+ plan: MessagingCompositeInvocationPlanV1,
495
+ environment: Environment,
496
+ at: string,
497
+ ): MessagingRunSnapshotV1 {
498
+ if (
499
+ plan.contextBindingSha256 === null
500
+ || plan.sourceConversationCoordinateSha256 === null
501
+ ) {
502
+ throw new Error(
503
+ "predecessor messaging plan lacks current context evidence; preview the action again",
504
+ );
505
+ }
506
+ ensurePrivateStateDirectory(root(environment), environment);
507
+ const startedAt = timestamp(at);
508
+ const run = parseRun({
509
+ schemaVersion: 1,
510
+ format: "wrench.messaging-run",
511
+ runId,
512
+ planDigest,
513
+ routeRef: plan.routeRef,
514
+ contextRef: plan.contextRef,
515
+ clientIntentSha256: plan.clientIntentSha256,
516
+ contextBindingSha256: plan.contextBindingSha256,
517
+ sourceConversationCoordinateSha256:
518
+ plan.sourceConversationCoordinateSha256,
519
+ turnDigest: plan.turnDigest,
520
+ previewDigest: plan.previewDigest,
521
+ state: "pending",
522
+ partCount: plan.parts.length,
523
+ provenPartCount: 0,
524
+ observedAcceptedPrefixCount: 0,
525
+ possibleSubmittedPartIndex: null,
526
+ privateProviderOutcome: null,
527
+ terminalReason: null,
528
+ parts: plan.parts.map((part) => ({
529
+ partId: part.partId,
530
+ text: part.text,
531
+ replyRef: part.replyRef,
532
+ replyToProviderId: part.replyToProviderId,
533
+ direction: "outgoing" as const,
534
+ bodySha256: sha256(part.text),
535
+ state: "unattempted" as const,
536
+ providerMessageId: null,
537
+ providerRevision: null,
538
+ delivery: "unknown" as const,
539
+ read: "unknown" as const,
540
+ })),
541
+ startedAt,
542
+ recordedAt: startedAt,
543
+ });
544
+ const envelope = sealed(run, environment);
545
+ const encoded = `${canonicalJson(envelope)}\n`;
546
+ const created = createPrivateJsonIfAbsent(path(runId, environment), envelope, {
547
+ environment,
548
+ privateParent: true,
549
+ });
550
+ if (!created.created) {
551
+ const existing = readMessagingRun(runId, environment);
552
+ if (
553
+ existing.run.planDigest !== planDigest
554
+ || existing.run.turnDigest !== plan.turnDigest
555
+ || existing.run.contextBindingSha256 !== plan.contextBindingSha256
556
+ || existing.run.sourceConversationCoordinateSha256
557
+ !== plan.sourceConversationCoordinateSha256
558
+ ) throw new Error("existing messaging run belongs to another confirmation");
559
+ return existing;
560
+ }
561
+ return Object.freeze({ run, contentSha256: sha256(encoded) });
562
+ }
563
+
564
+ export function readMessagingRun(
565
+ runId: string,
566
+ environment: Environment = process.env,
567
+ ): MessagingRunSnapshotV1 {
568
+ const text = readPrivateStateFileIfPresent(
569
+ path(runId, environment),
570
+ MAX_ENCRYPTED_BYTES,
571
+ "encrypted messaging run",
572
+ environment,
573
+ );
574
+ if (text === null) throw new Error("messaging run was not found");
575
+ let envelope: unknown;
576
+ try {
577
+ envelope = JSON.parse(text) as unknown;
578
+ } catch {
579
+ throw new Error("encrypted messaging run is malformed");
580
+ }
581
+ const run = parseRun(openAuthenticatedPrivatePayload(
582
+ envelope,
583
+ domain(runId),
584
+ environment,
585
+ MAX_PLAINTEXT_BYTES,
586
+ ));
587
+ if (run.runId !== runId) throw new Error("messaging run coordinate disagrees");
588
+ return Object.freeze({ run, contentSha256: sha256(text) });
589
+ }
590
+
591
+ export function readMessagingRunIfPresent(
592
+ runId: string,
593
+ environment: Environment = process.env,
594
+ ): MessagingRunSnapshotV1 | null {
595
+ try {
596
+ return readMessagingRun(runId, environment);
597
+ } catch (error) {
598
+ if (error instanceof Error && error.message === "messaging run was not found") return null;
599
+ throw error;
600
+ }
601
+ }
602
+
603
+ export function transitionMessagingRun(
604
+ run: MessagingRunV1,
605
+ event: MessagingRunEventV1,
606
+ ): MessagingRunV1 {
607
+ assertRun(run);
608
+ if (run.state !== "pending" || event.index !== run.provenPartCount) {
609
+ throw new Error("messaging run transition is outside the active prefix");
610
+ }
611
+ const current = run.parts[event.index];
612
+ if (current === undefined) throw new Error("messaging run transition index is invalid");
613
+ let nextState: MessagingPartJournalStateV1;
614
+ let providerMessageId = current.providerMessageId;
615
+ let providerRevision = current.providerRevision;
616
+ let state: MessagingRunV1["state"] = run.state;
617
+ let provenPartCount = run.provenPartCount;
618
+ let observedAcceptedPrefixCount = run.observedAcceptedPrefixCount;
619
+ let possibleSubmittedPartIndex = run.possibleSubmittedPartIndex;
620
+ let privateProviderOutcome = run.privateProviderOutcome;
621
+ let terminalReason = run.terminalReason;
622
+ if (event.type === "claimed") {
623
+ if (current.state !== "unattempted") throw new Error("messaging part was already claimed");
624
+ if (
625
+ !Number.isSafeInteger(event.observedAcceptedPrefixCount)
626
+ || event.observedAcceptedPrefixCount < observedAcceptedPrefixCount
627
+ || event.observedAcceptedPrefixCount > run.provenPartCount
628
+ ) throw new Error("messaging accepted-prefix observation is not monotonic");
629
+ observedAcceptedPrefixCount = event.observedAcceptedPrefixCount;
630
+ nextState = "claimed";
631
+ } else if (event.type === "dispatching") {
632
+ if (current.state !== "claimed") throw new Error("messaging part was not claimed");
633
+ nextState = "dispatching";
634
+ } else if (event.type === "accepted") {
635
+ if (current.state !== "dispatching") throw new Error("messaging part did not cross dispatch");
636
+ nextState = "accepted";
637
+ providerMessageId = event.providerMessageId;
638
+ providerRevision = event.providerRevision;
639
+ provenPartCount += 1;
640
+ if (provenPartCount === run.partCount) state = "submitted";
641
+ } else if (event.type === "categorical-stop") {
642
+ if (current.state !== "unattempted" && current.state !== "claimed") {
643
+ throw new Error("categorical stop crossed the dispatch boundary");
644
+ }
645
+ nextState = event.partState;
646
+ state = provenPartCount === 0 ? "failed" : "partial";
647
+ terminalReason = event.reason;
648
+ } else {
649
+ if (current.state !== "dispatching" && current.state !== "claimed") {
650
+ throw new Error("indeterminate part was not active");
651
+ }
652
+ if (
653
+ event.reason === "provider-result-indeterminate"
654
+ && event.privateProviderOutcome !== null
655
+ && current.state !== "dispatching"
656
+ ) throw new Error("private provider outcome did not cross dispatch");
657
+ nextState = "indeterminate";
658
+ state = "indeterminate";
659
+ possibleSubmittedPartIndex = event.index;
660
+ terminalReason = event.reason;
661
+ privateProviderOutcome = event.reason === "provider-result-indeterminate"
662
+ ? event.privateProviderOutcome
663
+ : null;
664
+ }
665
+ const parts = run.parts.map((part, index) => index === event.index
666
+ ? Object.freeze({ ...part, state: nextState, providerMessageId, providerRevision })
667
+ : part);
668
+ if (Date.parse(event.at) < Date.parse(run.recordedAt)) {
669
+ throw new Error("messaging run transition time moved backward");
670
+ }
671
+ return parseRun({
672
+ ...run,
673
+ state,
674
+ provenPartCount,
675
+ observedAcceptedPrefixCount,
676
+ possibleSubmittedPartIndex,
677
+ privateProviderOutcome,
678
+ terminalReason,
679
+ parts,
680
+ recordedAt: timestamp(event.at),
681
+ });
682
+ }
683
+
684
+ export function updateMessagingRun(
685
+ snapshot: MessagingRunSnapshotV1,
686
+ event: MessagingRunEventV1,
687
+ environment: Environment = process.env,
688
+ ): MessagingRunSnapshotV1 {
689
+ const run = transitionMessagingRun(snapshot.run, event);
690
+ const envelope = sealed(run, environment);
691
+ const encoded = `${canonicalJson(envelope)}\n`;
692
+ if (!writePrivateJsonIfUnchanged(path(run.runId, environment), envelope, {
693
+ expectedCurrentContentSha256: snapshot.contentSha256,
694
+ maximumExpectedCurrentBytes: MAX_ENCRYPTED_BYTES,
695
+ })) throw new Error("messaging run changed concurrently");
696
+ return Object.freeze({ run, contentSha256: sha256(encoded) });
697
+ }
698
+
699
+ export function messagingReceiptBinding(run: MessagingRunV1): MessagingReceiptBinding {
700
+ if (run.state === "pending") throw new Error("pending messaging run has no terminal receipt binding");
701
+ if (run.contextBindingSha256 === null) {
702
+ if (run.sourceConversationCoordinateSha256 !== null) {
703
+ throw new Error("messaging run has partial context evidence");
704
+ }
705
+ const predecessorWithoutReceipt = Object.freeze({
706
+ schemaVersion: 1 as const,
707
+ format: "wrench.messaging-receipt-binding" as const,
708
+ contractId: MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID,
709
+ contractHash: MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH,
710
+ clientIntentSha256: run.clientIntentSha256,
711
+ routeRefSha256: sha256(run.routeRef),
712
+ contextRefSha256: sha256(run.contextRef),
713
+ turnDigest: run.turnDigest,
714
+ previewDigest: run.previewDigest,
715
+ runId: run.runId,
716
+ state: run.state,
717
+ partCount: run.partCount,
718
+ provenPartCount: run.provenPartCount,
719
+ recordedAt: run.recordedAt,
720
+ });
721
+ return parseMessagingReceiptBindingV1({
722
+ ...predecessorWithoutReceipt,
723
+ receiptSha256: sha256(canonicalJson(predecessorWithoutReceipt)),
724
+ });
725
+ }
726
+ if (run.sourceConversationCoordinateSha256 === null) {
727
+ throw new Error("messaging run has partial context evidence");
728
+ }
729
+ const withoutReceipt = Object.freeze({
730
+ schemaVersion: 2 as const,
731
+ format: "wrench.messaging-receipt-binding" as const,
732
+ contractId: MESSAGING_RECEIPT_BINDING_CONTRACT_ID,
733
+ contractHash: MESSAGING_RECEIPT_BINDING_CONTRACT_HASH,
734
+ clientIntentSha256: run.clientIntentSha256,
735
+ contextBindingSha256: run.contextBindingSha256,
736
+ sourceConversationCoordinateSha256:
737
+ run.sourceConversationCoordinateSha256,
738
+ routeRefSha256: sha256(run.routeRef),
739
+ contextRefSha256: sha256(run.contextRef),
740
+ turnDigest: run.turnDigest,
741
+ previewDigest: run.previewDigest,
742
+ runId: run.runId,
743
+ state: run.state,
744
+ partCount: run.partCount,
745
+ provenPartCount: run.provenPartCount,
746
+ recordedAt: run.recordedAt,
747
+ });
748
+ return parseMessagingReceiptBindingV2({
749
+ ...withoutReceipt,
750
+ receiptSha256: sha256(canonicalJson(withoutReceipt)),
751
+ });
752
+ }
753
+
754
+ export function messagingRunReceipt(run: MessagingRunV1): MessagingRunReceipt {
755
+ const binding = messagingReceiptBinding(run);
756
+ if (binding.schemaVersion === 1) {
757
+ return Object.freeze({
758
+ schemaVersion: 1,
759
+ format: "wrench.messaging-run-receipt",
760
+ planDigest: run.planDigest,
761
+ runId: run.runId,
762
+ state: binding.state,
763
+ partCount: binding.partCount,
764
+ provenPartCount: binding.provenPartCount,
765
+ clientIntentSha256: binding.clientIntentSha256,
766
+ routeRefSha256: binding.routeRefSha256,
767
+ contextRefSha256: binding.contextRefSha256,
768
+ turnDigest: binding.turnDigest,
769
+ previewDigest: binding.previewDigest,
770
+ receiptBindingSha256: binding.receiptSha256,
771
+ recordedAt: binding.recordedAt,
772
+ });
773
+ }
774
+ return Object.freeze({
775
+ schemaVersion: 2,
776
+ format: "wrench.messaging-run-receipt",
777
+ planDigest: run.planDigest,
778
+ runId: run.runId,
779
+ state: binding.state,
780
+ partCount: binding.partCount,
781
+ provenPartCount: binding.provenPartCount,
782
+ clientIntentSha256: binding.clientIntentSha256,
783
+ contextBindingSha256: binding.contextBindingSha256,
784
+ sourceConversationCoordinateSha256:
785
+ binding.sourceConversationCoordinateSha256,
786
+ routeRefSha256: binding.routeRefSha256,
787
+ contextRefSha256: binding.contextRefSha256,
788
+ turnDigest: binding.turnDigest,
789
+ previewDigest: binding.previewDigest,
790
+ receiptBindingSha256: binding.receiptSha256,
791
+ recordedAt: binding.recordedAt,
792
+ });
793
+ }