wrangler 2.0.8 → 2.0.12

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 (67) hide show
  1. package/kv-asset-handler.js +1 -0
  2. package/package.json +3 -1
  3. package/src/__tests__/configuration.test.ts +255 -142
  4. package/src/__tests__/dev.test.tsx +88 -58
  5. package/src/__tests__/index.test.ts +2 -1
  6. package/src/__tests__/init.test.ts +3 -0
  7. package/src/__tests__/kv.test.ts +23 -2
  8. package/src/__tests__/pages.test.ts +98 -1
  9. package/src/__tests__/publish.test.ts +514 -162
  10. package/src/__tests__/whoami.test.tsx +34 -0
  11. package/src/bundle.ts +9 -5
  12. package/src/cfetch/internal.ts +6 -9
  13. package/src/config/config.ts +1 -1
  14. package/src/config/environment.ts +1 -1
  15. package/src/config/validation-helpers.ts +10 -1
  16. package/src/config/validation.ts +22 -13
  17. package/src/create-worker-preview.ts +15 -15
  18. package/src/dev/dev.tsx +32 -56
  19. package/src/dev/local.tsx +10 -7
  20. package/src/dev/remote.tsx +30 -17
  21. package/src/dev/use-esbuild.ts +1 -4
  22. package/src/index.tsx +239 -244
  23. package/src/kv.ts +1 -1
  24. package/src/pages.tsx +295 -229
  25. package/src/parse.ts +21 -1
  26. package/src/proxy.ts +19 -6
  27. package/src/publish.ts +154 -16
  28. package/src/sites.tsx +49 -18
  29. package/src/user.tsx +12 -1
  30. package/src/whoami.tsx +3 -2
  31. package/src/worker.ts +2 -1
  32. package/src/zones.ts +73 -0
  33. package/templates/static-asset-facade.js +1 -5
  34. package/wrangler-dist/cli.js +73693 -73458
  35. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  36. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  37. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  38. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  39. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  40. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  41. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  42. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  43. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  44. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  45. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  46. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  47. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  48. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  49. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  50. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  51. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  52. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  53. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  54. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  55. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  56. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  57. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  58. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  59. package/vendor/wrangler-mime/LICENSE +0 -21
  60. package/vendor/wrangler-mime/Mime.js +0 -97
  61. package/vendor/wrangler-mime/README.md +0 -187
  62. package/vendor/wrangler-mime/cli.js +0 -46
  63. package/vendor/wrangler-mime/index.js +0 -4
  64. package/vendor/wrangler-mime/lite.js +0 -4
  65. package/vendor/wrangler-mime/package.json +0 -52
  66. package/vendor/wrangler-mime/types/other.js +0 -1
  67. package/vendor/wrangler-mime/types/standard.js +0 -1
@@ -649,8 +649,85 @@ describe("publish", () => {
649
649
  await runWrangler("publish ./index --env dev --legacy-env false");
650
650
  });
651
651
 
652
+ it("should fallback to the Wrangler 1 zone-based API if the bulk-routes API fails", async () => {
653
+ writeWranglerToml({
654
+ routes: ["example.com/some-route/*"],
655
+ });
656
+ writeWorkerSource();
657
+ mockUpdateWorkerRequest({ enabled: false });
658
+ mockUploadWorkerRequest({ expectedType: "esm" });
659
+ // Simulate the bulk-routes API failing with a not authorized error.
660
+ mockUnauthorizedPublishRoutesRequest();
661
+ // Simulate that the worker has already been deployed to another route in this zone.
662
+ mockCollectKnownRoutesRequest([
663
+ {
664
+ pattern: "foo.example.com/other-route",
665
+ script: "test-name",
666
+ },
667
+ ]);
668
+ mockGetZoneFromHostRequest("example.com", "some-zone-id");
669
+ mockPublishRoutesFallbackRequest({
670
+ pattern: "example.com/some-route/*",
671
+ script: "test-name",
672
+ });
673
+ await runWrangler("publish ./index");
674
+
675
+ expect(std.err).toMatchInlineSnapshot(`""`);
676
+ expect(std.warn).toMatchInlineSnapshot(`
677
+ "▲ [WARNING] The current authentication token does not have 'All Zones' permissions.
678
+
679
+ Falling back to using the zone-based API endpoint to update each route individually.
680
+ Note that there is no access to routes associated with zones that the API token does not have
681
+ permission for.
682
+ Existing routes for this Worker in such zones will not be deleted.
683
+
684
+
685
+ ▲ [WARNING] Previously deployed routes:
686
+
687
+ The following routes were already associated with this worker, and have not been deleted:
688
+ - \\"foo.example.com/other-route\\"
689
+ If these routes are not wanted then you can remove them in the dashboard.
690
+
691
+ "
692
+ `);
693
+ expect(std.out).toMatchInlineSnapshot(`
694
+ "Uploaded test-name (TIMINGS)
695
+ Published test-name (TIMINGS)
696
+ example.com/some-route/*"
697
+ `);
698
+ });
699
+
700
+ it("should error if the bulk-routes API fails and trying to push to a non-production environment", async () => {
701
+ writeWranglerToml({
702
+ routes: ["example.com/some-route/*"],
703
+ legacy_env: false,
704
+ });
705
+ writeWorkerSource();
706
+ mockUpdateWorkerRequest({ env: "staging", enabled: false });
707
+ mockUploadWorkerRequest({ env: "staging", expectedType: "esm" });
708
+ // Simulate the bulk-routes API failing with a not authorized error.
709
+ mockUnauthorizedPublishRoutesRequest({ env: "staging" });
710
+ // Simulate that the worker has already been deployed to another route in this zone.
711
+ mockCollectKnownRoutesRequest([
712
+ {
713
+ pattern: "foo.example.com/other-route",
714
+ script: "test-name",
715
+ },
716
+ ]);
717
+ mockGetZoneFromHostRequest("example.com", "some-zone-id");
718
+ mockPublishRoutesFallbackRequest({
719
+ pattern: "example.com/some-route/*",
720
+ script: "test-name",
721
+ });
722
+ await expect(runWrangler("publish ./index --env=staging")).rejects
723
+ .toThrowErrorMatchingInlineSnapshot(`
724
+ "Service environments combined with an API token that doesn't have 'All Zones' permissions is not supported.
725
+ Either turn off service environments by setting \`legacy_env = true\`, creating an API token with 'All Zones' permissions, or logging in via OAuth"
726
+ `);
727
+ });
728
+
652
729
  describe("custom domains", () => {
653
- it("should publish routes marked with 'custom_domain' as seperate custom domains", async () => {
730
+ it("should publish routes marked with 'custom_domain' as separate custom domains", async () => {
654
731
  writeWranglerToml({
655
732
  routes: [{ pattern: "api.example.com", custom_domain: true }],
656
733
  });
@@ -1146,8 +1223,8 @@ addEventListener('fetch', event => {});`
1146
1223
 
1147
1224
  it("should warn if there is a `site.entry-point` configuration", async () => {
1148
1225
  const assets = [
1149
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1150
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1226
+ { filePath: "file-1.txt", content: "Content of file-1" },
1227
+ { filePath: "file-2.txt", content: "Content of file-2" },
1151
1228
  ];
1152
1229
  const kvNamespace = {
1153
1230
  title: "__test-name-workers_sites_assets",
@@ -1173,10 +1250,10 @@ addEventListener('fetch', event => {});`
1173
1250
  Object {
1174
1251
  "debug": "",
1175
1252
  "err": "",
1176
- "out": "Reading assets/file-1.txt...
1177
- Uploading as assets/file-1.2ca234f380.txt...
1178
- Reading assets/file-2.txt...
1179
- Uploading as assets/file-2.5938485188.txt...
1253
+ "out": "Reading file-1.txt...
1254
+ Uploading as file-1.2ca234f380.txt...
1255
+ Reading file-2.txt...
1256
+ Uploading as file-2.5938485188.txt...
1180
1257
  ↗️ Done syncing assets
1181
1258
  Uploaded test-name (TIMINGS)
1182
1259
  Published test-name (TIMINGS)
@@ -1197,8 +1274,8 @@ addEventListener('fetch', event => {});`
1197
1274
 
1198
1275
  it("should resolve site.entry-point relative to wrangler.toml", async () => {
1199
1276
  const assets = [
1200
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1201
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1277
+ { filePath: "file-1.txt", content: "Content of file-1" },
1278
+ { filePath: "file-2.txt", content: "Content of file-2" },
1202
1279
  ];
1203
1280
  const kvNamespace = {
1204
1281
  title: "__test-name-workers_sites_assets",
@@ -1224,10 +1301,10 @@ addEventListener('fetch', event => {});`
1224
1301
  await runWrangler("publish --config ./my-site/wrangler.toml");
1225
1302
 
1226
1303
  expect(std.out).toMatchInlineSnapshot(`
1227
- "Reading assets/file-1.txt...
1228
- Uploading as assets/file-1.2ca234f380.txt...
1229
- Reading assets/file-2.txt...
1230
- Uploading as assets/file-2.5938485188.txt...
1304
+ "Reading file-1.txt...
1305
+ Uploading as file-1.2ca234f380.txt...
1306
+ Reading file-2.txt...
1307
+ Uploading as file-2.5938485188.txt...
1231
1308
  ↗️ Done syncing assets
1232
1309
  Uploaded test-name (TIMINGS)
1233
1310
  Published test-name (TIMINGS)
@@ -1292,8 +1369,8 @@ addEventListener('fetch', event => {});`
1292
1369
  describe("asset upload", () => {
1293
1370
  it("should upload all the files in the directory specified by `config.site.bucket`", async () => {
1294
1371
  const assets = [
1295
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1296
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1372
+ { filePath: "file-1.txt", content: "Content of file-1" },
1373
+ { filePath: "file-2.txt", content: "Content of file-2" },
1297
1374
  ];
1298
1375
  const kvNamespace = {
1299
1376
  title: "__test-name-workers_sites_assets",
@@ -1315,10 +1392,46 @@ addEventListener('fetch', event => {});`
1315
1392
  await runWrangler("publish");
1316
1393
 
1317
1394
  expect(std.out).toMatchInlineSnapshot(`
1318
- "Reading assets/file-1.txt...
1319
- Uploading as assets/file-1.2ca234f380.txt...
1320
- Reading assets/file-2.txt...
1321
- Uploading as assets/file-2.5938485188.txt...
1395
+ "Reading file-1.txt...
1396
+ Uploading as file-1.2ca234f380.txt...
1397
+ Reading file-2.txt...
1398
+ Uploading as file-2.5938485188.txt...
1399
+ ↗️ Done syncing assets
1400
+ Uploaded test-name (TIMINGS)
1401
+ Published test-name (TIMINGS)
1402
+ test-name.test-sub-domain.workers.dev"
1403
+ `);
1404
+ expect(std.err).toMatchInlineSnapshot(`""`);
1405
+ });
1406
+
1407
+ it("should upload all the files in the directory specified by `--experimental-public`", async () => {
1408
+ const assets = [
1409
+ { filePath: "file-1.txt", content: "Content of file-1" },
1410
+ { filePath: "file-2.txt", content: "Content of file-2" },
1411
+ ];
1412
+ const kvNamespace = {
1413
+ title: "__test-name-workers_sites_assets",
1414
+ id: "__test-name-workers_sites_assets-id",
1415
+ };
1416
+ writeWranglerToml({
1417
+ main: "./index.js",
1418
+ });
1419
+ writeWorkerSource();
1420
+ writeAssets(assets);
1421
+ mockUploadWorkerRequest({
1422
+ expectedMainModule: "stdin.js",
1423
+ });
1424
+ mockSubDomainRequest();
1425
+ mockListKVNamespacesRequest(kvNamespace);
1426
+ mockKeyListRequest(kvNamespace.id, []);
1427
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
1428
+ await runWrangler("publish --experimental-public assets");
1429
+
1430
+ expect(std.out).toMatchInlineSnapshot(`
1431
+ "Reading file-1.txt...
1432
+ Uploading as file-1.2ca234f380.txt...
1433
+ Reading file-2.txt...
1434
+ Uploading as file-2.5938485188.txt...
1322
1435
  ↗️ Done syncing assets
1323
1436
  Uploaded test-name (TIMINGS)
1324
1437
  Published test-name (TIMINGS)
@@ -1327,10 +1440,37 @@ addEventListener('fetch', event => {});`
1327
1440
  expect(std.err).toMatchInlineSnapshot(`""`);
1328
1441
  });
1329
1442
 
1443
+ it("should error if --experimental-public and --site are used together", async () => {
1444
+ writeWranglerToml({
1445
+ main: "./index.js",
1446
+ });
1447
+ writeWorkerSource();
1448
+ await expect(
1449
+ runWrangler("publish --experimental-public abc --site xyz")
1450
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1451
+ `"Cannot use --experimental-public and a Site configuration together."`
1452
+ );
1453
+ });
1454
+
1455
+ it("should error if --experimental-public and config.site are used together", async () => {
1456
+ writeWranglerToml({
1457
+ main: "./index.js",
1458
+ site: {
1459
+ bucket: "xyz",
1460
+ },
1461
+ });
1462
+ writeWorkerSource();
1463
+ await expect(
1464
+ runWrangler("publish --experimental-public abc")
1465
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1466
+ `"Cannot use --experimental-public and a Site configuration together."`
1467
+ );
1468
+ });
1469
+
1330
1470
  it("should not contain backslash for assets with nested directories", async () => {
1331
1471
  const assets = [
1332
- { filePath: "assets/subdir/file-1.txt", content: "Content of file-1" },
1333
- { filePath: "assets/subdir/file-2.txt", content: "Content of file-2" },
1472
+ { filePath: "subdir/file-1.txt", content: "Content of file-1" },
1473
+ { filePath: "subdir/file-2.txt", content: "Content of file-2" },
1334
1474
  ];
1335
1475
  const kvNamespace = {
1336
1476
  title: "__test-name-workers_sites_assets",
@@ -1354,7 +1494,7 @@ addEventListener('fetch', event => {});`
1354
1494
  ],
1355
1495
  expectedModules: {
1356
1496
  __STATIC_CONTENT_MANIFEST:
1357
- '{"subdir/file-1.txt":"assets/subdir/file-1.2ca234f380.txt","subdir/file-2.txt":"assets/subdir/file-2.5938485188.txt"}',
1497
+ '{"subdir/file-1.txt":"subdir/file-1.2ca234f380.txt","subdir/file-2.txt":"subdir/file-2.5938485188.txt"}',
1358
1498
  },
1359
1499
  });
1360
1500
  mockSubDomainRequest();
@@ -1365,10 +1505,10 @@ addEventListener('fetch', event => {});`
1365
1505
  await runWrangler("publish");
1366
1506
 
1367
1507
  expect(std.out).toMatchInlineSnapshot(`
1368
- "Reading assets/subdir/file-1.txt...
1369
- Uploading as assets/subdir/file-1.2ca234f380.txt...
1370
- Reading assets/subdir/file-2.txt...
1371
- Uploading as assets/subdir/file-2.5938485188.txt...
1508
+ "Reading subdir/file-1.txt...
1509
+ Uploading as subdir/file-1.2ca234f380.txt...
1510
+ Reading subdir/file-2.txt...
1511
+ Uploading as subdir/file-2.5938485188.txt...
1372
1512
  ↗️ Done syncing assets
1373
1513
  Uploaded test-name (TIMINGS)
1374
1514
  Published test-name (TIMINGS)
@@ -1379,8 +1519,8 @@ addEventListener('fetch', event => {});`
1379
1519
 
1380
1520
  it("when using a service-worker type, it should add an asset manifest as a text_blob, and bind to a namespace", async () => {
1381
1521
  const assets = [
1382
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1383
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1522
+ { filePath: "file-1.txt", content: "Content of file-1" },
1523
+ { filePath: "file-2.txt", content: "Content of file-2" },
1384
1524
  ];
1385
1525
  const kvNamespace = {
1386
1526
  title: "__test-name-workers_sites_assets",
@@ -1398,7 +1538,7 @@ addEventListener('fetch', event => {});`
1398
1538
  expectedType: "sw",
1399
1539
  expectedModules: {
1400
1540
  __STATIC_CONTENT_MANIFEST:
1401
- '{"file-1.txt":"assets/file-1.2ca234f380.txt","file-2.txt":"assets/file-2.5938485188.txt"}',
1541
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
1402
1542
  },
1403
1543
  expectedBindings: [
1404
1544
  {
@@ -1421,10 +1561,10 @@ addEventListener('fetch', event => {});`
1421
1561
  await runWrangler("publish");
1422
1562
 
1423
1563
  expect(std.out).toMatchInlineSnapshot(`
1424
- "Reading assets/file-1.txt...
1425
- Uploading as assets/file-1.2ca234f380.txt...
1426
- Reading assets/file-2.txt...
1427
- Uploading as assets/file-2.5938485188.txt...
1564
+ "Reading file-1.txt...
1565
+ Uploading as file-1.2ca234f380.txt...
1566
+ Reading file-2.txt...
1567
+ Uploading as file-2.5938485188.txt...
1428
1568
  ↗️ Done syncing assets
1429
1569
  Uploaded test-name (TIMINGS)
1430
1570
  Published test-name (TIMINGS)
@@ -1435,8 +1575,8 @@ addEventListener('fetch', event => {});`
1435
1575
 
1436
1576
  it("when using a module worker type, it should add an asset manifest module, and bind to a namespace", async () => {
1437
1577
  const assets = [
1438
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1439
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1578
+ { filePath: "file-1.txt", content: "Content of file-1" },
1579
+ { filePath: "file-2.txt", content: "Content of file-2" },
1440
1580
  ];
1441
1581
  const kvNamespace = {
1442
1582
  title: "__test-name-workers_sites_assets",
@@ -1460,7 +1600,7 @@ addEventListener('fetch', event => {});`
1460
1600
  ],
1461
1601
  expectedModules: {
1462
1602
  __STATIC_CONTENT_MANIFEST:
1463
- '{"file-1.txt":"assets/file-1.2ca234f380.txt","file-2.txt":"assets/file-2.5938485188.txt"}',
1603
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
1464
1604
  },
1465
1605
  });
1466
1606
  mockSubDomainRequest();
@@ -1471,10 +1611,10 @@ addEventListener('fetch', event => {});`
1471
1611
  await runWrangler("publish");
1472
1612
 
1473
1613
  expect(std.out).toMatchInlineSnapshot(`
1474
- "Reading assets/file-1.txt...
1475
- Uploading as assets/file-1.2ca234f380.txt...
1476
- Reading assets/file-2.txt...
1477
- Uploading as assets/file-2.5938485188.txt...
1614
+ "Reading file-1.txt...
1615
+ Uploading as file-1.2ca234f380.txt...
1616
+ Reading file-2.txt...
1617
+ Uploading as file-2.5938485188.txt...
1478
1618
  ↗️ Done syncing assets
1479
1619
  Uploaded test-name (TIMINGS)
1480
1620
  Published test-name (TIMINGS)
@@ -1486,8 +1626,8 @@ addEventListener('fetch', event => {});`
1486
1626
  it("should make environment specific kv namespace for assets, even for service envs", async () => {
1487
1627
  // This is the same test as the one before this, but with an env arg
1488
1628
  const assets = [
1489
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1490
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1629
+ { filePath: "file-1.txt", content: "Content of file-1" },
1630
+ { filePath: "file-2.txt", content: "Content of file-2" },
1491
1631
  ];
1492
1632
  const kvNamespace = {
1493
1633
  title: "__test-name-some-env-workers_sites_assets",
@@ -1519,10 +1659,10 @@ addEventListener('fetch', event => {});`
1519
1659
  await runWrangler("publish --env some-env --legacy-env false");
1520
1660
 
1521
1661
  expect(std.out).toMatchInlineSnapshot(`
1522
- "Reading assets/file-1.txt...
1523
- Uploading as assets/file-1.2ca234f380.txt...
1524
- Reading assets/file-2.txt...
1525
- Uploading as assets/file-2.5938485188.txt...
1662
+ "Reading file-1.txt...
1663
+ Uploading as file-1.2ca234f380.txt...
1664
+ Reading file-2.txt...
1665
+ Uploading as file-2.5938485188.txt...
1526
1666
  ↗️ Done syncing assets
1527
1667
  Uploaded test-name (some-env) (TIMINGS)
1528
1668
  Published test-name (some-env) (TIMINGS)
@@ -1534,8 +1674,8 @@ addEventListener('fetch', event => {});`
1534
1674
  it("should make environment specific kv namespace for assets, even for legacy envs", async () => {
1535
1675
  // And this is the same test as the one before this, but with legacyEnv:true
1536
1676
  const assets = [
1537
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1538
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1677
+ { filePath: "file-1.txt", content: "Content of file-1" },
1678
+ { filePath: "file-2.txt", content: "Content of file-2" },
1539
1679
  ];
1540
1680
  const kvNamespace = {
1541
1681
  title: "__test-name-some-env-workers_sites_assets",
@@ -1568,10 +1708,10 @@ addEventListener('fetch', event => {});`
1568
1708
  await runWrangler("publish --env some-env --legacy-env true");
1569
1709
 
1570
1710
  expect(std.out).toMatchInlineSnapshot(`
1571
- "Reading assets/file-1.txt...
1572
- Uploading as assets/file-1.2ca234f380.txt...
1573
- Reading assets/file-2.txt...
1574
- Uploading as assets/file-2.5938485188.txt...
1711
+ "Reading file-1.txt...
1712
+ Uploading as file-1.2ca234f380.txt...
1713
+ Reading file-2.txt...
1714
+ Uploading as file-2.5938485188.txt...
1575
1715
  ↗️ Done syncing assets
1576
1716
  Uploaded test-name-some-env (TIMINGS)
1577
1717
  Published test-name-some-env (TIMINGS)
@@ -1582,8 +1722,8 @@ addEventListener('fetch', event => {});`
1582
1722
 
1583
1723
  it("should only upload files that are not already in the KV namespace", async () => {
1584
1724
  const assets = [
1585
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1586
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1725
+ { filePath: "file-1.txt", content: "Content of file-1" },
1726
+ { filePath: "file-2.txt", content: "Content of file-2" },
1587
1727
  ];
1588
1728
  const kvNamespace = {
1589
1729
  title: "__test-name-workers_sites_assets",
@@ -1601,21 +1741,19 @@ addEventListener('fetch', event => {});`
1601
1741
  mockSubDomainRequest();
1602
1742
  mockListKVNamespacesRequest(kvNamespace);
1603
1743
  // Put file-1 in the KV namespace
1604
- mockKeyListRequest(kvNamespace.id, [
1605
- { name: "assets/file-1.2ca234f380.txt" },
1606
- ]);
1744
+ mockKeyListRequest(kvNamespace.id, [{ name: "file-1.2ca234f380.txt" }]);
1607
1745
  // Check we do not upload file-1
1608
1746
  mockUploadAssetsToKVRequest(
1609
1747
  kvNamespace.id,
1610
- assets.filter((a) => a.filePath !== "assets/file-1.txt")
1748
+ assets.filter((a) => a.filePath !== "file-1.txt")
1611
1749
  );
1612
1750
  await runWrangler("publish");
1613
1751
 
1614
1752
  expect(std.out).toMatchInlineSnapshot(`
1615
- "Reading assets/file-1.txt...
1753
+ "Reading file-1.txt...
1616
1754
  Skipping - already uploaded.
1617
- Reading assets/file-2.txt...
1618
- Uploading as assets/file-2.5938485188.txt...
1755
+ Reading file-2.txt...
1756
+ Uploading as file-2.5938485188.txt...
1619
1757
  ↗️ Done syncing assets
1620
1758
  Uploaded test-name (TIMINGS)
1621
1759
  Published test-name (TIMINGS)
@@ -1626,8 +1764,8 @@ addEventListener('fetch', event => {});`
1626
1764
 
1627
1765
  it("should only upload files that match the `site-include` arg", async () => {
1628
1766
  const assets = [
1629
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1630
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1767
+ { filePath: "file-1.txt", content: "Content of file-1" },
1768
+ { filePath: "file-2.txt", content: "Content of file-2" },
1631
1769
  ];
1632
1770
  const kvNamespace = {
1633
1771
  title: "__test-name-workers_sites_assets",
@@ -1648,13 +1786,13 @@ addEventListener('fetch', event => {});`
1648
1786
  // Check we only upload file-1
1649
1787
  mockUploadAssetsToKVRequest(
1650
1788
  kvNamespace.id,
1651
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1789
+ assets.filter((a) => a.filePath === "file-1.txt")
1652
1790
  );
1653
1791
  await runWrangler("publish --site-include file-1.txt");
1654
1792
 
1655
1793
  expect(std.out).toMatchInlineSnapshot(`
1656
- "Reading assets/file-1.txt...
1657
- Uploading as assets/file-1.2ca234f380.txt...
1794
+ "Reading file-1.txt...
1795
+ Uploading as file-1.2ca234f380.txt...
1658
1796
  ↗️ Done syncing assets
1659
1797
  Uploaded test-name (TIMINGS)
1660
1798
  Published test-name (TIMINGS)
@@ -1665,8 +1803,8 @@ addEventListener('fetch', event => {});`
1665
1803
 
1666
1804
  it("should not upload files that match the `site-exclude` arg", async () => {
1667
1805
  const assets = [
1668
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1669
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1806
+ { filePath: "file-1.txt", content: "Content of file-1" },
1807
+ { filePath: "file-2.txt", content: "Content of file-2" },
1670
1808
  ];
1671
1809
  const kvNamespace = {
1672
1810
  title: "__test-name-workers_sites_assets",
@@ -1687,13 +1825,13 @@ addEventListener('fetch', event => {});`
1687
1825
  // Check we only upload file-1
1688
1826
  mockUploadAssetsToKVRequest(
1689
1827
  kvNamespace.id,
1690
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1828
+ assets.filter((a) => a.filePath === "file-1.txt")
1691
1829
  );
1692
1830
  await runWrangler("publish --site-exclude file-2.txt");
1693
1831
 
1694
1832
  expect(std.out).toMatchInlineSnapshot(`
1695
- "Reading assets/file-1.txt...
1696
- Uploading as assets/file-1.2ca234f380.txt...
1833
+ "Reading file-1.txt...
1834
+ Uploading as file-1.2ca234f380.txt...
1697
1835
  ↗️ Done syncing assets
1698
1836
  Uploaded test-name (TIMINGS)
1699
1837
  Published test-name (TIMINGS)
@@ -1704,8 +1842,8 @@ addEventListener('fetch', event => {});`
1704
1842
 
1705
1843
  it("should only upload files that match the `site.include` config", async () => {
1706
1844
  const assets = [
1707
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1708
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1845
+ { filePath: "file-1.txt", content: "Content of file-1" },
1846
+ { filePath: "file-2.txt", content: "Content of file-2" },
1709
1847
  ];
1710
1848
  const kvNamespace = {
1711
1849
  title: "__test-name-workers_sites_assets",
@@ -1727,13 +1865,13 @@ addEventListener('fetch', event => {});`
1727
1865
  // Check we only upload file-1
1728
1866
  mockUploadAssetsToKVRequest(
1729
1867
  kvNamespace.id,
1730
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1868
+ assets.filter((a) => a.filePath === "file-1.txt")
1731
1869
  );
1732
1870
  await runWrangler("publish");
1733
1871
 
1734
1872
  expect(std.out).toMatchInlineSnapshot(`
1735
- "Reading assets/file-1.txt...
1736
- Uploading as assets/file-1.2ca234f380.txt...
1873
+ "Reading file-1.txt...
1874
+ Uploading as file-1.2ca234f380.txt...
1737
1875
  ↗️ Done syncing assets
1738
1876
  Uploaded test-name (TIMINGS)
1739
1877
  Published test-name (TIMINGS)
@@ -1744,8 +1882,8 @@ addEventListener('fetch', event => {});`
1744
1882
 
1745
1883
  it("should not upload files that match the `site.exclude` config", async () => {
1746
1884
  const assets = [
1747
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1748
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1885
+ { filePath: "file-1.txt", content: "Content of file-1" },
1886
+ { filePath: "file-2.txt", content: "Content of file-2" },
1749
1887
  ];
1750
1888
  const kvNamespace = {
1751
1889
  title: "__test-name-workers_sites_assets",
@@ -1767,13 +1905,13 @@ addEventListener('fetch', event => {});`
1767
1905
  // Check we only upload file-1
1768
1906
  mockUploadAssetsToKVRequest(
1769
1907
  kvNamespace.id,
1770
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1908
+ assets.filter((a) => a.filePath === "file-1.txt")
1771
1909
  );
1772
1910
  await runWrangler("publish");
1773
1911
 
1774
1912
  expect(std.out).toMatchInlineSnapshot(`
1775
- "Reading assets/file-1.txt...
1776
- Uploading as assets/file-1.2ca234f380.txt...
1913
+ "Reading file-1.txt...
1914
+ Uploading as file-1.2ca234f380.txt...
1777
1915
  ↗️ Done syncing assets
1778
1916
  Uploaded test-name (TIMINGS)
1779
1917
  Published test-name (TIMINGS)
@@ -1784,8 +1922,8 @@ addEventListener('fetch', event => {});`
1784
1922
 
1785
1923
  it("should use `site-include` arg over `site.include` config", async () => {
1786
1924
  const assets = [
1787
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1788
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1925
+ { filePath: "file-1.txt", content: "Content of file-1" },
1926
+ { filePath: "file-2.txt", content: "Content of file-2" },
1789
1927
  ];
1790
1928
  const kvNamespace = {
1791
1929
  title: "__test-name-workers_sites_assets",
@@ -1807,13 +1945,13 @@ addEventListener('fetch', event => {});`
1807
1945
  // Check we only upload file-1
1808
1946
  mockUploadAssetsToKVRequest(
1809
1947
  kvNamespace.id,
1810
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1948
+ assets.filter((a) => a.filePath === "file-1.txt")
1811
1949
  );
1812
1950
  await runWrangler("publish --site-include file-1.txt");
1813
1951
 
1814
1952
  expect(std.out).toMatchInlineSnapshot(`
1815
- "Reading assets/file-1.txt...
1816
- Uploading as assets/file-1.2ca234f380.txt...
1953
+ "Reading file-1.txt...
1954
+ Uploading as file-1.2ca234f380.txt...
1817
1955
  ↗️ Done syncing assets
1818
1956
  Uploaded test-name (TIMINGS)
1819
1957
  Published test-name (TIMINGS)
@@ -1824,8 +1962,8 @@ addEventListener('fetch', event => {});`
1824
1962
 
1825
1963
  it("should use `site-exclude` arg over `site.exclude` config", async () => {
1826
1964
  const assets = [
1827
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1828
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1965
+ { filePath: "file-1.txt", content: "Content of file-1" },
1966
+ { filePath: "file-2.txt", content: "Content of file-2" },
1829
1967
  ];
1830
1968
  const kvNamespace = {
1831
1969
  title: "__test-name-workers_sites_assets",
@@ -1835,7 +1973,7 @@ addEventListener('fetch', event => {});`
1835
1973
  main: "./index.js",
1836
1974
  site: {
1837
1975
  bucket: "assets",
1838
- exclude: ["assets/file-1.txt"],
1976
+ exclude: ["file-1.txt"],
1839
1977
  },
1840
1978
  });
1841
1979
  writeWorkerSource();
@@ -1847,13 +1985,13 @@ addEventListener('fetch', event => {});`
1847
1985
  // Check we only upload file-1
1848
1986
  mockUploadAssetsToKVRequest(
1849
1987
  kvNamespace.id,
1850
- assets.filter((a) => a.filePath.endsWith("assets/file-1.txt"))
1988
+ assets.filter((a) => a.filePath.endsWith("file-1.txt"))
1851
1989
  );
1852
1990
  await runWrangler("publish --site-exclude file-2.txt");
1853
1991
 
1854
1992
  expect(std.out).toMatchInlineSnapshot(`
1855
- "Reading assets/file-1.txt...
1856
- Uploading as assets/file-1.2ca234f380.txt...
1993
+ "Reading file-1.txt...
1994
+ Uploading as file-1.2ca234f380.txt...
1857
1995
  ↗️ Done syncing assets
1858
1996
  Uploaded test-name (TIMINGS)
1859
1997
  Published test-name (TIMINGS)
@@ -1865,11 +2003,11 @@ addEventListener('fetch', event => {});`
1865
2003
  it("should walk directories except node_modules", async () => {
1866
2004
  const assets = [
1867
2005
  {
1868
- filePath: "assets/directory-1/file-1.txt",
2006
+ filePath: "directory-1/file-1.txt",
1869
2007
  content: "Content of file-1",
1870
2008
  },
1871
2009
  {
1872
- filePath: "assets/node_modules/file-2.txt",
2010
+ filePath: "node_modules/file-2.txt",
1873
2011
  content: "Content of file-2",
1874
2012
  },
1875
2013
  ];
@@ -1894,8 +2032,8 @@ addEventListener('fetch', event => {});`
1894
2032
  await runWrangler("publish");
1895
2033
 
1896
2034
  expect(std.out).toMatchInlineSnapshot(`
1897
- "Reading assets/directory-1/file-1.txt...
1898
- Uploading as assets/directory-1/file-1.2ca234f380.txt...
2035
+ "Reading directory-1/file-1.txt...
2036
+ Uploading as directory-1/file-1.2ca234f380.txt...
1899
2037
  ↗️ Done syncing assets
1900
2038
  Uploaded test-name (TIMINGS)
1901
2039
  Published test-name (TIMINGS)
@@ -1907,15 +2045,15 @@ addEventListener('fetch', event => {});`
1907
2045
  it("should skip hidden files and directories except `.well-known`", async () => {
1908
2046
  const assets = [
1909
2047
  {
1910
- filePath: "assets/.hidden-file.txt",
2048
+ filePath: ".hidden-file.txt",
1911
2049
  content: "Content of hidden-file",
1912
2050
  },
1913
2051
  {
1914
- filePath: "assets/.hidden/file-1.txt",
2052
+ filePath: ".hidden/file-1.txt",
1915
2053
  content: "Content of file-1",
1916
2054
  },
1917
2055
  {
1918
- filePath: "assets/.well-known/file-2.txt",
2056
+ filePath: ".well-known/file-2.txt",
1919
2057
  content: "Content of file-2",
1920
2058
  },
1921
2059
  ];
@@ -1940,8 +2078,8 @@ addEventListener('fetch', event => {});`
1940
2078
  await runWrangler("publish");
1941
2079
 
1942
2080
  expect(std.out).toMatchInlineSnapshot(`
1943
- "Reading assets/.well-known/file-2.txt...
1944
- Uploading as assets/.well-known/file-2.5938485188.txt...
2081
+ "Reading .well-known/file-2.txt...
2082
+ Uploading as .well-known/file-2.5938485188.txt...
1945
2083
  ↗️ Done syncing assets
1946
2084
  Uploaded test-name (TIMINGS)
1947
2085
  Published test-name (TIMINGS)
@@ -1953,12 +2091,12 @@ addEventListener('fetch', event => {});`
1953
2091
  it("should error if the asset is over 25Mb", async () => {
1954
2092
  const assets = [
1955
2093
  {
1956
- filePath: "assets/large-file.txt",
2094
+ filePath: "large-file.txt",
1957
2095
  // This file is greater than 25MiB when base64 encoded but small enough to be uploaded.
1958
2096
  content: "X".repeat(25 * 1024 * 1024 * 0.8 + 1),
1959
2097
  },
1960
2098
  {
1961
- filePath: "assets/too-large-file.txt",
2099
+ filePath: "too-large-file.txt",
1962
2100
  content: "X".repeat(25 * 1024 * 1024 + 1),
1963
2101
  },
1964
2102
  ];
@@ -1970,7 +2108,7 @@ addEventListener('fetch', event => {});`
1970
2108
  main: "./index.js",
1971
2109
  site: {
1972
2110
  bucket: "assets",
1973
- exclude: ["assets/file-1.txt"],
2111
+ exclude: ["file-1.txt"],
1974
2112
  },
1975
2113
  });
1976
2114
  writeWorkerSource();
@@ -1983,25 +2121,122 @@ addEventListener('fetch', event => {});`
1983
2121
  await expect(
1984
2122
  runWrangler("publish")
1985
2123
  ).rejects.toThrowErrorMatchingInlineSnapshot(
1986
- `"File assets/too-large-file.txt is too big, it should be under 25 MiB. See https://developers.cloudflare.com/workers/platform/limits#kv-limits"`
2124
+ `"File too-large-file.txt is too big, it should be under 25 MiB. See https://developers.cloudflare.com/workers/platform/limits#kv-limits"`
1987
2125
  );
1988
2126
 
1989
2127
  expect(std.out).toMatchInlineSnapshot(`
1990
- "Reading assets/large-file.txt...
1991
- Uploading as assets/large-file.0ea0637a45.txt...
2128
+ "Reading large-file.txt...
2129
+ Uploading as large-file.0ea0637a45.txt...
2130
+ Reading too-large-file.txt...
1992
2131
 
1993
2132
  If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1994
2133
  `);
1995
2134
  expect(std.err).toMatchInlineSnapshot(`
1996
- "X [ERROR] File assets/too-large-file.txt is too big, it should be under 25 MiB. See https://developers.cloudflare.com/workers/platform/limits#kv-limits
2135
+ "X [ERROR] File too-large-file.txt is too big, it should be under 25 MiB. See https://developers.cloudflare.com/workers/platform/limits#kv-limits
1997
2136
 
1998
2137
  "
1999
2138
  `);
2000
2139
  });
2001
2140
 
2141
+ it("should batch assets in groups <100 mb", async () => {
2142
+ // Let's have 20 files, from size 1 - 20 mb
2143
+ const assets = Array.from({ length: 20 }, (_, index) => ({
2144
+ filePath: `file-${`${index}`.padStart(2, "0")}.txt`,
2145
+ content: "X".repeat(1024 * 1024 * (index + 1)),
2146
+ }));
2147
+
2148
+ const kvNamespace = {
2149
+ title: "__test-name-workers_sites_assets",
2150
+ id: "__test-name-workers_sites_assets-id",
2151
+ };
2152
+ writeWranglerToml({
2153
+ main: "./index.js",
2154
+ site: {
2155
+ bucket: "assets",
2156
+ },
2157
+ });
2158
+ writeWorkerSource();
2159
+ writeAssets(assets);
2160
+ mockUploadWorkerRequest();
2161
+ mockSubDomainRequest();
2162
+ mockListKVNamespacesRequest(kvNamespace);
2163
+ mockKeyListRequest(kvNamespace.id, []);
2164
+ const requests = mockUploadAssetsToKVRequest(kvNamespace.id);
2165
+
2166
+ await runWrangler("publish");
2167
+
2168
+ // We expect this to be uploaded in 3 batches
2169
+ // The first batch has 11 files (88mb)
2170
+ expect(requests[0].uploads.length).toEqual(11);
2171
+ // The next batch has 5 files (93mb)
2172
+ expect(requests[1].uploads.length).toEqual(5);
2173
+ // And the last one has 4 files (98mb)
2174
+ expect(requests[2].uploads.length).toEqual(4);
2175
+
2176
+ let assetIndex = 0;
2177
+ for (const request of requests) {
2178
+ for (const upload of request.uploads) {
2179
+ checkAssetUpload(assets[assetIndex], upload);
2180
+ assetIndex++;
2181
+ }
2182
+ }
2183
+
2184
+ expect(std).toMatchInlineSnapshot(`
2185
+ Object {
2186
+ "debug": "",
2187
+ "err": "",
2188
+ "out": "Reading file-00.txt...
2189
+ Uploading as file-00.be5be5dd26.txt...
2190
+ Reading file-01.txt...
2191
+ Uploading as file-01.4842d35994.txt...
2192
+ Reading file-02.txt...
2193
+ Uploading as file-02.990572ec63.txt...
2194
+ Reading file-03.txt...
2195
+ Uploading as file-03.9d7dda9045.txt...
2196
+ Reading file-04.txt...
2197
+ Uploading as file-04.2b6fac6382.txt...
2198
+ Reading file-05.txt...
2199
+ Uploading as file-05.55762dc758.txt...
2200
+ Reading file-06.txt...
2201
+ Uploading as file-06.f408a6b020.txt...
2202
+ Reading file-07.txt...
2203
+ Uploading as file-07.64c051715b.txt...
2204
+ Reading file-08.txt...
2205
+ Uploading as file-08.d286789adb.txt...
2206
+ Reading file-09.txt...
2207
+ Uploading as file-09.6838c183a8.txt...
2208
+ Reading file-10.txt...
2209
+ Uploading as file-10.6e03221d2a.txt...
2210
+ Reading file-11.txt...
2211
+ Uploading as file-11.37d3fb2eff.txt...
2212
+ Reading file-12.txt...
2213
+ Uploading as file-12.b3556942f8.txt...
2214
+ Reading file-13.txt...
2215
+ Uploading as file-13.680caf51b1.txt...
2216
+ Reading file-14.txt...
2217
+ Uploading as file-14.51e88468f0.txt...
2218
+ Reading file-15.txt...
2219
+ Uploading as file-15.8e3fedb394.txt...
2220
+ Reading file-16.txt...
2221
+ Uploading as file-16.c81c5e426f.txt...
2222
+ Reading file-17.txt...
2223
+ Uploading as file-17.4b2ae3c47b.txt...
2224
+ Reading file-18.txt...
2225
+ Uploading as file-18.07f245e02b.txt...
2226
+ Reading file-19.txt...
2227
+ Uploading as file-19.f0d69f705d.txt...
2228
+ ↗️ Done syncing assets
2229
+ Uploaded test-name (TIMINGS)
2230
+ Published test-name (TIMINGS)
2231
+ test-name.test-sub-domain.workers.dev",
2232
+ "warn": "",
2233
+ }
2234
+ `);
2235
+ });
2236
+
2002
2237
  it("should error if the asset key is over 512 characters", async () => {
2003
2238
  const longFilePathAsset = {
2004
- filePath: "assets/" + "folder/".repeat(100) + "file.txt",
2239
+ filePath: "folder/".repeat(100) + "file.txt",
2005
2240
  content: "content of file",
2006
2241
  };
2007
2242
  const kvNamespace = {
@@ -2024,16 +2259,16 @@ addEventListener('fetch', event => {});`
2024
2259
  await expect(
2025
2260
  runWrangler("publish")
2026
2261
  ).rejects.toThrowErrorMatchingInlineSnapshot(
2027
- `"The asset path key \\"assets/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.3da0d0cd12.txt\\" exceeds the maximum key size limit of 512. See https://developers.cloudflare.com/workers/platform/limits#kv-limits\\","`
2262
+ `"The asset path key \\"folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.3da0d0cd12.txt\\" exceeds the maximum key size limit of 512. See https://developers.cloudflare.com/workers/platform/limits#kv-limits\\","`
2028
2263
  );
2029
2264
 
2030
2265
  expect(std.out).toMatchInlineSnapshot(`
2031
- "Reading assets/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.txt...
2266
+ "Reading folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.txt...
2032
2267
 
2033
2268
  If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
2034
2269
  `);
2035
2270
  expect(std.err).toMatchInlineSnapshot(`
2036
- "X [ERROR] The asset path key \\"assets/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.3da0d0cd12.txt\\" exceeds the maximum key size limit of 512. See https://developers.cloudflare.com/workers/platform/limits#kv-limits\\",
2271
+ "X [ERROR] The asset path key \\"folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.3da0d0cd12.txt\\" exceeds the maximum key size limit of 512. See https://developers.cloudflare.com/workers/platform/limits#kv-limits\\",
2037
2272
 
2038
2273
  "
2039
2274
  `);
@@ -2041,8 +2276,8 @@ addEventListener('fetch', event => {});`
2041
2276
 
2042
2277
  it("should delete uploaded assets that aren't included anymore", async () => {
2043
2278
  const assets = [
2044
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
2045
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
2279
+ { filePath: "file-1.txt", content: "Content of file-1" },
2280
+ { filePath: "file-2.txt", content: "Content of file-2" },
2046
2281
  ];
2047
2282
  const kvNamespace = {
2048
2283
  title: "__test-name-workers_sites_assets",
@@ -2061,32 +2296,86 @@ addEventListener('fetch', event => {});`
2061
2296
  mockListKVNamespacesRequest(kvNamespace);
2062
2297
  mockKeyListRequest(kvNamespace.id, [
2063
2298
  // Put file-1 in the KV namespace
2064
- { name: "assets/file-1.2ca234f380.txt" },
2299
+ { name: "file-1.2ca234f380.txt" },
2065
2300
  // As well as a couple from a previous upload
2066
- { name: "assets/file-3.somehash.txt" },
2067
- { name: "assets/file-4.anotherhash.txt" },
2301
+ { name: "file-3.somehash.txt" },
2302
+ { name: "file-4.anotherhash.txt" },
2068
2303
  ]);
2069
2304
 
2070
2305
  // we upload only file-1.txt
2071
- mockUploadAssetsToKVRequest(kvNamespace.id, [
2072
- ...assets.filter((a) => a.filePath !== "assets/file-1.txt"),
2073
- ]);
2306
+ mockUploadAssetsToKVRequest(
2307
+ kvNamespace.id,
2308
+ assets.filter((a) => a.filePath !== "file-1.txt")
2309
+ );
2074
2310
 
2075
2311
  // and mark file-3 and file-4 for deletion
2076
2312
  mockDeleteUnusedAssetsRequest(kvNamespace.id, [
2077
- "assets/file-3.somehash.txt",
2078
- "assets/file-4.anotherhash.txt",
2313
+ "file-3.somehash.txt",
2314
+ "file-4.anotherhash.txt",
2079
2315
  ]);
2080
2316
 
2081
2317
  await runWrangler("publish");
2082
2318
 
2083
2319
  expect(std.out).toMatchInlineSnapshot(`
2084
- "Reading assets/file-1.txt...
2320
+ "Reading file-1.txt...
2085
2321
  Skipping - already uploaded.
2086
- Reading assets/file-2.txt...
2087
- Uploading as assets/file-2.5938485188.txt...
2088
- Deleting assets/file-3.somehash.txt from the asset store...
2089
- Deleting assets/file-4.anotherhash.txt from the asset store...
2322
+ Reading file-2.txt...
2323
+ Uploading as file-2.5938485188.txt...
2324
+ Deleting file-3.somehash.txt from the asset store...
2325
+ Deleting file-4.anotherhash.txt from the asset store...
2326
+ ↗️ Done syncing assets
2327
+ Uploaded test-name (TIMINGS)
2328
+ Published test-name (TIMINGS)
2329
+ test-name.test-sub-domain.workers.dev"
2330
+ `);
2331
+ expect(std.err).toMatchInlineSnapshot(`""`);
2332
+ });
2333
+
2334
+ it("should generate an asset manifest with keys relative to site.bucket", async () => {
2335
+ const assets = [
2336
+ { filePath: "file-1.txt", content: "Content of file-1" },
2337
+ { filePath: "file-2.txt", content: "Content of file-2" },
2338
+ ];
2339
+ const kvNamespace = {
2340
+ title: "__test-name-workers_sites_assets",
2341
+ id: "__test-name-workers_sites_assets-id",
2342
+ };
2343
+
2344
+ writeWranglerToml({
2345
+ main: "./src/index.js",
2346
+ site: {
2347
+ bucket: "assets",
2348
+ },
2349
+ });
2350
+ writeWorkerSource({ basePath: "src", type: "esm" });
2351
+ writeAssets(assets);
2352
+ mockUploadWorkerRequest({
2353
+ expectedBindings: [
2354
+ {
2355
+ name: "__STATIC_CONTENT",
2356
+ namespace_id: "__test-name-workers_sites_assets-id",
2357
+ type: "kv_namespace",
2358
+ },
2359
+ ],
2360
+ expectedModules: {
2361
+ __STATIC_CONTENT_MANIFEST:
2362
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
2363
+ },
2364
+ });
2365
+ mockSubDomainRequest();
2366
+ mockListKVNamespacesRequest(kvNamespace);
2367
+ mockKeyListRequest(kvNamespace.id, []);
2368
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
2369
+
2370
+ process.chdir("./src");
2371
+ await runWrangler("publish");
2372
+ process.chdir("../");
2373
+
2374
+ expect(std.out).toMatchInlineSnapshot(`
2375
+ "Reading file-1.txt...
2376
+ Uploading as file-1.2ca234f380.txt...
2377
+ Reading file-2.txt...
2378
+ Uploading as file-2.5938485188.txt...
2090
2379
  ↗️ Done syncing assets
2091
2380
  Uploaded test-name (TIMINGS)
2092
2381
  Published test-name (TIMINGS)
@@ -5004,7 +5293,7 @@ addEventListener('fetch', event => {});`
5004
5293
  "debug": "",
5005
5294
  "err": "",
5006
5295
  "out": "--dry-run: exiting now.",
5007
- "warn": "▲ [WARNING] Enabling node.js compatibility mode for builtins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details.
5296
+ "warn": "▲ [WARNING] Enabling node.js compatibility mode for built-ins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details.
5008
5297
 
5009
5298
  ",
5010
5299
  }
@@ -5048,7 +5337,7 @@ addEventListener('fetch', event => {});`
5048
5337
  "debug": "",
5049
5338
  "err": "",
5050
5339
  "out": "--dry-run: exiting now.",
5051
- "warn": "▲ [WARNING] Enabling node.js compatibility mode for builtins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details.
5340
+ "warn": "▲ [WARNING] Enabling node.js compatibility mode for built-ins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details.
5052
5341
 
5053
5342
  ",
5054
5343
  }
@@ -5058,10 +5347,16 @@ addEventListener('fetch', event => {});`
5058
5347
  });
5059
5348
 
5060
5349
  /** Write mock assets to the file system so they can be uploaded. */
5061
- function writeAssets(assets: { filePath: string; content: string }[]) {
5350
+ function writeAssets(
5351
+ assets: { filePath: string; content: string }[],
5352
+ destination = "assets"
5353
+ ) {
5062
5354
  for (const asset of assets) {
5063
- fs.mkdirSync(path.dirname(asset.filePath), { recursive: true });
5064
- fs.writeFileSync(asset.filePath, asset.content);
5355
+ const filePathDestination = path.join(destination, asset.filePath);
5356
+ fs.mkdirSync(path.dirname(filePathDestination), {
5357
+ recursive: true,
5358
+ });
5359
+ fs.writeFileSync(filePathDestination, asset.content);
5065
5360
  }
5066
5361
  }
5067
5362
 
@@ -5070,6 +5365,7 @@ function mockUploadWorkerRequest(
5070
5365
  options: {
5071
5366
  available_on_subdomain?: boolean;
5072
5367
  expectedEntry?: string;
5368
+ expectedMainModule?: string;
5073
5369
  expectedType?: "esm" | "sw";
5074
5370
  expectedBindings?: unknown;
5075
5371
  expectedModules?: Record<string, string>;
@@ -5083,6 +5379,7 @@ function mockUploadWorkerRequest(
5083
5379
  const {
5084
5380
  available_on_subdomain = true,
5085
5381
  expectedEntry,
5382
+ expectedMainModule = "index.js",
5086
5383
  expectedType = "esm",
5087
5384
  expectedBindings,
5088
5385
  expectedModules = {},
@@ -5106,6 +5403,7 @@ function mockUploadWorkerRequest(
5106
5403
  expect(envName).toEqual(env);
5107
5404
  }
5108
5405
  expect(queryParams.get("include_subdomain_availability")).toEqual("true");
5406
+ expect(queryParams.get("excludeScript")).toEqual("true");
5109
5407
  const formBody = body as FormData;
5110
5408
  if (expectedEntry !== undefined) {
5111
5409
  expect(await (formBody.get("index.js") as File).text()).toMatch(
@@ -5116,7 +5414,7 @@ function mockUploadWorkerRequest(
5116
5414
  formBody.get("metadata") as string
5117
5415
  ) as WorkerMetadata;
5118
5416
  if (expectedType === "esm") {
5119
- expect(metadata.main_module).toEqual("index.js");
5417
+ expect(metadata.main_module).toEqual(expectedMainModule);
5120
5418
  } else {
5121
5419
  expect(metadata.body_part).toEqual("index.js");
5122
5420
  }
@@ -5226,6 +5524,49 @@ function mockPublishRoutesRequest({
5226
5524
  );
5227
5525
  }
5228
5526
 
5527
+ function mockUnauthorizedPublishRoutesRequest({
5528
+ env = undefined,
5529
+ legacyEnv = false,
5530
+ }: {
5531
+ env?: string | undefined;
5532
+ legacyEnv?: boolean | undefined;
5533
+ } = {}) {
5534
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5535
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5536
+
5537
+ setMockRawResponse(
5538
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/routes`,
5539
+ "PUT",
5540
+ () =>
5541
+ createFetchResult(null, false, [
5542
+ { message: "Authentication error", code: 10000 },
5543
+ ])
5544
+ );
5545
+ }
5546
+
5547
+ function mockCollectKnownRoutesRequest(
5548
+ routes: { pattern: string; script: string }[]
5549
+ ) {
5550
+ setMockResponse(`/zones/:zoneId/workers/routes`, "GET", () => routes);
5551
+ }
5552
+
5553
+ function mockGetZoneFromHostRequest(host: string, zone: string) {
5554
+ setMockResponse("/zones", (_uri, _init, queryParams) => {
5555
+ expect(queryParams.get("name")).toEqual(host);
5556
+ return [{ id: zone }];
5557
+ });
5558
+ }
5559
+
5560
+ function mockPublishRoutesFallbackRequest(route: {
5561
+ pattern: string;
5562
+ script: string;
5563
+ }) {
5564
+ setMockResponse(`/zones/:zoneId/workers/routes`, "POST", (_url, { body }) => {
5565
+ expect(JSON.parse(body as string)).toEqual(route);
5566
+ return route.pattern;
5567
+ });
5568
+ }
5569
+
5229
5570
  function mockPublishCustomDomainsRequest({
5230
5571
  publishFlags,
5231
5572
  domains = [],
@@ -5334,16 +5675,28 @@ function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
5334
5675
  );
5335
5676
  }
5336
5677
 
5678
+ interface ExpectedAsset {
5679
+ filePath: string;
5680
+ content: string;
5681
+ expiration?: number;
5682
+ expiration_ttl?: number;
5683
+ }
5684
+ interface StaticAssetUpload {
5685
+ key: string;
5686
+ base64: boolean;
5687
+ value: string;
5688
+ expiration: number | undefined;
5689
+ expiration_ttl: number | undefined;
5690
+ }
5691
+
5337
5692
  /** Create a mock handler for the request that tries to do a bulk upload of assets to a KV namespace. */
5338
5693
  function mockUploadAssetsToKVRequest(
5339
5694
  expectedNamespaceId: string,
5340
- assets: {
5341
- filePath: string;
5342
- content: string;
5343
- expiration?: number;
5344
- expiration_ttl?: number;
5345
- }[]
5695
+ assets?: ExpectedAsset[]
5346
5696
  ) {
5697
+ const requests: {
5698
+ uploads: StaticAssetUpload[];
5699
+ }[] = [];
5347
5700
  setMockResponse(
5348
5701
  "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
5349
5702
  "PUT",
@@ -5351,32 +5704,31 @@ function mockUploadAssetsToKVRequest(
5351
5704
  expect(accountId).toEqual("some-account-id");
5352
5705
  expect(namespaceId).toEqual(expectedNamespaceId);
5353
5706
  const uploads = JSON.parse(body as string);
5354
- expect(assets.length).toEqual(uploads.length);
5355
- for (let i = 0; i < uploads.length; i++) {
5356
- const asset = assets[i];
5357
- const upload = uploads[i];
5358
- // The asset key consists of:
5359
- // - the basename of the filepath
5360
- // - some hash value
5361
- // - the extension
5362
- const keyMatcher = new RegExp(
5363
- "^" +
5364
- asset.filePath
5365
- .replace(/(\.[^.]+)$/, ".[a-z0-9]+$1")
5366
- .replace(/\./g, "\\.")
5367
- );
5368
- expect(upload.key).toMatch(keyMatcher);
5369
- // The asset value is base64 encoded.
5370
- expect(upload.base64).toBe(true);
5371
- expect(Buffer.from(upload.value, "base64").toString()).toEqual(
5372
- asset.content
5373
- );
5374
- expect(upload.expiration).toEqual(asset.expiration);
5375
- expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
5707
+ if (assets) {
5708
+ expect(assets.length).toEqual(uploads.length);
5709
+ for (let i = 0; i < uploads.length; i++) {
5710
+ checkAssetUpload(assets[i], uploads[i]);
5711
+ }
5712
+ } else {
5713
+ requests.push({ uploads });
5376
5714
  }
5377
- return null;
5378
5715
  }
5379
5716
  );
5717
+ return requests;
5718
+ }
5719
+
5720
+ function checkAssetUpload(asset: ExpectedAsset, upload: StaticAssetUpload) {
5721
+ // The asset key consists of: `<basename>.<hash>.<extension>`
5722
+ const keyMatcher = new RegExp(
5723
+ "^" +
5724
+ asset.filePath.replace(/(\.[^.]+)$/, ".[a-z0-9]+$1").replace(/\./g, "\\.")
5725
+ );
5726
+ expect(upload.key).toMatch(keyMatcher);
5727
+ // The asset value is base64 encoded.
5728
+ expect(upload.base64).toBe(true);
5729
+ expect(Buffer.from(upload.value, "base64").toString()).toEqual(asset.content);
5730
+ expect(upload.expiration).toEqual(asset.expiration);
5731
+ expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
5380
5732
  }
5381
5733
 
5382
5734
  /** Create a mock handler for thr request that does a bulk delete of unused assets */