@volter/twin-x 0.1.0 → 0.1.1
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/README.md +22 -8
- package/dist/client/x-mirror.bundle.js +90 -90
- package/dist/src/index.js +4 -2
- package/dist/src/x-capabilities.js +168 -1
- package/dist/src/x-oauth1.d.ts +24 -0
- package/dist/src/x-oauth1.js +145 -0
- package/dist/src/x-problems.d.ts +7 -0
- package/dist/src/x-problems.js +18 -0
- package/dist/src/x-server.js +51 -13
- package/dist/src/x-twin.d.ts +4 -0
- package/dist/src/x-twin.js +58 -18
- package/package.json +3 -3
- package/src/index.ts +4 -2
- package/src/x-capabilities.ts +175 -1
- package/src/x-oauth1.ts +138 -0
- package/src/x-problems.ts +19 -0
- package/src/x-server.ts +43 -8
- package/src/x-twin.ts +57 -18
package/README.md
CHANGED
|
@@ -29,14 +29,14 @@ bun packages/twin/x/src/cli.ts serve --root /tmp/world
|
|
|
29
29
|
| `GET /2/users/:id/timelines/reverse_chronological` | The home timeline — the account plus the accounts it follows; refused for anyone else's id. |
|
|
30
30
|
| `GET /2/users/:id` · `GET /2/users/by/username/:username` | User lookup (handles are case-insensitive). An unknown user is X's partial-error 200 with a `resource_type: "user"` row, never a fabricated account. `GET /2/users/me` is `xidentity`'s and is not claimed here. |
|
|
31
31
|
| `GET /2/tweets/search/recent` | Recent search over the local corpus: keywords, quoted phrases and `from:`. Grammar the twin does not model (`OR`, negation, grouping, other operators) is **refused**, never silently ignored. |
|
|
32
|
-
| projection | `tweet.fields`, `user.fields`, `media.fields` and `expansions` (`attachments.media_keys` included) + the `includes` sidecar. The default is X's three fields (`id`, `text`, `edit_history_tweet_ids`) and nothing else — a documented field the twin holds no state for is refused by name rather than quietly omitted. |
|
|
32
|
+
| projection | `tweet.fields`, `user.fields`, `media.fields` and `expansions` (`attachments.media_keys` included) + the `includes` sidecar. The default is X's three fields (`id`, `text`, `edit_history_tweet_ids`) and nothing else — a documented field the twin holds no state for is refused by name rather than quietly omitted. `user.fields=profile_image_url` is the photo seeded for the account, or X's default avatar URL for one without (the twin serves the URL, not the picture). |
|
|
33
33
|
| paging + windows | `pagination_token` / `meta.next_token`, `max_results` (5..100 on the timelines, 10..100 on search), and `since_id` / `until_id` / `start_time` / `end_time` with X's own id-beats-time precedence. |
|
|
34
|
-
| auth | The bearer `xidentity`'s OAuth flow mints
|
|
34
|
+
| auth | The bearer `xidentity`'s OAuth 2.0 flow mints and its scope set, or an **OAuth 1.0a User Context** signature (HMAC-SHA1) over an access token `xidentity`'s three legs issued — a Read-only App's token reads and gets X's `oauth1-permissions` 403 on a write; X's `about:blank` 401 / `Forbidden` 403 problems. |
|
|
35
35
|
| errors | `resource-not-found`, `invalid-request`, the 429 + legacy code 88 pair, `405` under `--read-only`. |
|
|
36
36
|
| connector | Pull **both** timelines — mentions and the account's own posts — following `next_token` to the end of each; **push** a pending post/quote/reply/delete to the real vendor, confirmed under the id X minted. A post with media is **performed** by uploading each file to X first (an image in one request; a video chunked, then polled on STATUS until processed) and posting with the media ids X minted. |
|
|
37
|
-
| `/_twin/*` | Twin-only control plane: seed an account (its profile — `description`, `location`, `url`, `protected`, `verified` — and its long-post entitlement), a bearer, an inbound mention, a follow edge, or an armed rate refusal. |
|
|
37
|
+
| `/_twin/*` | Twin-only control plane: seed an account (its profile — `description`, `location`, `url`, `profile_image_url`, `protected`, `verified` — and its long-post entitlement), a bearer, an inbound mention, a follow edge, or an armed rate refusal. |
|
|
38
38
|
|
|
39
|
-
`src/x-capabilities.ts` is the denominator: **
|
|
39
|
+
`src/x-capabilities.ts` is the denominator: **125 capabilities, 83 done**. What is
|
|
40
40
|
not modelled is enumerated there as a todo — polls, hide-reply, `entities`/`public_metrics`,
|
|
41
41
|
the `user.fields` with no state behind them, full-archive search and the query grammar, likes/reposts/bookmarks, stream rules, the
|
|
42
42
|
filtered and sampled **streaming** connections, GIFs, alt text, a video's real poster frame and X's transcoded
|
|
@@ -72,10 +72,24 @@ on those exact fields to decide what it writes (`conversation_id`, `in_reply_to_
|
|
|
72
72
|
|
|
73
73
|
## Relationship to `@volter/twin-xidentity`
|
|
74
74
|
|
|
75
|
-
`xidentity` owns **X's OAuth
|
|
76
|
-
round trip,
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
`xidentity` owns **X's OAuth** — the OAuth 2.0 authorize screen and authorization-code + PKCE
|
|
76
|
+
round trip, the OAuth 1.0a three legs (`oauth/request_token`, the `oauth/authorize` /
|
|
77
|
+
`oauth/authenticate` screen, `oauth/access_token`) and `GET /2/users/me`. This pack owns the
|
|
78
|
+
**posting surface** and consumes the credentials those flows mint. It never models OAuth:
|
|
79
|
+
duplicating it here would be two accounts of one vendor's auth.
|
|
80
|
+
|
|
81
|
+
**One credential store, read across the seam.** X has one store of OAuth 1.0a access tokens, and
|
|
82
|
+
it is `xidentity`'s. An access token a person approved there must also sign a post here, so
|
|
83
|
+
`src/x-oauth1.ts` reads `xidentity`'s `oauth1_token` and `oauth1_app` rows through the kernel
|
|
84
|
+
projection (read-only; the row shapes are the contract `xidentity-oauth1.ts` states) and verifies
|
|
85
|
+
the signature with a transcription of its RFC 5849 verifier. The token acts for its `user_id`,
|
|
86
|
+
which is the X account in this pack's state: a World that posts as a person seeds that account
|
|
87
|
+
(id and handle) here, as it does for a `/_twin/tokens` bearer. The World's own App — the
|
|
88
|
+
`X_API_KEY` / `X_API_SECRET` the World sets (Postiz's names; `TWITTER_API_KEY` /
|
|
89
|
+
`TWITTER_API_SECRET` also) — is read with `worldEnvValue` on both sides.
|
|
90
|
+
`src/x-oauth1.integration.test.ts` runs both packs on one root (xidentity from its own bin) and
|
|
91
|
+
drives Postiz's path with `twitter-api-v2`: the three legs, `v2.me()`, `v2.uploadMedia`, a post, and
|
|
92
|
+
Postiz's own `signOAuth1`.
|
|
79
93
|
|
|
80
94
|
The two agree about X rather than sharing code: `scripts/architecture.test.ts` (A3) forbids a
|
|
81
95
|
cross-vendor pack import, so `src/x-problems.ts` and `src/x-scopes.ts` **transcribe** xidentity's
|