wrangler 2.6.1 → 2.7.0

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 (130) hide show
  1. package/bin/wrangler.js +9 -1
  2. package/miniflare-dist/index.mjs +1 -1
  3. package/package.json +12 -10
  4. package/src/__tests__/api-dev.test.ts +65 -36
  5. package/src/__tests__/api-devregistry.test.js +14 -6
  6. package/src/__tests__/configuration.test.ts +2 -31
  7. package/src/__tests__/{d1.test.ts → d1/d1.test.ts} +48 -5
  8. package/src/__tests__/d1/splitter.test.ts +255 -0
  9. package/src/__tests__/delete.test.ts +5 -2
  10. package/src/__tests__/deployments.test.ts +20 -6
  11. package/src/__tests__/dev.test.tsx +52 -19
  12. package/src/__tests__/generate.test.ts +7 -4
  13. package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
  14. package/src/__tests__/helpers/mock-cfetch.ts +2 -57
  15. package/src/__tests__/helpers/mock-dialogs.ts +70 -86
  16. package/src/__tests__/helpers/mock-oauth-flow.ts +64 -49
  17. package/src/__tests__/helpers/mock-process.ts +8 -13
  18. package/src/__tests__/helpers/msw/blob-worker.cjs +19 -0
  19. package/src/__tests__/helpers/msw/read-file-sync.js +61 -0
  20. package/src/__tests__/index.test.ts +46 -42
  21. package/src/__tests__/init.test.ts +782 -522
  22. package/src/__tests__/jest.setup.ts +20 -24
  23. package/src/__tests__/kv.test.ts +286 -173
  24. package/src/__tests__/logout.test.ts +1 -1
  25. package/src/__tests__/metrics.test.ts +5 -7
  26. package/src/__tests__/middleware.scheduled.test.ts +40 -30
  27. package/src/__tests__/middleware.test.ts +144 -120
  28. package/src/__tests__/pages.test.ts +1618 -1161
  29. package/src/__tests__/publish.test.ts +174 -125
  30. package/src/__tests__/r2.test.ts +2 -2
  31. package/src/__tests__/secret.test.ts +183 -126
  32. package/src/__tests__/tail.test.ts +6 -0
  33. package/src/__tests__/tsconfig-sanity.ts +12 -0
  34. package/src/__tests__/tsconfig.json +8 -0
  35. package/src/__tests__/tsconfig.tsbuildinfo +1 -0
  36. package/src/__tests__/whoami.test.tsx +1 -96
  37. package/src/api/dev.ts +78 -41
  38. package/src/api/index.ts +1 -1
  39. package/src/{bundle-reporter.tsx → bundle-reporter.ts} +0 -0
  40. package/src/cfetch/index.ts +0 -2
  41. package/src/cfetch/internal.ts +16 -18
  42. package/src/cli.ts +2 -2
  43. package/src/config/index.ts +2 -1
  44. package/src/config/validation.ts +1 -2
  45. package/src/create-worker-upload-form.ts +2 -2
  46. package/src/d1/{delete.tsx → delete.ts} +0 -0
  47. package/src/d1/execute.tsx +8 -37
  48. package/src/d1/migrations/apply.tsx +32 -19
  49. package/src/d1/migrations/{index.tsx → index.ts} +0 -0
  50. package/src/d1/splitter.ts +161 -0
  51. package/src/d1/{types.tsx → types.ts} +0 -0
  52. package/src/delete.ts +3 -8
  53. package/src/deployments.ts +6 -0
  54. package/src/deprecated/index.ts +2 -295
  55. package/src/dev/dev.tsx +2 -2
  56. package/src/dev/{get-local-persistence-path.tsx → get-local-persistence-path.ts} +0 -0
  57. package/src/dev/local.tsx +16 -4
  58. package/src/dev/remote.tsx +28 -1
  59. package/src/dev/start-server.ts +19 -11
  60. package/src/dev/use-esbuild.ts +1 -1
  61. package/src/{dev-registry.tsx → dev-registry.ts} +0 -0
  62. package/src/dev.tsx +35 -11
  63. package/src/dialogs.ts +136 -0
  64. package/src/dispatch-namespace.ts +1 -1
  65. package/src/docs/index.ts +97 -0
  66. package/src/environment-variables/factory.ts +88 -0
  67. package/src/environment-variables/misc-variables.ts +30 -0
  68. package/src/generate/index.ts +300 -0
  69. package/src/{index.tsx → index.ts} +16 -10
  70. package/src/init.ts +106 -60
  71. package/src/jest.d.ts +4 -0
  72. package/src/logger.ts +15 -3
  73. package/src/metrics/metrics-config.ts +1 -1
  74. package/src/metrics/send-event.ts +2 -1
  75. package/src/miniflare-cli/assets.ts +4 -0
  76. package/src/miniflare-cli/index.ts +1 -5
  77. package/src/miniflare-cli/tsconfig.json +9 -0
  78. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  79. package/src/miniflare-cli/types.ts +11 -0
  80. package/src/pages/{build.tsx → build.ts} +0 -0
  81. package/src/pages/{deployment-tails.tsx → deployment-tails.ts} +0 -0
  82. package/src/pages/{dev.tsx → dev.ts} +53 -55
  83. package/src/pages/functions/buildWorker.ts +1 -1
  84. package/src/pages/functions/tsconfig.json +8 -0
  85. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  86. package/src/pages/{functions.tsx → functions.ts} +0 -0
  87. package/src/pages/{hash.tsx → hash.ts} +0 -0
  88. package/src/pages/{index.tsx → index.ts} +0 -0
  89. package/src/pages/projects.tsx +3 -5
  90. package/src/pages/publish.tsx +16 -5
  91. package/src/pages/upload.tsx +27 -6
  92. package/src/publish/publish.ts +9 -7
  93. package/src/pubsub/{pubsub-commands.tsx → pubsub-commands.ts} +1 -1
  94. package/src/secret/index.ts +1 -1
  95. package/src/{sites.tsx → sites.ts} +0 -0
  96. package/src/tail/index.ts +2 -3
  97. package/src/tsconfig-sanity.ts +16 -0
  98. package/src/user/access.ts +0 -1
  99. package/src/user/auth-variables.ts +113 -0
  100. package/src/user/choose-account.tsx +1 -31
  101. package/src/user/index.ts +0 -1
  102. package/src/user/{user.tsx → user.ts} +107 -73
  103. package/src/{whoami.tsx → whoami.ts} +37 -71
  104. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  105. package/templates/__tests__/tsconfig.json +8 -0
  106. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  107. package/templates/d1-beta-facade.js +36 -0
  108. package/templates/facade.d.ts +14 -0
  109. package/templates/first-party-worker-module-facade.ts +4 -3
  110. package/templates/format-dev-errors.ts +7 -6
  111. package/templates/init-tests/test-jest-new-worker.js +3 -5
  112. package/templates/init-tests/test-vitest-new-worker.js +3 -5
  113. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  114. package/templates/middleware/loader-modules.ts +0 -2
  115. package/templates/middleware/loader-sw.ts +6 -0
  116. package/templates/pages-dev-pipeline.ts +4 -1
  117. package/templates/pages-shim.ts +4 -1
  118. package/templates/pages-template-plugin.ts +12 -7
  119. package/templates/serve-static-assets.ts +16 -14
  120. package/templates/tsconfig-sanity.ts +11 -0
  121. package/templates/tsconfig.init.json +106 -0
  122. package/templates/tsconfig.json +5 -103
  123. package/templates/tsconfig.tsbuildinfo +1 -0
  124. package/wrangler-dist/cli.d.ts +58 -60
  125. package/wrangler-dist/cli.js +34498 -55459
  126. package/wrangler-dist/wasm-sync.wasm +0 -0
  127. package/src/__tests__/dialogs.test.tsx +0 -40
  128. package/src/dialogs.tsx +0 -168
  129. package/src/environment-variables.ts +0 -50
  130. package/src/user/env-vars.ts +0 -46
package/bin/wrangler.js CHANGED
@@ -93,7 +93,15 @@ function runDelegatedWrangler() {
93
93
  } = JSON.parse(fs.readFileSync(packageJsonPath));
94
94
  const resolvedBinaryPath = path.resolve(packageJsonPath, "..", binaryPath);
95
95
 
96
- debug(`Delegating to locally-installed version of wrangler @ v${version}`);
96
+ // Make sure the user knows we're delegating to a different installation
97
+ const currentPackageJsonPath = path.resolve(__dirname, "..", "package.json");
98
+ const currentPackage = JSON.parse(fs.readFileSync(currentPackageJsonPath));
99
+ const argv = process.argv.slice(2).join(" ");
100
+ console.log(
101
+ `Delegating to locally-installed wrangler@${version} over global wrangler@${currentPackage.version}...
102
+ Run \`npx wrangler ${argv}\` to use the local version directly.
103
+ `
104
+ );
97
105
 
98
106
  // this call to `spawn` is simpler because the delegated version will do all
99
107
  // of the other work.
@@ -6019,7 +6019,7 @@ function parseRedirects(input) {
6019
6019
  var import_mime = __toESM(require_mime());
6020
6020
  import { watch } from "chokidar";
6021
6021
 
6022
- // src/pages/hash.tsx
6022
+ // src/pages/hash.ts
6023
6023
  import { readFileSync as readFileSync4 } from "node:fs";
6024
6024
  import { extname as extname2 } from "node:path";
6025
6025
  import { hash as blake3hash } from "blake3-wasm";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrangler",
3
- "version": "2.6.1",
3
+ "version": "2.7.0",
4
4
  "description": "Command-line interface for all things Cloudflare Workers",
5
5
  "keywords": [
6
6
  "wrangler",
@@ -57,7 +57,7 @@
57
57
  "assert-git-version": "node -r esbuild-register scripts/assert-git-version.ts",
58
58
  "build": "npm run clean && npm run bundle && npm run emit-types",
59
59
  "bundle": "node -r esbuild-register scripts/bundle.ts",
60
- "check:type": "tsc",
60
+ "check:type": "node -r esbuild-register scripts/tsc-all.ts",
61
61
  "clean": "rimraf wrangler-dist miniflare-dist emitted-types",
62
62
  "dev": "npm run clean && concurrently -c black,blue --kill-others-on-fail false 'npm run bundle -- --watch' 'npm run check:type -- --watch --preserveWatchOutput'",
63
63
  "emit-types": "tsc -p tsconfig.emit.json && node -r esbuild-register scripts/emit-types.ts",
@@ -100,13 +100,13 @@
100
100
  "@cloudflare/kv-asset-handler": "^0.2.0",
101
101
  "@esbuild-plugins/node-globals-polyfill": "^0.1.1",
102
102
  "@esbuild-plugins/node-modules-polyfill": "^0.1.4",
103
- "@miniflare/core": "2.10.0",
104
- "@miniflare/d1": "2.10.0",
105
- "@miniflare/durable-objects": "2.10.0",
103
+ "@miniflare/core": "2.11.0",
104
+ "@miniflare/d1": "2.11.0",
105
+ "@miniflare/durable-objects": "2.11.0",
106
106
  "blake3-wasm": "^2.1.5",
107
107
  "chokidar": "^3.5.3",
108
108
  "esbuild": "0.14.51",
109
- "miniflare": "2.10.0",
109
+ "miniflare": "2.11.0",
110
110
  "nanoid": "^3.3.3",
111
111
  "path-to-regexp": "^6.2.0",
112
112
  "selfsigned": "^2.0.1",
@@ -115,8 +115,7 @@
115
115
  },
116
116
  "devDependencies": {
117
117
  "@cloudflare/types": "^6.18.4",
118
- "@databases/split-sql-query": "^1.0.3",
119
- "@databases/sql": "^3.2.0",
118
+ "@cloudflare/workers-types": "^4.20221111.1",
120
119
  "@iarna/toml": "^3.0.0",
121
120
  "@microsoft/api-extractor": "^7.28.3",
122
121
  "@miniflare/tre": "^3.0.0-next.8",
@@ -136,6 +135,8 @@
136
135
  "@types/yargs": "^17.0.10",
137
136
  "@webcontainer/env": "^1.0.1",
138
137
  "body-parser": "^1.20.0",
138
+ "chalk": "^2.4.2",
139
+ "cli-table3": "^0.6.3",
139
140
  "clipboardy": "^3.0.0",
140
141
  "cmd-shim": "^4.1.0",
141
142
  "command-exists": "^1.2.9",
@@ -178,11 +179,12 @@
178
179
  "timeago.js": "^4.0.2",
179
180
  "tmp-promise": "^3.0.3",
180
181
  "ts-dedent": "^2.2.0",
181
- "undici": "^5.11.0",
182
+ "undici": "5.11.0",
182
183
  "update-check": "^1.5.4",
183
184
  "ws": "^8.5.0",
184
185
  "xdg-app-paths": "^7.3.0",
185
- "yargs": "^17.4.1"
186
+ "yargs": "^17.4.1",
187
+ "yoga-layout": "file:../../vendor/yoga-layout-2.0.0-beta.1.tgz"
186
188
  },
187
189
  "optionalDependencies": {
188
190
  "fsevents": "~2.3.2"
@@ -5,12 +5,16 @@ import { runInTempDir } from "./helpers/run-in-tmp";
5
5
 
6
6
  jest.unmock("undici");
7
7
 
8
- describe.skip("unstable_dev", () => {
8
+ describe("unstable_dev", () => {
9
9
  it("should return Hello World", async () => {
10
10
  const worker = await unstable_dev(
11
11
  "src/__tests__/helpers/worker-scripts/hello-world-worker.js",
12
- {},
13
- { disableExperimentalWarning: true }
12
+ {
13
+ experimental: {
14
+ disableExperimentalWarning: true,
15
+ disableDevRegistry: true,
16
+ },
17
+ }
14
18
  );
15
19
  const resp = await worker.fetch();
16
20
  if (resp) {
@@ -23,8 +27,12 @@ describe.skip("unstable_dev", () => {
23
27
  it("should return the port that the server started on (1)", async () => {
24
28
  const worker = await unstable_dev(
25
29
  "src/__tests__/helpers/worker-scripts/hello-world-worker.js",
26
- {},
27
- { disableExperimentalWarning: true }
30
+ {
31
+ experimental: {
32
+ disableExperimentalWarning: true,
33
+ disableDevRegistry: true,
34
+ },
35
+ }
28
36
  );
29
37
  expect(worker.port).toBeGreaterThan(0);
30
38
  await worker.stop();
@@ -33,8 +41,13 @@ describe.skip("unstable_dev", () => {
33
41
  it("should return the port that the server started on (2)", async () => {
34
42
  const worker = await unstable_dev(
35
43
  "src/__tests__/helpers/worker-scripts/hello-world-worker.js",
36
- { port: 9191 },
37
- { disableExperimentalWarning: true }
44
+ {
45
+ port: 9191,
46
+ experimental: {
47
+ disableExperimentalWarning: true,
48
+ disableDevRegistry: true,
49
+ },
50
+ }
38
51
  );
39
52
  expect(worker.port).toBe(9191);
40
53
  await worker.stop();
@@ -45,8 +58,13 @@ describe("unstable dev fetch input protocol", () => {
45
58
  it("should use http localProtocol", async () => {
46
59
  const worker = await unstable_dev(
47
60
  "src/__tests__/helpers/worker-scripts/hello-world-worker.js",
48
- { localProtocol: "http" },
49
- { disableExperimentalWarning: true }
61
+ {
62
+ localProtocol: "http",
63
+ experimental: {
64
+ disableExperimentalWarning: true,
65
+ disableDevRegistry: true,
66
+ },
67
+ }
50
68
  );
51
69
  const res = await worker.fetch();
52
70
  if (res) {
@@ -59,8 +77,13 @@ describe("unstable dev fetch input protocol", () => {
59
77
  it("should use undefined localProtocol", async () => {
60
78
  const worker = await unstable_dev(
61
79
  "src/__tests__/helpers/worker-scripts/hello-world-worker.js",
62
- { localProtocol: undefined },
63
- { disableExperimentalWarning: true }
80
+ {
81
+ localProtocol: undefined,
82
+ experimental: {
83
+ disableExperimentalWarning: true,
84
+ disableDevRegistry: true,
85
+ },
86
+ }
64
87
  );
65
88
  const res = await worker.fetch();
66
89
  if (res) {
@@ -91,11 +114,13 @@ describe("unstable dev fetch input parsing", () => {
91
114
  `;
92
115
  fs.writeFileSync("index.js", scriptContent);
93
116
  const port = 21213;
94
- const worker = await unstable_dev(
95
- "index.js",
96
- { port },
97
- { disableExperimentalWarning: true }
98
- );
117
+ const worker = await unstable_dev("index.js", {
118
+ port,
119
+ experimental: {
120
+ disableExperimentalWarning: true,
121
+ disableDevRegistry: true,
122
+ },
123
+ });
99
124
  const req = new Request("http://0.0.0.0:21213/test", {
100
125
  method: "POST",
101
126
  });
@@ -119,11 +144,12 @@ describe("unstable dev fetch input parsing", () => {
119
144
  };
120
145
  `;
121
146
  fs.writeFileSync("index.js", scriptContent);
122
- const worker = await unstable_dev(
123
- "index.js",
124
- {},
125
- { disableExperimentalWarning: true }
126
- );
147
+ const worker = await unstable_dev("index.js", {
148
+ experimental: {
149
+ disableExperimentalWarning: true,
150
+ disableDevRegistry: true,
151
+ },
152
+ });
127
153
  const url = new URL("http://localhost:80/test");
128
154
  const resp = await worker.fetch(url);
129
155
  let text;
@@ -145,11 +171,12 @@ describe("unstable dev fetch input parsing", () => {
145
171
  };
146
172
  `;
147
173
  fs.writeFileSync("index.js", scriptContent);
148
- const worker = await unstable_dev(
149
- "index.js",
150
- {},
151
- { disableExperimentalWarning: true }
152
- );
174
+ const worker = await unstable_dev("index.js", {
175
+ experimental: {
176
+ disableExperimentalWarning: true,
177
+ disableDevRegistry: true,
178
+ },
179
+ });
153
180
  const resp = await worker.fetch("http://example.com/test");
154
181
  let text;
155
182
  if (resp) text = await resp.text();
@@ -170,11 +197,12 @@ describe("unstable dev fetch input parsing", () => {
170
197
  };
171
198
  `;
172
199
  fs.writeFileSync("index.js", scriptContent);
173
- const worker = await unstable_dev(
174
- "index.js",
175
- {},
176
- { disableExperimentalWarning: true }
177
- );
200
+ const worker = await unstable_dev("index.js", {
201
+ experimental: {
202
+ disableExperimentalWarning: true,
203
+ disableDevRegistry: true,
204
+ },
205
+ });
178
206
  const resp = await worker.fetch("/test");
179
207
  let text;
180
208
  if (resp) text = await resp.text();
@@ -195,11 +223,12 @@ describe("unstable dev fetch input parsing", () => {
195
223
  };
196
224
  `;
197
225
  fs.writeFileSync("index.js", scriptContent);
198
- const worker = await unstable_dev(
199
- "index.js",
200
- {},
201
- { disableExperimentalWarning: true }
202
- );
226
+ const worker = await unstable_dev("index.js", {
227
+ experimental: {
228
+ disableExperimentalWarning: true,
229
+ disableDevRegistry: true,
230
+ },
231
+ });
203
232
  const resp = await worker.fetch("");
204
233
  let text;
205
234
  if (resp) text = await resp.text();
@@ -1,26 +1,34 @@
1
1
  import { unstable_dev } from "../api";
2
2
  import { fetch } from "undici";
3
3
 
4
- // jest.unmock("undici");
4
+ jest.unmock("undici");
5
5
 
6
6
  /**
7
7
  * a huge caveat to how testing multi-worker scripts works:
8
8
  * you can't shutdown the first worker you spun up, or it'll kill the devRegistry
9
9
  */
10
- describe.skip("multi-worker testing", () => {
10
+ describe("multi-worker testing", () => {
11
11
  let childWorker;
12
12
  let parentWorker;
13
13
 
14
14
  beforeAll(async () => {
15
15
  childWorker = await unstable_dev(
16
16
  "src/__tests__/helpers/worker-scripts/hello-world-worker.js",
17
- { config: "src/__tests__/helpers/worker-scripts/child-wrangler.toml" },
18
- { disableExperimentalWarning: true }
17
+ {
18
+ config: "src/__tests__/helpers/worker-scripts/child-wrangler.toml",
19
+ experimental: {
20
+ disableExperimentalWarning: true,
21
+ },
22
+ }
19
23
  );
20
24
  parentWorker = await unstable_dev(
21
25
  "src/__tests__/helpers/worker-scripts/parent-worker.js",
22
- { config: "src/__tests__/helpers/worker-scripts/parent-wrangler.toml" },
23
- { disableExperimentalWarning: true }
26
+ {
27
+ config: "src/__tests__/helpers/worker-scripts/parent-wrangler.toml",
28
+ experimental: {
29
+ disableExperimentalWarning: true,
30
+ },
31
+ }
24
32
  );
25
33
  });
26
34
 
@@ -2125,27 +2125,6 @@ describe("normalizeAndValidateConfig()", () => {
2125
2125
  });
2126
2126
 
2127
2127
  describe("[dispatch_namespaces]", () => {
2128
- it("should log an experimental warning when dispatch_namespaces is used", () => {
2129
- const { diagnostics } = normalizeAndValidateConfig(
2130
- {
2131
- dispatch_namespaces: [
2132
- {
2133
- binding: "BINDING_1",
2134
- namespace: "NAMESPACE_1",
2135
- },
2136
- ],
2137
- } as unknown as RawConfig,
2138
- undefined,
2139
- { env: undefined }
2140
- );
2141
- expect(diagnostics.hasWarnings()).toBe(true);
2142
- expect(diagnostics.hasErrors()).toBe(false);
2143
- expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2144
- "Processing wrangler configuration:
2145
- - \\"dispatch_namespaces\\" fields are experimental and may change or break at any time."
2146
- `);
2147
- });
2148
-
2149
2128
  it("should error if dispatch_namespaces is not an array", () => {
2150
2129
  const { diagnostics } = normalizeAndValidateConfig(
2151
2130
  {
@@ -2155,12 +2134,8 @@ describe("normalizeAndValidateConfig()", () => {
2155
2134
  { env: undefined }
2156
2135
  );
2157
2136
 
2158
- expect(diagnostics.hasWarnings()).toBe(true);
2137
+ expect(diagnostics.hasWarnings()).toBe(false);
2159
2138
  expect(diagnostics.hasErrors()).toBe(true);
2160
- expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2161
- "Processing wrangler configuration:
2162
- - \\"dispatch_namespaces\\" fields are experimental and may change or break at any time."
2163
- `);
2164
2139
  expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2165
2140
  "Processing wrangler configuration:
2166
2141
  - The field \\"dispatch_namespaces\\" should be an array but got \\"just a string\\"."
@@ -2199,12 +2174,8 @@ describe("normalizeAndValidateConfig()", () => {
2199
2174
  undefined,
2200
2175
  { env: undefined }
2201
2176
  );
2202
- expect(diagnostics.hasWarnings()).toBe(true);
2177
+ expect(diagnostics.hasWarnings()).toBe(false);
2203
2178
  expect(diagnostics.hasErrors()).toBe(true);
2204
- expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2205
- "Processing wrangler configuration:
2206
- - \\"dispatch_namespaces\\" fields are experimental and may change or break at any time."
2207
- `);
2208
2179
  expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2209
2180
  "Processing wrangler configuration:
2210
2181
  - \\"dispatch_namespaces[0]\\" binding should be objects, but got \\"a string\\"
@@ -1,6 +1,9 @@
1
- import { mockAccountId } from "./helpers/mock-account-id";
2
- import { mockConsoleMethods } from "./helpers/mock-console";
3
- import { runWrangler } from "./helpers/run-wrangler";
1
+ import { cwd } from "process";
2
+ import { mockConsoleMethods } from "../helpers/mock-console";
3
+ import { useMockIsTTY } from "../helpers/mock-istty";
4
+ import { runInTempDir } from "../helpers/run-in-tmp";
5
+ import { runWrangler } from "../helpers/run-wrangler";
6
+ import writeWranglerToml from "../helpers/write-wrangler-toml";
4
7
 
5
8
  function endEventLoop() {
6
9
  return new Promise((resolve) => setImmediate(resolve));
@@ -8,8 +11,8 @@ function endEventLoop() {
8
11
 
9
12
  describe("d1", () => {
10
13
  const std = mockConsoleMethods();
11
-
12
- mockAccountId();
14
+ runInTempDir();
15
+ const { setIsTTY } = useMockIsTTY();
13
16
 
14
17
  it("should show help when no argument is passed", async () => {
15
18
  await runWrangler("d1");
@@ -77,4 +80,44 @@ describe("d1", () => {
77
80
  To give feedback, visit https://discord.gg/cloudflaredev"
78
81
  `);
79
82
  });
83
+
84
+ describe("migrate", () => {
85
+ describe("apply", () => {
86
+ it("should not attempt to login in local mode", async () => {
87
+ setIsTTY(false);
88
+ writeWranglerToml({
89
+ d1_databases: [
90
+ { binding: "DATABASE", database_name: "db", database_id: "xxxx" },
91
+ ],
92
+ });
93
+ // If we get to the point where we are checking for migrations then we have not been asked to log in.
94
+ await expect(
95
+ runWrangler("d1 migrations apply --local DATABASE")
96
+ ).rejects.toThrowError(
97
+ `No migrations present at ${cwd().replaceAll("\\", "/")}/migrations.`
98
+ );
99
+ });
100
+
101
+ it("should try to read D1 config from wrangler.toml", async () => {
102
+ setIsTTY(false);
103
+ writeWranglerToml();
104
+ await expect(
105
+ runWrangler("d1 migrations apply DATABASE")
106
+ ).rejects.toThrowError(
107
+ "Can't find a DB with name/binding 'DATABASE' in local config. Check info in wrangler.toml..."
108
+ );
109
+ });
110
+
111
+ it("should not try to read wrangler.toml in local mode", async () => {
112
+ setIsTTY(false);
113
+ writeWranglerToml();
114
+ // If we get to the point where we are checking for migrations then we have not checked wrangler.toml.
115
+ await expect(
116
+ runWrangler("d1 migrations apply --local DATABASE")
117
+ ).rejects.toThrowError(
118
+ `No migrations present at ${cwd().replaceAll("\\", "/")}/migrations.`
119
+ );
120
+ });
121
+ });
122
+ });
80
123
  });
@@ -0,0 +1,255 @@
1
+ import splitSqlQuery, { mayContainMultipleStatements } from "../../d1/splitter";
2
+
3
+ describe("mayContainMultipleStatements()", () => {
4
+ it("should return false if there is only a semi-colon at the end", () => {
5
+ expect(mayContainMultipleStatements(`SELECT * FROM my_table`)).toBe(false);
6
+ expect(
7
+ mayContainMultipleStatements(`SELECT * FROM my_table WHERE id = 42;`)
8
+ ).toBe(false);
9
+ expect(
10
+ mayContainMultipleStatements(`SELECT * FROM my_table WHERE id = 42; `)
11
+ ).toBe(false);
12
+ });
13
+
14
+ it("should return true if there is a semi-colon before the end of the string", () => {
15
+ expect(
16
+ mayContainMultipleStatements(
17
+ `SELECT * FROM my_table WHERE val = "foo;bar";`
18
+ )
19
+ ).toBe(true);
20
+ });
21
+
22
+ it("should return true if there is more than one statement", () => {
23
+ expect(
24
+ mayContainMultipleStatements(
25
+ `
26
+ INSERT INTO my_table (id, value) VALUES (42, 'foo');
27
+ SELECT * FROM my_table WHERE id = 42;
28
+ `
29
+ )
30
+ ).toBe(true);
31
+ });
32
+ });
33
+
34
+ describe("splitSqlQuery()", () => {
35
+ it("should return original SQL if there are no real statements", () => {
36
+ expect(splitSqlQuery(`;;;`)).toMatchInlineSnapshot(`
37
+ Array [
38
+ ";;;",
39
+ ]
40
+ `);
41
+ });
42
+
43
+ it("should not split single statements", () => {
44
+ expect(splitSqlQuery(`SELECT * FROM my_table`)).toMatchInlineSnapshot(`
45
+ Array [
46
+ "SELECT * FROM my_table",
47
+ ]
48
+ `);
49
+ expect(splitSqlQuery(`SELECT * FROM my_table WHERE id = 42;`))
50
+ .toMatchInlineSnapshot(`
51
+ Array [
52
+ "SELECT * FROM my_table WHERE id = 42;",
53
+ ]
54
+ `);
55
+ expect(
56
+ splitSqlQuery(
57
+ `
58
+ SELECT * FROM my_table WHERE id = 42;
59
+ `
60
+ )
61
+ ).toMatchInlineSnapshot(`
62
+ Array [
63
+ "
64
+ SELECT * FROM my_table WHERE id = 42;
65
+ ",
66
+ ]
67
+ `);
68
+ });
69
+
70
+ it("should handle strings", () => {
71
+ expect(
72
+ splitSqlQuery(
73
+ `
74
+ SELECT * FROM my_table WHERE val = "foo;bar";
75
+ `
76
+ )
77
+ ).toMatchInlineSnapshot(`
78
+ Array [
79
+ "SELECT * FROM my_table WHERE val = \\"foo;bar\\"",
80
+ ]
81
+ `);
82
+ });
83
+
84
+ it("should handle inline comments", () => {
85
+ expect(
86
+ splitSqlQuery(
87
+ `SELECT * FROM my_table -- semicolons; in; comments; don't count;
88
+ WHERE val = 'foo;bar'
89
+ AND "col;name" = \`other;col\`; -- or identifiers (Postgres or MySQL style)`
90
+ )
91
+ ).toMatchInlineSnapshot(`
92
+ Array [
93
+ "SELECT * FROM my_table -- semicolons; in; comments; don't count;
94
+ WHERE val = 'foo;bar'
95
+ AND \\"col;name\\" = \`other;col\`",
96
+ "-- or identifiers (Postgres or MySQL style)",
97
+ ]
98
+ `);
99
+ });
100
+
101
+ it("should handle block comments", () => {
102
+ expect(
103
+ splitSqlQuery(
104
+ `/****
105
+ * Block comments are ignored;
106
+ ****/
107
+ SELECT * FROM my_table /* semicolons; in; comments; don't count; */
108
+ WHERE val = 'foo;bar' AND count / 2 > 0`
109
+ )
110
+ ).toMatchInlineSnapshot(`
111
+ Array [
112
+ "/****
113
+ * Block comments are ignored;
114
+ ****/
115
+ SELECT * FROM my_table /* semicolons; in; comments; don't count; */
116
+ WHERE val = 'foo;bar' AND count / 2 > 0",
117
+ ]
118
+ `);
119
+ });
120
+
121
+ it("should split multiple statements", () => {
122
+ expect(
123
+ splitSqlQuery(
124
+ `
125
+ INSERT INTO my_table (id, value) VALUES (42, 'foo');
126
+ SELECT * FROM my_table WHERE id = 42 - 10;
127
+ `
128
+ )
129
+ ).toMatchInlineSnapshot(`
130
+ Array [
131
+ "INSERT INTO my_table (id, value) VALUES (42, 'foo')",
132
+ "SELECT * FROM my_table WHERE id = 42 - 10",
133
+ ]
134
+ `);
135
+ });
136
+
137
+ it("should handle whitespace between statements", () => {
138
+ expect(
139
+ splitSqlQuery(`
140
+ CREATE DOMAIN custom_types.email AS TEXT CHECK (VALUE ~ '^.+@.+$');
141
+ CREATE TYPE custom_types.currency AS ENUM('USD', 'GBP');
142
+
143
+ CREATE TYPE custom_types.money_with_currency AS (
144
+ value NUMERIC(1000, 2),
145
+ currency custom_types.currency,
146
+ description TEXT
147
+ );
148
+ CREATE TYPE custom_types.balance_pair AS (
149
+ income custom_types.money_with_currency,
150
+ expenditure custom_types.money_with_currency
151
+ );
152
+
153
+ CREATE TABLE custom_types.accounts (
154
+ email custom_types.email NOT NULL PRIMARY KEY,
155
+ balance custom_types.money_with_currency
156
+ );
157
+ CREATE TABLE custom_types.balance_pairs (
158
+ balance custom_types.balance_pair
159
+ );
160
+ `)
161
+ ).toMatchInlineSnapshot(`
162
+ Array [
163
+ "CREATE DOMAIN custom_types.email AS TEXT CHECK (VALUE ~ '^.+@.+$')",
164
+ "CREATE TYPE custom_types.currency AS ENUM('USD', 'GBP')",
165
+ "CREATE TYPE custom_types.money_with_currency AS (
166
+ value NUMERIC(1000, 2),
167
+ currency custom_types.currency,
168
+ description TEXT
169
+ )",
170
+ "CREATE TYPE custom_types.balance_pair AS (
171
+ income custom_types.money_with_currency,
172
+ expenditure custom_types.money_with_currency
173
+ )",
174
+ "CREATE TABLE custom_types.accounts (
175
+ email custom_types.email NOT NULL PRIMARY KEY,
176
+ balance custom_types.money_with_currency
177
+ )",
178
+ "CREATE TABLE custom_types.balance_pairs (
179
+ balance custom_types.balance_pair
180
+ )",
181
+ ]
182
+ `);
183
+ });
184
+
185
+ it("should handle $...$ style string markers", () => {
186
+ expect(
187
+ splitSqlQuery(`
188
+ CREATE OR REPLACE FUNCTION update_updated_at_column()
189
+ RETURNS TRIGGER AS $$
190
+ BEGIN
191
+ NEW.updated_at = now();
192
+ RETURN NEW;
193
+ END;
194
+ $$ language 'plpgsql';
195
+ CREATE TRIGGER <trigger_name> BEFORE UPDATE ON <table_name> FOR EACH ROW EXECUTE PROCEDURE update_updated_at_column();
196
+ `)
197
+ ).toMatchInlineSnapshot(`
198
+ Array [
199
+ "CREATE OR REPLACE FUNCTION update_updated_at_column()
200
+ RETURNS TRIGGER AS $$
201
+ BEGIN
202
+ NEW.updated_at = now();
203
+ RETURN NEW;
204
+ END;
205
+ $$ language 'plpgsql'",
206
+ "CREATE TRIGGER <trigger_name> BEFORE UPDATE ON <table_name> FOR EACH ROW EXECUTE PROCEDURE update_updated_at_column()",
207
+ ]
208
+ `);
209
+ expect(
210
+ splitSqlQuery(
211
+ `$SomeTag$Dianne's$WrongTag$;$some non tag an$identifier;; horse$SomeTag$;$SomeTag$Dianne's horse$SomeTag$`
212
+ )
213
+ ).toMatchInlineSnapshot(`
214
+ Array [
215
+ "$SomeTag$Dianne's$WrongTag$;$some non tag an$identifier;; horse$SomeTag$",
216
+ "$SomeTag$Dianne's horse$SomeTag$",
217
+ ]
218
+ `);
219
+ });
220
+
221
+ it("should handle compound statements", () => {
222
+ expect(
223
+ splitSqlQuery(`
224
+ CREATE TRIGGER IF NOT EXISTS update_trigger AFTER UPDATE ON items
225
+ BEGIN
226
+ DELETE FROM updates WHERE item_id=old.id;
227
+ END;
228
+ CREATE TRIGGER IF NOT EXISTS actors_search_fts_update AFTER UPDATE ON actors
229
+ BEGIN
230
+ DELETE FROM search_fts WHERE rowid=old.rowid;
231
+ INSERT INTO search_fts (rowid, type, name, preferredUsername)
232
+ VALUES (new.rowid,
233
+ new.type,
234
+ json_extract(new.properties, '$.name'),
235
+ json_extract(new.properties, '$.preferredUsername'));
236
+ END;`)
237
+ ).toMatchInlineSnapshot(`
238
+ Array [
239
+ "CREATE TRIGGER IF NOT EXISTS update_trigger AFTER UPDATE ON items
240
+ BEGIN
241
+ DELETE FROM updates WHERE item_id=old.id;
242
+ END",
243
+ "CREATE TRIGGER IF NOT EXISTS actors_search_fts_update AFTER UPDATE ON actors
244
+ BEGIN
245
+ DELETE FROM search_fts WHERE rowid=old.rowid;
246
+ INSERT INTO search_fts (rowid, type, name, preferredUsername)
247
+ VALUES (new.rowid,
248
+ new.type,
249
+ json_extract(new.properties, '$.name'),
250
+ json_extract(new.properties, '$.preferredUsername'));
251
+ END",
252
+ ]
253
+ `);
254
+ });
255
+ });