@witnium-tech/witniumchain 0.11.0 → 0.12.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.
@@ -86,16 +86,17 @@ const result = await client.createOrg({
86
86
  ownerPublicKey: ownerPubHex,
87
87
  initialSigningPublicKey: signingPubHex,
88
88
  });
89
- // → { orgId, userId, contractAddress, contractVersion, emailVerifyToken }
89
+ // → { orgId, userId, contractAddress, contractVersion }
90
90
  ```
91
91
 
92
92
  Persist the two private keys + `contractAddress` locally (wrapped, per §1) and
93
93
  prompt a recovery-file download (§5) before doing anything else.
94
94
 
95
- `emailVerifyToken` is also emailed to the admin. It's echoed in the response so
96
- you can render a "click to verify" link inline if you prefer. **The email is
97
- the login gate, not the contract-deploy gate** — the contract is already live
98
- when this returns.
95
+ The verification email is sent to `adminEmail`; there is nothing to render.
96
+ The response never carries the verify token. If the email cannot be sent,
97
+ nothing is created and the call fails with a 502; retry the same request.
98
+ **The email is the login gate, not the contract-deploy gate**: the contract is
99
+ already live when this returns.
99
100
 
100
101
  ---
101
102
 
@@ -112,12 +113,27 @@ await client.verifyEmail(token); // GET /v1/auth/verify?token=…
112
113
  ### Password login
113
114
 
114
115
  ```ts
115
- await client.login({ email, password }); // sets wac_session cookie
116
+ const res = await client.login({ email, password });
117
+ if (res.status === 'mfa_required') {
118
+ // NO session yet. Ask for the authenticator code (offer "use a recovery code").
119
+ await client.loginMfa({ code }); // or { recoveryCode }
120
+ }
121
+ // status 'authenticated': the wac_session cookie is set
116
122
  ```
117
123
 
118
- In a browser the `wac_session` cookie is set automatically (the SDK uses
124
+ Always check `status`. A user with an authenticator app gets `mfa_required`
125
+ and only a short-lived challenge cookie scoped to `/v1/auth/login/mfa`;
126
+ treating that as logged in leaves the user without a session. `loginMfa`
127
+ errors: 401 `mfa_code_invalid` (wrong or reused code, let them retry), 401
128
+ `mfa_challenge_invalid` (expired or too many tries, back to the password
129
+ step), 429 `mfa_rate_limited` (`retryAfterSeconds` on the error body).
130
+
131
+ In a browser the cookies are set automatically (the SDK uses
119
132
  `credentials: 'include'`). Server-side callers must capture + replay the cookie.
120
133
 
134
+ `client.logout()` ends the session and drops the SDK's cached bearer token,
135
+ even when the request fails.
136
+
121
137
  ### Cookie-only dashboard → bearer calls (automatic, no OAuth needed)
122
138
 
123
139
  You do **not** need to run the OAuth code flow to call the operational API
@@ -157,9 +173,19 @@ and the accounts OpenAPI for `/v1/auth/magic/*`.
157
173
 
158
174
  ```ts
159
175
  const { secret, otpauthUrl } = await client.mfa.totp.enroll(); // render QR from otpauthUrl
160
- const { recoveryCodes } = await client.mfa.totp.confirm({ code }); // show ONCE
176
+ const { recoveryCodes } = await client.mfa.totp.confirm(code); // show ONCE
177
+
178
+ // Both need the user's current code (or a recovery code):
179
+ await client.mfa.totp.disable({ code });
180
+ const { recoveryCodes: fresh } = await client.mfa.recoveryCodes.regenerate({ recoveryCode });
161
181
  ```
162
182
 
183
+ `confirm` signs the user out of every other device and connected app (MCP
184
+ connectors included); tell the user so. The SDK drops its cached
185
+ session-minted bearer token and mints a fresh one on the next call.
186
+ `disable` and `regenerate` fail with 403 `mfa_step_up_failed` on a wrong
187
+ proof and 429 `mfa_rate_limited`.
188
+
163
189
  ### OAuth 2.1 + PKCE (for when your dashboard is itself an OAuth client)
164
190
 
165
191
  ```ts
package/README.md CHANGED
@@ -28,16 +28,25 @@ where each call belongs.
28
28
  - **`client.mfa.totp.enroll/confirm/disable` + `client.mfa.recoveryCodes.regenerate`** —
29
29
  TOTP MFA self-management. `enroll` returns the secret + otpauth URL (render
30
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).
31
+ first code and returns 10 single-use recovery codes (shown ONCE). `disable`
32
+ and `regenerate` require a second-factor proof (`{ code }` or
33
+ `{ recoveryCode }`). Password login: check `login()`'s `status`; on
34
+ `mfa_required`, finish with `loginMfa({ code })`.
32
35
 
33
36
  What's NOT exposed (by design): chain-api v5 writes — those are proxied by
34
37
  accounts' v5 surface which adds credit reservation + idempotency + scope
35
38
  checks. Calling chain-api writes directly would burn credits without
36
39
  billing them. See `docs/PLAN-PHASE-SDK-UNIFIED.md` for the routing rules.
37
40
 
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`.
41
+ Every type comes from the OpenAPI specs of both services, vendored in
42
+ `specs/` and compiled with `openapi-typescript`. `npm test` fails when the
43
+ chain spec differs from this repo's `public/openapi.json`, when the accounts
44
+ spec differs from the sha256 recorded in `specs/sources.json`, or when
45
+ `src/generated/` is stale. The accounts service is a separate private repo, so
46
+ CI cannot read it: `npm run openapi:verify:accounts` (with
47
+ `WITNIUMCHAIN_ACCOUNTS_REPO` pointing at a clone) checks the recorded commit
48
+ and the current `origin/main` there, and runs ahead of every `npm publish`.
49
+ `npm run openapi:refresh` re-vendors both specs and regenerates the types.
41
50
 
42
51
  ## Install
43
52
 
@@ -104,7 +113,8 @@ const { provisioningToken } = await client.verifyEmail('the-token-from-the-link'
104
113
 
105
114
  // Then login (sets the wac_session cookie in a browser; in Node, capture
106
115
  // from response headers and pass back via `sessionCookie`).
107
- await client.login({ email: 'alice@example.com', password: '…' });
116
+ const res = await client.login({ email: 'alice@example.com', password: '…' });
117
+ if (res.status === 'mfa_required') await client.loginMfa({ code: '123456' });
108
118
  ```
109
119
 
110
120
  ### Org admin — create a user