@xkova/sdk 0.1.0-alpha.1

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 (76) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +453 -0
  3. package/dist/abi.d.ts +10288 -0
  4. package/dist/abi.js +6645 -0
  5. package/dist/client.d.ts +80 -0
  6. package/dist/client.js +251 -0
  7. package/dist/cursor.d.ts +21 -0
  8. package/dist/cursor.js +28 -0
  9. package/dist/errors.d.ts +31 -0
  10. package/dist/errors.js +63 -0
  11. package/dist/generated/types.d.ts +13371 -0
  12. package/dist/generated/types.js +3 -0
  13. package/dist/idempotency.d.ts +25 -0
  14. package/dist/idempotency.js +46 -0
  15. package/dist/index.d.ts +11 -0
  16. package/dist/index.js +8 -0
  17. package/dist/member-action-intents.d.ts +72 -0
  18. package/dist/member-action-intents.js +181 -0
  19. package/dist/member-bff.d.ts +535 -0
  20. package/dist/member-bff.js +1594 -0
  21. package/dist/member-resources.d.ts +203 -0
  22. package/dist/member-resources.js +56 -0
  23. package/dist/request-signing.d.ts +23 -0
  24. package/dist/request-signing.js +112 -0
  25. package/dist/resources/account-holders.d.ts +295 -0
  26. package/dist/resources/account-holders.js +166 -0
  27. package/dist/resources/base.d.ts +47 -0
  28. package/dist/resources/base.js +25 -0
  29. package/dist/resources/branding.d.ts +154 -0
  30. package/dist/resources/branding.js +34 -0
  31. package/dist/resources/chains.d.ts +6 -0
  32. package/dist/resources/chains.js +6 -0
  33. package/dist/resources/contacts.d.ts +55 -0
  34. package/dist/resources/contacts.js +22 -0
  35. package/dist/resources/escrows.d.ts +45 -0
  36. package/dist/resources/escrows.js +18 -0
  37. package/dist/resources/fee-schedules.d.ts +40 -0
  38. package/dist/resources/fee-schedules.js +15 -0
  39. package/dist/resources/index.d.ts +21 -0
  40. package/dist/resources/index.js +21 -0
  41. package/dist/resources/integration-gateways.d.ts +114 -0
  42. package/dist/resources/integration-gateways.js +27 -0
  43. package/dist/resources/onboarding.d.ts +18 -0
  44. package/dist/resources/onboarding.js +9 -0
  45. package/dist/resources/payment-requests.d.ts +115 -0
  46. package/dist/resources/payment-requests.js +27 -0
  47. package/dist/resources/payments.d.ts +182 -0
  48. package/dist/resources/payments.js +33 -0
  49. package/dist/resources/ramps.d.ts +163 -0
  50. package/dist/resources/ramps.js +44 -0
  51. package/dist/resources/rwa.d.ts +397 -0
  52. package/dist/resources/rwa.js +150 -0
  53. package/dist/resources/tenant.d.ts +136 -0
  54. package/dist/resources/tenant.js +42 -0
  55. package/dist/resources/tokenization.d.ts +394 -0
  56. package/dist/resources/tokenization.js +126 -0
  57. package/dist/resources/transactions.d.ts +8 -0
  58. package/dist/resources/transactions.js +6 -0
  59. package/dist/resources/wallets.d.ts +56 -0
  60. package/dist/resources/wallets.js +21 -0
  61. package/dist/resources/webhooks.d.ts +115 -0
  62. package/dist/resources/webhooks.js +43 -0
  63. package/dist/resources/workflows.d.ts +44 -0
  64. package/dist/resources/workflows.js +70 -0
  65. package/dist/resources/workspace-tokens.d.ts +6 -0
  66. package/dist/resources/workspace-tokens.js +6 -0
  67. package/dist/resources/workspaces.d.ts +25 -0
  68. package/dist/resources/workspaces.js +12 -0
  69. package/dist/retry.d.ts +21 -0
  70. package/dist/retry.js +44 -0
  71. package/dist/rwa-verify.d.ts +50 -0
  72. package/dist/rwa-verify.js +159 -0
  73. package/dist/webhook.d.ts +24 -0
  74. package/dist/webhook.js +56 -0
  75. package/llms.txt +84 -0
  76. package/package.json +62 -0
@@ -0,0 +1,295 @@
1
+ import { Resource, type ReqBody, type Query } from './base.js';
2
+ import type { XKOVAClient, XKOVAMutationOptions, XKOVARequestControl } from '../client.js';
3
+ /** Trusted BFF context for operations scoped to the current member. */
4
+ export interface XKOVAMemberSessionContext {
5
+ /** Opaque XKOVA session UUID stored by the customer BFF. */
6
+ memberSessionId: string;
7
+ /** Non-secret application registration identifier stored with the session by the BFF. */
8
+ memberAuthPublishableKey: string;
9
+ }
10
+ export declare class AccountHoldersResource extends Resource {
11
+ private readonly storageFetch;
12
+ constructor(client: XKOVAClient, storageFetch?: typeof fetch);
13
+ list(query?: Query<'listAccountHolders'>): Promise<{
14
+ data: unknown[];
15
+ next_cursor: string | null;
16
+ has_more: boolean;
17
+ } & {
18
+ data?: import("../generated/types.js").components["schemas"]["AccountHolder"][];
19
+ }>;
20
+ create(body: ReqBody<'createAccountHolder'>, opts?: XKOVAMutationOptions): Promise<{
21
+ id: import("../generated/types.js").components["schemas"]["AccountHolderId"];
22
+ tenant_id?: string;
23
+ state: "active" | "held" | "closed" | "closed_uncooperative" | "provisioning_failed";
24
+ state_reason?: string | null;
25
+ state_changed_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
26
+ tier: "tier_1" | "tier_2";
27
+ tier_2_uplift_status?: "not_requested" | "pending" | "passed" | "failed";
28
+ first_use_completed: boolean;
29
+ cip_payload?: {
30
+ name_hash?: string;
31
+ dob_hash?: string;
32
+ id_hash?: string;
33
+ address_hash?: string;
34
+ } | null;
35
+ cip_accepted_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
36
+ merchant_role_state?: "none" | "pending_review" | "approved" | "rejected" | "revoked";
37
+ auto_save_contacts?: boolean;
38
+ created_at: import("../generated/types.js").components["schemas"]["TimestampUtc"];
39
+ updated_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"];
40
+ email?: string | null;
41
+ first_name?: string | null;
42
+ last_name?: string | null;
43
+ phone?: string | null;
44
+ avatar_url?: string | null;
45
+ }>;
46
+ retrieve(id: string, query?: Query<'getAccountHolder'>): Promise<{
47
+ id: import("../generated/types.js").components["schemas"]["AccountHolderId"];
48
+ tenant_id?: string;
49
+ state: "active" | "held" | "closed" | "closed_uncooperative" | "provisioning_failed";
50
+ state_reason?: string | null;
51
+ state_changed_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
52
+ tier: "tier_1" | "tier_2";
53
+ tier_2_uplift_status?: "not_requested" | "pending" | "passed" | "failed";
54
+ first_use_completed: boolean;
55
+ cip_payload?: {
56
+ name_hash?: string;
57
+ dob_hash?: string;
58
+ id_hash?: string;
59
+ address_hash?: string;
60
+ } | null;
61
+ cip_accepted_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
62
+ merchant_role_state?: "none" | "pending_review" | "approved" | "rejected" | "revoked";
63
+ auto_save_contacts?: boolean;
64
+ created_at: import("../generated/types.js").components["schemas"]["TimestampUtc"];
65
+ updated_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"];
66
+ email?: string | null;
67
+ first_name?: string | null;
68
+ last_name?: string | null;
69
+ phone?: string | null;
70
+ avatar_url?: string | null;
71
+ }>;
72
+ update(id: string, body: ReqBody<'updateAccountHolder'>, opts?: XKOVAMutationOptions): Promise<{
73
+ id: import("../generated/types.js").components["schemas"]["AccountHolderId"];
74
+ tenant_id?: string;
75
+ state: "active" | "held" | "closed" | "closed_uncooperative" | "provisioning_failed";
76
+ state_reason?: string | null;
77
+ state_changed_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
78
+ tier: "tier_1" | "tier_2";
79
+ tier_2_uplift_status?: "not_requested" | "pending" | "passed" | "failed";
80
+ first_use_completed: boolean;
81
+ cip_payload?: {
82
+ name_hash?: string;
83
+ dob_hash?: string;
84
+ id_hash?: string;
85
+ address_hash?: string;
86
+ } | null;
87
+ cip_accepted_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
88
+ merchant_role_state?: "none" | "pending_review" | "approved" | "rejected" | "revoked";
89
+ auto_save_contacts?: boolean;
90
+ created_at: import("../generated/types.js").components["schemas"]["TimestampUtc"];
91
+ updated_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"];
92
+ email?: string | null;
93
+ first_name?: string | null;
94
+ last_name?: string | null;
95
+ phone?: string | null;
96
+ avatar_url?: string | null;
97
+ }>;
98
+ history(id: string, query?: Query<'listAccountHolderHistory'>): Promise<{
99
+ data: import("../generated/types.js").components["schemas"]["WalletTransactionSummary"][];
100
+ next_cursor?: string | null;
101
+ has_more: boolean;
102
+ }>;
103
+ selfVerification(context: XKOVAMemberSessionContext, control?: XKOVARequestControl): Promise<{
104
+ required: boolean;
105
+ status: string;
106
+ verified_via: string | null;
107
+ verified_at: string | null;
108
+ verification_expires_at: string | null;
109
+ required_kinds: ("kyc" | "kyb")[];
110
+ sessions: {
111
+ kind: "kyc" | "kyb";
112
+ status: string;
113
+ vendor: string | null;
114
+ vendor_detail_url: string | null;
115
+ initiated_at: string | null;
116
+ completed_at: string | null;
117
+ expires_at: string | null;
118
+ }[];
119
+ verification_url: string | null;
120
+ }>;
121
+ selfBalance(context: XKOVAMemberSessionContext, control?: XKOVARequestControl): Promise<{
122
+ balances: import("../generated/types.js").components["schemas"]["AccountHolderSelfBalanceEntry"][];
123
+ }>;
124
+ listSelfWallets(context: XKOVAMemberSessionContext, control?: XKOVARequestControl): Promise<{
125
+ data: import("../generated/types.js").components["schemas"]["Wallet"][];
126
+ }>;
127
+ selfWalletReadiness(context: XKOVAMemberSessionContext, control?: XKOVARequestControl): Promise<{
128
+ status: "not_registered" | "provisioning" | "ready";
129
+ wallets: import("../generated/types.js").components["schemas"]["Wallet"][];
130
+ }>;
131
+ ensureSelfWalletProvisioning(context: XKOVAMemberSessionContext, opts?: XKOVAMutationOptions): Promise<{
132
+ status: "pending" | "processing" | "reconciling" | "retry" | "ready" | "paused" | "manual_review" | "cancelled";
133
+ }>;
134
+ selfBankBalance(context: XKOVAMemberSessionContext, control?: XKOVARequestControl): Promise<{
135
+ currency: "USD";
136
+ available_balance: import("../generated/types.js").components["schemas"]["Money"];
137
+ current_balance: import("../generated/types.js").components["schemas"]["Money"];
138
+ as_of: import("../generated/types.js").components["schemas"]["TimestampUtc"];
139
+ }>;
140
+ selfSandboxBankingContext(context: XKOVAMemberSessionContext, control?: XKOVARequestControl): Promise<{
141
+ account_holder_id: import("../generated/types.js").components["schemas"]["AccountHolderId"];
142
+ savings_bank_account_id: string;
143
+ checking_bank_account_id: string;
144
+ pool_bank_account_id: string;
145
+ settlement_bank_account_id: string;
146
+ destination_account: import("../generated/types.js").components["schemas"]["CuPayoutAccountRef"];
147
+ }>;
148
+ /** Advisory, uncached setup facts from the existing exact-session read. */
149
+ selfActionReadiness(context: XKOVAMemberSessionContext & {
150
+ accountHolderId: string;
151
+ }, control?: XKOVARequestControl): Promise<{
152
+ authorization_method: "hosted_passkey" | "external_oidc";
153
+ setup_status: "passkey_required" | "recovery_acknowledgement_required" | "recovery_required" | "ready" | "externally_managed";
154
+ action_authorization_enabled: boolean;
155
+ requires_fresh_proof: true;
156
+ provider_status: "not_checked";
157
+ }>;
158
+ listSelfBankTransactions(context: XKOVAMemberSessionContext, query?: Query<'listAccountHolderSelfBankTransactions'>, control?: XKOVARequestControl): Promise<{
159
+ data: {
160
+ transfer_ref: string;
161
+ amount: string;
162
+ currency: string;
163
+ status: "pending" | "posted" | "reversed" | "rejected";
164
+ from_account: "savings" | "checking" | "other";
165
+ to_account: "savings" | "checking" | "other";
166
+ memo?: string | null;
167
+ occurred_at: string;
168
+ }[];
169
+ }>;
170
+ createSelfBankTransfer(context: XKOVAMemberSessionContext, body: ReqBody<'createAccountHolderSelfBankTransfer'>, opts?: XKOVAMutationOptions): Promise<{
171
+ transfer_ref: string;
172
+ status: "pending" | "posted" | "reversed" | "rejected";
173
+ as_of: string;
174
+ }>;
175
+ selfCheckingBalance(context: XKOVAMemberSessionContext, control?: XKOVARequestControl): Promise<{
176
+ currency: "USD";
177
+ available_balance: import("../generated/types.js").components["schemas"]["Money"];
178
+ current_balance: import("../generated/types.js").components["schemas"]["Money"];
179
+ as_of: import("../generated/types.js").components["schemas"]["TimestampUtc"];
180
+ }>;
181
+ selfConsentState(context: XKOVAMemberSessionContext, control?: XKOVARequestControl): Promise<{
182
+ account_holder_id: import("../generated/types.js").components["schemas"]["AccountHolderId"];
183
+ current_policies: import("../generated/types.js").components["schemas"]["CurrentPolicy"][];
184
+ accepted: import("../generated/types.js").components["schemas"]["Consent"][];
185
+ missing_consents: import("../generated/types.js").components["schemas"]["MissingConsent"][];
186
+ consents_current: boolean;
187
+ first_use_completed: boolean;
188
+ }>;
189
+ acceptSelfConsents(context: XKOVAMemberSessionContext, body: ReqBody<'acceptAccountHolderConsents'>, opts?: XKOVAMutationOptions): Promise<{
190
+ account_holder_id: import("../generated/types.js").components["schemas"]["AccountHolderId"];
191
+ current_policies: import("../generated/types.js").components["schemas"]["CurrentPolicy"][];
192
+ accepted: import("../generated/types.js").components["schemas"]["Consent"][];
193
+ missing_consents: import("../generated/types.js").components["schemas"]["MissingConsent"][];
194
+ consents_current: boolean;
195
+ first_use_completed: boolean;
196
+ }>;
197
+ requestSelfDataExport(context: XKOVAMemberSessionContext, opts?: XKOVAMutationOptions): Promise<{
198
+ id: import("../generated/types.js").components["schemas"]["DataExportId"];
199
+ account_holder_id: import("../generated/types.js").components["schemas"]["AccountHolderId"];
200
+ state: "queued" | "processing" | "ready" | "expired" | "failed";
201
+ signed_url: string | null;
202
+ url_expires_at: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
203
+ requested_at: import("../generated/types.js").components["schemas"]["TimestampUtc"];
204
+ started_at: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
205
+ completed_at: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
206
+ failure_reason: string | null;
207
+ }>;
208
+ selfDataExport(context: XKOVAMemberSessionContext, id: string, control?: XKOVARequestControl): Promise<{
209
+ id: import("../generated/types.js").components["schemas"]["DataExportId"];
210
+ account_holder_id: import("../generated/types.js").components["schemas"]["AccountHolderId"];
211
+ state: "queued" | "processing" | "ready" | "expired" | "failed";
212
+ signed_url: string | null;
213
+ url_expires_at: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
214
+ requested_at: import("../generated/types.js").components["schemas"]["TimestampUtc"];
215
+ started_at: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
216
+ completed_at: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
217
+ failure_reason: string | null;
218
+ }>;
219
+ listSelfTransactions(context: XKOVAMemberSessionContext, query?: Query<'listAccountHolderSelfTransactions'>, control?: XKOVARequestControl): Promise<{
220
+ data: import("../generated/types.js").components["schemas"]["AccountHolderSelfTransaction"][];
221
+ next_cursor: string | null;
222
+ has_more: boolean;
223
+ }>;
224
+ /**
225
+ * Server-side avatar upload using the platform's presign/upload/confirm
226
+ * contract. Only image bytes go to object storage. API bearer, signatures,
227
+ * member context and cookies never follow the presigned URL or a redirect.
228
+ */
229
+ uploadAvatar(id: string, image: Blob, control?: XKOVARequestControl): Promise<{
230
+ url: string | null;
231
+ }>;
232
+ avatarUrl(id: string): Promise<{
233
+ url: string | null;
234
+ }>;
235
+ deleteAvatar(id: string, opts?: XKOVAMutationOptions): Promise<{
236
+ id: import("../generated/types.js").components["schemas"]["AccountHolderId"];
237
+ tenant_id?: string;
238
+ state: "active" | "held" | "closed" | "closed_uncooperative" | "provisioning_failed";
239
+ state_reason?: string | null;
240
+ state_changed_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
241
+ tier: "tier_1" | "tier_2";
242
+ tier_2_uplift_status?: "not_requested" | "pending" | "passed" | "failed";
243
+ first_use_completed: boolean;
244
+ cip_payload?: {
245
+ name_hash?: string;
246
+ dob_hash?: string;
247
+ id_hash?: string;
248
+ address_hash?: string;
249
+ } | null;
250
+ cip_accepted_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
251
+ merchant_role_state?: "none" | "pending_review" | "approved" | "rejected" | "revoked";
252
+ auto_save_contacts?: boolean;
253
+ created_at: import("../generated/types.js").components["schemas"]["TimestampUtc"];
254
+ updated_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"];
255
+ email?: string | null;
256
+ first_name?: string | null;
257
+ last_name?: string | null;
258
+ phone?: string | null;
259
+ avatar_url?: string | null;
260
+ }>;
261
+ confirmAvatar(id: string, body: ReqBody<'confirmAccountHolderAvatar'>, opts?: XKOVAMutationOptions): Promise<{
262
+ id: import("../generated/types.js").components["schemas"]["AccountHolderId"];
263
+ tenant_id?: string;
264
+ state: "active" | "held" | "closed" | "closed_uncooperative" | "provisioning_failed";
265
+ state_reason?: string | null;
266
+ state_changed_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
267
+ tier: "tier_1" | "tier_2";
268
+ tier_2_uplift_status?: "not_requested" | "pending" | "passed" | "failed";
269
+ first_use_completed: boolean;
270
+ cip_payload?: {
271
+ name_hash?: string;
272
+ dob_hash?: string;
273
+ id_hash?: string;
274
+ address_hash?: string;
275
+ } | null;
276
+ cip_accepted_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"] | null;
277
+ merchant_role_state?: "none" | "pending_review" | "approved" | "rejected" | "revoked";
278
+ auto_save_contacts?: boolean;
279
+ created_at: import("../generated/types.js").components["schemas"]["TimestampUtc"];
280
+ updated_at?: import("../generated/types.js").components["schemas"]["TimestampUtc"];
281
+ email?: string | null;
282
+ first_name?: string | null;
283
+ last_name?: string | null;
284
+ phone?: string | null;
285
+ avatar_url?: string | null;
286
+ }>;
287
+ presignAvatarUpload(id: string, body: ReqBody<'presignAccountHolderAvatarUpload'>, opts?: XKOVAMutationOptions): Promise<{
288
+ upload_url: string;
289
+ object_key: string;
290
+ expires_at: import("../generated/types.js").components["schemas"]["TimestampUtc"];
291
+ }>;
292
+ listWallets(id: string): Promise<{
293
+ data: import("../generated/types.js").components["schemas"]["Wallet"][];
294
+ }>;
295
+ }
@@ -0,0 +1,166 @@
1
+ import { Resource } from './base.js';
2
+ import { XKOVAUploadError } from '../errors.js';
3
+ function memberSessionHeaders(context) {
4
+ return {
5
+ 'X-Member-Session-Id': context.memberSessionId,
6
+ 'X-XKOVA-Publishable-Key': context.memberAuthPublishableKey,
7
+ };
8
+ }
9
+ export class AccountHoldersResource extends Resource {
10
+ storageFetch;
11
+ constructor(client, storageFetch = fetch) {
12
+ super(client);
13
+ this.storageFetch = storageFetch;
14
+ }
15
+ list(query = {}) {
16
+ return this.getJson('/account-holders', query);
17
+ }
18
+ create(body, opts) {
19
+ return this.postJson('/account-holders', body, opts);
20
+ }
21
+ retrieve(id, query = {}) {
22
+ return this.getJson(`/account-holders/${this.enc(id)}`, query);
23
+ }
24
+ update(id, body, opts) {
25
+ return this.patchJson(`/account-holders/${this.enc(id)}`, body, opts);
26
+ }
27
+ history(id, query = {}) {
28
+ return this.getJson(`/account-holders/${this.enc(id)}/history`, query);
29
+ }
30
+ selfVerification(context, control) {
31
+ return this.getJson('/account-holders/self/verification', undefined, control, memberSessionHeaders(context));
32
+ }
33
+ selfBalance(context, control) {
34
+ return this.getJson('/account-holders/self/balance', undefined, control, memberSessionHeaders(context));
35
+ }
36
+ listSelfWallets(context, control) {
37
+ return this.getJson('/account-holders/self/wallets', undefined, control, memberSessionHeaders(context));
38
+ }
39
+ selfWalletReadiness(context, control) {
40
+ return this.getJson('/account-holders/self/wallet-readiness', undefined, control, memberSessionHeaders(context));
41
+ }
42
+ ensureSelfWalletProvisioning(context, opts) {
43
+ return this.postJson('/account-holders/self/wallet-provision', undefined, opts, undefined, memberSessionHeaders(context));
44
+ }
45
+ selfBankBalance(context, control) {
46
+ return this.getJson('/account-holders/self/bank-balance', undefined, control, memberSessionHeaders(context));
47
+ }
48
+ selfSandboxBankingContext(context, control) {
49
+ return this.getJson('/account-holders/self/sandbox-banking-context', undefined, control, memberSessionHeaders(context));
50
+ }
51
+ /** Advisory, uncached setup facts from the existing exact-session read. */
52
+ async selfActionReadiness(context, control) {
53
+ const status = await this.getJson('/member-auth/session', undefined, control, memberSessionHeaders(context));
54
+ if (status.session_id !== context.memberSessionId ||
55
+ status.account_holder_id !== context.accountHolderId) {
56
+ throw new Error('Member readiness returned a different session or account holder');
57
+ }
58
+ const readiness = status.action_readiness;
59
+ if (!readiness ||
60
+ !['hosted_passkey', 'external_oidc'].includes(readiness.authorization_method) ||
61
+ ![
62
+ 'passkey_required',
63
+ 'recovery_acknowledgement_required',
64
+ 'recovery_required',
65
+ 'ready',
66
+ 'externally_managed',
67
+ ].includes(readiness.setup_status) ||
68
+ typeof readiness.action_authorization_enabled !== 'boolean' ||
69
+ readiness.requires_fresh_proof !== true ||
70
+ readiness.provider_status !== 'not_checked') {
71
+ throw new Error('Member action readiness response is invalid');
72
+ }
73
+ return readiness;
74
+ }
75
+ listSelfBankTransactions(context, query = {}, control) {
76
+ return this.getJson('/account-holders/self/bank-transactions', query, control, memberSessionHeaders(context));
77
+ }
78
+ createSelfBankTransfer(context, body, opts) {
79
+ return this.postJson('/account-holders/self/bank-transfers', body, opts, undefined, memberSessionHeaders(context));
80
+ }
81
+ selfCheckingBalance(context, control) {
82
+ return this.getJson('/account-holders/self/checking-balance', undefined, control, memberSessionHeaders(context));
83
+ }
84
+ selfConsentState(context, control) {
85
+ return this.getJson('/account-holders/self/consents', undefined, control, memberSessionHeaders(context));
86
+ }
87
+ acceptSelfConsents(context, body, opts) {
88
+ return this.postJson('/account-holders/self/consents', body, opts, undefined, memberSessionHeaders(context));
89
+ }
90
+ requestSelfDataExport(context, opts) {
91
+ return this.postJson('/account-holders/self/data-exports', undefined, opts, undefined, memberSessionHeaders(context));
92
+ }
93
+ selfDataExport(context, id, control) {
94
+ return this.getJson(`/account-holders/self/data-exports/${this.enc(id)}`, undefined, control, memberSessionHeaders(context));
95
+ }
96
+ listSelfTransactions(context, query = {}, control) {
97
+ return this.getJson('/account-holders/self/transactions', query, control, memberSessionHeaders(context));
98
+ }
99
+ /**
100
+ * Server-side avatar upload using the platform's presign/upload/confirm
101
+ * contract. Only image bytes go to object storage. API bearer, signatures,
102
+ * member context and cookies never follow the presigned URL or a redirect.
103
+ */
104
+ async uploadAvatar(id, image, control = {}) {
105
+ if (!['image/png', 'image/jpeg', 'image/webp', 'image/gif'].includes(image.type) ||
106
+ image.size === 0 ||
107
+ image.size > 5 * 1024 * 1024) {
108
+ throw new TypeError('Avatar must be a PNG, JPEG, WebP, or GIF image of at most 5 MiB');
109
+ }
110
+ const upload = await this.presignAvatarUpload(id, {
111
+ content_type: image.type,
112
+ content_length: image.size,
113
+ }, control);
114
+ const target = new URL(upload.upload_url);
115
+ if (target.username ||
116
+ target.password ||
117
+ target.hash ||
118
+ (target.protocol !== 'https:' &&
119
+ !(target.protocol === 'http:' && target.hostname === 'localhost')) ||
120
+ !Number.isFinite(Date.parse(upload.expires_at)) ||
121
+ Date.parse(upload.expires_at) <= Date.now()) {
122
+ throw new XKOVAUploadError('The avatar upload capability is invalid or expired');
123
+ }
124
+ let response;
125
+ try {
126
+ response = await this.storageFetch(target, {
127
+ method: 'PUT',
128
+ body: image,
129
+ headers: {
130
+ 'content-type': image.type,
131
+ 'content-length': String(image.size),
132
+ },
133
+ credentials: 'omit',
134
+ redirect: 'error',
135
+ referrerPolicy: 'no-referrer',
136
+ cache: 'no-store',
137
+ signal: control.signal
138
+ ? AbortSignal.any([control.signal, AbortSignal.timeout(30_000)])
139
+ : AbortSignal.timeout(30_000),
140
+ });
141
+ }
142
+ catch {
143
+ // Never attach provider errors containing the signed URL to a public error.
144
+ throw new XKOVAUploadError('Object storage did not accept the avatar upload');
145
+ }
146
+ if (!response.ok)
147
+ throw new XKOVAUploadError('Object storage rejected the avatar upload', response.status);
148
+ await this.confirmAvatar(id, { object_key: upload.object_key }, control);
149
+ return this.avatarUrl(id);
150
+ }
151
+ avatarUrl(id) {
152
+ return this.getJson(`/account-holders/${this.enc(id)}/avatar`);
153
+ }
154
+ deleteAvatar(id, opts) {
155
+ return this.deleteJson(`/account-holders/${this.enc(id)}/avatar`, opts);
156
+ }
157
+ confirmAvatar(id, body, opts) {
158
+ return this.postJson(`/account-holders/${this.enc(id)}/avatar/confirm`, body, opts);
159
+ }
160
+ presignAvatarUpload(id, body, opts) {
161
+ return this.postJson(`/account-holders/${this.enc(id)}/avatar/upload-url`, body, opts);
162
+ }
163
+ listWallets(id) {
164
+ return this.getJson(`/account-holders/${this.enc(id)}/wallets`);
165
+ }
166
+ }
@@ -0,0 +1,47 @@
1
+ import type { operations } from '../generated/types.js';
2
+ import type { XKOVAClient, XKOVAMutationOptions, XKOVARequestControl } from '../client.js';
3
+ export type OpId = keyof operations;
4
+ type SuccessStatus = 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 226;
5
+ type ResponseBody<T> = T extends {
6
+ content: infer Content;
7
+ } ? Content extends {
8
+ 'application/json': infer Body;
9
+ } ? Body : Content extends {
10
+ 'image/svg+xml': unknown;
11
+ } ? string : Content extends {
12
+ 'text/csv': unknown;
13
+ } ? string : unknown : void;
14
+ export type Ok<Op extends OpId> = operations[Op] extends {
15
+ responses: infer Responses;
16
+ } ? ResponseBody<Responses[keyof Responses & SuccessStatus]> : never;
17
+ export type ReqBody<Op extends OpId> = operations[Op] extends {
18
+ requestBody: {
19
+ content: {
20
+ 'application/json': infer Body;
21
+ };
22
+ };
23
+ } ? Body : operations[Op] extends {
24
+ requestBody?: {
25
+ content: {
26
+ 'application/json': infer Body;
27
+ };
28
+ };
29
+ } ? Body : never;
30
+ export type Query<Op extends OpId> = operations[Op] extends {
31
+ parameters: {
32
+ query?: infer Params;
33
+ };
34
+ } ? NonNullable<Params> : Record<string, never>;
35
+ type QueryRecord = Record<string, string | number | boolean | null | undefined | readonly string[]>;
36
+ export declare abstract class Resource {
37
+ protected readonly client: XKOVAClient;
38
+ constructor(client: XKOVAClient);
39
+ protected getJson<Op extends OpId>(path: `/${string}`, query?: QueryRecord, control?: XKOVARequestControl, headers?: Record<string, string>): Promise<Ok<Op>>;
40
+ protected getText<Op extends OpId>(path: `/${string}`, query?: QueryRecord, control?: XKOVARequestControl, accept?: string): Promise<Ok<Op>>;
41
+ protected postJson<Op extends OpId, Body = ReqBody<Op>>(path: `/${string}`, body?: Body, opts?: XKOVAMutationOptions, query?: QueryRecord, headers?: Record<string, string>): Promise<Ok<Op>>;
42
+ protected putJson<Op extends OpId, Body = ReqBody<Op>>(path: `/${string}`, body: Body, opts?: XKOVAMutationOptions, query?: QueryRecord, headers?: Record<string, string>): Promise<Ok<Op>>;
43
+ protected patchJson<Op extends OpId, Body = ReqBody<Op>>(path: `/${string}`, body: Body, opts?: XKOVAMutationOptions, query?: QueryRecord, headers?: Record<string, string>): Promise<Ok<Op>>;
44
+ protected deleteJson<Op extends OpId>(path: `/${string}`, opts?: XKOVAMutationOptions, query?: QueryRecord, headers?: Record<string, string>): Promise<Ok<Op>>;
45
+ protected enc(value: string): string;
46
+ }
47
+ export {};
@@ -0,0 +1,25 @@
1
+ export class Resource {
2
+ client;
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ getJson(path, query, control = {}, headers) {
7
+ return this.client.requestJson({ method: 'GET', path, ...(query !== undefined && { query }), ...(headers !== undefined && { headers }), ...(control.signal !== undefined && { signal: control.signal }) });
8
+ }
9
+ getText(path, query, control = {}, accept = 'text/plain, */*') {
10
+ return this.client.requestText({ method: 'GET', path, accept, ...(query !== undefined && { query }), ...(control.signal !== undefined && { signal: control.signal }) });
11
+ }
12
+ postJson(path, body, opts = {}, query, headers) {
13
+ return this.client.requestJson({ method: 'POST', path, ...(body !== undefined && { body }), ...(query !== undefined && { query }), ...(headers !== undefined && { headers }), ...(opts.idempotencyKey !== undefined && { idempotencyKey: opts.idempotencyKey }), ...(opts.signal !== undefined && { signal: opts.signal }) });
14
+ }
15
+ putJson(path, body, opts = {}, query, headers) {
16
+ return this.client.requestJson({ method: 'PUT', path, body, ...(query !== undefined && { query }), ...(headers !== undefined && { headers }), ...(opts.idempotencyKey !== undefined && { idempotencyKey: opts.idempotencyKey }), ...(opts.signal !== undefined && { signal: opts.signal }) });
17
+ }
18
+ patchJson(path, body, opts = {}, query, headers) {
19
+ return this.client.requestJson({ method: 'PATCH', path, body, ...(query !== undefined && { query }), ...(headers !== undefined && { headers }), ...(opts.idempotencyKey !== undefined && { idempotencyKey: opts.idempotencyKey }), ...(opts.signal !== undefined && { signal: opts.signal }) });
20
+ }
21
+ deleteJson(path, opts = {}, query, headers) {
22
+ return this.client.requestJson({ method: 'DELETE', path, ...(query !== undefined && { query }), ...(headers !== undefined && { headers }), ...(opts.idempotencyKey !== undefined && { idempotencyKey: opts.idempotencyKey }), ...(opts.signal !== undefined && { signal: opts.signal }) });
23
+ }
24
+ enc(value) { return encodeURIComponent(value); }
25
+ }