@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,106 @@
1
+ import type {
2
+ ProviderPluginBindingDefinitionV1,
3
+ } from "./provider-plugin";
4
+ import type { GhostgetManifest } from "./model";
5
+ import {
6
+ isVerifiedPortableProviderPluginPackage,
7
+ type PortableProviderPluginBindingV1,
8
+ type VerifiedPortableProviderPluginPackage,
9
+ } from "./provider-plugin-package";
10
+ import {
11
+ createKernelPortableProviderPluginBindingProjections,
12
+ isResolvedPortableProviderRuntimeDependencies,
13
+ type KernelPortableProviderPluginBindingProjection,
14
+ type PortableProviderRuntimeDependencies,
15
+ } from "./provider-plugin-portable-runtime";
16
+
17
+ type Environment = Readonly<Record<string, string | undefined>>;
18
+
19
+ type PortableProjectionBindingAuthority = {
20
+ readonly package: VerifiedPortableProviderPluginPackage;
21
+ readonly portableBinding: PortableProviderPluginBindingV1;
22
+ readonly adapterId: string;
23
+ readonly manifest: GhostgetManifest;
24
+ readonly operations: ProviderPluginBindingDefinitionV1["operations"];
25
+ readonly runtime: ProviderPluginBindingDefinitionV1["runtime"];
26
+ };
27
+
28
+ const authorizedBindings = new WeakMap<
29
+ ProviderPluginBindingDefinitionV1,
30
+ PortableProjectionBindingAuthority
31
+ >();
32
+
33
+ /**
34
+ * Build and authorize the exact immutable child-host wrappers for one verified
35
+ * package. There is intentionally no API that accepts caller-provided runtime
36
+ * hooks: portable authority can only be minted around the kernel builder's
37
+ * own return values.
38
+ */
39
+ export function createAuthorizedKernelPortableProviderPluginBindingProjections(
40
+ packageValue: VerifiedPortableProviderPluginPackage,
41
+ environment: Environment,
42
+ dependencies: PortableProviderRuntimeDependencies,
43
+ ): readonly KernelPortableProviderPluginBindingProjection[] {
44
+ if (
45
+ !isVerifiedPortableProviderPluginPackage(packageValue)
46
+ || !isResolvedPortableProviderRuntimeDependencies(dependencies)
47
+ ) {
48
+ throw new Error(
49
+ "portable provider plugin binding authority requires an exact verified package and kernel dependencies",
50
+ );
51
+ }
52
+ const projections = createKernelPortableProviderPluginBindingProjections(
53
+ packageValue,
54
+ environment,
55
+ dependencies,
56
+ );
57
+ for (const projection of projections) {
58
+ if (
59
+ !packageValue.manifest.bindings.includes(projection.portableBinding)
60
+ || !Object.isFrozen(projection)
61
+ || !Object.isFrozen(projection.binding)
62
+ || !Object.isFrozen(projection.binding.operations)
63
+ || !projection.binding.operations.every(Object.isFrozen)
64
+ || !Object.isFrozen(projection.binding.runtime)
65
+ ) {
66
+ throw new Error(
67
+ "portable provider plugin kernel wrapper construction violated its immutable authority boundary",
68
+ );
69
+ }
70
+ authorizedBindings.set(projection.binding, Object.freeze({
71
+ package: packageValue,
72
+ portableBinding: projection.portableBinding,
73
+ adapterId: projection.adapterId,
74
+ manifest: projection.manifest,
75
+ operations: projection.binding.operations,
76
+ runtime: projection.binding.runtime,
77
+ }));
78
+ }
79
+ return projections;
80
+ }
81
+
82
+ export function assertKernelPortableProviderPluginBindingProjection(
83
+ binding: ProviderPluginBindingDefinitionV1,
84
+ packageValue: VerifiedPortableProviderPluginPackage,
85
+ portableBinding: PortableProviderPluginBindingV1,
86
+ adapterId: string,
87
+ manifest: GhostgetManifest,
88
+ ): void {
89
+ const authority = authorizedBindings.get(binding);
90
+ if (
91
+ authority?.package !== packageValue
92
+ || authority.portableBinding !== portableBinding
93
+ || authority.adapterId !== adapterId
94
+ || authority.manifest !== manifest
95
+ || authority.operations !== binding.operations
96
+ || authority.runtime !== binding.runtime
97
+ || !Object.isFrozen(binding)
98
+ || !Object.isFrozen(binding.operations)
99
+ || !binding.operations.every(Object.isFrozen)
100
+ || !Object.isFrozen(binding.runtime)
101
+ ) {
102
+ throw new Error(
103
+ "portable provider plugin runtime must be a kernel-owned child-host wrapper",
104
+ );
105
+ }
106
+ }
@@ -0,0 +1,94 @@
1
+ import { join } from "node:path";
2
+
3
+ import {
4
+ definePortableProviderPluginProjection,
5
+ PROVIDER_PLUGIN_API_VERSION,
6
+ type ProviderPluginV1,
7
+ } from "./provider-plugin";
8
+ import type {
9
+ VerifiedPortableProviderPluginPackage,
10
+ } from "./provider-plugin-package";
11
+ import {
12
+ createAuthorizedKernelPortableProviderPluginBindingProjections,
13
+ } from "./provider-plugin-portable-authority";
14
+ import {
15
+ resolvePortableProviderRuntimeDependencies,
16
+ type PortableProviderRuntimeDependencies,
17
+ } from "./provider-plugin-portable-runtime";
18
+ import {
19
+ extendProviderPluginRegistryWithPortablePlugins,
20
+ type ProviderPluginRegistry,
21
+ } from "./provider-plugin-registry";
22
+ import {
23
+ listInstalledPortableProviderPlugins,
24
+ type InstalledPortableProviderPlugin,
25
+ } from "./provider-plugin-store";
26
+ import { ghostgetStateHome } from "./storage";
27
+
28
+ type Environment = Readonly<Record<string, string | undefined>>;
29
+
30
+ export type PortableProviderPluginCatalog = {
31
+ readonly registry: ProviderPluginRegistry;
32
+ readonly installed: readonly InstalledPortableProviderPlugin[];
33
+ };
34
+
35
+ function projectWithResolvedDependencies(
36
+ packageValue: VerifiedPortableProviderPluginPackage,
37
+ environment: Environment,
38
+ dependencies: PortableProviderRuntimeDependencies,
39
+ ): ProviderPluginV1 {
40
+ const bindings =
41
+ createAuthorizedKernelPortableProviderPluginBindingProjections(
42
+ packageValue,
43
+ environment,
44
+ dependencies,
45
+ );
46
+ return definePortableProviderPluginProjection({
47
+ apiVersion: PROVIDER_PLUGIN_API_VERSION,
48
+ id: packageValue.manifest.id,
49
+ version: packageValue.manifest.version,
50
+ displayName: packageValue.manifest.displayName,
51
+ sourceKind: "portable",
52
+ package: packageValue,
53
+ bindings,
54
+ });
55
+ }
56
+
57
+ /**
58
+ * Project one already-verified immutable package into the ordinary provider
59
+ * plugin contract. Projection is pure with respect to plugin code: it never
60
+ * starts the package host or crosses a network boundary.
61
+ */
62
+ export function projectPortableProviderPluginPackage(
63
+ packageValue: VerifiedPortableProviderPluginPackage,
64
+ environment: Environment = process.env,
65
+ dependencyOverrides: Partial<PortableProviderRuntimeDependencies> = {},
66
+ ): ProviderPluginV1 {
67
+ return projectWithResolvedDependencies(
68
+ packageValue,
69
+ environment,
70
+ resolvePortableProviderRuntimeDependencies(dependencyOverrides),
71
+ );
72
+ }
73
+
74
+ export function createPortableProviderPluginCatalog(
75
+ sourceRegistry: ProviderPluginRegistry,
76
+ environment: Environment = process.env,
77
+ dependencyOverrides: Partial<PortableProviderRuntimeDependencies> = {},
78
+ ): PortableProviderPluginCatalog {
79
+ const dependencies = resolvePortableProviderRuntimeDependencies(
80
+ dependencyOverrides,
81
+ );
82
+ const installed = listInstalledPortableProviderPlugins(
83
+ join(ghostgetStateHome(environment), "provider-plugins"),
84
+ );
85
+ const portable = installed.map((entry) =>
86
+ projectWithResolvedDependencies(entry.package, environment, dependencies));
87
+ return Object.freeze({
88
+ registry: extendProviderPluginRegistryWithPortablePlugins(
89
+ sourceRegistry,
90
+ portable,
91
+ ),
92
+ installed,
93
+ });
94
+ }
@@ -0,0 +1,315 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ import type {
4
+ PortableProviderPluginBindingV1,
5
+ PortableProviderPluginCapabilitiesV1,
6
+ PortableProviderPluginOperationV1,
7
+ } from "./provider-plugin-package";
8
+
9
+ export const PORTABLE_OPERATION_IDENTITY_VERSION = 1 as const;
10
+
11
+ export type PortableProviderPluginPackageMetadataV1 = {
12
+ readonly id: string;
13
+ readonly version: string;
14
+ readonly hostApiVersion: 1;
15
+ readonly bundleSha256: string;
16
+ readonly manifestSha256: string;
17
+ readonly capabilities: PortableProviderPluginCapabilitiesV1;
18
+ };
19
+
20
+ export type PortableProviderPluginArtifactMetadataV1 = Omit<
21
+ PortableProviderPluginPackageMetadataV1,
22
+ "id" | "version"
23
+ >;
24
+
25
+ export type PortableOperationIdentityV1 = {
26
+ readonly pluginId: string;
27
+ readonly pluginVersion: string;
28
+ readonly hostApiVersion: 1;
29
+ readonly bundleSha256: string;
30
+ readonly manifestSha256: string;
31
+ readonly adapterId: string;
32
+ readonly transport: PortableProviderPluginBindingV1["transport"];
33
+ readonly surfaceId: string;
34
+ readonly operation: string;
35
+ readonly contractVersion: number;
36
+ readonly descriptorSha256: string;
37
+ };
38
+
39
+ export type PortableOperationIdentitySourceV1 = {
40
+ readonly package: PortableProviderPluginPackageMetadataV1;
41
+ readonly binding: PortableProviderPluginBindingV1;
42
+ readonly operation: PortableProviderPluginOperationV1;
43
+ };
44
+
45
+ const descriptorDomain =
46
+ `io-portable-operation-descriptor-v${PORTABLE_OPERATION_IDENTITY_VERSION}\0`;
47
+ const pluginIdPattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
48
+ const pluginVersionPattern =
49
+ /^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u;
50
+ const sha256Pattern = /^[a-f0-9]{64}$/u;
51
+ const adapterIdPattern = /^[a-z][a-z0-9-]{0,47}$/u;
52
+ const operationPattern =
53
+ /^[a-z][a-z0-9-]{0,39}(?:\.[a-z][a-z0-9-]{0,39}){1,3}$/u;
54
+
55
+ function ownDataValue(
56
+ value: object,
57
+ key: PropertyKey,
58
+ label: string,
59
+ ): unknown {
60
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
61
+ if (
62
+ descriptor === undefined
63
+ || !descriptor.enumerable
64
+ || !("value" in descriptor)
65
+ ) {
66
+ throw new Error(`${label} contains unsupported accessor state`);
67
+ }
68
+ return descriptor.value as unknown;
69
+ }
70
+
71
+ function canonicalPortableJson(value: unknown, label: string): string {
72
+ if (value === null) return "null";
73
+ if (typeof value === "string" || typeof value === "boolean") {
74
+ return JSON.stringify(value);
75
+ }
76
+ if (typeof value === "number") {
77
+ if (!Number.isFinite(value)) {
78
+ throw new Error(`${label} contains a non-finite number`);
79
+ }
80
+ return JSON.stringify(value);
81
+ }
82
+ if (Array.isArray(value)) {
83
+ if ((Object.getPrototypeOf(value) as unknown) !== Array.prototype) {
84
+ throw new Error(`${label} contains a non-plain array`);
85
+ }
86
+ const length = value.length;
87
+ const keys = Reflect.ownKeys(value);
88
+ if (
89
+ keys.length !== length + 1
90
+ || !keys.includes("length")
91
+ || Array.from({ length }, (_unused, index) => String(index))
92
+ .some((key) => !keys.includes(key))
93
+ ) {
94
+ throw new Error(`${label} contains a sparse or decorated array`);
95
+ }
96
+ return `[${Array.from(
97
+ { length },
98
+ (_unused, index) =>
99
+ canonicalPortableJson(
100
+ ownDataValue(value, String(index), `${label}[${index}]`),
101
+ `${label}[${index}]`,
102
+ ),
103
+ ).join(",")}]`;
104
+ }
105
+ if (typeof value !== "object") {
106
+ throw new Error(`${label} contains a non-JSON value`);
107
+ }
108
+ const prototype: unknown = Object.getPrototypeOf(value) as unknown;
109
+ if (prototype !== Object.prototype && prototype !== null) {
110
+ throw new Error(`${label} contains a non-plain object`);
111
+ }
112
+ const keys = Reflect.ownKeys(value);
113
+ if (keys.some((key) => typeof key !== "string")) {
114
+ throw new Error(`${label} contains a symbol field`);
115
+ }
116
+ const sorted = (keys as string[]).sort();
117
+ return `{${sorted.map((key) =>
118
+ `${JSON.stringify(key)}:${canonicalPortableJson(
119
+ ownDataValue(value, key, `${label}.${key}`),
120
+ `${label}.${key}`,
121
+ )}`).join(",")}}`;
122
+ }
123
+
124
+ function assertPackageMetadata(
125
+ value: PortableProviderPluginPackageMetadataV1,
126
+ ): void {
127
+ if (
128
+ !pluginIdPattern.test(value.id)
129
+ || !pluginVersionPattern.test(value.version)
130
+ || value.hostApiVersion !== 1
131
+ || !sha256Pattern.test(value.bundleSha256)
132
+ || !sha256Pattern.test(value.manifestSha256)
133
+ ) {
134
+ throw new Error("portable operation package identity is invalid");
135
+ }
136
+ }
137
+
138
+ function identityRecord(
139
+ value: unknown,
140
+ ): Readonly<Record<string, unknown>> {
141
+ if (
142
+ typeof value !== "object"
143
+ || value === null
144
+ || Array.isArray(value)
145
+ ) {
146
+ throw new Error("portable operation identity must be an object");
147
+ }
148
+ const prototype: unknown = Object.getPrototypeOf(value) as unknown;
149
+ if (prototype !== Object.prototype && prototype !== null) {
150
+ throw new Error("portable operation identity must be a plain object");
151
+ }
152
+ const keys = Reflect.ownKeys(value);
153
+ const expected = [
154
+ "pluginId",
155
+ "pluginVersion",
156
+ "hostApiVersion",
157
+ "bundleSha256",
158
+ "manifestSha256",
159
+ "adapterId",
160
+ "transport",
161
+ "surfaceId",
162
+ "operation",
163
+ "contractVersion",
164
+ "descriptorSha256",
165
+ ].sort();
166
+ if (
167
+ keys.some((key) => typeof key !== "string")
168
+ || keys.length !== expected.length
169
+ || (keys as string[]).sort().some(
170
+ (key, index) => key !== expected[index],
171
+ )
172
+ ) {
173
+ throw new Error("portable operation identity has unsupported fields");
174
+ }
175
+ const result: Record<string, unknown> = {};
176
+ for (const key of expected) {
177
+ result[key] = ownDataValue(
178
+ value,
179
+ key,
180
+ `portable operation identity.${key}`,
181
+ );
182
+ }
183
+ return result;
184
+ }
185
+
186
+ export function parsePortableOperationIdentityV1(
187
+ value: unknown,
188
+ ): PortableOperationIdentityV1 {
189
+ const record = identityRecord(value);
190
+ if (
191
+ typeof record.pluginId !== "string"
192
+ || record.pluginId.length > 128
193
+ || !pluginIdPattern.test(record.pluginId)
194
+ || typeof record.pluginVersion !== "string"
195
+ || record.pluginVersion.length > 128
196
+ || !pluginVersionPattern.test(record.pluginVersion)
197
+ || record.hostApiVersion !== 1
198
+ || typeof record.bundleSha256 !== "string"
199
+ || !sha256Pattern.test(record.bundleSha256)
200
+ || typeof record.manifestSha256 !== "string"
201
+ || !sha256Pattern.test(record.manifestSha256)
202
+ || typeof record.adapterId !== "string"
203
+ || !adapterIdPattern.test(record.adapterId)
204
+ || (
205
+ record.transport !== "provider-api"
206
+ && record.transport !== "web-session-api"
207
+ && record.transport !== "linked-device"
208
+ )
209
+ || typeof record.surfaceId !== "string"
210
+ || record.surfaceId.length > 128
211
+ || !pluginIdPattern.test(record.surfaceId)
212
+ || typeof record.operation !== "string"
213
+ || !operationPattern.test(record.operation)
214
+ || typeof record.contractVersion !== "number"
215
+ || !Number.isSafeInteger(record.contractVersion)
216
+ || record.contractVersion < 1
217
+ || record.contractVersion > 1_000_000
218
+ || typeof record.descriptorSha256 !== "string"
219
+ || !sha256Pattern.test(record.descriptorSha256)
220
+ ) {
221
+ throw new Error("portable operation identity is malformed");
222
+ }
223
+ return Object.freeze({
224
+ pluginId: record.pluginId,
225
+ pluginVersion: record.pluginVersion,
226
+ hostApiVersion: 1,
227
+ bundleSha256: record.bundleSha256,
228
+ manifestSha256: record.manifestSha256,
229
+ adapterId: record.adapterId,
230
+ transport: record.transport,
231
+ surfaceId: record.surfaceId,
232
+ operation: record.operation,
233
+ contractVersion: record.contractVersion,
234
+ descriptorSha256: record.descriptorSha256,
235
+ });
236
+ }
237
+
238
+ function operationBelongsToBinding(
239
+ binding: PortableProviderPluginBindingV1,
240
+ operation: PortableProviderPluginOperationV1,
241
+ ): boolean {
242
+ const encoded = canonicalPortableJson(
243
+ operation,
244
+ "portable operation descriptor",
245
+ );
246
+ return binding.operations.some((candidate) =>
247
+ candidate.name === operation.name
248
+ && candidate.contractVersion === operation.contractVersion
249
+ && canonicalPortableJson(
250
+ candidate,
251
+ "portable binding operation descriptor",
252
+ ) === encoded);
253
+ }
254
+
255
+ function descriptorValue(
256
+ source: PortableOperationIdentitySourceV1,
257
+ ): Readonly<Record<string, unknown>> {
258
+ const packageValue = source.package;
259
+ const binding = source.binding;
260
+ return Object.freeze({
261
+ identityVersion: PORTABLE_OPERATION_IDENTITY_VERSION,
262
+ plugin: Object.freeze({
263
+ id: packageValue.id,
264
+ version: packageValue.version,
265
+ hostApiVersion: packageValue.hostApiVersion,
266
+ }),
267
+ capabilities: packageValue.capabilities,
268
+ binding: Object.freeze({
269
+ adapterId: binding.adapterId,
270
+ transport: binding.transport,
271
+ surfaceId: binding.surfaceId,
272
+ origin: binding.origin,
273
+ authKinds: binding.authKinds,
274
+ subject: binding.subject,
275
+ }),
276
+ operation: source.operation,
277
+ });
278
+ }
279
+
280
+ /**
281
+ * Bind one exact logical operation to the immutable package that implements it.
282
+ *
283
+ * Executable closures, runtime wrapper objects, filesystem paths, and host
284
+ * process state are deliberately absent from the descriptor projection.
285
+ */
286
+ export function createPortableOperationIdentityV1(
287
+ source: PortableOperationIdentitySourceV1,
288
+ ): PortableOperationIdentityV1 {
289
+ assertPackageMetadata(source.package);
290
+ if (!operationBelongsToBinding(source.binding, source.operation)) {
291
+ throw new Error(
292
+ "portable operation descriptor is not owned by its declared binding",
293
+ );
294
+ }
295
+ const descriptorSha256 = createHash("sha256")
296
+ .update(descriptorDomain)
297
+ .update(canonicalPortableJson(
298
+ descriptorValue(source),
299
+ "portable operation identity",
300
+ ))
301
+ .digest("hex");
302
+ return parsePortableOperationIdentityV1({
303
+ pluginId: source.package.id,
304
+ pluginVersion: source.package.version,
305
+ hostApiVersion: source.package.hostApiVersion,
306
+ bundleSha256: source.package.bundleSha256,
307
+ manifestSha256: source.package.manifestSha256,
308
+ adapterId: source.binding.adapterId,
309
+ transport: source.binding.transport,
310
+ surfaceId: source.binding.surfaceId,
311
+ operation: source.operation.name,
312
+ contractVersion: source.operation.contractVersion,
313
+ descriptorSha256,
314
+ });
315
+ }