@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,91 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Either from "effect/Either";
3
+ import * as Exit from "effect/Exit";
4
+ import type { PortableOperationIdentityV1 } from "./provider-plugin-portable-identity";
5
+ import {
6
+ acquirePortableProviderPluginInvocationLease,
7
+ createPortableProviderPluginInvocationLeaseContainmentController,
8
+ releasePortableProviderPluginInvocationLease
9
+ } from "./provider-plugin-invocation-lease";
10
+ import { settlePortableProviderPluginCleanup } from "./provider-plugin-cleanup-barrier";
11
+ import {
12
+ acquireWebSessionCleanupAdmission,
13
+ WebSessionCleanupAdmissionBlockedError,
14
+ type WebSessionCleanupAdmissionIdentity
15
+ } from "./web-session-cleanup-admission";
16
+ import type { WebSessionCleanupBarrierRegistrar } from "./web-session-execution";
17
+ import { readAttempt, type ReadEffectFailure } from "./read-effect";
18
+ import { readNative } from "./read-effect-platform";
19
+ import { runReadEffect } from "./read-effect-runtime";
20
+
21
+ type Environment = Readonly<Record<string, string | undefined>>;
22
+
23
+ /** Exact kernel/content custody stays synchronous. The program owns closing
24
+ * registration, joining every registered barrier, and releasing only a proven
25
+ * cleanup-complete controller. An unsafe controller remains durable. */
26
+ export async function withReadCleanupAdmission<A>(
27
+ identity: WebSessionCleanupAdmissionIdentity,
28
+ environment: Environment,
29
+ operation: (register: WebSessionCleanupBarrierRegistrar) => Promise<A>,
30
+ acquiredAt: Date | undefined,
31
+ onBlocked: (error: WebSessionCleanupAdmissionBlockedError) => Promise<A>
32
+
33
+ ): Promise<A> {
34
+ const program: Effect.Effect<A, ReadEffectFailure> = Effect.gen(function*() {
35
+ const acquired = yield* Effect.either(readAttempt(() => acquireWebSessionCleanupAdmission(identity, environment, acquiredAt)));
36
+ if (Either.isLeft(acquired)) {
37
+ const cause = acquired.left.cause;
38
+ if (cause instanceof WebSessionCleanupAdmissionBlockedError) return yield* readNative(() => onBlocked(cause));
39
+ return yield* Effect.fail(acquired.left);
40
+ }
41
+ const admission = acquired.right;
42
+ const settlement = yield* Effect.exit(Effect.gen(function*() {
43
+ const outcome = yield* Effect.exit(readNative(() => operation(admission.registerCleanupBarrier)));
44
+ yield* readAttempt(admission.closeRegistration);
45
+ const barriers = yield* Effect.all(
46
+ admission.barriers.map(barrier => Effect.either(readNative(() => barrier))),
47
+ { concurrency: "unbounded" }
48
+ );
49
+ yield* readAttempt(() => {
50
+ if (barriers.some(Either.isLeft)) admission.cleanupUnsafe();
51
+ else { admission.cleanupComplete(); admission.release(); }
52
+ });
53
+ return yield* outcome;
54
+ }));
55
+ if (Exit.isFailure(settlement)) {
56
+ yield* readAttempt(() => {
57
+ admission.closeRegistration();
58
+ if (admission.current.claim.containment.status === "parent-owned") { admission.cleanupComplete(); admission.release(); }
59
+ });
60
+ }
61
+ return yield* settlement;
62
+ }).pipe(Effect.uninterruptible);
63
+ return runReadEffect(program);
64
+ }
65
+
66
+ /** AsyncLocalStorage in the native portable host retains descendant barrier
67
+ * registration. Its positive proof precedes the synchronous exact lease release;
68
+ * neither a failed operation nor Effect scope completion can substitute for it. */
69
+ export async function withPortableReadAdmission<A>(
70
+ identity: PortableOperationIdentityV1,
71
+ runId: string,
72
+ environment: Environment,
73
+ acquiredAt: Date | undefined,
74
+ operation: () => Promise<A>
75
+
76
+ ): Promise<A> {
77
+ const program: Effect.Effect<A, ReadEffectFailure> = Effect.gen(function*() {
78
+ const containment = yield* readAttempt(() => createPortableProviderPluginInvocationLeaseContainmentController(
79
+ acquirePortableProviderPluginInvocationLease(identity, runId, environment, acquiredAt),
80
+ environment
81
+ ));
82
+ const outcome = yield* readNative(() => settlePortableProviderPluginCleanup(
83
+ operation,
84
+ { containment, cleanupComplete: containment.cleanupComplete }
85
+ ));
86
+ yield* readAttempt(() => releasePortableProviderPluginInvocationLease(containment.current, environment, new Date()));
87
+ if (outcome.status === "rejected") return yield* readAttempt(() => { throw outcome.reason; });
88
+ return outcome.value;
89
+ }).pipe(Effect.uninterruptible);
90
+ return runReadEffect(program);
91
+ }
@@ -0,0 +1,521 @@
1
+ import { canonicalJson, sha256 } from "./canonical-json";
2
+ import { loadAuthSnapshotIfPresent } from "./auth";
3
+ import {
4
+ createPortableProviderPluginCatalog,
5
+ } from "./provider-plugin-portable-catalog";
6
+ import type { ProviderPluginRegistry } from "./provider-plugin-registry";
7
+ import { providerPluginRegistry } from "./provider-plugins";
8
+ import {
9
+ ReadProjectionDurableRepairError,
10
+ READ_PROJECTION_TRANSITION_SETTLEMENT_WAIT_MS,
11
+ isReadProjectionCorruptionError,
12
+ publishReadProjection,
13
+ readReadProjection,
14
+ repairReadProjection,
15
+ removeReadProjection,
16
+ projectionAuthIdentityHash,
17
+ withSettledReadProjectionAuthAdmission,
18
+ type ReadProjectionCacheResult,
19
+ type ReadProjectionPublication,
20
+ type ReadProjectionQuery,
21
+ type ReadProjectionAdmissionSettlementOptions,
22
+ } from "./read-projections";
23
+ import {
24
+ isPublicWebSessionInvocationAuthority,
25
+ publicWebSessionAuthorityIdentityHash,
26
+ } from "./web-session-authentication-policy";
27
+ import {
28
+ createReadProjectionQueryForInvocation,
29
+ executeReadInvocation,
30
+ prepareInvocation,
31
+ type InvocationResult,
32
+ type PreparedInvocation,
33
+ } from "./runtime";
34
+
35
+ type Environment = Readonly<Record<string, string | undefined>>;
36
+ const MAX_FRESH_FOR_MS = 365 * 24 * 60 * 60 * 1_000;
37
+
38
+ export type CapabilityReadRequest = {
39
+ readonly adapterId: string;
40
+ readonly operationId: string;
41
+ readonly input?: unknown;
42
+ readonly authId?: string;
43
+ };
44
+
45
+ export type ReadCapabilityOptions = {
46
+ readonly environment?: Environment;
47
+ readonly registry?: ProviderPluginRegistry;
48
+ readonly freshForMs?: number;
49
+ readonly now?: Date;
50
+ };
51
+
52
+ export type RevalidateCapabilityOptions = ReadCapabilityOptions & {
53
+ readonly headed?: boolean;
54
+ readonly signal?: AbortSignal;
55
+ };
56
+
57
+ export type ReadProjectionCacheOutcome =
58
+ | {
59
+ readonly status: "stored";
60
+ readonly publication: ReadProjectionPublication;
61
+ }
62
+ | {
63
+ readonly status: "retained";
64
+ readonly reason: "live-read-failed";
65
+ }
66
+ | {
67
+ readonly status: "miss";
68
+ readonly reason: "no-cached-snapshot";
69
+ }
70
+ | {
71
+ readonly status: "skipped";
72
+ readonly reason: "auth-subject-unbound";
73
+ }
74
+ | {
75
+ readonly status: "error";
76
+ readonly message: string;
77
+ };
78
+
79
+ export type RevalidatedCapability = {
80
+ readonly cachedBefore: ReadProjectionCacheResult | null;
81
+ readonly live: InvocationResult;
82
+ readonly cache: ReadProjectionCacheOutcome;
83
+ };
84
+
85
+ type PreparedReadOptions = RevalidateCapabilityOptions & {
86
+ readonly registry: ProviderPluginRegistry;
87
+ readonly executeRead?: typeof executeReadInvocation;
88
+ };
89
+
90
+ function selectedRegistry(
91
+ environment: Environment,
92
+ registry: ProviderPluginRegistry | undefined,
93
+ ): ProviderPluginRegistry {
94
+ return registry
95
+ ?? createPortableProviderPluginCatalog(
96
+ providerPluginRegistry,
97
+ environment,
98
+ ).registry;
99
+ }
100
+
101
+ function prepareCapability(
102
+ request: CapabilityReadRequest,
103
+ environment: Environment,
104
+ registry: ProviderPluginRegistry,
105
+ ): PreparedInvocation {
106
+ return prepareInvocation(
107
+ request.adapterId,
108
+ request.operationId,
109
+ request.input === undefined ? {} : request.input,
110
+ request.authId,
111
+ environment,
112
+ registry,
113
+ );
114
+ }
115
+
116
+ function exactAuthHash(invocation: PreparedInvocation): string {
117
+ return sha256(canonicalJson(invocation.auth));
118
+ }
119
+
120
+ function withInvocationAuthorityAdmission<T>(
121
+ invocation: PreparedInvocation,
122
+ environment: Environment,
123
+ operation: () => T,
124
+ options: ReadProjectionAdmissionSettlementOptions = {},
125
+ ): T {
126
+ return isPublicWebSessionInvocationAuthority(invocation.auth)
127
+ ? operation()
128
+ : withSettledReadProjectionAuthAdmission(
129
+ invocation.auth.id,
130
+ environment,
131
+ operation,
132
+ options,
133
+ );
134
+ }
135
+
136
+ function liveReadDiscardedError(
137
+ invocation: PreparedInvocation,
138
+ cause?: unknown,
139
+ ): Error {
140
+ return new Error(
141
+ `auth locator ${invocation.auth.id} changed while the live read was running; its result was discarded`,
142
+ cause === undefined ? undefined : { cause },
143
+ );
144
+ }
145
+
146
+ function isOptionalAdmissionRewrite(error: unknown): boolean {
147
+ if (!(error instanceof Error)) return false;
148
+ return error.message.includes("could not safely open optional read projection admission")
149
+ && error.message.includes("state file changed while it was read");
150
+ }
151
+
152
+ type AuthRealmState = "matches" | "missing" | "changed";
153
+
154
+ function authRealmState(
155
+ invocation: PreparedInvocation,
156
+ query: ReadProjectionQuery | null,
157
+ environment: Environment,
158
+ ): AuthRealmState {
159
+ if (isPublicWebSessionInvocationAuthority(invocation.auth)) {
160
+ const expected = publicWebSessionAuthorityIdentityHash(invocation.auth);
161
+ return invocation.readProjectionAuthIdentityHash === expected
162
+ && (query === null || query.identity.auth.hash === expected)
163
+ ? "matches"
164
+ : "changed";
165
+ }
166
+ const snapshot = loadAuthSnapshotIfPresent(
167
+ invocation.auth.id,
168
+ environment,
169
+ );
170
+ if (snapshot === null) return "missing";
171
+ const current = snapshot.auth;
172
+ const currentHash = sha256(canonicalJson(current));
173
+ const preparedAuthIdentityHash =
174
+ invocation.readProjectionAuthIdentityHash;
175
+ if (preparedAuthIdentityHash === undefined) {
176
+ throw new Error(
177
+ "prepared invocation is missing its auth lifetime identity; prepare it again",
178
+ );
179
+ }
180
+ if (
181
+ currentHash !== exactAuthHash(invocation)
182
+ || current.subject !== invocation.auth.subject
183
+ ) return "changed";
184
+ const currentAuthIdentityHash = projectionAuthIdentityHash(
185
+ current.id,
186
+ currentHash,
187
+ environment,
188
+ );
189
+ if (
190
+ currentAuthIdentityHash !== preparedAuthIdentityHash
191
+ || (
192
+ query !== null
193
+ && query.identity.auth.hash !== preparedAuthIdentityHash
194
+ )
195
+ ) return "changed";
196
+ return "matches";
197
+ }
198
+
199
+ function requireCurrentAuthRealm(
200
+ invocation: PreparedInvocation,
201
+ query: ReadProjectionQuery | null,
202
+ environment: Environment,
203
+ ): void {
204
+ if (authRealmState(invocation, query, environment) !== "matches") {
205
+ throw new Error(
206
+ `auth locator ${invocation.auth.id} changed since this invocation was prepared`,
207
+ );
208
+ }
209
+ }
210
+
211
+ function validateReadOptions(options: ReadCapabilityOptions): void {
212
+ if (
213
+ options.now !== undefined
214
+ && (
215
+ !(options.now instanceof Date)
216
+ || !Number.isFinite(options.now.getTime())
217
+ )
218
+ ) throw new Error("read projection observation time is invalid");
219
+ if (
220
+ options.freshForMs !== undefined
221
+ && (
222
+ typeof options.freshForMs !== "number"
223
+ || !Number.isSafeInteger(options.freshForMs)
224
+ || options.freshForMs < 0
225
+ || options.freshForMs > MAX_FRESH_FOR_MS
226
+ )
227
+ ) throw new Error("read projection freshness window is malformed");
228
+ }
229
+
230
+ function boundedErrorMessage(error: unknown): string {
231
+ const message = error instanceof Error ? error.message : String(error);
232
+ return Buffer.byteLength(message, "utf8") <= 8 * 1024
233
+ ? message
234
+ : `${Buffer.from(message, "utf8").subarray(0, 8 * 1024).toString("utf8")}…`;
235
+ }
236
+
237
+ export function readCachedPreparedCapability(
238
+ invocation: PreparedInvocation,
239
+ options: ReadCapabilityOptions & { readonly registry: ProviderPluginRegistry },
240
+ ): ReadProjectionCacheResult {
241
+ const environment = options.environment ?? process.env;
242
+ validateReadOptions(options);
243
+ return withInvocationAuthorityAdmission(
244
+ invocation,
245
+ environment,
246
+ () => {
247
+ const query = createReadProjectionQueryForInvocation(
248
+ invocation,
249
+ environment,
250
+ options.registry,
251
+ );
252
+ if (authRealmState(invocation, query, environment) !== "matches") {
253
+ return Object.freeze({ status: "miss" as const, key: query.key });
254
+ }
255
+ const cached = readReadProjection(query, {
256
+ environment,
257
+ ...(options.now === undefined ? {} : { now: options.now }),
258
+ ...(options.freshForMs === undefined
259
+ ? {}
260
+ : { freshForMs: options.freshForMs }),
261
+ });
262
+ if (authRealmState(invocation, query, environment) !== "matches") {
263
+ return Object.freeze({ status: "miss" as const, key: query.key });
264
+ }
265
+ return cached;
266
+ },
267
+ );
268
+ }
269
+
270
+ export function readCachedCapability(
271
+ request: CapabilityReadRequest,
272
+ options: ReadCapabilityOptions = {},
273
+ ): ReadProjectionCacheResult {
274
+ const environment = options.environment ?? process.env;
275
+ const registry = selectedRegistry(environment, options.registry);
276
+ return readCachedPreparedCapability(
277
+ prepareCapability(request, environment, registry),
278
+ { ...options, environment, registry },
279
+ );
280
+ }
281
+
282
+ export async function revalidatePreparedCapability(
283
+ invocation: PreparedInvocation,
284
+ options: PreparedReadOptions,
285
+ cachedBeforeOverride?: ReadProjectionCacheResult | null,
286
+ ): Promise<RevalidatedCapability> {
287
+ const environment = options.environment ?? process.env;
288
+ validateReadOptions(options);
289
+ const query = withInvocationAuthorityAdmission(
290
+ invocation,
291
+ environment,
292
+ () => {
293
+ const prepared = invocation.auth.subject === undefined
294
+ ? null
295
+ : createReadProjectionQueryForInvocation(
296
+ invocation,
297
+ environment,
298
+ options.registry,
299
+ );
300
+ requireCurrentAuthRealm(invocation, prepared, environment);
301
+ return prepared;
302
+ },
303
+ );
304
+ let cacheReadError: unknown = null;
305
+ let cachedBefore: ReadProjectionCacheResult | null;
306
+ try {
307
+ cachedBefore = cachedBeforeOverride !== undefined
308
+ ? cachedBeforeOverride
309
+ : query === null
310
+ ? null
311
+ : readCachedPreparedCapability(invocation, {
312
+ environment,
313
+ registry: options.registry,
314
+ ...(options.now === undefined ? {} : { now: options.now }),
315
+ ...(options.freshForMs === undefined
316
+ ? {}
317
+ : { freshForMs: options.freshForMs }),
318
+ });
319
+ } catch (error) {
320
+ withInvocationAuthorityAdmission(
321
+ invocation,
322
+ environment,
323
+ () => requireCurrentAuthRealm(invocation, query, environment),
324
+ );
325
+ cacheReadError = error;
326
+ cachedBefore = null;
327
+ }
328
+ withInvocationAuthorityAdmission(
329
+ invocation,
330
+ environment,
331
+ () => requireCurrentAuthRealm(invocation, query, environment),
332
+ );
333
+ const live = await (options.executeRead ?? executeReadInvocation)(
334
+ invocation,
335
+ {
336
+ headed: options.headed ?? false,
337
+ environment,
338
+ registry: options.registry,
339
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
340
+ },
341
+ );
342
+ try {
343
+ return withInvocationAuthorityAdmission(
344
+ invocation,
345
+ environment,
346
+ () => {
347
+ if (authRealmState(invocation, query, environment) !== "matches") {
348
+ throw liveReadDiscardedError(invocation);
349
+ }
350
+ if (query === null) {
351
+ return Object.freeze({
352
+ cachedBefore,
353
+ live,
354
+ cache: Object.freeze({
355
+ status: "skipped" as const,
356
+ reason: "auth-subject-unbound" as const,
357
+ }),
358
+ });
359
+ }
360
+ if (live.receipt.status !== "succeeded") {
361
+ if (cacheReadError !== null) {
362
+ return Object.freeze({
363
+ cachedBefore,
364
+ live,
365
+ cache: Object.freeze({
366
+ status: "error" as const,
367
+ message: boundedErrorMessage(cacheReadError),
368
+ }),
369
+ });
370
+ }
371
+ if (cachedBefore?.status !== "hit") {
372
+ return Object.freeze({
373
+ cachedBefore,
374
+ live,
375
+ cache: Object.freeze({
376
+ status: "miss" as const,
377
+ reason: "no-cached-snapshot" as const,
378
+ }),
379
+ });
380
+ }
381
+ return Object.freeze({
382
+ cachedBefore,
383
+ live,
384
+ cache: Object.freeze({
385
+ status: "retained" as const,
386
+ reason: "live-read-failed" as const,
387
+ }),
388
+ });
389
+ }
390
+ const publicationOptions = {
391
+ environment,
392
+ runId: live.receipt.runId,
393
+ startedAt: live.receipt.startedAt,
394
+ finishedAt: live.receipt.finishedAt,
395
+ } as const;
396
+ let publication: ReadProjectionPublication;
397
+ try {
398
+ if (isReadProjectionCorruptionError(cacheReadError)) {
399
+ publication = repairReadProjection(
400
+ query,
401
+ live.output,
402
+ {
403
+ ...publicationOptions,
404
+ corruption: cacheReadError,
405
+ observedBeforeLive: true,
406
+ },
407
+ );
408
+ } else {
409
+ try {
410
+ publication = publishReadProjection(
411
+ query,
412
+ live.output,
413
+ publicationOptions,
414
+ );
415
+ } catch (error) {
416
+ if (!isReadProjectionCorruptionError(error)) throw error;
417
+ publication = repairReadProjection(
418
+ query,
419
+ live.output,
420
+ {
421
+ ...publicationOptions,
422
+ corruption: error,
423
+ observedBeforeLive: false,
424
+ },
425
+ );
426
+ }
427
+ }
428
+ } catch (error) {
429
+ if (
430
+ error instanceof ReadProjectionDurableRepairError
431
+ && error.queryKey === query.key
432
+ ) {
433
+ publication = error.publication;
434
+ } else {
435
+ return Object.freeze({
436
+ cachedBefore,
437
+ live,
438
+ cache: Object.freeze({
439
+ status: "error" as const,
440
+ message: boundedErrorMessage(error),
441
+ }),
442
+ });
443
+ }
444
+ }
445
+ if (authRealmState(invocation, query, environment) !== "matches") {
446
+ removeReadProjection(query, environment);
447
+ throw new Error(
448
+ `auth locator ${invocation.auth.id} changed while the live read was being published; its result was discarded`,
449
+ );
450
+ }
451
+ return Object.freeze({
452
+ cachedBefore,
453
+ live,
454
+ cache: Object.freeze({
455
+ status: "stored" as const,
456
+ publication,
457
+ }),
458
+ });
459
+ },
460
+ { maximumWaitMs: READ_PROJECTION_TRANSITION_SETTLEMENT_WAIT_MS },
461
+ );
462
+ } catch (error) {
463
+ if (isOptionalAdmissionRewrite(error)) {
464
+ throw liveReadDiscardedError(invocation, error);
465
+ }
466
+ throw error;
467
+ }
468
+ }
469
+
470
+ export async function revalidateCapability(
471
+ request: CapabilityReadRequest,
472
+ options: RevalidateCapabilityOptions = {},
473
+ ): Promise<RevalidatedCapability> {
474
+ const environment = options.environment ?? process.env;
475
+ const registry = selectedRegistry(environment, options.registry);
476
+ return revalidatePreparedCapability(
477
+ prepareCapability(request, environment, registry),
478
+ { ...options, environment, registry },
479
+ );
480
+ }
481
+
482
+ /**
483
+ * Return the current exact snapshot synchronously and start one explicit live
484
+ * R1 revalidation. UI callers can render `cached` before awaiting
485
+ * `revalidation`; Ghostget never hides a transport refresh in a cache lookup.
486
+ */
487
+ export function staleWhileRevalidateCapability(
488
+ request: CapabilityReadRequest,
489
+ options: RevalidateCapabilityOptions = {},
490
+ ): {
491
+ readonly cached: ReadProjectionCacheResult | null;
492
+ readonly revalidation: Promise<RevalidatedCapability>;
493
+ } {
494
+ const environment = options.environment ?? process.env;
495
+ const registry = selectedRegistry(environment, options.registry);
496
+ const invocation = prepareCapability(request, environment, registry);
497
+ validateReadOptions(options);
498
+ let cached: ReadProjectionCacheResult | null = null;
499
+ let cacheReadCompleted = false;
500
+ if (invocation.auth.subject !== undefined) {
501
+ try {
502
+ cached = readCachedPreparedCapability(invocation, {
503
+ ...options,
504
+ environment,
505
+ registry,
506
+ });
507
+ cacheReadCompleted = true;
508
+ } catch {
509
+ // A corrupt or unavailable local projection must not prevent the live
510
+ // R1 contract from running and reporting its independent outcome.
511
+ }
512
+ }
513
+ return Object.freeze({
514
+ cached,
515
+ revalidation: revalidatePreparedCapability(
516
+ invocation,
517
+ { ...options, environment, registry },
518
+ cacheReadCompleted ? cached : undefined,
519
+ ),
520
+ });
521
+ }
@@ -0,0 +1,7 @@
1
+ import * as Effect from "effect/Effect";
2
+ import { ReadEffectFailure } from "./read-effect";
3
+
4
+ /** Adapts a native operation. AbortSignal/native settlement rules belong to the
5
+ * supplied product port, not to interruption of this Promise subscription. */
6
+ export const readNative = <A>(work: () => Promise<A>): Effect.Effect<A, ReadEffectFailure> =>
7
+ Effect.tryPromise({ try: work, catch: cause => new ReadEffectFailure({ cause }) });
@@ -0,0 +1,14 @@
1
+ import * as Cause from "effect/Cause";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Exit from "effect/Exit";
4
+ import * as Option from "effect/Option";
5
+ import type { ReadEffectFailure } from "./read-effect";
6
+
7
+ /** Only genuine Promise/plugin boundaries interpret closed read programs. */
8
+ export async function runReadEffect<A>(program: Effect.Effect<A, ReadEffectFailure>): Promise<A> {
9
+ const exit = await Effect.runPromiseExit(program);
10
+ if (Exit.isSuccess(exit)) return exit.value;
11
+ const failure = Cause.failureOption(exit.cause);
12
+ if (Option.isSome(failure)) throw failure.value.cause;
13
+ throw Cause.squash(exit.cause);
14
+ }
@@ -0,0 +1,52 @@
1
+ import * as Cause from "effect/Cause";
2
+ import * as Data from "effect/Data";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Exit from "effect/Exit";
5
+ import * as Option from "effect/Option";
6
+
7
+ /** A foreign boundary failure retains the original rejection privately. */
8
+ export class ReadEffectFailure extends Data.TaggedError("ReadEffectFailure")<{
9
+ readonly cause: unknown;
10
+ readonly cleanupCause?: unknown;
11
+ readonly primaryCause?: unknown;
12
+ }> { }
13
+
14
+ export const readAttempt = <A>(work: () => A): Effect.Effect<A, ReadEffectFailure> =>
15
+ Effect.try({ try: work, catch: cause => new ReadEffectFailure({ cause }) });
16
+
17
+ /** Native acquisition and finalization settle before ownership leaves the scope.
18
+ * A failing finalizer retains the primary failure while preserving the previous
19
+ * finally-block precedence at the Promise boundary. */
20
+ export function withReadResource<Resource, A, R>(
21
+ acquire: Effect.Effect<Resource, ReadEffectFailure, R>,
22
+ use: (resource: Resource) => Effect.Effect<A, ReadEffectFailure, R>,
23
+ release: (resource: Resource) => Effect.Effect<void, ReadEffectFailure, R>,
24
+
25
+ ): Effect.Effect<A, ReadEffectFailure, R> {
26
+ return Effect.gen(function*() {
27
+ let finalization: Exit.Exit<void, ReadEffectFailure> = Exit.void;
28
+ const outcome = yield* Effect.scoped(Effect.gen(function*() {
29
+ const resource = yield* Effect.acquireRelease(
30
+ acquire,
31
+ resource =>
32
+ Effect.exit(release(resource)).pipe(Effect.map(exit => { finalization = exit; }))
33
+ );
34
+ return yield* Effect.exit(use(resource));
35
+ }));
36
+ return yield* resumeReadOutcome(outcome, finalization);
37
+ });
38
+ }
39
+
40
+ /** Preserve native finalizer rejection precedence and the primary Cause. */
41
+ export function resumeReadOutcome<A>(
42
+ outcome: Exit.Exit<A, ReadEffectFailure>,
43
+ finalization: Exit.Exit<void, ReadEffectFailure>
44
+
45
+ ): Effect.Effect<A, ReadEffectFailure> {
46
+ if (Exit.isFailure(finalization)) {
47
+ const cleanup = Cause.failureOption(finalization.cause);
48
+ if (Option.isSome(cleanup) && Exit.isFailure(outcome)) return Effect.fail(new ReadEffectFailure({ cause: cleanup.value.cause, primaryCause: outcome.cause }));
49
+ return Effect.failCause(finalization.cause);
50
+ }
51
+ return outcome;
52
+ }