alchemy 0.93.7 → 0.93.10

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.
@@ -320,7 +320,7 @@ export type R2Bucket = _R2Bucket & {
320
320
  | Blob,
321
321
  options?: Pick<R2PutOptions, "httpMetadata">,
322
322
  ): Promise<PutR2ObjectResponse>;
323
- delete(key: string): Promise<Response>;
323
+ delete(key: string): Promise<Response | void>;
324
324
  list(options?: R2ListOptions): Promise<R2Objects>;
325
325
  };
326
326
 
@@ -463,7 +463,6 @@ export async function R2Bucket(
463
463
  ): Promise<R2Bucket> {
464
464
  const scope = Scope.current;
465
465
  const isLocal = scope.local && props.dev?.remote !== true;
466
- const api = await createCloudflareApi(props);
467
466
  const bucket = await _R2Bucket(id, {
468
467
  ...props,
469
468
  dev: {
@@ -472,6 +471,9 @@ export async function R2Bucket(
472
471
  },
473
472
  });
474
473
 
474
+ let _api: CloudflareApi | undefined;
475
+ const api = async () => (_api ??= await createCloudflareApi(props));
476
+
475
477
  let _miniflare: mf.Miniflare | undefined;
476
478
  const miniflare = () => {
477
479
  if (_miniflare) {
@@ -505,9 +507,10 @@ export async function R2Bucket(
505
507
  }
506
508
  return null;
507
509
  }
508
- return headObject(api, {
510
+ return headObject(await api(), {
509
511
  bucketName: bucket.name,
510
512
  key,
513
+ jurisdiction: bucket.jurisdiction,
511
514
  });
512
515
  },
513
516
  get: async (key: string) => {
@@ -519,9 +522,10 @@ export async function R2Bucket(
519
522
  }
520
523
  return null;
521
524
  }
522
- const response = await getObject(api, {
525
+ const response = await getObject(await api(), {
523
526
  bucketName: bucket.name,
524
527
  key,
528
+ jurisdiction: bucket.jurisdiction,
525
529
  });
526
530
  if (response.ok) {
527
531
  return parseR2Object(key, response);
@@ -535,7 +539,7 @@ export async function R2Bucket(
535
539
  if (isLocal) {
536
540
  return (await localBucket()).list(options);
537
541
  }
538
- return listObjects(api, bucket.name, {
542
+ return listObjects(await api(), bucket.name, {
539
543
  ...options,
540
544
  jurisdiction: bucket.jurisdiction,
541
545
  });
@@ -565,11 +569,12 @@ export async function R2Bucket(
565
569
  options,
566
570
  );
567
571
  }
568
- const response = await putObject(api, {
572
+ const response = await putObject(await api(), {
569
573
  bucketName: bucket.name,
570
574
  key: key,
571
575
  object: value,
572
576
  options: options,
577
+ jurisdiction: bucket.jurisdiction,
573
578
  });
574
579
  const body = (await response.json()) as {
575
580
  result: {
@@ -591,10 +596,12 @@ export async function R2Bucket(
591
596
  delete: async (key: string) => {
592
597
  if (isLocal) {
593
598
  await (await localBucket()).delete(key);
599
+ return;
594
600
  }
595
- return deleteObject(api, {
601
+ return deleteObject(await api(), {
596
602
  bucketName: bucket.name,
597
603
  key: key,
604
+ jurisdiction: bucket.jurisdiction,
598
605
  });
599
606
  },
600
607
  };
@@ -1239,12 +1246,17 @@ export async function getBucketLockRules(
1239
1246
 
1240
1247
  export async function headObject(
1241
1248
  api: CloudflareApi,
1242
- { bucketName, key }: { bucketName: string; key: string },
1249
+ {
1250
+ bucketName,
1251
+ key,
1252
+ jurisdiction,
1253
+ }: { bucketName: string; key: string; jurisdiction?: R2BucketJurisdiction },
1243
1254
  ): Promise<R2ObjectMetadata | null> {
1244
1255
  const response = await withRetries(
1245
1256
  async () =>
1246
1257
  await api.get(
1247
1258
  `/accounts/${api.accountId}/r2/buckets/${bucketName}/objects/${key}`,
1259
+ { headers: withJurisdiction({ jurisdiction }) },
1248
1260
  ),
1249
1261
  );
1250
1262
  // for some reason HEAD returns 404 for keys that exist, this is the best we can do without using S3 API
@@ -1269,16 +1281,23 @@ const withRetries = (f: () => Promise<Response>) => {
1269
1281
 
1270
1282
  export async function getObject(
1271
1283
  api: CloudflareApi,
1272
- { bucketName, key }: { bucketName: string; key: string },
1284
+ {
1285
+ bucketName,
1286
+ key,
1287
+ jurisdiction,
1288
+ }: { bucketName: string; key: string; jurisdiction?: R2BucketJurisdiction },
1273
1289
  ) {
1274
1290
  return await withRetries(async () => {
1275
1291
  const response = await api.get(
1276
1292
  `/accounts/${api.accountId}/r2/buckets/${bucketName}/objects/${key}`,
1277
1293
  {
1278
- headers: {
1279
- "Content-Type": "application/octet-stream",
1280
- Accept: "application/octet-stream",
1281
- },
1294
+ headers: withJurisdiction(
1295
+ { jurisdiction },
1296
+ {
1297
+ "Content-Type": "application/octet-stream",
1298
+ Accept: "application/octet-stream",
1299
+ },
1300
+ ),
1282
1301
  },
1283
1302
  );
1284
1303
  if (!response.ok && response.status !== 404) {
@@ -1346,21 +1365,26 @@ export async function putObject(
1346
1365
  key,
1347
1366
  object,
1348
1367
  options,
1368
+ jurisdiction,
1349
1369
  }: {
1350
1370
  bucketName: string;
1351
1371
  key: string;
1352
1372
  object: PutObjectObject;
1353
1373
  options?: Pick<R2PutOptions, "httpMetadata">;
1374
+ jurisdiction?: R2BucketJurisdiction;
1354
1375
  },
1355
1376
  ): Promise<Response> {
1356
1377
  // Using withExponentialBackoff for reliability
1357
1378
  return await withRetries(async () => {
1358
- const headers: Record<string, string> = {
1359
- "Content-Type": "application/octet-stream",
1360
- ...(options?.httpMetadata
1361
- ? mapHttpMetadataToHeaders(options?.httpMetadata)
1362
- : {}),
1363
- };
1379
+ const headers: Record<string, string> = withJurisdiction(
1380
+ { jurisdiction },
1381
+ {
1382
+ "Content-Type": "application/octet-stream",
1383
+ ...(options?.httpMetadata
1384
+ ? mapHttpMetadataToHeaders(options?.httpMetadata)
1385
+ : {}),
1386
+ },
1387
+ );
1364
1388
 
1365
1389
  const response = await api.put(
1366
1390
  `/accounts/${api.accountId}/r2/buckets/${bucketName}/objects/${key}`,
@@ -1378,11 +1402,16 @@ export async function putObject(
1378
1402
 
1379
1403
  export async function deleteObject(
1380
1404
  api: CloudflareApi,
1381
- { bucketName, key }: { bucketName: string; key: string },
1405
+ {
1406
+ bucketName,
1407
+ key,
1408
+ jurisdiction,
1409
+ }: { bucketName: string; key: string; jurisdiction?: R2BucketJurisdiction },
1382
1410
  ) {
1383
1411
  return await withRetries(async () => {
1384
1412
  const response = await api.delete(
1385
1413
  `/accounts/${api.accountId}/r2/buckets/${bucketName}/objects/${key}`,
1414
+ { headers: withJurisdiction({ jurisdiction }) },
1386
1415
  );
1387
1416
 
1388
1417
  if (!response.ok && response.status !== 404) {
@@ -38,11 +38,16 @@ export async function createTunnel(
38
38
  getMiniflare,
39
39
  mode: "remote",
40
40
  transformRequest: (request) => {
41
- if (request.url.origin === remote.origin) {
42
- request.url.protocol = proxy.url.protocol;
43
- request.url.host = proxy.url.host;
44
- request.url.port = proxy.url.port;
45
- request.headers.set("host", proxy.url.host);
41
+ const originalUrl = request.headers.get("alchemy-original-url");
42
+ if (originalUrl) {
43
+ const parsed = new URL(originalUrl);
44
+ request.url.protocol = parsed.protocol;
45
+ request.url.host = parsed.host;
46
+ request.url.port = parsed.port;
47
+ request.url.pathname = parsed.pathname;
48
+ request.url.search = parsed.search;
49
+ request.headers.set("host", parsed.host);
50
+ request.headers.delete("alchemy-original-url");
46
51
  }
47
52
  },
48
53
  getWorkerName: (request) => {
@@ -62,6 +62,16 @@ export type PriceRecurring =
62
62
  type TaxBehavior = Stripe.PriceCreateParams.TaxBehavior;
63
63
  type BillingScheme = Stripe.PriceCreateParams.BillingScheme;
64
64
 
65
+ // Stripe SDK >=19 returns `*_decimal` fields as a `Stripe.Decimal` class
66
+ // instance (which holds a BigInt internally) rather than a plain string.
67
+ // Resource state must remain JSON-serialisable, so coerce to string here.
68
+ // Older SDKs that already return strings flow through unchanged.
69
+ const toDecimalString = (value: unknown): string | undefined => {
70
+ if (value == null) return undefined;
71
+ const str = typeof value === "string" ? value : String(value);
72
+ return str || undefined;
73
+ };
74
+
65
75
  /**
66
76
  * Properties for price tier configuration
67
77
  */
@@ -529,9 +539,9 @@ export const Price = Resource(
529
539
  const tiers = price.tiers
530
540
  ? price.tiers.map((tier) => ({
531
541
  flatAmount: tier.flat_amount || undefined,
532
- flatAmountDecimal: tier.flat_amount_decimal || undefined,
542
+ flatAmountDecimal: toDecimalString(tier.flat_amount_decimal),
533
543
  unitAmount: tier.unit_amount || undefined,
534
- unitAmountDecimal: tier.unit_amount_decimal || undefined,
544
+ unitAmountDecimal: toDecimalString(tier.unit_amount_decimal),
535
545
  upTo: tier.up_to === null ? ("inf" as const) : tier.up_to!,
536
546
  }))
537
547
  : undefined;
@@ -551,7 +561,7 @@ export const Price = Resource(
551
561
  typeof price.product === "string" ? price.product : price.product.id,
552
562
  currency: price.currency,
553
563
  unitAmount: price.unit_amount || undefined,
554
- unitAmountDecimal: price.unit_amount_decimal || undefined,
564
+ unitAmountDecimal: toDecimalString(price.unit_amount_decimal),
555
565
  active: price.active,
556
566
  billingScheme: price.billing_scheme as BillingScheme,
557
567
  nickname: price.nickname || undefined,