wrangler 2.0.9 → 2.0.14

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 (61) hide show
  1. package/kv-asset-handler.js +1 -0
  2. package/package.json +4 -2
  3. package/src/__tests__/configuration.test.ts +255 -142
  4. package/src/__tests__/dev.test.tsx +27 -0
  5. package/src/__tests__/index.test.ts +2 -1
  6. package/src/__tests__/jest.setup.ts +30 -0
  7. package/src/__tests__/publish.test.ts +393 -160
  8. package/src/__tests__/user.test.ts +1 -0
  9. package/src/bundle.ts +9 -5
  10. package/src/config/environment.ts +1 -1
  11. package/src/config/validation-helpers.ts +10 -1
  12. package/src/config/validation.ts +22 -13
  13. package/src/dev/dev.tsx +29 -45
  14. package/src/dev/local.tsx +10 -7
  15. package/src/dev/remote.tsx +4 -1
  16. package/src/dev/use-esbuild.ts +1 -4
  17. package/src/generate-auth-url.ts +33 -0
  18. package/src/generate-random-state.ts +16 -0
  19. package/src/index.tsx +234 -179
  20. package/src/open-in-browser.ts +1 -3
  21. package/src/pages.tsx +295 -240
  22. package/src/parse.ts +2 -1
  23. package/src/proxy.ts +19 -6
  24. package/src/publish.ts +6 -1
  25. package/src/sites.tsx +49 -18
  26. package/src/user.tsx +12 -24
  27. package/templates/static-asset-facade.js +2 -6
  28. package/wrangler-dist/cli.js +73627 -73462
  29. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  30. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  31. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  32. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  33. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  34. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  35. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  36. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  37. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  38. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  39. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  40. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  41. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  42. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  43. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  44. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  45. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  46. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  47. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  48. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  49. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  50. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  51. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  52. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  53. package/vendor/wrangler-mime/LICENSE +0 -21
  54. package/vendor/wrangler-mime/Mime.js +0 -97
  55. package/vendor/wrangler-mime/README.md +0 -187
  56. package/vendor/wrangler-mime/cli.js +0 -46
  57. package/vendor/wrangler-mime/index.js +0 -4
  58. package/vendor/wrangler-mime/lite.js +0 -4
  59. package/vendor/wrangler-mime/package.json +0 -52
  60. package/vendor/wrangler-mime/types/other.js +0 -1
  61. package/vendor/wrangler-mime/types/standard.js +0 -1
@@ -66,7 +66,6 @@ describe("publish", () => {
66
66
  writeWorkerSource();
67
67
  mockSubDomainRequest();
68
68
  mockUploadWorkerRequest();
69
-
70
69
  mockOAuthServerCallback();
71
70
  const accessTokenRequest = mockGrantAccessToken({ respondWith: "ok" });
72
71
  mockGrantAuthorization({ respondWith: "success" });
@@ -79,6 +78,7 @@ describe("publish", () => {
79
78
 
80
79
  expect(std.out).toMatchInlineSnapshot(`
81
80
  "Attempting to login via OAuth...
81
+ Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20pages%3Awrite%20zone%3Aread%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
82
82
  Successfully logged in.
83
83
  Uploaded test-name (TIMINGS)
84
84
  Published test-name (TIMINGS)
@@ -108,6 +108,7 @@ describe("publish", () => {
108
108
 
109
109
  expect(std.out).toMatchInlineSnapshot(`
110
110
  "Attempting to login via OAuth...
111
+ Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20pages%3Awrite%20zone%3Aread%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
111
112
  Successfully logged in.
112
113
  Uploaded test-name (TIMINGS)
113
114
  Published test-name (TIMINGS)
@@ -1223,8 +1224,8 @@ addEventListener('fetch', event => {});`
1223
1224
 
1224
1225
  it("should warn if there is a `site.entry-point` configuration", async () => {
1225
1226
  const assets = [
1226
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1227
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1227
+ { filePath: "file-1.txt", content: "Content of file-1" },
1228
+ { filePath: "file-2.txt", content: "Content of file-2" },
1228
1229
  ];
1229
1230
  const kvNamespace = {
1230
1231
  title: "__test-name-workers_sites_assets",
@@ -1250,10 +1251,10 @@ addEventListener('fetch', event => {});`
1250
1251
  Object {
1251
1252
  "debug": "",
1252
1253
  "err": "",
1253
- "out": "Reading assets/file-1.txt...
1254
- Uploading as assets/file-1.2ca234f380.txt...
1255
- Reading assets/file-2.txt...
1256
- Uploading as assets/file-2.5938485188.txt...
1254
+ "out": "Reading file-1.txt...
1255
+ Uploading as file-1.2ca234f380.txt...
1256
+ Reading file-2.txt...
1257
+ Uploading as file-2.5938485188.txt...
1257
1258
  ↗️ Done syncing assets
1258
1259
  Uploaded test-name (TIMINGS)
1259
1260
  Published test-name (TIMINGS)
@@ -1274,8 +1275,8 @@ addEventListener('fetch', event => {});`
1274
1275
 
1275
1276
  it("should resolve site.entry-point relative to wrangler.toml", async () => {
1276
1277
  const assets = [
1277
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1278
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1278
+ { filePath: "file-1.txt", content: "Content of file-1" },
1279
+ { filePath: "file-2.txt", content: "Content of file-2" },
1279
1280
  ];
1280
1281
  const kvNamespace = {
1281
1282
  title: "__test-name-workers_sites_assets",
@@ -1301,10 +1302,10 @@ addEventListener('fetch', event => {});`
1301
1302
  await runWrangler("publish --config ./my-site/wrangler.toml");
1302
1303
 
1303
1304
  expect(std.out).toMatchInlineSnapshot(`
1304
- "Reading assets/file-1.txt...
1305
- Uploading as assets/file-1.2ca234f380.txt...
1306
- Reading assets/file-2.txt...
1307
- Uploading as assets/file-2.5938485188.txt...
1305
+ "Reading file-1.txt...
1306
+ Uploading as file-1.2ca234f380.txt...
1307
+ Reading file-2.txt...
1308
+ Uploading as file-2.5938485188.txt...
1308
1309
  ↗️ Done syncing assets
1309
1310
  Uploaded test-name (TIMINGS)
1310
1311
  Published test-name (TIMINGS)
@@ -1369,8 +1370,8 @@ addEventListener('fetch', event => {});`
1369
1370
  describe("asset upload", () => {
1370
1371
  it("should upload all the files in the directory specified by `config.site.bucket`", async () => {
1371
1372
  const assets = [
1372
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1373
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1373
+ { filePath: "file-1.txt", content: "Content of file-1" },
1374
+ { filePath: "file-2.txt", content: "Content of file-2" },
1374
1375
  ];
1375
1376
  const kvNamespace = {
1376
1377
  title: "__test-name-workers_sites_assets",
@@ -1392,10 +1393,10 @@ addEventListener('fetch', event => {});`
1392
1393
  await runWrangler("publish");
1393
1394
 
1394
1395
  expect(std.out).toMatchInlineSnapshot(`
1395
- "Reading assets/file-1.txt...
1396
- Uploading as assets/file-1.2ca234f380.txt...
1397
- Reading assets/file-2.txt...
1398
- Uploading as assets/file-2.5938485188.txt...
1396
+ "Reading file-1.txt...
1397
+ Uploading as file-1.2ca234f380.txt...
1398
+ Reading file-2.txt...
1399
+ Uploading as file-2.5938485188.txt...
1399
1400
  ↗️ Done syncing assets
1400
1401
  Uploaded test-name (TIMINGS)
1401
1402
  Published test-name (TIMINGS)
@@ -1404,10 +1405,73 @@ addEventListener('fetch', event => {});`
1404
1405
  expect(std.err).toMatchInlineSnapshot(`""`);
1405
1406
  });
1406
1407
 
1408
+ it("should upload all the files in the directory specified by `--experimental-public`", async () => {
1409
+ const assets = [
1410
+ { filePath: "file-1.txt", content: "Content of file-1" },
1411
+ { filePath: "file-2.txt", content: "Content of file-2" },
1412
+ ];
1413
+ const kvNamespace = {
1414
+ title: "__test-name-workers_sites_assets",
1415
+ id: "__test-name-workers_sites_assets-id",
1416
+ };
1417
+ writeWranglerToml({
1418
+ main: "./index.js",
1419
+ });
1420
+ writeWorkerSource();
1421
+ writeAssets(assets);
1422
+ mockUploadWorkerRequest({
1423
+ expectedMainModule: "stdin.js",
1424
+ });
1425
+ mockSubDomainRequest();
1426
+ mockListKVNamespacesRequest(kvNamespace);
1427
+ mockKeyListRequest(kvNamespace.id, []);
1428
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
1429
+ await runWrangler("publish --experimental-public assets");
1430
+
1431
+ expect(std.out).toMatchInlineSnapshot(`
1432
+ "Reading file-1.txt...
1433
+ Uploading as file-1.2ca234f380.txt...
1434
+ Reading file-2.txt...
1435
+ Uploading as file-2.5938485188.txt...
1436
+ ↗️ Done syncing assets
1437
+ Uploaded test-name (TIMINGS)
1438
+ Published test-name (TIMINGS)
1439
+ test-name.test-sub-domain.workers.dev"
1440
+ `);
1441
+ expect(std.err).toMatchInlineSnapshot(`""`);
1442
+ });
1443
+
1444
+ it("should error if --experimental-public and --site are used together", async () => {
1445
+ writeWranglerToml({
1446
+ main: "./index.js",
1447
+ });
1448
+ writeWorkerSource();
1449
+ await expect(
1450
+ runWrangler("publish --experimental-public abc --site xyz")
1451
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1452
+ `"Cannot use --experimental-public and a Site configuration together."`
1453
+ );
1454
+ });
1455
+
1456
+ it("should error if --experimental-public and config.site are used together", async () => {
1457
+ writeWranglerToml({
1458
+ main: "./index.js",
1459
+ site: {
1460
+ bucket: "xyz",
1461
+ },
1462
+ });
1463
+ writeWorkerSource();
1464
+ await expect(
1465
+ runWrangler("publish --experimental-public abc")
1466
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1467
+ `"Cannot use --experimental-public and a Site configuration together."`
1468
+ );
1469
+ });
1470
+
1407
1471
  it("should not contain backslash for assets with nested directories", async () => {
1408
1472
  const assets = [
1409
- { filePath: "assets/subdir/file-1.txt", content: "Content of file-1" },
1410
- { filePath: "assets/subdir/file-2.txt", content: "Content of file-2" },
1473
+ { filePath: "subdir/file-1.txt", content: "Content of file-1" },
1474
+ { filePath: "subdir/file-2.txt", content: "Content of file-2" },
1411
1475
  ];
1412
1476
  const kvNamespace = {
1413
1477
  title: "__test-name-workers_sites_assets",
@@ -1431,7 +1495,7 @@ addEventListener('fetch', event => {});`
1431
1495
  ],
1432
1496
  expectedModules: {
1433
1497
  __STATIC_CONTENT_MANIFEST:
1434
- '{"subdir/file-1.txt":"assets/subdir/file-1.2ca234f380.txt","subdir/file-2.txt":"assets/subdir/file-2.5938485188.txt"}',
1498
+ '{"subdir/file-1.txt":"subdir/file-1.2ca234f380.txt","subdir/file-2.txt":"subdir/file-2.5938485188.txt"}',
1435
1499
  },
1436
1500
  });
1437
1501
  mockSubDomainRequest();
@@ -1442,10 +1506,10 @@ addEventListener('fetch', event => {});`
1442
1506
  await runWrangler("publish");
1443
1507
 
1444
1508
  expect(std.out).toMatchInlineSnapshot(`
1445
- "Reading assets/subdir/file-1.txt...
1446
- Uploading as assets/subdir/file-1.2ca234f380.txt...
1447
- Reading assets/subdir/file-2.txt...
1448
- Uploading as assets/subdir/file-2.5938485188.txt...
1509
+ "Reading subdir/file-1.txt...
1510
+ Uploading as subdir/file-1.2ca234f380.txt...
1511
+ Reading subdir/file-2.txt...
1512
+ Uploading as subdir/file-2.5938485188.txt...
1449
1513
  ↗️ Done syncing assets
1450
1514
  Uploaded test-name (TIMINGS)
1451
1515
  Published test-name (TIMINGS)
@@ -1456,8 +1520,8 @@ addEventListener('fetch', event => {});`
1456
1520
 
1457
1521
  it("when using a service-worker type, it should add an asset manifest as a text_blob, and bind to a namespace", async () => {
1458
1522
  const assets = [
1459
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1460
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1523
+ { filePath: "file-1.txt", content: "Content of file-1" },
1524
+ { filePath: "file-2.txt", content: "Content of file-2" },
1461
1525
  ];
1462
1526
  const kvNamespace = {
1463
1527
  title: "__test-name-workers_sites_assets",
@@ -1475,7 +1539,7 @@ addEventListener('fetch', event => {});`
1475
1539
  expectedType: "sw",
1476
1540
  expectedModules: {
1477
1541
  __STATIC_CONTENT_MANIFEST:
1478
- '{"file-1.txt":"assets/file-1.2ca234f380.txt","file-2.txt":"assets/file-2.5938485188.txt"}',
1542
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
1479
1543
  },
1480
1544
  expectedBindings: [
1481
1545
  {
@@ -1498,10 +1562,10 @@ addEventListener('fetch', event => {});`
1498
1562
  await runWrangler("publish");
1499
1563
 
1500
1564
  expect(std.out).toMatchInlineSnapshot(`
1501
- "Reading assets/file-1.txt...
1502
- Uploading as assets/file-1.2ca234f380.txt...
1503
- Reading assets/file-2.txt...
1504
- Uploading as assets/file-2.5938485188.txt...
1565
+ "Reading file-1.txt...
1566
+ Uploading as file-1.2ca234f380.txt...
1567
+ Reading file-2.txt...
1568
+ Uploading as file-2.5938485188.txt...
1505
1569
  ↗️ Done syncing assets
1506
1570
  Uploaded test-name (TIMINGS)
1507
1571
  Published test-name (TIMINGS)
@@ -1512,8 +1576,8 @@ addEventListener('fetch', event => {});`
1512
1576
 
1513
1577
  it("when using a module worker type, it should add an asset manifest module, and bind to a namespace", async () => {
1514
1578
  const assets = [
1515
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1516
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1579
+ { filePath: "file-1.txt", content: "Content of file-1" },
1580
+ { filePath: "file-2.txt", content: "Content of file-2" },
1517
1581
  ];
1518
1582
  const kvNamespace = {
1519
1583
  title: "__test-name-workers_sites_assets",
@@ -1537,7 +1601,7 @@ addEventListener('fetch', event => {});`
1537
1601
  ],
1538
1602
  expectedModules: {
1539
1603
  __STATIC_CONTENT_MANIFEST:
1540
- '{"file-1.txt":"assets/file-1.2ca234f380.txt","file-2.txt":"assets/file-2.5938485188.txt"}',
1604
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
1541
1605
  },
1542
1606
  });
1543
1607
  mockSubDomainRequest();
@@ -1548,10 +1612,10 @@ addEventListener('fetch', event => {});`
1548
1612
  await runWrangler("publish");
1549
1613
 
1550
1614
  expect(std.out).toMatchInlineSnapshot(`
1551
- "Reading assets/file-1.txt...
1552
- Uploading as assets/file-1.2ca234f380.txt...
1553
- Reading assets/file-2.txt...
1554
- Uploading as assets/file-2.5938485188.txt...
1615
+ "Reading file-1.txt...
1616
+ Uploading as file-1.2ca234f380.txt...
1617
+ Reading file-2.txt...
1618
+ Uploading as file-2.5938485188.txt...
1555
1619
  ↗️ Done syncing assets
1556
1620
  Uploaded test-name (TIMINGS)
1557
1621
  Published test-name (TIMINGS)
@@ -1563,8 +1627,8 @@ addEventListener('fetch', event => {});`
1563
1627
  it("should make environment specific kv namespace for assets, even for service envs", async () => {
1564
1628
  // This is the same test as the one before this, but with an env arg
1565
1629
  const assets = [
1566
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1567
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1630
+ { filePath: "file-1.txt", content: "Content of file-1" },
1631
+ { filePath: "file-2.txt", content: "Content of file-2" },
1568
1632
  ];
1569
1633
  const kvNamespace = {
1570
1634
  title: "__test-name-some-env-workers_sites_assets",
@@ -1596,10 +1660,10 @@ addEventListener('fetch', event => {});`
1596
1660
  await runWrangler("publish --env some-env --legacy-env false");
1597
1661
 
1598
1662
  expect(std.out).toMatchInlineSnapshot(`
1599
- "Reading assets/file-1.txt...
1600
- Uploading as assets/file-1.2ca234f380.txt...
1601
- Reading assets/file-2.txt...
1602
- Uploading as assets/file-2.5938485188.txt...
1663
+ "Reading file-1.txt...
1664
+ Uploading as file-1.2ca234f380.txt...
1665
+ Reading file-2.txt...
1666
+ Uploading as file-2.5938485188.txt...
1603
1667
  ↗️ Done syncing assets
1604
1668
  Uploaded test-name (some-env) (TIMINGS)
1605
1669
  Published test-name (some-env) (TIMINGS)
@@ -1611,8 +1675,8 @@ addEventListener('fetch', event => {});`
1611
1675
  it("should make environment specific kv namespace for assets, even for legacy envs", async () => {
1612
1676
  // And this is the same test as the one before this, but with legacyEnv:true
1613
1677
  const assets = [
1614
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1615
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1678
+ { filePath: "file-1.txt", content: "Content of file-1" },
1679
+ { filePath: "file-2.txt", content: "Content of file-2" },
1616
1680
  ];
1617
1681
  const kvNamespace = {
1618
1682
  title: "__test-name-some-env-workers_sites_assets",
@@ -1645,10 +1709,10 @@ addEventListener('fetch', event => {});`
1645
1709
  await runWrangler("publish --env some-env --legacy-env true");
1646
1710
 
1647
1711
  expect(std.out).toMatchInlineSnapshot(`
1648
- "Reading assets/file-1.txt...
1649
- Uploading as assets/file-1.2ca234f380.txt...
1650
- Reading assets/file-2.txt...
1651
- Uploading as assets/file-2.5938485188.txt...
1712
+ "Reading file-1.txt...
1713
+ Uploading as file-1.2ca234f380.txt...
1714
+ Reading file-2.txt...
1715
+ Uploading as file-2.5938485188.txt...
1652
1716
  ↗️ Done syncing assets
1653
1717
  Uploaded test-name-some-env (TIMINGS)
1654
1718
  Published test-name-some-env (TIMINGS)
@@ -1659,8 +1723,8 @@ addEventListener('fetch', event => {});`
1659
1723
 
1660
1724
  it("should only upload files that are not already in the KV namespace", async () => {
1661
1725
  const assets = [
1662
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1663
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1726
+ { filePath: "file-1.txt", content: "Content of file-1" },
1727
+ { filePath: "file-2.txt", content: "Content of file-2" },
1664
1728
  ];
1665
1729
  const kvNamespace = {
1666
1730
  title: "__test-name-workers_sites_assets",
@@ -1678,21 +1742,19 @@ addEventListener('fetch', event => {});`
1678
1742
  mockSubDomainRequest();
1679
1743
  mockListKVNamespacesRequest(kvNamespace);
1680
1744
  // Put file-1 in the KV namespace
1681
- mockKeyListRequest(kvNamespace.id, [
1682
- { name: "assets/file-1.2ca234f380.txt" },
1683
- ]);
1745
+ mockKeyListRequest(kvNamespace.id, [{ name: "file-1.2ca234f380.txt" }]);
1684
1746
  // Check we do not upload file-1
1685
1747
  mockUploadAssetsToKVRequest(
1686
1748
  kvNamespace.id,
1687
- assets.filter((a) => a.filePath !== "assets/file-1.txt")
1749
+ assets.filter((a) => a.filePath !== "file-1.txt")
1688
1750
  );
1689
1751
  await runWrangler("publish");
1690
1752
 
1691
1753
  expect(std.out).toMatchInlineSnapshot(`
1692
- "Reading assets/file-1.txt...
1754
+ "Reading file-1.txt...
1693
1755
  Skipping - already uploaded.
1694
- Reading assets/file-2.txt...
1695
- Uploading as assets/file-2.5938485188.txt...
1756
+ Reading file-2.txt...
1757
+ Uploading as file-2.5938485188.txt...
1696
1758
  ↗️ Done syncing assets
1697
1759
  Uploaded test-name (TIMINGS)
1698
1760
  Published test-name (TIMINGS)
@@ -1703,8 +1765,8 @@ addEventListener('fetch', event => {});`
1703
1765
 
1704
1766
  it("should only upload files that match the `site-include` arg", async () => {
1705
1767
  const assets = [
1706
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1707
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1768
+ { filePath: "file-1.txt", content: "Content of file-1" },
1769
+ { filePath: "file-2.txt", content: "Content of file-2" },
1708
1770
  ];
1709
1771
  const kvNamespace = {
1710
1772
  title: "__test-name-workers_sites_assets",
@@ -1725,13 +1787,13 @@ addEventListener('fetch', event => {});`
1725
1787
  // Check we only upload file-1
1726
1788
  mockUploadAssetsToKVRequest(
1727
1789
  kvNamespace.id,
1728
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1790
+ assets.filter((a) => a.filePath === "file-1.txt")
1729
1791
  );
1730
1792
  await runWrangler("publish --site-include file-1.txt");
1731
1793
 
1732
1794
  expect(std.out).toMatchInlineSnapshot(`
1733
- "Reading assets/file-1.txt...
1734
- Uploading as assets/file-1.2ca234f380.txt...
1795
+ "Reading file-1.txt...
1796
+ Uploading as file-1.2ca234f380.txt...
1735
1797
  ↗️ Done syncing assets
1736
1798
  Uploaded test-name (TIMINGS)
1737
1799
  Published test-name (TIMINGS)
@@ -1742,8 +1804,8 @@ addEventListener('fetch', event => {});`
1742
1804
 
1743
1805
  it("should not upload files that match the `site-exclude` arg", async () => {
1744
1806
  const assets = [
1745
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1746
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1807
+ { filePath: "file-1.txt", content: "Content of file-1" },
1808
+ { filePath: "file-2.txt", content: "Content of file-2" },
1747
1809
  ];
1748
1810
  const kvNamespace = {
1749
1811
  title: "__test-name-workers_sites_assets",
@@ -1764,13 +1826,13 @@ addEventListener('fetch', event => {});`
1764
1826
  // Check we only upload file-1
1765
1827
  mockUploadAssetsToKVRequest(
1766
1828
  kvNamespace.id,
1767
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1829
+ assets.filter((a) => a.filePath === "file-1.txt")
1768
1830
  );
1769
1831
  await runWrangler("publish --site-exclude file-2.txt");
1770
1832
 
1771
1833
  expect(std.out).toMatchInlineSnapshot(`
1772
- "Reading assets/file-1.txt...
1773
- Uploading as assets/file-1.2ca234f380.txt...
1834
+ "Reading file-1.txt...
1835
+ Uploading as file-1.2ca234f380.txt...
1774
1836
  ↗️ Done syncing assets
1775
1837
  Uploaded test-name (TIMINGS)
1776
1838
  Published test-name (TIMINGS)
@@ -1781,8 +1843,8 @@ addEventListener('fetch', event => {});`
1781
1843
 
1782
1844
  it("should only upload files that match the `site.include` config", async () => {
1783
1845
  const assets = [
1784
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1785
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1846
+ { filePath: "file-1.txt", content: "Content of file-1" },
1847
+ { filePath: "file-2.txt", content: "Content of file-2" },
1786
1848
  ];
1787
1849
  const kvNamespace = {
1788
1850
  title: "__test-name-workers_sites_assets",
@@ -1804,13 +1866,13 @@ addEventListener('fetch', event => {});`
1804
1866
  // Check we only upload file-1
1805
1867
  mockUploadAssetsToKVRequest(
1806
1868
  kvNamespace.id,
1807
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1869
+ assets.filter((a) => a.filePath === "file-1.txt")
1808
1870
  );
1809
1871
  await runWrangler("publish");
1810
1872
 
1811
1873
  expect(std.out).toMatchInlineSnapshot(`
1812
- "Reading assets/file-1.txt...
1813
- Uploading as assets/file-1.2ca234f380.txt...
1874
+ "Reading file-1.txt...
1875
+ Uploading as file-1.2ca234f380.txt...
1814
1876
  ↗️ Done syncing assets
1815
1877
  Uploaded test-name (TIMINGS)
1816
1878
  Published test-name (TIMINGS)
@@ -1821,8 +1883,8 @@ addEventListener('fetch', event => {});`
1821
1883
 
1822
1884
  it("should not upload files that match the `site.exclude` config", async () => {
1823
1885
  const assets = [
1824
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1825
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1886
+ { filePath: "file-1.txt", content: "Content of file-1" },
1887
+ { filePath: "file-2.txt", content: "Content of file-2" },
1826
1888
  ];
1827
1889
  const kvNamespace = {
1828
1890
  title: "__test-name-workers_sites_assets",
@@ -1844,13 +1906,13 @@ addEventListener('fetch', event => {});`
1844
1906
  // Check we only upload file-1
1845
1907
  mockUploadAssetsToKVRequest(
1846
1908
  kvNamespace.id,
1847
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1909
+ assets.filter((a) => a.filePath === "file-1.txt")
1848
1910
  );
1849
1911
  await runWrangler("publish");
1850
1912
 
1851
1913
  expect(std.out).toMatchInlineSnapshot(`
1852
- "Reading assets/file-1.txt...
1853
- Uploading as assets/file-1.2ca234f380.txt...
1914
+ "Reading file-1.txt...
1915
+ Uploading as file-1.2ca234f380.txt...
1854
1916
  ↗️ Done syncing assets
1855
1917
  Uploaded test-name (TIMINGS)
1856
1918
  Published test-name (TIMINGS)
@@ -1861,8 +1923,8 @@ addEventListener('fetch', event => {});`
1861
1923
 
1862
1924
  it("should use `site-include` arg over `site.include` config", async () => {
1863
1925
  const assets = [
1864
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1865
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1926
+ { filePath: "file-1.txt", content: "Content of file-1" },
1927
+ { filePath: "file-2.txt", content: "Content of file-2" },
1866
1928
  ];
1867
1929
  const kvNamespace = {
1868
1930
  title: "__test-name-workers_sites_assets",
@@ -1884,13 +1946,13 @@ addEventListener('fetch', event => {});`
1884
1946
  // Check we only upload file-1
1885
1947
  mockUploadAssetsToKVRequest(
1886
1948
  kvNamespace.id,
1887
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1949
+ assets.filter((a) => a.filePath === "file-1.txt")
1888
1950
  );
1889
1951
  await runWrangler("publish --site-include file-1.txt");
1890
1952
 
1891
1953
  expect(std.out).toMatchInlineSnapshot(`
1892
- "Reading assets/file-1.txt...
1893
- Uploading as assets/file-1.2ca234f380.txt...
1954
+ "Reading file-1.txt...
1955
+ Uploading as file-1.2ca234f380.txt...
1894
1956
  ↗️ Done syncing assets
1895
1957
  Uploaded test-name (TIMINGS)
1896
1958
  Published test-name (TIMINGS)
@@ -1901,8 +1963,8 @@ addEventListener('fetch', event => {});`
1901
1963
 
1902
1964
  it("should use `site-exclude` arg over `site.exclude` config", async () => {
1903
1965
  const assets = [
1904
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1905
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1966
+ { filePath: "file-1.txt", content: "Content of file-1" },
1967
+ { filePath: "file-2.txt", content: "Content of file-2" },
1906
1968
  ];
1907
1969
  const kvNamespace = {
1908
1970
  title: "__test-name-workers_sites_assets",
@@ -1912,7 +1974,7 @@ addEventListener('fetch', event => {});`
1912
1974
  main: "./index.js",
1913
1975
  site: {
1914
1976
  bucket: "assets",
1915
- exclude: ["assets/file-1.txt"],
1977
+ exclude: ["file-1.txt"],
1916
1978
  },
1917
1979
  });
1918
1980
  writeWorkerSource();
@@ -1924,13 +1986,13 @@ addEventListener('fetch', event => {});`
1924
1986
  // Check we only upload file-1
1925
1987
  mockUploadAssetsToKVRequest(
1926
1988
  kvNamespace.id,
1927
- assets.filter((a) => a.filePath.endsWith("assets/file-1.txt"))
1989
+ assets.filter((a) => a.filePath.endsWith("file-1.txt"))
1928
1990
  );
1929
1991
  await runWrangler("publish --site-exclude file-2.txt");
1930
1992
 
1931
1993
  expect(std.out).toMatchInlineSnapshot(`
1932
- "Reading assets/file-1.txt...
1933
- Uploading as assets/file-1.2ca234f380.txt...
1994
+ "Reading file-1.txt...
1995
+ Uploading as file-1.2ca234f380.txt...
1934
1996
  ↗️ Done syncing assets
1935
1997
  Uploaded test-name (TIMINGS)
1936
1998
  Published test-name (TIMINGS)
@@ -1942,11 +2004,11 @@ addEventListener('fetch', event => {});`
1942
2004
  it("should walk directories except node_modules", async () => {
1943
2005
  const assets = [
1944
2006
  {
1945
- filePath: "assets/directory-1/file-1.txt",
2007
+ filePath: "directory-1/file-1.txt",
1946
2008
  content: "Content of file-1",
1947
2009
  },
1948
2010
  {
1949
- filePath: "assets/node_modules/file-2.txt",
2011
+ filePath: "node_modules/file-2.txt",
1950
2012
  content: "Content of file-2",
1951
2013
  },
1952
2014
  ];
@@ -1971,8 +2033,8 @@ addEventListener('fetch', event => {});`
1971
2033
  await runWrangler("publish");
1972
2034
 
1973
2035
  expect(std.out).toMatchInlineSnapshot(`
1974
- "Reading assets/directory-1/file-1.txt...
1975
- Uploading as assets/directory-1/file-1.2ca234f380.txt...
2036
+ "Reading directory-1/file-1.txt...
2037
+ Uploading as directory-1/file-1.2ca234f380.txt...
1976
2038
  ↗️ Done syncing assets
1977
2039
  Uploaded test-name (TIMINGS)
1978
2040
  Published test-name (TIMINGS)
@@ -1984,15 +2046,15 @@ addEventListener('fetch', event => {});`
1984
2046
  it("should skip hidden files and directories except `.well-known`", async () => {
1985
2047
  const assets = [
1986
2048
  {
1987
- filePath: "assets/.hidden-file.txt",
2049
+ filePath: ".hidden-file.txt",
1988
2050
  content: "Content of hidden-file",
1989
2051
  },
1990
2052
  {
1991
- filePath: "assets/.hidden/file-1.txt",
2053
+ filePath: ".hidden/file-1.txt",
1992
2054
  content: "Content of file-1",
1993
2055
  },
1994
2056
  {
1995
- filePath: "assets/.well-known/file-2.txt",
2057
+ filePath: ".well-known/file-2.txt",
1996
2058
  content: "Content of file-2",
1997
2059
  },
1998
2060
  ];
@@ -2017,8 +2079,8 @@ addEventListener('fetch', event => {});`
2017
2079
  await runWrangler("publish");
2018
2080
 
2019
2081
  expect(std.out).toMatchInlineSnapshot(`
2020
- "Reading assets/.well-known/file-2.txt...
2021
- Uploading as assets/.well-known/file-2.5938485188.txt...
2082
+ "Reading .well-known/file-2.txt...
2083
+ Uploading as .well-known/file-2.5938485188.txt...
2022
2084
  ↗️ Done syncing assets
2023
2085
  Uploaded test-name (TIMINGS)
2024
2086
  Published test-name (TIMINGS)
@@ -2030,12 +2092,12 @@ addEventListener('fetch', event => {});`
2030
2092
  it("should error if the asset is over 25Mb", async () => {
2031
2093
  const assets = [
2032
2094
  {
2033
- filePath: "assets/large-file.txt",
2095
+ filePath: "large-file.txt",
2034
2096
  // This file is greater than 25MiB when base64 encoded but small enough to be uploaded.
2035
2097
  content: "X".repeat(25 * 1024 * 1024 * 0.8 + 1),
2036
2098
  },
2037
2099
  {
2038
- filePath: "assets/too-large-file.txt",
2100
+ filePath: "too-large-file.txt",
2039
2101
  content: "X".repeat(25 * 1024 * 1024 + 1),
2040
2102
  },
2041
2103
  ];
@@ -2047,7 +2109,7 @@ addEventListener('fetch', event => {});`
2047
2109
  main: "./index.js",
2048
2110
  site: {
2049
2111
  bucket: "assets",
2050
- exclude: ["assets/file-1.txt"],
2112
+ exclude: ["file-1.txt"],
2051
2113
  },
2052
2114
  });
2053
2115
  writeWorkerSource();
@@ -2060,25 +2122,122 @@ addEventListener('fetch', event => {});`
2060
2122
  await expect(
2061
2123
  runWrangler("publish")
2062
2124
  ).rejects.toThrowErrorMatchingInlineSnapshot(
2063
- `"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"`
2125
+ `"File too-large-file.txt is too big, it should be under 25 MiB. See https://developers.cloudflare.com/workers/platform/limits#kv-limits"`
2064
2126
  );
2065
2127
 
2066
2128
  expect(std.out).toMatchInlineSnapshot(`
2067
- "Reading assets/large-file.txt...
2068
- Uploading as assets/large-file.0ea0637a45.txt...
2129
+ "Reading large-file.txt...
2130
+ Uploading as large-file.0ea0637a45.txt...
2131
+ Reading too-large-file.txt...
2069
2132
 
2070
2133
  If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
2071
2134
  `);
2072
2135
  expect(std.err).toMatchInlineSnapshot(`
2073
- "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
2136
+ "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
2074
2137
 
2075
2138
  "
2076
2139
  `);
2077
2140
  });
2078
2141
 
2142
+ it("should batch assets in groups <100 mb", async () => {
2143
+ // Let's have 20 files, from size 1 - 20 mb
2144
+ const assets = Array.from({ length: 20 }, (_, index) => ({
2145
+ filePath: `file-${`${index}`.padStart(2, "0")}.txt`,
2146
+ content: "X".repeat(1024 * 1024 * (index + 1)),
2147
+ }));
2148
+
2149
+ const kvNamespace = {
2150
+ title: "__test-name-workers_sites_assets",
2151
+ id: "__test-name-workers_sites_assets-id",
2152
+ };
2153
+ writeWranglerToml({
2154
+ main: "./index.js",
2155
+ site: {
2156
+ bucket: "assets",
2157
+ },
2158
+ });
2159
+ writeWorkerSource();
2160
+ writeAssets(assets);
2161
+ mockUploadWorkerRequest();
2162
+ mockSubDomainRequest();
2163
+ mockListKVNamespacesRequest(kvNamespace);
2164
+ mockKeyListRequest(kvNamespace.id, []);
2165
+ const requests = mockUploadAssetsToKVRequest(kvNamespace.id);
2166
+
2167
+ await runWrangler("publish");
2168
+
2169
+ // We expect this to be uploaded in 3 batches
2170
+ // The first batch has 11 files (88mb)
2171
+ expect(requests[0].uploads.length).toEqual(11);
2172
+ // The next batch has 5 files (93mb)
2173
+ expect(requests[1].uploads.length).toEqual(5);
2174
+ // And the last one has 4 files (98mb)
2175
+ expect(requests[2].uploads.length).toEqual(4);
2176
+
2177
+ let assetIndex = 0;
2178
+ for (const request of requests) {
2179
+ for (const upload of request.uploads) {
2180
+ checkAssetUpload(assets[assetIndex], upload);
2181
+ assetIndex++;
2182
+ }
2183
+ }
2184
+
2185
+ expect(std).toMatchInlineSnapshot(`
2186
+ Object {
2187
+ "debug": "",
2188
+ "err": "",
2189
+ "out": "Reading file-00.txt...
2190
+ Uploading as file-00.be5be5dd26.txt...
2191
+ Reading file-01.txt...
2192
+ Uploading as file-01.4842d35994.txt...
2193
+ Reading file-02.txt...
2194
+ Uploading as file-02.990572ec63.txt...
2195
+ Reading file-03.txt...
2196
+ Uploading as file-03.9d7dda9045.txt...
2197
+ Reading file-04.txt...
2198
+ Uploading as file-04.2b6fac6382.txt...
2199
+ Reading file-05.txt...
2200
+ Uploading as file-05.55762dc758.txt...
2201
+ Reading file-06.txt...
2202
+ Uploading as file-06.f408a6b020.txt...
2203
+ Reading file-07.txt...
2204
+ Uploading as file-07.64c051715b.txt...
2205
+ Reading file-08.txt...
2206
+ Uploading as file-08.d286789adb.txt...
2207
+ Reading file-09.txt...
2208
+ Uploading as file-09.6838c183a8.txt...
2209
+ Reading file-10.txt...
2210
+ Uploading as file-10.6e03221d2a.txt...
2211
+ Reading file-11.txt...
2212
+ Uploading as file-11.37d3fb2eff.txt...
2213
+ Reading file-12.txt...
2214
+ Uploading as file-12.b3556942f8.txt...
2215
+ Reading file-13.txt...
2216
+ Uploading as file-13.680caf51b1.txt...
2217
+ Reading file-14.txt...
2218
+ Uploading as file-14.51e88468f0.txt...
2219
+ Reading file-15.txt...
2220
+ Uploading as file-15.8e3fedb394.txt...
2221
+ Reading file-16.txt...
2222
+ Uploading as file-16.c81c5e426f.txt...
2223
+ Reading file-17.txt...
2224
+ Uploading as file-17.4b2ae3c47b.txt...
2225
+ Reading file-18.txt...
2226
+ Uploading as file-18.07f245e02b.txt...
2227
+ Reading file-19.txt...
2228
+ Uploading as file-19.f0d69f705d.txt...
2229
+ ↗️ Done syncing assets
2230
+ Uploaded test-name (TIMINGS)
2231
+ Published test-name (TIMINGS)
2232
+ test-name.test-sub-domain.workers.dev",
2233
+ "warn": "",
2234
+ }
2235
+ `);
2236
+ });
2237
+
2079
2238
  it("should error if the asset key is over 512 characters", async () => {
2080
2239
  const longFilePathAsset = {
2081
- filePath: "assets/" + "folder/".repeat(100) + "file.txt",
2240
+ filePath: "folder/".repeat(100) + "file.txt",
2082
2241
  content: "content of file",
2083
2242
  };
2084
2243
  const kvNamespace = {
@@ -2101,16 +2260,16 @@ addEventListener('fetch', event => {});`
2101
2260
  await expect(
2102
2261
  runWrangler("publish")
2103
2262
  ).rejects.toThrowErrorMatchingInlineSnapshot(
2104
- `"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\\","`
2263
+ `"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\\","`
2105
2264
  );
2106
2265
 
2107
2266
  expect(std.out).toMatchInlineSnapshot(`
2108
- "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...
2267
+ "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...
2109
2268
 
2110
2269
  If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
2111
2270
  `);
2112
2271
  expect(std.err).toMatchInlineSnapshot(`
2113
- "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\\",
2272
+ "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\\",
2114
2273
 
2115
2274
  "
2116
2275
  `);
@@ -2118,8 +2277,8 @@ addEventListener('fetch', event => {});`
2118
2277
 
2119
2278
  it("should delete uploaded assets that aren't included anymore", async () => {
2120
2279
  const assets = [
2121
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
2122
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
2280
+ { filePath: "file-1.txt", content: "Content of file-1" },
2281
+ { filePath: "file-2.txt", content: "Content of file-2" },
2123
2282
  ];
2124
2283
  const kvNamespace = {
2125
2284
  title: "__test-name-workers_sites_assets",
@@ -2138,32 +2297,86 @@ addEventListener('fetch', event => {});`
2138
2297
  mockListKVNamespacesRequest(kvNamespace);
2139
2298
  mockKeyListRequest(kvNamespace.id, [
2140
2299
  // Put file-1 in the KV namespace
2141
- { name: "assets/file-1.2ca234f380.txt" },
2300
+ { name: "file-1.2ca234f380.txt" },
2142
2301
  // As well as a couple from a previous upload
2143
- { name: "assets/file-3.somehash.txt" },
2144
- { name: "assets/file-4.anotherhash.txt" },
2302
+ { name: "file-3.somehash.txt" },
2303
+ { name: "file-4.anotherhash.txt" },
2145
2304
  ]);
2146
2305
 
2147
2306
  // we upload only file-1.txt
2148
- mockUploadAssetsToKVRequest(kvNamespace.id, [
2149
- ...assets.filter((a) => a.filePath !== "assets/file-1.txt"),
2150
- ]);
2307
+ mockUploadAssetsToKVRequest(
2308
+ kvNamespace.id,
2309
+ assets.filter((a) => a.filePath !== "file-1.txt")
2310
+ );
2151
2311
 
2152
2312
  // and mark file-3 and file-4 for deletion
2153
2313
  mockDeleteUnusedAssetsRequest(kvNamespace.id, [
2154
- "assets/file-3.somehash.txt",
2155
- "assets/file-4.anotherhash.txt",
2314
+ "file-3.somehash.txt",
2315
+ "file-4.anotherhash.txt",
2156
2316
  ]);
2157
2317
 
2158
2318
  await runWrangler("publish");
2159
2319
 
2160
2320
  expect(std.out).toMatchInlineSnapshot(`
2161
- "Reading assets/file-1.txt...
2321
+ "Reading file-1.txt...
2162
2322
  Skipping - already uploaded.
2163
- Reading assets/file-2.txt...
2164
- Uploading as assets/file-2.5938485188.txt...
2165
- Deleting assets/file-3.somehash.txt from the asset store...
2166
- Deleting assets/file-4.anotherhash.txt from the asset store...
2323
+ Reading file-2.txt...
2324
+ Uploading as file-2.5938485188.txt...
2325
+ Deleting file-3.somehash.txt from the asset store...
2326
+ Deleting file-4.anotherhash.txt from the asset store...
2327
+ ↗️ Done syncing assets
2328
+ Uploaded test-name (TIMINGS)
2329
+ Published test-name (TIMINGS)
2330
+ test-name.test-sub-domain.workers.dev"
2331
+ `);
2332
+ expect(std.err).toMatchInlineSnapshot(`""`);
2333
+ });
2334
+
2335
+ it("should generate an asset manifest with keys relative to site.bucket", async () => {
2336
+ const assets = [
2337
+ { filePath: "file-1.txt", content: "Content of file-1" },
2338
+ { filePath: "file-2.txt", content: "Content of file-2" },
2339
+ ];
2340
+ const kvNamespace = {
2341
+ title: "__test-name-workers_sites_assets",
2342
+ id: "__test-name-workers_sites_assets-id",
2343
+ };
2344
+
2345
+ writeWranglerToml({
2346
+ main: "./src/index.js",
2347
+ site: {
2348
+ bucket: "assets",
2349
+ },
2350
+ });
2351
+ writeWorkerSource({ basePath: "src", type: "esm" });
2352
+ writeAssets(assets);
2353
+ mockUploadWorkerRequest({
2354
+ expectedBindings: [
2355
+ {
2356
+ name: "__STATIC_CONTENT",
2357
+ namespace_id: "__test-name-workers_sites_assets-id",
2358
+ type: "kv_namespace",
2359
+ },
2360
+ ],
2361
+ expectedModules: {
2362
+ __STATIC_CONTENT_MANIFEST:
2363
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
2364
+ },
2365
+ });
2366
+ mockSubDomainRequest();
2367
+ mockListKVNamespacesRequest(kvNamespace);
2368
+ mockKeyListRequest(kvNamespace.id, []);
2369
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
2370
+
2371
+ process.chdir("./src");
2372
+ await runWrangler("publish");
2373
+ process.chdir("../");
2374
+
2375
+ expect(std.out).toMatchInlineSnapshot(`
2376
+ "Reading file-1.txt...
2377
+ Uploading as file-1.2ca234f380.txt...
2378
+ Reading file-2.txt...
2379
+ Uploading as file-2.5938485188.txt...
2167
2380
  ↗️ Done syncing assets
2168
2381
  Uploaded test-name (TIMINGS)
2169
2382
  Published test-name (TIMINGS)
@@ -5135,10 +5348,16 @@ addEventListener('fetch', event => {});`
5135
5348
  });
5136
5349
 
5137
5350
  /** Write mock assets to the file system so they can be uploaded. */
5138
- function writeAssets(assets: { filePath: string; content: string }[]) {
5351
+ function writeAssets(
5352
+ assets: { filePath: string; content: string }[],
5353
+ destination = "assets"
5354
+ ) {
5139
5355
  for (const asset of assets) {
5140
- fs.mkdirSync(path.dirname(asset.filePath), { recursive: true });
5141
- fs.writeFileSync(asset.filePath, asset.content);
5356
+ const filePathDestination = path.join(destination, asset.filePath);
5357
+ fs.mkdirSync(path.dirname(filePathDestination), {
5358
+ recursive: true,
5359
+ });
5360
+ fs.writeFileSync(filePathDestination, asset.content);
5142
5361
  }
5143
5362
  }
5144
5363
 
@@ -5147,6 +5366,7 @@ function mockUploadWorkerRequest(
5147
5366
  options: {
5148
5367
  available_on_subdomain?: boolean;
5149
5368
  expectedEntry?: string;
5369
+ expectedMainModule?: string;
5150
5370
  expectedType?: "esm" | "sw";
5151
5371
  expectedBindings?: unknown;
5152
5372
  expectedModules?: Record<string, string>;
@@ -5160,6 +5380,7 @@ function mockUploadWorkerRequest(
5160
5380
  const {
5161
5381
  available_on_subdomain = true,
5162
5382
  expectedEntry,
5383
+ expectedMainModule = "index.js",
5163
5384
  expectedType = "esm",
5164
5385
  expectedBindings,
5165
5386
  expectedModules = {},
@@ -5183,6 +5404,7 @@ function mockUploadWorkerRequest(
5183
5404
  expect(envName).toEqual(env);
5184
5405
  }
5185
5406
  expect(queryParams.get("include_subdomain_availability")).toEqual("true");
5407
+ expect(queryParams.get("excludeScript")).toEqual("true");
5186
5408
  const formBody = body as FormData;
5187
5409
  if (expectedEntry !== undefined) {
5188
5410
  expect(await (formBody.get("index.js") as File).text()).toMatch(
@@ -5193,7 +5415,7 @@ function mockUploadWorkerRequest(
5193
5415
  formBody.get("metadata") as string
5194
5416
  ) as WorkerMetadata;
5195
5417
  if (expectedType === "esm") {
5196
- expect(metadata.main_module).toEqual("index.js");
5418
+ expect(metadata.main_module).toEqual(expectedMainModule);
5197
5419
  } else {
5198
5420
  expect(metadata.body_part).toEqual("index.js");
5199
5421
  }
@@ -5454,16 +5676,28 @@ function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
5454
5676
  );
5455
5677
  }
5456
5678
 
5679
+ interface ExpectedAsset {
5680
+ filePath: string;
5681
+ content: string;
5682
+ expiration?: number;
5683
+ expiration_ttl?: number;
5684
+ }
5685
+ interface StaticAssetUpload {
5686
+ key: string;
5687
+ base64: boolean;
5688
+ value: string;
5689
+ expiration: number | undefined;
5690
+ expiration_ttl: number | undefined;
5691
+ }
5692
+
5457
5693
  /** Create a mock handler for the request that tries to do a bulk upload of assets to a KV namespace. */
5458
5694
  function mockUploadAssetsToKVRequest(
5459
5695
  expectedNamespaceId: string,
5460
- assets: {
5461
- filePath: string;
5462
- content: string;
5463
- expiration?: number;
5464
- expiration_ttl?: number;
5465
- }[]
5696
+ assets?: ExpectedAsset[]
5466
5697
  ) {
5698
+ const requests: {
5699
+ uploads: StaticAssetUpload[];
5700
+ }[] = [];
5467
5701
  setMockResponse(
5468
5702
  "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
5469
5703
  "PUT",
@@ -5471,32 +5705,31 @@ function mockUploadAssetsToKVRequest(
5471
5705
  expect(accountId).toEqual("some-account-id");
5472
5706
  expect(namespaceId).toEqual(expectedNamespaceId);
5473
5707
  const uploads = JSON.parse(body as string);
5474
- expect(assets.length).toEqual(uploads.length);
5475
- for (let i = 0; i < uploads.length; i++) {
5476
- const asset = assets[i];
5477
- const upload = uploads[i];
5478
- // The asset key consists of:
5479
- // - the basename of the filepath
5480
- // - some hash value
5481
- // - the extension
5482
- const keyMatcher = new RegExp(
5483
- "^" +
5484
- asset.filePath
5485
- .replace(/(\.[^.]+)$/, ".[a-z0-9]+$1")
5486
- .replace(/\./g, "\\.")
5487
- );
5488
- expect(upload.key).toMatch(keyMatcher);
5489
- // The asset value is base64 encoded.
5490
- expect(upload.base64).toBe(true);
5491
- expect(Buffer.from(upload.value, "base64").toString()).toEqual(
5492
- asset.content
5493
- );
5494
- expect(upload.expiration).toEqual(asset.expiration);
5495
- expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
5708
+ if (assets) {
5709
+ expect(assets.length).toEqual(uploads.length);
5710
+ for (let i = 0; i < uploads.length; i++) {
5711
+ checkAssetUpload(assets[i], uploads[i]);
5712
+ }
5713
+ } else {
5714
+ requests.push({ uploads });
5496
5715
  }
5497
- return null;
5498
5716
  }
5499
5717
  );
5718
+ return requests;
5719
+ }
5720
+
5721
+ function checkAssetUpload(asset: ExpectedAsset, upload: StaticAssetUpload) {
5722
+ // The asset key consists of: `<basename>.<hash>.<extension>`
5723
+ const keyMatcher = new RegExp(
5724
+ "^" +
5725
+ asset.filePath.replace(/(\.[^.]+)$/, ".[a-z0-9]+$1").replace(/\./g, "\\.")
5726
+ );
5727
+ expect(upload.key).toMatch(keyMatcher);
5728
+ // The asset value is base64 encoded.
5729
+ expect(upload.base64).toBe(true);
5730
+ expect(Buffer.from(upload.value, "base64").toString()).toEqual(asset.content);
5731
+ expect(upload.expiration).toEqual(asset.expiration);
5732
+ expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
5500
5733
  }
5501
5734
 
5502
5735
  /** Create a mock handler for thr request that does a bulk delete of unused assets */