@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.
- package/CHANGELOG.md +458 -0
- package/LICENSE +21 -0
- package/README.md +1359 -0
- package/bunfig.toml +2 -0
- package/dist/apple-photos-client.js +704 -0
- package/dist/beeper-client.js +4602 -0
- package/dist/client.js +1605 -0
- package/dist/index-26yq8q16.js +31 -0
- package/dist/index-9t13b4k7.js +508 -0
- package/dist/index-axwm9b3v.js +5 -0
- package/dist/index-gwk7rbyj.js +30 -0
- package/dist/index.js +701 -0
- package/dist/messaging.js +1130 -0
- package/dist/omni-client.js +1406 -0
- package/dist/whatsapp-client.js +355 -0
- package/docs/imessage-direct-provider.md +106 -0
- package/docs/rental-listings.md +94 -0
- package/package.json +600 -0
- package/skills/ghostget/SKILL.md +251 -0
- package/skills/ghostget/agents/openai.yaml +4 -0
- package/skills/ghostget/references/adapter-contract.md +181 -0
- package/skills/ghostget/references/apple-photos.md +115 -0
- package/skills/ghostget/references/article-drafts.md +235 -0
- package/skills/ghostget/references/code-owned-provider-scaffold.md +134 -0
- package/skills/ghostget/references/cross-posting-video.md +139 -0
- package/skills/ghostget/references/cross-posting.md +82 -0
- package/skills/ghostget/references/derivation.md +390 -0
- package/skills/ghostget/references/hraness-social-profile-stats.json +269 -0
- package/skills/ghostget/references/install.md +66 -0
- package/skills/ghostget/references/linkedin-adapter.md +442 -0
- package/skills/ghostget/references/messaging.md +168 -0
- package/skills/ghostget/references/meta-comet-contract.md +153 -0
- package/skills/ghostget/references/platform-patterns.md +122 -0
- package/skills/ghostget/references/provider-plugins.md +496 -0
- package/skills/ghostget/references/reddit-flair.md +78 -0
- package/skills/ghostget/references/safety-and-state.md +214 -0
- package/skills/ghostget/references/settlement-and-duplicate-cleanup.md +79 -0
- package/skills/ghostget/references/social-platform-routing.md +66 -0
- package/skills/ghostget/references/social-profile-stats.md +195 -0
- package/skills/ghostget/references/social-video-platform-routing.md +89 -0
- package/skills/ghostget/references/whatsapp-adapter.md +101 -0
- package/skills/ghostget/references/x-adapter.md +332 -0
- package/skills/ghostget/references/x-ai-disclosure.md +71 -0
- package/src/apple-photos-cli.ts +639 -0
- package/src/apple-photos-client-types.ts +168 -0
- package/src/apple-photos-client.ts +201 -0
- package/src/apple-photos-contact-evidence.ts +838 -0
- package/src/apple-photos-local-source.ts +1131 -0
- package/src/args.ts +2053 -0
- package/src/article-draft-document.ts +417 -0
- package/src/article-draft-embeds.ts +123 -0
- package/src/article-draft-images.ts +214 -0
- package/src/assets/adapter-template/wrench-adapter.json +40 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.json +1500 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v1.0.0.json +129 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v1.1.0.json +207 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v2.0.0.json +1463 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v2.1.0.json +1463 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v2.2.0.json +1475 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v2.3.0.json +1488 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.json +684 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.0.0.json +581 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.1.0.json +581 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.2.0.json +581 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.3.0.json +615 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.4.0.json +684 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.5.0.json +684 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.6.0.json +684 -0
- package/src/assets/adapters/clasificados/wrench-web-adapter.json +54 -0
- package/src/assets/adapters/facebook/wrench-web-adapter.json +750 -0
- package/src/assets/adapters/facebook/wrench-web-adapter.v1.0.0.json +706 -0
- package/src/assets/adapters/facebook/wrench-web-adapter.v1.1.0.json +703 -0
- package/src/assets/adapters/facebook/wrench-web-adapter.v1.2.0.json +750 -0
- package/src/assets/adapters/facebook-group/wrench-web-adapter.json +682 -0
- package/src/assets/adapters/facebook-group/wrench-web-adapter.v1.0.0.json +583 -0
- package/src/assets/adapters/facebook-group/wrench-web-adapter.v1.1.0.json +682 -0
- package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.json +437 -0
- package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.0.0.json +383 -0
- package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.1.0.json +437 -0
- package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.1.1.json +437 -0
- package/src/assets/adapters/facebook-page/wrench-web-adapter.json +880 -0
- package/src/assets/adapters/facebook-page/wrench-web-adapter.v1.0.0.json +740 -0
- package/src/assets/adapters/facebook-page/wrench-web-adapter.v1.1.0.json +880 -0
- package/src/assets/adapters/github/wrench-web-adapter.json +69 -0
- package/src/assets/adapters/github/wrench-web-adapter.v1.0.0.json +42 -0
- package/src/assets/adapters/github/wrench-web-adapter.v1.1.0.json +69 -0
- package/src/assets/adapters/gmail/wrench-adapter.json +161 -0
- package/src/assets/adapters/gmail/wrench-adapter.v1.2.0.json +157 -0
- package/src/assets/adapters/hacker-news/wrench-web-adapter.json +315 -0
- package/src/assets/adapters/hacker-news/wrench-web-adapter.v1.0.0.json +315 -0
- package/src/assets/adapters/imessage/wrench-web-adapter.json +236 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.json +719 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.0.0.json +627 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.1.0.json +609 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.2.0.json +640 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.3.0.json +671 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.4.0.json +710 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.5.0.json +710 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.6.0.json +719 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.7.0.json +719 -0
- package/src/assets/adapters/linkedin/wrench-adapter.json +442 -0
- package/src/assets/adapters/linkedin/wrench-adapter.v0.4.0.json +124 -0
- package/src/assets/adapters/linkedin/wrench-adapter.v1.0.0.json +411 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.json +914 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.0.0.json +604 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.1.0.json +604 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.10.0.json +809 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.11.0.json +809 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.12.0.json +820 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.13.0.json +819 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.14.0.json +819 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.15.0.json +819 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.16.0.json +874 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.17.0.json +874 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.18.0.json +874 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.19.0.json +874 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.2.0.json +731 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.3.0.json +768 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.4.0.json +808 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.5.0.json +808 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.6.0.json +808 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.7.0.json +825 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.8.0.json +792 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.9.0.json +809 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.json +855 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.0.0.json +577 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.1.0.json +604 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.10.0.json +712 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.11.0.json +712 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.12.0.json +712 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.2.0.json +653 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.3.0.json +712 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.4.0.json +713 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.5.0.json +712 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.6.0.json +713 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.7.0.json +713 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.8.0.json +713 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.9.0.json +713 -0
- package/src/assets/adapters/substack/wrench-web-adapter.json +936 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.0.0.json +817 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.1.0.json +812 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.2.0.json +812 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.3.0.json +902 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.4.0.json +936 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.5.0.json +936 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.6.0.json +936 -0
- package/src/assets/adapters/threads/wrench-web-adapter.json +692 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.0.0.json +629 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.1.0.json +623 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.2.0.json +622 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.3.0.json +622 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.4.0.json +622 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.5.0.json +699 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.6.0.json +693 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.7.0.json +692 -0
- package/src/assets/adapters/tiktok/wrench-web-adapter.json +762 -0
- package/src/assets/adapters/tiktok/wrench-web-adapter.v1.0.0.json +681 -0
- package/src/assets/adapters/tiktok/wrench-web-adapter.v1.1.0.json +708 -0
- package/src/assets/adapters/tiktok/wrench-web-adapter.v1.2.0.json +762 -0
- package/src/assets/adapters/tiktok/wrench-web-adapter.v1.3.0.json +762 -0
- package/src/assets/adapters/twitch/wrench-web-adapter.json +42 -0
- package/src/assets/adapters/twitch/wrench-web-adapter.v1.0.0.json +42 -0
- package/src/assets/adapters/whatsapp/wrench-web-adapter.json +400 -0
- package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.0.0.json +355 -0
- package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.1.0.json +386 -0
- package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.2.0.json +386 -0
- package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.3.0.json +400 -0
- package/src/assets/adapters/x/wrench-adapter.json +749 -0
- package/src/assets/adapters/x/wrench-adapter.v1.0.0.json +700 -0
- package/src/assets/adapters/x/wrench-adapter.v1.1.0.json +707 -0
- package/src/assets/adapters/x/wrench-web-adapter.json +712 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.1.0.json +579 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.10.0.json +685 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.11.0.json +712 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.12.0.json +712 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.13.0.json +712 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.2.0.json +578 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.3.0.json +610 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.4.0.json +617 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.5.0.json +634 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.6.0.json +632 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.7.0.json +649 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.8.0.json +649 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.9.0.json +683 -0
- package/src/assets/adapters/youtube/wrench-web-adapter.json +561 -0
- package/src/assets/adapters/youtube/wrench-web-adapter.v1.0.0.json +465 -0
- package/src/assets/adapters/youtube/wrench-web-adapter.v1.1.0.json +519 -0
- package/src/assets/adapters/youtube/wrench-web-adapter.v1.2.0.json +561 -0
- package/src/assets/adapters/youtube/wrench-web-adapter.v1.3.0.json +561 -0
- package/src/assets/code-owned-provider-template/plugin.test.ts.template +54 -0
- package/src/assets/code-owned-provider-template/plugin.ts.template +102 -0
- package/src/assets/code-owned-provider-template/runtime.internal.test.ts.template +44 -0
- package/src/assets/code-owned-provider-template/runtime.ts.template +59 -0
- package/src/assets/code-owned-provider-template/wrench-adapter.json.template +33 -0
- package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
- package/src/assets/fonts/nebula-sans/PROVENANCE.md +14 -0
- package/src/assets.d.ts +4 -0
- package/src/auth.ts +1157 -0
- package/src/beeper-client-types.ts +169 -0
- package/src/beeper-client.ts +250 -0
- package/src/beeper-contact-interactions-cli.ts +180 -0
- package/src/beeper-contact-interactions.ts +1612 -0
- package/src/beeper-message-bundle-v1.ts +257 -0
- package/src/beeper-message-like-me-cli.ts +84 -0
- package/src/beeper-message-like-me-export.ts +2274 -0
- package/src/beeper-message-like-me-recovery.ts +931 -0
- package/src/beeper-message-like-me-source.ts +4034 -0
- package/src/browser-admission.ts +928 -0
- package/src/browser-snapshots.ts +260 -0
- package/src/browser.ts +3873 -0
- package/src/canonical-json.ts +60 -0
- package/src/catalog-cli.ts +638 -0
- package/src/cli.ts +208 -0
- package/src/client-types.ts +301 -0
- package/src/client.ts +2726 -0
- package/src/confirmed-write-failure.ts +44 -0
- package/src/confirmed-write-model.ts +72 -0
- package/src/confirmed-write-platform.ts +1055 -0
- package/src/confirmed-write-program.ts +224 -0
- package/src/confirmed-write-runtime.ts +16 -0
- package/src/cursor-token.ts +228 -0
- package/src/derivation-dnr-readiness.ts +367 -0
- package/src/derivation-file-chooser.ts +384 -0
- package/src/derivation-network-boundary.ts +835 -0
- package/src/derivation-network-guard.ts +782 -0
- package/src/derivation-network-proxy-helper.ts +440 -0
- package/src/derivation-network-proxy.ts +385 -0
- package/src/derive-command-helper.ts +693 -0
- package/src/derive-fixtures.ts +343 -0
- package/src/derive-review.ts +980 -0
- package/src/derive.ts +4754 -0
- package/src/fixtures/beeper-message-like-me-v1/accounts.ndjson +2 -0
- package/src/fixtures/beeper-message-like-me-v1/conversations.ndjson +1 -0
- package/src/fixtures/beeper-message-like-me-v1/manifest.json +1 -0
- package/src/fixtures/beeper-message-like-me-v1/messages.ndjson +2 -0
- package/src/fixtures/beeper-message-like-me-v1/participants.ndjson +3 -0
- package/src/fixtures/beeper-message-like-me-v1/reactions.ndjson +1 -0
- package/src/fixtures/beeper-message-like-me-v1/tombstones.ndjson +1 -0
- package/src/ghostget.ts +3672 -0
- package/src/gmail-capture.ts +1244 -0
- package/src/har-internal.ts +1242 -0
- package/src/har.ts +743 -0
- package/src/index.ts +218 -0
- package/src/invocation-read-platform.ts +55 -0
- package/src/invocation-read-program.ts +93 -0
- package/src/invocation-read-runtime.ts +11 -0
- package/src/linked-device-lifecycle-admission.ts +450 -0
- package/src/linked-device-lifecycle-journal.ts +1560 -0
- package/src/linked-device-lifecycle-runtime.ts +1602 -0
- package/src/local-cli-admission.ts +135 -0
- package/src/local-cli-contracts.ts +271 -0
- package/src/local-cli-execution.ts +98 -0
- package/src/local-cli-surface-contract.ts +1510 -0
- package/src/local-cli-tool-identity.ts +336 -0
- package/src/media/archive.ts +2325 -0
- package/src/media/args.ts +303 -0
- package/src/media/cli.ts +287 -0
- package/src/media/doctor.ts +475 -0
- package/src/media/ffmpeg.ts +1330 -0
- package/src/media/http-capture.ts +711 -0
- package/src/media/http-probe.ts +593 -0
- package/src/media/http.ts +387 -0
- package/src/media/index.ts +10 -0
- package/src/media/local-transcription.ts +613 -0
- package/src/media/lock.ts +321 -0
- package/src/media/manifest.ts +1712 -0
- package/src/media/metadata.ts +906 -0
- package/src/media/process.ts +723 -0
- package/src/media/revision.ts +166 -0
- package/src/media/runtime-closure.ts +1063 -0
- package/src/media/source-router.ts +187 -0
- package/src/media/transcriber-config.ts +1122 -0
- package/src/media/transcript-persistence-model.ts +15 -0
- package/src/media/transcript-persistence-platform.ts +89 -0
- package/src/media/transcript-persistence-program.ts +39 -0
- package/src/media/transcript-persistence-runtime.ts +24 -0
- package/src/media/transcript.ts +616 -0
- package/src/media/utf8-order.ts +30 -0
- package/src/media/whisper-cpp.ts +464 -0
- package/src/media/whisper-language.ts +58 -0
- package/src/media/yt-dlp.ts +439 -0
- package/src/message-like-me-agentic-messaging.ts +882 -0
- package/src/messaging-action-store.ts +793 -0
- package/src/messaging-runtime.ts +2136 -0
- package/src/messaging-store.ts +539 -0
- package/src/messaging-types.ts +1663 -0
- package/src/messaging.ts +334 -0
- package/src/model.ts +2671 -0
- package/src/oauth-google.ts +888 -0
- package/src/omni-client-types.ts +306 -0
- package/src/omni-client.ts +2225 -0
- package/src/omni-limits.ts +34 -0
- package/src/omni-model.ts +1614 -0
- package/src/omni-request.ts +379 -0
- package/src/omni-runtime.ts +1632 -0
- package/src/operation-deadline.ts +189 -0
- package/src/path-helper.ts +1656 -0
- package/src/pinned-https.ts +194 -0
- package/src/plan-assets.ts +832 -0
- package/src/platform-catalog.ts +1832 -0
- package/src/plugins/beeper-linked-device/plugin.ts +310 -0
- package/src/plugins/bluesky-web/plugin.ts +178 -0
- package/src/plugins/clasificados-web/plugin.ts +66 -0
- package/src/plugins/github-web/plugin.ts +80 -0
- package/src/plugins/gmail-official/plugin.ts +110 -0
- package/src/plugins/hacker-news-web/plugin.ts +52 -0
- package/src/plugins/imessage-direct/plugin.ts +195 -0
- package/src/plugins/imessage-direct/vendor/0001-fix-keep-AppleScript-send-payloads-out-of-child-argv.patch +1430 -0
- package/src/plugins/imessage-direct/vendor/0002-feat-rpc-add-exact-chat-lookup.patch +225 -0
- package/src/plugins/imessage-direct/vendor/provenance.json +80 -0
- package/src/plugins/linkedin-official/plugin.ts +84 -0
- package/src/plugins/linkedin-web/plugin.ts +412 -0
- package/src/plugins/meta-web/plugin.ts +317 -0
- package/src/plugins/reddit-web/flair.ts +492 -0
- package/src/plugins/reddit-web/plugin.ts +477 -0
- package/src/plugins/substack-web/plugin.ts +124 -0
- package/src/plugins/tiktok-web/plugin.ts +67 -0
- package/src/plugins/twitch-web/plugin.ts +54 -0
- package/src/plugins/whatsapp-linked-device/plugin.ts +105 -0
- package/src/plugins/x-official/plugin.ts +64 -0
- package/src/plugins/x-web/plugin.ts +488 -0
- package/src/plugins/youtube-web/plugin.ts +101 -0
- package/src/portable-run-recovery.ts +466 -0
- package/src/process-identity.ts +501 -0
- package/src/profile-clone-helper.ts +104 -0
- package/src/provider-catalog-views.ts +51 -0
- package/src/provider-context.ts +69 -0
- package/src/provider-contract-definitions-x.ts +45 -0
- package/src/provider-contract-definitions.ts +948 -0
- package/src/provider-contract-input-gmail.ts +176 -0
- package/src/provider-contract-input-linkedin.ts +77 -0
- package/src/provider-contract-input-x.ts +304 -0
- package/src/provider-contract-planning.ts +23 -0
- package/src/provider-contract-semantic-identity.ts +54 -0
- package/src/provider-contracts.ts +251 -0
- package/src/provider-http.ts +723 -0
- package/src/provider-plugin-auth.ts +36 -0
- package/src/provider-plugin-builtins.ts +229 -0
- package/src/provider-plugin-cleanup-barrier.ts +229 -0
- package/src/provider-plugin-cleanup-execution.ts +79 -0
- package/src/provider-plugin-cleanup-resource.ts +470 -0
- package/src/provider-plugin-contract-identity.ts +707 -0
- package/src/provider-plugin-host.ts +1972 -0
- package/src/provider-plugin-identifiers.ts +60 -0
- package/src/provider-plugin-invocation-lease.ts +889 -0
- package/src/provider-plugin-lifecycle-kernel.ts +566 -0
- package/src/provider-plugin-lifecycle.ts +1455 -0
- package/src/provider-plugin-module-analysis.ts +336 -0
- package/src/provider-plugin-package.ts +2530 -0
- package/src/provider-plugin-portable-authority.ts +106 -0
- package/src/provider-plugin-portable-catalog.ts +94 -0
- package/src/provider-plugin-portable-identity.ts +315 -0
- package/src/provider-plugin-portable-runtime.ts +2057 -0
- package/src/provider-plugin-protocol.ts +1625 -0
- package/src/provider-plugin-registry.ts +3342 -0
- package/src/provider-plugin-store.ts +2155 -0
- package/src/provider-plugin-test-fixture.ts +5 -0
- package/src/provider-plugin.ts +4907 -0
- package/src/provider-plugins.generated.ts +43 -0
- package/src/provider-plugins.ts +8 -0
- package/src/provider-subject.ts +41 -0
- package/src/provider.ts +315 -0
- package/src/providers/beeper-local-runtime.ts +5426 -0
- package/src/providers/beeper-local.ts +2739 -0
- package/src/providers/beeper-messaging.ts +462 -0
- package/src/providers/beeper-omni.ts +1159 -0
- package/src/providers/bluesky-web-runtime.ts +2895 -0
- package/src/providers/bluesky-web.ts +1614 -0
- package/src/providers/clasificados-web-runtime.ts +255 -0
- package/src/providers/clasificados-web.ts +503 -0
- package/src/providers/contact-projection.ts +301 -0
- package/src/providers/github-read-model.ts +94 -0
- package/src/providers/github-read-platform.ts +165 -0
- package/src/providers/github-read-program.ts +97 -0
- package/src/providers/github-web-runtime.ts +320 -0
- package/src/providers/github-web.ts +403 -0
- package/src/providers/gmail-api.ts +2834 -0
- package/src/providers/gmail-omni.ts +830 -0
- package/src/providers/gmail.ts +1130 -0
- package/src/providers/hacker-news-web-runtime.ts +220 -0
- package/src/providers/hacker-news-web.ts +809 -0
- package/src/providers/imessage-direct-install.ts +354 -0
- package/src/providers/imessage-direct-messaging.ts +532 -0
- package/src/providers/imessage-direct-omni.ts +400 -0
- package/src/providers/imessage-direct-runtime.ts +1498 -0
- package/src/providers/imessage-direct.ts +351 -0
- package/src/providers/instagram-video-foundations.ts +913 -0
- package/src/providers/instagram-web-profile-browser.ts +600 -0
- package/src/providers/iso-bmff.ts +338 -0
- package/src/providers/linkedin-company-platform.ts +42 -0
- package/src/providers/linkedin-company-program.ts +88 -0
- package/src/providers/linkedin-contact-failure.ts +84 -0
- package/src/providers/linkedin-contact-platform.ts +45 -0
- package/src/providers/linkedin-contact-program.ts +91 -0
- package/src/providers/linkedin-profile-activity-failure.ts +76 -0
- package/src/providers/linkedin-profile-activity-platform.ts +41 -0
- package/src/providers/linkedin-profile-activity-program.ts +67 -0
- package/src/providers/linkedin-read-failure.ts +52 -0
- package/src/providers/linkedin-self-platform.ts +53 -0
- package/src/providers/linkedin-self-program.ts +122 -0
- package/src/providers/linkedin-web-article-browser.ts +794 -0
- package/src/providers/linkedin-web-bootstrap.ts +146 -0
- package/src/providers/linkedin-web-contact.ts +830 -0
- package/src/providers/linkedin-web-feed-browser.ts +832 -0
- package/src/providers/linkedin-web-feed.ts +864 -0
- package/src/providers/linkedin-web-post-browser.ts +653 -0
- package/src/providers/linkedin-web-profile-browser.ts +683 -0
- package/src/providers/linkedin-web-runtime.ts +2388 -0
- package/src/providers/linkedin-web.ts +3305 -0
- package/src/providers/linkedin.ts +1885 -0
- package/src/providers/meta-bootstrap.ts +1043 -0
- package/src/providers/meta-facebook-group.ts +690 -0
- package/src/providers/meta-marketplace-relay.ts +747 -0
- package/src/providers/meta-omni.ts +373 -0
- package/src/providers/meta-relay-bundle.ts +1049 -0
- package/src/providers/meta-web-descriptors.ts +1740 -0
- package/src/providers/meta-web-runtime.ts +3388 -0
- package/src/providers/meta-web.ts +2931 -0
- package/src/providers/read-failure.ts +139 -0
- package/src/providers/reddit-omni.ts +462 -0
- package/src/providers/reddit-web-runtime.ts +1929 -0
- package/src/providers/reddit-web.ts +1611 -0
- package/src/providers/rental-listings.ts +460 -0
- package/src/providers/substack-omni.ts +406 -0
- package/src/providers/substack-video-mp4.ts +33 -0
- package/src/providers/substack-web-runtime.ts +2812 -0
- package/src/providers/substack-web.ts +1502 -0
- package/src/providers/tiktok-video-mp4.ts +33 -0
- package/src/providers/tiktok-web-runtime.ts +770 -0
- package/src/providers/tiktok-web.ts +2786 -0
- package/src/providers/twitch-web-runtime.ts +226 -0
- package/src/providers/twitch-web.ts +274 -0
- package/src/providers/whatsapp-account-identity.ts +55 -0
- package/src/providers/whatsapp-contact-projection-helper.ts +874 -0
- package/src/providers/whatsapp-contact-projection-protocol.ts +403 -0
- package/src/providers/whatsapp-interaction-projection-helper.ts +1452 -0
- package/src/providers/whatsapp-interaction-projection-protocol.ts +462 -0
- package/src/providers/whatsapp-message-export-projection-protocol.ts +532 -0
- package/src/providers/whatsapp-messaging.ts +132 -0
- package/src/providers/whatsapp-omni.ts +586 -0
- package/src/providers/whatsapp-web-runtime.ts +3108 -0
- package/src/providers/whatsapp-web.ts +1037 -0
- package/src/providers/x-image-provenance.ts +523 -0
- package/src/providers/x-made-with-ai.ts +106 -0
- package/src/providers/x-transaction-id.ts +413 -0
- package/src/providers/x-web-runtime.ts +3485 -0
- package/src/providers/x-web.ts +2332 -0
- package/src/providers/x.ts +1889 -0
- package/src/providers/youtube-web-runtime.ts +1400 -0
- package/src/providers/youtube-web.ts +1221 -0
- package/src/read-admission-runtime.ts +91 -0
- package/src/read-client.ts +521 -0
- package/src/read-effect-platform.ts +7 -0
- package/src/read-effect-runtime.ts +14 -0
- package/src/read-effect.ts +52 -0
- package/src/read-projection-admission.ts +866 -0
- package/src/read-projections.ts +3151 -0
- package/src/recovery.ts +1492 -0
- package/src/reviewed-template.ts +146 -0
- package/src/run-journal.ts +1272 -0
- package/src/runtime.ts +5116 -0
- package/src/scripts/generate-provider-plugin-catalog.ts +121 -0
- package/src/scripts/install-whatsapp-protocol.sh +232 -0
- package/src/scripts/recover-install-stages.ts +1491 -0
- package/src/scripts/resolve-state-home.ts +30 -0
- package/src/scripts/scaffold-web-provider.ts +973 -0
- package/src/scripts/sync-bundled-adapters.ts +695 -0
- package/src/session-secrets.ts +1183 -0
- package/src/state-helper.bunfig.toml +2 -0
- package/src/state-helper.ts +2914 -0
- package/src/storage.ts +3842 -0
- package/src/transport-policy.ts +2 -0
- package/src/usage.ts +182 -0
- package/src/version.ts +2 -0
- package/src/web-session-authentication-policy.ts +136 -0
- package/src/web-session-cleanup-admission.ts +2344 -0
- package/src/web-session-cleanup-join.ts +99 -0
- package/src/web-session-client.ts +996 -0
- package/src/web-session-contract-definitions.ts +820 -0
- package/src/web-session-contract-planning.ts +42 -0
- package/src/web-session-contracts.ts +228 -0
- package/src/web-session-cookies.ts +500 -0
- package/src/web-session-execution.ts +385 -0
- package/src/web-session-http.ts +373 -0
- package/src/web-session-read-errors.ts +19 -0
- package/src/web-session-read-runtime.ts +124 -0
- package/src/web-session-recovery.ts +818 -0
- package/src/web-session-sites.ts +58 -0
- package/src/web-session-template.ts +994 -0
- package/src/web-session.ts +93 -0
- package/src/whatsapp-client-binding.ts +21 -0
- package/src/whatsapp-client-types.ts +75 -0
- package/src/whatsapp-client.ts +395 -0
- package/src/whatsapp-export-coordinate.ts +17 -0
- package/src/whatsapp-message-bundle-v2.ts +195 -0
- package/src/whatsapp-message-like-me-cli.ts +195 -0
- package/src/whatsapp-message-like-me-export.ts +1072 -0
- package/src/whatsapp-message-like-me-source.ts +1012 -0
- package/tsconfig.json +67 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { GhostgetAuth } from "./auth";
|
|
2
|
+
import type {
|
|
3
|
+
ProviderPluginAuthKind,
|
|
4
|
+
ProviderPluginBindingV1,
|
|
5
|
+
ProviderPluginTransport,
|
|
6
|
+
} from "./provider-plugin";
|
|
7
|
+
|
|
8
|
+
export type ProviderPluginAuthBinding = {
|
|
9
|
+
readonly surfaceId: string;
|
|
10
|
+
readonly transport: ProviderPluginTransport;
|
|
11
|
+
readonly authKinds: readonly ProviderPluginAuthKind[];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Enforce the kernel-owned relationship between a resolved plugin binding and
|
|
16
|
+
* an auth locator. Plugins choose accepted auth kinds; realm-bearing locators
|
|
17
|
+
* remain bound to the exact surface that selected them.
|
|
18
|
+
*/
|
|
19
|
+
export function requireProviderPluginAuth(
|
|
20
|
+
binding: ProviderPluginAuthBinding | ProviderPluginBindingV1,
|
|
21
|
+
auth: GhostgetAuth,
|
|
22
|
+
): void {
|
|
23
|
+
if (!binding.authKinds.includes(auth.kind)) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`provider plugin surface ${binding.surfaceId} does not accept ${auth.kind} auth`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
if (
|
|
29
|
+
(auth.kind === "oauth-token-file" || auth.kind === "linked-device-store")
|
|
30
|
+
&& auth.provider !== binding.surfaceId
|
|
31
|
+
) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`auth locator ${auth.id} is for ${auth.provider}, not ${binding.surfaceId}`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ProviderContract,
|
|
3
|
+
} from "./provider-contract-definitions";
|
|
4
|
+
import { planProviderContractDispatches } from "./provider-contract-planning";
|
|
5
|
+
import { assertContractSemanticIdentity } from "./provider-contract-semantic-identity";
|
|
6
|
+
import type {
|
|
7
|
+
ProviderApiPluginOperationDefinitionV1,
|
|
8
|
+
ProviderPluginAuthKind,
|
|
9
|
+
ProviderPluginImplementationSourceDefinitionV1,
|
|
10
|
+
ProviderPluginOmniDefinitionV1,
|
|
11
|
+
WebSessionPluginOperationDefinitionV1,
|
|
12
|
+
} from "./provider-plugin";
|
|
13
|
+
import type { WebSessionContract } from "./web-session-contract-definitions";
|
|
14
|
+
import { planWebSessionContractDispatches } from "./web-session-contract-planning";
|
|
15
|
+
import type { BrowserDispatchPlan, OperationInput } from "./model";
|
|
16
|
+
|
|
17
|
+
export type ProviderPluginOmniDefinitionsV1 = Readonly<
|
|
18
|
+
Record<string, ProviderPluginOmniDefinitionV1>
|
|
19
|
+
>;
|
|
20
|
+
|
|
21
|
+
function omniDefinition(
|
|
22
|
+
operation: string,
|
|
23
|
+
definitions: ProviderPluginOmniDefinitionsV1 | undefined,
|
|
24
|
+
): { readonly omni?: ProviderPluginOmniDefinitionV1 } {
|
|
25
|
+
const inboxRead = operation === "messaging.list"
|
|
26
|
+
|| operation === "messaging.read";
|
|
27
|
+
const definition = definitions?.[operation];
|
|
28
|
+
if (inboxRead && definition === undefined) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
`provider operation ${operation} must explicitly declare omni normalization support`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
if (!inboxRead && definition !== undefined) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`provider operation ${operation} has an unexpected inbox normalization declaration`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
return definition === undefined ? {} : { omni: definition };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function assertOmniDefinitionCoverage(
|
|
42
|
+
operations: readonly string[],
|
|
43
|
+
definitions: ProviderPluginOmniDefinitionsV1 | undefined,
|
|
44
|
+
): void {
|
|
45
|
+
const expected = operations.filter((operation) =>
|
|
46
|
+
operation === "messaging.list" || operation === "messaging.read")
|
|
47
|
+
.sort();
|
|
48
|
+
const actual = Object.keys(definitions ?? {}).sort();
|
|
49
|
+
if (
|
|
50
|
+
actual.length !== expected.length
|
|
51
|
+
|| actual.some((operation, index) => operation !== expected[index])
|
|
52
|
+
) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
"provider omni declarations must exactly cover installed messaging list/read operations",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const browserSessionAuthKinds = Object.freeze([
|
|
60
|
+
"browser-profile",
|
|
61
|
+
"cookie-source",
|
|
62
|
+
"cookies-file",
|
|
63
|
+
] as const satisfies readonly ProviderPluginAuthKind[]);
|
|
64
|
+
|
|
65
|
+
export const oauthTokenAuthKinds = Object.freeze([
|
|
66
|
+
"oauth-token-file",
|
|
67
|
+
] as const satisfies readonly ProviderPluginAuthKind[]);
|
|
68
|
+
|
|
69
|
+
export const linkedDeviceAuthKinds = Object.freeze([
|
|
70
|
+
"linked-device-store",
|
|
71
|
+
] as const satisfies readonly ProviderPluginAuthKind[]);
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Adapt reviewed official-provider definitions into complete plugin-owned host
|
|
75
|
+
* contracts. Hooks deliberately close over one exact contract version.
|
|
76
|
+
*/
|
|
77
|
+
export function officialContractOperations(
|
|
78
|
+
contracts: readonly ProviderContract[],
|
|
79
|
+
options: {
|
|
80
|
+
readonly semanticIdentity: string;
|
|
81
|
+
readonly validateInput: (
|
|
82
|
+
contract: ProviderContract,
|
|
83
|
+
input: OperationInput,
|
|
84
|
+
) => readonly string[];
|
|
85
|
+
readonly validateSubjectInput?: (
|
|
86
|
+
contract: ProviderContract,
|
|
87
|
+
input: OperationInput,
|
|
88
|
+
subject: string,
|
|
89
|
+
) => readonly string[];
|
|
90
|
+
readonly omni?: ProviderPluginOmniDefinitionsV1;
|
|
91
|
+
},
|
|
92
|
+
): readonly ProviderApiPluginOperationDefinitionV1[] {
|
|
93
|
+
assertOmniDefinitionCoverage(
|
|
94
|
+
contracts.map((contract) => contract.operation),
|
|
95
|
+
options.omni,
|
|
96
|
+
);
|
|
97
|
+
assertContractSemanticIdentity(
|
|
98
|
+
contracts[0]?.provider ?? "official provider",
|
|
99
|
+
contracts,
|
|
100
|
+
options.semanticIdentity,
|
|
101
|
+
);
|
|
102
|
+
const validateSubjectInput = options.validateSubjectInput;
|
|
103
|
+
return Object.freeze(contracts.map((contract) => Object.freeze({
|
|
104
|
+
name: contract.operation,
|
|
105
|
+
contractVersion: contract.contractVersion,
|
|
106
|
+
risk: contract.risk,
|
|
107
|
+
input: contract.input,
|
|
108
|
+
sideEffect: contract.sideEffect,
|
|
109
|
+
idempotency: contract.idempotency,
|
|
110
|
+
dedupeWindowMs: contract.dedupeWindowMs,
|
|
111
|
+
state: contract.state,
|
|
112
|
+
dispatch: contract.dispatch,
|
|
113
|
+
implementation: contract.implementation,
|
|
114
|
+
requiredScopeSets: contract.requiredScopeSets,
|
|
115
|
+
coverage: contract.coverage,
|
|
116
|
+
planDispatches: (input: OperationInput) =>
|
|
117
|
+
planProviderContractDispatches(contract, input),
|
|
118
|
+
validateInput: (input: OperationInput) =>
|
|
119
|
+
options.validateInput(contract, input),
|
|
120
|
+
...omniDefinition(contract.operation, options.omni),
|
|
121
|
+
...(validateSubjectInput === undefined
|
|
122
|
+
? {}
|
|
123
|
+
: {
|
|
124
|
+
validateSubjectInput: (input: OperationInput, subject: string) =>
|
|
125
|
+
validateSubjectInput(contract, input, subject),
|
|
126
|
+
}),
|
|
127
|
+
})));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Adapt reviewed authenticated-session definitions into complete plugin-owned
|
|
132
|
+
* host contracts. Conditional input laws are encoded in the exact input schema.
|
|
133
|
+
*/
|
|
134
|
+
export function webSessionContractOperations(
|
|
135
|
+
contracts: readonly WebSessionContract[],
|
|
136
|
+
semanticIdentity: string,
|
|
137
|
+
historicalVersions: Readonly<Record<string, readonly number[]>> = {},
|
|
138
|
+
omni?: ProviderPluginOmniDefinitionsV1,
|
|
139
|
+
planners: Readonly<Record<string, (input: OperationInput) => readonly BrowserDispatchPlan[]>> = {},
|
|
140
|
+
): readonly WebSessionPluginOperationDefinitionV1[] {
|
|
141
|
+
assertOmniDefinitionCoverage(
|
|
142
|
+
contracts.map((contract) => contract.operation),
|
|
143
|
+
omni,
|
|
144
|
+
);
|
|
145
|
+
assertContractSemanticIdentity(
|
|
146
|
+
contracts[0]?.site ?? "authenticated session",
|
|
147
|
+
contracts,
|
|
148
|
+
semanticIdentity,
|
|
149
|
+
);
|
|
150
|
+
const installedOperations = new Set(contracts.map((contract) => contract.operation));
|
|
151
|
+
for (const operation of Object.keys(planners)) {
|
|
152
|
+
if (!installedOperations.has(operation)) {
|
|
153
|
+
throw new Error(`provider dispatch planner references uninstalled operation ${operation}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return Object.freeze(contracts.map((contract) => Object.freeze({
|
|
157
|
+
name: contract.operation,
|
|
158
|
+
contractVersion: contract.contractVersion,
|
|
159
|
+
...(historicalVersions[contract.operation] === undefined
|
|
160
|
+
? {}
|
|
161
|
+
: { historicalContractVersions: historicalVersions[contract.operation] }),
|
|
162
|
+
risk: contract.risk,
|
|
163
|
+
input: contract.input,
|
|
164
|
+
sideEffect: contract.sideEffect,
|
|
165
|
+
idempotency: contract.idempotency,
|
|
166
|
+
dedupeWindowMs: contract.dedupeWindowMs,
|
|
167
|
+
state: contract.state,
|
|
168
|
+
dispatch: contract.dispatch,
|
|
169
|
+
implementation: contract.implementation,
|
|
170
|
+
planDispatches: planners[contract.operation] ?? ((input: OperationInput) =>
|
|
171
|
+
planWebSessionContractDispatches(contract, input)),
|
|
172
|
+
validateInput: () => Object.freeze([]),
|
|
173
|
+
...omniDefinition(contract.operation, omni),
|
|
174
|
+
})));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function source(
|
|
178
|
+
base: string,
|
|
179
|
+
label: string,
|
|
180
|
+
relativePath: string,
|
|
181
|
+
): ProviderPluginImplementationSourceDefinitionV1 {
|
|
182
|
+
return Object.freeze({ label, url: new URL(relativePath, base) });
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Declare one trusted source-plugin entrypoint. The registry derives and binds
|
|
187
|
+
* its complete eager and lazy value-dependency closure automatically.
|
|
188
|
+
*/
|
|
189
|
+
export function providerImplementationEntry(
|
|
190
|
+
base: string,
|
|
191
|
+
): readonly ProviderPluginImplementationSourceDefinitionV1[] {
|
|
192
|
+
return Object.freeze([source(base, "plugin.ts", "./plugin.ts")]);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function officialImplementationSources(
|
|
196
|
+
base: string,
|
|
197
|
+
implementation: "linkedin" | "x",
|
|
198
|
+
): readonly ProviderPluginImplementationSourceDefinitionV1[] {
|
|
199
|
+
return Object.freeze([
|
|
200
|
+
source(base, "plugin.ts", "./plugin.ts"),
|
|
201
|
+
source(base, "kernel/provider-plugin-builtins.ts", "../../provider-plugin-builtins.ts"),
|
|
202
|
+
source(base, "kernel/provider-contract-planning.ts", "../../provider-contract-planning.ts"),
|
|
203
|
+
source(base, "kernel/provider-contract-semantic-identity.ts", "../../provider-contract-semantic-identity.ts"),
|
|
204
|
+
source(base, "kernel/provider-context.ts", "../../provider-context.ts"),
|
|
205
|
+
source(base, "kernel/provider-subject.ts", "../../provider-subject.ts"),
|
|
206
|
+
source(base, `contracts/${implementation}-input.ts`, `../../provider-contract-input-${implementation}.ts`),
|
|
207
|
+
source(base, "kernel/provider-http.ts", "../../provider-http.ts"),
|
|
208
|
+
source(base, "kernel/operation-deadline.ts", "../../operation-deadline.ts"),
|
|
209
|
+
source(base, `providers/${implementation}.ts`, `../../providers/${implementation}.ts`),
|
|
210
|
+
]);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function webImplementationSources(
|
|
214
|
+
base: string,
|
|
215
|
+
providerSources: readonly (readonly [label: string, relativePath: string])[],
|
|
216
|
+
): readonly ProviderPluginImplementationSourceDefinitionV1[] {
|
|
217
|
+
return Object.freeze([
|
|
218
|
+
source(base, "plugin.ts", "./plugin.ts"),
|
|
219
|
+
source(base, "kernel/provider-plugin-builtins.ts", "../../provider-plugin-builtins.ts"),
|
|
220
|
+
source(base, "kernel/provider-contract-semantic-identity.ts", "../../provider-contract-semantic-identity.ts"),
|
|
221
|
+
source(base, "kernel/web-session-contract-planning.ts", "../../web-session-contract-planning.ts"),
|
|
222
|
+
source(base, "kernel/canonical-json.ts", "../../canonical-json.ts"),
|
|
223
|
+
source(base, "kernel/web-session-execution.ts", "../../web-session-execution.ts"),
|
|
224
|
+
source(base, "kernel/web-session-client.ts", "../../web-session-client.ts"),
|
|
225
|
+
source(base, "kernel/operation-deadline.ts", "../../operation-deadline.ts"),
|
|
226
|
+
source(base, "kernel/pinned-https.ts", "../../pinned-https.ts"),
|
|
227
|
+
...providerSources.map(([label, relativePath]) => source(base, label, relativePath)),
|
|
228
|
+
]);
|
|
229
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
|
|
3
|
+
import type { ProcessOwnerIdentity } from "./process-identity";
|
|
4
|
+
|
|
5
|
+
export type PortableProviderPluginCleanupContainment = {
|
|
6
|
+
readonly hostStarting: (host: ProcessOwnerIdentity) => void;
|
|
7
|
+
readonly hostStarted: (host: ProcessOwnerIdentity) => void;
|
|
8
|
+
readonly cleanupUnsafe: (cause?: unknown) => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type CleanupBarrierScope = {
|
|
12
|
+
readonly barriers: Promise<void>[];
|
|
13
|
+
readonly containment?: PortableProviderPluginCleanupContainment;
|
|
14
|
+
accepting: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type PortableProviderPluginCleanupBarrier = {
|
|
18
|
+
readonly settled: boolean;
|
|
19
|
+
readonly verified: () => void;
|
|
20
|
+
readonly unsafe: (cause?: unknown) => void;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type PortableProviderPluginOperationOutcome<T> =
|
|
24
|
+
| {
|
|
25
|
+
readonly status: "fulfilled";
|
|
26
|
+
readonly value: T;
|
|
27
|
+
}
|
|
28
|
+
| {
|
|
29
|
+
readonly status: "rejected";
|
|
30
|
+
readonly reason: unknown;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Cleanup safety is intentionally separate from the provider result. A
|
|
35
|
+
* provider failure can be safely quiescent; an unverified cleanup cannot.
|
|
36
|
+
*/
|
|
37
|
+
export class PortableProviderPluginCleanupUnverifiedError extends Error {
|
|
38
|
+
constructor(cause?: unknown) {
|
|
39
|
+
super(
|
|
40
|
+
"portable provider plugin cleanup could not be verified; its invocation lease was preserved",
|
|
41
|
+
cause === undefined ? undefined : { cause },
|
|
42
|
+
);
|
|
43
|
+
this.name = "PortableProviderPluginCleanupUnverifiedError";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const cleanupBarrierStorage = new AsyncLocalStorage<CleanupBarrierScope>();
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Register cleanup work in the current exact invocation-lease scope. The
|
|
51
|
+
* handle is still useful outside a scope, but no global state is retained.
|
|
52
|
+
*/
|
|
53
|
+
export function registerPortableProviderPluginCleanupBarrier():
|
|
54
|
+
PortableProviderPluginCleanupBarrier {
|
|
55
|
+
const scope = cleanupBarrierStorage.getStore();
|
|
56
|
+
if (scope?.accepting === false) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"portable provider plugin cleanup registration began after its operation scope closed",
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
let settled = false;
|
|
62
|
+
let resolveBarrier: (() => void) | undefined;
|
|
63
|
+
let rejectBarrier: ((cause: unknown) => void) | undefined;
|
|
64
|
+
if (scope !== undefined) {
|
|
65
|
+
const barrier = new Promise<void>((resolve, reject) => {
|
|
66
|
+
resolveBarrier = resolve;
|
|
67
|
+
rejectBarrier = reject;
|
|
68
|
+
});
|
|
69
|
+
// Cleanup may fail before the lease owner reaches its join gate. Observe
|
|
70
|
+
// the rejection immediately while retaining the original promise for the
|
|
71
|
+
// fail-closed allSettled join.
|
|
72
|
+
void barrier.catch(() => undefined);
|
|
73
|
+
scope.barriers.push(barrier);
|
|
74
|
+
}
|
|
75
|
+
const handle: PortableProviderPluginCleanupBarrier = {
|
|
76
|
+
get settled() {
|
|
77
|
+
return settled;
|
|
78
|
+
},
|
|
79
|
+
verified: () => {
|
|
80
|
+
if (settled) return;
|
|
81
|
+
settled = true;
|
|
82
|
+
resolveBarrier?.();
|
|
83
|
+
},
|
|
84
|
+
unsafe: (cause?: unknown) => {
|
|
85
|
+
if (settled) return;
|
|
86
|
+
settled = true;
|
|
87
|
+
let unsafeCause: unknown = cause ?? new Error(
|
|
88
|
+
"portable provider plugin cleanup was not verified",
|
|
89
|
+
);
|
|
90
|
+
try {
|
|
91
|
+
scope?.containment?.cleanupUnsafe(unsafeCause);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
unsafeCause = error;
|
|
94
|
+
}
|
|
95
|
+
rejectBarrier?.(unsafeCause);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
return Object.freeze(handle);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Announce the exact admission-gated host before portable code is allowed to
|
|
103
|
+
* execute. A lease-backed scope persists this identity synchronously.
|
|
104
|
+
*/
|
|
105
|
+
export function announcePortableProviderPluginHostStarting(
|
|
106
|
+
host: ProcessOwnerIdentity,
|
|
107
|
+
): void {
|
|
108
|
+
cleanupBarrierStorage.getStore()?.containment?.hostStarting(host);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Announce that the already-bound host crossed its admission gate.
|
|
113
|
+
*/
|
|
114
|
+
export function announcePortableProviderPluginHostStarted(
|
|
115
|
+
host: ProcessOwnerIdentity,
|
|
116
|
+
): void {
|
|
117
|
+
cleanupBarrierStorage.getStore()?.containment?.hostStarted(host);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Keep a host promise in the lease scope even when an outer operation
|
|
122
|
+
* deadline has already returned a terminal outcome. A real host separately
|
|
123
|
+
* reports whether its cleanup was safe; a test or alternate host's settled
|
|
124
|
+
* promise is its cleanup boundary.
|
|
125
|
+
*/
|
|
126
|
+
export function trackPortableProviderPluginHostCompletion<T>(
|
|
127
|
+
host: Promise<T>,
|
|
128
|
+
): Promise<T> {
|
|
129
|
+
const barrier = registerPortableProviderPluginCleanupBarrier();
|
|
130
|
+
void host.then(
|
|
131
|
+
() => barrier.verified(),
|
|
132
|
+
() => barrier.verified(),
|
|
133
|
+
);
|
|
134
|
+
return host;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function awaitCleanupBarriers(
|
|
138
|
+
scope: CleanupBarrierScope,
|
|
139
|
+
): Promise<void> {
|
|
140
|
+
const failures: unknown[] = [];
|
|
141
|
+
let joined = 0;
|
|
142
|
+
for (;;) {
|
|
143
|
+
const pending = scope.barriers.slice(joined);
|
|
144
|
+
joined = scope.barriers.length;
|
|
145
|
+
if (pending.length > 0) {
|
|
146
|
+
const results = await Promise.allSettled(pending);
|
|
147
|
+
for (const result of results) {
|
|
148
|
+
if (result.status === "rejected") failures.push(result.reason);
|
|
149
|
+
}
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
// Give descendants resumed by the last barrier one microtask to register
|
|
153
|
+
// their own narrower cleanup boundary before declaring quiescence.
|
|
154
|
+
await Promise.resolve();
|
|
155
|
+
if (joined === scope.barriers.length) break;
|
|
156
|
+
}
|
|
157
|
+
if (failures.length > 0) {
|
|
158
|
+
throw new PortableProviderPluginCleanupUnverifiedError(failures[0]);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** One native context, shared by a program's individually admitted foreign calls. */
|
|
163
|
+
export function createPortableProviderPluginCleanupContext(options: {
|
|
164
|
+
readonly containment?: PortableProviderPluginCleanupContainment;
|
|
165
|
+
readonly cleanupComplete?: () => void;
|
|
166
|
+
} = {}) {
|
|
167
|
+
const parentScope = cleanupBarrierStorage.getStore();
|
|
168
|
+
const parentJoin = parentScope === undefined
|
|
169
|
+
? undefined
|
|
170
|
+
: registerPortableProviderPluginCleanupBarrier();
|
|
171
|
+
const containment = options.containment ?? parentScope?.containment;
|
|
172
|
+
const scope: CleanupBarrierScope = {
|
|
173
|
+
barriers: [], accepting: true,
|
|
174
|
+
...(containment === undefined ? {} : { containment }),
|
|
175
|
+
};
|
|
176
|
+
return Object.freeze({
|
|
177
|
+
run: <A>(operation: () => A): A => cleanupBarrierStorage.run(scope, operation),
|
|
178
|
+
closeRegistration: () => { scope.accepting = false; },
|
|
179
|
+
join: () => awaitCleanupBarriers(scope),
|
|
180
|
+
complete: () => { options.cleanupComplete?.(); parentJoin?.verified(); },
|
|
181
|
+
unsafe: (cause: unknown) => { scope.accepting = false; parentJoin?.unsafe(cause); },
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Settle an operation independently from its cleanup join. Callers may publish
|
|
187
|
+
* an ordinary provider failure, but may release the exact durable lease only
|
|
188
|
+
* after this function returns an outcome.
|
|
189
|
+
*/
|
|
190
|
+
export async function settlePortableProviderPluginCleanup<T>(
|
|
191
|
+
operation: () => Promise<T>,
|
|
192
|
+
options: {
|
|
193
|
+
readonly containment?: PortableProviderPluginCleanupContainment;
|
|
194
|
+
/**
|
|
195
|
+
* Persist the outer lease owner's cleanup-complete transition only after
|
|
196
|
+
* every barrier in this exact scope has joined successfully.
|
|
197
|
+
*/
|
|
198
|
+
readonly cleanupComplete?: () => void;
|
|
199
|
+
} = {},
|
|
200
|
+
): Promise<PortableProviderPluginOperationOutcome<T>> {
|
|
201
|
+
const context = createPortableProviderPluginCleanupContext(options);
|
|
202
|
+
try {
|
|
203
|
+
const outcome = await context.run(
|
|
204
|
+
async (): Promise<PortableProviderPluginOperationOutcome<T>> => {
|
|
205
|
+
try {
|
|
206
|
+
return Object.freeze({
|
|
207
|
+
status: "fulfilled" as const,
|
|
208
|
+
value: await operation(),
|
|
209
|
+
});
|
|
210
|
+
} catch (reason) {
|
|
211
|
+
return Object.freeze({
|
|
212
|
+
status: "rejected" as const,
|
|
213
|
+
reason,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
);
|
|
218
|
+
// Resource owners must register their barrier before starting the
|
|
219
|
+
// resource. Once the operation settles, descendants may finish already
|
|
220
|
+
// registered cleanup but cannot introduce a late unjoined boundary.
|
|
221
|
+
context.closeRegistration();
|
|
222
|
+
await context.join();
|
|
223
|
+
context.complete();
|
|
224
|
+
return outcome;
|
|
225
|
+
} catch (error) {
|
|
226
|
+
context.unsafe(error);
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { ProviderPluginCleanupResourceIdentity } from "./provider-plugin-cleanup-resource";
|
|
2
|
+
|
|
3
|
+
export type ProviderPluginCleanupResourcePublisher = (
|
|
4
|
+
resource: ProviderPluginCleanupResourceIdentity,
|
|
5
|
+
) => void;
|
|
6
|
+
|
|
7
|
+
export type ProviderPluginCleanupBarrierRegistrar = (
|
|
8
|
+
barrier: Promise<void>,
|
|
9
|
+
) => ProviderPluginCleanupResourcePublisher | void;
|
|
10
|
+
|
|
11
|
+
export type ProviderPluginCleanupProofController = {
|
|
12
|
+
/** Call only after every published process/resource is exactly quiescent. */
|
|
13
|
+
readonly verified: () => void;
|
|
14
|
+
/** Preserve durable admission when exact cleanup cannot be proved. */
|
|
15
|
+
readonly unsafe: (reason: unknown) => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Register cleanup before starting resource-owning asynchronous work. If the
|
|
20
|
+
* durable registrar has closed, `start` is never called.
|
|
21
|
+
*/
|
|
22
|
+
export function startProviderPluginCleanupTrackedOperation<T>(
|
|
23
|
+
register: ProviderPluginCleanupBarrierRegistrar | undefined,
|
|
24
|
+
start: (
|
|
25
|
+
publishCleanupResource: ProviderPluginCleanupResourcePublisher | undefined,
|
|
26
|
+
cleanup: ProviderPluginCleanupProofController,
|
|
27
|
+
) => Promise<T>,
|
|
28
|
+
): Promise<T> {
|
|
29
|
+
if (register === undefined) {
|
|
30
|
+
return start(undefined, Object.freeze({
|
|
31
|
+
verified: () => undefined,
|
|
32
|
+
unsafe: () => undefined,
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
let resolveCleanup: (() => void) | undefined;
|
|
36
|
+
let rejectCleanup: ((reason: unknown) => void) | undefined;
|
|
37
|
+
let settled = false;
|
|
38
|
+
const cleanupBarrier = new Promise<void>((resolve, reject) => {
|
|
39
|
+
resolveCleanup = resolve;
|
|
40
|
+
rejectCleanup = reject;
|
|
41
|
+
});
|
|
42
|
+
// Prevent a rejection from becoming process-global before the outer cleanup
|
|
43
|
+
// join observes the registered barrier.
|
|
44
|
+
void cleanupBarrier.catch(() => undefined);
|
|
45
|
+
const publishCleanupResource = register(cleanupBarrier);
|
|
46
|
+
const cleanup: ProviderPluginCleanupProofController = Object.freeze({
|
|
47
|
+
verified: () => {
|
|
48
|
+
if (settled) return;
|
|
49
|
+
settled = true;
|
|
50
|
+
resolveCleanup?.();
|
|
51
|
+
},
|
|
52
|
+
unsafe: (reason) => {
|
|
53
|
+
if (settled) return;
|
|
54
|
+
settled = true;
|
|
55
|
+
rejectCleanup?.(
|
|
56
|
+
reason instanceof Error
|
|
57
|
+
? reason
|
|
58
|
+
: new Error("provider cleanup could not be verified"),
|
|
59
|
+
);
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
try {
|
|
63
|
+
return Promise.resolve(start(
|
|
64
|
+
typeof publishCleanupResource === "function"
|
|
65
|
+
? publishCleanupResource
|
|
66
|
+
: undefined,
|
|
67
|
+
cleanup,
|
|
68
|
+
)).catch((error: unknown) => {
|
|
69
|
+
// A runtime that rejects before it can prove cleanup must never leave an
|
|
70
|
+
// indefinitely pending barrier or accidentally release durable admission.
|
|
71
|
+
// If cleanup was already verified, the settled guard preserves that proof.
|
|
72
|
+
cleanup.unsafe(error);
|
|
73
|
+
throw error;
|
|
74
|
+
});
|
|
75
|
+
} catch (error) {
|
|
76
|
+
cleanup.unsafe(error);
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|