@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,782 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ chmodSync,
4
+ closeSync,
5
+ constants,
6
+ fchmodSync,
7
+ fstatSync,
8
+ fsyncSync,
9
+ lstatSync,
10
+ mkdirSync,
11
+ openSync,
12
+ readSync,
13
+ unlinkSync,
14
+ writeSync,
15
+ } from "node:fs";
16
+ import { tmpdir } from "node:os";
17
+ import { join } from "node:path";
18
+
19
+ import { canonicalJson, sha256 } from "./canonical-json";
20
+ import type { ProcessOwnerIdentity } from "./process-identity";
21
+
22
+ export const DERIVATION_GUARD_EXTENSION_DIRECTORY = "network-guard-extension";
23
+ export const DERIVATION_GUARD_PROXY_CONFIG = "network-proxy.json";
24
+ export const DERIVATION_GUARD_PROXY_READY = "network-proxy-ready.json";
25
+ /** Legacy schema-v1 location inside AGENT_BROWSER_SOCKET_DIR. */
26
+ export const DERIVATION_GUARD_CONTROL_SOCKET = "network-proxy-control.sock";
27
+
28
+ export const derivationGuardResourceTypes = Object.freeze([
29
+ "main_frame",
30
+ "sub_frame",
31
+ "stylesheet",
32
+ "script",
33
+ "image",
34
+ "font",
35
+ "object",
36
+ "xmlhttprequest",
37
+ "ping",
38
+ "csp_report",
39
+ "media",
40
+ "websocket",
41
+ "webtransport",
42
+ "webbundle",
43
+ "other",
44
+ ] as const);
45
+
46
+ const extensionPublicKey =
47
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8IQKI/uEK3ld2F8VY/ijbVaaT9uIILnZWiqOpI8K/n6/I6RKAm+QgBDjfq+mnvArr4uIFdkNm60utfLZ+bc6iFs3W62og1O7kTqohzkWc8VLwCIXJ4rMfQN2GFh+CSYu122uteGau87T1iUZtIc+k5oocpXiFlKDO39ZacV5v2zZLwu6ifz8r3XmWo1Knhhez0TzlsMpgHY6O7oQb3UFzjU4loZo+LpBTzObov05czdXAVHoVWE7rdRUxNeVHQrla0oY/MBh87bpd2rrEqG8K/RgkXE3LOZrdGRK2mqYNQC0eJgwIRxnpyD7QxAifs2r1KAPQeCjmgkscAR6T8m6gwIDAQAB";
48
+ export const DERIVATION_GUARD_EXTENSION_ID = "gjhalpeeegljfdmfkoilmojkfehhpgbm";
49
+ const extensionFileNames = Object.freeze([
50
+ "manifest.json",
51
+ "rules.json",
52
+ "readiness.js",
53
+ ] as const);
54
+ const digestPattern = /^[a-f0-9]{64}$/u;
55
+ const unsignedIntegerPattern = /^\d{1,40}$/u;
56
+ const derivationIdPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
57
+
58
+ /**
59
+ * Keep Ghostget's authenticated proxy control endpoint outside agent-browser's
60
+ * disposable socket namespace. The UUID-bounded name also stays below Unix
61
+ * domain socket path limits on the supported macOS and Linux hosts.
62
+ */
63
+ export function derivationGuardControlSocketPath(derivationId: string): string {
64
+ if (!derivationIdPattern.test(derivationId)) {
65
+ throw new Error("derivation proxy control identity is malformed");
66
+ }
67
+ const root = process.platform === "win32" ? tmpdir() : "/tmp";
68
+ // Do not use a `.sock` suffix: agent-browser treats orphan `*.sock` files
69
+ // in its configured socket root as disposable daemon endpoints.
70
+ return join(root, `io-wrench-dp-${derivationId}.ctl`);
71
+ }
72
+
73
+ export type GuardDirectoryIdentity = {
74
+ readonly device: string;
75
+ readonly inode: string;
76
+ };
77
+
78
+ export type GuardPrivateFileEvidence = GuardDirectoryIdentity & {
79
+ readonly byteLength: number;
80
+ readonly sha256: string;
81
+ };
82
+
83
+ export type DerivationGuardExtension = {
84
+ readonly id: typeof DERIVATION_GUARD_EXTENSION_ID;
85
+ readonly directoryIdentity: GuardDirectoryIdentity;
86
+ readonly files: Readonly<Record<(typeof extensionFileNames)[number], GuardPrivateFileEvidence>>;
87
+ };
88
+
89
+ export type DerivationProxyHelperConfig = {
90
+ readonly schemaVersion: 1;
91
+ readonly kind: "wrench-derivation-proxy-config";
92
+ readonly derivationId: string;
93
+ readonly directoryIdentity: GuardDirectoryIdentity;
94
+ readonly socketDirectory: string;
95
+ readonly socketIdentity: GuardDirectoryIdentity;
96
+ readonly browserDomains: readonly string[];
97
+ readonly parentOwner: ProcessOwnerIdentity;
98
+ readonly controlNonce: string;
99
+ readonly policySha256: string;
100
+ };
101
+
102
+ export type DerivationProxyHelperReady = {
103
+ readonly schemaVersion: 1;
104
+ readonly kind: "wrench-derivation-proxy-ready";
105
+ readonly derivationId: string;
106
+ readonly policySha256: string;
107
+ readonly port: number;
108
+ readonly owner: ProcessOwnerIdentity;
109
+ };
110
+
111
+ export type DerivationNetworkGuard = {
112
+ readonly schemaVersion: 1;
113
+ readonly kind: "contained-mv3-dnr-proxy";
114
+ readonly extension: DerivationGuardExtension;
115
+ readonly proxy: {
116
+ readonly policySha256: string;
117
+ readonly controlNonce: string;
118
+ readonly port: number;
119
+ readonly owner: ProcessOwnerIdentity;
120
+ readonly parentOwner: ProcessOwnerIdentity;
121
+ readonly configFile: GuardPrivateFileEvidence;
122
+ readonly readyFile: GuardPrivateFileEvidence;
123
+ };
124
+ };
125
+
126
+ type DnrRule = {
127
+ readonly id: number;
128
+ readonly priority: number;
129
+ readonly action: { readonly type: "allow" | "block" };
130
+ readonly condition: {
131
+ readonly regexFilter: string;
132
+ readonly isUrlFilterCaseSensitive: false;
133
+ readonly resourceTypes: typeof derivationGuardResourceTypes;
134
+ };
135
+ };
136
+
137
+ type GuardRuntimeCase = {
138
+ readonly label: string;
139
+ readonly url: string;
140
+ readonly type: (typeof derivationGuardResourceTypes)[number];
141
+ readonly ruleId: number;
142
+ };
143
+
144
+ function currentUserOwns(uid: number | bigint): boolean {
145
+ const current = typeof process.getuid === "function" ? process.getuid() : undefined;
146
+ return current === undefined || uid === (typeof uid === "bigint" ? BigInt(current) : current);
147
+ }
148
+
149
+ function escapeRegex(value: string): string {
150
+ return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
151
+ }
152
+
153
+ function domainAllowRegex(domain: string): string {
154
+ const wildcard = domain.startsWith("*.");
155
+ const base = wildcard ? domain.slice(2) : domain;
156
+ const host = wildcard
157
+ ? `(?:[a-z0-9-]+\\.)*${escapeRegex(base)}`
158
+ : escapeRegex(base);
159
+ return `^(?:https|wss)://${host}(?::[0-9]{1,5})?(?:[/?]|$)`;
160
+ }
161
+
162
+ function domainRuleId(index: number): number {
163
+ return 100 + index;
164
+ }
165
+
166
+ export function derivationGuardRules(browserDomains: readonly string[]): readonly DnrRule[] {
167
+ return Object.freeze([
168
+ {
169
+ id: 1,
170
+ priority: 1,
171
+ action: { type: "block" },
172
+ condition: {
173
+ regexFilter: "^(?:http|https|ws|wss)://",
174
+ isUrlFilterCaseSensitive: false,
175
+ resourceTypes: derivationGuardResourceTypes,
176
+ },
177
+ },
178
+ ...browserDomains.map((domain, index): DnrRule => ({
179
+ id: domainRuleId(index),
180
+ priority: 2,
181
+ action: { type: "allow" },
182
+ condition: {
183
+ regexFilter: domainAllowRegex(domain),
184
+ isUrlFilterCaseSensitive: false,
185
+ resourceTypes: derivationGuardResourceTypes,
186
+ },
187
+ })),
188
+ ]);
189
+ }
190
+
191
+ function runtimeCases(browserDomains: readonly string[]): readonly GuardRuntimeCase[] {
192
+ const cases: GuardRuntimeCase[] = [];
193
+ for (const [index, domain] of browserDomains.entries()) {
194
+ const base = domain.startsWith("*.") ? domain.slice(2) : domain;
195
+ const host = domain.startsWith("*.") ? `wrench-check.${base}` : base;
196
+ const ruleId = domainRuleId(index);
197
+ cases.push(
198
+ { label: `allow-${index}-https`, url: `https://${host}/wrench-check`, type: "xmlhttprequest", ruleId },
199
+ { label: `allow-${index}-wss`, url: `wss://${host}/wrench-check`, type: "websocket", ruleId },
200
+ { label: `allow-${index}-uppercase`, url: `https://${host.toUpperCase()}/wrench-check`, type: "main_frame", ruleId },
201
+ { label: `allow-${index}-port`, url: `https://${host}:8443/wrench-check`, type: "sub_frame", ruleId },
202
+ { label: `block-${index}-http`, url: `http://${host}/wrench-check`, type: "xmlhttprequest", ruleId: 1 },
203
+ { label: `block-${index}-ws`, url: `ws://${host}/wrench-check`, type: "websocket", ruleId: 1 },
204
+ { label: `block-${index}-trailing-dot`, url: `https://${host}./wrench-check`, type: "main_frame", ruleId: 1 },
205
+ { label: `block-${index}-suffix`, url: `https://${host}.invalid/wrench-check`, type: "main_frame", ruleId: 1 },
206
+ { label: `block-${index}-sibling`, url: `https://not-${host}/wrench-check`, type: "main_frame", ruleId: 1 },
207
+ );
208
+ if (domain.startsWith("*.")) {
209
+ cases.push({
210
+ label: `allow-${index}-wildcard-base`,
211
+ url: `https://${base}/wrench-check`,
212
+ type: "main_frame",
213
+ ruleId,
214
+ });
215
+ }
216
+ }
217
+ const first = browserDomains[0];
218
+ if (first !== undefined) {
219
+ const base = first.startsWith("*.") ? first.slice(2) : first;
220
+ const host = first.startsWith("*.") ? `wrench-check.${base}` : base;
221
+ for (const type of derivationGuardResourceTypes) {
222
+ cases.push({
223
+ label: `resource-${type}`,
224
+ url: `${type === "websocket" ? "wss" : "https"}://${host}/resource-${type}`,
225
+ type,
226
+ ruleId: domainRuleId(0),
227
+ });
228
+ }
229
+ }
230
+ cases.push({
231
+ label: "block-unallowed-punycode",
232
+ url: "https://xn--wrench-unallowed-9d0b.invalid/wrench-check",
233
+ type: "main_frame",
234
+ ruleId: 1,
235
+ });
236
+ return Object.freeze(cases);
237
+ }
238
+
239
+ export function derivationGuardReadinessCheckCount(
240
+ browserDomains: readonly string[],
241
+ ): number {
242
+ return 3 + derivationGuardRules(browserDomains).length + runtimeCases(browserDomains).length;
243
+ }
244
+
245
+ function readinessPolicySha256(
246
+ rules: readonly DnrRule[],
247
+ cases: readonly GuardRuntimeCase[],
248
+ ): string {
249
+ return sha256(canonicalJson({
250
+ schemaVersion: 1,
251
+ extensionId: DERIVATION_GUARD_EXTENSION_ID,
252
+ rules,
253
+ cases,
254
+ }));
255
+ }
256
+
257
+ export function derivationGuardReadinessPolicySha256(
258
+ browserDomains: readonly string[],
259
+ ): string {
260
+ return readinessPolicySha256(
261
+ derivationGuardRules(browserDomains),
262
+ runtimeCases(browserDomains),
263
+ );
264
+ }
265
+
266
+ function readinessScript(
267
+ rules: readonly DnrRule[],
268
+ cases: readonly GuardRuntimeCase[],
269
+ ): string {
270
+ const regexes = rules.map((rule) => ({
271
+ id: rule.id,
272
+ regex: rule.condition.regexFilter,
273
+ }));
274
+ const policySha256 = readinessPolicySha256(rules, cases);
275
+ return `"use strict";\nconst extensionId=${JSON.stringify(DERIVATION_GUARD_EXTENSION_ID)};\nconst policySha256=${JSON.stringify(policySha256)};\nconst regexes=${JSON.stringify(regexes)};\nconst cases=${JSON.stringify(cases)};\nglobalThis.__ghostgetCheckGuard=async()=>{let checks=0;try{if(chrome.runtime.id!==extensionId)throw new Error("id");checks+=1;const enabled=await chrome.declarativeNetRequest.getEnabledRulesets();if(!Array.isArray(enabled)||enabled.length!==1||enabled[0]!=="rules")throw new Error("ruleset");checks+=1;const disabled=await chrome.declarativeNetRequest.getDisabledRuleIds({rulesetId:"rules"});if(!Array.isArray(disabled)||disabled.length!==0)throw new Error("disabled");checks+=1;for(const item of regexes){const support=await chrome.declarativeNetRequest.isRegexSupported({isCaseSensitive:false,regex:item.regex});if(!support||support.isSupported!==true)throw new Error("regex");checks+=1}for(const item of cases){const result=await chrome.declarativeNetRequest.testMatchOutcome({type:item.type,url:item.url});if(!result||!Array.isArray(result.matchedRules)||result.matchedRules.length!==1)throw new Error("outcome");const match=result.matchedRules[0];if(!match||match.ruleId!==item.ruleId||match.rulesetId!=="rules")throw new Error("rule");checks+=1}return{schemaVersion:1,ok:true,extensionId,policySha256,checks}}catch{return{schemaVersion:1,ok:false,extensionId:"",policySha256:"",checks:0}}};\n`;
276
+ }
277
+
278
+ export function derivationGuardExtensionFiles(
279
+ browserDomains: readonly string[],
280
+ ): Readonly<Record<(typeof extensionFileNames)[number], string>> {
281
+ const rules = derivationGuardRules(browserDomains);
282
+ const manifest = {
283
+ manifest_version: 3,
284
+ name: "Ghostget Derivation Network Guard",
285
+ version: "1.0.0",
286
+ key: extensionPublicKey,
287
+ background: { service_worker: "readiness.js" },
288
+ permissions: ["declarativeNetRequest", "declarativeNetRequestFeedback"],
289
+ declarative_net_request: {
290
+ rule_resources: [{ id: "rules", enabled: true, path: "rules.json" }],
291
+ },
292
+ };
293
+ return Object.freeze({
294
+ "manifest.json": `${JSON.stringify(manifest)}\n`,
295
+ "rules.json": `${JSON.stringify(rules)}\n`,
296
+ "readiness.js": readinessScript(rules, runtimeCases(browserDomains)),
297
+ });
298
+ }
299
+
300
+ function extensionIdFromKey(): string {
301
+ const digest = createHash("sha256")
302
+ .update(Buffer.from(extensionPublicKey, "base64"))
303
+ .digest("hex")
304
+ .slice(0, 32);
305
+ return [...digest].map((value) => "abcdefghijklmnop"[Number.parseInt(value, 16)]).join("");
306
+ }
307
+
308
+ function inspectDirectory(path: string): GuardDirectoryIdentity {
309
+ try {
310
+ const stats = lstatSync(path, { bigint: true });
311
+ if (
312
+ !stats.isDirectory()
313
+ || stats.isSymbolicLink()
314
+ || !currentUserOwns(stats.uid)
315
+ || (stats.mode & 0o777n) !== 0o700n
316
+ ) throw new Error("unsafe");
317
+ return { device: stats.dev.toString(), inode: stats.ino.toString() };
318
+ } catch {
319
+ throw new Error("derivation network guard directory is unavailable or unsafe");
320
+ }
321
+ }
322
+
323
+ function sameIdentity(left: GuardDirectoryIdentity, right: GuardDirectoryIdentity): boolean {
324
+ return left.device === right.device && left.inode === right.inode;
325
+ }
326
+
327
+ export function writeGuardPrivateFile(path: string, content: string): GuardPrivateFileEvidence {
328
+ let descriptor: number | null = null;
329
+ let openedIdentity: GuardDirectoryIdentity | null = null;
330
+ let completed = false;
331
+ try {
332
+ descriptor = openSync(
333
+ path,
334
+ constants.O_WRONLY
335
+ | constants.O_CREAT
336
+ | constants.O_EXCL
337
+ | ("O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0),
338
+ 0o600,
339
+ );
340
+ const opened = fstatSync(descriptor, { bigint: true });
341
+ openedIdentity = { device: opened.dev.toString(), inode: opened.ino.toString() };
342
+ fchmodSync(descriptor, 0o600);
343
+ const bytes = Buffer.from(content, "utf8");
344
+ let offset = 0;
345
+ while (offset < bytes.byteLength) {
346
+ offset += writeSync(descriptor, bytes, offset, bytes.byteLength - offset);
347
+ }
348
+ fsyncSync(descriptor);
349
+ const stats = fstatSync(descriptor, { bigint: true });
350
+ if (
351
+ !stats.isFile()
352
+ || !currentUserOwns(stats.uid)
353
+ || (stats.mode & 0o777n) !== 0o600n
354
+ || stats.size !== BigInt(bytes.byteLength)
355
+ ) throw new Error("derivation network guard file could not be secured");
356
+ const evidence = {
357
+ device: stats.dev.toString(),
358
+ inode: stats.ino.toString(),
359
+ byteLength: bytes.byteLength,
360
+ sha256: sha256(content),
361
+ };
362
+ completed = true;
363
+ return evidence;
364
+ } catch {
365
+ throw new Error("derivation network guard file could not be secured");
366
+ } finally {
367
+ if (descriptor !== null) {
368
+ if (!completed && openedIdentity === null) {
369
+ try {
370
+ const stats = fstatSync(descriptor, { bigint: true });
371
+ openedIdentity = { device: stats.dev.toString(), inode: stats.ino.toString() };
372
+ } catch {
373
+ // Without an exact identity, preserve the path instead of unlinking.
374
+ }
375
+ }
376
+ try {
377
+ closeSync(descriptor);
378
+ } catch {
379
+ // The categorical write failure below must not expose a local path.
380
+ }
381
+ }
382
+ if (!completed && openedIdentity !== null) {
383
+ try {
384
+ const current = lstatSync(path, { bigint: true });
385
+ if (
386
+ current.dev.toString() === openedIdentity.device
387
+ && current.ino.toString() === openedIdentity.inode
388
+ ) unlinkSync(path);
389
+ } catch {
390
+ // A changed path is intentionally preserved.
391
+ }
392
+ }
393
+ }
394
+ }
395
+
396
+ export function readGuardPrivateFile(
397
+ path: string,
398
+ maximumBytes = 4 * 1024 * 1024,
399
+ ): { readonly content: string; readonly evidence: GuardPrivateFileEvidence } {
400
+ let descriptor: number | null = null;
401
+ try {
402
+ descriptor = openSync(
403
+ path,
404
+ constants.O_RDONLY | ("O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0),
405
+ );
406
+ const before = fstatSync(descriptor, { bigint: true });
407
+ if (
408
+ !before.isFile()
409
+ || !currentUserOwns(before.uid)
410
+ || (before.mode & 0o777n) !== 0o600n
411
+ || before.size < 1n
412
+ || before.size > BigInt(maximumBytes)
413
+ ) throw new Error("derivation network guard file is unavailable or unsafe");
414
+ const bytes = Buffer.alloc(Number(before.size));
415
+ let offset = 0;
416
+ while (offset < bytes.byteLength) {
417
+ const count = readSync(descriptor, bytes, offset, bytes.byteLength - offset, null);
418
+ if (count === 0) throw new Error("derivation network guard file changed size");
419
+ offset += count;
420
+ }
421
+ const after = fstatSync(descriptor, { bigint: true });
422
+ if (
423
+ before.dev !== after.dev
424
+ || before.ino !== after.ino
425
+ || before.size !== after.size
426
+ || before.mtimeNs !== after.mtimeNs
427
+ || before.ctimeNs !== after.ctimeNs
428
+ ) throw new Error("derivation network guard file changed while reading");
429
+ const content = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
430
+ return {
431
+ content,
432
+ evidence: {
433
+ device: before.dev.toString(),
434
+ inode: before.ino.toString(),
435
+ byteLength: bytes.byteLength,
436
+ sha256: sha256(content),
437
+ },
438
+ };
439
+ } catch {
440
+ throw new Error("derivation network guard file is unavailable or unsafe");
441
+ } finally {
442
+ if (descriptor !== null) {
443
+ try {
444
+ closeSync(descriptor);
445
+ } catch {
446
+ // Keep diagnostics categorical and path-free.
447
+ }
448
+ }
449
+ }
450
+ }
451
+
452
+ export function createDerivationGuardExtension(
453
+ directory: string,
454
+ browserDomains: readonly string[],
455
+ ): DerivationGuardExtension {
456
+ if (extensionIdFromKey() !== DERIVATION_GUARD_EXTENSION_ID) {
457
+ throw new Error("derivation network guard extension identity changed");
458
+ }
459
+ const extensionDirectory = join(directory, DERIVATION_GUARD_EXTENSION_DIRECTORY);
460
+ try {
461
+ mkdirSync(extensionDirectory, { mode: 0o700 });
462
+ chmodSync(extensionDirectory, 0o700);
463
+ } catch {
464
+ throw new Error("derivation network guard extension could not be created");
465
+ }
466
+ const directoryIdentity = inspectDirectory(extensionDirectory);
467
+ const contents = derivationGuardExtensionFiles(browserDomains);
468
+ const files = Object.fromEntries(extensionFileNames.map((name) => [
469
+ name,
470
+ writeGuardPrivateFile(join(extensionDirectory, name), contents[name]),
471
+ ])) as Record<(typeof extensionFileNames)[number], GuardPrivateFileEvidence>;
472
+ if (!sameIdentity(inspectDirectory(extensionDirectory), directoryIdentity)) {
473
+ throw new Error("derivation network guard directory changed during creation");
474
+ }
475
+ return Object.freeze({
476
+ id: DERIVATION_GUARD_EXTENSION_ID,
477
+ directoryIdentity,
478
+ files: Object.freeze(files),
479
+ });
480
+ }
481
+
482
+ export function verifyGuardPrivateFile(
483
+ path: string,
484
+ expected: GuardPrivateFileEvidence,
485
+ expectedContent: string,
486
+ ): void {
487
+ let descriptor: number | null = null;
488
+ try {
489
+ descriptor = openSync(
490
+ path,
491
+ constants.O_RDONLY | ("O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0),
492
+ );
493
+ const before = fstatSync(descriptor, { bigint: true });
494
+ if (
495
+ !before.isFile()
496
+ || !currentUserOwns(before.uid)
497
+ || (before.mode & 0o777n) !== 0o600n
498
+ || before.dev.toString() !== expected.device
499
+ || before.ino.toString() !== expected.inode
500
+ || before.size !== BigInt(expected.byteLength)
501
+ ) throw new Error("derivation network guard file changed identity");
502
+ const bytes = Buffer.alloc(expected.byteLength);
503
+ let offset = 0;
504
+ while (offset < bytes.byteLength) {
505
+ const count = readSync(descriptor, bytes, offset, bytes.byteLength - offset, null);
506
+ if (count === 0) throw new Error("derivation network guard file changed size");
507
+ offset += count;
508
+ }
509
+ const after = fstatSync(descriptor, { bigint: true });
510
+ if (
511
+ before.dev !== after.dev
512
+ || before.ino !== after.ino
513
+ || before.size !== after.size
514
+ || before.mtimeNs !== after.mtimeNs
515
+ || before.ctimeNs !== after.ctimeNs
516
+ || bytes.toString("utf8") !== expectedContent
517
+ || sha256(expectedContent) !== expected.sha256
518
+ ) throw new Error("derivation network guard file changed content");
519
+ } catch {
520
+ throw new Error("derivation network guard file changed or is unavailable");
521
+ } finally {
522
+ if (descriptor !== null) {
523
+ try {
524
+ closeSync(descriptor);
525
+ } catch {
526
+ // Keep diagnostics categorical and path-free.
527
+ }
528
+ }
529
+ }
530
+ }
531
+
532
+ export function verifyDerivationGuardExtension(
533
+ directory: string,
534
+ browserDomains: readonly string[],
535
+ extension: DerivationGuardExtension,
536
+ ): void {
537
+ if (extension.id !== DERIVATION_GUARD_EXTENSION_ID || extensionIdFromKey() !== extension.id) {
538
+ throw new Error("derivation network guard extension identity changed");
539
+ }
540
+ const extensionDirectory = join(directory, DERIVATION_GUARD_EXTENSION_DIRECTORY);
541
+ if (!sameIdentity(inspectDirectory(extensionDirectory), extension.directoryIdentity)) {
542
+ throw new Error("derivation network guard directory changed identity");
543
+ }
544
+ const contents = derivationGuardExtensionFiles(browserDomains);
545
+ for (const name of extensionFileNames) {
546
+ verifyGuardPrivateFile(join(extensionDirectory, name), extension.files[name], contents[name]);
547
+ }
548
+ }
549
+
550
+ export function derivationProxyPolicySha256(browserDomains: readonly string[]): string {
551
+ return sha256(canonicalJson({
552
+ schemaVersion: 1,
553
+ kind: "wrench-derivation-connect-policy",
554
+ browserDomains,
555
+ allowPrivateNetwork: false,
556
+ transport: "connect-tls-tunnel",
557
+ }));
558
+ }
559
+
560
+ export function proxyHelperConfigContent(config: DerivationProxyHelperConfig): string {
561
+ return `${JSON.stringify(config)}\n`;
562
+ }
563
+
564
+ export function proxyHelperReadyContent(ready: DerivationProxyHelperReady): string {
565
+ return `${JSON.stringify(ready)}\n`;
566
+ }
567
+
568
+ function exactKeys(record: Record<string, unknown>, expected: readonly string[]): boolean {
569
+ const actual = Object.keys(record).sort();
570
+ const sorted = [...expected].sort();
571
+ return actual.length === sorted.length
572
+ && actual.every((key, index) => key === sorted[index]);
573
+ }
574
+
575
+ export function parseGuardDirectoryIdentity(value: unknown): GuardDirectoryIdentity {
576
+ if (
577
+ typeof value !== "object"
578
+ || value === null
579
+ || Array.isArray(value)
580
+ || !exactKeys(value as Record<string, unknown>, ["device", "inode"])
581
+ ) throw new Error("derivation network guard identity is malformed");
582
+ const record = value as Record<string, unknown>;
583
+ if (
584
+ typeof record.device !== "string"
585
+ || !unsignedIntegerPattern.test(record.device)
586
+ || typeof record.inode !== "string"
587
+ || !unsignedIntegerPattern.test(record.inode)
588
+ ) throw new Error("derivation network guard identity is malformed");
589
+ return { device: record.device, inode: record.inode };
590
+ }
591
+
592
+ export function parseGuardFileEvidence(value: unknown): GuardPrivateFileEvidence {
593
+ if (
594
+ typeof value !== "object"
595
+ || value === null
596
+ || Array.isArray(value)
597
+ || !exactKeys(value as Record<string, unknown>, ["device", "inode", "byteLength", "sha256"])
598
+ ) throw new Error("derivation network guard file evidence is malformed");
599
+ const record = value as Record<string, unknown>;
600
+ const identity = parseGuardDirectoryIdentity({ device: record.device, inode: record.inode });
601
+ if (
602
+ !Number.isSafeInteger(record.byteLength)
603
+ || (record.byteLength as number) < 1
604
+ || (record.byteLength as number) > 4 * 1024 * 1024
605
+ || typeof record.sha256 !== "string"
606
+ || !digestPattern.test(record.sha256)
607
+ ) throw new Error("derivation network guard file evidence is malformed");
608
+ return {
609
+ ...identity,
610
+ byteLength: record.byteLength as number,
611
+ sha256: record.sha256,
612
+ };
613
+ }
614
+
615
+ function parseOwner(value: unknown): ProcessOwnerIdentity {
616
+ if (
617
+ typeof value !== "object"
618
+ || value === null
619
+ || Array.isArray(value)
620
+ || !exactKeys(value as Record<string, unknown>, ["pid", "bootId", "processStartId"])
621
+ ) throw new Error("derivation proxy owner is malformed");
622
+ const record = value as Record<string, unknown>;
623
+ if (
624
+ !Number.isSafeInteger(record.pid)
625
+ || (record.pid as number) < 1
626
+ || typeof record.bootId !== "string"
627
+ || !digestPattern.test(record.bootId)
628
+ || typeof record.processStartId !== "string"
629
+ || !digestPattern.test(record.processStartId)
630
+ ) throw new Error("derivation proxy owner is malformed");
631
+ return {
632
+ pid: record.pid as number,
633
+ bootId: record.bootId,
634
+ processStartId: record.processStartId,
635
+ };
636
+ }
637
+
638
+ export function parseDerivationNetworkGuard(value: unknown): DerivationNetworkGuard {
639
+ if (
640
+ typeof value !== "object"
641
+ || value === null
642
+ || Array.isArray(value)
643
+ || !exactKeys(value as Record<string, unknown>, ["schemaVersion", "kind", "extension", "proxy"])
644
+ ) throw new Error("derivation network guard metadata is malformed");
645
+ const record = value as Record<string, unknown>;
646
+ if (record.schemaVersion !== 1 || record.kind !== "contained-mv3-dnr-proxy") {
647
+ throw new Error("derivation network guard metadata is malformed");
648
+ }
649
+ if (
650
+ typeof record.extension !== "object"
651
+ || record.extension === null
652
+ || Array.isArray(record.extension)
653
+ || !exactKeys(record.extension as Record<string, unknown>, ["id", "directoryIdentity", "files"])
654
+ ) throw new Error("derivation network guard extension metadata is malformed");
655
+ const extensionRecord = record.extension as Record<string, unknown>;
656
+ if (
657
+ extensionRecord.id !== DERIVATION_GUARD_EXTENSION_ID
658
+ || typeof extensionRecord.files !== "object"
659
+ || extensionRecord.files === null
660
+ || Array.isArray(extensionRecord.files)
661
+ || !exactKeys(extensionRecord.files as Record<string, unknown>, extensionFileNames)
662
+ ) throw new Error("derivation network guard extension metadata is malformed");
663
+ const fileRecord = extensionRecord.files as Record<string, unknown>;
664
+ const files = Object.fromEntries(extensionFileNames.map((name) => [
665
+ name,
666
+ parseGuardFileEvidence(fileRecord[name]),
667
+ ])) as Record<(typeof extensionFileNames)[number], GuardPrivateFileEvidence>;
668
+ if (
669
+ typeof record.proxy !== "object"
670
+ || record.proxy === null
671
+ || Array.isArray(record.proxy)
672
+ || !exactKeys(record.proxy as Record<string, unknown>, [
673
+ "policySha256", "controlNonce", "port", "owner", "parentOwner", "configFile", "readyFile",
674
+ ])
675
+ ) throw new Error("derivation network proxy metadata is malformed");
676
+ const proxy = record.proxy as Record<string, unknown>;
677
+ if (
678
+ typeof proxy.policySha256 !== "string"
679
+ || !digestPattern.test(proxy.policySha256)
680
+ || typeof proxy.controlNonce !== "string"
681
+ || !/^[a-f0-9]{64}$/u.test(proxy.controlNonce)
682
+ || !Number.isSafeInteger(proxy.port)
683
+ || (proxy.port as number) < 1
684
+ || (proxy.port as number) > 65_535
685
+ ) throw new Error("derivation network proxy metadata is malformed");
686
+ return Object.freeze({
687
+ schemaVersion: 1,
688
+ kind: "contained-mv3-dnr-proxy",
689
+ extension: Object.freeze({
690
+ id: DERIVATION_GUARD_EXTENSION_ID,
691
+ directoryIdentity: parseGuardDirectoryIdentity(extensionRecord.directoryIdentity),
692
+ files: Object.freeze(files),
693
+ }),
694
+ proxy: Object.freeze({
695
+ policySha256: proxy.policySha256,
696
+ controlNonce: proxy.controlNonce,
697
+ port: proxy.port as number,
698
+ owner: parseOwner(proxy.owner),
699
+ parentOwner: parseOwner(proxy.parentOwner),
700
+ configFile: parseGuardFileEvidence(proxy.configFile),
701
+ readyFile: parseGuardFileEvidence(proxy.readyFile),
702
+ }),
703
+ });
704
+ }
705
+
706
+ export function parseProxyHelperConfig(value: unknown): DerivationProxyHelperConfig {
707
+ if (
708
+ typeof value !== "object"
709
+ || value === null
710
+ || Array.isArray(value)
711
+ || !exactKeys(value as Record<string, unknown>, [
712
+ "schemaVersion", "kind", "derivationId", "directoryIdentity", "socketDirectory",
713
+ "socketIdentity", "browserDomains", "parentOwner", "controlNonce", "policySha256",
714
+ ])
715
+ ) throw new Error("derivation proxy helper config is malformed");
716
+ const record = value as Record<string, unknown>;
717
+ if (
718
+ record.schemaVersion !== 1
719
+ || record.kind !== "wrench-derivation-proxy-config"
720
+ || typeof record.derivationId !== "string"
721
+ || !derivationIdPattern.test(record.derivationId)
722
+ || typeof record.socketDirectory !== "string"
723
+ || record.socketDirectory.length < 1
724
+ || record.socketDirectory.length > 4_096
725
+ || record.socketDirectory.includes("\0")
726
+ || !Array.isArray(record.browserDomains)
727
+ || record.browserDomains.length < 1
728
+ || record.browserDomains.length > 100
729
+ || record.browserDomains.some((domain) => typeof domain !== "string")
730
+ || typeof record.controlNonce !== "string"
731
+ || !/^[a-f0-9]{64}$/u.test(record.controlNonce)
732
+ || typeof record.policySha256 !== "string"
733
+ || !digestPattern.test(record.policySha256)
734
+ ) throw new Error("derivation proxy helper config is malformed");
735
+ const browserDomains = record.browserDomains.map((domain) => String(domain));
736
+ if (derivationProxyPolicySha256(browserDomains) !== record.policySha256) {
737
+ throw new Error("derivation proxy helper policy changed");
738
+ }
739
+ return Object.freeze({
740
+ schemaVersion: 1,
741
+ kind: "wrench-derivation-proxy-config",
742
+ derivationId: record.derivationId,
743
+ directoryIdentity: parseGuardDirectoryIdentity(record.directoryIdentity),
744
+ socketDirectory: record.socketDirectory,
745
+ socketIdentity: parseGuardDirectoryIdentity(record.socketIdentity),
746
+ browserDomains: Object.freeze(browserDomains),
747
+ parentOwner: parseOwner(record.parentOwner),
748
+ controlNonce: record.controlNonce,
749
+ policySha256: record.policySha256,
750
+ });
751
+ }
752
+
753
+ export function parseProxyHelperReady(value: unknown): DerivationProxyHelperReady {
754
+ if (
755
+ typeof value !== "object"
756
+ || value === null
757
+ || Array.isArray(value)
758
+ || !exactKeys(value as Record<string, unknown>, [
759
+ "schemaVersion", "kind", "derivationId", "policySha256", "port", "owner",
760
+ ])
761
+ ) throw new Error("derivation proxy helper readiness is malformed");
762
+ const record = value as Record<string, unknown>;
763
+ if (
764
+ record.schemaVersion !== 1
765
+ || record.kind !== "wrench-derivation-proxy-ready"
766
+ || typeof record.derivationId !== "string"
767
+ || !derivationIdPattern.test(record.derivationId)
768
+ || typeof record.policySha256 !== "string"
769
+ || !digestPattern.test(record.policySha256)
770
+ || !Number.isSafeInteger(record.port)
771
+ || (record.port as number) < 1
772
+ || (record.port as number) > 65_535
773
+ ) throw new Error("derivation proxy helper readiness is malformed");
774
+ return Object.freeze({
775
+ schemaVersion: 1,
776
+ kind: "wrench-derivation-proxy-ready",
777
+ derivationId: record.derivationId,
778
+ policySha256: record.policySha256,
779
+ port: record.port as number,
780
+ owner: parseOwner(record.owner),
781
+ });
782
+ }