@thirdweb-dev/service-utils 0.5.0-nightly-0f027069-20230828164852 → 0.5.0-nightly-6cf298a29-20240308012322

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 (37) hide show
  1. package/cf-worker/dist/thirdweb-dev-service-utils-cf-worker.cjs.dev.js +59 -27
  2. package/cf-worker/dist/thirdweb-dev-service-utils-cf-worker.cjs.prod.js +59 -27
  3. package/cf-worker/dist/thirdweb-dev-service-utils-cf-worker.esm.js +58 -27
  4. package/dist/declarations/src/cf-worker/index.d.ts +6 -3
  5. package/dist/declarations/src/cf-worker/index.d.ts.map +1 -1
  6. package/dist/declarations/src/cf-worker/usage.d.ts +75 -12
  7. package/dist/declarations/src/cf-worker/usage.d.ts.map +1 -1
  8. package/dist/declarations/src/core/api.d.ts +37 -1
  9. package/dist/declarations/src/core/api.d.ts.map +1 -1
  10. package/dist/declarations/src/core/authorize/client.d.ts.map +1 -1
  11. package/dist/declarations/src/core/authorize/index.d.ts.map +1 -1
  12. package/dist/declarations/src/core/authorize/service.d.ts.map +1 -1
  13. package/dist/declarations/src/core/rateLimit/index.d.ts +20 -0
  14. package/dist/declarations/src/core/rateLimit/index.d.ts.map +1 -0
  15. package/dist/declarations/src/core/rateLimit/types.d.ts +13 -0
  16. package/dist/declarations/src/core/rateLimit/types.d.ts.map +1 -0
  17. package/dist/declarations/src/core/services.d.ts +49 -1
  18. package/dist/declarations/src/core/services.d.ts.map +1 -1
  19. package/dist/declarations/src/core/usageLimit/index.d.ts +5 -0
  20. package/dist/declarations/src/core/usageLimit/index.d.ts.map +1 -0
  21. package/dist/declarations/src/core/usageLimit/types.d.ts +9 -0
  22. package/dist/declarations/src/core/usageLimit/types.d.ts.map +1 -0
  23. package/dist/declarations/src/node/index.d.ts +23 -3
  24. package/dist/declarations/src/node/index.d.ts.map +1 -1
  25. package/dist/{index-ffddf746.esm.js → index-3b9a0743.esm.js} +170 -20
  26. package/dist/{index-6e0ecc5f.cjs.prod.js → index-62b88cac.cjs.dev.js} +171 -19
  27. package/dist/{index-cd4f96ef.cjs.dev.js → index-aa324361.cjs.prod.js} +171 -19
  28. package/dist/{services-86283509.esm.js → services-2aecbda8.esm.js} +21 -0
  29. package/dist/{services-9e185105.cjs.prod.js → services-508322f3.cjs.dev.js} +21 -0
  30. package/dist/{services-a3f36057.cjs.dev.js → services-5c4d6977.cjs.prod.js} +21 -0
  31. package/dist/thirdweb-dev-service-utils.cjs.dev.js +1 -1
  32. package/dist/thirdweb-dev-service-utils.cjs.prod.js +1 -1
  33. package/dist/thirdweb-dev-service-utils.esm.js +1 -1
  34. package/node/dist/thirdweb-dev-service-utils-node.cjs.dev.js +50 -24
  35. package/node/dist/thirdweb-dev-service-utils-node.cjs.prod.js +50 -24
  36. package/node/dist/thirdweb-dev-service-utils-node.esm.js +49 -24
  37. package/package.json +9 -8
@@ -4,9 +4,12 @@ async function fetchKeyMetadataFromApi(clientId, config) {
4
4
  const {
5
5
  apiUrl,
6
6
  serviceScope,
7
- serviceApiKey
7
+ serviceApiKey,
8
+ checkPolicy,
9
+ policyMetadata
8
10
  } = config;
9
- const url = `${apiUrl}/v1/keys/use?clientId=${clientId}&scope=${serviceScope}`;
11
+ const policyQuery = checkPolicy && policyMetadata ? `&checkPolicy=true&policyMetadata=${encodeURIComponent(JSON.stringify(policyMetadata))}` : "";
12
+ const url = `${apiUrl}/v1/keys/use?clientId=${clientId}&scope=${serviceScope}&includeUsage=true${policyQuery}`;
10
13
  const response = await fetch(url, {
11
14
  method: "GET",
12
15
  headers: {
@@ -14,20 +17,20 @@ async function fetchKeyMetadataFromApi(clientId, config) {
14
17
  "content-type": "application/json"
15
18
  }
16
19
  });
17
- let json;
20
+ let text = "";
18
21
  try {
19
- json = await response.json();
22
+ text = await response.text();
23
+ return JSON.parse(text);
20
24
  } catch (e) {
21
- throw new Error(`Error fetching key metadata from API: ${response.status} - ${response.statusText} - ${await response.text()}`);
25
+ throw new Error(`Error fetching key metadata from API: ${response.status} - ${text}`);
22
26
  }
23
- return json;
24
27
  }
25
28
  async function fetchAccountFromApi(jwt, config, useWalletAuth) {
26
29
  const {
27
30
  apiUrl,
28
31
  serviceApiKey
29
32
  } = config;
30
- const url = useWalletAuth ? `${apiUrl}/v1/wallet/me` : `${apiUrl}/v1/account/me`;
33
+ const url = useWalletAuth ? `${apiUrl}/v1/wallet/me?includeUsage=true` : `${apiUrl}/v1/account/me?includeUsage=true`;
31
34
  const response = await fetch(url, {
32
35
  method: "GET",
33
36
  headers: {
@@ -36,13 +39,32 @@ async function fetchAccountFromApi(jwt, config, useWalletAuth) {
36
39
  authorization: `Bearer ${jwt}`
37
40
  }
38
41
  });
39
- let json;
42
+ let text = "";
40
43
  try {
41
- json = await response.json();
44
+ text = await response.text();
45
+ return JSON.parse(text);
42
46
  } catch (e) {
43
- throw new Error(`Error fetching account from API: ${response.status} - ${response.statusText} - ${await response.text()}`);
47
+ throw new Error(`Error fetching account from API: ${response.status} - ${text}`);
44
48
  }
45
- return json;
49
+ }
50
+ async function updateRateLimitedAt(apiKeyId, config) {
51
+ const {
52
+ apiUrl,
53
+ serviceScope: scope,
54
+ serviceApiKey
55
+ } = config;
56
+ const url = `${apiUrl}/usage/rateLimit`;
57
+ await fetch(url, {
58
+ method: "PUT",
59
+ headers: {
60
+ "x-service-api-key": serviceApiKey,
61
+ "content-type": "application/json"
62
+ },
63
+ body: JSON.stringify({
64
+ apiKeyId,
65
+ scope
66
+ })
67
+ });
46
68
  }
47
69
 
48
70
  function authorizeClient(authOptions, apiKeyMeta) {
@@ -63,7 +85,10 @@ function authorizeClient(authOptions, apiKeyMeta) {
63
85
  id: apiKeyMeta.accountId,
64
86
  // TODO update this later
65
87
  name: "",
66
- creatorWalletAddress: apiKeyMeta.creatorWalletAddress
88
+ creatorWalletAddress: apiKeyMeta.creatorWalletAddress,
89
+ limits: apiKeyMeta.limits,
90
+ rateLimits: apiKeyMeta.rateLimits,
91
+ usage: apiKeyMeta.usage
67
92
  }
68
93
  };
69
94
 
@@ -193,12 +218,15 @@ function authorizeService(apiKeyMetadata, serviceConfig, authorizationPayload) {
193
218
  }
194
219
  return {
195
220
  authorized: true,
221
+ apiKeyMeta: apiKeyMetadata,
196
222
  accountMeta: {
197
223
  id: apiKeyMetadata.accountId,
198
224
  name: "",
199
- creatorWalletAddress: apiKeyMetadata.creatorWalletAddress
200
- },
201
- apiKeyMeta: apiKeyMetadata
225
+ creatorWalletAddress: apiKeyMetadata.creatorWalletAddress,
226
+ limits: apiKeyMetadata.limits,
227
+ rateLimits: apiKeyMetadata.rateLimits,
228
+ usage: apiKeyMetadata.usage
229
+ }
202
230
  };
203
231
  }
204
232
 
@@ -236,9 +264,9 @@ async function authorize(authData, serviceConfig, cacheOptions) {
236
264
  // if the difference is greater than the cacheTtl we want to ignore the cached data
237
265
  const now = Date.now();
238
266
  const diff = now - parsed.updatedAt;
239
- const cacheTtl = cacheOptions.cacheTtlSeconds * 1000;
267
+ const cacheTtlMs = cacheOptions.cacheTtlSeconds * 1000;
240
268
  // only if the diff is less than the cacheTtl do we want to use the cached key
241
- if (diff < cacheTtl * 1000) {
269
+ if (diff < cacheTtlMs) {
242
270
  accountMeta = parsed.apiKeyMeta;
243
271
  }
244
272
  } else {
@@ -322,9 +350,9 @@ async function authorize(authData, serviceConfig, cacheOptions) {
322
350
  // if the difference is greater than the cacheTtl we want to ignore the cached data
323
351
  const now = Date.now();
324
352
  const diff = now - parsed.updatedAt;
325
- const cacheTtl = cacheOptions.cacheTtlSeconds * 1000;
353
+ const cacheTtlMs = cacheOptions.cacheTtlSeconds * 1000;
326
354
  // only if the diff is less than the cacheTtl do we want to use the cached key
327
- if (diff < cacheTtl * 1000) {
355
+ if (diff < cacheTtlMs) {
328
356
  apiKeyMeta = parsed.apiKeyMeta;
329
357
  }
330
358
  } else {
@@ -416,9 +444,133 @@ async function authorize(authData, serviceConfig, cacheOptions) {
416
444
  id: apiKeyMeta.accountId,
417
445
  // TODO update this later
418
446
  name: "",
447
+ limits: apiKeyMeta.limits,
448
+ rateLimits: apiKeyMeta.rateLimits,
449
+ usage: apiKeyMeta.usage,
419
450
  creatorWalletAddress: apiKeyMeta.creatorWalletAddress
420
451
  }
421
452
  };
422
453
  }
423
454
 
455
+ const RATE_LIMIT_WINDOW_SECONDS = 10;
456
+
457
+ // Redis interface compatible with ioredis (Node) and upstash (Cloudflare Workers).
458
+
459
+ async function rateLimit(args) {
460
+ const {
461
+ authzResult,
462
+ serviceConfig,
463
+ redis,
464
+ sampleRate = 1.0
465
+ } = args;
466
+ const shouldSampleRequest = Math.random() < sampleRate;
467
+ if (!shouldSampleRequest || !authzResult.authorized) {
468
+ return {
469
+ rateLimited: false,
470
+ requestCount: 0,
471
+ rateLimit: 0
472
+ };
473
+ }
474
+ const {
475
+ apiKeyMeta,
476
+ accountMeta
477
+ } = authzResult;
478
+ const accountId = apiKeyMeta?.accountId || accountMeta?.id;
479
+ const {
480
+ serviceScope
481
+ } = serviceConfig;
482
+ const limitPerSecond = apiKeyMeta?.rateLimits?.[serviceScope] ?? accountMeta?.rateLimits?.[serviceScope];
483
+ if (!limitPerSecond) {
484
+ // No rate limit is provided. Assume the request is not rate limited.
485
+ return {
486
+ rateLimited: false,
487
+ requestCount: 0,
488
+ rateLimit: 0
489
+ };
490
+ }
491
+
492
+ // Gets the 10-second window for the current timestamp.
493
+ const timestampWindow = Math.floor(Date.now() / (1000 * RATE_LIMIT_WINDOW_SECONDS)) * RATE_LIMIT_WINDOW_SECONDS;
494
+ const key = `rate-limit:${serviceScope}:${accountId}:${timestampWindow}`;
495
+
496
+ // Increment and get the current request count in this window.
497
+ const requestCount = await redis.incr(key);
498
+ if (requestCount === 1) {
499
+ // For the first increment, set an expiration to clean up this key.
500
+ await redis.expire(key, RATE_LIMIT_WINDOW_SECONDS);
501
+ }
502
+
503
+ // Get the limit for this window accounting for the sample rate.
504
+ const limitPerWindow = limitPerSecond * sampleRate * RATE_LIMIT_WINDOW_SECONDS;
505
+ if (requestCount > limitPerWindow) {
506
+ // Report rate limit hits.
507
+ if (apiKeyMeta?.id) {
508
+ await updateRateLimitedAt(apiKeyMeta.id, serviceConfig);
509
+ }
510
+
511
+ // Reject requests when they've exceeded 2x the rate limit.
512
+ if (requestCount > 2 * limitPerWindow) {
513
+ return {
514
+ rateLimited: true,
515
+ requestCount,
516
+ rateLimit: limitPerWindow,
517
+ status: 429,
518
+ errorMessage: `You've exceeded your ${serviceScope} rate limit at ${limitPerSecond} reqs/sec. To get higher rate limits, contact us at https://thirdweb.com/contact-us.`,
519
+ errorCode: "RATE_LIMIT_EXCEEDED"
520
+ };
521
+ }
522
+ }
523
+ return {
524
+ rateLimited: false,
525
+ requestCount,
526
+ rateLimit: limitPerWindow
527
+ };
528
+ }
529
+
530
+ async function usageLimit(authzResult, serviceConfig) {
531
+ if (!authzResult.authorized) {
532
+ return {
533
+ usageLimited: false
534
+ };
535
+ }
536
+ const {
537
+ apiKeyMeta,
538
+ accountMeta
539
+ } = authzResult;
540
+ const {
541
+ limits,
542
+ usage
543
+ } = apiKeyMeta || accountMeta || {};
544
+ const {
545
+ serviceScope
546
+ } = serviceConfig;
547
+ if (!usage || !(serviceScope in usage) || !limits || !(serviceScope in limits)) {
548
+ // No usage limit is provided. Assume the request is not limited.
549
+ return {
550
+ usageLimited: false
551
+ };
552
+ }
553
+ if (serviceScope === "storage" && (usage.storage?.sumFileSizeBytes ?? 0) > (limits.storage ?? 0)) {
554
+ return {
555
+ usageLimited: true,
556
+ status: 403,
557
+ errorMessage: `You've used all of your total usage credits for Storage Pinning. Please add your payment method at https://thirdweb.com/dashboard/settings/billing.`,
558
+ errorCode: "PAYMENT_METHOD_REQUIRED"
559
+ };
560
+ }
561
+ if (serviceScope === "embeddedWallets" && (usage.embeddedWallets?.countWalletAddresses ?? 0) > (limits.embeddedWallets ?? 0)) {
562
+ return {
563
+ usageLimited: true,
564
+ status: 403,
565
+ errorMessage: `You've used all of your total usage credits for Embedded Wallets. Please add your payment method at https://thirdweb.com/dashboard/settings/billing.`,
566
+ errorCode: "PAYMENT_METHOD_REQUIRED"
567
+ };
568
+ }
569
+ return {
570
+ usageLimited: false
571
+ };
572
+ }
573
+
424
574
  exports.authorize = authorize;
575
+ exports.rateLimit = rateLimit;
576
+ exports.usageLimit = usageLimit;
@@ -4,9 +4,12 @@ async function fetchKeyMetadataFromApi(clientId, config) {
4
4
  const {
5
5
  apiUrl,
6
6
  serviceScope,
7
- serviceApiKey
7
+ serviceApiKey,
8
+ checkPolicy,
9
+ policyMetadata
8
10
  } = config;
9
- const url = `${apiUrl}/v1/keys/use?clientId=${clientId}&scope=${serviceScope}`;
11
+ const policyQuery = checkPolicy && policyMetadata ? `&checkPolicy=true&policyMetadata=${encodeURIComponent(JSON.stringify(policyMetadata))}` : "";
12
+ const url = `${apiUrl}/v1/keys/use?clientId=${clientId}&scope=${serviceScope}&includeUsage=true${policyQuery}`;
10
13
  const response = await fetch(url, {
11
14
  method: "GET",
12
15
  headers: {
@@ -14,20 +17,20 @@ async function fetchKeyMetadataFromApi(clientId, config) {
14
17
  "content-type": "application/json"
15
18
  }
16
19
  });
17
- let json;
20
+ let text = "";
18
21
  try {
19
- json = await response.json();
22
+ text = await response.text();
23
+ return JSON.parse(text);
20
24
  } catch (e) {
21
- throw new Error(`Error fetching key metadata from API: ${response.status} - ${response.statusText} - ${await response.text()}`);
25
+ throw new Error(`Error fetching key metadata from API: ${response.status} - ${text}`);
22
26
  }
23
- return json;
24
27
  }
25
28
  async function fetchAccountFromApi(jwt, config, useWalletAuth) {
26
29
  const {
27
30
  apiUrl,
28
31
  serviceApiKey
29
32
  } = config;
30
- const url = useWalletAuth ? `${apiUrl}/v1/wallet/me` : `${apiUrl}/v1/account/me`;
33
+ const url = useWalletAuth ? `${apiUrl}/v1/wallet/me?includeUsage=true` : `${apiUrl}/v1/account/me?includeUsage=true`;
31
34
  const response = await fetch(url, {
32
35
  method: "GET",
33
36
  headers: {
@@ -36,13 +39,32 @@ async function fetchAccountFromApi(jwt, config, useWalletAuth) {
36
39
  authorization: `Bearer ${jwt}`
37
40
  }
38
41
  });
39
- let json;
42
+ let text = "";
40
43
  try {
41
- json = await response.json();
44
+ text = await response.text();
45
+ return JSON.parse(text);
42
46
  } catch (e) {
43
- throw new Error(`Error fetching account from API: ${response.status} - ${response.statusText} - ${await response.text()}`);
47
+ throw new Error(`Error fetching account from API: ${response.status} - ${text}`);
44
48
  }
45
- return json;
49
+ }
50
+ async function updateRateLimitedAt(apiKeyId, config) {
51
+ const {
52
+ apiUrl,
53
+ serviceScope: scope,
54
+ serviceApiKey
55
+ } = config;
56
+ const url = `${apiUrl}/usage/rateLimit`;
57
+ await fetch(url, {
58
+ method: "PUT",
59
+ headers: {
60
+ "x-service-api-key": serviceApiKey,
61
+ "content-type": "application/json"
62
+ },
63
+ body: JSON.stringify({
64
+ apiKeyId,
65
+ scope
66
+ })
67
+ });
46
68
  }
47
69
 
48
70
  function authorizeClient(authOptions, apiKeyMeta) {
@@ -63,7 +85,10 @@ function authorizeClient(authOptions, apiKeyMeta) {
63
85
  id: apiKeyMeta.accountId,
64
86
  // TODO update this later
65
87
  name: "",
66
- creatorWalletAddress: apiKeyMeta.creatorWalletAddress
88
+ creatorWalletAddress: apiKeyMeta.creatorWalletAddress,
89
+ limits: apiKeyMeta.limits,
90
+ rateLimits: apiKeyMeta.rateLimits,
91
+ usage: apiKeyMeta.usage
67
92
  }
68
93
  };
69
94
 
@@ -193,12 +218,15 @@ function authorizeService(apiKeyMetadata, serviceConfig, authorizationPayload) {
193
218
  }
194
219
  return {
195
220
  authorized: true,
221
+ apiKeyMeta: apiKeyMetadata,
196
222
  accountMeta: {
197
223
  id: apiKeyMetadata.accountId,
198
224
  name: "",
199
- creatorWalletAddress: apiKeyMetadata.creatorWalletAddress
200
- },
201
- apiKeyMeta: apiKeyMetadata
225
+ creatorWalletAddress: apiKeyMetadata.creatorWalletAddress,
226
+ limits: apiKeyMetadata.limits,
227
+ rateLimits: apiKeyMetadata.rateLimits,
228
+ usage: apiKeyMetadata.usage
229
+ }
202
230
  };
203
231
  }
204
232
 
@@ -236,9 +264,9 @@ async function authorize(authData, serviceConfig, cacheOptions) {
236
264
  // if the difference is greater than the cacheTtl we want to ignore the cached data
237
265
  const now = Date.now();
238
266
  const diff = now - parsed.updatedAt;
239
- const cacheTtl = cacheOptions.cacheTtlSeconds * 1000;
267
+ const cacheTtlMs = cacheOptions.cacheTtlSeconds * 1000;
240
268
  // only if the diff is less than the cacheTtl do we want to use the cached key
241
- if (diff < cacheTtl * 1000) {
269
+ if (diff < cacheTtlMs) {
242
270
  accountMeta = parsed.apiKeyMeta;
243
271
  }
244
272
  } else {
@@ -322,9 +350,9 @@ async function authorize(authData, serviceConfig, cacheOptions) {
322
350
  // if the difference is greater than the cacheTtl we want to ignore the cached data
323
351
  const now = Date.now();
324
352
  const diff = now - parsed.updatedAt;
325
- const cacheTtl = cacheOptions.cacheTtlSeconds * 1000;
353
+ const cacheTtlMs = cacheOptions.cacheTtlSeconds * 1000;
326
354
  // only if the diff is less than the cacheTtl do we want to use the cached key
327
- if (diff < cacheTtl * 1000) {
355
+ if (diff < cacheTtlMs) {
328
356
  apiKeyMeta = parsed.apiKeyMeta;
329
357
  }
330
358
  } else {
@@ -416,9 +444,133 @@ async function authorize(authData, serviceConfig, cacheOptions) {
416
444
  id: apiKeyMeta.accountId,
417
445
  // TODO update this later
418
446
  name: "",
447
+ limits: apiKeyMeta.limits,
448
+ rateLimits: apiKeyMeta.rateLimits,
449
+ usage: apiKeyMeta.usage,
419
450
  creatorWalletAddress: apiKeyMeta.creatorWalletAddress
420
451
  }
421
452
  };
422
453
  }
423
454
 
455
+ const RATE_LIMIT_WINDOW_SECONDS = 10;
456
+
457
+ // Redis interface compatible with ioredis (Node) and upstash (Cloudflare Workers).
458
+
459
+ async function rateLimit(args) {
460
+ const {
461
+ authzResult,
462
+ serviceConfig,
463
+ redis,
464
+ sampleRate = 1.0
465
+ } = args;
466
+ const shouldSampleRequest = Math.random() < sampleRate;
467
+ if (!shouldSampleRequest || !authzResult.authorized) {
468
+ return {
469
+ rateLimited: false,
470
+ requestCount: 0,
471
+ rateLimit: 0
472
+ };
473
+ }
474
+ const {
475
+ apiKeyMeta,
476
+ accountMeta
477
+ } = authzResult;
478
+ const accountId = apiKeyMeta?.accountId || accountMeta?.id;
479
+ const {
480
+ serviceScope
481
+ } = serviceConfig;
482
+ const limitPerSecond = apiKeyMeta?.rateLimits?.[serviceScope] ?? accountMeta?.rateLimits?.[serviceScope];
483
+ if (!limitPerSecond) {
484
+ // No rate limit is provided. Assume the request is not rate limited.
485
+ return {
486
+ rateLimited: false,
487
+ requestCount: 0,
488
+ rateLimit: 0
489
+ };
490
+ }
491
+
492
+ // Gets the 10-second window for the current timestamp.
493
+ const timestampWindow = Math.floor(Date.now() / (1000 * RATE_LIMIT_WINDOW_SECONDS)) * RATE_LIMIT_WINDOW_SECONDS;
494
+ const key = `rate-limit:${serviceScope}:${accountId}:${timestampWindow}`;
495
+
496
+ // Increment and get the current request count in this window.
497
+ const requestCount = await redis.incr(key);
498
+ if (requestCount === 1) {
499
+ // For the first increment, set an expiration to clean up this key.
500
+ await redis.expire(key, RATE_LIMIT_WINDOW_SECONDS);
501
+ }
502
+
503
+ // Get the limit for this window accounting for the sample rate.
504
+ const limitPerWindow = limitPerSecond * sampleRate * RATE_LIMIT_WINDOW_SECONDS;
505
+ if (requestCount > limitPerWindow) {
506
+ // Report rate limit hits.
507
+ if (apiKeyMeta?.id) {
508
+ await updateRateLimitedAt(apiKeyMeta.id, serviceConfig);
509
+ }
510
+
511
+ // Reject requests when they've exceeded 2x the rate limit.
512
+ if (requestCount > 2 * limitPerWindow) {
513
+ return {
514
+ rateLimited: true,
515
+ requestCount,
516
+ rateLimit: limitPerWindow,
517
+ status: 429,
518
+ errorMessage: `You've exceeded your ${serviceScope} rate limit at ${limitPerSecond} reqs/sec. To get higher rate limits, contact us at https://thirdweb.com/contact-us.`,
519
+ errorCode: "RATE_LIMIT_EXCEEDED"
520
+ };
521
+ }
522
+ }
523
+ return {
524
+ rateLimited: false,
525
+ requestCount,
526
+ rateLimit: limitPerWindow
527
+ };
528
+ }
529
+
530
+ async function usageLimit(authzResult, serviceConfig) {
531
+ if (!authzResult.authorized) {
532
+ return {
533
+ usageLimited: false
534
+ };
535
+ }
536
+ const {
537
+ apiKeyMeta,
538
+ accountMeta
539
+ } = authzResult;
540
+ const {
541
+ limits,
542
+ usage
543
+ } = apiKeyMeta || accountMeta || {};
544
+ const {
545
+ serviceScope
546
+ } = serviceConfig;
547
+ if (!usage || !(serviceScope in usage) || !limits || !(serviceScope in limits)) {
548
+ // No usage limit is provided. Assume the request is not limited.
549
+ return {
550
+ usageLimited: false
551
+ };
552
+ }
553
+ if (serviceScope === "storage" && (usage.storage?.sumFileSizeBytes ?? 0) > (limits.storage ?? 0)) {
554
+ return {
555
+ usageLimited: true,
556
+ status: 403,
557
+ errorMessage: `You've used all of your total usage credits for Storage Pinning. Please add your payment method at https://thirdweb.com/dashboard/settings/billing.`,
558
+ errorCode: "PAYMENT_METHOD_REQUIRED"
559
+ };
560
+ }
561
+ if (serviceScope === "embeddedWallets" && (usage.embeddedWallets?.countWalletAddresses ?? 0) > (limits.embeddedWallets ?? 0)) {
562
+ return {
563
+ usageLimited: true,
564
+ status: 403,
565
+ errorMessage: `You've used all of your total usage credits for Embedded Wallets. Please add your payment method at https://thirdweb.com/dashboard/settings/billing.`,
566
+ errorCode: "PAYMENT_METHOD_REQUIRED"
567
+ };
568
+ }
569
+ return {
570
+ usageLimited: false
571
+ };
572
+ }
573
+
424
574
  exports.authorize = authorize;
575
+ exports.rateLimit = rateLimit;
576
+ exports.usageLimit = usageLimit;
@@ -33,6 +33,27 @@ const SERVICE_DEFINITIONS = {
33
33
  description: "Enable gasless transactions",
34
34
  // all actions allowed
35
35
  actions: []
36
+ },
37
+ embeddedWallets: {
38
+ name: "embeddedWallets",
39
+ title: "Embedded Wallets",
40
+ description: "E-mail and social login wallets for easy web3 onboarding",
41
+ // all actions allowed
42
+ actions: []
43
+ },
44
+ checkout: {
45
+ name: "checkout",
46
+ title: "Checkouts",
47
+ description: "NFT Checkouts for easy web3 onboarding",
48
+ // all actions allowed
49
+ actions: []
50
+ },
51
+ pay: {
52
+ name: "pay",
53
+ title: "Pay",
54
+ description: "Pay for a blockchain transaction with any currency",
55
+ // all actions allowed
56
+ actions: []
36
57
  }
37
58
  };
38
59
  const SERVICE_NAMES = Object.keys(SERVICE_DEFINITIONS);
@@ -35,6 +35,27 @@ const SERVICE_DEFINITIONS = {
35
35
  description: "Enable gasless transactions",
36
36
  // all actions allowed
37
37
  actions: []
38
+ },
39
+ embeddedWallets: {
40
+ name: "embeddedWallets",
41
+ title: "Embedded Wallets",
42
+ description: "E-mail and social login wallets for easy web3 onboarding",
43
+ // all actions allowed
44
+ actions: []
45
+ },
46
+ checkout: {
47
+ name: "checkout",
48
+ title: "Checkouts",
49
+ description: "NFT Checkouts for easy web3 onboarding",
50
+ // all actions allowed
51
+ actions: []
52
+ },
53
+ pay: {
54
+ name: "pay",
55
+ title: "Pay",
56
+ description: "Pay for a blockchain transaction with any currency",
57
+ // all actions allowed
58
+ actions: []
38
59
  }
39
60
  };
40
61
  const SERVICE_NAMES = Object.keys(SERVICE_DEFINITIONS);
@@ -35,6 +35,27 @@ const SERVICE_DEFINITIONS = {
35
35
  description: "Enable gasless transactions",
36
36
  // all actions allowed
37
37
  actions: []
38
+ },
39
+ embeddedWallets: {
40
+ name: "embeddedWallets",
41
+ title: "Embedded Wallets",
42
+ description: "E-mail and social login wallets for easy web3 onboarding",
43
+ // all actions allowed
44
+ actions: []
45
+ },
46
+ checkout: {
47
+ name: "checkout",
48
+ title: "Checkouts",
49
+ description: "NFT Checkouts for easy web3 onboarding",
50
+ // all actions allowed
51
+ actions: []
52
+ },
53
+ pay: {
54
+ name: "pay",
55
+ title: "Pay",
56
+ description: "Pay for a blockchain transaction with any currency",
57
+ // all actions allowed
58
+ actions: []
38
59
  }
39
60
  };
40
61
  const SERVICE_NAMES = Object.keys(SERVICE_DEFINITIONS);
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var services = require('./services-a3f36057.cjs.dev.js');
5
+ var services = require('./services-508322f3.cjs.dev.js');
6
6
 
7
7
 
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var services = require('./services-9e185105.cjs.prod.js');
5
+ var services = require('./services-5c4d6977.cjs.prod.js');
6
6
 
7
7
 
8
8
 
@@ -1 +1 @@
1
- export { b as SERVICES, S as SERVICE_DEFINITIONS, a as SERVICE_NAMES, g as getServiceByName } from './services-86283509.esm.js';
1
+ export { b as SERVICES, S as SERVICE_DEFINITIONS, a as SERVICE_NAMES, g as getServiceByName } from './services-2aecbda8.esm.js';