wrangler 2.0.3 → 2.0.7

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.
@@ -12,6 +12,7 @@ import {
12
12
  unsetMockFetchKVGetValues,
13
13
  } from "./helpers/mock-cfetch";
14
14
  import { mockConsoleMethods, normalizeSlashes } from "./helpers/mock-console";
15
+ import { mockConfirm } from "./helpers/mock-dialogs";
15
16
  import { useMockIsTTY } from "./helpers/mock-istty";
16
17
  import { mockKeyListRequest } from "./helpers/mock-kv";
17
18
  import { mockOAuthFlow } from "./helpers/mock-oauth-flow";
@@ -470,7 +471,10 @@ describe("publish", () => {
470
471
  mockSubDomainRequest();
471
472
  await runWrangler("publish ./some-path/worker/index.js");
472
473
  expect(std.out).toMatchInlineSnapshot(`
473
- "Uploaded test-name (TIMINGS)
474
+ "Your worker has access to the following bindings:
475
+ - Vars:
476
+ - xyz: \\"123\\"
477
+ Uploaded test-name (TIMINGS)
474
478
  Published test-name (TIMINGS)
475
479
  test-name.test-sub-domain.workers.dev"
476
480
  `);
@@ -645,6 +649,136 @@ describe("publish", () => {
645
649
  await runWrangler("publish ./index --env dev --legacy-env false");
646
650
  });
647
651
 
652
+ describe("custom domains", () => {
653
+ it("should publish routes marked with 'custom_domain' as seperate custom domains", async () => {
654
+ writeWranglerToml({
655
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
656
+ });
657
+ writeWorkerSource();
658
+ mockUpdateWorkerRequest({ enabled: false });
659
+ mockUploadWorkerRequest({ expectedType: "esm" });
660
+ mockPublishCustomDomainsRequest({
661
+ publishFlags: {
662
+ override_scope: true,
663
+ override_existing_origin: false,
664
+ override_existing_dns_record: false,
665
+ },
666
+ domains: [{ hostname: "api.example.com" }],
667
+ });
668
+ await runWrangler("publish ./index");
669
+ expect(std.out).toContain("api.example.com (custom domain)");
670
+ });
671
+
672
+ it("should allow retrying if publish fails with a conflicting custom domain error", async () => {
673
+ writeWranglerToml({
674
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
675
+ });
676
+ writeWorkerSource();
677
+ mockUpdateWorkerRequest({ enabled: false });
678
+ mockUploadWorkerRequest({ expectedType: "esm" });
679
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
680
+ originConflicts: true,
681
+ domains: [{ hostname: "api.example.com" }],
682
+ });
683
+ mockConfirm({
684
+ text: `Custom Domains already exist for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
685
+ result: true,
686
+ });
687
+ await runWrangler("publish ./index");
688
+ expect(std.out).toContain("api.example.com (custom domain)");
689
+ });
690
+
691
+ it("should allow retrying if publish fails with a conflicting DNS record error", async () => {
692
+ writeWranglerToml({
693
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
694
+ });
695
+ writeWorkerSource();
696
+ mockUpdateWorkerRequest({ enabled: false });
697
+ mockUploadWorkerRequest({ expectedType: "esm" });
698
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
699
+ dnsRecordConflicts: true,
700
+ domains: [{ hostname: "api.example.com" }],
701
+ });
702
+ mockConfirm({
703
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
704
+ result: true,
705
+ });
706
+ await runWrangler("publish ./index");
707
+ expect(std.out).toContain("api.example.com (custom domain)");
708
+ });
709
+
710
+ it("should allow retrying for conflicting custom domains and then again for conflicting dns", async () => {
711
+ writeWranglerToml({
712
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
713
+ });
714
+ writeWorkerSource();
715
+ mockUpdateWorkerRequest({ enabled: false });
716
+ mockUploadWorkerRequest({ expectedType: "esm" });
717
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
718
+ originConflicts: true,
719
+ dnsRecordConflicts: true,
720
+ domains: [{ hostname: "api.example.com" }],
721
+ });
722
+ mockConfirm(
723
+ {
724
+ text: `Custom Domains already exist for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
725
+ result: true,
726
+ },
727
+ {
728
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
729
+ result: true,
730
+ }
731
+ );
732
+ await runWrangler("publish ./index");
733
+ expect(std.out).toContain("api.example.com (custom domain)");
734
+ });
735
+
736
+ it("should throw if an invalid custom domain is requested", async () => {
737
+ writeWranglerToml({
738
+ routes: [{ pattern: "*.example.com", custom_domain: true }],
739
+ });
740
+ writeWorkerSource();
741
+ await expect(
742
+ runWrangler("publish ./index")
743
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
744
+ `"Cannot use \\"*.example.com\\" as a Custom Domain; wildcard operators (*) are not allowed"`
745
+ );
746
+
747
+ writeWranglerToml({
748
+ routes: [
749
+ { pattern: "api.example.com/at/a/path", custom_domain: true },
750
+ ],
751
+ });
752
+ writeWorkerSource();
753
+ await expect(
754
+ runWrangler("publish ./index")
755
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
756
+ `"Cannot use \\"api.example.com/at/a/path\\" as a Custom Domain; paths are not allowed"`
757
+ );
758
+ });
759
+
760
+ it("should not retry publish on error if user does not confirm", async () => {
761
+ writeWranglerToml({
762
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
763
+ });
764
+ writeWorkerSource();
765
+ mockUpdateWorkerRequest({ enabled: false });
766
+ mockUploadWorkerRequest({ expectedType: "esm" });
767
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
768
+ dnsRecordConflicts: true,
769
+ domains: [{ hostname: "api.example.com" }],
770
+ });
771
+ mockConfirm({
772
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
773
+ result: false,
774
+ });
775
+ await runWrangler("publish ./index");
776
+ expect(std.out).toContain(
777
+ 'Publishing to Custom Domain "api.example.com" was skipped, fix conflict and try again'
778
+ );
779
+ });
780
+ });
781
+
648
782
  it.todo("should error if it's a workers.dev route");
649
783
  });
650
784
 
@@ -2698,13 +2832,22 @@ addEventListener('fetch', event => {});`
2698
2832
  mockUploadWorkerRequest();
2699
2833
  await runWrangler("publish index.js");
2700
2834
  expect(std.out).toMatchInlineSnapshot(`
2701
- "Uploaded test-name (TIMINGS)
2835
+ "Your worker has access to the following bindings:
2836
+ - Durable Objects:
2837
+ - SOMENAME: SomeClass
2838
+ Uploaded test-name (TIMINGS)
2702
2839
  Published test-name (TIMINGS)
2703
2840
  test-name.test-sub-domain.workers.dev"
2704
2841
  `);
2705
2842
  expect(std.err).toMatchInlineSnapshot(`""`);
2706
2843
  expect(std.warn).toMatchInlineSnapshot(`
2707
- "▲ [WARNING] In wrangler.toml, you have configured [durable_objects] exported by this Worker (SomeClass), but no [migrations] for them. This may not work as expected until you add a [migrations] section to your wrangler.toml. Refer to https://developers.cloudflare.com/workers/learning/using-durable-objects/#durable-object-migrations-in-wranglertoml for more details.
2844
+ "▲ [WARNING] Processing wrangler.toml configuration:
2845
+
2846
+ - In wrangler.toml, you have configured [durable_objects] exported by this Worker (SomeClass),
2847
+ but no [migrations] for them. This may not work as expected until you add a [migrations] section
2848
+ to your wrangler.toml. Refer to
2849
+ https://developers.cloudflare.com/workers/learning/using-durable-objects/#durable-object-migrations-in-wranglertoml
2850
+ for more details.
2708
2851
 
2709
2852
  "
2710
2853
  `);
@@ -2730,7 +2873,10 @@ addEventListener('fetch', event => {});`
2730
2873
  mockUploadWorkerRequest();
2731
2874
  await runWrangler("publish index.js");
2732
2875
  expect(std.out).toMatchInlineSnapshot(`
2733
- "Uploaded test-name (TIMINGS)
2876
+ "Your worker has access to the following bindings:
2877
+ - Durable Objects:
2878
+ - SOMENAME: SomeClass (defined in some-script)
2879
+ Uploaded test-name (TIMINGS)
2734
2880
  Published test-name (TIMINGS)
2735
2881
  test-name.test-sub-domain.workers.dev"
2736
2882
  `);
@@ -2769,7 +2915,11 @@ addEventListener('fetch', event => {});`
2769
2915
 
2770
2916
  await runWrangler("publish index.js");
2771
2917
  expect(std.out).toMatchInlineSnapshot(`
2772
- "Uploaded test-name (TIMINGS)
2918
+ "Your worker has access to the following bindings:
2919
+ - Durable Objects:
2920
+ - SOMENAME: SomeClass
2921
+ - SOMEOTHERNAME: SomeOtherClass
2922
+ Uploaded test-name (TIMINGS)
2773
2923
  Published test-name (TIMINGS)
2774
2924
  test-name.test-sub-domain.workers.dev"
2775
2925
  `);
@@ -2815,7 +2965,11 @@ addEventListener('fetch', event => {});`
2815
2965
  Object {
2816
2966
  "debug": "",
2817
2967
  "err": "",
2818
- "out": "Uploaded test-name (TIMINGS)
2968
+ "out": "Your worker has access to the following bindings:
2969
+ - Durable Objects:
2970
+ - SOMENAME: SomeClass
2971
+ - SOMEOTHERNAME: SomeOtherClass
2972
+ Uploaded test-name (TIMINGS)
2819
2973
  Published test-name (TIMINGS)
2820
2974
  test-name.test-sub-domain.workers.dev",
2821
2975
  "warn": "",
@@ -2854,7 +3008,11 @@ addEventListener('fetch', event => {});`
2854
3008
  Object {
2855
3009
  "debug": "",
2856
3010
  "err": "",
2857
- "out": "Uploaded test-name (TIMINGS)
3011
+ "out": "Your worker has access to the following bindings:
3012
+ - Durable Objects:
3013
+ - SOMENAME: SomeClass
3014
+ - SOMEOTHERNAME: SomeOtherClass
3015
+ Uploaded test-name (TIMINGS)
2858
3016
  Published test-name (TIMINGS)
2859
3017
  test-name.test-sub-domain.workers.dev",
2860
3018
  "warn": "",
@@ -2895,7 +3053,11 @@ addEventListener('fetch', event => {});`
2895
3053
 
2896
3054
  await runWrangler("publish index.js --legacy-env false");
2897
3055
  expect(std.out).toMatchInlineSnapshot(`
2898
- "Uploaded test-name (TIMINGS)
3056
+ "Your worker has access to the following bindings:
3057
+ - Durable Objects:
3058
+ - SOMENAME: SomeClass
3059
+ - SOMEOTHERNAME: SomeOtherClass
3060
+ Uploaded test-name (TIMINGS)
2899
3061
  Published test-name (TIMINGS)
2900
3062
  test-name.test-sub-domain.workers.dev"
2901
3063
  `);
@@ -2953,7 +3115,11 @@ addEventListener('fetch', event => {});`
2953
3115
 
2954
3116
  await runWrangler("publish index.js --legacy-env false --env xyz");
2955
3117
  expect(std.out).toMatchInlineSnapshot(`
2956
- "Uploaded test-name (xyz) (TIMINGS)
3118
+ "Your worker has access to the following bindings:
3119
+ - Durable Objects:
3120
+ - SOMENAME: SomeClass
3121
+ - SOMEOTHERNAME: SomeOtherClass
3122
+ Uploaded test-name (xyz) (TIMINGS)
2957
3123
  Published test-name (xyz) (TIMINGS)
2958
3124
  xyz.test-name.test-sub-domain.workers.dev"
2959
3125
  `);
@@ -3007,7 +3173,11 @@ addEventListener('fetch', event => {});`
3007
3173
  Object {
3008
3174
  "debug": "",
3009
3175
  "err": "",
3010
- "out": "Uploaded test-name (TIMINGS)
3176
+ "out": "Your worker has access to the following bindings:
3177
+ - Durable Objects:
3178
+ - SOMENAME: SomeClass
3179
+ - SOMEOTHERNAME: SomeOtherClass
3180
+ Uploaded test-name (TIMINGS)
3011
3181
  Published test-name (TIMINGS)
3012
3182
  test-name.test-sub-domain.workers.dev",
3013
3183
  "warn": "▲ [WARNING] Processing wrangler.toml configuration:
@@ -3071,7 +3241,11 @@ addEventListener('fetch', event => {});`
3071
3241
  Object {
3072
3242
  "debug": "",
3073
3243
  "err": "",
3074
- "out": "Uploaded test-name (xyz) (TIMINGS)
3244
+ "out": "Your worker has access to the following bindings:
3245
+ - Durable Objects:
3246
+ - SOMENAME: SomeClass
3247
+ - SOMEOTHERNAME: SomeOtherClass
3248
+ Uploaded test-name (xyz) (TIMINGS)
3075
3249
  Published test-name (xyz) (TIMINGS)
3076
3250
  xyz.test-name.test-sub-domain.workers.dev",
3077
3251
  "warn": "▲ [WARNING] Processing wrangler.toml configuration:
@@ -3106,6 +3280,7 @@ addEventListener('fetch', event => {});`
3106
3280
  name: "DURABLE_OBJECT_TWO",
3107
3281
  class_name: "AnotherDurableObject",
3108
3282
  script_name: "another-durable-object-worker",
3283
+ environment: "staging",
3109
3284
  },
3110
3285
  ],
3111
3286
  },
@@ -3164,6 +3339,12 @@ addEventListener('fetch', event => {});`
3164
3339
  mockUploadWorkerRequest({
3165
3340
  expectedType: "sw",
3166
3341
  expectedBindings: [
3342
+ { json: 123, name: "ENV_VAR_ONE", type: "json" },
3343
+ {
3344
+ name: "ENV_VAR_TWO",
3345
+ text: "Hello, I'm an environment variable",
3346
+ type: "plain_text",
3347
+ },
3167
3348
  {
3168
3349
  name: "KV_NAMESPACE_ONE",
3169
3350
  namespace_id: "kv-ns-one-id",
@@ -3182,6 +3363,7 @@ addEventListener('fetch', event => {});`
3182
3363
  },
3183
3364
  {
3184
3365
  class_name: "AnotherDurableObject",
3366
+ environment: "staging",
3185
3367
  name: "DURABLE_OBJECT_TWO",
3186
3368
  script_name: "another-durable-object-worker",
3187
3369
  type: "durable_object_namespace",
@@ -3196,12 +3378,6 @@ addEventListener('fetch', event => {});`
3196
3378
  name: "R2_BUCKET_TWO",
3197
3379
  type: "r2_bucket",
3198
3380
  },
3199
- { json: 123, name: "ENV_VAR_ONE", type: "json" },
3200
- {
3201
- name: "ENV_VAR_TWO",
3202
- text: "Hello, I'm an environment variable",
3203
- type: "plain_text",
3204
- },
3205
3381
  {
3206
3382
  name: "WASM_MODULE_ONE",
3207
3383
  part: "WASM_MODULE_ONE",
@@ -3233,7 +3409,32 @@ addEventListener('fetch', event => {});`
3233
3409
 
3234
3410
  await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
3235
3411
  expect(std.out).toMatchInlineSnapshot(`
3236
- "Uploaded test-name (TIMINGS)
3412
+ "Your worker has access to the following bindings:
3413
+ - Data Blobs:
3414
+ - DATA_BLOB_ONE: some-data-blob.bin
3415
+ - DATA_BLOB_TWO: more-data-blob.bin
3416
+ - Durable Objects:
3417
+ - DURABLE_OBJECT_ONE: SomeDurableObject (defined in some-durable-object-worker)
3418
+ - DURABLE_OBJECT_TWO: AnotherDurableObject (defined in another-durable-object-worker) - staging
3419
+ - KV Namespaces:
3420
+ - KV_NAMESPACE_ONE: kv-ns-one-id
3421
+ - KV_NAMESPACE_TWO: kv-ns-two-id
3422
+ - R2 Buckets:
3423
+ - R2_BUCKET_ONE: r2-bucket-one-name
3424
+ - R2_BUCKET_TWO: r2-bucket-two-name
3425
+ - Text Blobs:
3426
+ - TEXT_BLOB_ONE: my-entire-app-depends-on-this.cfg
3427
+ - TEXT_BLOB_TWO: the-entirety-of-human-knowledge.txt
3428
+ - Unsafe:
3429
+ - some unsafe thing: UNSAFE_BINDING_ONE
3430
+ - another unsafe thing: UNSAFE_BINDING_TWO
3431
+ - Vars:
3432
+ - ENV_VAR_ONE: \\"123\\"
3433
+ - ENV_VAR_TWO: \\"Hello, I'm an environment variable\\"
3434
+ - Wasm Modules:
3435
+ - WASM_MODULE_ONE: some_wasm.wasm
3436
+ - WASM_MODULE_TWO: more_wasm.wasm
3437
+ Uploaded test-name (TIMINGS)
3237
3438
  Published test-name (TIMINGS)
3238
3439
  test-name.test-sub-domain.workers.dev"
3239
3440
  `);
@@ -3609,10 +3810,13 @@ addEventListener('fetch', event => {});`
3609
3810
  mockSubDomainRequest();
3610
3811
  await runWrangler("publish index.js");
3611
3812
  expect(std.out).toMatchInlineSnapshot(`
3612
- "Uploaded test-name (TIMINGS)
3613
- Published test-name (TIMINGS)
3614
- test-name.test-sub-domain.workers.dev"
3615
- `);
3813
+ "Your worker has access to the following bindings:
3814
+ - Wasm Modules:
3815
+ - TESTWASMNAME: path/to/test.wasm
3816
+ Uploaded test-name (TIMINGS)
3817
+ Published test-name (TIMINGS)
3818
+ test-name.test-sub-domain.workers.dev"
3819
+ `);
3616
3820
  expect(std.err).toMatchInlineSnapshot(`""`);
3617
3821
  expect(std.warn).toMatchInlineSnapshot(`""`);
3618
3822
  });
@@ -3675,10 +3879,13 @@ addEventListener('fetch', event => {});`
3675
3879
  mockSubDomainRequest();
3676
3880
  await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3677
3881
  expect(std.out).toMatchInlineSnapshot(`
3678
- "Uploaded test-name (TIMINGS)
3679
- Published test-name (TIMINGS)
3680
- test-name.test-sub-domain.workers.dev"
3681
- `);
3882
+ "Your worker has access to the following bindings:
3883
+ - Wasm Modules:
3884
+ - TESTWASMNAME: path/to/and/the/path/to/test.wasm
3885
+ Uploaded test-name (TIMINGS)
3886
+ Published test-name (TIMINGS)
3887
+ test-name.test-sub-domain.workers.dev"
3888
+ `);
3682
3889
  expect(std.err).toMatchInlineSnapshot(`""`);
3683
3890
  expect(std.warn).toMatchInlineSnapshot(`""`);
3684
3891
  });
@@ -3740,10 +3947,13 @@ addEventListener('fetch', event => {});`
3740
3947
  mockSubDomainRequest();
3741
3948
  await runWrangler("publish index.js");
3742
3949
  expect(std.out).toMatchInlineSnapshot(`
3743
- "Uploaded test-name (TIMINGS)
3744
- Published test-name (TIMINGS)
3745
- test-name.test-sub-domain.workers.dev"
3746
- `);
3950
+ "Your worker has access to the following bindings:
3951
+ - Text Blobs:
3952
+ - TESTTEXTBLOBNAME: path/to/text.file
3953
+ Uploaded test-name (TIMINGS)
3954
+ Published test-name (TIMINGS)
3955
+ test-name.test-sub-domain.workers.dev"
3956
+ `);
3747
3957
  expect(std.err).toMatchInlineSnapshot(`""`);
3748
3958
  expect(std.warn).toMatchInlineSnapshot(`""`);
3749
3959
  });
@@ -3810,10 +4020,13 @@ addEventListener('fetch', event => {});`
3810
4020
  mockSubDomainRequest();
3811
4021
  await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3812
4022
  expect(std.out).toMatchInlineSnapshot(`
3813
- "Uploaded test-name (TIMINGS)
3814
- Published test-name (TIMINGS)
3815
- test-name.test-sub-domain.workers.dev"
3816
- `);
4023
+ "Your worker has access to the following bindings:
4024
+ - Text Blobs:
4025
+ - TESTTEXTBLOBNAME: path/to/and/the/path/to/text.file
4026
+ Uploaded test-name (TIMINGS)
4027
+ Published test-name (TIMINGS)
4028
+ test-name.test-sub-domain.workers.dev"
4029
+ `);
3817
4030
  expect(std.err).toMatchInlineSnapshot(`""`);
3818
4031
  expect(std.warn).toMatchInlineSnapshot(`""`);
3819
4032
  });
@@ -3843,10 +4056,13 @@ addEventListener('fetch', event => {});`
3843
4056
  mockSubDomainRequest();
3844
4057
  await runWrangler("publish index.js");
3845
4058
  expect(std.out).toMatchInlineSnapshot(`
3846
- "Uploaded test-name (TIMINGS)
3847
- Published test-name (TIMINGS)
3848
- test-name.test-sub-domain.workers.dev"
3849
- `);
4059
+ "Your worker has access to the following bindings:
4060
+ - Data Blobs:
4061
+ - TESTDATABLOBNAME: path/to/data.bin
4062
+ Uploaded test-name (TIMINGS)
4063
+ Published test-name (TIMINGS)
4064
+ test-name.test-sub-domain.workers.dev"
4065
+ `);
3850
4066
  expect(std.err).toMatchInlineSnapshot(`""`);
3851
4067
  expect(std.warn).toMatchInlineSnapshot(`""`);
3852
4068
  });
@@ -3913,10 +4129,13 @@ addEventListener('fetch', event => {});`
3913
4129
  mockSubDomainRequest();
3914
4130
  await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3915
4131
  expect(std.out).toMatchInlineSnapshot(`
3916
- "Uploaded test-name (TIMINGS)
3917
- Published test-name (TIMINGS)
3918
- test-name.test-sub-domain.workers.dev"
3919
- `);
4132
+ "Your worker has access to the following bindings:
4133
+ - Data Blobs:
4134
+ - TESTDATABLOBNAME: path/to/and/the/path/to/data.bin
4135
+ Uploaded test-name (TIMINGS)
4136
+ Published test-name (TIMINGS)
4137
+ test-name.test-sub-domain.workers.dev"
4138
+ `);
3920
4139
  expect(std.err).toMatchInlineSnapshot(`""`);
3921
4140
  expect(std.warn).toMatchInlineSnapshot(`""`);
3922
4141
  });
@@ -3947,10 +4166,15 @@ addEventListener('fetch', event => {});`
3947
4166
 
3948
4167
  await runWrangler("publish index.js");
3949
4168
  expect(std.out).toMatchInlineSnapshot(`
3950
- "Uploaded test-name (TIMINGS)
3951
- Published test-name (TIMINGS)
3952
- test-name.test-sub-domain.workers.dev"
3953
- `);
4169
+ "Your worker has access to the following bindings:
4170
+ - Vars:
4171
+ - text: \\"plain ol' string\\"
4172
+ - count: \\"1\\"
4173
+ - complex: \\"[object Object]\\"
4174
+ Uploaded test-name (TIMINGS)
4175
+ Published test-name (TIMINGS)
4176
+ test-name.test-sub-domain.workers.dev"
4177
+ `);
3954
4178
  expect(std.err).toMatchInlineSnapshot(`""`);
3955
4179
  expect(std.warn).toMatchInlineSnapshot(`""`);
3956
4180
  });
@@ -3971,10 +4195,13 @@ addEventListener('fetch', event => {});`
3971
4195
 
3972
4196
  await runWrangler("publish index.js");
3973
4197
  expect(std.out).toMatchInlineSnapshot(`
3974
- "Uploaded test-name (TIMINGS)
3975
- Published test-name (TIMINGS)
3976
- test-name.test-sub-domain.workers.dev"
3977
- `);
4198
+ "Your worker has access to the following bindings:
4199
+ - R2 Buckets:
4200
+ - FOO: foo-bucket
4201
+ Uploaded test-name (TIMINGS)
4202
+ Published test-name (TIMINGS)
4203
+ test-name.test-sub-domain.workers.dev"
4204
+ `);
3978
4205
  expect(std.err).toMatchInlineSnapshot(`""`);
3979
4206
  expect(std.warn).toMatchInlineSnapshot(`""`);
3980
4207
  });
@@ -4013,10 +4240,13 @@ addEventListener('fetch', event => {});`
4013
4240
 
4014
4241
  await runWrangler("publish index.js");
4015
4242
  expect(std.out).toMatchInlineSnapshot(`
4016
- "Uploaded test-name (TIMINGS)
4017
- Published test-name (TIMINGS)
4018
- test-name.test-sub-domain.workers.dev"
4019
- `);
4243
+ "Your worker has access to the following bindings:
4244
+ - Durable Objects:
4245
+ - EXAMPLE_DO_BINDING: ExampleDurableObject
4246
+ Uploaded test-name (TIMINGS)
4247
+ Published test-name (TIMINGS)
4248
+ test-name.test-sub-domain.workers.dev"
4249
+ `);
4020
4250
  expect(std.err).toMatchInlineSnapshot(`""`);
4021
4251
  expect(std.warn).toMatchInlineSnapshot(`""`);
4022
4252
  });
@@ -4049,10 +4279,13 @@ addEventListener('fetch', event => {});`
4049
4279
 
4050
4280
  await runWrangler("publish index.js");
4051
4281
  expect(std.out).toMatchInlineSnapshot(`
4052
- "Uploaded test-name (TIMINGS)
4053
- Published test-name (TIMINGS)
4054
- test-name.test-sub-domain.workers.dev"
4055
- `);
4282
+ "Your worker has access to the following bindings:
4283
+ - Durable Objects:
4284
+ - EXAMPLE_DO_BINDING: ExampleDurableObject (defined in example-do-binding-worker)
4285
+ Uploaded test-name (TIMINGS)
4286
+ Published test-name (TIMINGS)
4287
+ test-name.test-sub-domain.workers.dev"
4288
+ `);
4056
4289
  expect(std.err).toMatchInlineSnapshot(`""`);
4057
4290
  expect(std.warn).toMatchInlineSnapshot(`""`);
4058
4291
  });
@@ -4090,10 +4323,13 @@ addEventListener('fetch', event => {});`
4090
4323
 
4091
4324
  await runWrangler("publish index.js");
4092
4325
  expect(std.out).toMatchInlineSnapshot(`
4093
- "Uploaded test-name (TIMINGS)
4094
- Published test-name (TIMINGS)
4095
- test-name.test-sub-domain.workers.dev"
4096
- `);
4326
+ "Your worker has access to the following bindings:
4327
+ - Durable Objects:
4328
+ - EXAMPLE_DO_BINDING: ExampleDurableObject
4329
+ Uploaded test-name (TIMINGS)
4330
+ Published test-name (TIMINGS)
4331
+ test-name.test-sub-domain.workers.dev"
4332
+ `);
4097
4333
  expect(std.err).toMatchInlineSnapshot(`""`);
4098
4334
  expect(std.warn).toMatchInlineSnapshot(`""`);
4099
4335
  });
@@ -4123,6 +4359,50 @@ addEventListener('fetch', event => {});`
4123
4359
  });
4124
4360
  });
4125
4361
 
4362
+ describe("[services]", () => {
4363
+ it("should support service bindings", async () => {
4364
+ writeWranglerToml({
4365
+ services: [
4366
+ {
4367
+ binding: "FOO",
4368
+ service: "foo-service",
4369
+ environment: "production",
4370
+ },
4371
+ ],
4372
+ });
4373
+ writeWorkerSource();
4374
+ mockSubDomainRequest();
4375
+ mockUploadWorkerRequest({
4376
+ expectedBindings: [
4377
+ {
4378
+ type: "service",
4379
+ name: "FOO",
4380
+ service: "foo-service",
4381
+ environment: "production",
4382
+ },
4383
+ ],
4384
+ });
4385
+
4386
+ await runWrangler("publish index.js");
4387
+ expect(std.out).toMatchInlineSnapshot(`
4388
+ "Your worker has access to the following bindings:
4389
+ - Services:
4390
+ - FOO: foo-service - production
4391
+ Uploaded test-name (TIMINGS)
4392
+ Published test-name (TIMINGS)
4393
+ test-name.test-sub-domain.workers.dev"
4394
+ `);
4395
+ expect(std.err).toMatchInlineSnapshot(`""`);
4396
+ expect(std.warn).toMatchInlineSnapshot(`
4397
+ "▲ [WARNING] Processing wrangler.toml configuration:
4398
+
4399
+ - \\"services\\" fields are experimental and may change or break at any time.
4400
+
4401
+ "
4402
+ `);
4403
+ });
4404
+ });
4405
+
4126
4406
  describe("[unsafe]", () => {
4127
4407
  it("should warn if using unsafe bindings", async () => {
4128
4408
  writeWranglerToml({
@@ -4150,10 +4430,13 @@ addEventListener('fetch', event => {});`
4150
4430
 
4151
4431
  await runWrangler("publish index.js");
4152
4432
  expect(std.out).toMatchInlineSnapshot(`
4153
- "Uploaded test-name (TIMINGS)
4154
- Published test-name (TIMINGS)
4155
- test-name.test-sub-domain.workers.dev"
4156
- `);
4433
+ "Your worker has access to the following bindings:
4434
+ - Unsafe:
4435
+ - binding-type: my-binding
4436
+ Uploaded test-name (TIMINGS)
4437
+ Published test-name (TIMINGS)
4438
+ test-name.test-sub-domain.workers.dev"
4439
+ `);
4157
4440
  expect(std.err).toMatchInlineSnapshot(`""`);
4158
4441
  expect(std.warn).toMatchInlineSnapshot(`
4159
4442
  "▲ [WARNING] Processing wrangler.toml configuration:
@@ -4189,10 +4472,13 @@ addEventListener('fetch', event => {});`
4189
4472
 
4190
4473
  await runWrangler("publish index.js");
4191
4474
  expect(std.out).toMatchInlineSnapshot(`
4192
- "Uploaded test-name (TIMINGS)
4193
- Published test-name (TIMINGS)
4194
- test-name.test-sub-domain.workers.dev"
4195
- `);
4475
+ "Your worker has access to the following bindings:
4476
+ - Unsafe:
4477
+ - plain_text: my-binding
4478
+ Uploaded test-name (TIMINGS)
4479
+ Published test-name (TIMINGS)
4480
+ test-name.test-sub-domain.workers.dev"
4481
+ `);
4196
4482
  expect(std.err).toMatchInlineSnapshot(`""`);
4197
4483
  expect(std.warn).toMatchInlineSnapshot(`
4198
4484
  "▲ [WARNING] Processing wrangler.toml configuration:
@@ -4625,14 +4911,25 @@ addEventListener('fetch', event => {});`
4625
4911
 
4626
4912
  describe("--dry-run", () => {
4627
4913
  it("should not publish the worker if --dry-run is specified", async () => {
4628
- writeWranglerToml();
4914
+ writeWranglerToml({
4915
+ // add a durable object with migrations
4916
+ // to make sure we _don't_ fetch migration status
4917
+ durable_objects: {
4918
+ bindings: [{ name: "NAME", class_name: "SomeClass" }],
4919
+ },
4920
+ migrations: [{ tag: "v1", new_classes: ["SomeClass"] }],
4921
+ });
4629
4922
  writeWorkerSource();
4923
+ process.env.CLOUDFLARE_ACCOUNT_ID = "";
4630
4924
  await runWrangler("publish index.js --dry-run");
4631
4925
  expect(std).toMatchInlineSnapshot(`
4632
4926
  Object {
4633
4927
  "debug": "",
4634
4928
  "err": "",
4635
- "out": "--dry-run: exiting now.",
4929
+ "out": "Your worker has access to the following bindings:
4930
+ - Durable Objects:
4931
+ - NAME: SomeClass
4932
+ --dry-run: exiting now.",
4636
4933
  "warn": "",
4637
4934
  }
4638
4935
  `);
@@ -4656,6 +4953,27 @@ addEventListener('fetch', event => {});`
4656
4953
  `);
4657
4954
  });
4658
4955
 
4956
+ it("should recommend node compatibility mode when using node builtins and node-compat isn't enabled", async () => {
4957
+ writeWranglerToml();
4958
+ fs.writeFileSync(
4959
+ "index.js",
4960
+ `
4961
+ import path from 'path';
4962
+ console.log(path.join("some/path/to", "a/file.txt"));
4963
+ export default {}
4964
+ `
4965
+ );
4966
+ let err: Error | undefined;
4967
+ try {
4968
+ await runWrangler("publish index.js --dry-run"); // expecting this to throw, as node compatibility isn't enabled
4969
+ } catch (e) {
4970
+ err = e as Error;
4971
+ }
4972
+ expect(err?.message).toMatch(
4973
+ `Detected a Node builtin module import while Node compatibility is disabled.\nAdd node_compat = true to your wrangler.toml file to enable Node compatibility.`
4974
+ );
4975
+ });
4976
+
4659
4977
  it("should polyfill node builtins when enabled", async () => {
4660
4978
  writeWranglerToml();
4661
4979
  fs.writeFileSync(
@@ -4850,6 +5168,102 @@ function mockPublishRoutesRequest({
4850
5168
  );
4851
5169
  }
4852
5170
 
5171
+ function mockPublishCustomDomainsRequest({
5172
+ publishFlags,
5173
+ domains = [],
5174
+ env = undefined,
5175
+ legacyEnv = false,
5176
+ }: {
5177
+ publishFlags: {
5178
+ override_scope: boolean;
5179
+ override_existing_origin: boolean;
5180
+ override_existing_dns_record: boolean;
5181
+ };
5182
+ domains: Array<
5183
+ { hostname: string } & ({ zone_id?: string } | { zone_name?: string })
5184
+ >;
5185
+ env?: string | undefined;
5186
+ legacyEnv?: boolean | undefined;
5187
+ }) {
5188
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5189
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5190
+
5191
+ setMockResponse(
5192
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/domains`,
5193
+ "PUT",
5194
+ ([_url, accountId, scriptName, envName], { body }) => {
5195
+ expect(accountId).toEqual("some-account-id");
5196
+ expect(scriptName).toEqual(
5197
+ legacyEnv && env ? `test-name-${env}` : "test-name"
5198
+ );
5199
+ if (!legacyEnv) {
5200
+ expect(envName).toEqual(env);
5201
+ }
5202
+
5203
+ expect(JSON.parse(body as string)).toEqual({
5204
+ ...publishFlags,
5205
+ origins: domains,
5206
+ });
5207
+
5208
+ return null;
5209
+ }
5210
+ );
5211
+ }
5212
+
5213
+ function mockPublishCustomDomainsRequestConflictWithoutOverride({
5214
+ domains = [],
5215
+ originConflicts = false,
5216
+ dnsRecordConflicts = false,
5217
+ env = undefined,
5218
+ legacyEnv = false,
5219
+ }: {
5220
+ originConflicts?: boolean;
5221
+ dnsRecordConflicts?: boolean;
5222
+ domains: Array<
5223
+ { hostname: string } & ({ zone_id?: string } | { zone_name?: string })
5224
+ >;
5225
+ env?: string | undefined;
5226
+ legacyEnv?: boolean | undefined;
5227
+ }) {
5228
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5229
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5230
+
5231
+ setMockRawResponse(
5232
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/domains`,
5233
+ "PUT",
5234
+ ([_url, accountId, scriptName, envName], { body }) => {
5235
+ expect(accountId).toEqual("some-account-id");
5236
+ expect(scriptName).toEqual(
5237
+ legacyEnv && env ? `test-name-${env}` : "test-name"
5238
+ );
5239
+ if (!legacyEnv) {
5240
+ expect(envName).toEqual(env);
5241
+ }
5242
+
5243
+ const parsed = JSON.parse(body as string);
5244
+ expect(parsed.origins).toEqual(domains);
5245
+
5246
+ if (originConflicts && !parsed.override_existing_origin) {
5247
+ return createFetchResult(null, false, [
5248
+ {
5249
+ code: 100116,
5250
+ message: `Cannot create Custom Domain "${domains[0].hostname}": Custom Domain already exists and points to a different script; retry and use option "override_existing_origin" to override`,
5251
+ },
5252
+ ]);
5253
+ }
5254
+ if (dnsRecordConflicts && !parsed.override_existing_dns_record) {
5255
+ return createFetchResult(null, false, [
5256
+ {
5257
+ code: 100117,
5258
+ message: `Cannot create Custom Domain "${domains[0].hostname}": a DNS record already exists for this origin; retry and use option "override_existing_dns_record" to override`,
5259
+ },
5260
+ ]);
5261
+ }
5262
+ return createFetchResult(null, true);
5263
+ }
5264
+ );
5265
+ }
5266
+
4853
5267
  /** Create a mock handler for the request to get a list of all KV namespaces. */
4854
5268
  function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
4855
5269
  setMockResponse(