@medialane/sdk 0.3.2 → 0.4.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/dist/index.js CHANGED
@@ -6,6 +6,8 @@ import { TypedDataRevision, shortString, cairo, Contract, constants, RpcProvider
6
6
  // src/constants.ts
7
7
  var MARKETPLACE_CONTRACT_MAINNET = "0x04299b51289aa700de4ce19cc77bcea8430bfd1aef04193efab09d60a3a7ee0f";
8
8
  var COLLECTION_CONTRACT_MAINNET = "0x05e73b7be06d82beeb390a0e0d655f2c9e7cf519658e04f05d9c690ccc41da03";
9
+ var MARKETPLACE_CONTRACT_SEPOLIA = "";
10
+ var COLLECTION_CONTRACT_SEPOLIA = "";
9
11
  var SUPPORTED_TOKENS = [
10
12
  {
11
13
  // Circle-native USDC on Starknet (canonical — preferred)
@@ -42,122 +44,6 @@ var DEFAULT_RPC_URLS = {
42
44
  sepolia: "https://rpc.starknet-sepolia.lava.build"
43
45
  };
44
46
 
45
- // src/config.ts
46
- var MedialaneConfigSchema = z.object({
47
- network: z.enum(SUPPORTED_NETWORKS).default("mainnet"),
48
- rpcUrl: z.string().url().optional(),
49
- backendUrl: z.string().url().optional(),
50
- /** API key for authenticated /v1/* backend endpoints */
51
- apiKey: z.string().optional(),
52
- marketplaceContract: z.string().optional(),
53
- collectionContract: z.string().optional()
54
- });
55
- function resolveConfig(raw) {
56
- const parsed = MedialaneConfigSchema.parse(raw);
57
- return {
58
- network: parsed.network,
59
- rpcUrl: parsed.rpcUrl ?? DEFAULT_RPC_URLS[parsed.network],
60
- backendUrl: parsed.backendUrl,
61
- apiKey: parsed.apiKey,
62
- marketplaceContract: parsed.marketplaceContract ?? MARKETPLACE_CONTRACT_MAINNET,
63
- collectionContract: parsed.collectionContract ?? COLLECTION_CONTRACT_MAINNET
64
- };
65
- }
66
- function buildOrderTypedData(message, chainId) {
67
- return {
68
- domain: {
69
- name: "Medialane",
70
- version: "1",
71
- chainId,
72
- revision: TypedDataRevision.ACTIVE
73
- },
74
- primaryType: "OrderParameters",
75
- types: {
76
- StarknetDomain: [
77
- { name: "name", type: "shortstring" },
78
- { name: "version", type: "shortstring" },
79
- { name: "chainId", type: "shortstring" },
80
- { name: "revision", type: "shortstring" }
81
- ],
82
- OrderParameters: [
83
- { name: "offerer", type: "ContractAddress" },
84
- { name: "offer", type: "OfferItem" },
85
- { name: "consideration", type: "ConsiderationItem" },
86
- { name: "start_time", type: "felt" },
87
- { name: "end_time", type: "felt" },
88
- { name: "salt", type: "felt" },
89
- { name: "nonce", type: "felt" }
90
- ],
91
- OfferItem: [
92
- { name: "item_type", type: "shortstring" },
93
- { name: "token", type: "ContractAddress" },
94
- { name: "identifier_or_criteria", type: "felt" },
95
- { name: "start_amount", type: "felt" },
96
- { name: "end_amount", type: "felt" }
97
- ],
98
- ConsiderationItem: [
99
- { name: "item_type", type: "shortstring" },
100
- { name: "token", type: "ContractAddress" },
101
- { name: "identifier_or_criteria", type: "felt" },
102
- { name: "start_amount", type: "felt" },
103
- { name: "end_amount", type: "felt" },
104
- { name: "recipient", type: "ContractAddress" }
105
- ]
106
- },
107
- message
108
- };
109
- }
110
- function buildFulfillmentTypedData(message, chainId) {
111
- return {
112
- domain: {
113
- name: "Medialane",
114
- version: "1",
115
- chainId,
116
- revision: TypedDataRevision.ACTIVE
117
- },
118
- primaryType: "OrderFulfillment",
119
- types: {
120
- StarknetDomain: [
121
- { name: "name", type: "shortstring" },
122
- { name: "version", type: "shortstring" },
123
- { name: "chainId", type: "shortstring" },
124
- { name: "revision", type: "shortstring" }
125
- ],
126
- OrderFulfillment: [
127
- { name: "order_hash", type: "felt" },
128
- { name: "fulfiller", type: "ContractAddress" },
129
- { name: "nonce", type: "felt" }
130
- ]
131
- },
132
- message
133
- };
134
- }
135
- function buildCancellationTypedData(message, chainId) {
136
- return {
137
- domain: {
138
- name: "Medialane",
139
- version: "1",
140
- chainId,
141
- revision: TypedDataRevision.ACTIVE
142
- },
143
- primaryType: "OrderCancellation",
144
- types: {
145
- StarknetDomain: [
146
- { name: "name", type: "shortstring" },
147
- { name: "version", type: "shortstring" },
148
- { name: "chainId", type: "shortstring" },
149
- { name: "revision", type: "shortstring" }
150
- ],
151
- OrderCancellation: [
152
- { name: "order_hash", type: "felt" },
153
- { name: "offerer", type: "ContractAddress" },
154
- { name: "nonce", type: "felt" }
155
- ]
156
- },
157
- message
158
- };
159
- }
160
-
161
47
  // src/abis.ts
162
48
  var IPMarketplaceABI = [
163
49
  {
@@ -510,11 +396,106 @@ function getTokenBySymbol(symbol) {
510
396
  const upper = symbol.toUpperCase();
511
397
  return SUPPORTED_TOKENS.find((t) => t.symbol === upper);
512
398
  }
399
+ function buildOrderTypedData(message, chainId) {
400
+ return {
401
+ domain: {
402
+ name: "Medialane",
403
+ version: "1",
404
+ chainId,
405
+ revision: TypedDataRevision.ACTIVE
406
+ },
407
+ primaryType: "OrderParameters",
408
+ types: {
409
+ StarknetDomain: [
410
+ { name: "name", type: "shortstring" },
411
+ { name: "version", type: "shortstring" },
412
+ { name: "chainId", type: "shortstring" },
413
+ { name: "revision", type: "shortstring" }
414
+ ],
415
+ OrderParameters: [
416
+ { name: "offerer", type: "ContractAddress" },
417
+ { name: "offer", type: "OfferItem" },
418
+ { name: "consideration", type: "ConsiderationItem" },
419
+ { name: "start_time", type: "felt" },
420
+ { name: "end_time", type: "felt" },
421
+ { name: "salt", type: "felt" },
422
+ { name: "nonce", type: "felt" }
423
+ ],
424
+ OfferItem: [
425
+ { name: "item_type", type: "shortstring" },
426
+ { name: "token", type: "ContractAddress" },
427
+ { name: "identifier_or_criteria", type: "felt" },
428
+ { name: "start_amount", type: "felt" },
429
+ { name: "end_amount", type: "felt" }
430
+ ],
431
+ ConsiderationItem: [
432
+ { name: "item_type", type: "shortstring" },
433
+ { name: "token", type: "ContractAddress" },
434
+ { name: "identifier_or_criteria", type: "felt" },
435
+ { name: "start_amount", type: "felt" },
436
+ { name: "end_amount", type: "felt" },
437
+ { name: "recipient", type: "ContractAddress" }
438
+ ]
439
+ },
440
+ message
441
+ };
442
+ }
443
+ function buildFulfillmentTypedData(message, chainId) {
444
+ return {
445
+ domain: {
446
+ name: "Medialane",
447
+ version: "1",
448
+ chainId,
449
+ revision: TypedDataRevision.ACTIVE
450
+ },
451
+ primaryType: "OrderFulfillment",
452
+ types: {
453
+ StarknetDomain: [
454
+ { name: "name", type: "shortstring" },
455
+ { name: "version", type: "shortstring" },
456
+ { name: "chainId", type: "shortstring" },
457
+ { name: "revision", type: "shortstring" }
458
+ ],
459
+ OrderFulfillment: [
460
+ { name: "order_hash", type: "felt" },
461
+ { name: "fulfiller", type: "ContractAddress" },
462
+ { name: "nonce", type: "felt" }
463
+ ]
464
+ },
465
+ message
466
+ };
467
+ }
468
+ function buildCancellationTypedData(message, chainId) {
469
+ return {
470
+ domain: {
471
+ name: "Medialane",
472
+ version: "1",
473
+ chainId,
474
+ revision: TypedDataRevision.ACTIVE
475
+ },
476
+ primaryType: "OrderCancellation",
477
+ types: {
478
+ StarknetDomain: [
479
+ { name: "name", type: "shortstring" },
480
+ { name: "version", type: "shortstring" },
481
+ { name: "chainId", type: "shortstring" },
482
+ { name: "revision", type: "shortstring" }
483
+ ],
484
+ OrderCancellation: [
485
+ { name: "order_hash", type: "felt" },
486
+ { name: "offerer", type: "ContractAddress" },
487
+ { name: "nonce", type: "felt" }
488
+ ]
489
+ },
490
+ message
491
+ };
492
+ }
513
493
 
514
494
  // src/marketplace/orders.ts
515
495
  var MedialaneError = class extends Error {
516
- constructor(message, cause) {
496
+ constructor(message, code = "UNKNOWN", cause) {
517
497
  super(message);
498
+ this.code = code;
518
499
  this.cause = cause;
519
500
  this.name = "MedialaneError";
520
501
  }
@@ -554,7 +535,7 @@ function resolveToken(currency) {
554
535
  const token = SUPPORTED_TOKENS.find(
555
536
  (t) => t.symbol === currency.toUpperCase() || t.address.toLowerCase() === currency.toLowerCase()
556
537
  );
557
- if (!token) throw new MedialaneError(`Unsupported currency: ${currency}`);
538
+ if (!token) throw new MedialaneError(`Unsupported currency: ${currency}`, "INVALID_PARAMS");
558
539
  return token;
559
540
  }
560
541
  async function createListing(account, params, config) {
@@ -638,7 +619,7 @@ async function createListing(account, params, config) {
638
619
  await provider.waitForTransaction(tx.transaction_hash);
639
620
  return { txHash: tx.transaction_hash };
640
621
  } catch (err) {
641
- throw new MedialaneError("Failed to create listing", err);
622
+ throw new MedialaneError("Failed to create listing", "TRANSACTION_FAILED", err);
642
623
  }
643
624
  }
644
625
  async function makeOffer(account, params, config) {
@@ -709,7 +690,7 @@ async function makeOffer(account, params, config) {
709
690
  await provider.waitForTransaction(tx.transaction_hash);
710
691
  return { txHash: tx.transaction_hash };
711
692
  } catch (err) {
712
- throw new MedialaneError("Failed to make offer", err);
693
+ throw new MedialaneError("Failed to make offer", "TRANSACTION_FAILED", err);
713
694
  }
714
695
  }
715
696
  async function fulfillOrder(account, params, config) {
@@ -737,7 +718,7 @@ async function fulfillOrder(account, params, config) {
737
718
  await provider.waitForTransaction(tx.transaction_hash);
738
719
  return { txHash: tx.transaction_hash };
739
720
  } catch (err) {
740
- throw new MedialaneError("Failed to fulfill order", err);
721
+ throw new MedialaneError("Failed to fulfill order", "TRANSACTION_FAILED", err);
741
722
  }
742
723
  }
743
724
  async function cancelOrder(account, params, config) {
@@ -765,7 +746,7 @@ async function cancelOrder(account, params, config) {
765
746
  await provider.waitForTransaction(tx.transaction_hash);
766
747
  return { txHash: tx.transaction_hash };
767
748
  } catch (err) {
768
- throw new MedialaneError("Failed to cancel order", err);
749
+ throw new MedialaneError("Failed to cancel order", "TRANSACTION_FAILED", err);
769
750
  }
770
751
  }
771
752
  function encodeByteArray(str) {
@@ -788,7 +769,7 @@ async function mint(account, params, config) {
788
769
  await provider.waitForTransaction(tx.transaction_hash);
789
770
  return { txHash: tx.transaction_hash };
790
771
  } catch (err) {
791
- throw new MedialaneError("Failed to mint NFT", err);
772
+ throw new MedialaneError("Failed to mint NFT", "TRANSACTION_FAILED", err);
792
773
  }
793
774
  }
794
775
  async function createCollection(account, params, config) {
@@ -805,11 +786,11 @@ async function createCollection(account, params, config) {
805
786
  await provider.waitForTransaction(tx.transaction_hash);
806
787
  return { txHash: tx.transaction_hash };
807
788
  } catch (err) {
808
- throw new MedialaneError("Failed to create collection", err);
789
+ throw new MedialaneError("Failed to create collection", "TRANSACTION_FAILED", err);
809
790
  }
810
791
  }
811
792
  async function checkoutCart(account, items, config) {
812
- if (items.length === 0) throw new MedialaneError("Cart is empty");
793
+ if (items.length === 0) throw new MedialaneError("Cart is empty", "INVALID_PARAMS");
813
794
  const { contract, provider } = makeContract(config);
814
795
  const tokenTotals = /* @__PURE__ */ new Map();
815
796
  for (const item of items) {
@@ -856,10 +837,49 @@ async function checkoutCart(account, items, config) {
856
837
  await provider.waitForTransaction(tx.transaction_hash);
857
838
  return { txHash: tx.transaction_hash };
858
839
  } catch (err) {
859
- throw new MedialaneError("Cart checkout failed", err);
840
+ throw new MedialaneError("Cart checkout failed", "TRANSACTION_FAILED", err);
860
841
  }
861
842
  }
862
843
 
844
+ // src/config.ts
845
+ var MedialaneConfigSchema = z.object({
846
+ network: z.enum(SUPPORTED_NETWORKS).default("mainnet"),
847
+ rpcUrl: z.string().url().optional(),
848
+ backendUrl: z.string().url().optional(),
849
+ /** API key for authenticated /v1/* backend endpoints */
850
+ apiKey: z.string().optional(),
851
+ marketplaceContract: z.string().optional(),
852
+ collectionContract: z.string().optional(),
853
+ retryOptions: z.object({
854
+ maxAttempts: z.number().int().min(1).max(10).optional(),
855
+ baseDelayMs: z.number().int().min(0).optional(),
856
+ maxDelayMs: z.number().int().min(0).optional()
857
+ }).optional()
858
+ });
859
+ function resolveConfig(raw) {
860
+ const parsed = MedialaneConfigSchema.parse(raw);
861
+ const isMainnet = parsed.network === "mainnet";
862
+ const defaultMarketplace = isMainnet ? MARKETPLACE_CONTRACT_MAINNET : MARKETPLACE_CONTRACT_SEPOLIA;
863
+ const defaultCollection = isMainnet ? COLLECTION_CONTRACT_MAINNET : COLLECTION_CONTRACT_SEPOLIA;
864
+ const marketplaceContract = parsed.marketplaceContract ?? defaultMarketplace;
865
+ const collectionContract = parsed.collectionContract ?? defaultCollection;
866
+ if (!marketplaceContract || !collectionContract) {
867
+ throw new MedialaneError(
868
+ `Sepolia network is not yet supported: marketplace and collection contract addresses are not configured. Pass 'marketplaceContract' and 'collectionContract' explicitly in your MedialaneClient config.`,
869
+ "NETWORK_NOT_SUPPORTED"
870
+ );
871
+ }
872
+ return {
873
+ network: parsed.network,
874
+ rpcUrl: parsed.rpcUrl ?? DEFAULT_RPC_URLS[parsed.network],
875
+ backendUrl: parsed.backendUrl,
876
+ apiKey: parsed.apiKey,
877
+ marketplaceContract,
878
+ collectionContract,
879
+ retryOptions: parsed.retryOptions
880
+ };
881
+ }
882
+
863
883
  // src/marketplace/index.ts
864
884
  var MarketplaceModule = class {
865
885
  constructor(config) {
@@ -909,18 +929,60 @@ function shortenAddress(address, chars = 4) {
909
929
  return `${norm.slice(0, chars + 2)}...${norm.slice(-chars)}`;
910
930
  }
911
931
 
932
+ // src/utils/retry.ts
933
+ var DEFAULT_MAX_ATTEMPTS = 3;
934
+ var DEFAULT_BASE_DELAY_MS = 300;
935
+ var DEFAULT_MAX_DELAY_MS = 5e3;
936
+ function sleep(ms) {
937
+ return new Promise((resolve) => setTimeout(resolve, ms));
938
+ }
939
+ async function withRetry(fn, opts) {
940
+ const maxAttempts = opts?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
941
+ const baseDelayMs = opts?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS;
942
+ const maxDelayMs = opts?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
943
+ let lastError;
944
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
945
+ try {
946
+ return await fn();
947
+ } catch (err) {
948
+ lastError = err;
949
+ if (err instanceof MedialaneApiError && err.status < 500) {
950
+ throw err;
951
+ }
952
+ const isRetryable = err instanceof MedialaneApiError && err.status >= 500 || err instanceof TypeError;
953
+ if (!isRetryable || attempt === maxAttempts - 1) {
954
+ throw err;
955
+ }
956
+ const jitter = Math.random() * baseDelayMs;
957
+ const delay = Math.min(baseDelayMs * Math.pow(2, attempt) + jitter, maxDelayMs);
958
+ await sleep(delay);
959
+ }
960
+ }
961
+ throw lastError;
962
+ }
963
+
912
964
  // src/api/client.ts
965
+ function deriveErrorCode(status) {
966
+ if (status === 404) return "TOKEN_NOT_FOUND";
967
+ if (status === 429) return "RATE_LIMITED";
968
+ if (status === 410) return "INTENT_EXPIRED";
969
+ if (status === 401 || status === 403) return "UNAUTHORIZED";
970
+ if (status === 400) return "INVALID_PARAMS";
971
+ return "UNKNOWN";
972
+ }
913
973
  var MedialaneApiError = class extends Error {
914
974
  constructor(status, message) {
915
975
  super(message);
916
976
  this.status = status;
917
977
  this.name = "MedialaneApiError";
978
+ this.code = deriveErrorCode(status);
918
979
  }
919
980
  };
920
981
  var ApiClient = class {
921
- constructor(baseUrl, apiKey) {
982
+ constructor(baseUrl, apiKey, retryOptions) {
922
983
  this.baseUrl = baseUrl;
923
984
  this.baseHeaders = apiKey ? { "x-api-key": apiKey } : {};
985
+ this.retryOptions = retryOptions;
924
986
  }
925
987
  async request(path, init) {
926
988
  const url = `${this.baseUrl.replace(/\/$/, "")}${path}`;
@@ -928,19 +990,23 @@ var ApiClient = class {
928
990
  if (!(init?.body instanceof FormData)) {
929
991
  headers["Content-Type"] = "application/json";
930
992
  }
931
- const res = await fetch(url, {
932
- ...init,
933
- headers: { ...headers, ...init?.headers }
934
- });
935
- if (!res.ok) {
936
- let message = res.statusText;
937
- try {
938
- const body = await res.json();
939
- if (body.error) message = body.error;
940
- } catch {
993
+ const res = await withRetry(async () => {
994
+ const response = await fetch(url, {
995
+ ...init,
996
+ headers: { ...headers, ...init?.headers }
997
+ });
998
+ if (!response.ok) {
999
+ const text = await response.text().catch(() => response.statusText);
1000
+ let message = text;
1001
+ try {
1002
+ const body = JSON.parse(text);
1003
+ if (body.error) message = body.error;
1004
+ } catch {
1005
+ }
1006
+ throw new MedialaneApiError(response.status, message);
941
1007
  }
942
- throw new MedialaneApiError(res.status, message);
943
- }
1008
+ return response;
1009
+ }, this.retryOptions);
944
1010
  return res.json();
945
1011
  }
946
1012
  get(path) {
@@ -998,9 +1064,10 @@ var ApiClient = class {
998
1064
  );
999
1065
  }
1000
1066
  // ─── Collections ───────────────────────────────────────────────────────────
1001
- getCollections(page = 1, limit = 20, isKnown) {
1067
+ getCollections(page = 1, limit = 20, isKnown, sort) {
1002
1068
  const params = new URLSearchParams({ page: String(page), limit: String(limit) });
1003
1069
  if (isKnown !== void 0) params.set("isKnown", String(isKnown));
1070
+ if (sort) params.set("sort", sort);
1004
1071
  return this.get(`/v1/collections?${params}`);
1005
1072
  }
1006
1073
  getCollectionsByOwner(owner, page = 1, limit = 50) {
@@ -1107,6 +1174,79 @@ var ApiClient = class {
1107
1174
  `/v1/portal/webhooks/${id}`
1108
1175
  );
1109
1176
  }
1177
+ // ─── Collection Claims ──────────────────────────────────────────────────────
1178
+ /**
1179
+ * Path 1: On-chain auto claim. Sends both x-api-key (tenant auth) and
1180
+ * Authorization: Bearer (Clerk JWT) simultaneously.
1181
+ */
1182
+ async claimCollection(contractAddress, walletAddress, clerkToken) {
1183
+ const url = `${this.baseUrl.replace(/\/$/, "")}/v1/collections/claim`;
1184
+ const res = await fetch(url, {
1185
+ method: "POST",
1186
+ headers: {
1187
+ "x-api-key": this.baseHeaders["x-api-key"] ?? "",
1188
+ "Content-Type": "application/json",
1189
+ "Authorization": `Bearer ${clerkToken}`
1190
+ },
1191
+ body: JSON.stringify({ contractAddress, walletAddress })
1192
+ });
1193
+ return res.json();
1194
+ }
1195
+ /**
1196
+ * Path 3: Manual off-chain claim request (email-based).
1197
+ */
1198
+ requestCollectionClaim(params) {
1199
+ return this.request("/v1/collections/claim/request", {
1200
+ method: "POST",
1201
+ body: JSON.stringify(params)
1202
+ });
1203
+ }
1204
+ // ─── Collection Profiles ────────────────────────────────────────────────────
1205
+ async getCollectionProfile(contractAddress) {
1206
+ const url = `${this.baseUrl.replace(/\/$/, "")}/v1/collections/${normalizeAddress(contractAddress)}/profile`;
1207
+ const res = await fetch(url, { headers: this.baseHeaders });
1208
+ if (res.status === 404) return null;
1209
+ return res.json();
1210
+ }
1211
+ /**
1212
+ * Update collection profile. Requires Clerk JWT for ownership check.
1213
+ */
1214
+ async updateCollectionProfile(contractAddress, data, clerkToken) {
1215
+ const url = `${this.baseUrl.replace(/\/$/, "")}/v1/collections/${normalizeAddress(contractAddress)}/profile`;
1216
+ const res = await fetch(url, {
1217
+ method: "PATCH",
1218
+ headers: {
1219
+ "x-api-key": this.baseHeaders["x-api-key"] ?? "",
1220
+ "Content-Type": "application/json",
1221
+ "Authorization": `Bearer ${clerkToken}`
1222
+ },
1223
+ body: JSON.stringify(data)
1224
+ });
1225
+ return res.json();
1226
+ }
1227
+ // ─── Creator Profiles ───────────────────────────────────────────────────────
1228
+ async getCreatorProfile(walletAddress) {
1229
+ const url = `${this.baseUrl.replace(/\/$/, "")}/v1/creators/${normalizeAddress(walletAddress)}/profile`;
1230
+ const res = await fetch(url, { headers: this.baseHeaders });
1231
+ if (res.status === 404) return null;
1232
+ return res.json();
1233
+ }
1234
+ /**
1235
+ * Update creator profile. Requires Clerk JWT; wallet must match authenticated user.
1236
+ */
1237
+ async updateCreatorProfile(walletAddress, data, clerkToken) {
1238
+ const url = `${this.baseUrl.replace(/\/$/, "")}/v1/creators/${normalizeAddress(walletAddress)}/profile`;
1239
+ const res = await fetch(url, {
1240
+ method: "PATCH",
1241
+ headers: {
1242
+ "x-api-key": this.baseHeaders["x-api-key"] ?? "",
1243
+ "Content-Type": "application/json",
1244
+ "Authorization": `Bearer ${clerkToken}`
1245
+ },
1246
+ body: JSON.stringify(data)
1247
+ });
1248
+ return res.json();
1249
+ }
1110
1250
  };
1111
1251
 
1112
1252
  // src/client.ts
@@ -1125,7 +1265,7 @@ var MedialaneClient = class {
1125
1265
  }
1126
1266
  });
1127
1267
  } else {
1128
- this.api = new ApiClient(this.config.backendUrl, this.config.apiKey);
1268
+ this.api = new ApiClient(this.config.backendUrl, this.config.apiKey, this.config.retryOptions);
1129
1269
  }
1130
1270
  }
1131
1271
  get network() {