@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,639 @@
1
+ import { spawn } from "node:child_process";
2
+ import { fileURLToPath } from "node:url";
3
+
4
+ import {
5
+ APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS,
6
+ encodeApplePhotosContactEvidenceExportResult,
7
+ parseApplePhotosContactEvidenceExportResult,
8
+ } from "./apple-photos-contact-evidence";
9
+ import type {
10
+ ApplePhotosContactEvidenceExportResult,
11
+ } from "./apple-photos-client-types";
12
+ import {
13
+ exportApplePhotosContactEvidence,
14
+ type ApplePhotosLocalSourceDependencies,
15
+ type ApplePhotosLocalSourceProgressEvent,
16
+ } from "./apple-photos-local-source";
17
+ import {
18
+ acquireBeeperMessageLikeMeExportAdmission,
19
+ beginBeeperMessageLikeMeHelperLaunch,
20
+ bindBeeperMessageLikeMeHelperOwner,
21
+ markBeeperMessageLikeMeHelperCleanupUnsafe,
22
+ recoverBeeperMessageLikeMeDirectoryLeases,
23
+ releaseBeeperMessageLikeMeExportAdmission,
24
+ settleBeeperMessageLikeMeHelper,
25
+ type BeeperMessageLikeMeExportAdmission,
26
+ } from "./beeper-message-like-me-recovery";
27
+ import { canonicalJson } from "./canonical-json";
28
+ import { ghostgetStateHome } from "./storage";
29
+
30
+ const APPLE_PHOTOS_WORKER_TIMEOUT_MS = 15 * 60 * 1_000;
31
+ const APPLE_PHOTOS_WORKER_TERMINATION_GRACE_MS = 1_000;
32
+ const APPLE_PHOTOS_WORKER_MAX_STDERR_BYTES = 32 * 1024;
33
+ const APPLE_PHOTOS_WORKER_PROGRESS_PREFIX = "wrench-apple-photos-progress:";
34
+ const APPLE_PHOTOS_WORKER_ERROR_PREFIX = "wrench-apple-photos-error:";
35
+
36
+ type ApplePhotosWorkerSupervisorDependencies = Readonly<{
37
+ argv?: readonly string[];
38
+ timeoutMs?: number;
39
+ terminationGraceMs?: number;
40
+ processGroupAlive?: (pid: number) => boolean;
41
+ afterAbortListenerForTest?: () => void;
42
+ }>;
43
+
44
+ export type ApplePhotosContactEvidenceProgressEvent = Readonly<
45
+ | { phase: "platform-check" }
46
+ | { phase: "private-export-admission" }
47
+ | { phase: "private-export-recovery" }
48
+ | ApplePhotosLocalSourceProgressEvent
49
+ | { phase: "artifact-validation" }
50
+ | { phase: "complete" }
51
+ >;
52
+
53
+ export type ApplePhotosContactEvidenceCliRequest = Readonly<{
54
+ library?: string;
55
+ environment?: Readonly<Record<string, string | undefined>>;
56
+ signal?: AbortSignal;
57
+ dependencies?: ApplePhotosLocalSourceDependencies;
58
+ /** @internal Process-supervisor fault injection. */
59
+ supervisorDependencies?: ApplePhotosWorkerSupervisorDependencies;
60
+ progress?: (event: ApplePhotosContactEvidenceProgressEvent) => void;
61
+ }>;
62
+
63
+ function reportProgress(
64
+ request: ApplePhotosContactEvidenceCliRequest,
65
+ event: ApplePhotosContactEvidenceProgressEvent,
66
+ ): void {
67
+ try {
68
+ request.progress?.(Object.freeze(event));
69
+ } catch {
70
+ // Diagnostics are advisory and cannot change admission or cleanup behavior.
71
+ }
72
+ }
73
+
74
+ class ApplePhotosWorkerIndeterminateError extends Error {}
75
+
76
+ function fail(message: string): never {
77
+ throw new Error(`Apple Photos local source: ${message}`);
78
+ }
79
+
80
+ function abortError(signal: AbortSignal): Error {
81
+ return signal.reason instanceof Error
82
+ ? signal.reason
83
+ : new DOMException("Apple Photos export was cancelled", "AbortError");
84
+ }
85
+
86
+ function defaultWorkerArgv(): readonly string[] {
87
+ const program = [
88
+ `const runtime = await import(${JSON.stringify(import.meta.url)});`,
89
+ "await runtime.runApplePhotosContactEvidenceWorker();",
90
+ ].join("\n");
91
+ const config = fileURLToPath(new URL("./state-helper.bunfig.toml", import.meta.url));
92
+ return Object.freeze([
93
+ process.execPath,
94
+ "--no-env-file",
95
+ "--no-install",
96
+ "--no-macros",
97
+ "--no-addons",
98
+ `--config=${config}`,
99
+ "-e",
100
+ program,
101
+ ]);
102
+ }
103
+
104
+ function minimalWorkerEnvironment(
105
+ environment: Readonly<Record<string, string | undefined>>,
106
+ canonicalStateHome: string,
107
+ ): Readonly<Record<string, string>> {
108
+ const selected: Record<string, string> = Object.create(null);
109
+ for (const key of [
110
+ "TMPDIR",
111
+ "TMP",
112
+ "TEMP",
113
+ "LANG",
114
+ "LC_ALL",
115
+ "TZ",
116
+ ] as const) {
117
+ const value = environment[key];
118
+ if (typeof value === "string" && !value.includes("\0")) selected[key] = value;
119
+ }
120
+ selected.GHOSTGET_STATE_HOME = canonicalStateHome;
121
+ selected.NODE_ENV = "production";
122
+ return Object.freeze(selected);
123
+ }
124
+
125
+ function defaultProcessGroupAlive(pid: number): boolean {
126
+ try {
127
+ process.kill(-pid, 0);
128
+ return true;
129
+ } catch (error) {
130
+ if (typeof error === "object"
131
+ && error !== null
132
+ && "code" in error
133
+ && (error as { readonly code?: unknown }).code === "ESRCH") return false;
134
+ return true;
135
+ }
136
+ }
137
+
138
+ function privateWorkerError(stderr: string): Error {
139
+ const line = stderr.split("\n").find((candidate) =>
140
+ candidate.startsWith(APPLE_PHOTOS_WORKER_ERROR_PREFIX));
141
+ if (line !== undefined) {
142
+ try {
143
+ const decoded = JSON.parse(
144
+ line.slice(APPLE_PHOTOS_WORKER_ERROR_PREFIX.length),
145
+ ) as unknown;
146
+ if (
147
+ typeof decoded === "string"
148
+ && decoded.length > 0
149
+ && Buffer.byteLength(decoded, "utf8") <= 4_096
150
+ && !/[\\/\r\n]/u.test(decoded)
151
+ ) return new Error(decoded);
152
+ } catch {
153
+ // Malformed and path-bearing diagnostics are deliberately collapsed.
154
+ }
155
+ }
156
+ return new Error("Apple Photos local source: private worker failed");
157
+ }
158
+
159
+ function parseWorkerProgress(
160
+ line: string,
161
+ ): ApplePhotosLocalSourceProgressEvent | null {
162
+ if (!line.startsWith(APPLE_PHOTOS_WORKER_PROGRESS_PREFIX)) return null;
163
+ let decoded: unknown;
164
+ try {
165
+ decoded = JSON.parse(
166
+ line.slice(APPLE_PHOTOS_WORKER_PROGRESS_PREFIX.length),
167
+ ) as unknown;
168
+ } catch {
169
+ return null;
170
+ }
171
+ if (typeof decoded !== "object" || decoded === null || Array.isArray(decoded)) {
172
+ return null;
173
+ }
174
+ const record = decoded as Record<string, unknown>;
175
+ const simple = new Set([
176
+ "source-admission",
177
+ "contacts-discovery",
178
+ "photos-capture",
179
+ "evidence-validation",
180
+ "generation-hashing",
181
+ "cleanup",
182
+ ]);
183
+ if (
184
+ typeof record.phase === "string"
185
+ && simple.has(record.phase)
186
+ && Object.keys(record).length === 1
187
+ ) return Object.freeze({
188
+ phase: record.phase,
189
+ } as ApplePhotosLocalSourceProgressEvent);
190
+ if (
191
+ record.phase === "contacts-capture"
192
+ && Object.keys(record).sort().join(",") === "current,phase,total"
193
+ && typeof record.current === "number"
194
+ && Number.isSafeInteger(record.current)
195
+ && record.current >= 1
196
+ && typeof record.total === "number"
197
+ && Number.isSafeInteger(record.total)
198
+ && record.total >= record.current
199
+ && record.total <= APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContactsDatabases
200
+ ) return Object.freeze({
201
+ phase: "contacts-capture",
202
+ current: record.current,
203
+ total: record.total,
204
+ });
205
+ return null;
206
+ }
207
+
208
+ async function superviseApplePhotosWorker(
209
+ request: ApplePhotosContactEvidenceCliRequest,
210
+ environment: Readonly<Record<string, string | undefined>>,
211
+ canonicalStateHome: string,
212
+ deadlineAt: number,
213
+ admission: BeeperMessageLikeMeExportAdmission,
214
+ ): Promise<ApplePhotosContactEvidenceExportResult> {
215
+ if (request.signal?.aborted === true) throw abortError(request.signal);
216
+ const dependencies = request.supervisorDependencies;
217
+ const graceMs = dependencies?.terminationGraceMs
218
+ ?? APPLE_PHOTOS_WORKER_TERMINATION_GRACE_MS;
219
+ if (!Number.isSafeInteger(graceMs) || graceMs < 1 || graceMs > 10_000) {
220
+ return fail("private worker termination grace is invalid");
221
+ }
222
+ const argv = dependencies?.argv === undefined
223
+ ? [...defaultWorkerArgv()]
224
+ : [...dependencies.argv];
225
+ const [command, ...arguments_] = argv;
226
+ if (command === undefined) return fail("private worker command is unavailable");
227
+ beginBeeperMessageLikeMeHelperLaunch(admission);
228
+ let child: ReturnType<typeof spawn>;
229
+ try {
230
+ child = spawn(command, arguments_, {
231
+ cwd: process.cwd(),
232
+ env: minimalWorkerEnvironment(environment, canonicalStateHome),
233
+ detached: true,
234
+ stdio: ["pipe", "pipe", "pipe"],
235
+ });
236
+ } catch (error) {
237
+ try {
238
+ settleBeeperMessageLikeMeHelper(admission);
239
+ } catch {
240
+ try {
241
+ markBeeperMessageLikeMeHelperCleanupUnsafe(admission);
242
+ } catch {
243
+ // The unchanged launching claim remains fail-closed.
244
+ }
245
+ throw new ApplePhotosWorkerIndeterminateError(
246
+ "Apple Photos local source: private worker launch outcome is indeterminate; recovery remains blocked",
247
+ );
248
+ }
249
+ throw error;
250
+ }
251
+ const childStdin = child.stdin!;
252
+ const childStdout = child.stdout!;
253
+ const childStderr = child.stderr!;
254
+ const detachChild = (): void => {
255
+ child.removeAllListeners();
256
+ for (const stream of [childStdin, childStdout, childStderr]) {
257
+ stream.removeAllListeners();
258
+ stream.destroy();
259
+ (stream as unknown as { unref?: () => void }).unref?.();
260
+ }
261
+ child.unref();
262
+ };
263
+ if (child.pid === undefined) {
264
+ return new Promise<ApplePhotosContactEvidenceExportResult>((_resolve, reject) => {
265
+ let settled = false;
266
+ const timer = setTimeout(() => {
267
+ if (settled) return;
268
+ settled = true;
269
+ try {
270
+ markBeeperMessageLikeMeHelperCleanupUnsafe(admission);
271
+ } catch {
272
+ // The unchanged durable launching claim remains fail-closed.
273
+ }
274
+ detachChild();
275
+ reject(new ApplePhotosWorkerIndeterminateError(
276
+ "Apple Photos local source: private worker launch outcome is indeterminate; recovery remains blocked",
277
+ ));
278
+ }, graceMs);
279
+ child.once("error", () => {
280
+ if (settled) return;
281
+ settled = true;
282
+ clearTimeout(timer);
283
+ detachChild();
284
+ try {
285
+ settleBeeperMessageLikeMeHelper(admission);
286
+ } catch {
287
+ try {
288
+ markBeeperMessageLikeMeHelperCleanupUnsafe(admission);
289
+ } catch {
290
+ // The unchanged launching claim remains fail-closed.
291
+ }
292
+ reject(new ApplePhotosWorkerIndeterminateError(
293
+ "Apple Photos local source: private worker launch outcome is indeterminate; recovery remains blocked",
294
+ ));
295
+ return;
296
+ }
297
+ reject(new Error("Apple Photos local source: private worker launch failed"));
298
+ });
299
+ });
300
+ }
301
+ const pid = child.pid;
302
+ const groupAlive = dependencies?.processGroupAlive ?? defaultProcessGroupAlive;
303
+ const ownedGroupAlive = (): boolean => {
304
+ try {
305
+ return groupAlive(pid);
306
+ } catch {
307
+ return true;
308
+ }
309
+ };
310
+ const input = `${canonicalJson({
311
+ ...(request.library === undefined ? {} : { library: request.library }),
312
+ })}\n`;
313
+ return new Promise<ApplePhotosContactEvidenceExportResult>((resolvePromise, rejectPromise) => {
314
+ const stdout: Buffer[] = [];
315
+ const stderr: Buffer[] = [];
316
+ let stdoutBytes = 0;
317
+ let stderrBytes = 0;
318
+ let stdoutClosed = false;
319
+ let stderrClosed = false;
320
+ let childClosed = false;
321
+ let settled = false;
322
+ let terminating = false;
323
+ let pendingFailure: Error | null = null;
324
+ let killTimer: ReturnType<typeof setTimeout> | undefined;
325
+ let proofTimer: ReturnType<typeof setTimeout> | undefined;
326
+ let deadlineTimer: ReturnType<typeof setTimeout>;
327
+ const cleanupListeners = (): void => {
328
+ clearTimeout(deadlineTimer);
329
+ if (killTimer !== undefined) clearTimeout(killTimer);
330
+ if (proofTimer !== undefined) clearTimeout(proofTimer);
331
+ request.signal?.removeEventListener("abort", onAbort);
332
+ };
333
+ const signalGroup = (signal: "SIGTERM" | "SIGKILL"): void => {
334
+ try {
335
+ process.kill(-pid, signal);
336
+ } catch {
337
+ // Child close plus process-group absence are checked separately.
338
+ }
339
+ };
340
+ const failIndeterminate = (): void => {
341
+ if (settled) return;
342
+ settled = true;
343
+ cleanupListeners();
344
+ try {
345
+ markBeeperMessageLikeMeHelperCleanupUnsafe(admission);
346
+ } catch {
347
+ // A stale helper-active claim still retains exact ownership safely.
348
+ }
349
+ detachChild();
350
+ rejectPromise(new ApplePhotosWorkerIndeterminateError(
351
+ "Apple Photos local source: private worker termination is indeterminate; recovery remains blocked",
352
+ ));
353
+ };
354
+ let beginTermination: (reason: Error) => void;
355
+ const maybeFinish = (): void => {
356
+ if (settled || !stdoutClosed || !stderrClosed || !childClosed) return;
357
+ if (ownedGroupAlive()) {
358
+ if (!terminating) beginTermination(
359
+ new Error("Apple Photos local source: private worker process group remained active"),
360
+ );
361
+ return;
362
+ }
363
+ try {
364
+ settleBeeperMessageLikeMeHelper(admission);
365
+ } catch {
366
+ failIndeterminate();
367
+ return;
368
+ }
369
+ settled = true;
370
+ cleanupListeners();
371
+ if (pendingFailure !== null) {
372
+ rejectPromise(pendingFailure);
373
+ return;
374
+ }
375
+ const stderrText = Buffer.concat(stderr).toString("utf8");
376
+ if (child.exitCode !== 0) {
377
+ rejectPromise(privateWorkerError(stderrText));
378
+ return;
379
+ }
380
+ for (const line of stderrText.split("\n")) {
381
+ const event = parseWorkerProgress(line);
382
+ if (event !== null) reportProgress(request, event);
383
+ else if (line.length > 0) {
384
+ rejectPromise(new Error("Apple Photos local source: private worker protocol drifted"));
385
+ return;
386
+ }
387
+ }
388
+ let parsed: unknown;
389
+ try {
390
+ parsed = JSON.parse(Buffer.concat(stdout).toString("utf8")) as unknown;
391
+ } catch {
392
+ rejectPromise(new Error("Apple Photos local source: private worker returned malformed JSON"));
393
+ return;
394
+ }
395
+ try {
396
+ resolvePromise(parseApplePhotosContactEvidenceExportResult(parsed));
397
+ } catch (error) {
398
+ rejectPromise(error);
399
+ }
400
+ };
401
+ beginTermination = (reason: Error): void => {
402
+ pendingFailure ??= reason;
403
+ if (terminating) return;
404
+ terminating = true;
405
+ signalGroup("SIGTERM");
406
+ killTimer = setTimeout(() => {
407
+ signalGroup("SIGKILL");
408
+ proofTimer = setTimeout(() => {
409
+ maybeFinish();
410
+ if (!settled && (ownedGroupAlive() || !childClosed || !stdoutClosed || !stderrClosed)) {
411
+ failIndeterminate();
412
+ }
413
+ }, graceMs);
414
+ }, graceMs);
415
+ };
416
+ const observedSignal = request.signal;
417
+ const onAbort = (): void => beginTermination(abortError(observedSignal!));
418
+ deadlineTimer = setTimeout(() => beginTermination(
419
+ new Error("Apple Photos local source: private worker exceeded the total operation deadline"),
420
+ ), Math.max(0, deadlineAt - performance.now()));
421
+ observedSignal?.addEventListener("abort", onAbort, { once: true });
422
+ try {
423
+ dependencies?.afterAbortListenerForTest?.();
424
+ } catch {
425
+ beginTermination(new Error(
426
+ "Apple Photos local source: private worker abort hook failed",
427
+ ));
428
+ }
429
+ child.on("error", () => beginTermination(
430
+ new Error("Apple Photos local source: private worker launch failed"),
431
+ ));
432
+ childStdout.on("data", (chunk: Buffer) => {
433
+ stdoutBytes += chunk.byteLength;
434
+ if (stdoutBytes > APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumWireBytes) {
435
+ beginTermination(new Error(
436
+ "Apple Photos local source: private worker response exceeded its byte bound",
437
+ ));
438
+ return;
439
+ }
440
+ stdout.push(Buffer.from(chunk));
441
+ });
442
+ childStderr.on("data", (chunk: Buffer) => {
443
+ stderrBytes += chunk.byteLength;
444
+ if (stderrBytes > APPLE_PHOTOS_WORKER_MAX_STDERR_BYTES) {
445
+ beginTermination(new Error(
446
+ "Apple Photos local source: private worker diagnostic exceeded its byte bound",
447
+ ));
448
+ return;
449
+ }
450
+ stderr.push(Buffer.from(chunk));
451
+ });
452
+ childStdout.once("close", () => {
453
+ stdoutClosed = true;
454
+ maybeFinish();
455
+ });
456
+ childStderr.once("close", () => {
457
+ stderrClosed = true;
458
+ maybeFinish();
459
+ });
460
+ child.once("close", () => {
461
+ childClosed = true;
462
+ maybeFinish();
463
+ });
464
+ childStdin.once("error", () => beginTermination(
465
+ new Error("Apple Photos local source: private worker input failed"),
466
+ ));
467
+ try {
468
+ bindBeeperMessageLikeMeHelperOwner(admission, pid);
469
+ } catch {
470
+ beginTermination(new Error(
471
+ "Apple Photos local source: private worker ownership could not be bound safely",
472
+ ));
473
+ return;
474
+ }
475
+ if (observedSignal?.aborted === true) onAbort();
476
+ if (!terminating) childStdin.end(input, "utf8");
477
+ });
478
+ }
479
+
480
+ export async function exportApplePhotosContactEvidenceForCli(
481
+ request: ApplePhotosContactEvidenceCliRequest = {},
482
+ ): Promise<ApplePhotosContactEvidenceExportResult> {
483
+ const timeoutMs = request.supervisorDependencies?.timeoutMs
484
+ ?? APPLE_PHOTOS_WORKER_TIMEOUT_MS;
485
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1) {
486
+ return fail("private worker timeout is invalid");
487
+ }
488
+ const deadlineAt = performance.now() + timeoutMs;
489
+ reportProgress(request, { phase: "platform-check" });
490
+ const platform = request.dependencies?.platform ?? process.platform;
491
+ if (platform !== "darwin") {
492
+ throw new Error("Apple Photos local source: this source requires macOS");
493
+ }
494
+ if (request.signal?.aborted === true) throw abortError(request.signal);
495
+ const environment = request.environment ?? process.env;
496
+ const canonicalStateHome = ghostgetStateHome(environment);
497
+ reportProgress(request, { phase: "private-export-admission" });
498
+ const admission = acquireBeeperMessageLikeMeExportAdmission({ environment });
499
+ let releaseAdmission: boolean = true;
500
+ try {
501
+ reportProgress(request, { phase: "private-export-recovery" });
502
+ if (performance.now() >= deadlineAt) {
503
+ throw new Error("Apple Photos local source: private export exceeded the total operation deadline");
504
+ }
505
+ const result = await superviseApplePhotosWorker(
506
+ request,
507
+ environment,
508
+ canonicalStateHome,
509
+ deadlineAt,
510
+ admission,
511
+ )
512
+ .catch((error: unknown) => {
513
+ if (error instanceof ApplePhotosWorkerIndeterminateError) {
514
+ releaseAdmission = false;
515
+ }
516
+ throw error;
517
+ });
518
+ reportProgress(request, { phase: "artifact-validation" });
519
+ const verified = parseApplePhotosContactEvidenceExportResult(result);
520
+ reportProgress(request, { phase: "complete" });
521
+ return verified;
522
+ } finally {
523
+ if (releaseAdmission) releaseBeeperMessageLikeMeExportAdmission(admission);
524
+ }
525
+ }
526
+
527
+ async function readWorkerInput(): Promise<Readonly<{ library?: string }>> {
528
+ const chunks: Buffer[] = [];
529
+ let bytes = 0;
530
+ for await (const chunk of process.stdin) {
531
+ const value = Buffer.from(chunk as Buffer);
532
+ bytes += value.byteLength;
533
+ if (bytes > 16 * 1024) return fail("private worker request exceeded its byte bound");
534
+ chunks.push(value);
535
+ }
536
+ let decoded: unknown;
537
+ try {
538
+ decoded = JSON.parse(Buffer.concat(chunks).toString("utf8")) as unknown;
539
+ } catch {
540
+ return fail("private worker request was malformed");
541
+ }
542
+ if (typeof decoded !== "object" || decoded === null || Array.isArray(decoded)) {
543
+ return fail("private worker request was malformed");
544
+ }
545
+ const record = decoded as Record<string, unknown>;
546
+ if (
547
+ Object.keys(record).some((key) => key !== "library")
548
+ || (record.library !== undefined && typeof record.library !== "string")
549
+ ) return fail("private worker request was malformed");
550
+ return Object.freeze(
551
+ record.library === undefined ? {} : { library: record.library as string },
552
+ );
553
+ }
554
+
555
+ /** @internal No public argument parser route exposes this worker entry point. */
556
+ export async function runApplePhotosContactEvidenceWorker(): Promise<void> {
557
+ try {
558
+ const input = await readWorkerInput();
559
+ const recovery = await recoverBeeperMessageLikeMeDirectoryLeases({
560
+ environment: process.env,
561
+ });
562
+ if (recovery.active > 0 || recovery.indeterminate > 0) {
563
+ throw new Error(
564
+ "Apple Photos local source: another private export is active or prior recovery is indeterminate",
565
+ );
566
+ }
567
+ const result = await exportApplePhotosContactEvidence({
568
+ ...(input.library === undefined ? {} : { library: input.library }),
569
+ stateEnvironment: process.env,
570
+ progress: (event) => {
571
+ process.stderr.write(
572
+ `${APPLE_PHOTOS_WORKER_PROGRESS_PREFIX}${canonicalJson(event)}\n`,
573
+ );
574
+ },
575
+ });
576
+ process.stdout.write(encodeApplePhotosContactEvidenceExportResult(result));
577
+ } catch (error) {
578
+ const message = error instanceof Error
579
+ && Buffer.byteLength(error.message, "utf8") <= 4_096
580
+ && !/[\\/\r\n]/u.test(error.message)
581
+ ? error.message
582
+ : "Apple Photos local source: private local operation failed";
583
+ process.stderr.write(
584
+ `${APPLE_PHOTOS_WORKER_ERROR_PREFIX}${JSON.stringify(message)}\n`,
585
+ );
586
+ process.exitCode = 1;
587
+ }
588
+ }
589
+
590
+ export function formatApplePhotosContactEvidenceProgress(
591
+ event: ApplePhotosContactEvidenceProgressEvent,
592
+ ): string {
593
+ return event.phase === "contacts-capture"
594
+ ? `apple-photos: contacts-capture ${String(event.current)}-of-${String(event.total)}\n`
595
+ : `apple-photos: ${event.phase}\n`;
596
+ }
597
+
598
+ export function encodeApplePhotosContactEvidenceSummary(
599
+ value: ApplePhotosContactEvidenceExportResult,
600
+ ): string {
601
+ const parsed = parseApplePhotosContactEvidenceExportResult(value);
602
+ return `${canonicalJson({
603
+ schemaVersion: 1,
604
+ format: "wrench.apple-photos-contact-evidence-summary",
605
+ source: {
606
+ id: parsed.output.source.id,
607
+ version: parsed.output.source.version,
608
+ platform: parsed.output.source.platform,
609
+ libraryRealmSha256: parsed.output.source.libraryRealmSha256,
610
+ generationSha256: parsed.output.source.generationSha256,
611
+ },
612
+ qualification: {
613
+ people: parsed.output.scope.people,
614
+ consistency: parsed.output.source.capture.consistency,
615
+ crossDatabaseAtomicity:
616
+ parsed.output.source.capture.crossDatabaseAtomicity,
617
+ remoteSync: parsed.output.completeness.remoteSync,
618
+ biometricDerivedPrivateMetadata:
619
+ "aggregate-counts-included",
620
+ perClusterPrivateMetadata: "full-json-only",
621
+ },
622
+ counts: parsed.output.counts,
623
+ integrity: {
624
+ artifactSha256: parsed.output.integrity.artifactSha256,
625
+ receiptSha256: parsed.receipt.integrity.receiptSha256,
626
+ },
627
+ })}\n`;
628
+ }
629
+
630
+ export function encodeApplePhotosContactEvidenceCliOutput(
631
+ value: ApplePhotosContactEvidenceExportResult,
632
+ json: boolean,
633
+ ): string {
634
+ return json
635
+ ? encodeApplePhotosContactEvidenceExportResult(value)
636
+ : encodeApplePhotosContactEvidenceSummary(value);
637
+ }
638
+
639
+ export { encodeApplePhotosContactEvidenceExportResult };