@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,704 @@
1
+ // @bun
2
+ import {
3
+ GHOSTGET_VERSION
4
+ } from "./index-axwm9b3v.js";
5
+ import {
6
+ canonicalJson,
7
+ sha256
8
+ } from "./index-gwk7rbyj.js";
9
+
10
+ // src/apple-photos-client.ts
11
+ import { spawnSync } from "child_process";
12
+ import { existsSync } from "fs";
13
+ import { isAbsolute, resolve } from "path";
14
+ import { fileURLToPath } from "url";
15
+ import { types as nodeTypes2 } from "util";
16
+
17
+ // src/apple-photos-contact-evidence.ts
18
+ import { randomUUID } from "crypto";
19
+ import { types as nodeTypes } from "util";
20
+ var APPLE_PHOTOS_CONTACT_EVIDENCE_SCHEMA_VERSION = 1;
21
+ var APPLE_PHOTOS_CONTACT_EVIDENCE_FORMAT = "wrench.apple-photos-contact-evidence";
22
+ var APPLE_PHOTOS_CONTACT_EVIDENCE_RECEIPT_FORMAT = "wrench.apple-photos-contact-evidence-export-receipt";
23
+ var APPLE_PHOTOS_LOCAL_SOURCE = Object.freeze({
24
+ id: "apple-photos-local",
25
+ version: "1.0.0"
26
+ });
27
+ var APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS = Object.freeze({
28
+ captureAttemptsPerDatabase: 1,
29
+ maximumPhotosDatabaseBytes: 4 * 1024 * 1024 * 1024,
30
+ maximumContactsDatabases: 32,
31
+ maximumContactsDatabaseBytes: 2 * 1024 * 1024 * 1024,
32
+ maximumDirectoryEntries: 4096,
33
+ maximumContactsSourceDirectories: 256,
34
+ maximumPeople: 1e5,
35
+ maximumContacts: 1e6,
36
+ maximumWireBytes: 128 * 1024 * 1024
37
+ });
38
+ var COMPLETENESS = Object.freeze({
39
+ kind: "bounded-local-observation",
40
+ localPhotos: "one-reviewed-library-database-capture",
41
+ localContacts: "ordered-discovered-address-book-database-captures",
42
+ crossDatabaseAtomicity: "not-asserted",
43
+ remoteSync: "not-asserted",
44
+ unmatchedPeople: "excluded",
45
+ reason: "Exact matches from bounded independent local database captures; cross-database atomicity and remote synchronization state are not asserted."
46
+ });
47
+ var PRIVACY = Object.freeze({
48
+ names: "excluded-from-returned-json",
49
+ localPaths: "excluded-from-returned-json",
50
+ images: "excluded-from-returned-json",
51
+ media: "excluded-from-returned-json",
52
+ locations: "excluded-from-returned-json",
53
+ rawContactData: "excluded-from-returned-json",
54
+ rawPhotosData: "excluded-from-returned-json",
55
+ faceClusterIdentifiers: "included-biometric-derived-private-metadata",
56
+ faceClusterCounts: "included-biometric-derived-private-metadata",
57
+ faceprintTemplates: "excluded-from-returned-json",
58
+ faceCrops: "excluded-from-returned-json",
59
+ unmatchedPeople: "excluded-from-returned-json"
60
+ });
61
+ var SCOPE = Object.freeze({
62
+ people: "exact-zpersonuri-zuniqueid-matches-only",
63
+ faces: "detected-face-links-present-in-photos-capture",
64
+ assets: "distinct-zasset-rows-linked-through-detected-faces"
65
+ });
66
+ function fail(message) {
67
+ throw new Error(`Apple Photos contact evidence: ${message}`);
68
+ }
69
+ function dataRecord(value, label) {
70
+ if (typeof value !== "object" || value === null || Array.isArray(value) || nodeTypes.isProxy(value) || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
71
+ return fail(`${label} must be a plain, non-proxy object`);
72
+ const descriptors = Object.getOwnPropertyDescriptors(value);
73
+ for (const key of Reflect.ownKeys(descriptors)) {
74
+ if (typeof key !== "string")
75
+ return fail(`${label} has a symbol field`);
76
+ const descriptor = descriptors[key];
77
+ if (descriptor === undefined || !descriptor.enumerable || !("value" in descriptor))
78
+ return fail(`${label} must contain only enumerable data properties`);
79
+ }
80
+ return Object.freeze(Object.fromEntries(Object.entries(descriptors).map(([key, descriptor]) => [key, descriptor.value])));
81
+ }
82
+ function dataArray(value, label, maximum) {
83
+ if (!Array.isArray(value) || nodeTypes.isProxy(value) || Object.getPrototypeOf(value) !== Array.prototype)
84
+ return fail(`${label} must be an ordinary, non-proxy array`);
85
+ const descriptors = Object.getOwnPropertyDescriptors(value);
86
+ const lengthDescriptor = Object.getOwnPropertyDescriptor(value, "length");
87
+ if (lengthDescriptor === undefined || !("value" in lengthDescriptor) || typeof lengthDescriptor.value !== "number" || !Number.isSafeInteger(lengthDescriptor.value) || lengthDescriptor.value < 0 || lengthDescriptor.value > maximum)
88
+ return fail(`${label} length exceeds its reviewed bound`);
89
+ const length = lengthDescriptor.value;
90
+ const items = [];
91
+ const keys = Reflect.ownKeys(descriptors);
92
+ if (keys.length !== length + 1 || keys.some((key) => typeof key !== "string")) {
93
+ return fail(`${label} must not have holes, symbols, or named fields`);
94
+ }
95
+ for (let index = 0;index < length; index += 1) {
96
+ const descriptor = descriptors[String(index)];
97
+ if (descriptor === undefined || !descriptor.enumerable || !("value" in descriptor))
98
+ return fail(`${label} must contain dense enumerable data elements`);
99
+ items.push(descriptor.value);
100
+ }
101
+ if (keys.some((key) => key !== "length" && (typeof key !== "string" || !/^(0|[1-9][0-9]*)$/u.test(key)))) {
102
+ return fail(`${label} must not have holes, symbols, or named fields`);
103
+ }
104
+ return Object.freeze(items);
105
+ }
106
+ function exactKeys(record, expected, label) {
107
+ const actual = Object.keys(record).sort();
108
+ const sorted = [...expected].sort();
109
+ if (actual.length !== sorted.length || actual.some((key, index) => key !== sorted[index]))
110
+ return fail(`${label} fields drifted`);
111
+ }
112
+ function exactString(value, expected, label) {
113
+ if (value !== expected)
114
+ return fail(`${label} must equal ${expected}`);
115
+ return expected;
116
+ }
117
+ function digest(value, label) {
118
+ if (typeof value !== "string" || !/^[a-f0-9]{64}$/u.test(value)) {
119
+ return fail(`${label} must be a lowercase SHA-256 digest`);
120
+ }
121
+ return value;
122
+ }
123
+ function timestamp(value, label) {
124
+ if (typeof value !== "string" || value.length > 32 || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(value))
125
+ return fail(`${label} must be a canonical UTC timestamp`);
126
+ const parsed = new Date(value);
127
+ if (!Number.isFinite(parsed.getTime()) || parsed.toISOString() !== value) {
128
+ return fail(`${label} must be a real canonical UTC timestamp`);
129
+ }
130
+ return value;
131
+ }
132
+ function identifier(value, label, maximum) {
133
+ if (typeof value !== "string" || value.length < 1 || Buffer.byteLength(value, "utf8") > maximum || !/^[A-Za-z0-9._:-]+$/u.test(value))
134
+ return fail(`${label} must be a bounded provider identifier`);
135
+ return value;
136
+ }
137
+ function integer(value, label, maximum, minimum = 0) {
138
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < minimum || value > maximum)
139
+ return fail(`${label} must be an integer from ${String(minimum)} through ${String(maximum)}`);
140
+ return value;
141
+ }
142
+ function parseInterval(value, label) {
143
+ const record = dataRecord(value, label);
144
+ exactKeys(record, ["startedAt", "finishedAt"], label);
145
+ return parseIntervalFields(record, label);
146
+ }
147
+ function parseIntervalFields(record, label) {
148
+ const startedAt = timestamp(record.startedAt, `${label}.startedAt`);
149
+ const finishedAt = timestamp(record.finishedAt, `${label}.finishedAt`);
150
+ if (startedAt > finishedAt)
151
+ return fail(`${label} timestamps are reversed`);
152
+ return Object.freeze({ startedAt, finishedAt });
153
+ }
154
+ function parseCapture(value) {
155
+ const record = dataRecord(value, "source.capture");
156
+ exactKeys(record, [
157
+ "startedAt",
158
+ "finishedAt",
159
+ "photos",
160
+ "contacts",
161
+ "consistency",
162
+ "crossDatabaseAtomicity"
163
+ ], "source.capture");
164
+ const enclosing = parseIntervalFields(record, "source.capture");
165
+ const photos = parseInterval(record.photos, "source.capture.photos");
166
+ const contactValues = dataArray(record.contacts, "source.capture.contacts", APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContactsDatabases);
167
+ if (contactValues.length < 1) {
168
+ return fail("source.capture.contacts must contain at least one database interval");
169
+ }
170
+ const contacts = Object.freeze(contactValues.map((item, index) => {
171
+ const label = `source.capture.contacts[${String(index)}]`;
172
+ const contact = dataRecord(item, label);
173
+ exactKeys(contact, ["ordinal", "startedAt", "finishedAt"], label);
174
+ const interval = parseIntervalFields(contact, label);
175
+ const ordinal = integer(contact.ordinal, `${label}.ordinal`, APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContactsDatabases - 1);
176
+ if (ordinal !== index)
177
+ return fail(`${label}.ordinal must equal its array position`);
178
+ return Object.freeze({ ordinal, ...interval });
179
+ }));
180
+ if (enclosing.startedAt > photos.startedAt || photos.finishedAt > enclosing.finishedAt)
181
+ return fail("source.capture.photos must be inside its enclosing interval");
182
+ let priorFinishedAt = photos.finishedAt;
183
+ for (const [index, contact] of contacts.entries()) {
184
+ if (contact.startedAt < priorFinishedAt || contact.finishedAt > enclosing.finishedAt)
185
+ return fail(`source.capture.contacts[${String(index)}] is outside capture order`);
186
+ priorFinishedAt = contact.finishedAt;
187
+ }
188
+ return Object.freeze({
189
+ ...enclosing,
190
+ photos,
191
+ contacts,
192
+ consistency: exactString(record.consistency, "independent-read-transactions", "source.capture.consistency"),
193
+ crossDatabaseAtomicity: exactString(record.crossDatabaseAtomicity, "not-asserted", "source.capture.crossDatabaseAtomicity")
194
+ });
195
+ }
196
+ function parseCompleteness(value) {
197
+ const record = dataRecord(value, "completeness");
198
+ exactKeys(record, Object.keys(COMPLETENESS), "completeness");
199
+ for (const [key, expected] of Object.entries(COMPLETENESS)) {
200
+ exactString(record[key], expected, `completeness.${key}`);
201
+ }
202
+ return COMPLETENESS;
203
+ }
204
+ function parsePrivacy(value) {
205
+ const record = dataRecord(value, "privacy");
206
+ exactKeys(record, Object.keys(PRIVACY), "privacy");
207
+ for (const [key, expected] of Object.entries(PRIVACY)) {
208
+ exactString(record[key], expected, `privacy.${key}`);
209
+ }
210
+ return PRIVACY;
211
+ }
212
+ function parseEvidence(value, index) {
213
+ const label = `evidence[${String(index)}]`;
214
+ const record = dataRecord(value, label);
215
+ exactKeys(record, [
216
+ "photosPersonId",
217
+ "appleContactId",
218
+ "linkedFaceCount",
219
+ "linkedAssetCount",
220
+ "firstAssetAt",
221
+ "lastAssetAt"
222
+ ], label);
223
+ const first = record.firstAssetAt === null ? null : timestamp(record.firstAssetAt, `${label}.firstAssetAt`);
224
+ const last = record.lastAssetAt === null ? null : timestamp(record.lastAssetAt, `${label}.lastAssetAt`);
225
+ if (first === null !== (last === null)) {
226
+ return fail(`${label} asset date bounds must both be null or both be timestamps`);
227
+ }
228
+ if (first !== null && last !== null && first > last) {
229
+ return fail(`${label} asset date bounds are reversed`);
230
+ }
231
+ const linkedFaceCount = integer(record.linkedFaceCount, `${label}.linkedFaceCount`, 1e7);
232
+ const linkedAssetCount = integer(record.linkedAssetCount, `${label}.linkedAssetCount`, 1e7);
233
+ if (linkedAssetCount > linkedFaceCount) {
234
+ return fail(`${label} cannot link more distinct assets than detected faces`);
235
+ }
236
+ if (linkedAssetCount === 0 && (first !== null || last !== null)) {
237
+ return fail(`${label} with zero linked assets must have null date bounds`);
238
+ }
239
+ return Object.freeze({
240
+ photosPersonId: identifier(record.photosPersonId, `${label}.photosPersonId`, 128),
241
+ appleContactId: identifier(record.appleContactId, `${label}.appleContactId`, 512),
242
+ linkedFaceCount,
243
+ linkedAssetCount,
244
+ firstAssetAt: first,
245
+ lastAssetAt: last
246
+ });
247
+ }
248
+ function compareEvidence(left, right) {
249
+ const contact = Buffer.compare(Buffer.from(left.appleContactId, "utf8"), Buffer.from(right.appleContactId, "utf8"));
250
+ if (contact !== 0)
251
+ return contact;
252
+ return Buffer.compare(Buffer.from(left.photosPersonId, "utf8"), Buffer.from(right.photosPersonId, "utf8"));
253
+ }
254
+ function artifactWithoutIntegrity(input) {
255
+ const evidenceInput = dataArray(input.evidence, "evidence", APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumPeople);
256
+ const evidence = Object.freeze(evidenceInput.map((item, index) => parseEvidence(item, index)).sort(compareEvidence));
257
+ if (evidence.length > APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumPeople) {
258
+ return fail("evidence exceeds the matched-person bound");
259
+ }
260
+ const people = new Set;
261
+ const pairs = new Set;
262
+ const contacts = new Set;
263
+ let linkedFaces = 0;
264
+ let linkedAssets = 0;
265
+ for (const item of evidence) {
266
+ if (people.has(item.photosPersonId)) {
267
+ return fail("one Photos person appears more than once");
268
+ }
269
+ const pair = `${item.photosPersonId}\x00${item.appleContactId}`;
270
+ if (pairs.has(pair))
271
+ return fail("one Photos/contact pair appears more than once");
272
+ people.add(item.photosPersonId);
273
+ pairs.add(pair);
274
+ contacts.add(item.appleContactId);
275
+ linkedFaces += item.linkedFaceCount;
276
+ linkedAssets += item.linkedAssetCount;
277
+ if (!Number.isSafeInteger(linkedFaces) || !Number.isSafeInteger(linkedAssets)) {
278
+ return fail("aggregate counts exceed the safe integer range");
279
+ }
280
+ }
281
+ const capture = parseCapture(input.capture);
282
+ const observedAt = timestamp(input.observedAt, "observedAt");
283
+ if (observedAt < capture.startedAt || observedAt > capture.finishedAt) {
284
+ return fail("observedAt must be inside the enclosing capture interval");
285
+ }
286
+ const lastContact = capture.contacts[capture.contacts.length - 1];
287
+ if (observedAt < lastContact.finishedAt) {
288
+ return fail("observedAt must not precede the final database capture");
289
+ }
290
+ return Object.freeze({
291
+ schemaVersion: APPLE_PHOTOS_CONTACT_EVIDENCE_SCHEMA_VERSION,
292
+ format: APPLE_PHOTOS_CONTACT_EVIDENCE_FORMAT,
293
+ transform: Object.freeze({
294
+ id: "apple-photos-person-contact-evidence",
295
+ version: 1
296
+ }),
297
+ source: Object.freeze({
298
+ ...APPLE_PHOTOS_LOCAL_SOURCE,
299
+ platform: "darwin",
300
+ libraryRealmSha256: digest(input.libraryRealmSha256, "source.libraryRealmSha256"),
301
+ generationSha256: digest(input.generationSha256, "source.generationSha256"),
302
+ photosSchemaSha256: digest(input.photosSchemaSha256, "source.photosSchemaSha256"),
303
+ contactsSchemaSha256: digest(input.contactsSchemaSha256, "source.contactsSchemaSha256"),
304
+ capture
305
+ }),
306
+ observedAt,
307
+ scope: SCOPE,
308
+ completeness: COMPLETENESS,
309
+ privacy: PRIVACY,
310
+ counts: Object.freeze({
311
+ matchedPeople: evidence.length,
312
+ uniqueContacts: contacts.size,
313
+ linkedFaces,
314
+ linkedAssets
315
+ }),
316
+ evidence
317
+ });
318
+ }
319
+ function createApplePhotosContactEvidenceArtifact(input) {
320
+ const base = artifactWithoutIntegrity(input);
321
+ return Object.freeze({
322
+ ...base,
323
+ integrity: Object.freeze({
324
+ algorithm: "sha256",
325
+ artifactSha256: sha256(canonicalJson(base))
326
+ })
327
+ });
328
+ }
329
+ function parseArtifactSource(value) {
330
+ const source = dataRecord(value, "source");
331
+ exactKeys(source, [
332
+ "id",
333
+ "version",
334
+ "platform",
335
+ "libraryRealmSha256",
336
+ "generationSha256",
337
+ "photosSchemaSha256",
338
+ "contactsSchemaSha256",
339
+ "capture"
340
+ ], "source");
341
+ return Object.freeze({
342
+ id: exactString(source.id, "apple-photos-local", "source.id"),
343
+ version: exactString(source.version, "1.0.0", "source.version"),
344
+ platform: exactString(source.platform, "darwin", "source.platform"),
345
+ libraryRealmSha256: digest(source.libraryRealmSha256, "source.libraryRealmSha256"),
346
+ generationSha256: digest(source.generationSha256, "source.generationSha256"),
347
+ photosSchemaSha256: digest(source.photosSchemaSha256, "source.photosSchemaSha256"),
348
+ contactsSchemaSha256: digest(source.contactsSchemaSha256, "source.contactsSchemaSha256"),
349
+ capture: parseCapture(source.capture)
350
+ });
351
+ }
352
+ function parseApplePhotosContactEvidenceArtifact(value) {
353
+ const artifact = dataRecord(value, "artifact");
354
+ exactKeys(artifact, [
355
+ "schemaVersion",
356
+ "format",
357
+ "transform",
358
+ "source",
359
+ "observedAt",
360
+ "scope",
361
+ "completeness",
362
+ "privacy",
363
+ "counts",
364
+ "evidence",
365
+ "integrity"
366
+ ], "artifact");
367
+ exactString(artifact.schemaVersion, 1, "artifact.schemaVersion");
368
+ exactString(artifact.format, APPLE_PHOTOS_CONTACT_EVIDENCE_FORMAT, "artifact.format");
369
+ const transform = dataRecord(artifact.transform, "transform");
370
+ exactKeys(transform, ["id", "version"], "transform");
371
+ exactString(transform.id, "apple-photos-person-contact-evidence", "transform.id");
372
+ exactString(transform.version, 1, "transform.version");
373
+ const scope = dataRecord(artifact.scope, "scope");
374
+ exactKeys(scope, Object.keys(SCOPE), "scope");
375
+ for (const [key, expected] of Object.entries(SCOPE)) {
376
+ exactString(scope[key], expected, `scope.${key}`);
377
+ }
378
+ const evidenceValue = artifact.evidence;
379
+ const evidence = dataArray(evidenceValue, "evidence", APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumPeople);
380
+ const source = parseArtifactSource(artifact.source);
381
+ const parsed = createApplePhotosContactEvidenceArtifact({
382
+ observedAt: timestamp(artifact.observedAt, "observedAt"),
383
+ libraryRealmSha256: source.libraryRealmSha256,
384
+ generationSha256: source.generationSha256,
385
+ photosSchemaSha256: source.photosSchemaSha256,
386
+ contactsSchemaSha256: source.contactsSchemaSha256,
387
+ capture: source.capture,
388
+ evidence: evidence.map(parseEvidence)
389
+ });
390
+ const counts = dataRecord(artifact.counts, "counts");
391
+ exactKeys(counts, Object.keys(parsed.counts), "counts");
392
+ for (const [key, expected] of Object.entries(parsed.counts)) {
393
+ if (counts[key] !== expected)
394
+ return fail(`counts.${key} is inconsistent`);
395
+ }
396
+ parseCompleteness(artifact.completeness);
397
+ parsePrivacy(artifact.privacy);
398
+ const integrity = dataRecord(artifact.integrity, "integrity");
399
+ exactKeys(integrity, ["algorithm", "artifactSha256"], "integrity");
400
+ exactString(integrity.algorithm, "sha256", "integrity.algorithm");
401
+ if (digest(integrity.artifactSha256, "integrity.artifactSha256") !== parsed.integrity.artifactSha256)
402
+ return fail("artifact integrity digest does not match its content");
403
+ if (canonicalJson(parsed) !== canonicalJson(value)) {
404
+ return fail("artifact is not in its canonical schema order and representation");
405
+ }
406
+ return parsed;
407
+ }
408
+ function receiptWithoutIntegrity(input, output) {
409
+ const runId = input.runId ?? randomUUID();
410
+ if (!/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u.test(runId)) {
411
+ return fail("runId must be a lowercase UUIDv4");
412
+ }
413
+ const contactsDatabases = integer(input.contactsDatabases, "counts.contactsDatabases", APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContactsDatabases, 1);
414
+ const startedAt = timestamp(input.startedAt, "startedAt");
415
+ const finishedAt = timestamp(input.finishedAt, "finishedAt");
416
+ if (startedAt > finishedAt)
417
+ return fail("receipt timestamps are reversed");
418
+ if (startedAt > output.source.capture.startedAt || output.source.capture.finishedAt > finishedAt)
419
+ return fail("the database capture must be inside the receipt interval");
420
+ if (contactsDatabases !== output.source.capture.contacts.length) {
421
+ return fail("counts.contactsDatabases must match the ordered capture intervals");
422
+ }
423
+ return Object.freeze({
424
+ schemaVersion: 1,
425
+ format: APPLE_PHOTOS_CONTACT_EVIDENCE_RECEIPT_FORMAT,
426
+ runId,
427
+ operation: "apple-photos.export-contact-evidence",
428
+ status: "succeeded",
429
+ transport: "local-sqlite-vacuum-capture",
430
+ implementation: Object.freeze({
431
+ producer: Object.freeze({
432
+ package: "@hraness/ghostget",
433
+ version: GHOSTGET_VERSION
434
+ }),
435
+ source: APPLE_PHOTOS_LOCAL_SOURCE
436
+ }),
437
+ startedAt,
438
+ finishedAt,
439
+ bounds: Object.freeze({
440
+ captureAttemptsPerDatabase: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.captureAttemptsPerDatabase,
441
+ maximumPhotosDatabaseBytes: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumPhotosDatabaseBytes,
442
+ maximumContactsDatabases: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContactsDatabases,
443
+ maximumContactsDatabaseBytes: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContactsDatabaseBytes,
444
+ maximumDirectoryEntries: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumDirectoryEntries,
445
+ maximumContactsSourceDirectories: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContactsSourceDirectories,
446
+ maximumPeople: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumPeople,
447
+ maximumContacts: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContacts
448
+ }),
449
+ source: output.source,
450
+ completeness: output.completeness,
451
+ counts: Object.freeze({
452
+ ...output.counts,
453
+ contactsDatabases
454
+ }),
455
+ output: Object.freeze({
456
+ schemaVersion: output.schemaVersion,
457
+ format: output.format,
458
+ artifactSha256: output.integrity.artifactSha256
459
+ }),
460
+ privacy: output.privacy
461
+ });
462
+ }
463
+ function createApplePhotosContactEvidenceExportResult(input) {
464
+ const output = createApplePhotosContactEvidenceArtifact(input);
465
+ const base = receiptWithoutIntegrity(input, output);
466
+ const receipt = Object.freeze({
467
+ ...base,
468
+ integrity: Object.freeze({
469
+ algorithm: "sha256",
470
+ receiptSha256: sha256(canonicalJson(base))
471
+ })
472
+ });
473
+ return Object.freeze({ receipt, output });
474
+ }
475
+ function parseBounds(value) {
476
+ const bounds = dataRecord(value, "receipt.bounds");
477
+ const expected = {
478
+ captureAttemptsPerDatabase: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.captureAttemptsPerDatabase,
479
+ maximumPhotosDatabaseBytes: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumPhotosDatabaseBytes,
480
+ maximumContactsDatabases: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContactsDatabases,
481
+ maximumContactsDatabaseBytes: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContactsDatabaseBytes,
482
+ maximumDirectoryEntries: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumDirectoryEntries,
483
+ maximumContactsSourceDirectories: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContactsSourceDirectories,
484
+ maximumPeople: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumPeople,
485
+ maximumContacts: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContacts
486
+ };
487
+ exactKeys(bounds, Object.keys(expected), "receipt.bounds");
488
+ for (const [key, expectedValue] of Object.entries(expected)) {
489
+ if (bounds[key] !== expectedValue)
490
+ return fail(`receipt.bounds.${key} drifted`);
491
+ }
492
+ return Object.freeze(expected);
493
+ }
494
+ function parseApplePhotosContactEvidenceExportResult(value) {
495
+ const result = dataRecord(value, "result");
496
+ exactKeys(result, ["receipt", "output"], "result");
497
+ const output = parseApplePhotosContactEvidenceArtifact(result.output);
498
+ const receipt = dataRecord(result.receipt, "receipt");
499
+ exactKeys(receipt, [
500
+ "schemaVersion",
501
+ "format",
502
+ "runId",
503
+ "operation",
504
+ "status",
505
+ "transport",
506
+ "implementation",
507
+ "startedAt",
508
+ "finishedAt",
509
+ "bounds",
510
+ "source",
511
+ "completeness",
512
+ "counts",
513
+ "output",
514
+ "privacy",
515
+ "integrity"
516
+ ], "receipt");
517
+ exactString(receipt.schemaVersion, 1, "receipt.schemaVersion");
518
+ exactString(receipt.format, APPLE_PHOTOS_CONTACT_EVIDENCE_RECEIPT_FORMAT, "receipt.format");
519
+ exactString(receipt.operation, "apple-photos.export-contact-evidence", "receipt.operation");
520
+ exactString(receipt.status, "succeeded", "receipt.status");
521
+ exactString(receipt.transport, "local-sqlite-vacuum-capture", "receipt.transport");
522
+ const implementation = dataRecord(receipt.implementation, "receipt.implementation");
523
+ exactKeys(implementation, ["producer", "source"], "receipt.implementation");
524
+ const producer = dataRecord(implementation.producer, "receipt.implementation.producer");
525
+ exactKeys(producer, ["package", "version"], "receipt.implementation.producer");
526
+ exactString(producer.package, "@hraness/ghostget", "receipt.implementation.producer.package");
527
+ exactString(producer.version, GHOSTGET_VERSION, "receipt.implementation.producer.version");
528
+ const implementationSource = dataRecord(implementation.source, "receipt.implementation.source");
529
+ exactKeys(implementationSource, ["id", "version"], "receipt.implementation.source");
530
+ exactString(implementationSource.id, APPLE_PHOTOS_LOCAL_SOURCE.id, "receipt.implementation.source.id");
531
+ exactString(implementationSource.version, APPLE_PHOTOS_LOCAL_SOURCE.version, "receipt.implementation.source.version");
532
+ parseBounds(receipt.bounds);
533
+ const source = parseArtifactSource(receipt.source);
534
+ if (canonicalJson(source) !== canonicalJson(output.source)) {
535
+ return fail("receipt source does not match the artifact source");
536
+ }
537
+ parseCompleteness(receipt.completeness);
538
+ parsePrivacy(receipt.privacy);
539
+ const counts = dataRecord(receipt.counts, "receipt.counts");
540
+ exactKeys(counts, [...Object.keys(output.counts), "contactsDatabases"], "receipt.counts");
541
+ for (const [key, expected] of Object.entries(output.counts)) {
542
+ if (counts[key] !== expected)
543
+ return fail(`receipt.counts.${key} is inconsistent`);
544
+ }
545
+ const contactsDatabases = integer(counts.contactsDatabases, "receipt.counts.contactsDatabases", APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumContactsDatabases, 1);
546
+ const outputReference = dataRecord(receipt.output, "receipt.output");
547
+ exactKeys(outputReference, ["schemaVersion", "format", "artifactSha256"], "receipt.output");
548
+ exactString(outputReference.schemaVersion, 1, "receipt.output.schemaVersion");
549
+ exactString(outputReference.format, APPLE_PHOTOS_CONTACT_EVIDENCE_FORMAT, "receipt.output.format");
550
+ if (digest(outputReference.artifactSha256, "receipt.output.artifactSha256") !== output.integrity.artifactSha256)
551
+ return fail("receipt output digest does not match the artifact");
552
+ const integrity = dataRecord(receipt.integrity, "receipt.integrity");
553
+ exactKeys(integrity, ["algorithm", "receiptSha256"], "receipt.integrity");
554
+ exactString(integrity.algorithm, "sha256", "receipt.integrity.algorithm");
555
+ const rebuilt = createApplePhotosContactEvidenceExportResult({
556
+ runId: identifier(receipt.runId, "receipt.runId", 64),
557
+ startedAt: timestamp(receipt.startedAt, "receipt.startedAt"),
558
+ finishedAt: timestamp(receipt.finishedAt, "receipt.finishedAt"),
559
+ contactsDatabases,
560
+ observedAt: output.observedAt,
561
+ libraryRealmSha256: output.source.libraryRealmSha256,
562
+ generationSha256: output.source.generationSha256,
563
+ photosSchemaSha256: output.source.photosSchemaSha256,
564
+ contactsSchemaSha256: output.source.contactsSchemaSha256,
565
+ capture: output.source.capture,
566
+ evidence: output.evidence
567
+ });
568
+ if (digest(integrity.receiptSha256, "receipt.integrity.receiptSha256") !== rebuilt.receipt.integrity.receiptSha256)
569
+ return fail("receipt integrity digest does not match its content");
570
+ if (canonicalJson(rebuilt) !== canonicalJson(value)) {
571
+ return fail("result is not in its canonical schema representation");
572
+ }
573
+ return rebuilt;
574
+ }
575
+
576
+ // src/apple-photos-client.ts
577
+ var MAX_STDERR_BYTES = 8 * 1024;
578
+ var PROCESS_TIMEOUT_MS = 15 * 60 * 1000 + 1e4;
579
+ var SOURCE_AUTHORITY_ENVIRONMENT = new Set([
580
+ "HOME",
581
+ "TMPDIR",
582
+ "TMP",
583
+ "TEMP"
584
+ ]);
585
+ function fail2(message) {
586
+ throw new Error(`Ghostget Apple Photos client: ${message}`);
587
+ }
588
+ function cliSourcePath() {
589
+ const besideSource = fileURLToPath(new URL("./cli.ts", import.meta.url));
590
+ if (existsSync(besideSource))
591
+ return besideSource;
592
+ const packagedSource = fileURLToPath(new URL("../src/cli.ts", import.meta.url));
593
+ if (existsSync(packagedSource))
594
+ return packagedSource;
595
+ return fail2("the installed Ghostget CLI source is unavailable");
596
+ }
597
+ function requireBunRuntime() {
598
+ if (typeof process.versions.bun !== "string") {
599
+ return fail2("@hraness/ghostget/apple-photos requires Bun to run the installed Ghostget CLI");
600
+ }
601
+ }
602
+ function dataDescriptors(value, label) {
603
+ if (typeof value !== "object" || value === null || Array.isArray(value) || nodeTypes2.isProxy(value) || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
604
+ return fail2(`${label} must use a plain, non-proxy object`);
605
+ const descriptors = Object.getOwnPropertyDescriptors(value);
606
+ for (const key of Reflect.ownKeys(descriptors)) {
607
+ if (typeof key !== "string")
608
+ return fail2(`${label} has a symbol field`);
609
+ const descriptor = descriptors[key];
610
+ if (descriptor === undefined || !descriptor.enumerable || !("value" in descriptor))
611
+ return fail2(`${label} must contain only enumerable data properties`);
612
+ }
613
+ return descriptors;
614
+ }
615
+ function prepareRequest(value) {
616
+ const descriptors = dataDescriptors(value, "request");
617
+ if (Object.keys(descriptors).some((key) => key !== "library")) {
618
+ return fail2("request contains an unsupported field");
619
+ }
620
+ const library = descriptors.library?.value;
621
+ if (library === undefined)
622
+ return Object.freeze({});
623
+ if (typeof library !== "string" || !isAbsolute(library) || resolve(library) !== library || !library.endsWith(".photoslibrary") || Buffer.byteLength(library, "utf8") > 4096 || /[\0\r\n]/u.test(library))
624
+ return fail2("library must be one normalized absolute .photoslibrary path");
625
+ return Object.freeze({ library });
626
+ }
627
+ function prepareEnvironment(value) {
628
+ const environment = Object.create(null);
629
+ for (const [key, item] of Object.entries(process.env)) {
630
+ if (typeof item === "string")
631
+ environment[key] = item;
632
+ }
633
+ if (value === undefined)
634
+ return Object.freeze(environment);
635
+ const descriptors = dataDescriptors(value, "environment");
636
+ for (const key of Object.keys(descriptors).sort()) {
637
+ if (key.length < 1 || key.includes("=") || key.includes("\x00")) {
638
+ return fail2("environment name is malformed");
639
+ }
640
+ const item = descriptors[key].value;
641
+ if (SOURCE_AUTHORITY_ENVIRONMENT.has(key) && item !== environment[key])
642
+ return fail2(`${key} cannot override Apple Photos source authority`);
643
+ if (item === undefined)
644
+ delete environment[key];
645
+ else if (typeof item !== "string" || item.includes("\x00")) {
646
+ return fail2("environment value is malformed");
647
+ } else
648
+ environment[key] = item;
649
+ }
650
+ return Object.freeze(environment);
651
+ }
652
+ function prepareOptions(value) {
653
+ const descriptors = dataDescriptors(value, "options");
654
+ if (Object.keys(descriptors).some((key) => key !== "environment")) {
655
+ return fail2("options contain an unsupported field");
656
+ }
657
+ return prepareEnvironment(descriptors.environment?.value);
658
+ }
659
+ function boundedError(value) {
660
+ const text = typeof value === "string" ? value.trim() : "";
661
+ const bytes = Buffer.from(text, "utf8");
662
+ if (bytes.byteLength <= MAX_STDERR_BYTES)
663
+ return text;
664
+ return `${bytes.subarray(0, MAX_STDERR_BYTES).toString("utf8").trim()}\u2026`;
665
+ }
666
+ function exportApplePhotosContactEvidenceSync(requestValue = {}, optionsValue = {}) {
667
+ requireBunRuntime();
668
+ const request = prepareRequest(requestValue);
669
+ const environment = prepareOptions(optionsValue);
670
+ const result = spawnSync(process.execPath, [
671
+ cliSourcePath(),
672
+ "apple-photos",
673
+ "export-contact-evidence",
674
+ ...request.library === undefined ? [] : ["--library", request.library],
675
+ "--json"
676
+ ], {
677
+ cwd: process.cwd(),
678
+ env: environment,
679
+ encoding: "utf8",
680
+ maxBuffer: APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumWireBytes,
681
+ timeout: PROCESS_TIMEOUT_MS,
682
+ stdio: ["ignore", "pipe", "pipe"]
683
+ });
684
+ if (result.error !== undefined)
685
+ return fail2("export process could not complete");
686
+ if (result.status !== 0 || typeof result.stdout !== "string") {
687
+ const stderr = boundedError(result.stderr);
688
+ return fail2(stderr.length === 0 ? "export process failed" : stderr);
689
+ }
690
+ if (Buffer.byteLength(result.stdout, "utf8") > APPLE_PHOTOS_CONTACT_EVIDENCE_LIMITS.maximumWireBytes)
691
+ return fail2("export response exceeded its byte bound");
692
+ let parsed;
693
+ try {
694
+ parsed = JSON.parse(result.stdout);
695
+ } catch {
696
+ return fail2("export response was not JSON");
697
+ }
698
+ return parseApplePhotosContactEvidenceExportResult(parsed);
699
+ }
700
+ export {
701
+ parseApplePhotosContactEvidenceExportResult,
702
+ parseApplePhotosContactEvidenceArtifact,
703
+ exportApplePhotosContactEvidenceSync
704
+ };