@volter/twin-xidentity 0.1.10 → 0.1.12
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 +42 -14
- package/dist/src/generated/surface.gen.json +1 -0
- package/dist/src/generated/ui.gen.json +1 -0
- package/dist/src/index.d.ts +4 -4
- package/dist/src/index.js +40 -25
- package/dist/src/manifest.d.ts +2 -0
- package/dist/src/manifest.js +179 -0
- package/dist/src/screens/authorize.d.ts +40 -0
- package/dist/src/screens/authorize.js +184 -0
- package/dist/src/screens/oauth1.d.ts +12 -0
- package/dist/src/screens/oauth1.js +123 -0
- package/dist/src/semantics/index.d.ts +5 -0
- package/dist/src/semantics/index.js +15 -0
- package/dist/src/semantics/oauth1.d.ts +8 -0
- package/dist/src/semantics/oauth1.js +142 -0
- package/dist/src/semantics/shared.d.ts +37 -0
- package/dist/src/semantics/shared.js +55 -0
- package/dist/src/semantics/tokens.d.ts +37 -0
- package/dist/src/semantics/tokens.js +271 -0
- package/dist/src/semantics/users.d.ts +22 -0
- package/dist/src/semantics/users.js +207 -0
- package/dist/src/xidentity-capabilities.js +87 -16
- package/dist/src/xidentity-conformance.js +4 -4
- package/dist/src/xidentity-connector.js +3 -0
- package/dist/src/xidentity-consent-ui.js +2 -2
- package/dist/src/xidentity-doors.d.ts +4 -0
- package/dist/src/xidentity-doors.js +103 -0
- package/dist/src/xidentity-oauth1.d.ts +27 -11
- package/dist/src/xidentity-oauth1.js +18 -309
- package/dist/src/xidentity-scopes.d.ts +1 -1
- package/dist/src/xidentity-scopes.js +9 -5
- package/dist/src/xidentity-server.d.ts +23 -17
- package/dist/src/xidentity-server.js +132 -72
- package/dist/src/xidentity-store.d.ts +85 -45
- package/dist/src/xidentity-store.js +160 -159
- package/dist/src/xidentity-twin.d.ts +38 -45
- package/dist/src/xidentity-twin.js +81 -863
- package/package.json +3 -3
- package/src/generated/surface.gen.json +1 -0
- package/src/generated/ui.gen.json +1 -0
- package/src/index.ts +44 -27
- package/src/manifest.ts +220 -0
- package/src/screens/authorize.ts +212 -0
- package/src/screens/oauth1.ts +131 -0
- package/src/semantics/index.ts +23 -0
- package/src/semantics/oauth1.ts +156 -0
- package/src/semantics/shared.ts +79 -0
- package/src/semantics/tokens.ts +278 -0
- package/src/semantics/users.ts +221 -0
- package/src/xidentity-capabilities.ts +89 -15
- package/src/xidentity-conformance.ts +4 -4
- package/src/xidentity-connector.ts +2 -0
- package/src/xidentity-consent-ui.ts +2 -2
- package/src/xidentity-doors.ts +131 -0
- package/src/xidentity-oauth1.ts +23 -294
- package/src/xidentity-scopes.ts +9 -5
- package/src/xidentity-server.ts +135 -76
- package/src/xidentity-store.ts +180 -196
- package/src/xidentity-twin.ts +100 -949
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ X's OAuth 2.0 issues **opaque bearer tokens**: no `id_token`, no JWKS, no discov
|
|
|
17
17
|
Identity is fetched from `GET /2/users/me` with the access token. That non-OIDC shape is the whole
|
|
18
18
|
reason this vendor needs its own pack next to `googleoauth` — an integration built against an OIDC
|
|
19
19
|
provider (id_token claims, `openid email profile` scopes) breaks against X in exactly the ways this
|
|
20
|
-
twin reproduces: the scope model is X's own catalog (the OpenAPI's
|
|
20
|
+
twin reproduces: the scope model is X's own catalog (the OpenAPI's 26 scopes plus the announcement-added
|
|
21
21
|
`users.email`, which gates `confirmed_email` — a recorded intra-vendor discrepancy), the refresh
|
|
22
22
|
token only arrives with `offline.access`, PKCE is **required**, and the only identity read is the
|
|
23
23
|
API call.
|
|
@@ -31,18 +31,45 @@ bundle and stylesheet the twin serves are **committed text** (`src/xidentity-con
|
|
|
31
31
|
written from `client/` by `bun scripts/consent-clients.ts` and drift-gated by
|
|
32
32
|
`scripts/consent-clients.test.ts`): the serve path reads constants and never runs a bundler.
|
|
33
33
|
|
|
34
|
+
## A derived pack (Protocol 3)
|
|
35
|
+
|
|
36
|
+
The pack is derived ([architecture](../../../docs/contributing/architecture.md#protocol-3-the-derived-pack)) from
|
|
37
|
+
X's own OpenAPI document, X API v2 version 2.168 (`spec/openapi.json.gz`, the same bytes the `x` pack vendors;
|
|
38
|
+
provenance in `spec/SOURCE.md`), corrected by `spec/patches.json`: the `x` pack's corrections to the wire's names
|
|
39
|
+
(`tweet.fields`, `pinned_tweet_id`, `most_recent_tweet_id`), and X's OAuth endpoints the document does not list,
|
|
40
|
+
patched in from docs.x.com's Authorization Code Flow page and OAuth API reference. `bun scripts/derive-pack.ts
|
|
41
|
+
xidentity` writes the wire (`src/generated/`). `GET /2/users/me`, `POST /2/oauth2/token`, `POST /2/oauth2/revoke`,
|
|
42
|
+
`POST /oauth/request_token`, `POST /oauth/access_token` and `POST /1.1/oauth/invalidate_token` (and its `.json`
|
|
43
|
+
form) are semantics handlers (`src/semantics/`); every other operation of the document is the gap, X's 404
|
|
44
|
+
problem — in a World the `x` pack claims those paths on `api.x.com` and `api.twitter.com`. The authorize pages are
|
|
45
|
+
screens (`src/screens/`), and the World's doors are `src/xidentity-doors.ts`. `src/manifest.ts` declares the
|
|
46
|
+
state machines the handlers and screens ask on every move (a screen's settling, a code's redemption, a refresh
|
|
47
|
+
token's rotation and revocation, an access token's revocation, an OAuth 1.0a request token's life, an OAuth 1.0a
|
|
48
|
+
access token's invalidation).
|
|
49
|
+
|
|
50
|
+
**A credential is bookkeeping, kept by its SHA-256** — an authorization code, an access token, a refresh token, an
|
|
51
|
+
OAuth 1.0a request token and an OAuth 2.0 App's client secret live under `_` types, never as a subject id or a field
|
|
52
|
+
of an entry that could be deployed or read in a changeset. A World that ran the protocol 1 pack keeps its
|
|
53
|
+
credentials under the types they were written as; they still resolve, and the first move on one writes it as
|
|
54
|
+
bookkeeping. Two rows keep a secret by contract: the OAuth 1.0a App (`oauth1_app`) and access token
|
|
55
|
+
(`oauth1_token`), which the `x` pack reads by the token itself through the kernel's owner read
|
|
56
|
+
(`xidentity-oauth1.ts` states the row shapes); moving them is that contract's change, on both packs at once.
|
|
57
|
+
|
|
58
|
+
Not done by the Protocol 3 procedure yet: the customer life, the vendor's published examples and the report
|
|
59
|
+
(`journeys/`); the capability manifest stays the pack's T0.
|
|
60
|
+
|
|
34
61
|
## Coverage
|
|
35
62
|
|
|
36
63
|
Partial and honest. The manifest (`src/xidentity-capabilities.ts`) is the **enumerated identity
|
|
37
64
|
service-area** denominator, not a claim to enumerate the whole X vendor surface. It is authored
|
|
38
|
-
top-down from X's own artefacts (
|
|
39
|
-
v2 OpenAPI document** (2.167) for `/2/users/me`, the Problem error family and the
|
|
40
|
-
with X's consent descriptions; the **docs.x.com OAuth 2.0 guides** for the authorize/token/refresh/
|
|
65
|
+
top-down from X's own artefacts (first fetched 2026-08-21): the **X API
|
|
66
|
+
v2 OpenAPI document** (2.167 then; 2.168 vendored now) for `/2/users/me`, the Problem error family and the scope
|
|
67
|
+
catalog with X's consent descriptions; the **docs.x.com OAuth 2.0 guides** for the authorize/token/refresh/
|
|
41
68
|
revoke requests; the **docs.x.com rate-limit pages** for the `x-rate-limit-*` headers and the
|
|
42
69
|
75/15-minute per-user figure; and the **official SDK sources** (`@xdevplatform/xdk`,
|
|
43
70
|
`twitter-api-typescript-sdk`) for the token/revoke response shapes the docs never show as JSON.
|
|
44
|
-
It currently reads **
|
|
45
|
-
denominator). The `todo`s are real X identity
|
|
71
|
+
It currently reads **103 done / 162 covered** (59 `todo`, and the login leg is not an API surface: it is the seeded
|
|
72
|
+
session, so it is not in that denominator). The `todo`s are real X identity
|
|
46
73
|
surface this twin does not model — most notably the **v1.1 app-only bearer flow**, OAuth 1.0a's
|
|
47
74
|
timestamp window and nonce replay, the unmodelled `user.fields` (entities, withheld, subscription, the
|
|
48
75
|
relational fields), expansion hydration — plus a family of **wire-pinning todos**: behaviours the
|
|
@@ -66,7 +93,8 @@ code TTL). Each such `done` names its evidence boundary in the manifest and its
|
|
|
66
93
|
- **Vendor-shaped opaque credentials** — the twin's codes/tokens are base64url blobs whose decoded
|
|
67
94
|
structure (`<opaque>:<unix-ms>:1:1:ac|at|rt:1`) matches what the docs' own examples decode to.
|
|
68
95
|
- **The identity read** — `GET /2/users/me` with the OpenAPI's scope demands (`tweet.read` +
|
|
69
|
-
`users.read`), the
|
|
96
|
+
`users.read`), the spec's `user.fields`, `expansions` and `tweet.fields` / `post.fields` enums with the wire's
|
|
97
|
+
invalid-parameter envelope (a query parameter the operation does not take is refused the same way), the
|
|
70
98
|
documented `x-rate-limit-*` headers, 75/15min per-user accounting, and the documented
|
|
71
99
|
429 + legacy code 88 refusal. `user.fields=profile_image_url` is the seeded photo, or X's default
|
|
72
100
|
avatar URL (`abs.twimg.com/…/default_profile_normal.png`) for a persona seeded without one — the
|
|
@@ -77,7 +105,7 @@ code TTL). Each such `done` names its evidence boundary in the manifest and its
|
|
|
77
105
|
(`xidentity-sdk.integration.test.ts`); the OAuth legs its hardcoded hosts cannot re-aim are
|
|
78
106
|
proven over real transport in the docs' own curl shapes.
|
|
79
107
|
|
|
80
|
-
### OAuth 1.0a (`src/xidentity-oauth1.ts`)
|
|
108
|
+
### OAuth 1.0a (`src/semantics/oauth1.ts`, `src/screens/oauth1.ts`, `src/xidentity-oauth1.ts`)
|
|
81
109
|
|
|
82
110
|
The three-legged flow as docs.x.com's API reference and "Obtaining access tokens using 3-legged
|
|
83
111
|
OAuth flow" state it, which is what Postiz (`gitroomhq/postiz-app`) connects an X account with
|
|
@@ -112,9 +140,8 @@ World's, an app signs with its host's), request-token expiry, the login step `fo
|
|
|
112
140
|
|
|
113
141
|
The twin **authenticates nobody**: no password, no 2FA, no risk engine. The
|
|
114
142
|
x.com "signed in" session is a seeded persona row — `POST /_twin/session` switches it, which is the
|
|
115
|
-
honest local equivalent of "the browser is already signed in". This is
|
|
116
|
-
|
|
117
|
-
service-areas to add within this same pack; they are not a reason to create a second X vendor pack.
|
|
143
|
+
honest local equivalent of "the browser is already signed in". This is X's **identity** surface; posts,
|
|
144
|
+
timelines and media are the `x` pack's, which shares X's hosts with this one by path.
|
|
118
145
|
|
|
119
146
|
### Twin-only scaffolding (not vendor surface, not counted)
|
|
120
147
|
|
|
@@ -125,7 +152,7 @@ internal endpoint; the OAuth 1.0a screen's posts to `POST oauth/authorize`, abov
|
|
|
125
152
|
permission), `POST /_twin/clients`, `POST /_twin/accounts`, `POST /_twin/session`,
|
|
126
153
|
`POST /_twin/rate_limit` (arm a deterministic 429), and the `/_twin/assets/*` page assets. This
|
|
127
154
|
list is the audit trail the conformance census deliberately excludes — keep it in lockstep with
|
|
128
|
-
|
|
155
|
+
the doors in `xidentity-doors.ts`.
|
|
129
156
|
|
|
130
157
|
## The three operations
|
|
131
158
|
|
|
@@ -134,10 +161,11 @@ list is the audit trail the conformance census deliberately excludes — keep it
|
|
|
134
161
|
`liveXIdentityExecute(accessToken)`, the ONE place a real X request may be issued, guarded by the
|
|
135
162
|
fail-closed rate budget (`xidentity-budget.ts`: X's own 75/15min scheme, live-fetched
|
|
136
163
|
2026-08-21). The client registry and the grant's scope set are **not observable** (no API reads
|
|
137
|
-
X Apps; X has no token introspection) — reasoned gaps, not fakes.
|
|
164
|
+
X Apps; X has no token introspection) — reasoned gaps, not fakes. The same read is the protocol 2
|
|
165
|
+
refresh adapter, `syncXIdentityFromRemote`, over the kernel's executor.
|
|
138
166
|
- **write** — the default: local consent flows mint local credentials, no real calls.
|
|
139
167
|
- **push** — structurally impossible (X exposes no write API for this surface) and reported as
|
|
140
|
-
such, never faked
|
|
168
|
+
such, never faked: `performXIdentityAction` answers every entry `performed: false`.
|
|
141
169
|
|
|
142
170
|
## Serving
|
|
143
171
|
|