@sogni-ai/sogni-client 5.80.1 → 5.82.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.
Files changed (215) hide show
  1. package/AGENTS.md +2 -1
  2. package/CHANGELOG.md +25 -0
  3. package/README.md +192 -2
  4. package/dist/Account/TwoFactorRequiredError.d.ts +8 -0
  5. package/dist/Account/TwoFactorRequiredError.js +14 -0
  6. package/dist/Account/TwoFactorRequiredError.js.map +1 -0
  7. package/dist/Account/index.d.ts +43 -0
  8. package/dist/Account/index.js +97 -13
  9. package/dist/Account/index.js.map +1 -1
  10. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.js +6 -5
  11. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.js.map +1 -1
  12. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.d.ts +11 -0
  13. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js +43 -5
  14. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js.map +1 -1
  15. package/dist/ApiClient/WebSocketClient/events.d.ts +27 -0
  16. package/dist/ApiClient/WebSocketClient/index.d.ts +13 -0
  17. package/dist/ApiClient/WebSocketClient/index.js +33 -1
  18. package/dist/ApiClient/WebSocketClient/index.js.map +1 -1
  19. package/dist/ApiClient/WebSocketClient/messages.d.ts +8 -0
  20. package/dist/ApiClient/WebSocketClient/types.d.ts +4 -0
  21. package/dist/ApiClient/index.d.ts +19 -1
  22. package/dist/ApiClient/index.js +23 -1
  23. package/dist/ApiClient/index.js.map +1 -1
  24. package/dist/Chat/modelRouting.d.ts +1 -0
  25. package/dist/Chat/modelRouting.js +7 -1
  26. package/dist/Chat/modelRouting.js.map +1 -1
  27. package/dist/MediaEncryption/index.d.ts +153 -0
  28. package/dist/MediaEncryption/index.js +434 -0
  29. package/dist/MediaEncryption/index.js.map +1 -0
  30. package/dist/Projects/Job.d.ts +27 -1
  31. package/dist/Projects/Job.js +51 -4
  32. package/dist/Projects/Job.js.map +1 -1
  33. package/dist/Projects/Project.d.ts +29 -0
  34. package/dist/Projects/Project.js +43 -2
  35. package/dist/Projects/Project.js.map +1 -1
  36. package/dist/Projects/createJobRequestMessage.js +16 -0
  37. package/dist/Projects/createJobRequestMessage.js.map +1 -1
  38. package/dist/Projects/index.d.ts +63 -2
  39. package/dist/Projects/index.js +391 -71
  40. package/dist/Projects/index.js.map +1 -1
  41. package/dist/Projects/recovery.js +4 -0
  42. package/dist/Projects/recovery.js.map +1 -1
  43. package/dist/Projects/types/JobProvenance.d.ts +2 -0
  44. package/dist/Projects/types/PayAsYouGo.d.ts +88 -0
  45. package/dist/Projects/types/PayAsYouGo.js +60 -0
  46. package/dist/Projects/types/PayAsYouGo.js.map +1 -0
  47. package/dist/Projects/types/RawProject.d.ts +2 -0
  48. package/dist/Projects/types/events.d.ts +9 -1
  49. package/dist/Projects/types/index.d.ts +143 -1
  50. package/dist/Projects/types/index.js.map +1 -1
  51. package/dist/Projects/utils/imageLayers.d.ts +7 -0
  52. package/dist/Projects/utils/imageLayers.js +123 -0
  53. package/dist/Projects/utils/imageLayers.js.map +1 -0
  54. package/dist/browser/mediaEncryptionPlayback/encryptedMediaResponse.d.ts +11 -0
  55. package/dist/browser/mediaEncryptionPlayback/encryptedMediaResponse.js +97 -0
  56. package/dist/browser/mediaEncryptionPlayback/encryptedMediaResponse.js.map +1 -0
  57. package/dist/browser/mediaEncryptionPlayback/encryptedMediaWorker.d.ts +5 -0
  58. package/dist/browser/mediaEncryptionPlayback/encryptedMediaWorker.js +109 -0
  59. package/dist/browser/mediaEncryptionPlayback/encryptedMediaWorker.js.map +1 -0
  60. package/dist/browser/mediaEncryptionPlayback/encryptedPlayback.d.ts +12 -0
  61. package/dist/browser/mediaEncryptionPlayback/encryptedPlayback.js +169 -0
  62. package/dist/browser/mediaEncryptionPlayback/encryptedPlayback.js.map +1 -0
  63. package/dist/browser/mediaEncryptionPlayback/index.d.ts +3 -0
  64. package/dist/browser/mediaEncryptionPlayback/index.js +20 -0
  65. package/dist/browser/mediaEncryptionPlayback/index.js.map +1 -0
  66. package/dist/index.d.ts +47 -6
  67. package/dist/index.js +24 -8
  68. package/dist/index.js.map +1 -1
  69. package/dist/lib/RestClient.d.ts +6 -0
  70. package/dist/lib/RestClient.js +12 -0
  71. package/dist/lib/RestClient.js.map +1 -1
  72. package/dist/lib/mediaEncryption/capability.d.ts +16 -0
  73. package/dist/lib/mediaEncryption/capability.js +12 -0
  74. package/dist/lib/mediaEncryption/capability.js.map +1 -0
  75. package/dist/lib/mediaEncryption/crypto.d.ts +36 -0
  76. package/dist/lib/mediaEncryption/crypto.js +169 -0
  77. package/dist/lib/mediaEncryption/crypto.js.map +1 -0
  78. package/dist/lib/mediaEncryption/format.d.ts +62 -0
  79. package/dist/lib/mediaEncryption/format.js +167 -0
  80. package/dist/lib/mediaEncryption/format.js.map +1 -0
  81. package/dist/lib/mediaEncryption/index.d.ts +12 -0
  82. package/dist/lib/mediaEncryption/index.js +46 -0
  83. package/dist/lib/mediaEncryption/index.js.map +1 -0
  84. package/dist/lib/mediaEncryption/inputKeys.d.ts +24 -0
  85. package/dist/lib/mediaEncryption/inputKeys.js +102 -0
  86. package/dist/lib/mediaEncryption/inputKeys.js.map +1 -0
  87. package/dist/lib/mediaEncryption/networks.d.ts +14 -0
  88. package/dist/lib/mediaEncryption/networks.js +22 -0
  89. package/dist/lib/mediaEncryption/networks.js.map +1 -0
  90. package/dist/lib/mediaEncryption/recipient.d.ts +17 -0
  91. package/dist/lib/mediaEncryption/recipient.js +106 -0
  92. package/dist/lib/mediaEncryption/recipient.js.map +1 -0
  93. package/dist/lib/mediaEncryption/redact.d.ts +5 -0
  94. package/dist/lib/mediaEncryption/redact.js +34 -0
  95. package/dist/lib/mediaEncryption/redact.js.map +1 -0
  96. package/dist/lib/mediaEncryption/remote.d.ts +18 -0
  97. package/dist/lib/mediaEncryption/remote.js +243 -0
  98. package/dist/lib/mediaEncryption/remote.js.map +1 -0
  99. package/dist/lib/validation.d.ts +12 -2
  100. package/dist/lib/validation.js +100 -10
  101. package/dist/lib/validation.js.map +1 -1
  102. package/dist/types/ErrorData.d.ts +15 -0
  103. package/dist/types/ErrorData.js +15 -1
  104. package/dist/types/ErrorData.js.map +1 -1
  105. package/dist/version.d.ts +1 -1
  106. package/dist/version.js +1 -1
  107. package/dist-esm/Account/TwoFactorRequiredError.js +11 -0
  108. package/dist-esm/Account/TwoFactorRequiredError.js.map +1 -0
  109. package/dist-esm/Account/index.js +97 -13
  110. package/dist-esm/Account/index.js.map +1 -1
  111. package/dist-esm/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.js +6 -5
  112. package/dist-esm/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.js.map +1 -1
  113. package/dist-esm/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js +43 -5
  114. package/dist-esm/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js.map +1 -1
  115. package/dist-esm/ApiClient/WebSocketClient/index.js +33 -1
  116. package/dist-esm/ApiClient/WebSocketClient/index.js.map +1 -1
  117. package/dist-esm/ApiClient/index.js +23 -1
  118. package/dist-esm/ApiClient/index.js.map +1 -1
  119. package/dist-esm/Chat/modelRouting.js +8 -2
  120. package/dist-esm/Chat/modelRouting.js.map +1 -1
  121. package/dist-esm/MediaEncryption/index.js +429 -0
  122. package/dist-esm/MediaEncryption/index.js.map +1 -0
  123. package/dist-esm/Projects/Job.js +51 -4
  124. package/dist-esm/Projects/Job.js.map +1 -1
  125. package/dist-esm/Projects/Project.js +43 -2
  126. package/dist-esm/Projects/Project.js.map +1 -1
  127. package/dist-esm/Projects/createJobRequestMessage.js +16 -0
  128. package/dist-esm/Projects/createJobRequestMessage.js.map +1 -1
  129. package/dist-esm/Projects/index.js +351 -31
  130. package/dist-esm/Projects/index.js.map +1 -1
  131. package/dist-esm/Projects/recovery.js +4 -0
  132. package/dist-esm/Projects/recovery.js.map +1 -1
  133. package/dist-esm/Projects/types/PayAsYouGo.js +55 -0
  134. package/dist-esm/Projects/types/PayAsYouGo.js.map +1 -0
  135. package/dist-esm/Projects/types/index.js.map +1 -1
  136. package/dist-esm/Projects/utils/imageLayers.js +120 -0
  137. package/dist-esm/Projects/utils/imageLayers.js.map +1 -0
  138. package/dist-esm/browser/mediaEncryptionPlayback/encryptedMediaResponse.js +93 -0
  139. package/dist-esm/browser/mediaEncryptionPlayback/encryptedMediaResponse.js.map +1 -0
  140. package/dist-esm/browser/mediaEncryptionPlayback/encryptedMediaWorker.js +106 -0
  141. package/dist-esm/browser/mediaEncryptionPlayback/encryptedMediaWorker.js.map +1 -0
  142. package/dist-esm/browser/mediaEncryptionPlayback/encryptedPlayback.js +166 -0
  143. package/dist-esm/browser/mediaEncryptionPlayback/encryptedPlayback.js.map +1 -0
  144. package/dist-esm/browser/mediaEncryptionPlayback/index.js +4 -0
  145. package/dist-esm/browser/mediaEncryptionPlayback/index.js.map +1 -0
  146. package/dist-esm/index.js +16 -5
  147. package/dist-esm/index.js.map +1 -1
  148. package/dist-esm/lib/RestClient.js +12 -0
  149. package/dist-esm/lib/RestClient.js.map +1 -1
  150. package/dist-esm/lib/mediaEncryption/capability.js +9 -0
  151. package/dist-esm/lib/mediaEncryption/capability.js.map +1 -0
  152. package/dist-esm/lib/mediaEncryption/crypto.js +157 -0
  153. package/dist-esm/lib/mediaEncryption/crypto.js.map +1 -0
  154. package/dist-esm/lib/mediaEncryption/format.js +157 -0
  155. package/dist-esm/lib/mediaEncryption/format.js.map +1 -0
  156. package/dist-esm/lib/mediaEncryption/index.js +17 -0
  157. package/dist-esm/lib/mediaEncryption/index.js.map +1 -0
  158. package/dist-esm/lib/mediaEncryption/inputKeys.js +94 -0
  159. package/dist-esm/lib/mediaEncryption/inputKeys.js.map +1 -0
  160. package/dist-esm/lib/mediaEncryption/networks.js +17 -0
  161. package/dist-esm/lib/mediaEncryption/networks.js.map +1 -0
  162. package/dist-esm/lib/mediaEncryption/recipient.js +100 -0
  163. package/dist-esm/lib/mediaEncryption/recipient.js.map +1 -0
  164. package/dist-esm/lib/mediaEncryption/redact.js +31 -0
  165. package/dist-esm/lib/mediaEncryption/redact.js.map +1 -0
  166. package/dist-esm/lib/mediaEncryption/remote.js +240 -0
  167. package/dist-esm/lib/mediaEncryption/remote.js.map +1 -0
  168. package/dist-esm/lib/validation.js +99 -9
  169. package/dist-esm/lib/validation.js.map +1 -1
  170. package/dist-esm/types/ErrorData.js +14 -0
  171. package/dist-esm/types/ErrorData.js.map +1 -1
  172. package/dist-esm/version.js +1 -1
  173. package/llms-full.txt +73 -0
  174. package/llms.txt +7 -2
  175. package/package.json +15 -3
  176. package/src/Account/TwoFactorRequiredError.ts +12 -0
  177. package/src/Account/index.ts +183 -3
  178. package/src/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.ts +9 -5
  179. package/src/ApiClient/WebSocketClient/BrowserWebSocketClient/index.ts +42 -4
  180. package/src/ApiClient/WebSocketClient/events.ts +27 -0
  181. package/src/ApiClient/WebSocketClient/index.ts +32 -1
  182. package/src/ApiClient/WebSocketClient/messages.ts +4 -0
  183. package/src/ApiClient/WebSocketClient/types.ts +4 -0
  184. package/src/ApiClient/index.ts +31 -1
  185. package/src/Chat/modelRouting.ts +9 -2
  186. package/src/MediaEncryption/index.ts +500 -0
  187. package/src/Projects/Job.ts +57 -4
  188. package/src/Projects/Project.ts +56 -2
  189. package/src/Projects/createJobRequestMessage.ts +16 -0
  190. package/src/Projects/index.ts +383 -31
  191. package/src/Projects/recovery.ts +4 -0
  192. package/src/Projects/types/JobProvenance.ts +2 -0
  193. package/src/Projects/types/PayAsYouGo.ts +162 -0
  194. package/src/Projects/types/RawProject.ts +2 -0
  195. package/src/Projects/types/events.ts +9 -1
  196. package/src/Projects/types/index.ts +143 -1
  197. package/src/Projects/utils/imageLayers.ts +131 -0
  198. package/src/browser/mediaEncryptionPlayback/encryptedMediaResponse.ts +88 -0
  199. package/src/browser/mediaEncryptionPlayback/encryptedMediaWorker.ts +103 -0
  200. package/src/browser/mediaEncryptionPlayback/encryptedPlayback.ts +166 -0
  201. package/src/browser/mediaEncryptionPlayback/index.ts +3 -0
  202. package/src/index.ts +91 -4
  203. package/src/lib/RestClient.ts +13 -0
  204. package/src/lib/mediaEncryption/capability.ts +17 -0
  205. package/src/lib/mediaEncryption/crypto.ts +217 -0
  206. package/src/lib/mediaEncryption/format.ts +209 -0
  207. package/src/lib/mediaEncryption/index.ts +43 -0
  208. package/src/lib/mediaEncryption/inputKeys.ts +130 -0
  209. package/src/lib/mediaEncryption/networks.ts +31 -0
  210. package/src/lib/mediaEncryption/recipient.ts +118 -0
  211. package/src/lib/mediaEncryption/redact.ts +30 -0
  212. package/src/lib/mediaEncryption/remote.ts +259 -0
  213. package/src/lib/validation.ts +106 -9
  214. package/src/types/ErrorData.ts +18 -0
  215. package/src/version.ts +1 -1
package/AGENTS.md CHANGED
@@ -29,6 +29,7 @@ Current public API anchors:
29
29
  - Project cost helpers are `sogni.projects.estimateCost()`, `estimateVideoCost()`, and `estimateAudioCost()`.
30
30
  - `sogni.projects.assets` manages private subscriber uploads (`upload`, `list`, `remove`, `bind`). Supported servers automatically reuse matching files passed to `projects.create()`; saved IDs do not replace file parameters.
31
31
  - `checkAuth()` is only for cookie-auth browser flows. API-key auth auto-authenticates during `createInstance()`, and token auth uses `login()` or `setTokens()`.
32
+ - Optional media encryption: `createInstance({ mediaEncryption: 'auto' })` encrypts eligible new projects once encryption is available for the account (`sogni.mediaEncryption.available`). Unset, nothing changes. Read results through `job.getResultData()` or `sogni.mediaEncryption.fetchDecrypted()`, which return the media either way. `declareMediaCapability: false` keeps encrypting but has result links serve the media itself.
32
33
  - `ChatCompletionResult` is SDK-shaped (`content`, `role`, `finishReason`, `tool_calls`, `usage`, `cost`). Streaming chunks expose `chunk.content` and optional `chunk.tool_calls`.
33
34
 
34
35
  ## Public Release Security
@@ -72,7 +73,7 @@ Public chat and workflow media rules:
72
73
 
73
74
  ## Overview
74
75
 
75
- This is the **Sogni SDK for JavaScript/Node.js** - a TypeScript client library for the Sogni Supernet, a DePIN protocol for creative AI inference. The SDK supports image generation (Stable Diffusion, Flux, Z-Image / Z-Image Turbo, Krea 2 Turbo, Krea 2 Identity Edit, Chroma v.46 Flash / v.48 Detail / Chroma1-HD, Qwen image-edit models, GPT Image 2 and 2.5, Seedream 5.0 Pro Uncensored, plus community fine-tunes such as Dark Beast Z-Image Turbo v9, Dark Beast KREA 2, Dark Beast Krea 2 Identity Edit, and One Obsession v22), video generation (WAN 2.2, Wan 3, LTX-2.3, Seedance 2.0 and 2.5, HappyHorse 1.1, MiniMax H3, and MiniMax H3 Turbo), promptless video upscaling (FlashVSR v1.1), audio generation (MiniMax Music 3 by default, ACE-Step 1.5), LLM chat with tool calling, hosted creative tools, durable creative workflows, replay records, and multimodal vision chat (Qwen3.6 35B VLM, default `qwen3.6-35b-a3b-gguf-iq4xs`). The model catalog is discovered dynamically at runtime (`sogni.projects.getAvailableModels()`); model ids listed here are illustrative.
76
+ This is the **Sogni SDK for JavaScript/Node.js** - a TypeScript client library for the Sogni Supernet, a DePIN protocol for creative AI inference. The SDK supports image generation (Stable Diffusion, Flux, Z-Image / Z-Image Turbo, Krea 2 Turbo, Krea 2 Identity Edit, Chroma v.46 Flash / v.48 Detail / Chroma1-HD, Qwen image-edit models, GPT Image 2 and 2.5, Seedream 5.0 Pro Uncensored and Seedream 5.5 Uncensored, plus community fine-tunes such as Dark Beast Z-Image Turbo v9, Dark Beast KREA 2, Dark Beast Krea 2 Identity Edit, and One Obsession v22), video generation (WAN 2.2, Wan 3, LTX-2.3, Seedance 2.0 and 2.5, HappyHorse 1.1, MiniMax H3, and MiniMax H3 Turbo), promptless video upscaling (FlashVSR v1.1), audio generation (MiniMax Music 3 by default, ACE-Step 1.5), LLM chat with tool calling, hosted creative tools, durable creative workflows, replay records, and multimodal vision chat (Qwen3.6 35B VLM, default `qwen3.6-35b-a3b-gguf-iq4xs`). The model catalog is discovered dynamically at runtime (`sogni.projects.getAvailableModels()`); model ids listed here are illustrative.
76
77
 
77
78
  Choosing an image-edit model: pick by what the edit has to preserve, not by step count or quality tier. When a person or character must stay recognisable through the edit — style transfer, makeover, clothing or person swap, face swap, new pose or expression, character sheet — use Krea 2 Identity Edit (`krea2_identity_edit_v1_2`, or `dark_beast_krea2_identity_edit_v1_2` uncensored) with 1-2 context images. For general-purpose editing — photo transforms, in-image text, multi-person changes, combining up to 3 references — use a Qwen image-edit model. A higher-step general-purpose editor does not beat the identity model at a likeness task; it reinterprets the subject instead of preserving it. See `llms.txt` for parameters.
78
79
 
package/CHANGELOG.md CHANGED
@@ -1,3 +1,28 @@
1
+ # [5.82.0](https://github.com/Sogni-AI/sogni-client/compare/v5.81.0...v5.82.0) (2026-11-13)
2
+
3
+
4
+ ### Features
5
+
6
+ * **account:** add authenticator and passkey sign-in ([4420bb3](https://github.com/Sogni-AI/sogni-client/commit/4420bb3ef8c9f3669ade0480bb5cedbb2572d492))
7
+ * **media:** add optional media encryption ([ea7a618](https://github.com/Sogni-AI/sogni-client/commit/ea7a61882f2edc854a712b112ff30f91def701c0))
8
+
9
+ # [5.81.0](https://github.com/Sogni-AI/sogni-client/compare/v5.80.1...v5.81.0) (2026-11-13)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * **projects:** name a switch request that never left the client ([6b85108](https://github.com/Sogni-AI/sogni-client/commit/6b8510839d6f6501db5fb6e8b2ead59cb7cfb21d))
15
+ * **projects:** report unknown switch outcomes instead of fake refusals ([736b0ad](https://github.com/Sogni-AI/sogni-client/commit/736b0ad56ddd46eb78d1941a67471ad255d662a8))
16
+ * **projects:** treat a not_found switch reply as an unknown outcome ([c1688f5](https://github.com/Sogni-AI/sogni-client/commit/c1688f5e89e2db9e5fd850825c81aacb2ce15f66))
17
+
18
+
19
+ ### Features
20
+
21
+ * **projects:** expose the pay-as-you-go offer and Premium Spark switch ([672376b](https://github.com/Sogni-AI/sogni-client/commit/672376b92070d15935d030e7360ca2ce4597d271))
22
+ * **projects:** support seedream layer extraction ([a575eb9](https://github.com/Sogni-AI/sogni-client/commit/a575eb9d028bbda2f46a2f04b01e790f75fc3bd7))
23
+ * **seedream:** add Seedream 5.5 transparency, layer options and larger sizes ([0977330](https://github.com/Sogni-AI/sogni-client/commit/0977330bcdf38985b604b971346286ddf8f428bd))
24
+ * **seedream:** recognise Seedream 5.5 Uncensored as a Seedream model ([5f6235f](https://github.com/Sogni-AI/sogni-client/commit/5f6235f932fb3af4569314fe718c8c1617db55a1))
25
+
1
26
  ## [5.80.1](https://github.com/Sogni-AI/sogni-client/compare/v5.80.0...v5.80.1) (2026-11-10)
2
27
 
3
28
 
package/README.md CHANGED
@@ -135,6 +135,51 @@ await sogni.account.login('your-username', 'your-password');
135
135
  const models = await sogni.projects.waitForModels();
136
136
  ```
137
137
 
138
+ #### Two-factor sign-in
139
+
140
+ When an account has enabled two-factor authentication, `login()` throws
141
+ `TwoFactorRequiredError` without starting a session. Ask the person for an
142
+ authenticator or backup code, then complete that challenge:
143
+
144
+ ```javascript
145
+ import { TwoFactorRequiredError } from '@sogni-ai/sogni-client';
146
+
147
+ try {
148
+ await sogni.account.login(username, password, rememberMe);
149
+ } catch (error) {
150
+ if (!(error instanceof TwoFactorRequiredError)) throw error;
151
+ const code = await askForAuthenticatorOrBackupCode(); // Your application's input UI
152
+ await sogni.account.verifyTwoFactorLogin(error, code);
153
+ }
154
+ ```
155
+
156
+ Keep the challenge in memory and discard it when the person cancels. Do not log
157
+ or persist challenge tokens, authenticator setup keys, or backup codes.
158
+ The account API also provides `getTwoFactorStatus()`, `setupTwoFactor()`,
159
+ `confirmTwoFactorSetup()`, `disableTwoFactor()`, and
160
+ `regenerateTwoFactorBackupCodes()`. Setup and management require a password
161
+ session; API keys cannot manage two-factor settings.
162
+
163
+ Passkeys can complete the same pending sign-in from a browser. Trigger the device
164
+ prompt from a user gesture, such as a button click:
165
+
166
+ ```typescript
167
+ import { startAuthentication } from '@simplewebauthn/browser';
168
+
169
+ const pending = await sogni.account.getTwoFactorPasskeyOptions(challenge);
170
+ const assertion = await startAuthentication({ optionsJSON: pending.options });
171
+ await sogni.account.verifyTwoFactorLogin(challenge, {
172
+ challengeId: pending.challengeId,
173
+ assertion
174
+ });
175
+ ```
176
+
177
+ Account security screens use `beginPasskeySetup` / `finishPasskeySetup`
178
+ and `removePasskey`. Save the first registration's backup codes before finishing.
179
+ Management accepts an authenticator/backup code or a passkey proof from
180
+ `getTwoFactorPasskeyOptions()` without a login challenge. Keep pending proofs
181
+ in memory. A second step adds to the Sogni password; it does not replace it.
182
+
138
183
  #### Restoring a deleted account at sign-in
139
184
 
140
185
  When someone signs in to an account they deleted and the account can be restored, `login()` throws
@@ -236,6 +281,35 @@ The same current fields are available on `Project.waitingReason`, `Project.jobWa
236
281
 
237
282
  Set `socketEventSubscriptions: { projectQueue: false }` to opt out. A runtime subscription reset disables this optional stream; subscribe again with `{ projectQueue: true }` if needed.
238
283
 
284
+ #### Running a waiting plan project on Premium Spark
285
+
286
+ When an Unlimited plan project has waited a while on Fast and a card outside the plan's worker pool could start it now, supported servers add an optional offer to the same queue stream. `Project.payAsYouGo` and the `payAsYouGo` field of `queueChanged` hold `{ available: true, costInSpark, coveredByPremiumSpark }`, or `null` when nothing is offered. `costInSpark` is the project's normal Premium Spark price as a decimal string. `coveredByPremiumSpark` is advisory; the server decides when you ask. The offer clears when a result starts, the project ends, the connection drops, or the server stops sending it.
287
+
288
+ Nothing is charged until the owner asks:
289
+
290
+ ```typescript
291
+ const result = await sogni.projects.switchToPremiumSpark(projectId); // or project.switchToPremiumSpark()
292
+ if (result.status === 'switched') {
293
+ // The project now runs on Premium Spark; its price was charged once.
294
+ } else if (result.status === 'refused') {
295
+ // This request costs nothing. If the server had already started its debit
296
+ // (for example 'payment_failed', 'no_idle_worker' or 'started'), that debit
297
+ // is cancelled, and the balance can take a moment to show it, so tell the
298
+ // member they won't be charged rather than that they weren't.
299
+ // result.reason says why. 'started' and 'not_eligible' clear the offer; after other refusals, such as
300
+ // 'insufficient_premium_spark' (offer a Spark purchase, then ask again), the
301
+ // server's next queue update decides whether the offer stays.
302
+ } else {
303
+ // 'unknown' (result.reason: 'timeout', 'not_found', 'session_changed' or
304
+ // 'unrecognized_reply'): the project may have been switched and charged.
305
+ // Treat the payment as possibly made.
306
+ }
307
+ ```
308
+
309
+ Asking again is safe and never charges twice. It answers `switched` if the earlier request switched, a refusal from the server if it costs nothing, or `unknown` again, including `not_found` once the creation has finished. While the outcome stays unknown, check the member's Spark history or the creation's result rather than assuming either way. A `not_sent` refusal comes from the SDK itself: that request never left the client, so it says nothing about the earlier one; ask again once connected.
310
+
311
+ The server reads project ids of at most 128 characters, and API-key sessions are never offered the switch and are refused with `not_eligible`. Concurrent calls for one project share a single request. If the connection drops while a request is pending, the SDK sends it once more after reconnecting. `timeoutMs` (default 45 seconds) counts from when the request is sent. Servers without the feature never send an offer.
312
+
239
313
  User-facing subscription limit notices are opt-in. Enable the event when a client needs live queue, concurrency, or fair-use messaging:
240
314
 
241
315
  ```typescript
@@ -610,7 +684,7 @@ Here is a full list of project parameters that you can use:
610
684
  - `negativePrompt` - text prompt that describes what you don't want to see in the image. Can be an empty string.
611
685
  - `stylePrompt` - text prompt that describes the style of the image. Can be an empty string.
612
686
  - `numberOfImages` - number of images to generate.
613
- - `tokenType` - select token type to pay for render. Can be either `sogni` or `spark`. External API-backed models such as GPT Image 2, Seedream 5.0 Pro Uncensored, and Seedance are Spark-only.
687
+ - `tokenType` - select token type to pay for render. Can be either `sogni` or `spark`. External API-backed models such as GPT Image 2, Seedream 5.0 Pro Uncensored, Seedream 5.5 Uncensored, and Seedance are Spark-only.
614
688
  - `sizePreset` - optionally pass the ID of a size preset to use. If not passed, the default output is a square at
615
689
  either 512x512, 768x768 or 1024x1024 (SDXL and Flux) based on the default resolution of the selected model.
616
690
  See **Detecting available output presets** section below for available presets for your model. The token cost and
@@ -714,7 +788,61 @@ const project = await sogni.projects.create({
714
788
  });
715
789
  ```
716
790
 
717
- It shares the one-time likeness and consent agreement of Seedance 2.5 Uncensored: an account that has accepted it for Seedance can use Seedream, and until it is accepted in a Sogni app every Seedream job fails with `MODEL_CONSENT_REQUIRED_ERROR_CODE` (4103), whose error carries `consentRequired: { key: 'seedance-2-5-uncensored', version, modelId: 'seedream-5-0-pro-uncensored' }` and is detected by `isModelConsentRequiredError()`. `isSeedreamModel()` and `SEEDREAM_5_PRO_UNCENSORED_MODEL_ID` are exported from the package root. Hosted chat tools (`generate_image`, `edit_image`) use it only when the call names it.
791
+ It shares the one-time likeness and consent agreement of Seedance 2.5 Uncensored: an account that has accepted it for Seedance can use Seedream, and until it is accepted in a Sogni app every Seedream job fails with `MODEL_CONSENT_REQUIRED_ERROR_CODE` (4103), whose error carries `consentRequired: { key: 'seedance-2-5-uncensored', version, modelId: 'seedream-5-0-pro-uncensored' }` and is detected by `isModelConsentRequiredError()`. `isSeedreamModel()`, `SEEDREAM_5_PRO_UNCENSORED_MODEL_ID` and `SEEDREAM_5_5_UNCENSORED_MODEL_ID` are exported from the package root. Hosted chat tools (`generate_image`, `edit_image`) use it only when the call names it.
792
+
793
+ ### Seedream 5.5 Uncensored
794
+
795
+ Seedream 5.5 Uncensored (`seedream-5-5-uncensored`) takes the same requests as 5.0 Pro: text-to-image or edits from 1-10 `contextImages`, Spark-only, no negative prompt, seed or steps, and the same one-time agreement. It is chosen only by name; `seedream-uncensored` and the other unversioned names still select 5.0 Pro. Custom sizes run from 921,600 to 4,624,220 pixels at an aspect ratio from 1:16 to 16:1. Its native sizes are:
796
+
797
+ - 1K: 1024x1024, 1152x864, 864x1152, 1424x800, 800x1424, 1248x832, 832x1248, 1568x672
798
+ - 1.5K: 1536x1536, 1792x1344, 1344x1792, 2048x1152, 1152x2048, 1872x1248, 1248x1872, 2352x1008
799
+ - 2K: 2048x2048, 2368x1776, 1776x2368, 2816x1584, 1584x2816, 2496x1664, 1664x2496, 3136x1344
800
+
801
+ `seedreamBackground` sets transparency on 5.5 only: `'opaque'` (the default) returns an RGB image, `'transparent'` an RGBA image, and `'auto'` lets the model decide from the prompt. Transparency works for text-to-image and for edits from up to 10 references, which need no alpha channel of their own. It needs PNG (the default) or WebP output, so `'transparent'` and `'auto'` refuse `outputFormat: 'jpg'`, and it cannot combine with layer extraction.
802
+
803
+ ```javascript
804
+ const sticker = await sogni.projects.create({
805
+ type: 'image', network: 'fast', tokenType: 'spark',
806
+ modelId: 'seedream-5-5-uncensored',
807
+ positivePrompt: 'A glossy cherry sticker with a white die-cut border',
808
+ numberOfMedia: 1, width: 1536, height: 1536,
809
+ seedreamBackground: 'transparent'
810
+ });
811
+ ```
812
+
813
+ ### Seedream layer extraction
814
+
815
+ Both Seedream models can split one image into a base image and transparent PNG layers. Layer extraction is opt-in with `seedreamLayerDecomposition: true`, exactly one `contextImages` entry and `numberOfMedia: 1`. Choose `seedreamLayerSize: '1K' | '1.5K' | '2K'` (default `'1.5K'`); the source determines the aspect ratio. The prompt can be empty, which splits every major element, or name the parts to extract.
816
+
817
+ - Seedream 5.0 Pro Uncensored returns up to 16 layers. Its estimate reserves the maximum 17 returned images.
818
+ - Seedream 5.5 Uncensored returns up to 99 layers. `seedreamLayerMaxImages` caps the images returned, base included, at an integer from 2 to 100 (default 17), and its estimate reserves that many. `seedreamLayerTextRecognition: true` also reads the text of regular text layers.
819
+
820
+ The final charge uses the base image and layers actually returned. Pass the same layer options to `sogni.projects.estimateCost()` to quote a request. Both 5.5 options require `seedreamLayerDecomposition`, and 5.0 Pro refuses them.
821
+
822
+ ```javascript
823
+ const split = await sogni.projects.create({
824
+ type: 'image', network: 'fast', tokenType: 'spark',
825
+ modelId: 'seedream-5-5-uncensored',
826
+ contextImages: [sourceImage], numberOfMedia: 1,
827
+ positivePrompt: '',
828
+ seedreamLayerDecomposition: true, seedreamLayerSize: '1.5K',
829
+ seedreamLayerMaxImages: 8, seedreamLayerTextRecognition: true
830
+ });
831
+ await split.waitForCompletion();
832
+ const job = split.jobs[0];
833
+ // job.resultUrl is the base. job.layers holds the transparent PNG layers,
834
+ // ordered by zIndex, with names, dimensions and absolute/normalized bounds.
835
+ for (const layer of job.layers ?? []) {
836
+ const freshLayerUrl = await job.getLayerUrl(layer.zIndex);
837
+ if (layer.textRecognition) console.log(layer.textRecognition.text);
838
+ }
839
+ ```
840
+
841
+ Each `ImageLayer` has `url`, `width`, `height`, `zIndex` (1-99; the base is 0), `boundingBox: { absolute, normalized }` (`[left, top, right, bottom]` in base-image pixels and on a 0-1000 grid), and optional `name` and `description`. A layer image is rendered near the size tier, so it can be larger than its box: scale it to `right - left` by `bottom - top` before placing it at `left, top` on the base, stacking layers in `zIndex` order.
842
+
843
+ `layer.textRecognition` is present only on Seedream 5.5 layers the model classes as regular text, and only when text recognition was requested; artistic text, handwriting and other layers have none. Its shape is `{ text, lines: [{ boundingBox: { absolute, normalized }, runs: [{ text, style: { similarFontFamily, foregroundColor, bold, italic, underline, strikethrough, shadow, translucent } }] }] }`, where `text` is the layer's full text with lines separated by `\n`, `foregroundColor` is `#RRGGBB`, and `similarFontFamily` is the closest matching font or `'unknown'`.
844
+
845
+ Layer metadata also appears on completed job events and recovered projects. Layer URLs expire; `job.getLayerUrl(zIndex)` refreshes a layer URL after checking ownership. Omitting the extraction options preserves ordinary generation and editing.
718
846
 
719
847
  ### Detecting available output presets
720
848
 
@@ -980,6 +1108,67 @@ clients that manage project IDs and input slots directly.
980
1108
  Project history may include `byolUsed`, `personalLoras` public-source snapshots,
981
1109
  and `reusedAssetCount`. Missing fields on older projects mean unknown, not zero.
982
1110
 
1111
+ ### Media encryption
1112
+
1113
+ The SDK offers optional encryption of project media for the signed-in account.
1114
+ Turn it on when creating the client:
1115
+
1116
+ ```javascript
1117
+ const sogni = await SogniClient.createInstance({ appId, mediaEncryption: 'auto' });
1118
+ await sogni.account.login('username', 'password');
1119
+
1120
+ const project = await sogni.projects.create(params);
1121
+ await project.waitForCompletion();
1122
+ const blob = await project.jobs[0].getResultData(); // the media, with its real MIME type
1123
+ ```
1124
+
1125
+ - Once media encryption is available for the account
1126
+ (`sogni.mediaEncryption.available`), every eligible new project is encrypted.
1127
+ Until then, and without the option, the client works exactly as before.
1128
+ - Read results with `job.getResultData()`, or
1129
+ `sogni.mediaEncryption.fetchDecrypted(url)` for result and preview URLs, rather
1130
+ than loading the URL in an `<img>` or `<video>` directly. Both return the
1131
+ media whether or not it was encrypted.
1132
+ - A project is sent unencrypted when encryption is not available for it: for the
1133
+ account at that moment, for its model (`projects.supportsMediaEncryption(modelId)`),
1134
+ or for its network (Fast only, for now), or when an input is `true` ("already
1135
+ uploaded"). `job.encrypted` and `project.encrypted` say which projects were
1136
+ sent encrypted.
1137
+ - Set `mediaEncryption` on a project to override the client: `false` sends it
1138
+ unencrypted, and `true` encrypts it or throws `MediaEncryptionError` before
1139
+ anything is uploaded. Saved uploads work for encrypted projects too.
1140
+ - Services that pass result links on to others can add
1141
+ `declareMediaCapability: false`: projects are still encrypted, and result,
1142
+ preview and download URLs serve the media itself.
1143
+ - `availabilityChanged` fires when `sogni.mediaEncryption.available` changes.
1144
+ Client-side failures throw `MediaEncryptionError` with a `code` such as
1145
+ `locked`, `unsupported`, `wrong_account_key` or `authentication_failed`.
1146
+
1147
+ For encrypted video and audio, `openDecrypted()` reads byte ranges without
1148
+ downloading the entire file. Offsets refer to the media itself and the end offset
1149
+ is exclusive. Use `stream()` for large reads and close the reader when finished;
1150
+ locking or changing accounts also aborts its outstanding requests.
1151
+
1152
+ ```javascript
1153
+ const media = await sogni.mediaEncryption.openDecrypted(resultUrl);
1154
+ try {
1155
+ const header = await media.read(0, Math.min(1024, media.size));
1156
+ // media.contentType is the media's MIME type; media.stream() reads with backpressure.
1157
+ } finally {
1158
+ media.close();
1159
+ }
1160
+ ```
1161
+
1162
+ Browser apps can import `createEncryptedPlayback` and `serveEncryptedMedia` from
1163
+ `@sogni-ai/sogni-client/media-encryption-playback` to play encrypted video and
1164
+ audio through their own service worker. The worker must route
1165
+ `ENCRYPTED_MEDIA_PATH` requests with the requesting client's ID, and answer
1166
+ `SOGNI_ENCRYPTED_MEDIA_CLIENT` messages through their transferred port with
1167
+ `{ clientId: event.source.id }`. Pass the opened reader to
1168
+ `createEncryptedPlayback()`, use its returned `url` as the media element's
1169
+ source, and call `dispose()` when removing the element. The URL belongs to that
1170
+ tab. This requires an active service worker controlling the page.
1171
+
983
1172
  ### ControlNets
984
1173
 
985
1174
  **EXPERIMENTAL FEATURE:** This feature is still in development and may not work as expected. Use at your own risk.
@@ -2006,6 +2195,7 @@ scheduler and dimension bounds. Both presets accept compatible Personal LoRAs.
2006
2195
  | `qwen_image_edit_2511_fp8_lightning` | **Qwen Image Edit Lightning** - Fast 4-step editing | Rapid reference-based image generation |
2007
2196
  | `qwen_image_edit_2511_fp8` | **Qwen Image Edit** - High quality 20-step editing | Professional image editing with context awareness |
2008
2197
  | `seedream-5-0-pro-uncensored` | **Seedream 5.0 Pro Uncensored** - ByteDance, external API | Text-to-image and edits from 1-10 reference images; accept the Seedance 2.5 Uncensored agreement first (error 4103 until then) |
2198
+ | `seedream-5-5-uncensored` | **Seedream 5.5 Uncensored** - ByteDance, external API | Text-to-image and edits from 1-10 reference images up to 4,624,220 pixels, transparent backgrounds, up to 99 layers; same agreement |
2009
2199
  | `wan_v2.2-14b-fp8_t2v_lightx2v` | **Wan 2.2 T2V** - Text-to-video | Generate videos from text prompts |
2010
2200
  | `seedance-2-0` | **Seedance 2.0** - 4K external API multimodal video | Full Seedance 2.0 24fps video generation with optional image, video, and audio context |
2011
2201
  | `seedance-2-0-mini` | **Seedance 2.0 Mini** - 720p external API video | Fastest, lower-cost 24fps Seedance video generation |
@@ -0,0 +1,8 @@
1
+ /** Sign-in needs an authenticator or backup code before a session can begin. */
2
+ export default class TwoFactorRequiredError extends Error {
3
+ readonly tempToken: string;
4
+ readonly walletAddress: string;
5
+ readonly username: string;
6
+ readonly name = "TwoFactorRequiredError";
7
+ constructor(tempToken: string, walletAddress: string, username: string);
8
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /** Sign-in needs an authenticator or backup code before a session can begin. */
4
+ class TwoFactorRequiredError extends Error {
5
+ constructor(tempToken, walletAddress, username) {
6
+ super('Enter your authenticator code or a backup code to finish signing in.');
7
+ this.tempToken = tempToken;
8
+ this.walletAddress = walletAddress;
9
+ this.username = username;
10
+ this.name = 'TwoFactorRequiredError';
11
+ }
12
+ }
13
+ exports.default = TwoFactorRequiredError;
14
+ //# sourceMappingURL=TwoFactorRequiredError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TwoFactorRequiredError.js","sourceRoot":"","sources":["../../src/Account/TwoFactorRequiredError.ts"],"names":[],"mappings":";;AAAA,gFAAgF;AAChF,MAAqB,sBAAuB,SAAQ,KAAK;IAGvD,YACkB,SAAiB,EACjB,aAAqB,EACrB,QAAgB;QAEhC,KAAK,CAAC,sEAAsE,CAAC,CAAC;QAJ9D,cAAS,GAAT,SAAS,CAAQ;QACjB,kBAAa,GAAb,aAAa,CAAQ;QACrB,aAAQ,GAAR,QAAQ,CAAQ;QALzB,SAAI,GAAG,wBAAwB,CAAC;IAQzC,CAAC;CACF;AAVD,yCAUC"}
@@ -1,3 +1,5 @@
1
+ import type { AuthenticationResponseJSON, RegistrationResponseJSON, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON } from '@simplewebauthn/browser';
2
+ import TwoFactorRequiredError from './TwoFactorRequiredError.js';
1
3
  import { AccountCreateData, AccountCreateParams, Balances, ClaimOptions, FullBalances, LoginData, LoginOptions, MeData, Reward, RewardsQuery, TxHistoryEntry, TxHistoryParams } from './types.js';
2
4
  import { CreateSubscriptionCheckoutOptions, SubscriptionCheckoutResult, SubscriptionEntitlementSnapshot, SubscriptionPlanId, SubscriptionPlan, SubscriptionPortalSession, SubscriptionTerm, SubscriptionUsage, TrialEligibility } from './subscription.types.js';
3
5
  import ApiGroup, { ApiConfig } from '../ApiGroup.js';
@@ -16,6 +18,22 @@ import { SupernetType } from '../ApiClient/WebSocketClient/types.js';
16
18
  * ```
17
19
  *
18
20
  */
21
+ export type TwoFactorProof = {
22
+ code: string;
23
+ } | {
24
+ assertion: AuthenticationResponseJSON;
25
+ challengeId: string;
26
+ };
27
+ export interface TwoFactorStatus {
28
+ enabled: boolean;
29
+ backupCodesRemaining: number;
30
+ canManage: boolean;
31
+ authenticatorEnabled: boolean;
32
+ passkeys: {
33
+ id: string;
34
+ name: string;
35
+ }[];
36
+ }
19
37
  declare class AccountApi extends ApiGroup {
20
38
  readonly currentAccount: CurrentAccount;
21
39
  /**
@@ -139,6 +157,31 @@ declare class AccountApi extends ApiGroup {
139
157
  * seconds).
140
158
  */
141
159
  login(username: string, password: string, rememberMe?: boolean, appSource?: string, options?: LoginOptions): Promise<LoginData>;
160
+ private acceptLogin;
161
+ /** Complete the sign-in requested by a TwoFactorRequiredError. Keep the challenge in memory. */
162
+ verifyTwoFactorLogin(challenge: TwoFactorRequiredError, proof: string | TwoFactorProof): Promise<LoginData>;
163
+ getTwoFactorStatus(): Promise<TwoFactorStatus>;
164
+ getTwoFactorPasskeyOptions(challenge?: TwoFactorRequiredError): Promise<{
165
+ challengeId: string;
166
+ options: PublicKeyCredentialRequestOptionsJSON;
167
+ }>;
168
+ beginPasskeySetup(username: string, password: string, name: string, proof?: TwoFactorProof): Promise<{
169
+ setupId: string;
170
+ options: PublicKeyCredentialCreationOptionsJSON;
171
+ backupCodes?: string[];
172
+ }>;
173
+ finishPasskeySetup(setupId: string, response: RegistrationResponseJSON): Promise<void>;
174
+ removePasskey(username: string, password: string, credentialId: string, proof: string | TwoFactorProof): Promise<void>;
175
+ private twoFactorSignature;
176
+ setupTwoFactor(username: string, password: string, proof?: TwoFactorProof): Promise<{
177
+ setupId: string;
178
+ secret: string;
179
+ qrData: string;
180
+ backupCodes: string[];
181
+ }>;
182
+ confirmTwoFactorSetup(setupId: string, code: string): Promise<void>;
183
+ disableTwoFactor(username: string, password: string, proof: string | TwoFactorProof): Promise<void>;
184
+ regenerateTwoFactorBackupCodes(username: string, password: string, proof: string | TwoFactorProof): Promise<string[]>;
142
185
  /**
143
186
  * Logout the user and close the WebSocket connection.
144
187
  *
@@ -12,6 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
+ const TwoFactorRequiredError_js_1 = __importDefault(require("./TwoFactorRequiredError.js"));
15
16
  const ApiGroup_js_1 = __importDefault(require("../ApiGroup.js"));
16
17
  const requestSession_js_1 = require("../lib/requestSession.js");
17
18
  const ethers_1 = require("ethers");
@@ -43,17 +44,9 @@ function parseSubscriptionVersion(version) {
43
44
  }
44
45
  return null;
45
46
  }
46
- /**
47
- * Account API methods that let you interact with the user's account.
48
- * Can be accessed via `sogni.account`. Look for more samples below.
49
- *
50
- * @example Retrieve the current account balance
51
- * ```typescript
52
- * const balance = await sogni.account.refreshBalance();
53
- * console.log(balance);
54
- * ```
55
- *
56
- */
47
+ function factorProof(value) {
48
+ return typeof value === 'string' ? { code: value.trim().toUpperCase() } : value;
49
+ }
57
50
  class AccountApi extends ApiGroup_js_1.default {
58
51
  constructor(config) {
59
52
  super(config);
@@ -445,17 +438,108 @@ class AccountApi extends ApiGroup_js_1.default {
445
438
  });
446
439
  const resolvedAppSource = (appSource === null || appSource === void 0 ? void 0 : appSource.trim()) || this.client.appSource;
447
440
  const res = yield this.client.rest.post('/v1/account/login', Object.assign(Object.assign(Object.assign({ walletAddress: wallet.address, signature }, (resolvedAppSource ? { appSource: resolvedAppSource } : {})), { rememberMe }), ((options === null || options === void 0 ? void 0 : options.restoreDeletedAccount) ? { restoreDeletedAccount: true } : {})));
441
+ if (res.data.requires2FA) {
442
+ if (!res.data.tempToken)
443
+ throw new Error('Unable to start verification. Please sign in again.');
444
+ throw new TwoFactorRequiredError_js_1.default(res.data.tempToken, wallet.address, res.data.username);
445
+ }
446
+ yield this.acceptLogin(res.data, wallet.address);
447
+ return res.data;
448
+ });
449
+ }
450
+ acceptLogin(data, walletAddress) {
451
+ return __awaiter(this, void 0, void 0, function* () {
448
452
  const auth = this.client.auth;
449
453
  if (auth instanceof index_js_3.TokenAuthManager) {
450
- yield auth.authenticate({ refreshToken: res.data.refreshToken, token: res.data.token });
454
+ yield auth.authenticate({ refreshToken: data.refreshToken, token: data.token });
451
455
  }
452
456
  else if (auth instanceof index_js_3.CookieAuthManager) {
453
- auth._setSessionIdentity(wallet.address.toLowerCase());
457
+ auth._setSessionIdentity(walletAddress.toLowerCase());
454
458
  yield auth.authenticate();
455
459
  }
460
+ });
461
+ }
462
+ /** Complete the sign-in requested by a TwoFactorRequiredError. Keep the challenge in memory. */
463
+ verifyTwoFactorLogin(challenge, proof) {
464
+ return __awaiter(this, void 0, void 0, function* () {
465
+ const res = yield this.client.rest.post('/v1/account/2fa/verify-login', Object.assign({ tempToken: challenge.tempToken }, factorProof(proof)));
466
+ yield this.acceptLogin(res.data, challenge.walletAddress);
467
+ return Object.assign(Object.assign({}, res.data), { username: challenge.username });
468
+ });
469
+ }
470
+ getTwoFactorStatus() {
471
+ return __awaiter(this, void 0, void 0, function* () {
472
+ const res = yield this.client.rest.get('/v1/account/2fa/status');
456
473
  return res.data;
457
474
  });
458
475
  }
476
+ getTwoFactorPasskeyOptions(challenge) {
477
+ return __awaiter(this, void 0, void 0, function* () {
478
+ const res = yield this.client.rest.post(challenge
479
+ ? '/v1/account/2fa/passkeys/login-options'
480
+ : '/v1/account/2fa/passkeys/authentication-options', challenge ? { tempToken: challenge.tempToken } : {});
481
+ return res.data;
482
+ });
483
+ }
484
+ beginPasskeySetup(username, password, name, proof) {
485
+ return __awaiter(this, void 0, void 0, function* () {
486
+ const signature = yield this.twoFactorSignature(username, password);
487
+ const res = yield this.client.rest.post('/v1/account/2fa/passkeys/registration-options', Object.assign({ signature,
488
+ name }, (proof ? { proof } : {})));
489
+ return res.data;
490
+ });
491
+ }
492
+ finishPasskeySetup(setupId, response) {
493
+ return __awaiter(this, void 0, void 0, function* () {
494
+ yield this.client.rest.post('/v1/account/2fa/passkeys/register', { setupId, response });
495
+ });
496
+ }
497
+ removePasskey(username, password, credentialId, proof) {
498
+ return __awaiter(this, void 0, void 0, function* () {
499
+ const signature = yield this.twoFactorSignature(username, password);
500
+ yield this.client.rest.post('/v1/account/2fa/passkeys/remove', Object.assign({ signature,
501
+ credentialId }, factorProof(proof)));
502
+ });
503
+ }
504
+ twoFactorSignature(username, password) {
505
+ return __awaiter(this, void 0, void 0, function* () {
506
+ var _a;
507
+ const wallet = this.getWallet(username, password);
508
+ if (wallet.address.toLowerCase() !== ((_a = this.currentAccount.walletAddress) === null || _a === void 0 ? void 0 : _a.toLowerCase())) {
509
+ throw new Error('Incorrect password. Please try again.');
510
+ }
511
+ const nonce = yield this.getNonce(wallet.address);
512
+ return this.eip712.signTypedData(wallet, 'authentication', {
513
+ walletAddress: wallet.address,
514
+ nonce
515
+ });
516
+ });
517
+ }
518
+ setupTwoFactor(username, password, proof) {
519
+ return __awaiter(this, void 0, void 0, function* () {
520
+ const signature = yield this.twoFactorSignature(username, password);
521
+ const res = yield this.client.rest.post('/v1/account/2fa/setup', Object.assign({ signature }, (proof ? { proof } : {})));
522
+ return res.data;
523
+ });
524
+ }
525
+ confirmTwoFactorSetup(setupId, code) {
526
+ return __awaiter(this, void 0, void 0, function* () {
527
+ yield this.client.rest.post('/v1/account/2fa/verify-setup', { setupId, code: code.trim() });
528
+ });
529
+ }
530
+ disableTwoFactor(username, password, proof) {
531
+ return __awaiter(this, void 0, void 0, function* () {
532
+ const signature = yield this.twoFactorSignature(username, password);
533
+ yield this.client.rest.post('/v1/account/2fa/disable', Object.assign({ signature }, factorProof(proof)));
534
+ });
535
+ }
536
+ regenerateTwoFactorBackupCodes(username, password, proof) {
537
+ return __awaiter(this, void 0, void 0, function* () {
538
+ const signature = yield this.twoFactorSignature(username, password);
539
+ const res = yield this.client.rest.post('/v1/account/2fa/backup-codes', Object.assign({ signature }, factorProof(proof)));
540
+ return res.data.backupCodes;
541
+ });
542
+ }
459
543
  /**
460
544
  * Logout the user and close the WebSocket connection.
461
545
  *