@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,747 @@
|
|
|
1
|
+
import {
|
|
2
|
+
META_RELAY_ORIGINS,
|
|
3
|
+
assertMetaPaginationCursorBinding,
|
|
4
|
+
bindMetaAccessContext,
|
|
5
|
+
bindMetaPaginationCursor,
|
|
6
|
+
buildMetaRelayRequest,
|
|
7
|
+
defineMetaOperationDescriptor,
|
|
8
|
+
metaOperationDescriptorKey,
|
|
9
|
+
type MetaAccessContext,
|
|
10
|
+
type MetaBootstrapProofDeclaration,
|
|
11
|
+
type MetaPaginationCursor,
|
|
12
|
+
type MetaRelayRequest,
|
|
13
|
+
type MetaVariableField,
|
|
14
|
+
type MetaVariableSchema,
|
|
15
|
+
} from "./meta-web-descriptors";
|
|
16
|
+
import { canonicalJson, sha256 } from "../canonical-json";
|
|
17
|
+
import { parseFacebookViewerId, parseMetaJsonScripts } from "./meta-web";
|
|
18
|
+
|
|
19
|
+
const FRIENDLY_NAME = "MarketplaceCometBrowseFeedLightPaginationQuery";
|
|
20
|
+
const REVIEWED_PAGINATION_DOC_ID = "27448592924790037";
|
|
21
|
+
const REVIEWED_CONTAINER_DOC_ID = "28097605446510041";
|
|
22
|
+
const TARGET_ID = "marketplace_home_feed";
|
|
23
|
+
const MAX_TREE_NODES = 250_000;
|
|
24
|
+
const MAX_TREE_DEPTH = 40;
|
|
25
|
+
const MAX_CURSOR_HISTORY = 48;
|
|
26
|
+
|
|
27
|
+
const SHIPPING_ICON =
|
|
28
|
+
"__relay_internal__pv__CometMarketplaceShouldShowFeedShippingIconrelayprovider";
|
|
29
|
+
const TOP_PICKS_STRIKETHROUGH =
|
|
30
|
+
"__relay_internal__pv__CometMarketplaceShouldShowTopPicksStrikethroughrelayprovider";
|
|
31
|
+
const SPONSORED_FIELD_NAME =
|
|
32
|
+
"__relay_internal__pv__GHLShouldChangeMarketplaceSponsoredDataFieldNamerelayprovider";
|
|
33
|
+
const AD_MODULE =
|
|
34
|
+
"__relay_internal__pv__MarketplaceCometAdmodulerelayprovider";
|
|
35
|
+
|
|
36
|
+
const PRELOADER_VARIABLE_FIELDS = Object.freeze([
|
|
37
|
+
SHIPPING_ICON,
|
|
38
|
+
TOP_PICKS_STRIKETHROUGH,
|
|
39
|
+
SPONSORED_FIELD_NAME,
|
|
40
|
+
AD_MODULE,
|
|
41
|
+
"buyLocation",
|
|
42
|
+
"count",
|
|
43
|
+
"cursor",
|
|
44
|
+
"imageWidth",
|
|
45
|
+
"mediaType",
|
|
46
|
+
"radius",
|
|
47
|
+
"scale",
|
|
48
|
+
"sizing",
|
|
49
|
+
"useSDFPath",
|
|
50
|
+
] as const);
|
|
51
|
+
|
|
52
|
+
type PaginationInputField = Exclude<
|
|
53
|
+
(typeof PRELOADER_VARIABLE_FIELDS)[number],
|
|
54
|
+
"count" | "cursor"
|
|
55
|
+
>;
|
|
56
|
+
|
|
57
|
+
type JsonRecord = Record<string, unknown>;
|
|
58
|
+
|
|
59
|
+
export type FacebookMarketplacePaginationCursor = {
|
|
60
|
+
readonly schemaVersion: 1;
|
|
61
|
+
readonly inputHash: string;
|
|
62
|
+
readonly descriptorKey: string;
|
|
63
|
+
readonly actorId: string;
|
|
64
|
+
readonly targetId: string;
|
|
65
|
+
readonly cursor: string;
|
|
66
|
+
readonly cursorHistory: readonly string[];
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const marketplacePaginationBindings =
|
|
70
|
+
new WeakMap<object, MetaPaginationCursor>();
|
|
71
|
+
|
|
72
|
+
function isRecord(value: unknown): value is JsonRecord {
|
|
73
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isUnknownArray(value: unknown): value is readonly unknown[] {
|
|
77
|
+
return Array.isArray(value);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function record(value: unknown, label: string): JsonRecord {
|
|
81
|
+
if (!isRecord(value)) throw new Error(`${label} must be an object`);
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function exactKeys(value: JsonRecord, keys: readonly string[], label: string): void {
|
|
86
|
+
const observed = Object.keys(value);
|
|
87
|
+
const expected = new Set(keys);
|
|
88
|
+
if (
|
|
89
|
+
observed.length !== expected.size
|
|
90
|
+
|| observed.some((key) => !expected.has(key))
|
|
91
|
+
) throw new Error(`${label} changed its reviewed fields`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function boundedString(
|
|
95
|
+
value: unknown,
|
|
96
|
+
label: string,
|
|
97
|
+
minimum: number,
|
|
98
|
+
maximum: number,
|
|
99
|
+
): string {
|
|
100
|
+
if (
|
|
101
|
+
typeof value !== "string"
|
|
102
|
+
|| value.length < minimum
|
|
103
|
+
|| value.length > maximum
|
|
104
|
+
|| /[\0\r\n]/u.test(value)
|
|
105
|
+
) throw new Error(`${label} must be bounded text`);
|
|
106
|
+
return value;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function boundedInteger(
|
|
110
|
+
value: unknown,
|
|
111
|
+
label: string,
|
|
112
|
+
minimum: number,
|
|
113
|
+
maximum: number,
|
|
114
|
+
): number {
|
|
115
|
+
if (
|
|
116
|
+
!Number.isSafeInteger(value)
|
|
117
|
+
|| (value as number) < minimum
|
|
118
|
+
|| (value as number) > maximum
|
|
119
|
+
) throw new Error(`${label} must be a bounded integer`);
|
|
120
|
+
return value as number;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function boundedNumber(
|
|
124
|
+
value: unknown,
|
|
125
|
+
label: string,
|
|
126
|
+
minimum: number,
|
|
127
|
+
maximum: number,
|
|
128
|
+
): number {
|
|
129
|
+
if (
|
|
130
|
+
typeof value !== "number"
|
|
131
|
+
|| !Number.isFinite(value)
|
|
132
|
+
|| value < minimum
|
|
133
|
+
|| value > maximum
|
|
134
|
+
) throw new Error(`${label} must be a bounded finite number`);
|
|
135
|
+
return value;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function boolean(value: unknown, label: string): boolean {
|
|
139
|
+
if (typeof value !== "boolean") throw new Error(`${label} must be boolean`);
|
|
140
|
+
return value;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function isReviewedCometPlatformPreloaderPath(
|
|
144
|
+
roots: readonly unknown[],
|
|
145
|
+
path: readonly (string | number)[],
|
|
146
|
+
candidate: JsonRecord,
|
|
147
|
+
): boolean {
|
|
148
|
+
if (
|
|
149
|
+
path.length !== 12
|
|
150
|
+
|| typeof path[0] !== "number"
|
|
151
|
+
|| path[1] !== "require"
|
|
152
|
+
|| typeof path[2] !== "number"
|
|
153
|
+
|| path[3] !== 3
|
|
154
|
+
|| typeof path[4] !== "number"
|
|
155
|
+
|| path[5] !== "__bbox"
|
|
156
|
+
|| path[6] !== "require"
|
|
157
|
+
|| typeof path[7] !== "number"
|
|
158
|
+
|| path[8] !== 3
|
|
159
|
+
|| path[9] !== 0
|
|
160
|
+
|| path[10] !== "expectedPreloaders"
|
|
161
|
+
|| typeof path[11] !== "number"
|
|
162
|
+
) return false;
|
|
163
|
+
const root = roots[path[0]];
|
|
164
|
+
if (!isRecord(root) || !isUnknownArray(root.require)) return false;
|
|
165
|
+
const scheduled = root.require[path[2]];
|
|
166
|
+
if (
|
|
167
|
+
!isUnknownArray(scheduled)
|
|
168
|
+
|| scheduled.length !== 4
|
|
169
|
+
|| scheduled[0] !== "ScheduledServerJS"
|
|
170
|
+
|| scheduled[1] !== "handle"
|
|
171
|
+
|| scheduled[2] !== null
|
|
172
|
+
|| !isUnknownArray(scheduled[3])
|
|
173
|
+
) return false;
|
|
174
|
+
const scheduledPayload = scheduled[3][path[4]];
|
|
175
|
+
if (
|
|
176
|
+
!isRecord(scheduledPayload)
|
|
177
|
+
|| !isRecord(scheduledPayload.__bbox)
|
|
178
|
+
|| !isUnknownArray(scheduledPayload.__bbox.require)
|
|
179
|
+
) return false;
|
|
180
|
+
const platformRoot = scheduledPayload.__bbox.require[path[7]];
|
|
181
|
+
if (
|
|
182
|
+
!isUnknownArray(platformRoot)
|
|
183
|
+
|| platformRoot.length !== 4
|
|
184
|
+
|| platformRoot[0] !== "CometPlatformRootClient"
|
|
185
|
+
|| platformRoot[1] !== "initialize"
|
|
186
|
+
|| !isUnknownArray(platformRoot[2])
|
|
187
|
+
|| platformRoot[2].length !== 2
|
|
188
|
+
|| platformRoot[2][0] !== "CometFBLoggedInRootConfig"
|
|
189
|
+
|| platformRoot[2][1] !== "RequireDeferredReference"
|
|
190
|
+
|| !isUnknownArray(platformRoot[3])
|
|
191
|
+
|| platformRoot[3].length !== 1
|
|
192
|
+
) return false;
|
|
193
|
+
const configuration = platformRoot[3][0];
|
|
194
|
+
return (
|
|
195
|
+
isRecord(configuration)
|
|
196
|
+
&& isUnknownArray(configuration.expectedPreloaders)
|
|
197
|
+
&& configuration.expectedPreloaders[path[11]] === candidate
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function inputVariable(
|
|
202
|
+
name: string,
|
|
203
|
+
schema: MetaVariableSchema,
|
|
204
|
+
): MetaVariableField {
|
|
205
|
+
return Object.freeze({
|
|
206
|
+
name,
|
|
207
|
+
optional: false,
|
|
208
|
+
source: Object.freeze({ kind: "input", key: name }),
|
|
209
|
+
schema: Object.freeze(schema),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const ALL_PROOFS: readonly MetaBootstrapProofDeclaration[] = Object.freeze([
|
|
214
|
+
Object.freeze({
|
|
215
|
+
kind: "viewer",
|
|
216
|
+
source: "bootstrap.viewer",
|
|
217
|
+
sinks: Object.freeze(["access.viewer-id", "form.__user"] as const),
|
|
218
|
+
}),
|
|
219
|
+
Object.freeze({
|
|
220
|
+
kind: "actor",
|
|
221
|
+
source: "bootstrap.actor",
|
|
222
|
+
sinks: Object.freeze(["access.actor-id", "form.av"] as const),
|
|
223
|
+
}),
|
|
224
|
+
Object.freeze({
|
|
225
|
+
kind: "fb_dtsg",
|
|
226
|
+
source: "bootstrap.fb_dtsg",
|
|
227
|
+
sinks: Object.freeze(["form.fb_dtsg"] as const),
|
|
228
|
+
}),
|
|
229
|
+
Object.freeze({
|
|
230
|
+
kind: "jazoest",
|
|
231
|
+
source: "derived.fb_dtsg-jazoest",
|
|
232
|
+
sinks: Object.freeze(["form.jazoest"] as const),
|
|
233
|
+
}),
|
|
234
|
+
Object.freeze({
|
|
235
|
+
kind: "lsd",
|
|
236
|
+
source: "bootstrap.lsd",
|
|
237
|
+
sinks: Object.freeze(["form.lsd"] as const),
|
|
238
|
+
}),
|
|
239
|
+
Object.freeze({
|
|
240
|
+
kind: "client-revision",
|
|
241
|
+
source: "bootstrap.client-revision",
|
|
242
|
+
sinks: Object.freeze(["form.__rev"] as const),
|
|
243
|
+
}),
|
|
244
|
+
Object.freeze({
|
|
245
|
+
kind: "hsi",
|
|
246
|
+
source: "bootstrap.hsi",
|
|
247
|
+
sinks: Object.freeze(["form.__hsi"] as const),
|
|
248
|
+
}),
|
|
249
|
+
Object.freeze({
|
|
250
|
+
kind: "comet-environment",
|
|
251
|
+
source: "bootstrap.comet-environment",
|
|
252
|
+
sinks: Object.freeze(["form.__comet_req"] as const),
|
|
253
|
+
}),
|
|
254
|
+
Object.freeze({
|
|
255
|
+
kind: "request-counter",
|
|
256
|
+
source: "session.request-counter",
|
|
257
|
+
sinks: Object.freeze(["form.__req"] as const),
|
|
258
|
+
}),
|
|
259
|
+
] as const);
|
|
260
|
+
|
|
261
|
+
const BOOLEAN_SCHEMA = Object.freeze({ kind: "boolean" } as const);
|
|
262
|
+
|
|
263
|
+
export const FACEBOOK_MARKETPLACE_PAGINATION_DESCRIPTOR =
|
|
264
|
+
defineMetaOperationDescriptor(Object.freeze({
|
|
265
|
+
schemaVersion: 1,
|
|
266
|
+
id: "facebook-marketplace.feeds-read-pagination",
|
|
267
|
+
platform: "facebook",
|
|
268
|
+
kind: "query",
|
|
269
|
+
operationType: "query",
|
|
270
|
+
friendlyName: FRIENDLY_NAME,
|
|
271
|
+
docId: REVIEWED_PAGINATION_DOC_ID,
|
|
272
|
+
origin: META_RELAY_ORIGINS.facebook,
|
|
273
|
+
method: "POST",
|
|
274
|
+
path: "/api/graphql/",
|
|
275
|
+
contract: Object.freeze({
|
|
276
|
+
state: "observed",
|
|
277
|
+
contractVersion: 1,
|
|
278
|
+
evidenceId: "facebook-marketplace-pagination-2026-07-23",
|
|
279
|
+
}),
|
|
280
|
+
access: Object.freeze({ kind: "marketplace", actorBinding: "viewer" }),
|
|
281
|
+
proofs: ALL_PROOFS,
|
|
282
|
+
variables: Object.freeze({
|
|
283
|
+
fields: Object.freeze([
|
|
284
|
+
inputVariable(SHIPPING_ICON, BOOLEAN_SCHEMA),
|
|
285
|
+
inputVariable(TOP_PICKS_STRIKETHROUGH, BOOLEAN_SCHEMA),
|
|
286
|
+
inputVariable(SPONSORED_FIELD_NAME, BOOLEAN_SCHEMA),
|
|
287
|
+
inputVariable(AD_MODULE, BOOLEAN_SCHEMA),
|
|
288
|
+
inputVariable("buyLocation", Object.freeze({
|
|
289
|
+
kind: "object",
|
|
290
|
+
fields: Object.freeze([
|
|
291
|
+
Object.freeze({
|
|
292
|
+
name: "latitude",
|
|
293
|
+
optional: false,
|
|
294
|
+
schema: Object.freeze({ kind: "number", minimum: -90, maximum: 90 }),
|
|
295
|
+
}),
|
|
296
|
+
Object.freeze({
|
|
297
|
+
name: "longitude",
|
|
298
|
+
optional: false,
|
|
299
|
+
schema: Object.freeze({ kind: "number", minimum: -180, maximum: 180 }),
|
|
300
|
+
}),
|
|
301
|
+
]),
|
|
302
|
+
})),
|
|
303
|
+
Object.freeze({
|
|
304
|
+
name: "count",
|
|
305
|
+
optional: false,
|
|
306
|
+
source: Object.freeze({ kind: "literal", value: 5 }),
|
|
307
|
+
schema: Object.freeze({ kind: "literal", value: 5 }),
|
|
308
|
+
}),
|
|
309
|
+
Object.freeze({
|
|
310
|
+
name: "cursor",
|
|
311
|
+
optional: true,
|
|
312
|
+
source: Object.freeze({ kind: "pagination" }),
|
|
313
|
+
schema: Object.freeze({ kind: "cursor" }),
|
|
314
|
+
}),
|
|
315
|
+
inputVariable("imageWidth", Object.freeze({
|
|
316
|
+
kind: "integer",
|
|
317
|
+
minimum: 1,
|
|
318
|
+
maximum: 4_096,
|
|
319
|
+
})),
|
|
320
|
+
Object.freeze({
|
|
321
|
+
name: "includePDPRelevantListings",
|
|
322
|
+
optional: false,
|
|
323
|
+
source: Object.freeze({ kind: "literal", value: false }),
|
|
324
|
+
schema: Object.freeze({ kind: "literal", value: false }),
|
|
325
|
+
}),
|
|
326
|
+
inputVariable("mediaType", Object.freeze({
|
|
327
|
+
kind: "enum",
|
|
328
|
+
values: Object.freeze(["image/jpeg"]),
|
|
329
|
+
})),
|
|
330
|
+
Object.freeze({
|
|
331
|
+
name: "pdpListingId",
|
|
332
|
+
optional: false,
|
|
333
|
+
source: Object.freeze({ kind: "literal", value: "" }),
|
|
334
|
+
schema: Object.freeze({ kind: "literal", value: "" }),
|
|
335
|
+
}),
|
|
336
|
+
inputVariable("radius", Object.freeze({
|
|
337
|
+
kind: "integer",
|
|
338
|
+
minimum: 1,
|
|
339
|
+
maximum: 10_000_000,
|
|
340
|
+
})),
|
|
341
|
+
Object.freeze({
|
|
342
|
+
name: "refinement",
|
|
343
|
+
optional: false,
|
|
344
|
+
source: Object.freeze({ kind: "literal", value: null }),
|
|
345
|
+
schema: Object.freeze({ kind: "literal", value: null }),
|
|
346
|
+
}),
|
|
347
|
+
inputVariable("scale", Object.freeze({
|
|
348
|
+
kind: "integer",
|
|
349
|
+
minimum: 1,
|
|
350
|
+
maximum: 4,
|
|
351
|
+
})),
|
|
352
|
+
inputVariable("sizing", Object.freeze({
|
|
353
|
+
kind: "enum",
|
|
354
|
+
values: Object.freeze(["cover-fill-cropped"]),
|
|
355
|
+
})),
|
|
356
|
+
inputVariable("useSDFPath", BOOLEAN_SCHEMA),
|
|
357
|
+
]),
|
|
358
|
+
}),
|
|
359
|
+
pagination: Object.freeze({ kind: "cursor", variableName: "cursor" }),
|
|
360
|
+
responseRoots: Object.freeze([
|
|
361
|
+
Object.freeze({
|
|
362
|
+
kind: "query-data",
|
|
363
|
+
path: Object.freeze(["data", "marketplace_home_feed"]),
|
|
364
|
+
}),
|
|
365
|
+
]),
|
|
366
|
+
}));
|
|
367
|
+
|
|
368
|
+
function candidatePreloaders(roots: readonly unknown[]): readonly JsonRecord[] {
|
|
369
|
+
const candidates: JsonRecord[] = [];
|
|
370
|
+
for (const [index, value] of roots.entries()) {
|
|
371
|
+
if (!isRecord(value)) continue;
|
|
372
|
+
const root = value;
|
|
373
|
+
if (!Object.hasOwn(root, "errors")) continue;
|
|
374
|
+
if (!Array.isArray(root.errors)) {
|
|
375
|
+
throw new Error(`Marketplace Relay root[${index}].errors must be an array`);
|
|
376
|
+
}
|
|
377
|
+
if (root.errors.length > 0) {
|
|
378
|
+
throw new Error("Marketplace Relay preloader contained provider errors");
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
const seen = new WeakSet<object>();
|
|
382
|
+
const stack: {
|
|
383
|
+
readonly value: unknown;
|
|
384
|
+
readonly path: readonly (string | number)[];
|
|
385
|
+
readonly depth: number;
|
|
386
|
+
}[] = roots.map((value, index) => ({
|
|
387
|
+
value,
|
|
388
|
+
path: Object.freeze([index]),
|
|
389
|
+
depth: 0,
|
|
390
|
+
}));
|
|
391
|
+
let nodes = 0;
|
|
392
|
+
while (stack.length > 0) {
|
|
393
|
+
const current = stack.pop();
|
|
394
|
+
if (current === undefined) break;
|
|
395
|
+
nodes += 1;
|
|
396
|
+
if (nodes > MAX_TREE_NODES || current.depth > MAX_TREE_DEPTH) {
|
|
397
|
+
throw new Error("Marketplace Relay preloader exceeded its reviewed structural bound");
|
|
398
|
+
}
|
|
399
|
+
const value = current.value;
|
|
400
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
if (typeof value !== "object" || seen.has(value)) {
|
|
404
|
+
throw new Error("Marketplace Relay preloader was not plain acyclic JSON");
|
|
405
|
+
}
|
|
406
|
+
seen.add(value);
|
|
407
|
+
if (Array.isArray(value)) {
|
|
408
|
+
if (value.length > 10_000) throw new Error("Marketplace Relay preloader array exceeded its reviewed bound");
|
|
409
|
+
for (let index = value.length - 1; index >= 0; index -= 1) {
|
|
410
|
+
stack.push({
|
|
411
|
+
value: value[index],
|
|
412
|
+
path: Object.freeze([...current.path, index]),
|
|
413
|
+
depth: current.depth + 1,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
const source = record(value, "Marketplace Relay preloader object");
|
|
419
|
+
if (source.queryName === "MarketplaceCometBrowseFeedLightContainerQuery") {
|
|
420
|
+
if (
|
|
421
|
+
!isReviewedCometPlatformPreloaderPath(
|
|
422
|
+
roots,
|
|
423
|
+
current.path,
|
|
424
|
+
source,
|
|
425
|
+
)
|
|
426
|
+
) {
|
|
427
|
+
throw new Error("Marketplace Relay preloader appeared outside its reviewed root");
|
|
428
|
+
}
|
|
429
|
+
candidates.push(source);
|
|
430
|
+
}
|
|
431
|
+
const entries = Object.entries(source);
|
|
432
|
+
if (entries.length > 10_000) throw new Error("Marketplace Relay preloader object exceeded its reviewed bound");
|
|
433
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
434
|
+
const entry = entries[index];
|
|
435
|
+
if (entry === undefined) continue;
|
|
436
|
+
stack.push({
|
|
437
|
+
value: entry[1],
|
|
438
|
+
path: Object.freeze([...current.path, entry[0]]),
|
|
439
|
+
depth: current.depth + 1,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return Object.freeze(candidates);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export function extractFacebookMarketplacePaginationInput(
|
|
447
|
+
html: unknown,
|
|
448
|
+
expectedViewerId: string,
|
|
449
|
+
): Readonly<Record<string, unknown>> {
|
|
450
|
+
if (parseFacebookViewerId(html) !== expectedViewerId) {
|
|
451
|
+
throw new Error("Marketplace Relay preloader changed its bound viewer");
|
|
452
|
+
}
|
|
453
|
+
const candidates = candidatePreloaders(parseMetaJsonScripts(html));
|
|
454
|
+
if (candidates.length !== 1) {
|
|
455
|
+
throw new Error("Marketplace Relay preloader was missing or ambiguous");
|
|
456
|
+
}
|
|
457
|
+
const candidate = candidates[0];
|
|
458
|
+
if (candidate === undefined) throw new Error("Marketplace Relay preloader was missing");
|
|
459
|
+
exactKeys(
|
|
460
|
+
candidate,
|
|
461
|
+
["actorID", "preloaderID", "queryID", "queryName", "variables"],
|
|
462
|
+
"Marketplace Relay preloader",
|
|
463
|
+
);
|
|
464
|
+
if (candidate.actorID !== expectedViewerId) {
|
|
465
|
+
throw new Error("Marketplace Relay preloader actor changed its bound viewer");
|
|
466
|
+
}
|
|
467
|
+
// This loader-local label is not a Relay variable or request parameter. Its
|
|
468
|
+
// only role here is to prove the exact observed preloader record shape.
|
|
469
|
+
boundedString(candidate.preloaderID, "Marketplace Relay preloader ID", 1, 512);
|
|
470
|
+
if (
|
|
471
|
+
typeof candidate.queryID !== "string"
|
|
472
|
+
|| !/^[1-9][0-9]{9,23}$/u.test(candidate.queryID)
|
|
473
|
+
) throw new Error("Marketplace Relay preloader query ID was malformed");
|
|
474
|
+
if (candidate.queryID !== REVIEWED_CONTAINER_DOC_ID) {
|
|
475
|
+
throw new Error("Marketplace Relay preloader query ID drifted from reviewed evidence");
|
|
476
|
+
}
|
|
477
|
+
if (candidate.queryName !== "MarketplaceCometBrowseFeedLightContainerQuery") {
|
|
478
|
+
throw new Error("Marketplace Relay preloader query name drifted");
|
|
479
|
+
}
|
|
480
|
+
const variables = record(candidate.variables, "Marketplace Relay preloader variables");
|
|
481
|
+
exactKeys(variables, PRELOADER_VARIABLE_FIELDS, "Marketplace Relay preloader variables");
|
|
482
|
+
boundedInteger(variables.count, "Marketplace Relay preloader count", 1, 100);
|
|
483
|
+
if (variables.cursor !== null) {
|
|
484
|
+
throw new Error("Marketplace Relay initial preloader unexpectedly contained a cursor");
|
|
485
|
+
}
|
|
486
|
+
const location = record(variables.buyLocation, "Marketplace Relay buy location");
|
|
487
|
+
exactKeys(location, ["latitude", "longitude"], "Marketplace Relay buy location");
|
|
488
|
+
|
|
489
|
+
return Object.freeze({
|
|
490
|
+
[SHIPPING_ICON]: boolean(variables[SHIPPING_ICON], `Marketplace Relay ${SHIPPING_ICON}`),
|
|
491
|
+
[TOP_PICKS_STRIKETHROUGH]: boolean(
|
|
492
|
+
variables[TOP_PICKS_STRIKETHROUGH],
|
|
493
|
+
`Marketplace Relay ${TOP_PICKS_STRIKETHROUGH}`,
|
|
494
|
+
),
|
|
495
|
+
[SPONSORED_FIELD_NAME]: boolean(
|
|
496
|
+
variables[SPONSORED_FIELD_NAME],
|
|
497
|
+
`Marketplace Relay ${SPONSORED_FIELD_NAME}`,
|
|
498
|
+
),
|
|
499
|
+
[AD_MODULE]: boolean(variables[AD_MODULE], `Marketplace Relay ${AD_MODULE}`),
|
|
500
|
+
buyLocation: Object.freeze({
|
|
501
|
+
latitude: boundedNumber(location.latitude, "Marketplace Relay latitude", -90, 90),
|
|
502
|
+
longitude: boundedNumber(location.longitude, "Marketplace Relay longitude", -180, 180),
|
|
503
|
+
}),
|
|
504
|
+
imageWidth: boundedInteger(variables.imageWidth, "Marketplace Relay image width", 1, 4_096),
|
|
505
|
+
mediaType: boundedString(variables.mediaType, "Marketplace Relay media type", 1, 64),
|
|
506
|
+
radius: boundedInteger(variables.radius, "Marketplace Relay radius", 1, 10_000_000),
|
|
507
|
+
scale: boundedInteger(variables.scale, "Marketplace Relay scale", 1, 4),
|
|
508
|
+
sizing: boundedString(variables.sizing, "Marketplace Relay sizing", 1, 64),
|
|
509
|
+
useSDFPath: boolean(variables.useSDFPath, "Marketplace Relay SDF path flag"),
|
|
510
|
+
} satisfies Readonly<Record<PaginationInputField, unknown>>);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function facebookMarketplaceAccess(viewerId: string): MetaAccessContext {
|
|
514
|
+
return bindMetaAccessContext(
|
|
515
|
+
FACEBOOK_MARKETPLACE_PAGINATION_DESCRIPTOR,
|
|
516
|
+
Object.freeze({
|
|
517
|
+
kind: "marketplace",
|
|
518
|
+
platform: "facebook",
|
|
519
|
+
viewerId,
|
|
520
|
+
actorId: viewerId,
|
|
521
|
+
targetId: TARGET_ID,
|
|
522
|
+
} satisfies MetaAccessContext),
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function marketplacePaginationInputHash(value: unknown): string {
|
|
527
|
+
if (
|
|
528
|
+
typeof value !== "string"
|
|
529
|
+
|| !/^[a-f0-9]{64}$/u.test(value)
|
|
530
|
+
) {
|
|
531
|
+
throw new Error("Marketplace pagination input hash was malformed");
|
|
532
|
+
}
|
|
533
|
+
return value;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function marketplaceProviderCursor(value: unknown, label: string): string {
|
|
537
|
+
const cursor = boundedString(value, label, 1, 4_096);
|
|
538
|
+
if (!/^[\x20-\x7e]+$/u.test(cursor)) {
|
|
539
|
+
throw new Error(`${label} must use the reviewed printable-ASCII cursor alphabet`);
|
|
540
|
+
}
|
|
541
|
+
return cursor;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function marketplaceCursorHash(cursor: string): string {
|
|
545
|
+
return Buffer.from(sha256(cursor), "hex")
|
|
546
|
+
.subarray(0, 16)
|
|
547
|
+
.toString("base64url");
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function marketplaceCursorHistory(
|
|
551
|
+
value: unknown,
|
|
552
|
+
cursor: string,
|
|
553
|
+
): readonly string[] {
|
|
554
|
+
if (
|
|
555
|
+
!Array.isArray(value)
|
|
556
|
+
|| value.length < 1
|
|
557
|
+
|| value.length > MAX_CURSOR_HISTORY
|
|
558
|
+
|| value.some((item) =>
|
|
559
|
+
typeof item !== "string"
|
|
560
|
+
|| !/^[A-Za-z0-9_-]{22}$/u.test(item))
|
|
561
|
+
) {
|
|
562
|
+
throw new Error("Marketplace sealed cursor history was malformed");
|
|
563
|
+
}
|
|
564
|
+
const history = value as readonly string[];
|
|
565
|
+
if (
|
|
566
|
+
new Set(history).size !== history.length
|
|
567
|
+
|| history.at(-1) !== marketplaceCursorHash(cursor)
|
|
568
|
+
) {
|
|
569
|
+
throw new Error("Marketplace sealed cursor history changed its chain");
|
|
570
|
+
}
|
|
571
|
+
return Object.freeze([...history]);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function reviewedMarketplacePaginationInputHash(
|
|
575
|
+
input: Readonly<Record<string, unknown>>,
|
|
576
|
+
): string {
|
|
577
|
+
if (input.mediaType !== "image/jpeg") {
|
|
578
|
+
throw new Error("Marketplace Relay media type drifted from reviewed evidence");
|
|
579
|
+
}
|
|
580
|
+
if (input.sizing !== "cover-fill-cropped") {
|
|
581
|
+
throw new Error("Marketplace Relay sizing drifted from reviewed evidence");
|
|
582
|
+
}
|
|
583
|
+
return sha256(canonicalJson(input));
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
export function facebookMarketplacePaginationInputHash(
|
|
587
|
+
html: unknown,
|
|
588
|
+
viewerId: string,
|
|
589
|
+
): string {
|
|
590
|
+
return reviewedMarketplacePaginationInputHash(
|
|
591
|
+
extractFacebookMarketplacePaginationInput(html, viewerId),
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
export function bindFacebookMarketplacePaginationCursor(
|
|
596
|
+
viewerId: string,
|
|
597
|
+
cursor: string,
|
|
598
|
+
inputHashValue: string,
|
|
599
|
+
previous: FacebookMarketplacePaginationCursor | null = null,
|
|
600
|
+
): FacebookMarketplacePaginationCursor {
|
|
601
|
+
const access = facebookMarketplaceAccess(viewerId);
|
|
602
|
+
const inputHash = marketplacePaginationInputHash(inputHashValue);
|
|
603
|
+
const providerCursor = marketplaceProviderCursor(
|
|
604
|
+
cursor,
|
|
605
|
+
"Marketplace provider cursor",
|
|
606
|
+
);
|
|
607
|
+
if (previous !== null) {
|
|
608
|
+
if (
|
|
609
|
+
!marketplacePaginationBindings.has(previous)
|
|
610
|
+
|| previous.inputHash !== inputHash
|
|
611
|
+
) {
|
|
612
|
+
throw new Error("Marketplace pagination cursor changed its feed input context");
|
|
613
|
+
}
|
|
614
|
+
if (previous.cursorHistory.length >= MAX_CURSOR_HISTORY) {
|
|
615
|
+
throw new Error("Marketplace pagination cursor reached its reviewed chain bound");
|
|
616
|
+
}
|
|
617
|
+
if (previous.cursorHistory.includes(marketplaceCursorHash(providerCursor))) {
|
|
618
|
+
throw new Error("Marketplace pagination cursor repeated an earlier page");
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
const previousBinding = previous === null
|
|
622
|
+
? null
|
|
623
|
+
: marketplacePaginationBindings.get(previous);
|
|
624
|
+
if (previous !== null && previousBinding === undefined) {
|
|
625
|
+
throw new Error("Marketplace pagination cursor was not issued by its feed binding policy");
|
|
626
|
+
}
|
|
627
|
+
const binding = bindMetaPaginationCursor(
|
|
628
|
+
FACEBOOK_MARKETPLACE_PAGINATION_DESCRIPTOR,
|
|
629
|
+
access,
|
|
630
|
+
providerCursor,
|
|
631
|
+
previousBinding ?? null,
|
|
632
|
+
);
|
|
633
|
+
const result: FacebookMarketplacePaginationCursor = Object.freeze({
|
|
634
|
+
schemaVersion: 1,
|
|
635
|
+
inputHash,
|
|
636
|
+
descriptorKey: binding.descriptorKey,
|
|
637
|
+
actorId: binding.actorId,
|
|
638
|
+
targetId: binding.targetId,
|
|
639
|
+
cursor: binding.cursor,
|
|
640
|
+
cursorHistory: Object.freeze([
|
|
641
|
+
...(previous?.cursorHistory ?? []),
|
|
642
|
+
marketplaceCursorHash(binding.cursor),
|
|
643
|
+
]),
|
|
644
|
+
});
|
|
645
|
+
marketplacePaginationBindings.set(result, binding);
|
|
646
|
+
return result;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
export function reconstructFacebookMarketplacePaginationCursor(
|
|
650
|
+
viewerId: string,
|
|
651
|
+
value: unknown,
|
|
652
|
+
): FacebookMarketplacePaginationCursor {
|
|
653
|
+
const candidate = record(value, "Marketplace sealed pagination payload");
|
|
654
|
+
exactKeys(
|
|
655
|
+
candidate,
|
|
656
|
+
[
|
|
657
|
+
"schemaVersion",
|
|
658
|
+
"inputHash",
|
|
659
|
+
"descriptorKey",
|
|
660
|
+
"actorId",
|
|
661
|
+
"targetId",
|
|
662
|
+
"cursor",
|
|
663
|
+
"cursorHistory",
|
|
664
|
+
],
|
|
665
|
+
"Marketplace sealed pagination payload",
|
|
666
|
+
);
|
|
667
|
+
if (candidate.schemaVersion !== 1) {
|
|
668
|
+
throw new Error("Marketplace sealed pagination payload changed its schema");
|
|
669
|
+
}
|
|
670
|
+
const inputHash = marketplacePaginationInputHash(candidate.inputHash);
|
|
671
|
+
if (
|
|
672
|
+
candidate.descriptorKey !== metaOperationDescriptorKey(
|
|
673
|
+
FACEBOOK_MARKETPLACE_PAGINATION_DESCRIPTOR,
|
|
674
|
+
)
|
|
675
|
+
|| candidate.actorId !== viewerId
|
|
676
|
+
|| candidate.targetId !== TARGET_ID
|
|
677
|
+
) {
|
|
678
|
+
throw new Error("Marketplace sealed pagination payload changed its bound coordinates");
|
|
679
|
+
}
|
|
680
|
+
const cursor = marketplaceProviderCursor(
|
|
681
|
+
candidate.cursor,
|
|
682
|
+
"Marketplace sealed cursor",
|
|
683
|
+
);
|
|
684
|
+
const cursorHistory = marketplaceCursorHistory(
|
|
685
|
+
candidate.cursorHistory,
|
|
686
|
+
cursor,
|
|
687
|
+
);
|
|
688
|
+
const binding = bindMetaPaginationCursor(
|
|
689
|
+
FACEBOOK_MARKETPLACE_PAGINATION_DESCRIPTOR,
|
|
690
|
+
facebookMarketplaceAccess(viewerId),
|
|
691
|
+
cursor,
|
|
692
|
+
);
|
|
693
|
+
const current: FacebookMarketplacePaginationCursor = Object.freeze({
|
|
694
|
+
schemaVersion: 1,
|
|
695
|
+
inputHash,
|
|
696
|
+
descriptorKey: binding.descriptorKey,
|
|
697
|
+
actorId: binding.actorId,
|
|
698
|
+
targetId: binding.targetId,
|
|
699
|
+
cursor: binding.cursor,
|
|
700
|
+
cursorHistory,
|
|
701
|
+
});
|
|
702
|
+
if (
|
|
703
|
+
current.descriptorKey !== candidate.descriptorKey
|
|
704
|
+
|| current.actorId !== candidate.actorId
|
|
705
|
+
|| current.targetId !== candidate.targetId
|
|
706
|
+
) {
|
|
707
|
+
throw new Error("Marketplace sealed pagination payload failed reconstruction");
|
|
708
|
+
}
|
|
709
|
+
marketplacePaginationBindings.set(current, binding);
|
|
710
|
+
return current;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
export function facebookMarketplacePaginationCursorExhausted(
|
|
714
|
+
value: FacebookMarketplacePaginationCursor,
|
|
715
|
+
): boolean {
|
|
716
|
+
if (!marketplacePaginationBindings.has(value)) {
|
|
717
|
+
throw new Error("Marketplace pagination cursor was not issued by its feed binding policy");
|
|
718
|
+
}
|
|
719
|
+
return value.cursorHistory.length >= MAX_CURSOR_HISTORY;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
export function buildFacebookMarketplacePaginationRequest(
|
|
723
|
+
html: unknown,
|
|
724
|
+
viewerId: string,
|
|
725
|
+
paginationValue: FacebookMarketplacePaginationCursor,
|
|
726
|
+
): MetaRelayRequest {
|
|
727
|
+
const access = facebookMarketplaceAccess(viewerId);
|
|
728
|
+
const boundPagination = marketplacePaginationBindings.get(paginationValue);
|
|
729
|
+
if (boundPagination === undefined) {
|
|
730
|
+
throw new Error("Marketplace pagination cursor was not issued by its feed binding policy");
|
|
731
|
+
}
|
|
732
|
+
const input = extractFacebookMarketplacePaginationInput(html, viewerId);
|
|
733
|
+
const currentInputHash = reviewedMarketplacePaginationInputHash(input);
|
|
734
|
+
if (paginationValue.inputHash !== currentInputHash) {
|
|
735
|
+
throw new Error("Marketplace pagination cursor changed its feed input context");
|
|
736
|
+
}
|
|
737
|
+
const pagination = assertMetaPaginationCursorBinding(
|
|
738
|
+
FACEBOOK_MARKETPLACE_PAGINATION_DESCRIPTOR,
|
|
739
|
+
access,
|
|
740
|
+
boundPagination,
|
|
741
|
+
);
|
|
742
|
+
return buildMetaRelayRequest(FACEBOOK_MARKETPLACE_PAGINATION_DESCRIPTOR, {
|
|
743
|
+
input,
|
|
744
|
+
access,
|
|
745
|
+
pagination,
|
|
746
|
+
});
|
|
747
|
+
}
|