wrangler 2.0.12 → 2.0.16

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 (149) hide show
  1. package/README.md +7 -1
  2. package/bin/wrangler.js +111 -57
  3. package/miniflare-dist/index.mjs +9 -2
  4. package/package.json +156 -154
  5. package/src/__tests__/config-cache-without-cache-dir.test.ts +38 -0
  6. package/src/__tests__/config-cache.test.ts +30 -24
  7. package/src/__tests__/configuration.test.ts +3935 -3476
  8. package/src/__tests__/dev.test.tsx +1128 -979
  9. package/src/__tests__/guess-worker-format.test.ts +68 -68
  10. package/src/__tests__/helpers/cmd-shim.d.ts +6 -6
  11. package/src/__tests__/helpers/faye-websocket.d.ts +4 -4
  12. package/src/__tests__/helpers/mock-account-id.ts +24 -24
  13. package/src/__tests__/helpers/mock-bin.ts +20 -20
  14. package/src/__tests__/helpers/mock-cfetch.ts +92 -92
  15. package/src/__tests__/helpers/mock-console.ts +49 -39
  16. package/src/__tests__/helpers/mock-dialogs.ts +94 -71
  17. package/src/__tests__/helpers/mock-http-server.ts +30 -30
  18. package/src/__tests__/helpers/mock-istty.ts +65 -18
  19. package/src/__tests__/helpers/mock-kv.ts +26 -26
  20. package/src/__tests__/helpers/mock-oauth-flow.ts +223 -228
  21. package/src/__tests__/helpers/mock-process.ts +39 -0
  22. package/src/__tests__/helpers/mock-stdin.ts +82 -77
  23. package/src/__tests__/helpers/mock-web-socket.ts +21 -21
  24. package/src/__tests__/helpers/run-in-tmp.ts +27 -27
  25. package/src/__tests__/helpers/run-wrangler.ts +8 -8
  26. package/src/__tests__/helpers/write-worker-source.ts +16 -16
  27. package/src/__tests__/helpers/write-wrangler-toml.ts +9 -9
  28. package/src/__tests__/https-options.test.ts +104 -104
  29. package/src/__tests__/index.test.ts +239 -234
  30. package/src/__tests__/init.test.ts +1605 -1250
  31. package/src/__tests__/jest.setup.ts +63 -33
  32. package/src/__tests__/kv.test.ts +1128 -1011
  33. package/src/__tests__/logger.test.ts +100 -74
  34. package/src/__tests__/package-manager.test.ts +303 -303
  35. package/src/__tests__/pages.test.ts +1152 -652
  36. package/src/__tests__/parse.test.ts +252 -252
  37. package/src/__tests__/publish.test.ts +6371 -5622
  38. package/src/__tests__/pubsub.test.ts +367 -0
  39. package/src/__tests__/r2.test.ts +133 -133
  40. package/src/__tests__/route.test.ts +18 -18
  41. package/src/__tests__/secret.test.ts +382 -377
  42. package/src/__tests__/tail.test.ts +530 -530
  43. package/src/__tests__/user.test.ts +123 -111
  44. package/src/__tests__/whoami.test.tsx +198 -117
  45. package/src/__tests__/worker-namespace.test.ts +327 -0
  46. package/src/abort.d.ts +1 -1
  47. package/src/api/dev.ts +49 -0
  48. package/src/api/index.ts +1 -0
  49. package/src/bundle-reporter.tsx +29 -0
  50. package/src/bundle.ts +157 -149
  51. package/src/cfetch/index.ts +80 -80
  52. package/src/cfetch/internal.ts +90 -83
  53. package/src/cli.ts +21 -7
  54. package/src/config/config.ts +204 -195
  55. package/src/config/diagnostics.ts +61 -61
  56. package/src/config/environment.ts +390 -357
  57. package/src/config/index.ts +206 -193
  58. package/src/config/validation-helpers.ts +366 -366
  59. package/src/config/validation.ts +1573 -1376
  60. package/src/config-cache.ts +79 -41
  61. package/src/create-worker-preview.ts +206 -136
  62. package/src/create-worker-upload-form.ts +247 -238
  63. package/src/dev/dev-vars.ts +13 -13
  64. package/src/dev/dev.tsx +329 -307
  65. package/src/dev/local.tsx +304 -275
  66. package/src/dev/remote.tsx +366 -224
  67. package/src/dev/use-esbuild.ts +126 -91
  68. package/src/dev.tsx +538 -0
  69. package/src/dialogs.tsx +97 -97
  70. package/src/durable.ts +87 -87
  71. package/src/entry.ts +234 -228
  72. package/src/environment-variables.ts +23 -23
  73. package/src/errors.ts +6 -6
  74. package/src/generate.ts +33 -0
  75. package/src/git-client.ts +42 -0
  76. package/src/https-options.ts +79 -79
  77. package/src/index.tsx +1775 -2763
  78. package/src/init.ts +549 -0
  79. package/src/inspect.ts +593 -593
  80. package/src/intl-polyfill.d.ts +123 -123
  81. package/src/is-interactive.ts +12 -0
  82. package/src/kv.ts +277 -277
  83. package/src/logger.ts +46 -39
  84. package/src/miniflare-cli/enum-keys.ts +8 -8
  85. package/src/miniflare-cli/index.ts +42 -31
  86. package/src/miniflare-cli/request-context.ts +18 -18
  87. package/src/module-collection.ts +212 -212
  88. package/src/open-in-browser.ts +4 -6
  89. package/src/package-manager.ts +123 -123
  90. package/src/pages/build.tsx +202 -0
  91. package/src/pages/constants.ts +7 -0
  92. package/src/pages/deployments.tsx +101 -0
  93. package/src/pages/dev.tsx +964 -0
  94. package/src/pages/functions/buildPlugin.ts +105 -0
  95. package/src/pages/functions/buildWorker.ts +151 -0
  96. package/{pages → src/pages}/functions/filepath-routing.test.ts +113 -113
  97. package/src/pages/functions/filepath-routing.ts +189 -0
  98. package/src/pages/functions/identifiers.ts +78 -0
  99. package/src/pages/functions/routes.ts +151 -0
  100. package/src/pages/index.tsx +84 -0
  101. package/src/pages/projects.tsx +157 -0
  102. package/src/pages/publish.tsx +335 -0
  103. package/src/pages/types.ts +40 -0
  104. package/src/pages/upload.tsx +384 -0
  105. package/src/pages/utils.ts +12 -0
  106. package/src/parse.ts +202 -138
  107. package/src/paths.ts +6 -6
  108. package/src/preview.ts +31 -0
  109. package/src/proxy.ts +400 -402
  110. package/src/publish.ts +667 -621
  111. package/src/pubsub/index.ts +286 -0
  112. package/src/pubsub/pubsub-commands.tsx +577 -0
  113. package/src/r2.ts +19 -19
  114. package/src/selfsigned.d.ts +23 -23
  115. package/src/sites.tsx +271 -225
  116. package/src/tail/filters.ts +108 -108
  117. package/src/tail/index.ts +217 -217
  118. package/src/tail/printing.ts +45 -45
  119. package/src/update-check.ts +11 -11
  120. package/src/user/choose-account.tsx +60 -0
  121. package/src/user/env-vars.ts +46 -0
  122. package/src/user/generate-auth-url.ts +33 -0
  123. package/src/user/generate-random-state.ts +16 -0
  124. package/src/user/index.ts +3 -0
  125. package/src/user/user.tsx +1161 -0
  126. package/src/whoami.tsx +61 -42
  127. package/src/worker-namespace.ts +190 -0
  128. package/src/worker.ts +110 -100
  129. package/src/zones.ts +39 -36
  130. package/templates/checked-fetch.js +17 -0
  131. package/templates/new-worker-scheduled.js +3 -3
  132. package/templates/new-worker-scheduled.ts +15 -15
  133. package/templates/new-worker.js +3 -3
  134. package/templates/new-worker.ts +15 -15
  135. package/templates/no-op-worker.js +10 -0
  136. package/templates/pages-template-plugin.ts +155 -0
  137. package/templates/pages-template-worker.ts +161 -0
  138. package/templates/static-asset-facade.js +31 -31
  139. package/templates/tsconfig.json +95 -95
  140. package/wrangler-dist/cli.js +55383 -54138
  141. package/pages/functions/buildPlugin.ts +0 -105
  142. package/pages/functions/buildWorker.ts +0 -151
  143. package/pages/functions/filepath-routing.ts +0 -189
  144. package/pages/functions/identifiers.ts +0 -78
  145. package/pages/functions/routes.ts +0 -156
  146. package/pages/functions/template-plugin.ts +0 -147
  147. package/pages/functions/template-worker.ts +0 -143
  148. package/src/pages.tsx +0 -2093
  149. package/src/user.tsx +0 -1214
package/src/bundle.ts CHANGED
@@ -11,10 +11,10 @@ import type { Entry } from "./entry";
11
11
  import type { CfModule } from "./worker";
12
12
 
13
13
  type BundleResult = {
14
- modules: CfModule[];
15
- resolvedEntryPointPath: string;
16
- bundleType: "esm" | "commonjs";
17
- stop: (() => void) | undefined;
14
+ modules: CfModule[];
15
+ resolvedEntryPointPath: string;
16
+ bundleType: "esm" | "commonjs";
17
+ stop: (() => void) | undefined;
18
18
  };
19
19
 
20
20
  /**
@@ -23,135 +23,143 @@ type BundleResult = {
23
23
  * Supports both regular node builtins, and the new "node:<MODULE>" format.
24
24
  */
25
25
  const checkForNodeBuiltinsPlugin = {
26
- name: "checkForNodeBuiltins",
27
- setup(build: esbuild.PluginBuild) {
28
- build.onResolve(
29
- {
30
- filter: new RegExp(
31
- "^(" +
32
- builtinModules.join("|") +
33
- "|" +
34
- builtinModules.map((module) => "node:" + module).join("|") +
35
- ")$"
36
- ),
37
- },
38
- () => {
39
- throw new Error(
40
- `Detected a Node builtin module import while Node compatibility is disabled.\nAdd node_compat = true to your wrangler.toml file to enable Node compatibility.`
41
- );
42
- }
43
- );
44
- },
26
+ name: "checkForNodeBuiltins",
27
+ setup(build: esbuild.PluginBuild) {
28
+ build.onResolve(
29
+ {
30
+ filter: new RegExp(
31
+ "^(" +
32
+ builtinModules.join("|") +
33
+ "|" +
34
+ builtinModules.map((module) => "node:" + module).join("|") +
35
+ ")$"
36
+ ),
37
+ },
38
+ () => {
39
+ throw new Error(
40
+ `Detected a Node builtin module import while Node compatibility is disabled.\nAdd node_compat = true to your wrangler.toml file to enable Node compatibility.`
41
+ );
42
+ }
43
+ );
44
+ },
45
45
  };
46
46
 
47
47
  /**
48
48
  * Generate a bundle for the worker identified by the arguments passed in.
49
49
  */
50
50
  export async function bundleWorker(
51
- entry: Entry,
52
- destination: string,
53
- options: {
54
- serveAssetsFromWorker: boolean;
55
- jsxFactory: string | undefined;
56
- jsxFragment: string | undefined;
57
- rules: Config["rules"];
58
- watch?: esbuild.WatchMode;
59
- tsconfig: string | undefined;
60
- minify: boolean | undefined;
61
- nodeCompat: boolean | undefined;
62
- }
51
+ entry: Entry,
52
+ destination: string,
53
+ options: {
54
+ serveAssetsFromWorker: boolean;
55
+ jsxFactory: string | undefined;
56
+ jsxFragment: string | undefined;
57
+ rules: Config["rules"];
58
+ watch?: esbuild.WatchMode;
59
+ tsconfig: string | undefined;
60
+ minify: boolean | undefined;
61
+ nodeCompat: boolean | undefined;
62
+ define: Config["define"];
63
+ checkFetch: boolean;
64
+ }
63
65
  ): Promise<BundleResult> {
64
- const {
65
- serveAssetsFromWorker,
66
- jsxFactory,
67
- jsxFragment,
68
- rules,
69
- watch,
70
- tsconfig,
71
- minify,
72
- nodeCompat,
73
- } = options;
74
- const entryDirectory = path.dirname(entry.file);
75
- const moduleCollector = createModuleCollector({
76
- wrangler1xlegacyModuleReferences: {
77
- rootDirectory: entryDirectory,
78
- fileNames: new Set(
79
- fs
80
- .readdirSync(entryDirectory, { withFileTypes: true })
81
- .filter(
82
- (dirEntry) =>
83
- dirEntry.isFile() && dirEntry.name !== path.basename(entry.file)
84
- )
85
- .map((dirEnt) => dirEnt.name)
86
- ),
87
- },
88
- format: entry.format,
89
- rules,
90
- });
66
+ const {
67
+ serveAssetsFromWorker,
68
+ jsxFactory,
69
+ jsxFragment,
70
+ rules,
71
+ watch,
72
+ tsconfig,
73
+ minify,
74
+ nodeCompat,
75
+ checkFetch,
76
+ } = options;
77
+ const entryDirectory = path.dirname(entry.file);
78
+ const moduleCollector = createModuleCollector({
79
+ wrangler1xlegacyModuleReferences: {
80
+ rootDirectory: entryDirectory,
81
+ fileNames: new Set(
82
+ fs
83
+ .readdirSync(entryDirectory, { withFileTypes: true })
84
+ .filter(
85
+ (dirEntry) =>
86
+ dirEntry.isFile() && dirEntry.name !== path.basename(entry.file)
87
+ )
88
+ .map((dirEnt) => dirEnt.name)
89
+ ),
90
+ },
91
+ format: entry.format,
92
+ rules,
93
+ });
91
94
 
92
- const result = await esbuild.build({
93
- ...getEntryPoint(entry.file, serveAssetsFromWorker),
94
- bundle: true,
95
- absWorkingDir: entry.directory,
96
- outdir: destination,
97
- external: ["__STATIC_CONTENT_MANIFEST"],
98
- format: entry.format === "modules" ? "esm" : "iife",
99
- target: "es2020",
100
- sourcemap: true,
101
- minify,
102
- metafile: true,
103
- conditions: ["worker", "browser"],
104
- ...(process.env.NODE_ENV && {
105
- define: {
106
- "process.env.NODE_ENV": `"${process.env.NODE_ENV}"`,
107
- ...(nodeCompat ? { global: "globalThis" } : {}),
108
- },
109
- }),
110
- loader: {
111
- ".js": "jsx",
112
- ".mjs": "jsx",
113
- ".cjs": "jsx",
114
- },
115
- plugins: [
116
- moduleCollector.plugin,
117
- ...(nodeCompat
118
- ? [NodeGlobalsPolyfills({ buffer: true }), NodeModulesPolyfills()]
119
- : // we use checkForNodeBuiltinsPlugin to throw a nicer error
120
- // if we find node builtins when nodeCompat isn't turned on
121
- [checkForNodeBuiltinsPlugin]),
122
- ],
123
- ...(jsxFactory && { jsxFactory }),
124
- ...(jsxFragment && { jsxFragment }),
125
- ...(tsconfig && { tsconfig }),
126
- watch,
127
- });
95
+ const result = await esbuild.build({
96
+ ...getEntryPoint(entry.file, serveAssetsFromWorker),
97
+ bundle: true,
98
+ absWorkingDir: entry.directory,
99
+ outdir: destination,
100
+ inject: checkFetch
101
+ ? [path.resolve(__dirname, "../templates/checked-fetch.js")]
102
+ : [],
103
+ external: ["__STATIC_CONTENT_MANIFEST"],
104
+ format: entry.format === "modules" ? "esm" : "iife",
105
+ target: "es2020",
106
+ sourcemap: true,
107
+ minify,
108
+ metafile: true,
109
+ conditions: ["worker", "browser"],
110
+ ...(process.env.NODE_ENV && {
111
+ define: {
112
+ "process.env.NODE_ENV": `"${process.env.NODE_ENV}"`,
113
+ ...(nodeCompat ? { global: "globalThis" } : {}),
114
+ ...(checkFetch ? { fetch: "checkedFetch" } : {}),
115
+ ...options.define,
116
+ },
117
+ }),
118
+ loader: {
119
+ ".js": "jsx",
120
+ ".mjs": "jsx",
121
+ ".cjs": "jsx",
122
+ },
123
+ plugins: [
124
+ moduleCollector.plugin,
125
+ ...(nodeCompat
126
+ ? [NodeGlobalsPolyfills({ buffer: true }), NodeModulesPolyfills()]
127
+ : // we use checkForNodeBuiltinsPlugin to throw a nicer error
128
+ // if we find node builtins when nodeCompat isn't turned on
129
+ [checkForNodeBuiltinsPlugin]),
130
+ ],
131
+ ...(jsxFactory && { jsxFactory }),
132
+ ...(jsxFragment && { jsxFragment }),
133
+ ...(tsconfig && { tsconfig }),
134
+ watch,
135
+ });
128
136
 
129
- const entryPointOutputs = Object.entries(result.metafile.outputs).filter(
130
- ([_path, output]) => output.entryPoint !== undefined
131
- );
132
- assert(
133
- entryPointOutputs.length > 0,
134
- `Cannot find entry-point "${entry.file}" in generated bundle.` +
135
- listEntryPoints(entryPointOutputs)
136
- );
137
- assert(
138
- entryPointOutputs.length < 2,
139
- "More than one entry-point found for generated bundle." +
140
- listEntryPoints(entryPointOutputs)
141
- );
137
+ const entryPointOutputs = Object.entries(result.metafile.outputs).filter(
138
+ ([_path, output]) => output.entryPoint !== undefined
139
+ );
140
+ assert(
141
+ entryPointOutputs.length > 0,
142
+ `Cannot find entry-point "${entry.file}" in generated bundle.` +
143
+ listEntryPoints(entryPointOutputs)
144
+ );
145
+ assert(
146
+ entryPointOutputs.length < 2,
147
+ "More than one entry-point found for generated bundle." +
148
+ listEntryPoints(entryPointOutputs)
149
+ );
142
150
 
143
- const entryPointExports = entryPointOutputs[0][1].exports;
144
- const bundleType = entryPointExports.length > 0 ? "esm" : "commonjs";
151
+ const entryPointExports = entryPointOutputs[0][1].exports;
152
+ const bundleType = entryPointExports.length > 0 ? "esm" : "commonjs";
145
153
 
146
- return {
147
- modules: moduleCollector.modules,
148
- resolvedEntryPointPath: path.resolve(
149
- entry.directory,
150
- entryPointOutputs[0][0]
151
- ),
152
- bundleType,
153
- stop: result.stop,
154
- };
154
+ return {
155
+ modules: moduleCollector.modules,
156
+ resolvedEntryPointPath: path.resolve(
157
+ entry.directory,
158
+ entryPointOutputs[0][0]
159
+ ),
160
+ bundleType,
161
+ stop: result.stop,
162
+ };
155
163
  }
156
164
 
157
165
  type EntryPoint = { stdin: esbuild.StdinOptions } | { entryPoints: string[] };
@@ -164,41 +172,41 @@ type EntryPoint = { stdin: esbuild.StdinOptions } | { entryPoints: string[] };
164
172
  * or delegate to the actual worker.
165
173
  */
166
174
  function getEntryPoint(
167
- entryFile: string,
168
- serveAssetsFromWorker: boolean
175
+ entryFile: string,
176
+ serveAssetsFromWorker: boolean
169
177
  ): EntryPoint {
170
- if (serveAssetsFromWorker) {
171
- return {
172
- stdin: {
173
- contents: fs
174
- .readFileSync(
175
- path.join(__dirname, "../templates/static-asset-facade.js"),
176
- "utf8"
177
- )
178
- // on windows, escape backslashes in the path (`\`)
179
- .replace("__ENTRY_POINT__", entryFile.replaceAll("\\", "\\\\"))
180
- .replace(
181
- "__KV_ASSET_HANDLER__",
182
- path
183
- .join(__dirname, "../kv-asset-handler.js")
184
- .replaceAll("\\", "\\\\")
185
- ),
186
- sourcefile: "static-asset-facade.js",
187
- resolveDir: path.dirname(entryFile),
188
- },
189
- };
190
- } else {
191
- return { entryPoints: [entryFile] };
192
- }
178
+ if (serveAssetsFromWorker) {
179
+ return {
180
+ stdin: {
181
+ contents: fs
182
+ .readFileSync(
183
+ path.join(__dirname, "../templates/static-asset-facade.js"),
184
+ "utf8"
185
+ )
186
+ // on windows, escape backslashes in the path (`\`)
187
+ .replace("__ENTRY_POINT__", entryFile.replaceAll("\\", "\\\\"))
188
+ .replace(
189
+ "__KV_ASSET_HANDLER__",
190
+ path
191
+ .join(__dirname, "../kv-asset-handler.js")
192
+ .replaceAll("\\", "\\\\")
193
+ ),
194
+ sourcefile: "static-asset-facade.js",
195
+ resolveDir: path.dirname(entryFile),
196
+ },
197
+ };
198
+ } else {
199
+ return { entryPoints: [entryFile] };
200
+ }
193
201
  }
194
202
 
195
203
  /**
196
204
  * Generate a string that describes the entry-points that were identified by esbuild.
197
205
  */
198
206
  function listEntryPoints(
199
- outputs: [string, ValueOf<esbuild.Metafile["outputs"]>][]
207
+ outputs: [string, ValueOf<esbuild.Metafile["outputs"]>][]
200
208
  ): string {
201
- return outputs.map(([_input, output]) => output.entryPoint).join("\n");
209
+ return outputs.map(([_input, output]) => output.entryPoint).join("\n");
202
210
  }
203
211
 
204
212
  type ValueOf<T> = T[keyof T];
@@ -8,16 +8,16 @@ import type { RequestInit } from "undici";
8
8
  export { getCloudflareAPIBaseURL as getCloudflareApiBaseUrl } from "./internal";
9
9
 
10
10
  export interface FetchError {
11
- code: number;
12
- message: string;
13
- error_chain?: FetchError[];
11
+ code: number;
12
+ message: string;
13
+ error_chain?: FetchError[];
14
14
  }
15
15
  export interface FetchResult<ResponseType = unknown> {
16
- success: boolean;
17
- result: ResponseType;
18
- errors: FetchError[];
19
- messages: string[];
20
- result_info?: unknown;
16
+ success: boolean;
17
+ result: ResponseType;
18
+ errors: FetchError[];
19
+ messages: string[];
20
+ result_info?: unknown;
21
21
  }
22
22
 
23
23
  export { fetchKVGetValue } from "./internal";
@@ -26,22 +26,22 @@ export { fetchKVGetValue } from "./internal";
26
26
  * Make a fetch request, and extract the `result` from the JSON response.
27
27
  */
28
28
  export async function fetchResult<ResponseType>(
29
- resource: string,
30
- init: RequestInit = {},
31
- queryParams?: URLSearchParams,
32
- abortSignal?: AbortSignal
29
+ resource: string,
30
+ init: RequestInit = {},
31
+ queryParams?: URLSearchParams,
32
+ abortSignal?: AbortSignal
33
33
  ): Promise<ResponseType> {
34
- const json = await fetchInternal<FetchResult<ResponseType>>(
35
- resource,
36
- init,
37
- queryParams,
38
- abortSignal
39
- );
40
- if (json.success) {
41
- return json.result;
42
- } else {
43
- throwFetchError(resource, json);
44
- }
34
+ const json = await fetchInternal<FetchResult<ResponseType>>(
35
+ resource,
36
+ init,
37
+ queryParams,
38
+ abortSignal
39
+ );
40
+ if (json.success) {
41
+ return json.result;
42
+ } else {
43
+ throwFetchError(resource, json);
44
+ }
45
45
  }
46
46
 
47
47
  /**
@@ -50,72 +50,72 @@ export async function fetchResult<ResponseType>(
50
50
  * and repeating the request if the results are paginated.
51
51
  */
52
52
  export async function fetchListResult<ResponseType>(
53
- resource: string,
54
- init: RequestInit = {},
55
- queryParams?: URLSearchParams
53
+ resource: string,
54
+ init: RequestInit = {},
55
+ queryParams?: URLSearchParams
56
56
  ): Promise<ResponseType[]> {
57
- const results: ResponseType[] = [];
58
- let getMoreResults = true;
59
- let cursor: string | undefined;
60
- while (getMoreResults) {
61
- if (cursor) {
62
- queryParams = new URLSearchParams(queryParams);
63
- queryParams.set("cursor", cursor);
64
- }
65
- const json = await fetchInternal<FetchResult<ResponseType[]>>(
66
- resource,
67
- init,
68
- queryParams
69
- );
70
- if (json.success) {
71
- results.push(...json.result);
72
- if (hasCursor(json.result_info)) {
73
- cursor = json.result_info?.cursor;
74
- } else {
75
- getMoreResults = false;
76
- }
77
- } else {
78
- throwFetchError(resource, json);
79
- }
80
- }
81
- return results;
57
+ const results: ResponseType[] = [];
58
+ let getMoreResults = true;
59
+ let cursor: string | undefined;
60
+ while (getMoreResults) {
61
+ if (cursor) {
62
+ queryParams = new URLSearchParams(queryParams);
63
+ queryParams.set("cursor", cursor);
64
+ }
65
+ const json = await fetchInternal<FetchResult<ResponseType[]>>(
66
+ resource,
67
+ init,
68
+ queryParams
69
+ );
70
+ if (json.success) {
71
+ results.push(...json.result);
72
+ if (hasCursor(json.result_info)) {
73
+ cursor = json.result_info?.cursor;
74
+ } else {
75
+ getMoreResults = false;
76
+ }
77
+ } else {
78
+ throwFetchError(resource, json);
79
+ }
80
+ }
81
+ return results;
82
82
  }
83
83
 
84
84
  function throwFetchError(
85
- resource: string,
86
- response: FetchResult<unknown>
85
+ resource: string,
86
+ response: FetchResult<unknown>
87
87
  ): never {
88
- const error = new ParseError({
89
- text: `A request to the Cloudflare API (${resource}) failed.`,
90
- notes: response.errors.map((err) => ({
91
- text: renderError(err),
92
- })),
93
- });
94
- // add the first error code directly to this error
95
- // so consumers can use it for specific behaviour
96
- const code = response.errors[0]?.code;
97
- if (code) {
98
- //@ts-expect-error non-standard property on Error
99
- error.code = code;
100
- }
101
- throw error;
88
+ const error = new ParseError({
89
+ text: `A request to the Cloudflare API (${resource}) failed.`,
90
+ notes: response.errors.map((err) => ({
91
+ text: renderError(err),
92
+ })),
93
+ });
94
+ // add the first error code directly to this error
95
+ // so consumers can use it for specific behaviour
96
+ const code = response.errors[0]?.code;
97
+ if (code) {
98
+ //@ts-expect-error non-standard property on Error
99
+ error.code = code;
100
+ }
101
+ throw error;
102
102
  }
103
103
 
104
104
  function hasCursor(result_info: unknown): result_info is { cursor: string } {
105
- const cursor = (result_info as { cursor: string } | undefined)?.cursor;
106
- return cursor !== undefined && cursor !== null && cursor !== "";
105
+ const cursor = (result_info as { cursor: string } | undefined)?.cursor;
106
+ return cursor !== undefined && cursor !== null && cursor !== "";
107
107
  }
108
108
 
109
109
  function renderError(err: FetchError, level = 0): string {
110
- const chainedMessages =
111
- err.error_chain
112
- ?.map(
113
- (chainedError) =>
114
- `\n${" ".repeat(level)}- ${renderError(chainedError, level + 1)}`
115
- )
116
- .join("\n") ?? "";
117
- return (
118
- (err.code ? `${err.message} [code: ${err.code}]` : err.message) +
119
- chainedMessages
120
- );
110
+ const chainedMessages =
111
+ err.error_chain
112
+ ?.map(
113
+ (chainedError) =>
114
+ `\n${" ".repeat(level)}- ${renderError(chainedError, level + 1)}`
115
+ )
116
+ .join("\n") ?? "";
117
+ return (
118
+ (err.code ? `${err.message} [code: ${err.code}]` : err.message) +
119
+ chainedMessages
120
+ );
121
121
  }