@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,76 @@
1
+ import { OperationDeadlineError } from "../operation-deadline";
2
+ import { readFailureProjection, type ReadFailureProjection } from "../web-session-execution";
3
+ import {
4
+ LinkedInFeedBrowserFailure,
5
+ LinkedInFeedBrowserResponseRejectedError,
6
+ } from "./linkedin-web-feed-browser";
7
+
8
+ export type LinkedInProfileActivityStage = "identity" | "binding" | "page" | "projection";
9
+
10
+ /** Only the account-binding producer creates this category. Native wording is
11
+ * diagnostic data and cannot authorize account mismatch or auth repair. */
12
+ export class LinkedInProfileActivityIdentityMismatch extends Error {
13
+ constructor(cause: unknown) {
14
+ super("LinkedIn current member no longer matches the bound auth subject", { cause });
15
+ this.name = "LinkedInProfileActivityIdentityMismatch";
16
+ }
17
+ }
18
+
19
+ export function linkedInProfileActivityReadFailure(
20
+ error: unknown,
21
+ stage: LinkedInProfileActivityStage,
22
+ ): ReadFailureProjection {
23
+ let deadlineCause: unknown = error;
24
+ for (let depth = 0; depth < 8 && deadlineCause !== undefined; depth += 1) {
25
+ if (deadlineCause instanceof OperationDeadlineError) {
26
+ return readFailureProjection(deadlineCause.failure === "timed-out" ? "operation-timeout" : "contract-drift");
27
+ }
28
+ deadlineCause = deadlineCause instanceof Error ? deadlineCause.cause : undefined;
29
+ }
30
+ let current: unknown = error;
31
+ for (let depth = 0; depth < 8 && current !== undefined; depth += 1) {
32
+ if (current instanceof LinkedInProfileActivityIdentityMismatch) return readFailureProjection("account-mismatch");
33
+ if (current instanceof LinkedInFeedBrowserResponseRejectedError) {
34
+ if (current.status === 401 || current.status === 403) return readFailureProjection("auth-repair-required");
35
+ if (current.status === 429) return readFailureProjection("provider-throttled");
36
+ if (current.status === 302 || current.status === 408 || current.status >= 500) return readFailureProjection("provider-temporary");
37
+ if (current.status === 404 && stage !== "identity") return readFailureProjection("target-unavailable");
38
+ return readFailureProjection("contract-drift");
39
+ }
40
+ if (current instanceof LinkedInFeedBrowserFailure) {
41
+ if (current.category === "authwall" || current.category === "session-cookie") return readFailureProjection("auth-repair-required");
42
+ if (current.category === "startup" || current.category === "execution-context" || current.category === "provider-fetch") {
43
+ return readFailureProjection("provider-temporary");
44
+ }
45
+ return readFailureProjection("contract-drift");
46
+ }
47
+ current = current instanceof Error ? current.cause : undefined;
48
+ }
49
+ return readFailureProjection("contract-drift");
50
+ }
51
+
52
+ const REQUEST_STAGE: Readonly<Record<LinkedInProfileActivityStage, string>> = {
53
+ identity: "contained-browser signed-in identity preflight",
54
+ binding: "contained-browser profile-activity query observation",
55
+ page: "contained-browser profile-activity page read",
56
+ projection: "exact profile-activity projection",
57
+ };
58
+
59
+ export function linkedInProfileActivityDiagnostic(error: unknown, stage: LinkedInProfileActivityStage): string {
60
+ let category = stage === "binding" ? "live query observation"
61
+ : stage === "projection" ? "exact page projection" : "reviewed response projection";
62
+ let current: unknown = error;
63
+ for (let depth = 0; depth < 8 && current !== undefined; depth += 1) {
64
+ if (current instanceof LinkedInProfileActivityIdentityMismatch) {
65
+ category = "signed-in account binding";
66
+ break;
67
+ }
68
+ if (current instanceof LinkedInFeedBrowserFailure) {
69
+ if (current.category === "authwall") category = "signed-out authwall";
70
+ if (current.category === "session-cookie") category = "signed-in session cookie";
71
+ break;
72
+ }
73
+ current = current instanceof Error ? current.cause : undefined;
74
+ }
75
+ return `LinkedIn profile-activity read failed during ${REQUEST_STAGE[stage]} at ${category}; no remote write occurred`;
76
+ }
@@ -0,0 +1,41 @@
1
+ import * as Context from "effect/Context";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Layer from "effect/Layer";
4
+ import { ReadEffectFailure, readAttempt } from "../read-effect";
5
+ import { readNative } from "../read-effect-platform";
6
+ import type { LinkedInFeedBrowserTransport } from "./linkedin-web-feed-browser";
7
+ import { LinkedInProfileActivityIdentityMismatch } from "./linkedin-profile-activity-failure";
8
+
9
+ export type LinkedInProfileActivityIdentity = { readonly subject: string };
10
+
11
+ export type LinkedInProfileActivityNative = {
12
+ readonly openBrowser: () => Promise<LinkedInFeedBrowserTransport>;
13
+ readonly decodeIdentity: (value: unknown) => LinkedInProfileActivityIdentity;
14
+ readonly bindIdentity: (identity: LinkedInProfileActivityIdentity) => string;
15
+ readonly observedAt: () => string;
16
+ };
17
+
18
+ function platform(ports: LinkedInProfileActivityNative) {
19
+ return {
20
+ openBrowser: readNative(ports.openBrowser).pipe(Effect.uninterruptible),
21
+ identity: (browser: LinkedInFeedBrowserTransport) => readNative(() => browser.currentIdentityResponse()).pipe(
22
+ Effect.uninterruptible,
23
+ Effect.flatMap(value => readAttempt(() => ports.decodeIdentity(value))),
24
+ ),
25
+ bindIdentity: (identity: LinkedInProfileActivityIdentity) => readAttempt(() => ports.bindIdentity(identity)).pipe(
26
+ Effect.mapError(error => new ReadEffectFailure({ cause: new LinkedInProfileActivityIdentityMismatch(error.cause) })),
27
+ ),
28
+ binding: (browser: LinkedInFeedBrowserTransport, slug: string) => readNative(() => browser.resolveProfileActivityBinding(slug)).pipe(Effect.uninterruptible),
29
+ page: (browser: LinkedInFeedBrowserTransport, count: number, start: number) => readNative(() => browser.readProfileActivityPage({ count, start })).pipe(Effect.uninterruptible),
30
+ observedAt: readAttempt(ports.observedAt),
31
+ closeBrowser: (browser: LinkedInFeedBrowserTransport) => readNative(() => browser.close()).pipe(Effect.uninterruptible),
32
+ };
33
+ }
34
+
35
+ export class LinkedInProfileActivityPlatform extends Context.Tag("wrench/LinkedInProfileActivityPlatform/v1")<
36
+ LinkedInProfileActivityPlatform,
37
+ ReturnType<typeof platform>
38
+ >() { }
39
+
40
+ export const LinkedInProfileActivityPlatformLive = (ports: LinkedInProfileActivityNative): Layer.Layer<LinkedInProfileActivityPlatform> =>
41
+ Layer.succeed(LinkedInProfileActivityPlatform, platform(ports));
@@ -0,0 +1,67 @@
1
+ import * as Effect from "effect/Effect";
2
+ import { PreservedBrowserArtifactsError } from "../browser";
3
+ import { readAttempt, type ReadEffectFailure, withReadResource } from "../read-effect";
4
+ import type { WebSessionExecution } from "../web-session-execution";
5
+ import { LinkedInProfileActivityPlatform } from "./linkedin-profile-activity-platform";
6
+ import {
7
+ linkedInProfileActivityDiagnostic,
8
+ linkedInProfileActivityReadFailure,
9
+ type LinkedInProfileActivityStage,
10
+ } from "./linkedin-profile-activity-failure";
11
+ import {
12
+ projectLinkedInProfileActivityPage,
13
+ type LinkedInProfileActivityTarget,
14
+ } from "./linkedin-web-feed";
15
+
16
+ export function linkedInProfileActivityReadProgram(
17
+ target: LinkedInProfileActivityTarget,
18
+ start: number,
19
+ limit: number,
20
+ ): Effect.Effect<WebSessionExecution, ReadEffectFailure, LinkedInProfileActivityPlatform> {
21
+ return Effect.gen(function*() {
22
+ const platform = yield* LinkedInProfileActivityPlatform;
23
+ let stage: LinkedInProfileActivityStage = "identity";
24
+ let closeFailed = false;
25
+ return yield* withReadResource(
26
+ platform.openBrowser,
27
+ browser => Effect.gen(function*() {
28
+ const identity = yield* platform.identity(browser);
29
+ yield* platform.bindIdentity(identity);
30
+ stage = "binding";
31
+ const binding = yield* platform.binding(browser, target.slug);
32
+ stage = "page";
33
+ const response = yield* platform.page(browser, limit, start);
34
+ stage = "projection";
35
+ const observedAt = yield* platform.observedAt;
36
+ const output = yield* readAttempt(() => projectLinkedInProfileActivityPage({
37
+ response,
38
+ target,
39
+ profileUrn: binding.profileUrn,
40
+ queryId: binding.queryId,
41
+ limit,
42
+ start,
43
+ observedAt,
44
+ }));
45
+ return {
46
+ status: "succeeded" as const,
47
+ output,
48
+ finalUrl: target.activityUrl,
49
+ dispatchStarted: false,
50
+ dispatch: { planned: 0, started: 0, verified: 0 },
51
+ };
52
+ }),
53
+ browser => platform.closeBrowser(browser).pipe(Effect.tapError(() => Effect.sync(() => { closeFailed = true; }))),
54
+ ).pipe(Effect.catchTag("ReadEffectFailure", error => {
55
+ if (closeFailed || error.cause instanceof PreservedBrowserArtifactsError) return Effect.fail(error);
56
+ return Effect.succeed({
57
+ status: "failed" as const,
58
+ output: null,
59
+ finalUrl: target.activityUrl,
60
+ dispatchStarted: false,
61
+ dispatch: { planned: 0, started: 0, verified: 0 },
62
+ error: linkedInProfileActivityDiagnostic(error.cause, stage),
63
+ readFailure: linkedInProfileActivityReadFailure(error.cause, stage),
64
+ });
65
+ }));
66
+ });
67
+ }
@@ -0,0 +1,52 @@
1
+ import { OperationDeadlineError } from "../operation-deadline";
2
+ import { readFailureProjection, type ReadFailureProjection } from "../web-session-execution";
3
+ import {
4
+ WebSessionAuthStateError,
5
+ WebSessionReadTransportError,
6
+ WebSessionResponseRejectedError
7
+ } from "../web-session-read-errors";
8
+ import {
9
+ LinkedInProfileBrowserFailure,
10
+ LinkedInProfileBrowserResponseRejectedError
11
+ } from "./linkedin-web-profile-browser";
12
+
13
+ /** Typed provider metadata owns authority/retry decisions. Message text is never
14
+ * accepted as evidence for a session switch, account mismatch or retry. */
15
+ export function linkedInProfileReadFailure(error: unknown): ReadFailureProjection {
16
+ let current = error;
17
+ for (let depth = 0; depth < 8 && current instanceof Error; depth += 1) {
18
+ if (current instanceof OperationDeadlineError) return readFailureProjection(current.failure === "timed-out" ? "operation-timeout" : "contract-drift");
19
+ current = current.cause;
20
+ }
21
+ current = error;
22
+ for (let depth = 0; depth < 8 && current instanceof Error; depth += 1) {
23
+ if (current instanceof LinkedInProfileBrowserResponseRejectedError
24
+ || current instanceof WebSessionResponseRejectedError) {
25
+ const status = current.status;
26
+ return readFailureProjection(status === 401 || status === 403
27
+ ? "auth-repair-required"
28
+ : status === 429
29
+ ? "provider-throttled"
30
+ : status === 302 || status === 408 || status >= 500 ? "provider-temporary" : "contract-drift");
31
+ }
32
+ if (current instanceof WebSessionAuthStateError) return readFailureProjection("auth-repair-required");
33
+ if (current instanceof WebSessionReadTransportError) return readFailureProjection("provider-temporary");
34
+ if (current instanceof LinkedInProfileBrowserFailure) return readFailureProjection(current.category === "authwall" || current.category === "session-cookie"
35
+ ? "auth-repair-required"
36
+ : current.category === "startup" || current.category === "execution-context"
37
+ || current.category === "provider-fetch"
38
+ ? "provider-temporary"
39
+ : "contract-drift");
40
+ current = current.cause;
41
+ }
42
+ return readFailureProjection("contract-drift");
43
+ }
44
+
45
+
46
+ /** Only a rejected native identity response can authorize the reviewed fallback. */
47
+ export function linkedInProfileIdentityAllowsBrowserFallback(cause: unknown): boolean {
48
+ return cause instanceof WebSessionResponseRejectedError
49
+ && [302, 401, 403].includes(cause.status)
50
+ && /^(?:missing|[A-Za-z0-9!#$&^_.+-]+\/[A-Za-z0-9!#$&^_.+-]+)$/u.test(cause.contentType ?? "missing")
51
+ && (cause.contentType ?? "missing").length <= 128;
52
+ }
@@ -0,0 +1,53 @@
1
+ import * as Context from "effect/Context";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Layer from "effect/Layer";
4
+ import { ReadEffectFailure, readAttempt } from "../read-effect";
5
+ import type { WebSessionClient } from "../web-session-client";
6
+ import type { LinkedInProfileBrowserTransport } from "./linkedin-web-profile-browser";
7
+
8
+ export type LinkedInSelfIdentity = {
9
+ readonly subject: string;
10
+ readonly publicIdentifier: string | null;
11
+ };
12
+
13
+ export type LinkedInSelfNative = {
14
+ readonly openBrowser: () => Promise<LinkedInProfileBrowserTransport>;
15
+ readonly openDirect: () => Promise<WebSessionClient>;
16
+ readonly directIdentity: (client: WebSessionClient) => Promise<LinkedInSelfIdentity>;
17
+ readonly decodeIdentity: (value: unknown) => LinkedInSelfIdentity;
18
+ readonly bindIdentity: (identity: LinkedInSelfIdentity) => string;
19
+ readonly readProfile: (client: WebSessionClient, url: string) => Promise<string>;
20
+ readonly readConnections: (client: WebSessionClient, url: string) => Promise<string>;
21
+ readonly observedAt: () => string;
22
+ };
23
+
24
+ const native = <A>(work: () => Promise<A>): Effect.Effect<A, ReadEffectFailure> =>
25
+ Effect.tryPromise({ try: work, catch: cause => new ReadEffectFailure({ cause }) });
26
+
27
+ function platform(ports: LinkedInSelfNative) {
28
+ return {
29
+ openBrowser: native(ports.openBrowser),
30
+ closeBrowser: (browser: LinkedInProfileBrowserTransport) => native(() => browser.close()),
31
+ browserIdentity: (browser: LinkedInProfileBrowserTransport) => native(() => browser.currentIdentityResponse()).pipe(Effect.flatMap(value => readAttempt(() => ports.decodeIdentity(value)))),
32
+ openDirect: native(ports.openDirect),
33
+ directIdentity: (client: WebSessionClient) => native(() => ports.directIdentity(client)),
34
+ bindIdentity: (identity: LinkedInSelfIdentity) => readAttempt(() => ports.bindIdentity(identity)),
35
+ browserProfile: (
36
+ browser: LinkedInProfileBrowserTransport,
37
+ url: string
38
+
39
+ ) => native(() => browser.readProfileHtml(url)),
40
+ browserConnections: (
41
+ browser: LinkedInProfileBrowserTransport,
42
+ url: string
43
+
44
+ ) => native(() => browser.readConnectionsHtml(url)),
45
+ directProfile: (client: WebSessionClient, url: string) => native(() => ports.readProfile(client, url)),
46
+ directConnections: (client: WebSessionClient, url: string) => native(() => ports.readConnections(client, url)),
47
+ observedAt: readAttempt(ports.observedAt),
48
+ };
49
+ }
50
+
51
+ export class LinkedInSelfPlatform extends Context.Tag("wrench/LinkedInSelfPlatform/v1")<LinkedInSelfPlatform, ReturnType<typeof platform>>() { }
52
+
53
+ export const LinkedInSelfPlatformLive = (ports: LinkedInSelfNative): Layer.Layer<LinkedInSelfPlatform> => Layer.succeed(LinkedInSelfPlatform, platform(ports));
@@ -0,0 +1,122 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Either from "effect/Either";
3
+ import { PreservedBrowserArtifactsError } from "../browser";
4
+ import { readAttempt, type ReadEffectFailure, withReadResource } from "../read-effect";
5
+ import {
6
+ readFailureProjection,
7
+ type WebSessionExecution
8
+ } from "../web-session-execution";
9
+ import { LinkedInSelfPlatform, type LinkedInSelfIdentity } from "./linkedin-self-platform";
10
+ import { projectLinkedInPersonalProfileStats, type LinkedInProfileTarget } from "./linkedin-web";
11
+
12
+ import {
13
+ linkedInProfileIdentityAllowsBrowserFallback,
14
+ linkedInProfileReadFailure as linkedInSelfReadFailure
15
+ } from "./linkedin-read-failure";
16
+
17
+ export { linkedInSelfReadFailure };
18
+
19
+ export function linkedInSelfReadProgram(
20
+ target: LinkedInProfileTarget,
21
+ includeConnections: boolean,
22
+ preferBrowser: boolean,
23
+ diagnostic: (error: unknown, requestStage: string) => string
24
+
25
+ ): Effect.Effect<WebSessionExecution, ReadEffectFailure, LinkedInSelfPlatform> {
26
+ return Effect.gen(function*() {
27
+ const platform = yield* LinkedInSelfPlatform;
28
+ let requestStage = preferBrowser
29
+ ? "contained-browser signed-in identity preflight"
30
+ : "signed-in identity preflight";
31
+ let identityMismatch = false;
32
+ const report = (error: ReadEffectFailure): Effect.Effect<WebSessionExecution, ReadEffectFailure> => {
33
+ if (error.cause instanceof PreservedBrowserArtifactsError) return Effect.fail(error);
34
+ return Effect.succeed({
35
+ status: "failed",
36
+ output: null,
37
+ finalUrl: target.url,
38
+ dispatchStarted: false,
39
+ dispatch: { planned: 0, started: 0, verified: 0 },
40
+ error: diagnostic(error.cause, requestStage),
41
+ readFailure: identityMismatch
42
+ ? readFailureProjection("account-mismatch")
43
+ : linkedInSelfReadFailure(error.cause)
44
+ });
45
+ };
46
+ const readBoundProfile = (
47
+ identity: LinkedInSelfIdentity,
48
+ browser: boolean,
49
+ profile: Effect.Effect<string, ReadEffectFailure>,
50
+ connections: Effect.Effect<string, ReadEffectFailure>
51
+
52
+ ): Effect.Effect<WebSessionExecution, ReadEffectFailure> => Effect.gen(function*() {
53
+ const subject = yield* platform.bindIdentity(identity).pipe(Effect.tapError(() => Effect.sync(() => { identityMismatch = true; })));
54
+ yield* readAttempt(() => {
55
+ if (identity.publicIdentifier === null) throw new Error("LinkedIn current member omitted its bound public profile identifier");
56
+ if (identity.publicIdentifier !== target.slug) {
57
+ identityMismatch = true;
58
+ throw new Error("LinkedIn current member public profile identifier does not match the requested profile URL");
59
+ }
60
+ });
61
+ requestStage = browser ? "contained-browser public self-profile page read" : "public self-profile page read";
62
+ const profileHtml = yield* profile;
63
+ let connectionsHtml: string | null = null;
64
+ if (includeConnections) {
65
+ requestStage = browser
66
+ ? "contained-browser private My Network connections page read"
67
+ : "private My Network connections page read";
68
+ connectionsHtml = yield* connections;
69
+ }
70
+ requestStage = "exact metric projection";
71
+ const observedAt = yield* platform.observedAt;
72
+ const output = yield* readAttempt(() => projectLinkedInPersonalProfileStats({
73
+ profileHtml,
74
+ connectionsHtml,
75
+ profileUrl: target.url,
76
+ expectedSubject: subject,
77
+ expectedPublicIdentifier: identity.publicIdentifier,
78
+ observedAt
79
+ }));
80
+ return {
81
+ status: "succeeded",
82
+ output,
83
+ finalUrl: target.url,
84
+ dispatchStarted: false,
85
+ dispatch: { planned: 0, started: 0, verified: 0 }
86
+ };
87
+ });
88
+ const browserRead = (): Effect.Effect<WebSessionExecution, ReadEffectFailure> => {
89
+ let closeFailed = false;
90
+ return withReadResource(
91
+ platform.openBrowser,
92
+ browser => platform.browserIdentity(browser).pipe(Effect.flatMap(identity => readBoundProfile(
93
+ identity,
94
+ true,
95
+ platform.browserProfile(browser, target.url),
96
+ platform.browserConnections(browser, target.url)
97
+ ))),
98
+ browser => platform.closeBrowser(browser).pipe(Effect.tapError(() => Effect.sync(() => { closeFailed = true; }))),
99
+ ).pipe(Effect.catchTag("ReadEffectFailure", error => closeFailed ? Effect.fail(error) : report(error)));
100
+ };
101
+ if (preferBrowser) return yield* browserRead();
102
+ // A native close rejection must escape the safe read projection just as the
103
+ // previous finally block did. Only acquisition/operation errors are mapped.
104
+ const direct = yield* Effect.either(platform.openDirect);
105
+ if (Either.isLeft(direct)) return yield* report(direct.left);
106
+ const identity = yield* Effect.either(platform.directIdentity(direct.right));
107
+ if (Either.isLeft(identity)) {
108
+ const cause = identity.left.cause;
109
+ if (linkedInProfileIdentityAllowsBrowserFallback(cause)) {
110
+ requestStage = "contained-browser signed-in identity preflight";
111
+ return yield* browserRead();
112
+ }
113
+ return yield* report(identity.left);
114
+ }
115
+ return yield* readBoundProfile(
116
+ identity.right,
117
+ false,
118
+ platform.directProfile(direct.right, target.url),
119
+ platform.directConnections(direct.right, target.url)
120
+ ).pipe(Effect.catchTag("ReadEffectFailure", report));
121
+ });
122
+ }