@witnium-tech/witniumchain 0.2.0 → 0.5.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
@@ -1,25 +1,43 @@
1
1
  # @witnium-tech/witniumchain
2
2
 
3
- TypeScript SDK for the WitniumChain accounts service identity, billing,
4
- organisation administration, OAuth sessions, and delegated-signing-key
5
- management.
3
+ TypeScript SDK for WitniumChain — the canonical single client for both the
4
+ accounts service (identity, billing, OAuth, delegated keys, witness writes)
5
+ and the chain-api read surfaces (contract info, witness lookup, wallet
6
+ balance, dashboards). The two-service backend is hidden behind one
7
+ `WitniumchainClient` class; you give it one OAuth access token and it knows
8
+ where each call belongs.
6
9
 
7
10
  ## Status
8
11
 
9
- **v0.1low-level "shell" client.** One method per OpenAPI route, five
10
- auth modes selectable on a single client. Thread 4 of Phase C will layer
11
- three higher-level clients on top:
12
-
13
- - `WitniumAccountsClient` (end-user) wraps signup, login, subscriptions,
14
- delegated-key one-call provisioning, account management.
15
- - `WitniumAccountsOrgClient` (org admin) wraps user provisioning, Stripe
16
- Connect onboarding.
17
- - `WitniumAccountsAdminClient` (sysadmin) wraps org lifecycle, key
18
- rotation, credit adjustment.
19
-
20
- For now, this shell client is what's published. Every type comes from the
21
- OpenAPI spec via `openapi-typescript`; a CI drift test in the parent repo
22
- gates regeneration on every change.
12
+ **v0.5adds OAuth 2.1 + PKCE login helpers** on top of the v0.4 surface:
13
+
14
+ - All 41 accounts routes (five auth modes: session / OAuth / org / admin / signed)
15
+ - 9 chain-api read methods, routed to `chainBaseUrl`, reusing the same OAuth
16
+ `accessToken` (accounts mints tokens with `aud=https://api.witniumchain.com`,
17
+ so they're valid against both services unchanged)
18
+ - Three layered clients on top: `WitniumchainClient` (end-user),
19
+ `WitniumchainOrgClient` (org admin), `WitniumchainAdminClient` (sysadmin)
20
+ - **`beginOAuthLogin` / `completeOAuthLogin` / `refreshAccessToken` / `signOut`**
21
+ browser-side Authorization-Code + PKCE login flow. Discovery-driven
22
+ endpoint resolution (`/.well-known/openid-configuration`), PKCE verifier
23
+ in `sessionStorage`, access token held in memory only, transparent 401-retry
24
+ with single-flight refresh-token rotation. Refresh tokens are delivered as
25
+ an HttpOnly `wac_refresh` cookie scoped to `Path=/token` — JavaScript never
26
+ touches them. Non-browser callers (Node SSR, native apps without a cookie
27
+ jar) fall back to in-band refresh-token delivery; the SDK handles both.
28
+ - **`client.mfa.totp.enroll/confirm/disable` + `client.mfa.recoveryCodes.regenerate`** —
29
+ TOTP MFA self-management. `enroll` returns the secret + otpauth URL (render
30
+ as a QR code in your dashboard with any QR lib); `confirm` validates the
31
+ first code and returns 10 single-use recovery codes (shown ONCE).
32
+
33
+ What's NOT exposed (by design): chain-api v5 writes — those are proxied by
34
+ accounts' v5 surface which adds credit reservation + idempotency + scope
35
+ checks. Calling chain-api writes directly would burn credits without
36
+ billing them. See `docs/PLAN-PHASE-SDK-UNIFIED.md` for the routing rules.
37
+
38
+ Every type comes from the published OpenAPI specs of both services via
39
+ `openapi-typescript`. `npm run openapi:check` regenerates and fails on
40
+ diff; it runs ahead of every `npm publish`.
23
41
 
24
42
  ## Install
25
43
 
@@ -29,14 +47,14 @@ npm install @witnium-tech/witniumchain
29
47
 
30
48
  ## Auth model
31
49
 
32
- The accounts service accepts five distinct credentials. Configure whichever
50
+ The SDK accepts five distinct credentials. Configure whichever
33
51
  you need on the client; methods that require a credential you didn't supply
34
52
  throw at call time.
35
53
 
36
54
  | Credential | Header / Cookie | Used by |
37
55
  |---|---|---|
38
56
  | `sessionCookie` | `Cookie: wac_session=…` | `/v1/auth/logout`, `/v1/account/*`, `/v1/billing/*`, `/v1/keys/*`, `/v1/contracts/{pause,unpause}`, `/v1/oauth/sessions*` |
39
- | `accessToken` | `Authorization: Bearer <JWT>` | `/v1/users/me/delegated-keys/*`, `/v1/sign` |
57
+ | `accessToken` | `Authorization: Bearer <JWT>` | `/v1/users/me/delegated-keys/*`, `/v1/sign`, **all chain-api reads** |
40
58
  | `orgApiKey` | `Authorization: Bearer wcorg_live_…` | `/v1/orgs/me/*` |
41
59
  | `adminToken` | `Authorization: Bearer <ADMIN_TOKEN>` | `/v1/admin/*` |
42
60
  | `signedRequest` | `X-Witnium-Key/Timestamp/Signature` | `/v1/contracts/{addr}/witnesses/{propose,sign,finalize,revoke}` |
@@ -45,14 +63,38 @@ Public routes need no credential (`/v1/auth/{signup,verify,login,…}`,
45
63
  `/v1/contracts/provision`, `GET /v1/contracts/{addr}/witnesses/{id}`,
46
64
  `/health/*`).
47
65
 
66
+ ## Two services, one client
67
+
68
+ Accounts and chain-api are separate services today (consolidation is a
69
+ later phase). The SDK hides that:
70
+
71
+ ```ts
72
+ const client = new WitniumchainClient({
73
+ baseUrl: 'https://auth.witniumchain.com', // accounts
74
+ chainBaseUrl: 'https://api.witniumchain.com', // chain-api (omit if you only need accounts)
75
+ accessToken: oauthBearerJwt,
76
+ });
77
+
78
+ // Writes / billing / auth → accounts (baseUrl)
79
+ await client.proposeWitnessV5('0xabc', { ... });
80
+
81
+ // Reads of on-chain state → chain-api (chainBaseUrl)
82
+ const witness = await client.getWitnessV5('0xabc', witnessId);
83
+ const balance = await client.getWalletBalance('0xabc');
84
+ ```
85
+
86
+ If you call a chain-api method without `chainBaseUrl` configured, the SDK
87
+ throws a clear `WitniumchainApiError` at call time naming the missing
88
+ config — no silent fallback to a wrong base URL.
89
+
48
90
  ## Examples
49
91
 
50
92
  ### End-user signup + login
51
93
 
52
94
  ```ts
53
- import { WitniumAccountsClient } from '@witnium-tech/witniumchain';
95
+ import { WitniumchainClient } from '@witnium-tech/witniumchain';
54
96
 
55
- const client = new WitniumAccountsClient({
97
+ const client = new WitniumchainClient({
56
98
  baseUrl: 'https://auth.witniumchain.com',
57
99
  });
58
100
 
@@ -68,7 +110,7 @@ await client.login({ email: 'alice@example.com', password: '…' });
68
110
  ### Org admin — create a user
69
111
 
70
112
  ```ts
71
- const org = new WitniumAccountsClient({
113
+ const org = new WitniumchainClient({
72
114
  baseUrl: 'https://auth.witniumchain.com',
73
115
  orgApiKey: 'wcorg_live_…',
74
116
  });
@@ -83,7 +125,7 @@ const { userId, provisioningToken } = await org.createOrgUser({
83
125
  ### Sysadmin — create an organisation
84
126
 
85
127
  ```ts
86
- const sys = new WitniumAccountsClient({
128
+ const sys = new WitniumchainClient({
87
129
  baseUrl: 'https://auth.witniumchain.com',
88
130
  adminToken: process.env.ACCOUNTS_ADMIN_TOKEN!,
89
131
  });
@@ -97,10 +139,44 @@ const { organization, apiKey } = await sys.createOrganization({
97
139
  // `apiKey` is shown ONCE — store it now.
98
140
  ```
99
141
 
142
+ ### Sign in with Witnium (Authorization Code + PKCE)
143
+
144
+ For a browser SPA (e.g. a Lovable app) that wants to authenticate end-users
145
+ against a Witnium org. No backend required.
146
+
147
+ ```ts
148
+ const client = new WitniumchainClient({
149
+ baseUrl: 'https://auth.witniumchain.com',
150
+ oauthClientId: 'your-registered-client-id',
151
+ });
152
+
153
+ // 1. Kick off login. The SDK generates a PKCE pair, stashes the verifier in
154
+ // sessionStorage, and returns the URL to send the user to.
155
+ const { authorizationUrl } = await client.beginOAuthLogin({
156
+ redirectUri: 'https://your-app.example/callback',
157
+ });
158
+ window.location.assign(authorizationUrl);
159
+
160
+ // 2. On the callback page, complete the exchange. Returns the access token
161
+ // (the SDK ALSO holds it in memory; subsequent BearerJWT calls Just Work).
162
+ const { accessToken, expiresAt } = await client.completeOAuthLogin(
163
+ window.location.href,
164
+ );
165
+ window.history.replaceState({}, '', window.location.pathname); // strip ?code=…
166
+
167
+ // 3. Use the SDK normally. When the access token expires, the SDK refreshes
168
+ // transparently on the next call. You only need to redirect to login if
169
+ // refresh itself fails (refresh token revoked or expired).
170
+ const { keys } = await client.listDelegatedKeys();
171
+
172
+ // 4. Sign-out clears in-memory tokens.
173
+ client.signOut();
174
+ ```
175
+
100
176
  ### OAuth API — delegated-key + sign
101
177
 
102
178
  ```ts
103
- const api = new WitniumAccountsClient({
179
+ const api = new WitniumchainClient({
104
180
  baseUrl: 'https://auth.witniumchain.com',
105
181
  accessToken: bearerJwt,
106
182
  });
@@ -120,7 +196,7 @@ const { signature } = await api.sign(
120
196
  ### SDK signed-request (witness propose/sign/finalize)
121
197
 
122
198
  ```ts
123
- const sdk = new WitniumAccountsClient({
199
+ const sdk = new WitniumchainClient({
124
200
  baseUrl: 'https://auth.witniumchain.com',
125
201
  signedRequest: {
126
202
  publicKeyHex: 'abcd…64-chars…',
@@ -140,15 +216,15 @@ const intent = await sdk.proposeWitness('0x…', {
140
216
 
141
217
  ## Errors
142
218
 
143
- All non-2xx responses surface as `WitniumAccountsApiError`:
219
+ All non-2xx responses surface as `WitniumchainApiError`:
144
220
 
145
221
  ```ts
146
- import { WitniumAccountsApiError } from '@witnium-tech/witniumchain';
222
+ import { WitniumchainApiError } from '@witnium-tech/witniumchain';
147
223
 
148
224
  try {
149
225
  await client.createOrgUser({ email: 'taken@example.com' });
150
226
  } catch (err) {
151
- if (err instanceof WitniumAccountsApiError) {
227
+ if (err instanceof WitniumchainApiError) {
152
228
  console.error(err.status, err.errorLabel, err.message);
153
229
  // err.body holds the raw parsed body for advanced inspection.
154
230
  }