@topolo/sdk 0.7.0 → 0.8.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.
- package/README.md +11 -3
- package/dist/index.cjs +258 -53
- package/dist/index.d.cts +76 -8
- package/dist/index.d.ts +76 -8
- package/dist/index.js +255 -53
- package/dist/node/credential-store.cjs +16 -5
- package/dist/node/credential-store.d.cts +3 -1
- package/dist/node/credential-store.d.ts +3 -1
- package/dist/node/credential-store.js +16 -5
- package/package.json +5 -4
- package/src/application-requirements.ts +0 -517
- package/src/applications.generated.ts +0 -1509
- package/src/auth.ts +0 -48
- package/src/client.test.ts +0 -894
- package/src/client.ts +0 -1025
- package/src/errors.ts +0 -39
- package/src/index.test.ts +0 -69
- package/src/index.ts +0 -125
- package/src/modules/crm.test.ts +0 -208
- package/src/modules/crm.ts +0 -110
- package/src/modules/identity.test.ts +0 -165
- package/src/modules/identity.ts +0 -18
- package/src/modules/p2p.test.ts +0 -540
- package/src/modules/p2p.ts +0 -448
- package/src/node/credential-store.ts +0 -378
- package/src/oauth.test.ts +0 -216
- package/src/oauth.ts +0 -138
- package/src/services.generated.ts +0 -55
- package/src/services.test.ts +0 -243
- package/src/services.ts +0 -138
- package/src/widgets.test.ts +0 -416
- package/src/widgets.ts +0 -362
package/src/modules/p2p.ts
DELETED
|
@@ -1,448 +0,0 @@
|
|
|
1
|
-
import type { TopoloClient } from '../client.js';
|
|
2
|
-
|
|
3
|
-
export type P2PPricingModel = 'free' | 'fixed' | 'metered' | 'quote' | 'invoice';
|
|
4
|
-
|
|
5
|
-
export interface P2PCapability {
|
|
6
|
-
capability_id: string;
|
|
7
|
-
publisher_org_id: string;
|
|
8
|
-
app_id: string;
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
category: string;
|
|
12
|
-
pricing_model: P2PPricingModel;
|
|
13
|
-
pricing_amount_minor: number | null;
|
|
14
|
-
currency: string | null;
|
|
15
|
-
requires_human_approval: boolean;
|
|
16
|
-
supported_contexts: string[];
|
|
17
|
-
trust_level: string;
|
|
18
|
-
source_revision: string;
|
|
19
|
-
synced_at: number;
|
|
20
|
-
input_schema?: Record<string, unknown>;
|
|
21
|
-
output_schema?: Record<string, unknown>;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface PublishCapabilityInput {
|
|
25
|
-
capability_id: string;
|
|
26
|
-
publisher_org_id: string;
|
|
27
|
-
app_id: string;
|
|
28
|
-
name: string;
|
|
29
|
-
description: string;
|
|
30
|
-
category: string;
|
|
31
|
-
pricing_model: P2PPricingModel;
|
|
32
|
-
pricing_amount_minor?: number | null;
|
|
33
|
-
currency?: string | null;
|
|
34
|
-
requires_human_approval?: boolean;
|
|
35
|
-
supported_contexts: string[];
|
|
36
|
-
trust_level?: string;
|
|
37
|
-
public_directory_visible: boolean;
|
|
38
|
-
source_revision: string;
|
|
39
|
-
input_schema?: Record<string, unknown>;
|
|
40
|
-
output_schema?: Record<string, unknown>;
|
|
41
|
-
/** Set when the caller is the platform P2P service publishing on behalf of another org. */
|
|
42
|
-
acting_for_org_id?: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface P2PActionRequestInput {
|
|
46
|
-
capability_id: string;
|
|
47
|
-
idempotency_key: string;
|
|
48
|
-
inputs?: Record<string, unknown>;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface P2PActionRow {
|
|
52
|
-
request_id: string;
|
|
53
|
-
buyer_org_id: string;
|
|
54
|
-
seller_org_id: string;
|
|
55
|
-
capability_id: string;
|
|
56
|
-
initiating_principal_id: string;
|
|
57
|
-
inputs: Record<string, unknown>;
|
|
58
|
-
pricing_snapshot: Record<string, unknown>;
|
|
59
|
-
state: string;
|
|
60
|
-
policy_decision_id: string | null;
|
|
61
|
-
idempotency_key: string;
|
|
62
|
-
created_at: number;
|
|
63
|
-
updated_at: number;
|
|
64
|
-
capability: {
|
|
65
|
-
name: string | null;
|
|
66
|
-
category: string | null;
|
|
67
|
-
pricing_model: string | null;
|
|
68
|
-
pricing_amount_minor: number | null;
|
|
69
|
-
currency: string | null;
|
|
70
|
-
};
|
|
71
|
-
run: P2PActionRun | null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface P2PActionRun {
|
|
75
|
-
run_id: string;
|
|
76
|
-
state: string;
|
|
77
|
-
result: Record<string, unknown> | null;
|
|
78
|
-
error: string | null;
|
|
79
|
-
started_at: number | null;
|
|
80
|
-
completed_at: number | null;
|
|
81
|
-
updated_at: number;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export interface P2PActionRequestResult {
|
|
85
|
-
decision: string;
|
|
86
|
-
idempotent: boolean;
|
|
87
|
-
request: P2PActionRow;
|
|
88
|
-
run: P2PActionRun | null;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export interface P2PActionDetail {
|
|
92
|
-
action: P2PActionRow;
|
|
93
|
-
policy_decision: {
|
|
94
|
-
decision_id: string;
|
|
95
|
-
decision: string;
|
|
96
|
-
rationale: string;
|
|
97
|
-
policy_snapshot: Record<string, unknown>;
|
|
98
|
-
created_at: number;
|
|
99
|
-
} | null;
|
|
100
|
-
ledger_entries: P2PLedgerEntry[];
|
|
101
|
-
holds: P2PHold[];
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export interface P2PHold {
|
|
105
|
-
hold_id: string;
|
|
106
|
-
request_id: string;
|
|
107
|
-
buyer_org_id: string;
|
|
108
|
-
seller_org_id: string;
|
|
109
|
-
ledger_entry_id: string | null;
|
|
110
|
-
reason: string;
|
|
111
|
-
status: 'active' | 'released' | 'disputed' | 'expired';
|
|
112
|
-
release_after: number | null;
|
|
113
|
-
released_at: number | null;
|
|
114
|
-
created_at: number;
|
|
115
|
-
updated_at: number;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export interface P2PLedgerEntry {
|
|
119
|
-
entry_id: string;
|
|
120
|
-
request_id: string;
|
|
121
|
-
capability_id: string;
|
|
122
|
-
pricing_component: string;
|
|
123
|
-
buyer_org_id: string;
|
|
124
|
-
seller_org_id: string;
|
|
125
|
-
initiating_principal_id: string;
|
|
126
|
-
executing_principal_id: string;
|
|
127
|
-
policy_decision_id: string;
|
|
128
|
-
amount_minor: number;
|
|
129
|
-
currency: string;
|
|
130
|
-
audit_correlation_id: string;
|
|
131
|
-
settlement_batch_id: string | null;
|
|
132
|
-
created_at: number;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export interface P2PPolicy {
|
|
136
|
-
organization_id: string;
|
|
137
|
-
auto_approve_under_minor: number;
|
|
138
|
-
agent_spend_limit_minor_per_day: number;
|
|
139
|
-
human_approval_threshold_minor: number;
|
|
140
|
-
unknown_counterparty_requires_approval: boolean;
|
|
141
|
-
blocked_capability_ids: string[];
|
|
142
|
-
trusted_counterparty_org_ids: string[];
|
|
143
|
-
updated_at: number | null;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export interface P2PConnection {
|
|
147
|
-
connection_id: string;
|
|
148
|
-
organization_id?: string;
|
|
149
|
-
counterparty_org_id: string;
|
|
150
|
-
status: 'pending' | 'active' | 'suspended' | 'revoked';
|
|
151
|
-
initiated_by_principal_id: string;
|
|
152
|
-
created_at: number;
|
|
153
|
-
updated_at: number;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export interface P2PSettlementGroup {
|
|
157
|
-
buyer_org_id: string;
|
|
158
|
-
seller_org_id: string;
|
|
159
|
-
currency: string;
|
|
160
|
-
total_minor: number;
|
|
161
|
-
line_items: Array<{
|
|
162
|
-
entry_id: string;
|
|
163
|
-
request_id: string;
|
|
164
|
-
capability_id: string;
|
|
165
|
-
pricing_component: string;
|
|
166
|
-
amount_minor: number;
|
|
167
|
-
audit_correlation_id: string;
|
|
168
|
-
}>;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export interface P2PSettlementBatch {
|
|
172
|
-
batch_id: string;
|
|
173
|
-
buyer_org_id: string;
|
|
174
|
-
seller_org_id: string;
|
|
175
|
-
currency: string;
|
|
176
|
-
total_minor: number;
|
|
177
|
-
trigger: string;
|
|
178
|
-
pay_settlement_id: string | null;
|
|
179
|
-
status: string;
|
|
180
|
-
created_at: number;
|
|
181
|
-
updated_at: number;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
type EnvelopeData<T> = { data: T };
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* P2P module — typed wrapper over the TopoloP2P HTTP API.
|
|
188
|
-
*
|
|
189
|
-
* Cross-org isolation: `requestAction`, `respondAction`, `completeAction`,
|
|
190
|
-
* etc. all derive the buyer/seller org from the auth credential. There is
|
|
191
|
-
* intentionally no `orgId` parameter on per-org reads.
|
|
192
|
-
*
|
|
193
|
-
* Mutating calls go through TopoloClient's `confirm: true` write guardrail.
|
|
194
|
-
*/
|
|
195
|
-
export class P2PModule {
|
|
196
|
-
constructor(private readonly client: TopoloClient) {}
|
|
197
|
-
|
|
198
|
-
// Directory ----------------------------------------------------------------
|
|
199
|
-
|
|
200
|
-
async listDirectory(options: { limit?: number } = {}): Promise<P2PCapability[]> {
|
|
201
|
-
const res = await this.client.request<EnvelopeData<{ capabilities: P2PCapability[] }>>({
|
|
202
|
-
service: 'p2p',
|
|
203
|
-
path: '/api/directory/capabilities',
|
|
204
|
-
query: { limit: options.limit },
|
|
205
|
-
});
|
|
206
|
-
return res.data.capabilities;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
async getCapability(capabilityId: string): Promise<P2PCapability | null> {
|
|
210
|
-
if (!capabilityId) throw new Error('capabilityId is required');
|
|
211
|
-
try {
|
|
212
|
-
const res = await this.client.request<EnvelopeData<{ capability: P2PCapability }>>({
|
|
213
|
-
service: 'p2p',
|
|
214
|
-
path: `/api/directory/capabilities/${encodeURIComponent(capabilityId)}`,
|
|
215
|
-
});
|
|
216
|
-
return res.data.capability;
|
|
217
|
-
} catch (err) {
|
|
218
|
-
if (isNotFound(err)) return null;
|
|
219
|
-
throw err;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
async publishCapability(input: PublishCapabilityInput): Promise<P2PCapability> {
|
|
224
|
-
const res = await this.client.request<EnvelopeData<{ capability: P2PCapability }>>({
|
|
225
|
-
service: 'p2p',
|
|
226
|
-
method: 'POST',
|
|
227
|
-
path: '/api/p2p/internal/capabilities/sync',
|
|
228
|
-
body: {
|
|
229
|
-
capability_id: input.capability_id,
|
|
230
|
-
publisher_org_id: input.publisher_org_id,
|
|
231
|
-
app_id: input.app_id,
|
|
232
|
-
name: input.name,
|
|
233
|
-
description: input.description,
|
|
234
|
-
category: input.category,
|
|
235
|
-
pricing_model: input.pricing_model,
|
|
236
|
-
pricing_amount_minor: input.pricing_amount_minor ?? null,
|
|
237
|
-
currency: input.currency ?? null,
|
|
238
|
-
requires_human_approval: input.requires_human_approval ?? false,
|
|
239
|
-
supported_contexts: input.supported_contexts,
|
|
240
|
-
trust_level: input.trust_level ?? 'standard',
|
|
241
|
-
public_directory_visible: input.public_directory_visible,
|
|
242
|
-
source_revision: input.source_revision,
|
|
243
|
-
input_schema: input.input_schema ?? {},
|
|
244
|
-
output_schema: input.output_schema ?? {},
|
|
245
|
-
acting_for_org_id: input.acting_for_org_id ?? input.publisher_org_id,
|
|
246
|
-
},
|
|
247
|
-
confirm: true,
|
|
248
|
-
});
|
|
249
|
-
return res.data.capability;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Actions ------------------------------------------------------------------
|
|
253
|
-
|
|
254
|
-
async listActions(options: { state?: string; limit?: number } = {}): Promise<P2PActionRow[]> {
|
|
255
|
-
const res = await this.client.request<EnvelopeData<{ actions: P2PActionRow[] }>>({
|
|
256
|
-
service: 'p2p',
|
|
257
|
-
path: '/api/actions',
|
|
258
|
-
query: { state: options.state, limit: options.limit },
|
|
259
|
-
});
|
|
260
|
-
return res.data.actions;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async getAction(requestId: string): Promise<P2PActionDetail | null> {
|
|
264
|
-
if (!requestId) throw new Error('requestId is required');
|
|
265
|
-
try {
|
|
266
|
-
const res = await this.client.request<EnvelopeData<P2PActionDetail>>({
|
|
267
|
-
service: 'p2p',
|
|
268
|
-
path: `/api/actions/${encodeURIComponent(requestId)}`,
|
|
269
|
-
});
|
|
270
|
-
return res.data;
|
|
271
|
-
} catch (err) {
|
|
272
|
-
if (isNotFound(err)) return null;
|
|
273
|
-
throw err;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
async requestAction(input: P2PActionRequestInput): Promise<P2PActionRequestResult> {
|
|
278
|
-
if (!input.capability_id) throw new Error('capability_id is required');
|
|
279
|
-
if (!input.idempotency_key) throw new Error('idempotency_key is required');
|
|
280
|
-
const res = await this.client.request<EnvelopeData<P2PActionRequestResult>>({
|
|
281
|
-
service: 'p2p',
|
|
282
|
-
method: 'POST',
|
|
283
|
-
path: '/api/actions/request',
|
|
284
|
-
body: {
|
|
285
|
-
capability_id: input.capability_id,
|
|
286
|
-
idempotency_key: input.idempotency_key,
|
|
287
|
-
inputs: input.inputs ?? {},
|
|
288
|
-
},
|
|
289
|
-
confirm: true,
|
|
290
|
-
});
|
|
291
|
-
return res.data;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
async respondAction(
|
|
295
|
-
requestId: string,
|
|
296
|
-
response: 'accepted' | 'rejected' | 'approved' | 'quoted',
|
|
297
|
-
extras: Record<string, unknown> = {},
|
|
298
|
-
): Promise<P2PActionRow> {
|
|
299
|
-
if (!requestId) throw new Error('requestId is required');
|
|
300
|
-
const res = await this.client.request<EnvelopeData<{ request: P2PActionRow }>>({
|
|
301
|
-
service: 'p2p',
|
|
302
|
-
method: 'POST',
|
|
303
|
-
path: `/api/actions/${encodeURIComponent(requestId)}/respond`,
|
|
304
|
-
body: { response, ...extras },
|
|
305
|
-
confirm: true,
|
|
306
|
-
});
|
|
307
|
-
return res.data.request;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
async completeAction(requestId: string, result: Record<string, unknown> = {}): Promise<P2PActionRow> {
|
|
311
|
-
if (!requestId) throw new Error('requestId is required');
|
|
312
|
-
const res = await this.client.request<EnvelopeData<{ request: P2PActionRow }>>({
|
|
313
|
-
service: 'p2p',
|
|
314
|
-
method: 'POST',
|
|
315
|
-
path: `/api/actions/${encodeURIComponent(requestId)}/complete`,
|
|
316
|
-
body: { result },
|
|
317
|
-
confirm: true,
|
|
318
|
-
});
|
|
319
|
-
return res.data.request;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
async disputeAction(requestId: string, reason: string): Promise<P2PActionRow> {
|
|
323
|
-
if (!requestId) throw new Error('requestId is required');
|
|
324
|
-
const res = await this.client.request<EnvelopeData<{ request: P2PActionRow }>>({
|
|
325
|
-
service: 'p2p',
|
|
326
|
-
method: 'POST',
|
|
327
|
-
path: `/api/actions/${encodeURIComponent(requestId)}/dispute`,
|
|
328
|
-
body: { reason },
|
|
329
|
-
confirm: true,
|
|
330
|
-
});
|
|
331
|
-
return res.data.request;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// Policy + connections + ledger + settlement -----------------------------
|
|
335
|
-
|
|
336
|
-
async getPolicy(): Promise<P2PPolicy> {
|
|
337
|
-
const res = await this.client.request<EnvelopeData<{ policy: P2PPolicy }>>({
|
|
338
|
-
service: 'p2p',
|
|
339
|
-
path: '/api/policies',
|
|
340
|
-
});
|
|
341
|
-
return res.data.policy;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
async updatePolicy(policy: Partial<Omit<P2PPolicy, 'organization_id' | 'updated_at'>>): Promise<P2PPolicy> {
|
|
345
|
-
const res = await this.client.request<EnvelopeData<{ policy: P2PPolicy }>>({
|
|
346
|
-
service: 'p2p',
|
|
347
|
-
method: 'PUT',
|
|
348
|
-
path: '/api/policies',
|
|
349
|
-
body: policy,
|
|
350
|
-
confirm: true,
|
|
351
|
-
});
|
|
352
|
-
return res.data.policy;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
async listConnections(): Promise<P2PConnection[]> {
|
|
356
|
-
const res = await this.client.request<EnvelopeData<{ connections: P2PConnection[] }>>({
|
|
357
|
-
service: 'p2p',
|
|
358
|
-
path: '/api/connections',
|
|
359
|
-
});
|
|
360
|
-
return res.data.connections;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
async createConnection(
|
|
364
|
-
counterpartyOrgId: string,
|
|
365
|
-
options: { status?: 'pending' | 'active' | 'suspended' } = {},
|
|
366
|
-
): Promise<P2PConnection> {
|
|
367
|
-
if (!counterpartyOrgId) throw new Error('counterpartyOrgId is required');
|
|
368
|
-
const res = await this.client.request<EnvelopeData<{ connection: P2PConnection }>>({
|
|
369
|
-
service: 'p2p',
|
|
370
|
-
method: 'POST',
|
|
371
|
-
path: '/api/connections',
|
|
372
|
-
body: { counterparty_org_id: counterpartyOrgId, status: options.status ?? 'active' },
|
|
373
|
-
confirm: true,
|
|
374
|
-
});
|
|
375
|
-
return res.data.connection;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
async revokeConnection(connectionId: string): Promise<void> {
|
|
379
|
-
if (!connectionId) throw new Error('connectionId is required');
|
|
380
|
-
await this.client.request({
|
|
381
|
-
service: 'p2p',
|
|
382
|
-
method: 'DELETE',
|
|
383
|
-
path: `/api/connections/${encodeURIComponent(connectionId)}`,
|
|
384
|
-
confirm: true,
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
async listLedger(): Promise<P2PLedgerEntry[]> {
|
|
389
|
-
const res = await this.client.request<EnvelopeData<{ ledger_entries: P2PLedgerEntry[] }>>({
|
|
390
|
-
service: 'p2p',
|
|
391
|
-
path: '/api/ledger',
|
|
392
|
-
});
|
|
393
|
-
return res.data.ledger_entries;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
async previewSettlements(
|
|
397
|
-
filters: Partial<{ buyer_org_id: string; seller_org_id: string; currency: string }> = {},
|
|
398
|
-
): Promise<P2PSettlementGroup[]> {
|
|
399
|
-
const res = await this.client.request<EnvelopeData<{ groups: P2PSettlementGroup[] }>>({
|
|
400
|
-
service: 'p2p',
|
|
401
|
-
method: 'POST',
|
|
402
|
-
path: '/api/settlements/preview',
|
|
403
|
-
body: filters,
|
|
404
|
-
confirm: true,
|
|
405
|
-
});
|
|
406
|
-
return res.data.groups;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
async createSettlement(
|
|
410
|
-
filters: Partial<{
|
|
411
|
-
buyer_org_id: string;
|
|
412
|
-
seller_org_id: string;
|
|
413
|
-
currency: string;
|
|
414
|
-
trigger: 'threshold' | 'schedule' | 'manual' | 'invoice' | 'delivery';
|
|
415
|
-
}> = {},
|
|
416
|
-
): Promise<{ batch: P2PSettlementBatch; group: P2PSettlementGroup }> {
|
|
417
|
-
const res = await this.client.request<EnvelopeData<{ batch: P2PSettlementBatch; group: P2PSettlementGroup }>>({
|
|
418
|
-
service: 'p2p',
|
|
419
|
-
method: 'POST',
|
|
420
|
-
path: '/api/settlements/create',
|
|
421
|
-
body: { trigger: 'manual', ...filters },
|
|
422
|
-
confirm: true,
|
|
423
|
-
});
|
|
424
|
-
return res.data;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
async releaseHold(
|
|
428
|
-
holdId: string,
|
|
429
|
-
resolution: 'buyer' | 'seller',
|
|
430
|
-
options: { reason?: string } = {},
|
|
431
|
-
): Promise<{ hold: P2PHold; resolution: 'buyer' | 'seller'; cancel_entries: P2PLedgerEntry[] }> {
|
|
432
|
-
if (!holdId) throw new Error('holdId is required');
|
|
433
|
-
const res = await this.client.request<
|
|
434
|
-
EnvelopeData<{ hold: P2PHold; resolution: 'buyer' | 'seller'; cancel_entries: P2PLedgerEntry[] }>
|
|
435
|
-
>({
|
|
436
|
-
service: 'p2p',
|
|
437
|
-
method: 'POST',
|
|
438
|
-
path: `/api/holds/${encodeURIComponent(holdId)}/release`,
|
|
439
|
-
body: { resolution, reason: options.reason ?? null },
|
|
440
|
-
confirm: true,
|
|
441
|
-
});
|
|
442
|
-
return res.data;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
function isNotFound(err: unknown): boolean {
|
|
447
|
-
return Boolean(err && typeof err === 'object' && 'status' in err && (err as { status?: number }).status === 404);
|
|
448
|
-
}
|