@unicitylabs/sphere-sdk 0.14.0-dev.1 → 0.14.0-dev.2

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.
@@ -0,0 +1,577 @@
1
+ interface HttpResponseLike {
2
+ readonly status: number;
3
+ readonly ok: boolean;
4
+ readonly headers?: {
5
+ get(name: string): string | null;
6
+ };
7
+ text(): Promise<string>;
8
+ arrayBuffer(): Promise<ArrayBuffer>;
9
+ }
10
+ interface HttpRequestInit {
11
+ method: string;
12
+ headers?: Record<string, string>;
13
+ body?: string | Uint8Array;
14
+ }
15
+ type FetchLike = (url: string, init?: HttpRequestInit) => Promise<HttpResponseLike>;
16
+ declare class WalletApiHttpError extends Error {
17
+ readonly status: number;
18
+ readonly code: string;
19
+ /** Milliseconds, parsed from a Retry-After header when present. */
20
+ readonly retryAfter?: number;
21
+ constructor(status: number, code: string, message: string, retryAfter?: number);
22
+ }
23
+ declare function isWalletApiHttpError(err: unknown, status?: number): err is WalletApiHttpError;
24
+ interface WalletApiHttpConfig {
25
+ baseUrl: string;
26
+ fetchFn: FetchLike;
27
+ /** Bearer source; `null` sends the request unauthenticated. */
28
+ getToken: () => string | null;
29
+ }
30
+ interface RequestOptions {
31
+ /** Default true; auth endpoints opt out so a stale bearer is never attached. */
32
+ auth?: boolean;
33
+ }
34
+ interface WalletApiHttp {
35
+ readonly baseUrl: string;
36
+ request(method: string, path: string, body?: unknown, opts?: RequestOptions): Promise<unknown>;
37
+ /** Direct fetch for presigned S3 URLs — no base URL, no bearer. */
38
+ fetchRaw(url: string, init: HttpRequestInit): Promise<HttpResponseLike>;
39
+ }
40
+ /** ARCHITECTURE §4 transport rule: non-loopback MUST be https. Returns the URL without a trailing slash. */
41
+ declare function assertSecureBaseUrl(baseUrl: string): string;
42
+ declare function createWalletApiHttp(config: WalletApiHttpConfig): WalletApiHttp;
43
+
44
+ interface AuthChallengeWire {
45
+ nonce: string;
46
+ challenge: string;
47
+ expiresAt: string;
48
+ }
49
+ interface AuthTokensWire {
50
+ jwt: string;
51
+ refreshToken: string;
52
+ }
53
+ interface AssetWire {
54
+ coinId: string;
55
+ amount: string;
56
+ }
57
+ interface InventoryItemWire {
58
+ tokenId: string;
59
+ status: 'active' | 'removed';
60
+ seq: number;
61
+ stateHash: string;
62
+ assets?: AssetWire[];
63
+ }
64
+ interface InventoryPageWire {
65
+ cursor: number;
66
+ syncEpoch: number;
67
+ more: boolean;
68
+ items: InventoryItemWire[];
69
+ }
70
+ interface BalanceWire {
71
+ coinId: string;
72
+ total: string;
73
+ tokenCount: number;
74
+ }
75
+ interface BlobUrlWire {
76
+ tokenId: string;
77
+ getUrl: string;
78
+ }
79
+ interface UploadUrlWire {
80
+ sha256: string;
81
+ key: string;
82
+ putUrl: string;
83
+ }
84
+ interface ApplyDeltaWire {
85
+ cursor: number;
86
+ syncEpoch: number;
87
+ }
88
+ interface IntentWire {
89
+ transferId: string;
90
+ payload: string;
91
+ status: 'open' | 'aborted';
92
+ createdAt: string;
93
+ }
94
+ interface ProgressRecordWire {
95
+ opIndex: number;
96
+ payload: string;
97
+ createdAt: string;
98
+ }
99
+ interface MailboxDepositEntry {
100
+ recipientPubkey: string;
101
+ key: string;
102
+ transferId: string;
103
+ tokenId: string;
104
+ stateHash: string;
105
+ memo?: string;
106
+ }
107
+ interface MailboxEntryWire {
108
+ entryId: string;
109
+ seq: number;
110
+ status: string;
111
+ transferId: string;
112
+ tokenId: string;
113
+ assets: AssetWire[];
114
+ senderPubkey: string;
115
+ memo?: string;
116
+ createdAt: string;
117
+ getUrl?: string;
118
+ blobCollected?: boolean;
119
+ }
120
+ interface MailboxPageWire {
121
+ readPointer: number;
122
+ cursor: number;
123
+ syncEpoch: number;
124
+ more: boolean;
125
+ entries: MailboxEntryWire[];
126
+ }
127
+ interface ClaimResultWire {
128
+ claimed: string[];
129
+ alreadyClaimed: {
130
+ entryId: string;
131
+ intoInventory: boolean;
132
+ }[];
133
+ failed: {
134
+ entryId: string;
135
+ code: string;
136
+ }[];
137
+ }
138
+ type MailboxRejectReason = 'invalid' | 'not-owned' | 'storage-rejected' | 'other';
139
+ interface HistoryRecordWire {
140
+ dedupKey: string;
141
+ id: string;
142
+ type: 'SENT' | 'RECEIVED' | 'MINT';
143
+ assets: AssetWire[];
144
+ ts: string;
145
+ transferId?: string;
146
+ tokenId?: string;
147
+ counterpartyPubkey?: string;
148
+ counterpartyNametag?: string;
149
+ memo?: string;
150
+ }
151
+ interface HistoryPageWire {
152
+ records: HistoryRecordWire[];
153
+ more: boolean;
154
+ cursor: string | null;
155
+ syncEpoch: number;
156
+ }
157
+ type PaymentRequestWireStatus = 'open' | 'paid' | 'declined' | 'expired';
158
+ interface PaymentRequestWire {
159
+ id: string;
160
+ seq: number;
161
+ fromPubkey: string;
162
+ toPubkey: string;
163
+ assets: AssetWire[];
164
+ memo?: string;
165
+ status: PaymentRequestWireStatus;
166
+ transferId: string | null;
167
+ createdAt: string;
168
+ expiresAt?: string;
169
+ }
170
+ interface PaymentRequestsPageWire {
171
+ requests: PaymentRequestWire[];
172
+ more: boolean;
173
+ cursor: number | string | null;
174
+ syncEpoch: number;
175
+ }
176
+ type ListPaymentRequestsParams = {
177
+ role: 'incoming';
178
+ status?: PaymentRequestWireStatus;
179
+ since?: number;
180
+ } | {
181
+ role: 'outgoing';
182
+ status?: PaymentRequestWireStatus;
183
+ before?: string;
184
+ };
185
+ type RespondPaymentRequestInput = {
186
+ action: 'paid';
187
+ transferId: string;
188
+ } | {
189
+ action: 'declined';
190
+ };
191
+ declare class WalletApiV2Client {
192
+ private readonly http;
193
+ constructor(http: WalletApiHttp);
194
+ get baseUrl(): string;
195
+ authChallenge(pubkey: string): Promise<AuthChallengeWire>;
196
+ authVerify(input: {
197
+ nonce: string;
198
+ signature: string;
199
+ deviceId: string;
200
+ }): Promise<AuthTokensWire>;
201
+ authRefresh(refreshToken: string): Promise<AuthTokensWire>;
202
+ authLogout(): Promise<void>;
203
+ listInventory(since?: number): Promise<InventoryPageWire>;
204
+ balances(): Promise<BalanceWire[]>;
205
+ blobUrls(tokenIds: string[]): Promise<BlobUrlWire[]>;
206
+ uploadUrls(blobs: {
207
+ sha256: string;
208
+ size: number;
209
+ }[]): Promise<UploadUrlWire[]>;
210
+ apply(delta: {
211
+ transferId: string;
212
+ spent: string[];
213
+ added: {
214
+ tokenId: string;
215
+ key: string;
216
+ }[];
217
+ }): Promise<ApplyDeltaWire>;
218
+ fetchBlob(getUrl: string): Promise<Uint8Array>;
219
+ /**
220
+ * PUT to a presigned S3 URL. `x-amz-checksum-sha256` (base64) and
221
+ * `If-None-Match: *` are SIGNED headers — sent verbatim. S3 412 = the
222
+ * identical blob already exists = success.
223
+ */
224
+ uploadBlob(putUrl: string, bytes: Uint8Array): Promise<void>;
225
+ putIntent(transferId: string, payloadEnvelope: string, requiresSeedClose?: boolean): Promise<void>;
226
+ listIntents(status?: 'open' | 'aborted'): Promise<IntentWire[]>;
227
+ abortIntent(transferId: string): Promise<void>;
228
+ completeIntent(transferId: string, signature?: string): Promise<void>;
229
+ postProgress(transferId: string, opIndex: number, payloadEnvelope: string, signature: string): Promise<ProgressRecordWire>;
230
+ getProgress(transferId: string): Promise<ProgressRecordWire[]>;
231
+ deposit(entry: MailboxDepositEntry): Promise<string>;
232
+ depositBatch(entries: MailboxDepositEntry[]): Promise<{
233
+ entryId: string;
234
+ seq: number;
235
+ }[]>;
236
+ listMailbox(since?: number): Promise<MailboxPageWire>;
237
+ claim(entryIds: string[], intoInventory: boolean): Promise<ClaimResultWire>;
238
+ reject(entryIds: string[], reason?: MailboxRejectReason, detail?: string): Promise<string[]>;
239
+ postHistory(records: HistoryRecordWire[]): Promise<{
240
+ inserted: number;
241
+ deduped: number;
242
+ }>;
243
+ listHistory(options?: {
244
+ before?: string;
245
+ limit?: number;
246
+ }): Promise<HistoryPageWire>;
247
+ createPaymentRequest(input: {
248
+ toPubkey: string;
249
+ assets: AssetWire[];
250
+ memo?: string;
251
+ expiresAt?: string;
252
+ }): Promise<PaymentRequestWire>;
253
+ listPaymentRequests(params: ListPaymentRequestsParams): Promise<PaymentRequestsPageWire>;
254
+ respondPaymentRequest(id: string, response: RespondPaymentRequestInput): Promise<PaymentRequestWire>;
255
+ wsTicket(): Promise<string>;
256
+ }
257
+
258
+ /**
259
+ * token-engine/engine.ts — the FROZEN public port (ITokenEngine) + its config.
260
+ *
261
+ * This is the contract both migration tracks build against. It is sphere-domain
262
+ * only (see types.ts). The granular, SDK-typed steps (buildMint, submit,
263
+ * awaitProof, certify, …) are an INTERNAL concern of the real adapter and are
264
+ * intentionally NOT part of this public interface.
265
+ */
266
+
267
+ /**
268
+ * Durable, any-device store for a split's burn checkpoint (sdk-changes E.4, sphere-sdk#501
269
+ * option b). The engine passes opaque PLAINTEXT bytes; a transport adapter (the wallet-api
270
+ * provider) is responsible for AAD-encryption and the wallet-api §16 intent-progress round-trip.
271
+ *
272
+ * The store is the resume seed for the one split input the engine cannot re-derive — the burn's
273
+ * aggregator-issued inclusion proof — so the mint justification is rebuilt from stored bytes, not
274
+ * a refetch (the aggregator regenerates proofs per request).
275
+ */
276
+ interface SplitCheckpointStore {
277
+ /**
278
+ * Insert-once, first-write-wins. MUST resolve only AFTER the store acked durability, and MUST
279
+ * resolve with the AUTHORITATIVE stored bytes — the caller's own on a fresh write, or the FIRST
280
+ * writer's when the slot `(transferId, opIndex)` was already taken (the caller adopts those and
281
+ * mints from them, so concurrent resumers converge on one burn proof).
282
+ */
283
+ put(transferId: string, opIndex: number, bytes: Uint8Array): Promise<Uint8Array>;
284
+ /** The stored bytes for the slot, or `null` when none exists. */
285
+ get(transferId: string, opIndex: number): Promise<Uint8Array | null>;
286
+ }
287
+
288
+ interface ScopedKV {
289
+ get<T>(key: string): Promise<T | null>;
290
+ set<T>(key: string, value: T): Promise<void>;
291
+ remove(key: string): Promise<void>;
292
+ }
293
+
294
+ /**
295
+ * The JWT generation cell (#692 F8/F14). Every write is a compare-and-swap on
296
+ * a generation captured at operation start — the CAS lives INSIDE the setter,
297
+ * so a continuation returning from an await can never clobber a newer session.
298
+ */
299
+ declare class JwtGenerationCell {
300
+ private gen;
301
+ private jwt;
302
+ get generation(): number;
303
+ token(): string | null;
304
+ install(generation: number, jwt: string): boolean;
305
+ /** authGone(G) is a no-op when the cell moved to G+1 (F14). */
306
+ clearIfCurrent(generation: number): boolean;
307
+ dropIfMatches(generation: number, jwt: string): void;
308
+ bump(): number;
309
+ }
310
+ type WakeStream = 'inventory' | 'mailbox' | 'payment_requests';
311
+ declare const WAKE_STREAMS: readonly WakeStream[];
312
+ type ConnectionStatus = 'connected' | 'degraded' | 'offline';
313
+ interface SessionSigner {
314
+ readonly pubkey: string;
315
+ readonly network: string;
316
+ sign(message: string): string | Promise<string>;
317
+ }
318
+ interface WebSocketLike {
319
+ onopen: (() => void) | null;
320
+ onmessage: ((ev: {
321
+ data: unknown;
322
+ }) => void) | null;
323
+ onclose: ((ev: {
324
+ code?: number;
325
+ }) => void) | null;
326
+ onerror: ((err: unknown) => void) | null;
327
+ close(code?: number, reason?: string): void;
328
+ }
329
+ type WebSocketFactory = (url: string) => WebSocketLike;
330
+ interface SessionTimers {
331
+ setTimeout(cb: () => void, ms: number): unknown;
332
+ clearTimeout(handle: unknown): void;
333
+ setInterval(cb: () => void, ms: number): unknown;
334
+ clearInterval(handle: unknown): void;
335
+ }
336
+ interface SessionTiming {
337
+ pullIntervalMs: number;
338
+ reconnectBaseMs: number;
339
+ reconnectCapMs: number;
340
+ heartbeatTimeoutMs: number;
341
+ offlineAfterFailures: number;
342
+ }
343
+ declare const DEFAULT_SESSION_TIMING: SessionTiming;
344
+ interface WalletApiSessionDeps {
345
+ client: WalletApiV2Client;
346
+ cell: JwtGenerationCell;
347
+ signer: SessionSigner;
348
+ deviceId: string;
349
+ kv: ScopedKV;
350
+ webSocketFactory: WebSocketFactory;
351
+ emitStatus: (status: ConnectionStatus) => void;
352
+ /** Runs the syncEpoch re-seed protocol BEFORE any stream resumes. */
353
+ onEpochChange: (epoch: string) => Promise<void>;
354
+ timing?: Partial<SessionTiming>;
355
+ timers?: SessionTimers;
356
+ random?: () => number;
357
+ }
358
+ declare function refreshTokenKey(deviceId: string): string;
359
+ declare class WalletApiSession {
360
+ private readonly deps;
361
+ private readonly timing;
362
+ private readonly timers;
363
+ private readonly random;
364
+ private readonly refreshKey;
365
+ private authFlight;
366
+ private epochLatch;
367
+ private reseedChain;
368
+ private reseedsPending;
369
+ private readonly handlers;
370
+ private socket;
371
+ private started;
372
+ private stopped;
373
+ private reconnectAttempts;
374
+ private reconnectTimer;
375
+ private heartbeatTimer;
376
+ private pullTimers;
377
+ private lastStatus;
378
+ constructor(deps: WalletApiSessionDeps);
379
+ start(): Promise<void>;
380
+ stop(): Promise<void>;
381
+ token(): string | null;
382
+ /** Identity switch / lock / logout: supersede every in-flight auth continuation. */
383
+ invalidate(): void;
384
+ ensureAuthenticated(): Promise<string>;
385
+ /** Run an authenticated op; one 401 → single-flight re-auth → one retry. */
386
+ withAuth<T>(op: (jwt: string) => Promise<T>): Promise<T>;
387
+ private runAuthSingleFlight;
388
+ private authenticate;
389
+ private tryRefresh;
390
+ private challengeSignIn;
391
+ noteEpoch(epoch: string): void;
392
+ private runReseed;
393
+ subscribeStream(stream: WakeStream, handler: () => void): () => void;
394
+ private dispatch;
395
+ private nudgeAllStreams;
396
+ private startPullTimers;
397
+ status(): ConnectionStatus;
398
+ private emitStatus;
399
+ private connect;
400
+ private openSocket;
401
+ private handleOpen;
402
+ private handleMessage;
403
+ private handleClose;
404
+ private scheduleReconnect;
405
+ private armHeartbeat;
406
+ private clearHeartbeat;
407
+ }
408
+
409
+ interface InventoryAsset {
410
+ coinId: string;
411
+ amount: string;
412
+ }
413
+ interface InventoryItem {
414
+ tokenId: string;
415
+ status: 'active' | 'removed';
416
+ seq: number;
417
+ stateHash: string;
418
+ assets?: InventoryAsset[];
419
+ }
420
+ interface InventoryPage {
421
+ cursor: number;
422
+ syncEpoch: string;
423
+ more: boolean;
424
+ items: InventoryItem[];
425
+ }
426
+ interface ApplyDeltaResult {
427
+ cursor: number;
428
+ syncEpoch: string;
429
+ }
430
+ interface StoragePort {
431
+ listInventory(since?: number): Promise<InventoryPage>;
432
+ balances(): Promise<{
433
+ coinId: string;
434
+ total: string;
435
+ tokenCount: number;
436
+ }[]>;
437
+ getBlobs(tokenIds: string[]): Promise<Map<string, Uint8Array>>;
438
+ uploadBlobs(blobs: {
439
+ sha256: string;
440
+ bytes: Uint8Array;
441
+ }[]): Promise<Map<string, string>>;
442
+ applyDelta(delta: {
443
+ transferId: string;
444
+ spent: string[];
445
+ added: {
446
+ tokenId: string;
447
+ key: string;
448
+ }[];
449
+ }): Promise<ApplyDeltaResult>;
450
+ }
451
+ interface DeliveryReceipt {
452
+ deliveryId: string;
453
+ }
454
+ interface IncomingDelivery {
455
+ deliveryId: string;
456
+ transferId?: string;
457
+ senderPubkey?: string;
458
+ senderNametag?: string;
459
+ memo?: string;
460
+ fetchBlob(): Promise<Uint8Array>;
461
+ cursor: string;
462
+ }
463
+ interface DeliverOptions {
464
+ transferId: string;
465
+ memo?: string;
466
+ senderNametag?: string;
467
+ }
468
+ interface DeliveryPort {
469
+ bindDeliveryKeys(derive: (blob: Uint8Array) => Promise<{
470
+ tokenId: string;
471
+ stateHash: string;
472
+ }>): void;
473
+ deliver(recipientPubkey: string, blob: Uint8Array, options: DeliverOptions): Promise<DeliveryReceipt>;
474
+ deliverBatch?(recipientPubkey: string, blobs: Uint8Array[], options: DeliverOptions): Promise<DeliveryReceipt[]>;
475
+ incoming(sinceCursor?: string): AsyncIterable<IncomingDelivery>;
476
+ ack(deliveryId: string, disposition: 'claimed' | 'rejected', reason?: 'invalid' | 'not-owned' | 'storage-rejected' | 'other'): Promise<void>;
477
+ onWake?(cb: () => void): () => void;
478
+ }
479
+
480
+ type StoragePortClient = Pick<WalletApiV2Client, 'listInventory' | 'balances' | 'blobUrls' | 'uploadUrls' | 'apply' | 'fetchBlob' | 'uploadBlob'>;
481
+ declare class WalletApiStoragePort implements StoragePort {
482
+ private readonly client;
483
+ constructor(client: StoragePortClient);
484
+ listInventory(since?: number): Promise<InventoryPage>;
485
+ balances(): Promise<{
486
+ coinId: string;
487
+ total: string;
488
+ tokenCount: number;
489
+ }[]>;
490
+ getBlobs(tokenIds: string[]): Promise<Map<string, Uint8Array>>;
491
+ uploadBlobs(blobs: {
492
+ sha256: string;
493
+ bytes: Uint8Array;
494
+ }[]): Promise<Map<string, string>>;
495
+ applyDelta(delta: {
496
+ transferId: string;
497
+ spent: string[];
498
+ added: {
499
+ tokenId: string;
500
+ key: string;
501
+ }[];
502
+ }): Promise<ApplyDeltaResult>;
503
+ }
504
+
505
+ type DeliveryPortClient = Pick<WalletApiV2Client, 'uploadUrls' | 'uploadBlob' | 'fetchBlob' | 'deposit' | 'depositBatch' | 'listMailbox' | 'claim' | 'reject'>;
506
+ type DeliveryCustody = 'inventory' | 'external';
507
+ interface WakeSource {
508
+ subscribeStream(stream: 'inventory' | 'mailbox' | 'payment_requests', handler: () => void): () => void;
509
+ }
510
+ interface DeliveryIdentity {
511
+ privateKey: string;
512
+ chainPubkey: string;
513
+ nametag?: string;
514
+ }
515
+ interface WalletApiDeliveryPortConfig {
516
+ client: DeliveryPortClient;
517
+ kv: ScopedKV;
518
+ identity: DeliveryIdentity;
519
+ /** Composition-time custody (S7) — NEVER a per-call flag. */
520
+ custody: DeliveryCustody;
521
+ wake?: WakeSource;
522
+ deliveryKeys?: (blob: Uint8Array) => Promise<{
523
+ tokenId: string;
524
+ stateHash: string;
525
+ }>;
526
+ }
527
+ declare class WalletApiDeliveryPort implements DeliveryPort {
528
+ readonly custody: DeliveryCustody;
529
+ private readonly client;
530
+ private readonly kv;
531
+ private readonly identity;
532
+ private readonly wake;
533
+ private deriveFn;
534
+ private seenChain;
535
+ constructor(config: WalletApiDeliveryPortConfig);
536
+ bindDeliveryKeys(derive: (blob: Uint8Array) => Promise<{
537
+ tokenId: string;
538
+ stateHash: string;
539
+ }>): void;
540
+ private deriveKeys;
541
+ deliver(recipientPubkey: string, blob: Uint8Array, options: DeliverOptions): Promise<DeliveryReceipt>;
542
+ deliverBatch(recipientPubkey: string, blobs: Uint8Array[], options: DeliverOptions): Promise<DeliveryReceipt[]>;
543
+ private prepare;
544
+ private buildEnvelope;
545
+ private upload;
546
+ private depositAll;
547
+ private depositOne;
548
+ incoming(sinceCursor?: string): AsyncIterable<IncomingDelivery>;
549
+ private toIncoming;
550
+ private openEnvelope;
551
+ private fetchVerified;
552
+ ack(deliveryId: string, disposition: 'claimed' | 'rejected', reason?: 'invalid' | 'not-owned' | 'storage-rejected' | 'other'): Promise<void>;
553
+ onWake(cb: () => void): () => void;
554
+ private readSeen;
555
+ private addSeen;
556
+ }
557
+
558
+ type CheckpointClient = Pick<WalletApiV2Client, 'postProgress' | 'getProgress'>;
559
+ interface WalletApiSplitCheckpointStoreConfig {
560
+ client: CheckpointClient;
561
+ kv: ScopedKV;
562
+ /** S6 self-scoped field key (`deriveFieldEncryptionKey`). */
563
+ fieldKey: Uint8Array;
564
+ /** Signs the wallet-api.progress.v1 message with the chain key. */
565
+ signProgress: (message: string) => string | Promise<string>;
566
+ }
567
+ declare class WalletApiSplitCheckpointStore implements SplitCheckpointStore {
568
+ private readonly config;
569
+ constructor(config: WalletApiSplitCheckpointStoreConfig);
570
+ private cacheKey;
571
+ private aad;
572
+ put(transferId: string, opIndex: number, bytes: Uint8Array): Promise<Uint8Array>;
573
+ get(transferId: string, opIndex: number): Promise<Uint8Array | null>;
574
+ private open;
575
+ }
576
+
577
+ export { type ConnectionStatus, DEFAULT_SESSION_TIMING, type FetchLike, JwtGenerationCell, type SessionSigner, type SessionTimers, type SessionTiming, WAKE_STREAMS, type WakeStream, WalletApiDeliveryPort, type WalletApiHttp, type WalletApiHttpConfig, WalletApiHttpError, WalletApiSession, type WalletApiSessionDeps, WalletApiSplitCheckpointStore, WalletApiStoragePort, WalletApiV2Client, type WebSocketFactory, type WebSocketLike, assertSecureBaseUrl, createWalletApiHttp, isWalletApiHttpError, refreshTokenKey };