@viceme-ai/sdk 0.7.0 → 0.8.0

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 CHANGED
@@ -86,7 +86,7 @@ is `wrk_live_...`. Other Work key shapes are rejected locally.
86
86
 
87
87
  Access operations establish a short-lived, memory-only Work session on first
88
88
  use. They expose `client.auth`, `client.access`, and `client.checkout`; login,
89
- explicit follow, and hosted checkout remain ViceMe-owned UI. The host never
89
+ buyer recovery, and hosted checkout remain ViceMe-owned UI. The host never
90
90
  receives a general ViceMe session or payment credential. Tests can inject a
91
91
  deterministic transport and presenter through `@viceme-ai/sdk/testing`.
92
92
  Calling `client.destroy()` cancels in-flight access requests, closes the active
@@ -94,24 +94,60 @@ SDK-owned sign-in or checkout layer, and rejects the interrupted call with
94
94
  `CLIENT_DESTROYED`; late responses cannot restore the in-memory Work token.
95
95
  Request cancellation and timeouts remain effective until the parsed response is
96
96
  delivered. Cancelling the client's optional `signal` preserves the caller's
97
- `Error` reason; a request timeout rejects with retryable `NETWORK_TIMEOUT`.
97
+ `Error` reason for requests and interactive presentations; a request timeout
98
+ rejects with retryable `NETWORK_TIMEOUT`.
98
99
  A cancelled response cannot establish a Work session even if its body has
99
100
  already finished parsing.
100
101
 
101
- The current Website Access release accepts any valid HTTP(S) host Origin and
102
- does not require DNS TXT verification. Session tokens remain bound to the
103
- Origin observed when they were issued, but that Origin is not compared with a
104
- registered allowlist. The hosted checkout iframe likewise has no parent-Origin
105
- `frame-ancestors` restriction; its signed launch context, expiry, official
106
- Shop URL, and server-authoritative entitlement checks remain enforced.
107
-
108
- Website access login renders the work-bound WeChat QR code directly in the SDK
109
- layer. Paid access keeps desktop QR payment and WeChat JSAPI in that layer;
110
- mobile H5/WAP payment may open a provider page or app. The original page polls
111
- the server-authoritative access decision and closes the layer after entitlement
112
- is active. Before login, the consent layer shows only the creator avatar,
113
- display name, published Work count, and the current Work title, summary, and
114
- cover. This behavior does not change the separate Tip Widget flow.
102
+ Website Access v3 is negotiated during the first Access session request via
103
+ `supportedAccessProtocolVersions: [3]`. An unversioned server response retains
104
+ the legacy login/follow flow and CNY `amountCents` representation. V3 returns
105
+ CNY or USD `amountMinor` prices and feature `status`; `PENDING_CHANNEL` may have
106
+ no sale price and a non-null `pricingIntent`. The server decides which channels
107
+ are ready. GLOBAL supports access integration and login; missing payment
108
+ channels never fall back to CN or create an order.
109
+
110
+ V3 does not require, bind, or compare host Origin, including null/missing origins.
111
+ Official HTTPS Shop URLs and server-authoritative identity, Work, expiry, and
112
+ entitlement validation remain mandatory. Browser restrictions on Web Crypto,
113
+ frames, navigation, and storage can still require a first-party recovery step.
114
+
115
+ `access.require(featureKey)` handles buyer identification, checkout, and a fresh
116
+ access check. It never grants access from a payment or window message. V3 login
117
+ opens directly from the initiating action; `FOLLOW` executes in that same user
118
+ interaction without another confirmation. Shop owns automatic follow after an
119
+ authenticated login/payment; anonymous purchase skips both login and follow.
120
+
121
+ Optional recovery controls use the same protocol:
122
+
123
+ ```ts
124
+ await client.access.restorePurchase('download'); // Remains anonymous.
125
+ await client.access.claimPurchase('download'); // User explicitly chooses login and claim.
126
+ ```
127
+
128
+ The official page owns purchase receipts, account selection, and claim consent.
129
+ The SDK obtains only a short-lived Work-scoped buyer or user credential through
130
+ PKCE challenge/result/exchange calls. These calls omit cookies. It does not
131
+ accept credentials from postMessage, query strings, or fragments. Explicit
132
+ claim replaces the current anonymous context only after a verified user
133
+ exchange; failed/cancelled claim keeps existing purchase authorization.
134
+
135
+ If an iframe cannot access first-party storage, “在当前页面继续” navigates to the
136
+ official page. Only the challenge, state, verifier, and selected feature/purpose
137
+ are saved in sessionStorage for at most five minutes. After returning, invoking
138
+ the same action or `require()` for the same feature resumes the authorized
139
+ recovery/claim handshake. No buyer/user token, recovery secret,
140
+ or payment result is persisted by the SDK. Unavailable navigation storage is
141
+ reported instead of pretending that a purchase was recovered.
142
+
143
+ Work-session refresh is single-flight and server expiry retries at most once.
144
+ Refreshing a Work session drops user/buyer context; the next authoritative
145
+ check can request recovery again. Logout, identity replacement, and destruction
146
+ invalidate late identity results. Authorization reads that race a session
147
+ change are retried against the current identity; successful mutations are not
148
+ replayed merely because another request refreshed a session. Both explicit
149
+ `destroy()` and caller cancellation stop bridge polling and close the layer;
150
+ the caller's `Error` reason remains intact.
115
151
 
116
152
  ```ts
117
153
  const decisions = await client.access.checkMany(['members', 'pro-tools']);