x-api-rs 3.0.1__tar.gz
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.
- x_api_rs-3.0.1/.cargo/config.toml +10 -0
- x_api_rs-3.0.1/.claude/commands/update-docs.md +68 -0
- x_api_rs-3.0.1/.claude/memory/MEMORY.md +76 -0
- x_api_rs-3.0.1/.claude/memory/ci_wheel_runner_migration.md +28 -0
- x_api_rs-3.0.1/.claude/memory/feature_block_unblock_force_remove_follower.md +11 -0
- x_api_rs-3.0.1/.claude/memory/feedback_commit_plan_files.md +11 -0
- x_api_rs-3.0.1/.claude/memory/feedback_docs_sync_priority.md +19 -0
- x_api_rs-3.0.1/.claude/memory/feedback_must_run_integration_tests.md +11 -0
- x_api_rs-3.0.1/.claude/memory/feedback_sdk_config_extensibility.md +11 -0
- x_api_rs-3.0.1/.claude/memory/feedback_string_length_charcount.md +30 -0
- x_api_rs-3.0.1/.claude/memory/feedback_subagent_completion_verify.md +14 -0
- x_api_rs-3.0.1/.claude/memory/feedback_x_obfuscation_var_names.md +16 -0
- x_api_rs-3.0.1/.claude/memory/x_content_warning_protocol_2026_06_01.md +83 -0
- x_api_rs-3.0.1/.claude/memory/x_create_tweet_protocol_2026_05_27.md +76 -0
- x_api_rs-3.0.1/.claude/memory/x_rest_endpoints_need_httpclient_trait.md +11 -0
- x_api_rs-3.0.1/.claude/plans/20260511-160000-XChat-v3-/346/200/273/350/247/210/344/270/216/351/207/207/350/256/277/347/273/223/350/256/272.md +133 -0
- x_api_rs-3.0.1/.claude/plans/20260511-160001-XChat-v3-Phase1-/345/237/272/347/241/200/350/256/276/346/226/275.md +173 -0
- x_api_rs-3.0.1/.claude/plans/20260511-160002-XChat-v3-Phase2-Enrollment.md +160 -0
- x_api_rs-3.0.1/.claude/plans/20260511-160003-XChat-v3-Phase3-1v1/345/217/221/346/224/266.md +159 -0
- x_api_rs-3.0.1/.claude/plans/20260511-160004-XChat-v3-Phase4-/347/276/244/347/273/204/345/252/222/344/275/223.md +149 -0
- x_api_rs-3.0.1/.claude/plans/20260605-CLAUDE.md/347/262/276/347/256/200/351/207/215/346/236/204/346/226/271/346/241/210.md +163 -0
- x_api_rs-3.0.1/.claude/plans/CLI/345/221/275/344/273/244/350/241/214/346/216/245/345/217/243/345/274/200/345/217/221/350/256/241/345/210/222.md +979 -0
- x_api_rs-3.0.1/.claude/plans/client_transaction_id_/345/256/236/347/216/260/350/247/204/345/210/222.md +250 -0
- x_api_rs-3.0.1/.claude/plans/completed/20260303-162336-/344/273/243/347/240/201/350/264/250/351/207/217/347/254/254/344/272/214/350/275/256/344/277/256/345/244/215.md +64 -0
- x_api_rs-3.0.1/.claude/plans/completed/20260511-160001-XChat-v3-Phase1-/345/237/272/347/241/200/350/256/276/346/226/275.md +183 -0
- x_api_rs-3.0.1/.claude/plans/completed//350/241/245/345/205/250/345/210/240/351/231/244/346/270/205/347/220/206/347/261/273/345/212/237/350/203/275-8/351/241/271.md +269 -0
- x_api_rs-3.0.1/.claude/plans/completed//351/207/215/346/236/204HTTP/345/256/242/346/210/267/347/253/257header/346/236/204/345/273/272/346/236/266/346/236/204.md +152 -0
- x_api_rs-3.0.1/.claude/plans/pending-test/20260304-163942-v2/347/247/201/344/277/241/350/260/203/346/225/264/344/270/216/346/265/213/350/257/225fixture/350/277/201/347/247/273.md +254 -0
- x_api_rs-3.0.1/.claude/plans/pending-test/20260305-101502-XChat/345/257/271/350/257/235/345/210/227/350/241/250/346/216/245/345/217/243/345/274/200/345/217/221.md +516 -0
- x_api_rs-3.0.1/.claude/plans/pending-test/20260311-163000-DM-V2/345/233/276/347/211/207/346/224/257/346/214/201.md +335 -0
- x_api_rs-3.0.1/.claude/plans/pending-test/20260328-214500-Settings/346/225/217/346/204/237/345/206/205/345/256/271/346/250/241/345/235/227/345/274/200/345/217/221/350/256/241/345/210/222.md +426 -0
- x_api_rs-3.0.1/.claude/plans/pending-test/20260407-161852-/346/220/234/347/264/242/351/207/207/351/233/206/346/250/241/345/235/227/345/274/200/345/217/221/350/256/241/345/210/222.md +295 -0
- x_api_rs-3.0.1/.claude/plans/pending-test/20260511-160002-XChat-v3-Phase2-Enrollment.md +193 -0
- x_api_rs-3.0.1/.claude/plans/pending-test/20260511-160003-XChat-v3-Phase3-1v1/345/217/221/346/224/266.md +182 -0
- x_api_rs-3.0.1/.claude/plans/pending-test/CI-CD/346/265/201/346/260/264/347/272/277/350/277/201/347/247/273/345/210/260/347/273/204/347/273/207Runner.md +256 -0
- x_api_rs-3.0.1/.claude/plans//346/226/207/346/241/243/347/264/242/345/274/225/346/233/264/346/226/260-Communities/346/250/241/345/235/227.md +148 -0
- x_api_rs-3.0.1/.claude/plans//347/224/250/346/210/267/351/207/207/351/233/206/345/212/237/350/203/275/345/274/200/345/217/221/350/256/241/345/210/222.md +459 -0
- x_api_rs-3.0.1/.claude/plans//347/244/276/345/214/272/346/250/241/345/235/227/345/274/200/345/217/221/350/256/241/345/210/222.md +692 -0
- x_api_rs-3.0.1/.claude/skills/code-docs-guardian/SKILL.md +326 -0
- x_api_rs-3.0.1/.claude/skills/code-docs-guardian/references/doc-mapping.md +107 -0
- x_api_rs-3.0.1/.claude/skills/code-docs-guardian/references/templates.md +291 -0
- x_api_rs-3.0.1/.claude/skills/protocol-reverse-engineering/SKILL.md +520 -0
- x_api_rs-3.0.1/.claude/skills/rust-async-patterns/SKILL.md +519 -0
- x_api_rs-3.0.1/.claude/skills/rust-best-practices/SKILL.md +94 -0
- x_api_rs-3.0.1/.claude/skills/rust-best-practices/references/chapter_01.md +552 -0
- x_api_rs-3.0.1/.claude/skills/rust-best-practices/references/chapter_02.md +117 -0
- x_api_rs-3.0.1/.claude/skills/rust-best-practices/references/chapter_03.md +209 -0
- x_api_rs-3.0.1/.claude/skills/rust-best-practices/references/chapter_04.md +180 -0
- x_api_rs-3.0.1/.claude/skills/rust-best-practices/references/chapter_05.md +381 -0
- x_api_rs-3.0.1/.claude/skills/rust-best-practices/references/chapter_06.md +161 -0
- x_api_rs-3.0.1/.claude/skills/rust-best-practices/references/chapter_07.md +226 -0
- x_api_rs-3.0.1/.claude/skills/rust-best-practices/references/chapter_08.md +254 -0
- x_api_rs-3.0.1/.claude/skills/rust-best-practices/references/chapter_09.md +256 -0
- x_api_rs-3.0.1/.github/docker/Dockerfile.manylinux +68 -0
- x_api_rs-3.0.1/.github/runner-docs/README.md +75 -0
- x_api_rs-3.0.1/.github/runner-docs/cloudflare-pages.md +59 -0
- x_api_rs-3.0.1/.github/runner-docs/windows-runner.md +1445 -0
- x_api_rs-3.0.1/.github/runner-docs/wsl2-runner.md +240 -0
- x_api_rs-3.0.1/.github/workflows/build-and-release.yml +735 -0
- x_api_rs-3.0.1/.github/workflows/build-docker-image.yml +79 -0
- x_api_rs-3.0.1/.github/workflows/cli-check.yml +78 -0
- x_api_rs-3.0.1/.github/workflows/cli-docker.yml +121 -0
- x_api_rs-3.0.1/.github/workflows/cli-release.yml +166 -0
- x_api_rs-3.0.1/.github/workflows/docs.yml +96 -0
- x_api_rs-3.0.1/.gitignore +156 -0
- x_api_rs-3.0.1/CLAUDE.md +376 -0
- x_api_rs-3.0.1/Cargo.lock +4401 -0
- x_api_rs-3.0.1/Cargo.toml +347 -0
- x_api_rs-3.0.1/Cross.toml +13 -0
- x_api_rs-3.0.1/Dockerfile.build +25 -0
- x_api_rs-3.0.1/Dockerfile.cli +55 -0
- x_api_rs-3.0.1/PKG-INFO +317 -0
- x_api_rs-3.0.1/README.md +291 -0
- x_api_rs-3.0.1/TwitterMessageApi.cs +501 -0
- x_api_rs-3.0.1/build-linux.sh +20 -0
- x_api_rs-3.0.1/docs/CHANGELOG.md +874 -0
- x_api_rs-3.0.1/docs/README.md +45 -0
- x_api_rs-3.0.1/docs/api/README.md +326 -0
- x_api_rs-3.0.1/docs/api/communities.md +585 -0
- x_api_rs-3.0.1/docs/api/configuration.md +210 -0
- x_api_rs-3.0.1/docs/api/dm.md +727 -0
- x_api_rs-3.0.1/docs/api/inbox.md +950 -0
- x_api_rs-3.0.1/docs/api/posts.md +1033 -0
- x_api_rs-3.0.1/docs/api/raw-http.md +289 -0
- x_api_rs-3.0.1/docs/api/search.md +311 -0
- x_api_rs-3.0.1/docs/api/settings.md +629 -0
- x_api_rs-3.0.1/docs/api/twitter-api.md +496 -0
- x_api_rs-3.0.1/docs/api/upload.md +868 -0
- x_api_rs-3.0.1/docs/api/user.md +1464 -0
- x_api_rs-3.0.1/docs/api/xchat-enrollment.md +347 -0
- x_api_rs-3.0.1/docs/architecture/xchat-e2e-capture-procedure.md +274 -0
- x_api_rs-3.0.1/docs/architecture/xchat-e2e-reverse-engineering.md +487 -0
- x_api_rs-3.0.1/docs/architecture/xchat-implementation.md +128 -0
- x_api_rs-3.0.1/docs/architecture/xchat-phase2-juicebox-spike.md +145 -0
- x_api_rs-3.0.1/docs/cli/README.md +106 -0
- x_api_rs-3.0.1/docs/cli/dm.md +247 -0
- x_api_rs-3.0.1/docs/cli/getting-started.md +292 -0
- x_api_rs-3.0.1/docs/cli/llms-full.txt +1321 -0
- x_api_rs-3.0.1/docs/cli/llms.txt +70 -0
- x_api_rs-3.0.1/docs/cli/output-schema.md +307 -0
- x_api_rs-3.0.1/docs/cli/posts.md +344 -0
- x_api_rs-3.0.1/docs/cli/raw.md +251 -0
- x_api_rs-3.0.1/docs/cli/search.md +259 -0
- x_api_rs-3.0.1/docs/cli/settings.md +527 -0
- x_api_rs-3.0.1/docs/cli/upload.md +201 -0
- x_api_rs-3.0.1/docs/cli/user.md +281 -0
- x_api_rs-3.0.1/docs/cli/xchat.md +209 -0
- x_api_rs-3.0.1/docs/daily/2026-04-20.md +13 -0
- x_api_rs-3.0.1/docs/daily/2026-04-28.md +3 -0
- x_api_rs-3.0.1/docs/daily/2026-05-08.md +26 -0
- x_api_rs-3.0.1/docs/development/README.md +54 -0
- x_api_rs-3.0.1/docs/development/cross-compile.md +255 -0
- x_api_rs-3.0.1/docs/development/doc-update-checklist.md +302 -0
- x_api_rs-3.0.1/docs/development/getting-started.md +440 -0
- x_api_rs-3.0.1/docs/development/logging.md +359 -0
- x_api_rs-3.0.1/docs/development/modules.md +462 -0
- x_api_rs-3.0.1/docs/development/testing.md +319 -0
- x_api_rs-3.0.1/docs/development/transaction.md +341 -0
- x_api_rs-3.0.1/docs/examples/README.md +536 -0
- x_api_rs-3.0.1/docs/examples/batch_operations.md +741 -0
- x_api_rs-3.0.1/docs/examples/communities_demo.md +709 -0
- x_api_rs-3.0.1/docs/examples/dm_demo.md +505 -0
- x_api_rs-3.0.1/docs/examples/inbox_demo.md +997 -0
- x_api_rs-3.0.1/docs/examples/posts_demo.md +811 -0
- x_api_rs-3.0.1/docs/examples/quickstart.md +610 -0
- x_api_rs-3.0.1/docs/examples/search_demo.md +241 -0
- x_api_rs-3.0.1/docs/examples/settings_demo.md +702 -0
- x_api_rs-3.0.1/docs/examples/upload_demo.md +574 -0
- x_api_rs-3.0.1/docs/examples/user_demo.md +810 -0
- x_api_rs-3.0.1/docs/index.md +80 -0
- x_api_rs-3.0.1/docs/llms-full.txt +1614 -0
- x_api_rs-3.0.1/docs/llms.txt +75 -0
- x_api_rs-3.0.1/docs/pypi/pep541-request-template.md +113 -0
- x_api_rs-3.0.1/examples/README.md +161 -0
- x_api_rs-3.0.1/examples/python/README.md +779 -0
- x_api_rs-3.0.1/examples/python/async_example.py +134 -0
- x_api_rs-3.0.1/examples/python/communities/search_and_join.py +145 -0
- x_api_rs-3.0.1/examples/python/dm/batch.py +89 -0
- x_api_rs-3.0.1/examples/python/dm/batch_custom_texts.py +134 -0
- x_api_rs-3.0.1/examples/python/inbox/demo_strong_types.py +161 -0
- x_api_rs-3.0.1/examples/python/inbox/test_strong_types.py +132 -0
- x_api_rs-3.0.1/examples/python/posts/clear_bookmarks.py +45 -0
- x_api_rs-3.0.1/examples/python/posts/create_with_content_warning.py +109 -0
- x_api_rs-3.0.1/examples/python/posts/delete_replies.py +88 -0
- x_api_rs-3.0.1/examples/python/search/basic.py +62 -0
- x_api_rs-3.0.1/examples/python/settings/privacy_settings.py +121 -0
- x_api_rs-3.0.1/examples/python/settings/sensitive_account.py +74 -0
- x_api_rs-3.0.1/examples/python/test_async_typing.py +109 -0
- x_api_rs-3.0.1/examples/python/upload/batch.py +102 -0
- x_api_rs-3.0.1/examples/python/user/block_unblock.py +57 -0
- x_api_rs-3.0.1/examples/python/user/get_followers.py +102 -0
- x_api_rs-3.0.1/examples/python/user/get_following.py +101 -0
- x_api_rs-3.0.1/examples/python/user/reset_profile.py +50 -0
- x_api_rs-3.0.1/examples/python/user/unsubscribe_lists.py +68 -0
- x_api_rs-3.0.1/examples/python/xchat/enroll.py +81 -0
- x_api_rs-3.0.1/examples/python/xchat/receive.py +72 -0
- x_api_rs-3.0.1/examples/python/xchat/send.py +72 -0
- x_api_rs-3.0.1/examples/python/xchat/send_batch.py +69 -0
- x_api_rs-3.0.1/examples/python/xchat/status.py +40 -0
- x_api_rs-3.0.1/examples/rust/README.md +307 -0
- x_api_rs-3.0.1/examples/rust/debug/inspect_headers.rs +101 -0
- x_api_rs-3.0.1/examples/rust/dm/batch_custom_texts.rs +155 -0
- x_api_rs-3.0.1/examples/rust/dm/with_media.rs +88 -0
- x_api_rs-3.0.1/examples/rust/posts/create_with_content_warning.rs +73 -0
- x_api_rs-3.0.1/examples/rust/simple.rs +89 -0
- x_api_rs-3.0.1/examples/rust/upload/batch.rs +74 -0
- x_api_rs-3.0.1/examples/rust/upload/single.rs +53 -0
- x_api_rs-3.0.1/mkdocs.yml +97 -0
- x_api_rs-3.0.1/pyproject.toml +52 -0
- x_api_rs-3.0.1/python/x_api_rs/__init__.py +206 -0
- x_api_rs-3.0.1/python/x_api_rs/communities/__init__.py +45 -0
- x_api_rs-3.0.1/python/x_api_rs/dm/__init__.py +62 -0
- x_api_rs-3.0.1/python/x_api_rs/fingerprint/__init__.py +36 -0
- x_api_rs-3.0.1/python/x_api_rs/inbox/__init__.py +42 -0
- x_api_rs-3.0.1/python/x_api_rs/posts/__init__.py +66 -0
- x_api_rs-3.0.1/python/x_api_rs/transaction/__init__.py +34 -0
- x_api_rs-3.0.1/python/x_api_rs/upload/__init__.py +35 -0
- x_api_rs-3.0.1/python/x_api_rs/user/__init__.py +66 -0
- x_api_rs-3.0.1/python/x_api_rs/x_api_rs.pyi +837 -0
- x_api_rs-3.0.1/python_tests/conftest.py +366 -0
- x_api_rs-3.0.1/python_tests/test_auth_token.py +92 -0
- x_api_rs-3.0.1/python_tests/test_communities.py +248 -0
- x_api_rs-3.0.1/python_tests/test_dm.py +324 -0
- x_api_rs-3.0.1/python_tests/test_inbox.py +240 -0
- x_api_rs-3.0.1/python_tests/test_posts.py +410 -0
- x_api_rs-3.0.1/python_tests/test_posts_clear_bookmarks.py +23 -0
- x_api_rs-3.0.1/python_tests/test_search.py +171 -0
- x_api_rs-3.0.1/python_tests/test_settings.py +622 -0
- x_api_rs-3.0.1/python_tests/test_transaction.py +175 -0
- x_api_rs-3.0.1/python_tests/test_upload.py +151 -0
- x_api_rs-3.0.1/python_tests/test_user.py +335 -0
- x_api_rs-3.0.1/python_tests/test_user_block.py +45 -0
- x_api_rs-3.0.1/python_tests/test_user_lists.py +49 -0
- x_api_rs-3.0.1/python_tests/test_xchat.py +348 -0
- x_api_rs-3.0.1/requirements-docs.txt +4 -0
- x_api_rs-3.0.1/scripts/README.md +223 -0
- x_api_rs-3.0.1/scripts/update_version.py +179 -0
- x_api_rs-3.0.1/scripts/xchat_capture/README.md +28 -0
- x_api_rs-3.0.1/scripts/xchat_capture/check_bulk_accounts.py +127 -0
- x_api_rs-3.0.1/scripts/xchat_capture/check_bulk_accounts.sh +75 -0
- x_api_rs-3.0.1/scripts/xchat_capture/decode_capture.py +311 -0
- x_api_rs-3.0.1/scripts/xchat_capture/instrumentation.js +201 -0
- x_api_rs-3.0.1/src/bin/twitter-cli.rs +15 -0
- x_api_rs-3.0.1/src/cli/args.rs +1244 -0
- x_api_rs-3.0.1/src/cli/auth.rs +443 -0
- x_api_rs-3.0.1/src/cli/commands/communities.rs +7 -0
- x_api_rs-3.0.1/src/cli/commands/diagnostic.rs +708 -0
- x_api_rs-3.0.1/src/cli/commands/dm.rs +335 -0
- x_api_rs-3.0.1/src/cli/commands/inbox.rs +7 -0
- x_api_rs-3.0.1/src/cli/commands/mod.rs +29 -0
- x_api_rs-3.0.1/src/cli/commands/posts.rs +390 -0
- x_api_rs-3.0.1/src/cli/commands/raw.rs +145 -0
- x_api_rs-3.0.1/src/cli/commands/search.rs +61 -0
- x_api_rs-3.0.1/src/cli/commands/settings.rs +248 -0
- x_api_rs-3.0.1/src/cli/commands/upload.rs +184 -0
- x_api_rs-3.0.1/src/cli/commands/user.rs +168 -0
- x_api_rs-3.0.1/src/cli/commands/xchat.rs +604 -0
- x_api_rs-3.0.1/src/cli/config.rs +275 -0
- x_api_rs-3.0.1/src/cli/error.rs +309 -0
- x_api_rs-3.0.1/src/cli/mod.rs +19 -0
- x_api_rs-3.0.1/src/cli/output.rs +317 -0
- x_api_rs-3.0.1/src/cli/runner.rs +378 -0
- x_api_rs-3.0.1/src/cli/signal.rs +19 -0
- x_api_rs-3.0.1/src/cli/tracing_setup.rs +32 -0
- x_api_rs-3.0.1/src/common/auth.rs +387 -0
- x_api_rs-3.0.1/src/common/client.rs +570 -0
- x_api_rs-3.0.1/src/common/debug.rs +48 -0
- x_api_rs-3.0.1/src/common/error.rs +33 -0
- x_api_rs-3.0.1/src/common/fingerprint/data/chrome.rs +241 -0
- x_api_rs-3.0.1/src/common/fingerprint/data/mod.rs +5 -0
- x_api_rs-3.0.1/src/common/fingerprint/mod.rs +30 -0
- x_api_rs-3.0.1/src/common/fingerprint/profile.rs +565 -0
- x_api_rs-3.0.1/src/common/fingerprint/types.rs +217 -0
- x_api_rs-3.0.1/src/common/mod.rs +20 -0
- x_api_rs-3.0.1/src/common/text.rs +91 -0
- x_api_rs-3.0.1/src/common/text_validation.rs +200 -0
- x_api_rs-3.0.1/src/common/transaction/client.rs +712 -0
- x_api_rs-3.0.1/src/common/transaction/cubic.rs +143 -0
- x_api_rs-3.0.1/src/common/transaction/interpolate.rs +96 -0
- x_api_rs-3.0.1/src/common/transaction/mod.rs +43 -0
- x_api_rs-3.0.1/src/common/transaction/rotation.rs +85 -0
- x_api_rs-3.0.1/src/common/transaction/utils.rs +167 -0
- x_api_rs-3.0.1/src/common/types.rs +18 -0
- x_api_rs-3.0.1/src/lib.rs +1289 -0
- x_api_rs-3.0.1/src/python/communities/client.rs +162 -0
- x_api_rs-3.0.1/src/python/communities/mod.rs +22 -0
- x_api_rs-3.0.1/src/python/communities/types.rs +245 -0
- x_api_rs-3.0.1/src/python/dm/client.rs +517 -0
- x_api_rs-3.0.1/src/python/dm/mod.rs +113 -0
- x_api_rs-3.0.1/src/python/dm/types.rs +308 -0
- x_api_rs-3.0.1/src/python/errors.rs +262 -0
- x_api_rs-3.0.1/src/python/fingerprint.rs +387 -0
- x_api_rs-3.0.1/src/python/inbox/client.rs +189 -0
- x_api_rs-3.0.1/src/python/inbox/mod.rs +50 -0
- x_api_rs-3.0.1/src/python/inbox/types.rs +678 -0
- x_api_rs-3.0.1/src/python/mod.rs +668 -0
- x_api_rs-3.0.1/src/python/posts/client.rs +388 -0
- x_api_rs-3.0.1/src/python/posts/mod.rs +39 -0
- x_api_rs-3.0.1/src/python/posts/types.rs +816 -0
- x_api_rs-3.0.1/src/python/search/client.rs +254 -0
- x_api_rs-3.0.1/src/python/search/mod.rs +26 -0
- x_api_rs-3.0.1/src/python/search/types.rs +231 -0
- x_api_rs-3.0.1/src/python/settings/client.rs +388 -0
- x_api_rs-3.0.1/src/python/settings/mod.rs +27 -0
- x_api_rs-3.0.1/src/python/settings/types.rs +464 -0
- x_api_rs-3.0.1/src/python/transaction.rs +165 -0
- x_api_rs-3.0.1/src/python/upload/client.rs +447 -0
- x_api_rs-3.0.1/src/python/upload/mod.rs +38 -0
- x_api_rs-3.0.1/src/python/upload/types.rs +670 -0
- x_api_rs-3.0.1/src/python/user/client.rs +578 -0
- x_api_rs-3.0.1/src/python/user/mod.rs +43 -0
- x_api_rs-3.0.1/src/python/user/types.rs +1006 -0
- x_api_rs-3.0.1/src/python/xchat/client.rs +477 -0
- x_api_rs-3.0.1/src/python/xchat/mod.rs +24 -0
- x_api_rs-3.0.1/src/python/xchat/types.rs +348 -0
- x_api_rs-3.0.1/src/x/communities/client.rs +349 -0
- x_api_rs-3.0.1/src/x/communities/mod.rs +12 -0
- x_api_rs-3.0.1/src/x/communities/service.rs +34 -0
- x_api_rs-3.0.1/src/x/communities/types.rs +126 -0
- x_api_rs-3.0.1/src/x/dm/client.rs +981 -0
- x_api_rs-3.0.1/src/x/dm/encoder.rs +1530 -0
- x_api_rs-3.0.1/src/x/dm/mod.rs +25 -0
- x_api_rs-3.0.1/src/x/dm/service.rs +126 -0
- x_api_rs-3.0.1/src/x/dm/types.rs +236 -0
- x_api_rs-3.0.1/src/x/inbox/client.rs +709 -0
- x_api_rs-3.0.1/src/x/inbox/mod.rs +15 -0
- x_api_rs-3.0.1/src/x/inbox/service.rs +58 -0
- x_api_rs-3.0.1/src/x/inbox/types.rs +568 -0
- x_api_rs-3.0.1/src/x/mod.rs +77 -0
- x_api_rs-3.0.1/src/x/posts/client.rs +1055 -0
- x_api_rs-3.0.1/src/x/posts/mod.rs +19 -0
- x_api_rs-3.0.1/src/x/posts/service.rs +99 -0
- x_api_rs-3.0.1/src/x/posts/types.rs +678 -0
- x_api_rs-3.0.1/src/x/search/client.rs +901 -0
- x_api_rs-3.0.1/src/x/search/mod.rs +17 -0
- x_api_rs-3.0.1/src/x/search/service.rs +73 -0
- x_api_rs-3.0.1/src/x/search/types.rs +236 -0
- x_api_rs-3.0.1/src/x/settings/client.rs +507 -0
- x_api_rs-3.0.1/src/x/settings/mod.rs +19 -0
- x_api_rs-3.0.1/src/x/settings/service.rs +251 -0
- x_api_rs-3.0.1/src/x/settings/types.rs +435 -0
- x_api_rs-3.0.1/src/x/upload/client.rs +1325 -0
- x_api_rs-3.0.1/src/x/upload/mod.rs +17 -0
- x_api_rs-3.0.1/src/x/upload/service.rs +121 -0
- x_api_rs-3.0.1/src/x/upload/types.rs +646 -0
- x_api_rs-3.0.1/src/x/user/client.rs +2103 -0
- x_api_rs-3.0.1/src/x/user/mod.rs +16 -0
- x_api_rs-3.0.1/src/x/user/service.rs +224 -0
- x_api_rs-3.0.1/src/x/user/types.rs +947 -0
- x_api_rs-3.0.1/src/x/xchat/api.rs +821 -0
- x_api_rs-3.0.1/src/x/xchat/client.rs +1405 -0
- x_api_rs-3.0.1/src/x/xchat/conversation.rs +197 -0
- x_api_rs-3.0.1/src/x/xchat/crypto.rs +902 -0
- x_api_rs-3.0.1/src/x/xchat/error.rs +281 -0
- x_api_rs-3.0.1/src/x/xchat/juicebox.rs +318 -0
- x_api_rs-3.0.1/src/x/xchat/keystore.rs +483 -0
- x_api_rs-3.0.1/src/x/xchat/mod.rs +45 -0
- x_api_rs-3.0.1/src/x/xchat/payload.rs +246 -0
- x_api_rs-3.0.1/src/x/xchat/service.rs +140 -0
- x_api_rs-3.0.1/src/x/xchat/thrift.rs +1112 -0
- x_api_rs-3.0.1/src/x/xchat/types.rs +311 -0
- x_api_rs-3.0.1/tests/.gitignore +6 -0
- x_api_rs-3.0.1/tests/CLAUDE.md +190 -0
- x_api_rs-3.0.1/tests/cli/integration_cli.rs +237 -0
- x_api_rs-3.0.1/tests/cli/integration_cli_snapshot.rs +76 -0
- x_api_rs-3.0.1/tests/cli/integration_xchat.rs +241 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_cli_snapshot__error_codes.snap +66 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_cli_snapshot__example_dm_send.snap +27 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_cli_snapshot__exit_codes.snap +19 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_cli_snapshot__invalid_args_envelope.snap +23 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_cli_snapshot__version_full.snap +23 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_xchat__xchat_delete_account_help.snap +63 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_xchat__xchat_enroll_help.snap +58 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_xchat__xchat_help.snap +61 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_xchat__xchat_receive_help.snap +63 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_xchat__xchat_reset_pin_help.snap +63 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_xchat__xchat_send_batch_custom_help.snap +61 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_xchat__xchat_send_batch_help.snap +61 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_xchat__xchat_send_help.snap +61 -0
- x_api_rs-3.0.1/tests/cli/snapshots/integration_xchat__xchat_status_help.snap +53 -0
- x_api_rs-3.0.1/tests/common/mod.rs +484 -0
- x_api_rs-3.0.1/tests/fixtures/.gitignore +7 -0
- x_api_rs-3.0.1/tests/fixtures/accounts.example.txt +4 -0
- x_api_rs-3.0.1/tests/fixtures/dm_disabled_xchat_users.txt +104 -0
- x_api_rs-3.0.1/tests/fixtures/dm_users.example.txt +10 -0
- x_api_rs-3.0.1/tests/fixtures/test_image.jpg +0 -0
- x_api_rs-3.0.1/tests/fixtures/test_video.mp4 +0 -0
- x_api_rs-3.0.1/tests/fixtures//346/226/207/346/241/210.example.txt +4 -0
- x_api_rs-3.0.1/tests/fixtures//346/234/272/345/231/250/344/272/272.png +0 -0
- x_api_rs-3.0.1/tests/fixtures//350/264/276/347/273/264/346/226/257.jpeg +0 -0
- x_api_rs-3.0.1/tests/fixtures//351/276/231/350/231/276.jpg +0 -0
- x_api_rs-3.0.1/tests/x/auth/integration_auth_token.rs +110 -0
- x_api_rs-3.0.1/tests/x/communities/integration_communities.rs +190 -0
- x_api_rs-3.0.1/tests/x/dm/integration_batch_custom_texts.rs +358 -0
- x_api_rs-3.0.1/tests/x/dm/integration_batch_v1_inbox_verify.rs +343 -0
- x_api_rs-3.0.1/tests/x/dm/integration_batch_v2_inbox_verify.rs +352 -0
- x_api_rs-3.0.1/tests/x/dm/integration_decoder.rs +388 -0
- x_api_rs-3.0.1/tests/x/dm/integration_dm_disabled_xchat.rs +71 -0
- x_api_rs-3.0.1/tests/x/dm/integration_dm_v2.rs +387 -0
- x_api_rs-3.0.1/tests/x/dm/integration_dm_with_media.rs +287 -0
- x_api_rs-3.0.1/tests/x/inbox/integration_inbox.rs +339 -0
- x_api_rs-3.0.1/tests/x/posts/integration_clear_bookmarks.rs +37 -0
- x_api_rs-3.0.1/tests/x/posts/integration_create_tweet.rs +619 -0
- x_api_rs-3.0.1/tests/x/posts/integration_delete_tweet.rs +202 -0
- x_api_rs-3.0.1/tests/x/posts/integration_favorite.rs +192 -0
- x_api_rs-3.0.1/tests/x/posts/integration_get_tweets.rs +257 -0
- x_api_rs-3.0.1/tests/x/posts/integration_retweet.rs +195 -0
- x_api_rs-3.0.1/tests/x/search/integration_search.rs +357 -0
- x_api_rs-3.0.1/tests/x/settings/integration_detection_settings.rs +193 -0
- x_api_rs-3.0.1/tests/x/settings/integration_sensitive.rs +350 -0
- x_api_rs-3.0.1/tests/x/upload/integration_batch_upload.rs +207 -0
- x_api_rs-3.0.1/tests/x/upload/integration_set_metadata.rs +132 -0
- x_api_rs-3.0.1/tests/x/upload/integration_upload.rs +158 -0
- x_api_rs-3.0.1/tests/x/upload/integration_video_upload.rs +228 -0
- x_api_rs-3.0.1/tests/x/user/integration_block.rs +73 -0
- x_api_rs-3.0.1/tests/x/user/integration_lists.rs +70 -0
- x_api_rs-3.0.1/tests/x/user/integration_remove_profile.rs +60 -0
- x_api_rs-3.0.1/tests/x/user/integration_user.rs +513 -0
- x_api_rs-3.0.1/tests/x/xchat/integration_xchat_batch_send.rs +203 -0
- x_api_rs-3.0.1/tests/x/xchat/integration_xchat_lifecycle.rs +443 -0
- x_api_rs-3.0.1/tests/x/xchat/integration_xchat_receive.rs +202 -0
- x_api_rs-3.0.1/tests/x/xchat/integration_xchat_send.rs +273 -0
- x_api_rs-3.0.1/tests/x/xchat/integration_xchat_status.rs +91 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# 使 cargo 使用系统 git CLI 拉取 git 依赖,而非内置 libgit2。
|
|
2
|
+
#
|
|
3
|
+
# 原因:juicebox_sdk@0.3.4 的子模块 artifacts 在其 .gitmodules 中使用
|
|
4
|
+
# SCP 风格 URL (`git@github.com:juicebox-systems/juicebox-sdk-artifacts.git`),
|
|
5
|
+
# libgit2 不接受这种格式("relative URL without a base"),但系统 git 接受。
|
|
6
|
+
#
|
|
7
|
+
# 配合 `git config --global url."https://github.com/".insteadOf "git@github.com:"`
|
|
8
|
+
# 把 SSH URL 重写为 HTTPS,避免 CI 上无 SSH key 拉不到子模块。
|
|
9
|
+
[net]
|
|
10
|
+
git-fetch-with-cli = true
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# 文档更新命令
|
|
2
|
+
|
|
3
|
+
自动检测代码变更并同步更新所有相关文档,确保无遗漏。
|
|
4
|
+
|
|
5
|
+
## 执行流程
|
|
6
|
+
|
|
7
|
+
### Step 1: 确定更新类型
|
|
8
|
+
|
|
9
|
+
询问用户更新类型:
|
|
10
|
+
1. **新增模块** - 新增了功能模块(如 communities)
|
|
11
|
+
2. **API 变更** - 修改了现有 API(如构造函数变更)
|
|
12
|
+
3. **其他** - 用户指定具体更新内容
|
|
13
|
+
|
|
14
|
+
### Step 2: 读取检查清单
|
|
15
|
+
|
|
16
|
+
读取 `docs/development/doc-update-checklist.md` 获取完整的更新规则。
|
|
17
|
+
|
|
18
|
+
### Step 3: 调用 docs-architect agent
|
|
19
|
+
|
|
20
|
+
使用 Task 工具调用 docs-architect agent 执行批量文档更新:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Task(
|
|
24
|
+
subagent_type="docs-architect",
|
|
25
|
+
prompt="根据以下变更更新文档:<变更描述>,参考 docs/development/doc-update-checklist.md 中的规则确保所有文件都被更新"
|
|
26
|
+
)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Step 4: 验证更新
|
|
30
|
+
|
|
31
|
+
**新增模块验证命令**:
|
|
32
|
+
```bash
|
|
33
|
+
MODULE="<module_name>"
|
|
34
|
+
grep -n "$MODULE" README.md docs/index.md docs/README.md docs/api/README.md docs/examples/README.md
|
|
35
|
+
ls docs/api/${MODULE}.md docs/examples/${MODULE}_demo.md
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**API 变更验证命令**:
|
|
39
|
+
```bash
|
|
40
|
+
grep -rn "<旧API模式>" docs/ README.md
|
|
41
|
+
# 结果应为空
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 必须更新的文件清单
|
|
45
|
+
|
|
46
|
+
### 新增模块(全部必须)
|
|
47
|
+
|
|
48
|
+
| 文件 | 内容 |
|
|
49
|
+
|------|------|
|
|
50
|
+
| `README.md` | 功能模块表格 |
|
|
51
|
+
| `docs/index.md` | 功能模块表格 |
|
|
52
|
+
| `docs/README.md` | API 参考导航 |
|
|
53
|
+
| `docs/api/README.md` | 文档列表 + 快速导航 |
|
|
54
|
+
| `docs/examples/README.md` | 示例分类表格 |
|
|
55
|
+
| `docs/api/<module>.md` | 新建 API 文档 |
|
|
56
|
+
| `docs/examples/<module>_demo.md` | 新建示例文档 |
|
|
57
|
+
|
|
58
|
+
### API 变更(全局搜索替换)
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
README.md
|
|
62
|
+
docs/**/*.md
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 客户端创建规范
|
|
66
|
+
|
|
67
|
+
正确:`client = await Twitter.create(cookies)`
|
|
68
|
+
禁止:`client = Twitter(cookies)`
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# x-api-rs 项目记忆
|
|
2
|
+
|
|
3
|
+
## 用户工作流偏好
|
|
4
|
+
- **采访式需求收集** — 技术决策由我做(遵从 Rust 理念),业务决策问用户;用户不懂 Rust,不要问技术选型问题
|
|
5
|
+
- **计划文件工作流** — 计划存 `.claude/plans/`(中文文件名),完成移至 `completed/`,待测移至 `pending-test/`
|
|
6
|
+
- **不执行直到被告知** — 用户说"开始执行"前只做分析和计划,不修改代码
|
|
7
|
+
|
|
8
|
+
## SDK 设计原则
|
|
9
|
+
- [SDK 配置必须暴露给上层](feedback_sdk_config_extensibility.md) — HTTP/性能/可用性参数(timeout/retry/proxy/pool/JA3)必须 ClientConfig 化,不能硬编码;默认值"非幂等操作安全为先"
|
|
10
|
+
- [文档同步优先级提升](feedback_docs_sync_priority.md) — 代码改动必须同 commit 更新 docs/,bug 修复/新配置项/API 变更必须当次完成(CHANGELOG + API doc)
|
|
11
|
+
|
|
12
|
+
## rquest 5.x 关键行为
|
|
13
|
+
- `.json()` 和 `.multipart()` 均使用 `or_insert` 设置 Content-Type — 已有则不覆盖
|
|
14
|
+
- header builder 中不应手动设置 Content-Type,交给 rquest body 方法自动管理
|
|
15
|
+
- **Emulation default_headers 合并陷阱** — `execute_request()` 会将 Client 的 default_headers 补充到 per-request headers 中(缺失的 key 自动补回)。`headers.remove()` 在 per-request HeaderMap 上无效,必须在 ClientBuilder 层清除:`.emulation(X).default_headers(HeaderMap::new())`
|
|
16
|
+
- **Emulation 注入的 Upgrade-Insecure-Requests** — 仅适用于导航请求,API/XHR 请求不应携带,已通过清空 default_headers 解决
|
|
17
|
+
- 源码: `~/.cargo/registry/src/index.crates.io-*/rquest-5.1.0/src/client/`
|
|
18
|
+
- **`http2_max_retry_count` 默认 = 2** — H2 收到 RST_STREAM(REFUSED_STREAM) 或 GOAWAY(NO_ERROR) 自动重发。Twitter 限流会先处理请求再发 RST_STREAM,导致非幂等写操作(DM/Posts)重复。已在 `RquestClient::build_client` 设为 0。源码: `src/client/http.rs:225, 2367-2396`
|
|
19
|
+
|
|
20
|
+
## Burp Suite 代理限制
|
|
21
|
+
- Burp 作为 TLS MITM 会破坏 JA3 指纹模拟 → Twitter 看到 Burp 的指纹 → 触发 226
|
|
22
|
+
- 大文件 multipart 上传 (>~100KB) 通过 Burp 会失败:"Stream failed to close correctly"
|
|
23
|
+
- 测试代理通过 `TEST_PROXY` 环境变量控制,默认无代理直连
|
|
24
|
+
|
|
25
|
+
## CI / 发版流水线
|
|
26
|
+
- [wheel runner 迁移方案](ci_wheel_runner_migration.md) — x86_64 慢=QEMU模拟根因;迁 ubuntu-latest + aarch64迁ubuntu-24.04-arm + macOS留Mac mini;硬约束:必须留manylinux容器(PyPI拒裸linux_x86_64)/需libclang/不改job名
|
|
27
|
+
|
|
28
|
+
## 已知架构债务
|
|
29
|
+
- `user/client.rs` 用 `as_any()` downcast 绕过 HttpClient trait
|
|
30
|
+
|
|
31
|
+
## 已完成的重构
|
|
32
|
+
- `build_upload_headers` 已删除,替换为 `UploadClient::upload_headers()`(仅含 Host + Referer)
|
|
33
|
+
- `build_twitter_headers` 不再设置 Content-Type,由 rquest body 方法自动管理
|
|
34
|
+
- Chrome 指纹数据扩展至 144 版本,支持新旧 sec-ch-ua 格式
|
|
35
|
+
- upload INIT 阶段 media_type 自动检测(magic bytes: JPEG/PNG/GIF/WebP)
|
|
36
|
+
|
|
37
|
+
## 业务功能要点
|
|
38
|
+
- [拉黑→解除拉黑 = 强制清除粉丝](feature_block_unblock_force_remove_follower.md) — block 强制对方取消关注,unblock 不会恢复
|
|
39
|
+
|
|
40
|
+
## REST 端点实现
|
|
41
|
+
- [必须走 HttpClient::post trait](x_rest_endpoints_need_httpclient_trait.md) — `.client().post()` 直链会绕过 csrf 头注入,导致 "Bad Authentication data"
|
|
42
|
+
|
|
43
|
+
## 提交规范
|
|
44
|
+
- [提交时包含计划文件](feedback_commit_plan_files.md) — git commit 时不要遗漏 .claude/plans/ 下的文件
|
|
45
|
+
|
|
46
|
+
## 开发流程
|
|
47
|
+
- [必须运行真实集成测试](feedback_must_run_integration_tests.md) — 开发完成后必须 `cargo test <模块> -- --ignored --nocapture`,不能只跑本地参数校验
|
|
48
|
+
- [子代理完成报告必须实证](feedback_subagent_completion_verify.md) — Agent 返回成功后主 session 必须独立跑 cargo 验证,不能直接采信子代理摘要
|
|
49
|
+
- [字符串长度校验用字符数而非字节数](feedback_string_length_charcount.md) — `text.len()` 是 UTF-8 字节数,中文场景会误判;DM 用 `chars().count()`,Posts 用 `twitter_weighted_length()`
|
|
50
|
+
- **CLI 无条件必须** — 任何暴露给外部的新功能(含调试工具、辅助接口),必须同时实现 CLI 子命令;不得以"调试用途"为由跳过。CLAUDE.md Phase 2.6 旧文本"若 CLI 已发布"已删除,现为无条件强制。
|
|
51
|
+
|
|
52
|
+
## Twitter GraphQL
|
|
53
|
+
- query ID 会不定期轮换,过期返回 404 → 从 [vladkens/twscrape](https://github.com/vladkens/twscrape) 获取最新值
|
|
54
|
+
- 搜索 API 并发请求易触发限流(404),需单独验证失败的测试
|
|
55
|
+
|
|
56
|
+
## ClientTransaction 调试
|
|
57
|
+
- [ondemand.s 混淆变量名会变化](feedback_x_obfuscation_var_names.md) — 报 "无法提取 KEY_BYTE indices" 时先查变量名是否从 `n[..]` 变了,正则要用 `\w` 通配
|
|
58
|
+
|
|
59
|
+
## 测试
|
|
60
|
+
- `cargo test --lib` — 可靠的单元测试(193 tests,含 settings 和清理类功能模块)
|
|
61
|
+
- `cargo test` 包含 doctest,因 crate 名称问题全部失败(已知,非回归)
|
|
62
|
+
- 集成测试代理: `TEST_PROXY=127.0.0.1:8080 cargo test ... -- --ignored --nocapture`
|
|
63
|
+
|
|
64
|
+
## 2026-06-01 抓包:content warning / disclosure 协议
|
|
65
|
+
- [content warning / disclosure 协议字段](x_content_warning_protocol_2026_06_01.md) — `media/metadata/create.json` 设置图片级:`sensitive_media_warning:[adult_content|graphic_violence|other]` + `self_reported_ai_generated:"true"` + `grok_actions.block_grok_edit:"true"`(全字符串)。CreateTweet 的 `content_disclosure.ai_generated_disclosure` 设置帖子级 Made with AI。两个 AI 字段独立
|
|
66
|
+
|
|
67
|
+
## 2026-05-27 抓包:CreateTweet 协议快照
|
|
68
|
+
- [CreateTweet 协议变更](x_create_tweet_protocol_2026_05_27.md) — queryId 轮换为 `H-t2v_HvFR07ZBP9aOeKoA`;variables 新增 `semantic_annotation_options:{source:"UniversalLink"}`、移除 `dark_request`;features 38 项含 5 项新增 / 2 项移除 / 2 项值变更;content warning(Nudity/AI) 字段待带图场景补抓
|
|
69
|
+
|
|
70
|
+
## 2026-05-08 抓包:清理类功能 GraphQL queryId(已验证)
|
|
71
|
+
- `BookmarksAllDelete: skiACZKC1GDYli-M8RzEPQ` — body `{variables:{}, queryId}`
|
|
72
|
+
- `ListUnsubscribe: -diULb6PX5grQ_MvItGiJQ` — body `{variables:{listId}, features:{6项固定}, queryId}`
|
|
73
|
+
- `ListSubscribe: Gpws7iVbAR7ebO3qCCYmPw` — 同上结构
|
|
74
|
+
- `ListsManagementPageTimeline: MZPMTf6uAC8bCYZmoiqVVg` — GET,30+ features
|
|
75
|
+
- `DeleteRetweet: ZyZigVsNiFO6v1dEks1eWg`(旧 `iQtK4dl5hBmXewYZuEOKVw` 仍有效)
|
|
76
|
+
- chrome-devtools 抓包技巧:先 `fetch main.js` regex 提取 operationName↔queryId 映射;动态 chunk 需访问对应页面触发加载(如 /i/bookmarks → bundle.Bookmarks.js)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ci-wheel-runner-migration
|
|
3
|
+
description: build-and-release.yml 三个 wheel job 的 runner 迁移方案与约束(QEMU根因/manylinux必需/成本)
|
|
4
|
+
metadata:
|
|
5
|
+
node_type: memory
|
|
6
|
+
type: project
|
|
7
|
+
originSessionId: e9324e28-4626-4b22-9fcc-51dd5db5ccb0
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
build-and-release.yml 的三个 wheel job 当前全跑在一台 self-hosted Apple Silicon Mac mini(`[self-hosted, macOS, ARM64]`)。x86_64 wheel 用 `docker run --platform linux/amd64 ... maturin build --manylinux 2_28` = **QEMU/Rosetta 模拟 amd64**,是 2h+ 卡死 / `libwriteable-*.rlib: failed to open object file` 报错的根因(不是 nasm、不是 juicebox 网络问题)。
|
|
11
|
+
|
|
12
|
+
**迁移方案(2026-06-03 已实施并合并到 master)**:
|
|
13
|
+
- x86_64 → `ubuntu-latest`(托管原生 amd64,1× 计费)—— 已合并 commit a1840dd,分支实测 7.4min(原 QEMU 2h+ 卡死)
|
|
14
|
+
- aarch64 → `ubuntu-24.04-arm`(托管原生 ARM64,私有仓 2026-01-29 起可用、2 vCPU、占套餐免费分钟非无限免费;cli-docker.yml 已用此 label)—— 已合并,分支实测 6.3min
|
|
15
|
+
- docs.yml(文档部署)→ 也迁到 `ubuntu-latest`(PR #6 / commit 4e522a8),原因同样是 Mac mini 网络反复让 `mike` 推 gh-pages 失败;Python 从 uv 换 actions/setup-python;master 已实测全绿(mike+cloudflare)
|
|
16
|
+
- macOS wheel → **仍保留 Mac mini**(物理需 Apple 硬件 + 托管 macOS 是 10× 倍率 $0.062/min 最贵)。⚠️ 这是发版唯一的自托管单点:Mac mini 排查中反复网络抖动/接不了单,下次发版若它离线 macOS wheel 会卡住整条发布。待定:稳住 Mac mini,或 macOS 也迁 `macos-14` 托管(10×)
|
|
17
|
+
- ⚠️ wheel 流水线只在 tag/release/dispatch 触发,迁移后 master 自身尚未端到端跑过(仅分支 workflow_dispatch 验证过 Linux 两 job),下次正式发版自然验证
|
|
18
|
+
|
|
19
|
+
**硬约束(违反会回归)**:
|
|
20
|
+
1. PyPI 拒收裸 `linux_x86_64` wheel → 迁移后**必须仍在 manylinux 容器内构建**(保留 `--manylinux 2_28`),不能裸 `maturin build`。
|
|
21
|
+
2. boring-sys2 4.15.15 用 bindgen → **需要 libclang**;stock manylinux_2_28 不预装。若用 maturin-action 公开镜像,`before-script-linux` 必须装 `cmake clang clang-libs llvm-devel openssl-devel perl-IPC-Cmd` + `LIBCLANG_PATH=/usr/lib64`。**Linux 不需要 nasm**(仅 Windows)。
|
|
22
|
+
3. 只改 `runs-on`,**绝不改 job 名 / artifact 名**——`github-release`/`pypi-publish` 的 needs 链 + release body 硬编码了 job 名和文件名 `cp38-abi3-manylinux_2_28_{arch}`(由 abi3-py38+容器决定,与 runner 无关,名字不变则链接不失效)。
|
|
23
|
+
|
|
24
|
+
**最小改动做法(Option 0,推荐先做)**:保留现有 `docker run BUILDER_IMAGE ... maturin build` 命令一字不改,只换 host(`--platform` 在原生 host 上变无开销),保留 docker login GHCR(拉私有镜像),删 self-hosted 专属的"清理残留产物"步骤。比改用 maturin-action 风险低(复用已验证镜像,免手维护依赖清单)。
|
|
25
|
+
|
|
26
|
+
成本:open-luban = Org Free = 2000 免费分钟/月,按当前发版频率三件套 ≈100min/月,现金成本 ≈$0。验证用 `test-v*` tag(跳过 CLI 门禁)+ `curl -I` 校验下载链接。
|
|
27
|
+
|
|
28
|
+
相关:[[feedback_must_run_integration_tests]](迁移后需真实跑一轮验证)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 拉黑→解除拉黑 = 强制清除粉丝
|
|
3
|
+
description: block→unblock 组合可强制对方取消关注当前账号;当前 SDK 只暴露原子 block/unblock,组合逻辑在 CLI/示例层完成
|
|
4
|
+
type: project
|
|
5
|
+
originSessionId: 48d12030-f020-438e-b6d4-5a79505022a3
|
|
6
|
+
---
|
|
7
|
+
「强制清除粉丝」语义通过 `user.block(uid)` → `user.unblock(uid)` 组合实现。
|
|
8
|
+
|
|
9
|
+
**Why:** 拉黑会强制对方取消关注当前账号;解除拉黑只解锁双向交互,不会自动恢复关注关系。这是 Twitter 的固有行为,不是 SDK 设计。
|
|
10
|
+
|
|
11
|
+
**How to apply:** SDK 层只提供原子 `block` / `unblock` 方法(`src/x/user/client.rs`)。CLI 没有 `--force-remove-follower` 一键 flag — 用户需自行 `&&` 串联两条命令。Python 示例 `examples/python/user/block_unblock.py` 演示了完整组合逻辑。
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 提交时不要遗漏计划文件
|
|
3
|
+
description: git commit 时必须包含 .claude/plans/ 下的计划文件,不要只提交代码
|
|
4
|
+
type: feedback
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
提交功能代码时,必须同时提交对应的 `.claude/plans/` 计划文件(包括 pending-test/ 中的)。
|
|
8
|
+
|
|
9
|
+
**Why:** 用户发现第一次提交遗漏了计划文件,需要额外补一次提交。计划文件是开发成果的一部分。
|
|
10
|
+
|
|
11
|
+
**How to apply:** 在 `git add` 阶段检查是否有 `.claude/plans/` 下的新增或移动文件需要一并提交。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 文档同步优先级提升
|
|
3
|
+
description: 公共 API 变更必须代码+文档同一 commit;breaking change 有专属检查清单;不许分两次提交
|
|
4
|
+
type: feedback
|
|
5
|
+
originSessionId: 37625ac9-2a59-469c-81ef-5a1b0b82f074
|
|
6
|
+
---
|
|
7
|
+
代码改动必须**同次工作**完成对应文档更新,不能拖到下次。优先级:🔴 bug 修复 > 🟡 新配置项 > 🟢 重构/优化。
|
|
8
|
+
|
|
9
|
+
**Why(2026-05-09):** 修复 rquest H2 重试 bug 后,Rust trait/Python docstring 都改了,但 docs/api/dm.md、CHANGELOG、configuration.md 没有同步,文档漂移。
|
|
10
|
+
|
|
11
|
+
**Why(2026-06-04,加强):** settings 模块 breaking change(删除 20 个方法)完成后,代码先提交、文档后提交,中间存在不一致窗口。用户要求加强约束,增加了两条规则。
|
|
12
|
+
|
|
13
|
+
**How to apply:**
|
|
14
|
+
|
|
15
|
+
**规则 B(门控):** 涉及新增/删除/重命名公共 API 时,代码 commit 和文档 commit 必须是同一个 commit。不允许先提交代码再提交文档,哪怕相差几分钟。提交前口诀:有没有删/加公共 API?→ 有 → docs/api、docs/cli、llms-full.txt、CHANGELOG 都改了吗?→ 没改完 → 不许提交。
|
|
16
|
+
|
|
17
|
+
**规则 C(breaking change 清单):** 删除/重命名已发布公共 API 时,逐项勾选:CHANGELOG Breaking Changes 节、docs/api/<module>.md 完全重写、docs/cli/<module>.md 完全重写、llms-full.txt 段落替换、cli/llms-full.txt 段落替换、版本号 major bump 确认、删除类型已从文档移除。
|
|
18
|
+
|
|
19
|
+
具体映射表和完整清单见 `CLAUDE.md` 的"📚 文档同步原则 / 任务完成门控 / Breaking Change 专属检查清单"章节。
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 必须运行真实集成测试
|
|
3
|
+
description: 开发完成后必须运行真实 API 调用的集成测试,不能只跑本地参数校验
|
|
4
|
+
type: feedback
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
开发完成后必须运行真实调用集成测试(`cargo test <模块> -- --ignored --nocapture`),不能只跑本地验证测试就标记完成。
|
|
8
|
+
|
|
9
|
+
**Why:** 2026-04-07 搜索模块开发中,只运行了 4 个本地参数校验测试就标记完成,用户指出必须运行真实 API 调用测试验证功能可用。
|
|
10
|
+
|
|
11
|
+
**How to apply:** 每次新功能开发的测试阶段,必须在文档更新之前运行 `cargo test <模块> -- --ignored --nocapture` 执行真实集成测试,并报告测试结果。
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: SDK 配置必须暴露给上层
|
|
3
|
+
description: 本项目是 SDK,HTTP/性能/可用性类配置必须通过 ClientConfig 暴露,不能硬编码
|
|
4
|
+
type: feedback
|
|
5
|
+
originSessionId: 37625ac9-2a59-469c-81ef-5a1b0b82f074
|
|
6
|
+
---
|
|
7
|
+
SDK 层只设置"安全默认值",所有可调 HTTP/性能/可用性参数(timeout、retry、proxy、pool、JA3、并发数)必须通过 `ClientConfig` 暴露给上层使用方。
|
|
8
|
+
|
|
9
|
+
**Why:** 用户明确指出本项目是 SDK 不是 end-user app。2026-05-09 修 rquest `http2_max_retry_count` 重复发 DM 的 bug 时,第一反应是直接硬编码 `0`,被用户纠正:应该让外层可配置 + 文档说明,而不是 SDK 写死。SDK 写死意味着每个集成方都得 fork 才能调整,违背 SDK 的可扩展性本质。
|
|
10
|
+
|
|
11
|
+
**How to apply:** 任何在 `src/common/` 或基础设施层添加配置项时,先问"这是 Twitter 协议常量还是 HTTP/性能参数"——前者可硬编码(如 GraphQL queryId、`MAX_MESSAGE_LENGTH`、Bearer Token),后者必须走 `ClientConfig`。设计默认值时遵循"对非幂等操作安全为先"(如 retry 默认 0)。同时在 `docs/api/` 文档中说明每个配置的默认值、风险、何时该改。紧急 hotfix 可以先硬编码止血,但下个 minor 版本必须重构为可配置。
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Rust 字符串长度校验必须用字符数而非字节数
|
|
3
|
+
description: 对 Twitter API 文本字段做长度上限校验时,禁止使用 String::len()(UTF-8 字节数),中文/emoji 会被误判超限
|
|
4
|
+
type: feedback
|
|
5
|
+
originSessionId: d67384aa-3051-4fc6-81a8-c6505550a524
|
|
6
|
+
---
|
|
7
|
+
Rust 中 `String::len()` 和 `&str::len()` 返回 **UTF-8 字节数**,而非字符数。
|
|
8
|
+
对 Twitter API 的文本长度做上限校验时:
|
|
9
|
+
|
|
10
|
+
- **DM 私信(10000 字符限制)**:用 `text.chars().count()`
|
|
11
|
+
- **Posts 发帖(280 限制)**:Twitter 用加权计数(CJK/emoji=2, URL=23, Latin=1),
|
|
12
|
+
使用 `src/x/posts/types.rs::twitter_weighted_length()` 函数
|
|
13
|
+
|
|
14
|
+
**Why**:2026-04-20 在 `posts/client.rs:468` 和 `dm/client.rs` 发现字节数校验
|
|
15
|
+
bug——中文每字符占 3 字节,导致 Posts 93 个中文即被误判超过 280 限制(实际
|
|
16
|
+
Twitter 加权计数仅 186)、DM 约 3333 个中文即触发 10000 字节超限。Python 绑定层
|
|
17
|
+
`src/python/dm/client.rs` 还有 6 处相同 bug 的重复校验代码。
|
|
18
|
+
|
|
19
|
+
已修复版本:release-v1.0.12(commit 2ad5030)。
|
|
20
|
+
|
|
21
|
+
**How to apply**:
|
|
22
|
+
- 任何 `if text.len() > LIMIT` 或 `if text.len() >= LIMIT` 的长度比较都是可疑
|
|
23
|
+
signal,必须复核:上限是字符数还是字节数?
|
|
24
|
+
- Twitter 的文本字段一律是字符/加权单位,不是字节。默认用 `chars().count()` 或
|
|
25
|
+
加权函数
|
|
26
|
+
- 审计新模块时搜索 `\.len\(\) > [A-Z_]+LENGTH` 和 `\.len\(\) > \d+` 两种模式
|
|
27
|
+
- 只有对明确的字节语义限制(如文件大小、HTTP body 字节数、charset 字节约束)
|
|
28
|
+
才允许用 `.len()`
|
|
29
|
+
- Python 绑定层如果重复做长度校验(Rust 业务层已经做了一遍),要么同步修,
|
|
30
|
+
要么考虑删除 Python 层的重复校验让 Rust 兜底
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: feedback-subagent-completion-verify
|
|
3
|
+
description: "子代理自报\"测试/编译通过\"必须用主 session 实证,不能直接采信"
|
|
4
|
+
metadata:
|
|
5
|
+
node_type: memory
|
|
6
|
+
type: feedback
|
|
7
|
+
originSessionId: 9647dc95-2033-4599-9400-4c51ccaa6d23
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
子代理报告任务完成时,必须用主 session 独立跑一遍验证命令并核对输出。
|
|
11
|
+
|
|
12
|
+
**Why:** 2026-05-12 rust-pro 在 x-api-rs 项目报告"receive 测试通过",实际只跑了 receive,send 仍卡在 NotEnrolled 直到主 session 主动跑才暴露。子代理上下文受限,可能漏测、误读输出、或选择性报告。
|
|
13
|
+
|
|
14
|
+
**How to apply:** Agent 工具返回成功后,针对它声称"已验证"的命令至少抽样跑一条,比对实际 stdout 与子代理摘要。差异处优先信 cargo/pytest 输出。
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ondemand.s 混淆变量名会随版本变化
|
|
3
|
+
description: 修复 ClientTransaction "无法提取 KEY_BYTE indices" 错误的诊断思路
|
|
4
|
+
type: feedback
|
|
5
|
+
originSessionId: 6b073450-afb2-41d6-a7f8-64867e736789
|
|
6
|
+
---
|
|
7
|
+
排查 `ClientTransaction` 报 `无法提取 KEY_BYTE indices` 时,先怀疑 X.com 的 `ondemand.s` JS 混淆变量名换了,而非算法变了。
|
|
8
|
+
|
|
9
|
+
**Why:** X.com 不定期重新混淆前端 JS,承载 key byte 索引的临时变量名会变化(已观察到从 `n[..]` 变成 `t[..]`),但语义形态 `(变量[数字],16)` 保持稳定。本项目和上游 iSarabjitDhiman/XClientTransaction 都踩过这个坑——上游已用 `\w` 通配单字母变量名。
|
|
10
|
+
|
|
11
|
+
**How to apply:**
|
|
12
|
+
1. 用 chrome-devtools 抓 `https://abs.twimg.com/responsive-web/client-web/ondemand.s.<hash>.js`
|
|
13
|
+
2. `grep -oE '\(\w\[[0-9]+\], ?16\)' /tmp/<file>` 验证至少 4 个匹配
|
|
14
|
+
3. 如果命中但变量名不是 `n`,只需放宽 `src/common/transaction/client.rs:KEY_BYTE_INDICES_REGEX` 中字母约束
|
|
15
|
+
4. 如果完全没匹配 `(X[N],16)` 形态,才考虑算法变更(参考 `iSarabjitDhiman/XClientTransaction` 仓库的最新代码)
|
|
16
|
+
5. `cargo test --lib test_extract_key_byte_indices_from_js` 单元测试 fixture 已使用带括号格式 `(n[7],16)`,向后兼容
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: x-content-warning-protocol-2026-06-01
|
|
3
|
+
description: "2026-06-01 抓包确认的 Twitter content warning / disclosure 协议:分布在 media/metadata/create.json 与 CreateTweet 两处,且存在两个独立的\"AI\"字段"
|
|
4
|
+
metadata:
|
|
5
|
+
node_type: memory
|
|
6
|
+
type: project
|
|
7
|
+
originSessionId: f332723c-c191-40c8-b2ce-0e9ab6f8fefd
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
抓包时间:2026-06-01(chrome-devtools,UI 流程:上传图片 → Edit media → Content warning 勾选 Nudity + Generated with AI → 返回 → Content disclosure 开启 Made with AI → 发帖)。
|
|
11
|
+
|
|
12
|
+
## 字段分布在两个请求中
|
|
13
|
+
|
|
14
|
+
**Nudity / Violence / Sensitive / 图片级 AI / Block-Grok** → `POST /1.1/media/metadata/create.json`(每个 media_id 一个请求,在 CreateTweet 之前调用,Content-Type: application/json,需要 Bearer + csrf):
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"media_id": "<media_id>",
|
|
19
|
+
"sensitive_media_warning": ["adult_content", "graphic_violence", "other"], // 数组,按需多选
|
|
20
|
+
"allow_download_status": {"allow_download": "true"}, // 字符串 "true"
|
|
21
|
+
"self_reported_ai_generated": {"self_reported_ai_generated": "true"}, // 字符串 "true",对应"Content warning → Generated with AI"
|
|
22
|
+
"grok_actions": {"block_grok_edit": "true"} // 字符串 "true",对应"Block modifications by Grok"
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
字段映射:
|
|
27
|
+
- Nudity → `sensitive_media_warning: "adult_content"`
|
|
28
|
+
- Violence → `sensitive_media_warning: "graphic_violence"`
|
|
29
|
+
- Sensitive → `sensitive_media_warning: "other"`
|
|
30
|
+
- "Generated with AI"(在 Content warning 面板,图片级)→ `self_reported_ai_generated`
|
|
31
|
+
- "Block modifications by Grok"(在 Content warning 面板)→ `grok_actions.block_grok_edit`
|
|
32
|
+
- `allow_download_status`:UI 无独立控件,似乎默认始终带 `"true"`
|
|
33
|
+
|
|
34
|
+
字段值类型全部是**字符串 "true"**(不是 bool),`sensitive_media_warning` 是字符串数组。响应体为空(HTTP 200 + empty body)。
|
|
35
|
+
|
|
36
|
+
**帖子级 "Made with AI"** → `POST /i/api/graphql/CreateTweet` 的 `variables` 新增:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
"content_disclosure": {
|
|
40
|
+
"ai_generated_disclosure": {
|
|
41
|
+
"has_ai_generated_media": true,
|
|
42
|
+
"ai_generated_detection_source": "UserDeclared"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 两个 AI 字段独立
|
|
48
|
+
|
|
49
|
+
- "Content disclosure → Made with AI" 顶层 toggle → CreateTweet 的 `content_disclosure.ai_generated_disclosure`(帖子级声明)
|
|
50
|
+
- "Content warning → Generated with AI" 在媒体编辑器 → media/metadata/create.json 的 `self_reported_ai_generated`(图片级声明)
|
|
51
|
+
|
|
52
|
+
二者不互相联动,用户可以单独开任一边。
|
|
53
|
+
|
|
54
|
+
## 服务端回响(CreateTweet response 中的回显字段)
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
"sensitive_media_warning": {
|
|
58
|
+
"graphic_violence": true, // bool 而非字符串
|
|
59
|
+
"other": true
|
|
60
|
+
}
|
|
61
|
+
"possibly_sensitive_editable": true // tweet 顶层
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
注意:响应里的 `sensitive_media_warning` 是 **object/bool**(`{"graphic_violence": true}`),不是发送时的字符串数组。
|
|
65
|
+
|
|
66
|
+
## 待补抓
|
|
67
|
+
|
|
68
|
+
- "Paid partnership" toggle 对应的 CreateTweet/metadata 字段(本次未开启)
|
|
69
|
+
- 多张图片各自不同 warning 时的请求形态(应该是多次 metadata/create.json 调用)
|
|
70
|
+
|
|
71
|
+
## 抓包样本路径
|
|
72
|
+
|
|
73
|
+
- `.claude/captures/create_tweet_with_warning.network-request` — CreateTweet body
|
|
74
|
+
- `.claude/captures/media_metadata_create.network-request` — media/metadata body
|
|
75
|
+
- 测试 tweet text: "test capture content warning",media_id: 2061431868747309056
|
|
76
|
+
|
|
77
|
+
## SDK 实现建议
|
|
78
|
+
|
|
79
|
+
在 `src/x/posts/` 新增:
|
|
80
|
+
1. `PostsParams` 增加 `ai_generated_disclosure: bool`(帖子级)
|
|
81
|
+
2. 新增 `MediaWarning` 入参(每张图片可独立配置 Nudity/Violence/Sensitive + 图片级 AI),实际调用顺序:upload FINALIZE → media/metadata/create.json(若有 warning)→ CreateTweet
|
|
82
|
+
3. `media/metadata/create.json` 走 HttpClient::post + Bearer + csrf,body 为 JSON
|
|
83
|
+
4. CreateTweet 在 `client.rs:76-115` 构造 variables 时按需注入 `content_disclosure` 字段
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: x-create-tweet-protocol-2026-05-27
|
|
3
|
+
description: 2026-05-27 chrome-devtools 抓包获取的 CreateTweet 最新协议参数与当前代码差异
|
|
4
|
+
metadata:
|
|
5
|
+
node_type: memory
|
|
6
|
+
type: reference
|
|
7
|
+
originSessionId: 8a2ef1de-5940-4767-af0d-533d198c617f
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# CreateTweet 协议快照(2026-05-27)
|
|
11
|
+
|
|
12
|
+
抓包来源:chrome-devtools 实测 hedda44673 账号在 x.com/home 发纯文本帖,reqid=570。
|
|
13
|
+
|
|
14
|
+
## 端点
|
|
15
|
+
|
|
16
|
+
- URL: `https://x.com/i/api/graphql/H-t2v_HvFR07ZBP9aOeKoA/CreateTweet`
|
|
17
|
+
- **queryId 已从 `Ah3G_byjEDs_HSlgU0PyZw` → `H-t2v_HvFR07ZBP9aOeKoA`**
|
|
18
|
+
- Method: POST, Content-Type: application/json
|
|
19
|
+
|
|
20
|
+
## Variables(纯文本帖最小集)
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"tweet_text": "...",
|
|
25
|
+
"media": { "media_entities": [], "possibly_sensitive": false },
|
|
26
|
+
"semantic_annotation_ids": [],
|
|
27
|
+
"disallowed_reply_options": null,
|
|
28
|
+
"semantic_annotation_options": { "source": "UniversalLink" }
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 与 src/x/posts/client.rs 的差异
|
|
33
|
+
|
|
34
|
+
- ➕ **新参数** `semantic_annotation_options: {"source": "UniversalLink"}` — 当前代码缺失
|
|
35
|
+
- ➖ **已移除** `dark_request: false` — 当前代码多余字段,Twitter 已不再要求
|
|
36
|
+
- 🟡 reply / attachment_url 在纯文本帖中不出现(条件字段,需补抓 reply/quote 场景验证)
|
|
37
|
+
|
|
38
|
+
## Features(38 项实测,与当前代码差异)
|
|
39
|
+
|
|
40
|
+
### 新增(代码必须补)
|
|
41
|
+
- `rweb_cashtags_enabled: true`
|
|
42
|
+
- `rweb_cashtags_composer_attachment_enabled: true`
|
|
43
|
+
- `rweb_conversational_replies_downvote_enabled: false`
|
|
44
|
+
- `content_disclosure_indicator_enabled: true` — 内容披露总开关
|
|
45
|
+
- `content_disclosure_ai_generated_indicator_enabled: true` — AI 生成披露开关
|
|
46
|
+
|
|
47
|
+
### 已移除(代码需删)
|
|
48
|
+
- `responsive_web_enhance_cards_enabled`
|
|
49
|
+
- `tweet_awards_web_tipping_enabled`
|
|
50
|
+
|
|
51
|
+
### 值变更
|
|
52
|
+
- `responsive_web_grok_community_note_auto_translation_is_enabled`: false → **true**
|
|
53
|
+
- `longform_notetweets_inline_media_enabled`: true → **false**
|
|
54
|
+
|
|
55
|
+
## Content Warning(待补抓)
|
|
56
|
+
|
|
57
|
+
UI 中"Content warning"对话框包含 Nudity / Violence / Sensitive / Generated with AI / Block modifications by Grok 五项,**字段不在纯文本帖里**。
|
|
58
|
+
|
|
59
|
+
- features 里 `content_disclosure_*_enabled` 已开启,说明协议支持
|
|
60
|
+
- 真实字段路径与值需在**带图发布 + 勾选 Nudity + 勾选 Generated with AI** 的场景下抓包确认
|
|
61
|
+
- 推测挂载位置:`media.media_entities[i]` 内,或顶层新增 `content_warning` / `disclosure` 字段
|
|
62
|
+
|
|
63
|
+
## Headers(已被项目 build_twitter_headers 覆盖,无需改动)
|
|
64
|
+
|
|
65
|
+
`authorization`(Bearer)、`x-csrf-token`、`x-twitter-auth-type: OAuth2Session`、`x-twitter-active-user: yes`、`x-twitter-client-language`、`x-client-transaction-id`、`referer: https://x.com/home`、`origin: https://x.com`
|
|
66
|
+
|
|
67
|
+
## 测试痕迹
|
|
68
|
+
|
|
69
|
+
- 测试账号: hedda44673(u=2039411983011790848)
|
|
70
|
+
- 已发布 tweet_id: `2059542161897763324`
|
|
71
|
+
- 链接: https://x.com/hedda44673/status/2059542161897763324
|
|
72
|
+
|
|
73
|
+
## 相关
|
|
74
|
+
|
|
75
|
+
- [[feedback_must_run_integration_tests]] — 修改 queryId/features 后必须跑真实集成测试验证
|
|
76
|
+
- [[feedback_docs_sync_priority]] — 同步更新 docs/api/twitter-api.md 端点表
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: REST 端点必须走 HttpClient::post trait
|
|
3
|
+
description: 直接调用 .client().post() 会绕过 auth/csrf 头注入导致 "Bad Authentication data"
|
|
4
|
+
type: feedback
|
|
5
|
+
originSessionId: 48d12030-f020-438e-b6d4-5a79505022a3
|
|
6
|
+
---
|
|
7
|
+
新增 REST 端点(如 `blocks/create.json`、`account/remove_profile_image.json`)时,必须走 `HttpClient::post(...)` trait 方法,而非 `.as_any().downcast::<RquestClient>().client().post(...)` 直链。
|
|
8
|
+
|
|
9
|
+
**Why:** trait `post` 会自动用 `build_twitter_headers()` 注入 Authorization / x-csrf-token / x-twitter-active-user 等 Twitter API 必需头。直接调用 rquest builder 只发 cookies,导致 `api.x.com/1.1/blocks/create.json` 返回 400 "Bad Authentication data"(即使 ct0 cookie 在域内也不行 — Twitter 严格校验 x-csrf-token 头)。
|
|
10
|
+
|
|
11
|
+
**How to apply:** 用 `client.post(url, &[], None, RequestBody::Form(...) | RequestBody::Empty, None).await?`,第三参数 `None` 触发自动头生成。`UserClient::post_form_action` / `post_empty_action` 已封装好这两种情况。已废弃的反例:`src/x/user/client.rs::follow/unfollow` 用了 downcast 直链(仅因 friendships/create.json 域为 x.com 走 cookie 同源认证侥幸可用)— 待后续迁回 trait。
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# XChat v3 总览与采访结论
|
|
2
|
+
|
|
3
|
+
> **目标**:在 `src/x/xchat/` 新增模块,实现 X 官方新版 XChat 端到端加密私信完整链路(与 web 客户端 wire 兼容),SDK 发版号跳跃至 **v2.0.0**。
|
|
4
|
+
> **范围**:完整 E2E(含 AES-GCM 加密 + Juicebox PIN 备份) + 1v1 + 群组 + 文本/图片/视频/附件 + 发送 + 接收解密。
|
|
5
|
+
> **预计工时**:14-21 工作日,拆 4 phase 递交。
|
|
6
|
+
> **状态**:📋 规划完成,等待用户「开始执行」指令。
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 总待办(4 个 phase)
|
|
11
|
+
|
|
12
|
+
- [ ] **Phase 1 — 基础设施**([计划](./20260511-160001-XChat-v3-Phase1-基础设施.md),预计 3-4 天)
|
|
13
|
+
- [ ] **Phase 2 — Enrollment**([计划](./20260511-160002-XChat-v3-Phase2-Enrollment.md),预计 4-5 天)
|
|
14
|
+
- [ ] **Phase 3 — 1v1 加密发收**([计划](./20260511-160003-XChat-v3-Phase3-1v1发收.md),预计 4-5 天)
|
|
15
|
+
- [ ] **Phase 4 — 群组与媒体**([计划](./20260511-160004-XChat-v3-Phase4-群组媒体.md),预计 5-7 天)
|
|
16
|
+
|
|
17
|
+
每个 phase 完成后:
|
|
18
|
+
1. 调 `code-reviewer` agent 审查该 phase 变更(**必办事件**)
|
|
19
|
+
2. 跑该 phase 集成测试(用 `tests/fixtures/xchat_e2e_evidence/cookies_20260511.json` + PIN)
|
|
20
|
+
3. 更新本 phase 计划文件顶部 TODO 为已完成
|
|
21
|
+
4. 移动到 `.claude/plans/pending-test/`
|
|
22
|
+
5. 等待用户审批
|
|
23
|
+
6. 用户审批后移到 `.claude/plans/completed/`,方可启动下一 phase
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 关键决策汇总(来自采访)
|
|
28
|
+
|
|
29
|
+
| 决策点 | 选择 | 理由 |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| 核心目标 | **完整 E2E**(加密+签名+备份+收发) | 与官方 web 客户端完全兼容 |
|
|
32
|
+
| 模块归属 | **新建 `src/x/xchat/`** | 与 dm/v1/v2 独立,不破坏现有 |
|
|
33
|
+
| 发版号 | **v2.0.0**(主版本跳跃) | 新增大量依赖 + 新模块面积 |
|
|
34
|
+
| Enrollment 模式 | **仅 CustomPin** | 与官方 web 一致,依赖 Juicebox |
|
|
35
|
+
| 加密策略 | **双方均 enrolled 时自动加密**,否则明文签名 | 与官方一致 |
|
|
36
|
+
| 收件人未 enroll | 返回 `DMResult { warning: 'recipient_not_enrolled' }` 仍发送 | 与官方一致 |
|
|
37
|
+
| Conversation key | **SDK 内部自动管理** | 用户无感知 |
|
|
38
|
+
| 接收 | **实现完整发+收** | E2E 闭环 |
|
|
39
|
+
| 群组 | **1v1 + 创建群 + 群内发消息** | 含 ratchet tree |
|
|
40
|
+
| 媒体 | **文本 + 图片 + 视频 + 其他附件** | 含 InitializeXChatMediaUpload 链路 |
|
|
41
|
+
| Franking | **不实现** | 服务端不强制;放弃举报能力 |
|
|
42
|
+
| 密钥存储 | **JSON 文件 + 用户传入路径** | SDK 提供工具方法首次生成 |
|
|
43
|
+
| PIN 输入 | **API 参数明文传入** | `client.xchat.enroll(pin="8527")` |
|
|
44
|
+
| 错误模型 | **新增 `XChatError`**,与 `TwitterError` 透传 | 不污染现有错误枚举 |
|
|
45
|
+
| 重试 | **不重试** | 与 v1.0.15 修复一致(非幂等保护) |
|
|
46
|
+
| 批量 | **send_batch + send_batch_with_custom_texts** | 与 dm v1/v2 一致 |
|
|
47
|
+
| Python API | **`client.xchat.send_message(user_id, text)`** | 与现有 client.dm/posts/user 一致 |
|
|
48
|
+
| 状态查询 | **`is_enrolled()` / `xchat_status()`** | 让上层判断 |
|
|
49
|
+
| Juicebox 实现 | **依赖 `juicebox-sdk` Rust crate**,必要时 fork | 节省 5 天 |
|
|
50
|
+
| 密码学栈 | **RustCrypto 生态**(p256, aes-gcm, sha2, hmac, hkdf, x509-cert) | 纯 Rust,maturin 友好 |
|
|
51
|
+
| 集成测试 | **用 `@mamadoufri23588` 真实账号** | 已 enrolled,PIN=8527 |
|
|
52
|
+
| 测试消息清理 | **不删**,留作证据 | 与 CLAUDE.md 一致 |
|
|
53
|
+
| 文档 | **`docs/api/xchat.md` + `examples/python/xchat/` + mkdocs nav + `llms-full.txt`** | 全套 |
|
|
54
|
+
| CLAUDE.md | 加 XChat 模块专章 | 让未来 AI agent 同步 |
|
|
55
|
+
| 阶段交接 | **每 phase 都 code-reviewer + 集成测试 + 用户审批** | 安全优先 |
|
|
56
|
+
| 验证复用 | **`validate_message` 抽到 `src/common/text_validation.rs`** | 跨模块共享 |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 不在 v3 范围内(明确排除)
|
|
61
|
+
|
|
62
|
+
- ❌ ManagedPin / SelfCustody enrollment(仅 CustomPin)
|
|
63
|
+
- ❌ Franking HMAC 生成
|
|
64
|
+
- ❌ ReportFrankedMessageMutation
|
|
65
|
+
- ❌ XChatGrokSearchMutation
|
|
66
|
+
- ❌ DmAvPermissions / Voice / Video call E2EE(AvCallE2eePipelines)
|
|
67
|
+
- ❌ Screen capture blocking
|
|
68
|
+
- ❌ Mute / Disable / TTL / Disappearing messages
|
|
69
|
+
- ❌ Welcome message
|
|
70
|
+
- ❌ Group invite links
|
|
71
|
+
- ❌ 自动重试(用户显式选择不要)
|
|
72
|
+
|
|
73
|
+
如需扩展,放 v3.x minor 版本迭代。
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 依赖增量预估(Cargo.toml)
|
|
78
|
+
|
|
79
|
+
```toml
|
|
80
|
+
# 新增
|
|
81
|
+
p256 = { version = "0.13", features = ["ecdh", "ecdsa", "pkcs8"] }
|
|
82
|
+
aes-gcm = "0.10"
|
|
83
|
+
sha2 = "0.10"
|
|
84
|
+
hmac = "0.12"
|
|
85
|
+
hkdf = "0.12"
|
|
86
|
+
x509-cert = "0.2" # for SPKI encoding
|
|
87
|
+
spki = "0.7"
|
|
88
|
+
pkcs8 = "0.10"
|
|
89
|
+
zeroize = "1.7" # 安全擦除密钥
|
|
90
|
+
juicebox-sdk = "0.3" # 待评估,必要时 fork
|
|
91
|
+
rand_core = "0.6"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 风险与缓解
|
|
97
|
+
|
|
98
|
+
| 风险 | 概率 | 缓解 |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| `juicebox-sdk` crate 与 X 的 realm 不兼容 | 中 | Phase 2 开始时先做 1 天 spike,必要时 fork |
|
|
101
|
+
| 测试账号被 X 检测为异常并冻结 | 低 | 使用真实 cookies + 不批量调用敏感接口 |
|
|
102
|
+
| Thrift Binary 还有隐藏字段差异 | 中 | Phase 1 用抓包做字节级 diff 验证 |
|
|
103
|
+
| `ratchet_tree_change` 算法逆向不完整 | 高 | Phase 4 可降级为「仅文本群发」如果群密钥逆向卡壳 |
|
|
104
|
+
| 媒体上传加密细节缺失(需要 Phase 4 抓包补充) | 高 | Phase 4 第一步重新抓包补全 |
|
|
105
|
+
| RustCrypto 与官方 web 实现微小不一致(如签名编码差异) | 低 | Phase 1 用 capture 做 byte-for-byte 验证 |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 整体里程碑
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
Phase 1 ────► 基础设施(无 Twitter 调用) ────► code-review ────► pending-test ────► 用户审批
|
|
113
|
+
│
|
|
114
|
+
Phase 2 ◄──── 真实 enroll + Juicebox 联调 ◄──── 真实 GetPublicKeys ◄──── 用户审批 ◄──┘
|
|
115
|
+
│
|
|
116
|
+
└─► code-review ─► pending-test ─► 用户审批 ─► Phase 3
|
|
117
|
+
|
|
118
|
+
Phase 3 ────► 真实 1v1 加密发收 ────► code-review ────► pending-test ────► 用户审批
|
|
119
|
+
│
|
|
120
|
+
Phase 4 ◄──── 群+媒体(依赖前 3)◄──── 用户审批 ◄────────────────────────────┘
|
|
121
|
+
│
|
|
122
|
+
└─► code-review ─► pending-test ─► 用户审批 ─► v2.0.0 发版
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 参考资料
|
|
128
|
+
|
|
129
|
+
- 逆向文档:[`docs/architecture/xchat-e2e-reverse-engineering.md`](../../docs/architecture/xchat-e2e-reverse-engineering.md)
|
|
130
|
+
- 抓包证据:[`tests/fixtures/xchat_e2e_evidence/`](../../tests/fixtures/xchat_e2e_evidence/)(gitignored)
|
|
131
|
+
- 复盘报告:`tests/fixtures/xchat_e2e_evidence/findings_20260511.md`
|
|
132
|
+
- RFC 9420 (MLS):https://www.rfc-editor.org/rfc/rfc9420.html
|
|
133
|
+
- Juicebox SDK:https://github.com/juicebox-systems/juicebox-sdk
|