@xkova/sdk 0.1.0-alpha.1 → 0.1.0-alpha.10

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 (51) hide show
  1. package/README.md +324 -32
  2. package/dist/abi.d.ts +40 -0
  3. package/dist/abi.js +25 -0
  4. package/dist/client.d.ts +4 -0
  5. package/dist/client.js +62 -3
  6. package/dist/generated/types.d.ts +8629 -5182
  7. package/dist/held-approval.d.ts +41 -0
  8. package/dist/held-approval.js +33 -0
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.js +1 -0
  11. package/dist/member-action-intents.js +2 -2
  12. package/dist/member-bff.d.ts +60 -21
  13. package/dist/member-bff.js +81 -79
  14. package/dist/member-resources.d.ts +67 -1
  15. package/dist/member-resources.js +9 -5
  16. package/dist/request-signing.js +6 -0
  17. package/dist/resources/account-holders.d.ts +131 -1
  18. package/dist/resources/account-holders.js +44 -9
  19. package/dist/resources/branding.d.ts +10 -0
  20. package/dist/resources/branding.js +2 -0
  21. package/dist/resources/contacts.d.ts +2 -2
  22. package/dist/resources/contacts.js +3 -3
  23. package/dist/resources/escrows.d.ts +3 -0
  24. package/dist/resources/payment-requests.d.ts +4 -0
  25. package/dist/resources/payments.d.ts +13 -0
  26. package/dist/resources/payments.js +7 -0
  27. package/dist/resources/ramps.d.ts +73 -64
  28. package/dist/resources/ramps.js +2 -2
  29. package/dist/resources/rwa.d.ts +9 -9
  30. package/dist/resources/tenant.d.ts +15 -0
  31. package/dist/resources/tenant.js +6 -1
  32. package/dist/resources/tokenization.d.ts +30 -11
  33. package/dist/resources/tokenization.js +10 -10
  34. package/dist/resources/treasury.d.ts +404 -0
  35. package/dist/resources/treasury.js +115 -0
  36. package/dist/resources/wallets.d.ts +2 -0
  37. package/dist/resources/webhooks.d.ts +1 -1
  38. package/dist/resources/webhooks.js +2 -2
  39. package/dist/resources/workflows.d.ts +7 -6
  40. package/dist/resources/workflows.js +87 -24
  41. package/dist/resources/workforce-wallets.d.ts +34 -0
  42. package/dist/resources/workforce-wallets.js +19 -0
  43. package/dist/url.d.ts +1 -0
  44. package/dist/url.js +4 -0
  45. package/dist/webhook.js +1 -1
  46. package/dist/workforce-bff.d.ts +202 -0
  47. package/dist/workforce-bff.js +462 -0
  48. package/examples/postgres-checkpoint-store.mjs +116 -0
  49. package/examples/postgres-checkpoints.sql +9 -0
  50. package/llms.txt +29 -9
  51. package/package.json +8 -3
package/README.md CHANGED
@@ -6,7 +6,7 @@ holders, wallets, payments, tokenization, and other customer resources.
6
6
  ## Install
7
7
 
8
8
  ```bash
9
- npm install @xkova/sdk@0.1.0-alpha.1
9
+ npm install @xkova/sdk@alpha
10
10
  ```
11
11
 
12
12
  Requires Node.js 22 or newer. Keep this package and your API keys on the server.
@@ -93,6 +93,83 @@ one live successor; either key can be revoked immediately.
93
93
 
94
94
  ## Typed resources
95
95
 
96
+ ### Customer workforce applications
97
+
98
+ Use `@xkova/sdk/workforce-bff` on a confidential server for an institution's
99
+ staff application. It is separate from member login and Console operator
100
+ sessions. The Console administrator first registers an exact issuer, audience,
101
+ JWKS endpoint, application origins/callbacks and dedicated workspace API
102
+ principal. They explicitly admit each immutable provider subject to an existing
103
+ staff membership with narrowed roles and assigned resources. Email and provider
104
+ groups never grant authority. A transport key cannot admit its own users.
105
+
106
+ ```ts
107
+ import { XKOVAWorkforceBffClient } from '@xkova/sdk/workforce-bff';
108
+
109
+ const workforce = new XKOVAWorkforceBffClient({
110
+ baseUrl: 'https://sandbox-api.xkova.com',
111
+ apiKey: process.env.XKOVA_WORKFORCE_API_KEY!,
112
+ workforceKey: process.env.XKOVA_WORKFORCE_KEY!,
113
+ });
114
+ ```
115
+
116
+ Use separate encrypted durable transaction/session stores implementing
117
+ `XKOVAWorkforceStore`. Each write must commit independently of a later callback
118
+ error. Serialize each reference across replicas, and make `replace` fail when
119
+ the record is absent. The included PostgreSQL adapter demonstrates this contract.
120
+ Use a distinct namespace from member sessions. Keep session material, provider
121
+ proofs, PKCE verifiers and refresh attempts on the server.
122
+
123
+ `beginAuthorization` returns the registered provider endpoint, audience, nonce,
124
+ PKCE challenge and policy. Use a short-lived HttpOnly flow cookie for its state.
125
+ Your BFF exchanges the real provider code and verifies its signature, issuer,
126
+ audience, nonce and PKCE through `completeAuthorizationCallback`. XKOVA performs
127
+ its own registered-provider verification before issuing the workforce session.
128
+ An uncertain provider exchange cannot redeem the code again. A staged proof can
129
+ recover the same API exchange attempt. A provider token's actual expiry bounds
130
+ the session; refreshing XKOVA credentials does not refresh upstream identity.
131
+
132
+ Read only `projectXKOVAWorkforceSession` into browser UI. Resolve resource access
133
+ per request with `resolveResources({ reference, sessionStore, browserOrigin })`.
134
+ The browser's Origin and session-bound CSRF proof must be checked before writes.
135
+ The BFF pins its registered origin, workforce application and resolved human
136
+ session. Roles/scopes/resources are intersected by the API, never combined with
137
+ the transport principal's authority. A member credential cannot supply workforce
138
+ authority, and workforce sessions cannot enter Console operator routes.
139
+
140
+ For `human_authorization_required`, preserve the exact request, body, origin and
141
+ idempotency key in a private review record. Use `inspectAction` and
142
+ `beginActionProof` for its exact `authorization_token`. Show the returned review
143
+ before starting real fresh provider authentication with the returned nonce and
144
+ qualified assurance policy. Validate the provider callback's own state, PKCE,
145
+ issuer, audience, nonce and current subject; require fresh authentication rather
146
+ than accepting a cached login. Submit the real token with `completeActionProof`.
147
+ Keep its short-lived grant server-side and pass it as `actionGrant` to
148
+ `resolveResources` for only the unchanged frozen request. A grant never approves
149
+ another request or replaces independent Safe signatures/quorum. These methods
150
+ do not automatically retry an action or an uncertain proof completion.
151
+
152
+ `logoutSession` durably blocks the local session before retiring it at XKOVA.
153
+ Retry only that same logout if the network result is uncertain. It does not
154
+ promise a global logout at the external provider. No request may fall back to a
155
+ machine principal after workforce authentication fails.
156
+
157
+ The resolved `wallets` resource supports `list`, `provision`, `register` and
158
+ `signingBootstrap`. Provisioning and signing need the exact one-use human grant.
159
+ Register only after signing the API's returned enrollment typed data. Signing
160
+ bootstrap requires the existing proposal ID, its frozen Safe digest and nonce.
161
+ Use `@xkova/browser/wallet` for the isolated browser ceremony, with a fresh
162
+ purpose-bound admission and the expected wallet address. Keep the BFF key,
163
+ provider proofs and workforce session credentials on the server. Provider
164
+ admission does not replace wallet possession, current signer eligibility,
165
+ independent-person quorum or confirmed chain settlement.
166
+
167
+ Workforce session staff IDs and assigned treasury/token IDs use the API's
168
+ canonical 22-character base62 bodies (`stf_`, `vlt_`, `ctk_`). Preserve these
169
+ opaque values exactly. Server SDK alpha.9 fixes alpha.8's incorrect rejection
170
+ of these API responses. The separate enrollment typed-data UUID strings must
171
+ also remain unchanged; they are not the session's public resource IDs.
172
+
96
173
  Call resource methods with typed inputs:
97
174
 
98
175
  ```ts
@@ -113,6 +190,48 @@ const paymentRequests = await xkova.paymentRequests.list({ limit: 25 });
113
190
 
114
191
  Writes accept an optional caller-provided `idempotencyKey`. Reuse the same key when retrying the same logical request. If omitted, the SDK generates a new key for that individual call.
115
192
 
193
+ Optional mutation queries follow the existing mutation options. For contact
194
+ search, pass the returned cursor to fetch another page; each page is a distinct
195
+ request, so use a new idempotency key or leave the options undefined:
196
+
197
+ ```ts
198
+ const matches = await xkova.contacts.search(
199
+ { account_holder_id: holderId, email: contactEmail },
200
+ undefined,
201
+ { cursor: nextCursor, limit: 25 },
202
+ );
203
+ ```
204
+
205
+ Signer removal accepts its explicit acknowledgement as the fourth argument:
206
+
207
+ ```ts
208
+ await xkova.treasury.deleteSigner(
209
+ vaultId,
210
+ signerStaffId,
211
+ { idempotencyKey: crypto.randomUUID() },
212
+ { acknowledged_unsafe: true },
213
+ );
214
+ ```
215
+
216
+ Set that flag only after reviewing the reduced lost-key safety buffer. Omission
217
+ keeps the API's normal safety check; the SDK never selects acknowledgement.
218
+ The API's minimum threshold, human authorization, current signer authority and
219
+ other controls still apply.
220
+
221
+ Optional bodies for webhook secret rotation, token pause/unpause and access
222
+ registry disable follow the existing mutation options as a third argument:
223
+
224
+ ```ts
225
+ await xkova.webhooks.rotateSecret(
226
+ endpointId,
227
+ { idempotencyKey: crypto.randomUUID() },
228
+ { overlap_sec: 120 },
229
+ );
230
+ ```
231
+
232
+ Omitting that body keeps the API's default behavior. If a token operation's
233
+ body includes `idempotencyKey`, keep it equal to the mutation option's key.
234
+
116
235
  Account-holder `self` methods require a member session and its application's
117
236
  publishable key. Load both from your BFF's session store. These methods act on
118
237
  the signed-in account holder; browser input cannot select a different person:
@@ -124,6 +243,10 @@ const balance = await xkova.accountHolders.selfBalance({
124
243
  });
125
244
  ```
126
245
 
246
+ `selfBalance` can return a partial answer. A chain not known right now has no
247
+ entries in `balances` and a null `through_block` in `data_freshness`, so check
248
+ that before treating a missing token as zero or adding balances together.
249
+
127
250
  ## Register a Hosted Auth application
128
251
 
129
252
  Hosted Auth provides an optional XKOVA-hosted sign-in flow. Register an
@@ -197,26 +320,17 @@ For your own OIDC provider, use `beginAuthorization` and
197
320
  code unless your integration explicitly assigns that exchange to XKOVA. Both
198
321
  sign-in paths use the same XKOVA session and store contracts.
199
322
 
200
- ### Sandbox demo sign-in
201
-
202
- For a sandbox application explicitly enabled for demo sign-in, call
203
- `completeSandboxDemoAuthorization({ state: start.state, transactionStore })`
204
- after `beginHostedAuthorization`. The SDK obtains the capability and exact
205
- callback from the server-held transaction, validates the returned callback and
206
- expiry, and returns `{ callbackUrl, expiresAt }`. Complete that callback through
207
- `completeHostedAuthorization` with the original browser flow cookie. The API
208
- reserves a demo account for the session. This operation is not
209
- available to ordinary tenant applications or production workspaces, and it
210
- accepts no member, email, wallet, or callback selector.
211
-
212
- Keep the same pending reservation and transaction after an ambiguous admission
213
- failure. Repeating the method uses the same idempotency key and recovers the
214
- same demo account reservation. The method never retries automatically.
215
- `isDefinitiveXKOVASandboxDemoAdmissionFailure(error)` identifies confirmed
216
- rejection before an account was reserved; network, malformed-response, and
217
- unknown server failures can leave the reservation outcome uncertain.
218
- API errors retain their status, correlation ID, and Retry-After. Both admission
219
- and session requests reject HTTP redirects.
323
+ ### Local development
324
+
325
+ The SDK accepts HTTP API URLs, browser origins, callbacks, and storage URLs on
326
+ `localhost` and `127.0.0.1`. Remote hosts require HTTPS. Register each origin
327
+ and callback with its exact scheme, host, port, and path. These two local hosts
328
+ are distinct origins; cookies and browser storage are not shared between them.
329
+
330
+ For local passkeys, serve the authentication page on `localhost` and use
331
+ `localhost` as its relying-party ID. An IP address cannot be a passkey
332
+ relying-party ID. Keep API keys and member sessions in your BFF, including
333
+ during local development.
220
334
 
221
335
  ### Stores and callback recovery
222
336
 
@@ -225,6 +339,26 @@ proofs, and manages session refresh and logout. Implement its session,
225
339
  authorization-transaction, and direct proof-exchange store contracts in your
226
340
  own database. It does not include a web framework or database adapter.
227
341
 
342
+ `runExclusive` is an exclusivity boundary, not an all-or-nothing SQL
343
+ transaction. Every awaited `put`, `replace` and `delete` must commit before
344
+ returning, and remain committed if later callback work throws. Wrapping the
345
+ whole callback in a rollback transaction can erase a staged proof after its
346
+ one-time provider code was consumed. The same rule protects refresh-attempt
347
+ checkpoints. Reconcile an uncertain write acknowledgement using the exact
348
+ record and attempt identity, rather than starting a new operation.
349
+
350
+ The package includes [a PostgreSQL checkpoint-store example](examples/postgres-checkpoint-store.mjs)
351
+ and its [application-owned table definition](examples/postgres-checkpoints.sql).
352
+ Install `pg` in your backend and apply the table definition through your own
353
+ migration process. Instantiate separate stores with namespaces such as
354
+ `authorization`, `sessions` and `exchange`, one shared pool and an existing
355
+ 32-byte application encryption key. The example uses session advisory locks
356
+ across replicas, independent autocommit checkpoints, authenticated encryption
357
+ bound to namespace/reference, exact replacement without upsert, and connection
358
+ discard when lock release is uncertain. Do not use a transaction-pooling proxy
359
+ for session locks. Own key rotation, pool deadlines and expired-record cleanup
360
+ in your application; do not log records or encryption material.
361
+
228
362
  Authorization, Account Center, and action transactions expire within ten
229
363
  minutes of starting the request, or at the server's expiry if sooner. Late,
230
364
  expired, or excessively long-lived responses are rejected. Keep your BFF's
@@ -255,8 +389,60 @@ To exchange a proof without a browser callback, call `establishSession` with an
255
389
  `exchangeId`. Persist that ID before the first attempt and reuse it on retries.
256
390
  The store serializes attempts and preserves the exchange and session references.
257
391
 
392
+ ### Enroll an external identity-provider member
393
+
394
+ For a registered OIDC connection, the confidential backend can call
395
+ `memberAuth.enrollExternalMember({ externalSub, applicationConfigVersion,
396
+ idempotencyKey })`. Use the exact opaque subject from a fully verified provider
397
+ proof, the final read-back application configuration version, and one persisted
398
+ operation key. Never link by email. The API derives issuer namespace, tenant,
399
+ workspace and application from the registered connection and its bound
400
+ `member_auth` API principal. The header selector and body selector must match.
401
+ An existing issuer/subject membership is returned without replacing its identity,
402
+ status or wallet bindings. A held or closed member remains held or closed.
403
+
404
+ Enrollment creates or finds a membership, not an authenticated session or wallet.
405
+ The normal nonce-bound provider-proof exchange remains required. For callback
406
+ flows use `completeAuthorizationCallback`'s optional `ensureMemberEnrollment`
407
+ hook. It runs after the one-time provider proof is durably staged, with a stable
408
+ `idempotencyKey` preserved across retries. Verify the staged proof's signature,
409
+ issuer, audience, algorithm, expiry and nonce, then call `enrollExternalMember`
410
+ with its exact `sub`. Return that result from the hook. The helper checks that
411
+ the resulting authenticated session resolves to the enrolled account holder.
412
+ Do not put a fallible enrollment call inside `exchangeProviderCode`, before
413
+ the provider result has been staged. A version conflict requires reviewing the
414
+ changed registration and starting a new authorization flow, not blind retries.
415
+
416
+ ```ts
417
+ const completion = await memberAuth.completeAuthorizationCallback({
418
+ ...callbackInput,
419
+ ensureMemberEnrollment: async ({ proofToken, idempotencyKey }) => {
420
+ // This application function performs full JOSE and exact nonce validation.
421
+ const verified = await verifyRegisteredProviderProof(proofToken);
422
+ return memberAuth.enrollExternalMember({
423
+ externalSub: verified.sub,
424
+ applicationConfigVersion: registration.config_version,
425
+ idempotencyKey,
426
+ });
427
+ },
428
+ });
429
+ ```
430
+
431
+ The verifier and `registration` are application prerequisites in this example,
432
+ not SDK-provided provider validation or discovery functions. The public endpoint
433
+ is `POST /v1/member-auth/enrollments`; it accepts no caller-selected account
434
+ holder, tenant, issuer namespace, email or permissions. Enrollment alone never
435
+ qualifies fresh action assurance, signing authority or settlement.
436
+
258
437
  ### Account Center and action callbacks
259
438
 
439
+ Direct Account Center starts accept `security`, `sessions`, or
440
+ `wallet_readiness`. Resource-bound actions start through the member action
441
+ flow; their shared callback result may contain the `action` intent. Refresh
442
+ preserves the session ID, account holder, and provider subject. A changed
443
+ identity is rejected before replacing stored credentials, including when
444
+ separate session validation is disabled for an immediate business request.
445
+
260
446
  Account Center accepts a same-origin `applicationReturnUri` and preserves it
261
447
  through successful callback recovery. Member actions separately accept
262
448
  `applicationReviewUri` for cancellation or expiry and `applicationReturnUri`
@@ -344,6 +530,10 @@ Business requests use `no-store` and reject redirects so credentials cannot
344
530
  follow a redirect. Network failures preserve the application session. Reuse the
345
531
  original idempotency key when reconciling an uncertain write.
346
532
 
533
+ `resolved.resources.self.profile()` returns the current member's profile,
534
+ including email and name. These fields are display metadata, not authentication
535
+ proof. Read the profile when displaying it instead of caching it in the session.
536
+
347
537
  `resolved.resources.self.verification()` returns the member's verification
348
538
  requirements and sessions through the public self-verification operation.
349
539
  `resolved.resources.self.uploadAvatar(image)` performs presign, object upload,
@@ -351,7 +541,7 @@ confirmation, and refreshed avatar lookup. Pass a nonempty PNG, JPEG, WebP, or G
351
541
  `Blob` of at most 5 MiB. Storage receives only the image bytes and their content
352
542
  headers, never bearer credentials, request signatures, member context, or cookies.
353
543
  The helper rejects redirects, expired capabilities, URL credentials, and non-HTTPS
354
- storage URLs (localhost HTTP is permitted for local development). It does not
544
+ storage URLs (HTTP on `localhost` or `127.0.0.1` is permitted for local development). It does not
355
545
  retry an upload. `XKOVAUploadError` identifies the object-storage stage without
356
546
  exposing the signed URL; API failures retain `XKOVAApiError` metadata.
357
547
 
@@ -371,7 +561,44 @@ Durable application cookies use the host-only `__Host-` prefix, `Secure`, `HttpO
371
561
 
372
562
  The publishable key is a non-secret application registration identifier. It grants no member or tenant authority by itself. The registered application pins tenant, workspace, environment, provider kind, issuer, audience, origins, redirects, and session policy, and must also match the authenticated workspace principal.
373
563
 
374
- ## Cancellation and deadlines
564
+ ### Recover an existing member payment
565
+
566
+ Read recovery state through the resolved member resources:
567
+
568
+ ```ts
569
+ const recovery = await resolved.resources.payments.recovery(paymentId);
570
+ // Call only after the member confirms cancellation in your app.
571
+ if (recovery.can_cancel) {
572
+ await resolved.resources.payments.cancelForMember(paymentId);
573
+ }
574
+ ```
575
+
576
+ The API permits reads by the sender or recipient. Only the sender can cancel
577
+ or continue. The API principal needs `payment.read` and `payment.cancel`
578
+ permissions for these operations. Your BFF must validate the session, exact
579
+ Origin, and CSRF token before cancellation. Cancellation does not require a
580
+ passkey because it sends no value.
581
+
582
+ When `can_continue` is true, use `beginMemberAction()` with
583
+ `resourceType: 'payment'`, the existing `resourceId`, and `action: 'sign'`.
584
+ Complete fresh authorization through the registered provider. Keep the original
585
+ amount, recipient, fees, and deadline. Do not create a second payment or reuse
586
+ an expired signing credential. Recovery uses the payment ID, so a new valid
587
+ session for the same member can recover it without the original form draft.
588
+
589
+ `approval_expired` means the signing window has closed. It remains cancellable
590
+ until a signature has been accepted. After acceptance, `processing` disables
591
+ both actions. `cancelled`, `completed`, and `failed` are separate outcomes;
592
+ retain all three in history. These actions apply to payments; escrow
593
+ cancellation has its own authorization and settlement rules.
594
+
595
+ Availability can change between a read and a click. After a conflict or an
596
+ uncertain cancellation response, read recovery state again. Repeating an
597
+ already completed member cancellation returns the cancelled payment. Aborting
598
+ an HTTP request or cancelling an authorization ceremony does not cancel the
599
+ payment.
600
+
601
+ ## Request cancellation and deadlines
375
602
 
376
603
  Set `timeoutMs` on the client for a default request deadline. Mutation options and workflow polling also accept an `AbortSignal`:
377
604
 
@@ -386,6 +613,33 @@ await xkova.payments.cancel('pay_...', {
386
613
 
387
614
  The SDK does not automatically retry writes. Use `withRetry` with a stable idempotency key when retry behavior is appropriate for your application.
388
615
 
616
+ ## Product enrollment
617
+
618
+ After a member accepts your displayed terms, call
619
+ `resources.self.acceptProductEnrollment(product, { terms_version })` from the
620
+ BFF. Select the product and terms version on your server. Read the saved result
621
+ with `resources.self.productEnrollment(product)` when the member returns.
622
+ Acceptance does not require an `Idempotency-Key` header. Repeating the same
623
+ acceptance preserves its timestamp. Changed terms or credit parameters with the
624
+ same product are rejected.
625
+
626
+ Sandbox applications can include `sandbox_credit: { token_deployment_id,
627
+ amount }` to issue a test-token welcome credit. Use an active dUSDC deployment.
628
+ The credit is issued once per member, workspace, and product, across application
629
+ registrations. The daily workspace budget is 1000 dUSDC. Keep amounts and token
630
+ selection in the BFF, and give each product a stable identifier.
631
+
632
+ For Hosted Auth, set `require_passkey: true` to hold activation and the credit
633
+ until the member has an active passkey and has acknowledged recovery codes.
634
+ `setup_required` means terms are saved and security setup remains incomplete.
635
+ Open Account Center with the `security` intent, then read the enrollment again
636
+ on return. The setup requirement is fixed when the enrollment is accepted.
637
+
638
+ Poll the enrollment after acceptance. `opening` means delivery is pending;
639
+ `active` means the credit has a successful receipt and an indexed balance.
640
+ `requires_review` needs operator investigation. Do not create another product
641
+ identifier to retry an uncertain credit. Credits do not debit bank accounts.
642
+
389
643
  ## Errors
390
644
 
391
645
  `XKOVAApiError.retryAfter` preserves the upstream `Retry-After` header when
@@ -405,6 +659,40 @@ try {
405
659
  }
406
660
  ```
407
661
 
662
+ ## Treasury vaults and transfer proposals
663
+
664
+ Use `client.treasury` from a trusted backend with the workspace's explicitly
665
+ granted treasury scopes and roles. Discover the chain and eligible assets before
666
+ creating a vault or proposal. An existing same-chain vault retains its real
667
+ owner set and threshold.
668
+
669
+ ```ts
670
+ import { isHeldApproval } from '@xkova/sdk';
671
+
672
+ const vaults = await xkova.treasury.listWallets();
673
+ const proposal = await xkova.treasury.getTransfer('trf_...');
674
+ const counterparties = await xkova.treasury.listCounterparties({ limit: 20 });
675
+ ```
676
+
677
+ Vault and counterparty setup can return a governance hold. Check `isHeldApproval`
678
+ before reading entity fields. Keep the original request and idempotency key;
679
+ resume through normal policy after independently eligible approvers complete the
680
+ required approval. The SDK does not approve, sign or retry a held operation.
681
+
682
+ `draftTransfer` creates a proposal. `getTransfer` reads its frozen signing context
683
+ and current quorum. Each eligible owner produces their own signature over that
684
+ exact Safe transaction. `submitTransferSignature` submits an existing signature;
685
+ it does not create a wallet or sign on anyone's behalf. `executeTransfer` retains
686
+ current role, signer, nonce, quorum and policy checks. A returned relay result is
687
+ not settlement; read the proposal until its actual confirmed or failed outcome.
688
+ After a timeout, reconcile the existing proposal before creating another one.
689
+
690
+ The API key's attributed staff ID is audit metadata, not a per-human session or
691
+ permission to bootstrap a staff wallet. This namespace does not expose Console
692
+ credentials, staff-wallet bootstrap credentials, or raw private-key material.
693
+ The supported workforce authentication and independent signer ceremonies remain
694
+ separate requirements for a complete customer treasury application.
695
+
408
696
  ## Webhooks and generated types
409
697
 
410
698
  ```ts
@@ -412,7 +700,19 @@ import { verifyWebhookSignature } from '@xkova/sdk/webhook';
412
700
  import type { components, paths } from '@xkova/sdk/types';
413
701
  ```
414
702
 
415
- Pass the raw request body to `verifyWebhookSignature`. The `types` subpath contains only the customer operations included in this SDK release.
703
+ Pass the raw request body to `verifyWebhookSignature`. Import request and response types from `@xkova/sdk/types`.
704
+
705
+ Each `v1` signature must contain exactly 64 lowercase hexadecimal characters.
706
+ Malformed candidates are rejected without truncation; valid multiple-signature
707
+ rotation headers remain supported.
708
+
709
+ `tokenDeploy` submits once and observes the returned token until it is active.
710
+ Deployment operations cannot be read through the generic operation endpoint.
711
+ `tokenMint` waits for its exact mint operation to be confirmed before returning
712
+ the token. An already-active token does not establish mint success.
713
+ Cancellation, pending exhaustion, a failed operation, or an uncertain response
714
+ never causes these helpers to submit another mutation. Reconcile the retained
715
+ token or operation before deciding whether to retry explicitly.
416
716
 
417
717
  The package also exposes `@xkova/sdk/rwa-verify` for offline RWA transparency proof verification and `@xkova/sdk/abi` for the documented customer contract ABIs.
418
718
 
@@ -432,14 +732,6 @@ idempotency, and settlement. It links the public customer OpenAPI and expanded
432
732
  documentation. Installed declarations determine the methods available in your
433
733
  version; live documentation may describe a newer release.
434
734
 
435
- ## Thirdweb and dependencies
436
-
437
- The only direct runtime dependency is `viem`, used for offline RWA signature
438
- verification. This SDK does not import Thirdweb. The optional `@xkova/browser`
439
- browser companion has no runtime dependencies. XKOVA manages wallet signing,
440
- and API provider metadata may name Thirdweb. You do not need to install its SDK
441
- or obtain Thirdweb credentials.
442
-
443
735
  ## Contributing
444
736
 
445
737
  Run `pnpm check` from the source repository root before committing. The
package/dist/abi.d.ts CHANGED
@@ -336,6 +336,14 @@ export declare const erc20XGaslessAbi: readonly [{
336
336
  readonly name: "";
337
337
  readonly type: "string";
338
338
  readonly internalType: "string";
339
+ }, {
340
+ readonly name: "";
341
+ readonly type: "uint8";
342
+ readonly internalType: "uint8";
343
+ }, {
344
+ readonly name: "";
345
+ readonly type: "address";
346
+ readonly internalType: "address";
339
347
  }, {
340
348
  readonly name: "";
341
349
  readonly type: "address";
@@ -362,6 +370,10 @@ export declare const erc20XGaslessAbi: readonly [{
362
370
  readonly name: "_symbol";
363
371
  readonly type: "string";
364
372
  readonly internalType: "string";
373
+ }, {
374
+ readonly name: "decimals_";
375
+ readonly type: "uint8";
376
+ readonly internalType: "uint8";
365
377
  }, {
366
378
  readonly name: "defaultAdmin";
367
379
  readonly type: "address";
@@ -370,6 +382,10 @@ export declare const erc20XGaslessAbi: readonly [{
370
382
  readonly name: "minter";
371
383
  readonly type: "address";
372
384
  readonly internalType: "address";
385
+ }, {
386
+ readonly name: "burner";
387
+ readonly type: "address";
388
+ readonly internalType: "address";
373
389
  }, {
374
390
  readonly name: "pauser";
375
391
  readonly type: "address";
@@ -1062,6 +1078,10 @@ export declare const erc20XGaslessAbi: readonly [{
1062
1078
  readonly type: "error";
1063
1079
  readonly name: "InvalidAddress";
1064
1080
  readonly inputs: readonly [];
1081
+ }, {
1082
+ readonly type: "error";
1083
+ readonly name: "InvalidDecimals";
1084
+ readonly inputs: readonly [];
1065
1085
  }, {
1066
1086
  readonly type: "error";
1067
1087
  readonly name: "InvalidImplementation";
@@ -5482,6 +5502,14 @@ export declare const tokenizationAbis: {
5482
5502
  readonly name: "";
5483
5503
  readonly type: "string";
5484
5504
  readonly internalType: "string";
5505
+ }, {
5506
+ readonly name: "";
5507
+ readonly type: "uint8";
5508
+ readonly internalType: "uint8";
5509
+ }, {
5510
+ readonly name: "";
5511
+ readonly type: "address";
5512
+ readonly internalType: "address";
5485
5513
  }, {
5486
5514
  readonly name: "";
5487
5515
  readonly type: "address";
@@ -5508,6 +5536,10 @@ export declare const tokenizationAbis: {
5508
5536
  readonly name: "_symbol";
5509
5537
  readonly type: "string";
5510
5538
  readonly internalType: "string";
5539
+ }, {
5540
+ readonly name: "decimals_";
5541
+ readonly type: "uint8";
5542
+ readonly internalType: "uint8";
5511
5543
  }, {
5512
5544
  readonly name: "defaultAdmin";
5513
5545
  readonly type: "address";
@@ -5516,6 +5548,10 @@ export declare const tokenizationAbis: {
5516
5548
  readonly name: "minter";
5517
5549
  readonly type: "address";
5518
5550
  readonly internalType: "address";
5551
+ }, {
5552
+ readonly name: "burner";
5553
+ readonly type: "address";
5554
+ readonly internalType: "address";
5519
5555
  }, {
5520
5556
  readonly name: "pauser";
5521
5557
  readonly type: "address";
@@ -6208,6 +6244,10 @@ export declare const tokenizationAbis: {
6208
6244
  readonly type: "error";
6209
6245
  readonly name: "InvalidAddress";
6210
6246
  readonly inputs: readonly [];
6247
+ }, {
6248
+ readonly type: "error";
6249
+ readonly name: "InvalidDecimals";
6250
+ readonly inputs: readonly [];
6211
6251
  }, {
6212
6252
  readonly type: "error";
6213
6253
  readonly name: "InvalidImplementation";
package/dist/abi.js CHANGED
@@ -443,6 +443,16 @@ export const erc20XGaslessAbi = [
443
443
  "type": "string",
444
444
  "internalType": "string"
445
445
  },
446
+ {
447
+ "name": "",
448
+ "type": "uint8",
449
+ "internalType": "uint8"
450
+ },
451
+ {
452
+ "name": "",
453
+ "type": "address",
454
+ "internalType": "address"
455
+ },
446
456
  {
447
457
  "name": "",
448
458
  "type": "address",
@@ -476,6 +486,11 @@ export const erc20XGaslessAbi = [
476
486
  "type": "string",
477
487
  "internalType": "string"
478
488
  },
489
+ {
490
+ "name": "decimals_",
491
+ "type": "uint8",
492
+ "internalType": "uint8"
493
+ },
479
494
  {
480
495
  "name": "defaultAdmin",
481
496
  "type": "address",
@@ -486,6 +501,11 @@ export const erc20XGaslessAbi = [
486
501
  "type": "address",
487
502
  "internalType": "address"
488
503
  },
504
+ {
505
+ "name": "burner",
506
+ "type": "address",
507
+ "internalType": "address"
508
+ },
489
509
  {
490
510
  "name": "pauser",
491
511
  "type": "address",
@@ -1376,6 +1396,11 @@ export const erc20XGaslessAbi = [
1376
1396
  "name": "InvalidAddress",
1377
1397
  "inputs": []
1378
1398
  },
1399
+ {
1400
+ "type": "error",
1401
+ "name": "InvalidDecimals",
1402
+ "inputs": []
1403
+ },
1379
1404
  {
1380
1405
  "type": "error",
1381
1406
  "name": "InvalidImplementation",
package/dist/client.d.ts CHANGED
@@ -13,6 +13,7 @@ import { RampsResource } from './resources/ramps.js';
13
13
  import { RwaResource } from './resources/rwa.js';
14
14
  import { TenantResource } from './resources/tenant.js';
15
15
  import { TokenizationResource } from './resources/tokenization.js';
16
+ import { TreasuryResource } from './resources/treasury.js';
16
17
  import { TransactionsResource } from './resources/transactions.js';
17
18
  import { WalletsResource } from './resources/wallets.js';
18
19
  import { WebhooksResource } from './resources/webhooks.js';
@@ -47,6 +48,7 @@ export interface XKOVAMutationOptions extends XKOVARequestControl {
47
48
  export declare class XKOVAClient {
48
49
  private readonly config;
49
50
  private readonly memberContext?;
51
+ private readonly workforceContext?;
50
52
  private readonly apiBaseUrl;
51
53
  private readonly fetchImpl;
52
54
  private constructor();
@@ -65,6 +67,8 @@ export declare class XKOVAClient {
65
67
  get rwa(): RwaResource;
66
68
  get tenant(): TenantResource;
67
69
  get tokenization(): TokenizationResource;
70
+ /** Tenant treasury operations retain server-side roles, governance and signer checks. */
71
+ get treasury(): TreasuryResource;
68
72
  get transactions(): TransactionsResource;
69
73
  get wallets(): WalletsResource;
70
74
  get webhooks(): WebhooksResource;