wrangler 0.0.0-e64812e → 0.0.0-e8e684c7

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 (214) hide show
  1. package/README.md +27 -3
  2. package/bin/wrangler.js +150 -62
  3. package/kv-asset-handler.js +1 -0
  4. package/miniflare-dist/index.mjs +663 -7
  5. package/package.json +173 -152
  6. package/src/__tests__/config-cache-without-cache-dir.test.ts +38 -0
  7. package/src/__tests__/config-cache.test.ts +30 -24
  8. package/src/__tests__/configuration.test.ts +4015 -3363
  9. package/src/__tests__/dev.test.tsx +1290 -952
  10. package/src/__tests__/generate.test.ts +91 -0
  11. package/src/__tests__/guess-worker-format.test.ts +68 -68
  12. package/src/__tests__/helpers/cmd-shim.d.ts +6 -6
  13. package/src/__tests__/helpers/mock-account-id.ts +24 -24
  14. package/src/__tests__/helpers/mock-bin.ts +20 -20
  15. package/src/__tests__/helpers/mock-cfetch.ts +179 -94
  16. package/src/__tests__/helpers/mock-console.ts +49 -39
  17. package/src/__tests__/helpers/mock-dialogs.ts +94 -71
  18. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  19. package/src/__tests__/helpers/mock-http-server.ts +30 -30
  20. package/src/__tests__/helpers/mock-istty.ts +65 -18
  21. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  22. package/src/__tests__/helpers/mock-kv.ts +26 -26
  23. package/src/__tests__/helpers/mock-oauth-flow.ts +223 -228
  24. package/src/__tests__/helpers/mock-process.ts +39 -0
  25. package/src/__tests__/helpers/mock-stdin.ts +82 -77
  26. package/src/__tests__/helpers/mock-web-socket.ts +21 -21
  27. package/src/__tests__/helpers/run-in-tmp.ts +27 -28
  28. package/src/__tests__/helpers/run-wrangler.ts +8 -8
  29. package/src/__tests__/helpers/write-worker-source.ts +16 -16
  30. package/src/__tests__/helpers/write-wrangler-toml.ts +9 -9
  31. package/src/__tests__/https-options.test.ts +142 -109
  32. package/src/__tests__/index.test.ts +222 -233
  33. package/src/__tests__/init.test.ts +2139 -1603
  34. package/src/__tests__/jest.setup.ts +114 -34
  35. package/src/__tests__/kv.test.ts +1222 -1032
  36. package/src/__tests__/logger.test.ts +100 -74
  37. package/src/__tests__/metrics.test.ts +450 -0
  38. package/src/__tests__/package-manager.test.ts +303 -303
  39. package/src/__tests__/pages.test.ts +1173 -652
  40. package/src/__tests__/parse.test.ts +252 -252
  41. package/src/__tests__/publish.test.ts +6788 -5301
  42. package/src/__tests__/pubsub.test.ts +367 -0
  43. package/src/__tests__/r2.test.ts +328 -225
  44. package/src/__tests__/route.test.ts +18 -18
  45. package/src/__tests__/secret.test.ts +470 -459
  46. package/src/__tests__/tail.test.ts +676 -564
  47. package/src/__tests__/test-old-node-version.js +31 -0
  48. package/src/__tests__/user.test.ts +136 -112
  49. package/src/__tests__/validate-dev-props.test.ts +56 -0
  50. package/src/__tests__/version.test.ts +35 -0
  51. package/src/__tests__/whoami.test.tsx +267 -83
  52. package/src/__tests__/worker-namespace.test.ts +329 -0
  53. package/src/abort.d.ts +1 -1
  54. package/src/api/dev.ts +93 -0
  55. package/src/api/index.ts +1 -0
  56. package/src/bundle-reporter.tsx +29 -0
  57. package/src/bundle.ts +430 -157
  58. package/src/cfetch/index.ts +80 -80
  59. package/src/cfetch/internal.ts +244 -91
  60. package/src/cli.ts +21 -7
  61. package/src/config/config.ts +224 -195
  62. package/src/config/diagnostics.ts +61 -61
  63. package/src/config/environment.ts +422 -357
  64. package/src/config/index.ts +219 -193
  65. package/src/config/validation-helpers.ts +379 -357
  66. package/src/config/validation.ts +1690 -1367
  67. package/src/config-cache.ts +81 -41
  68. package/src/create-worker-preview.ts +208 -136
  69. package/src/create-worker-upload-form.ts +275 -238
  70. package/src/dev/dev-vars.ts +13 -13
  71. package/src/dev/dev.tsx +477 -351
  72. package/src/dev/local.tsx +426 -295
  73. package/src/dev/remote.tsx +406 -211
  74. package/src/dev/use-esbuild.ts +154 -94
  75. package/src/dev/validate-dev-props.ts +31 -0
  76. package/src/dev-registry.tsx +160 -0
  77. package/src/dev.tsx +696 -0
  78. package/src/dialogs.tsx +97 -97
  79. package/src/dispatch-namespace.ts +206 -0
  80. package/src/durable.ts +87 -87
  81. package/src/entry.ts +234 -228
  82. package/src/environment-variables.ts +23 -23
  83. package/src/errors.ts +6 -6
  84. package/src/faye-websocket.d.ts +6 -0
  85. package/src/generate.ts +131 -0
  86. package/src/git-client.ts +42 -0
  87. package/src/global-wrangler-config-path.ts +26 -0
  88. package/src/https-options.ts +84 -80
  89. package/src/index.tsx +2164 -2768
  90. package/src/init.ts +622 -0
  91. package/src/inspect.ts +678 -593
  92. package/src/intl-polyfill.d.ts +123 -123
  93. package/src/is-ci.ts +14 -0
  94. package/src/is-interactive.ts +12 -0
  95. package/src/kv.ts +299 -277
  96. package/src/logger.ts +46 -39
  97. package/src/metrics/index.ts +5 -0
  98. package/src/metrics/metrics-config.ts +239 -0
  99. package/src/metrics/metrics-dispatcher.ts +96 -0
  100. package/src/metrics/metrics-usage-headers.ts +24 -0
  101. package/src/metrics/send-event.ts +92 -0
  102. package/src/miniflare-cli/assets.ts +554 -0
  103. package/src/miniflare-cli/enum-keys.ts +8 -8
  104. package/src/miniflare-cli/index.ts +198 -32
  105. package/src/miniflare-cli/request-context.ts +18 -18
  106. package/src/module-collection.ts +212 -212
  107. package/src/open-in-browser.ts +4 -6
  108. package/src/package-manager.ts +173 -128
  109. package/src/pages/build.tsx +238 -0
  110. package/src/pages/constants.ts +12 -0
  111. package/src/pages/deployments.tsx +106 -0
  112. package/src/pages/dev.tsx +528 -0
  113. package/src/pages/errors.ts +22 -0
  114. package/src/pages/functions/buildPlugin.ts +109 -0
  115. package/src/pages/functions/buildWorker.ts +155 -0
  116. package/{pages → src/pages}/functions/filepath-routing.test.ts +113 -113
  117. package/src/pages/functions/filepath-routing.ts +189 -0
  118. package/src/pages/functions/identifiers.ts +78 -0
  119. package/src/pages/functions/routes-consolidation.test.ts +250 -0
  120. package/src/pages/functions/routes-consolidation.ts +73 -0
  121. package/src/pages/functions/routes-transformation.test.ts +271 -0
  122. package/src/pages/functions/routes-transformation.ts +122 -0
  123. package/src/pages/functions/routes.ts +151 -0
  124. package/src/pages/functions.tsx +96 -0
  125. package/src/pages/index.tsx +94 -0
  126. package/src/pages/projects.tsx +169 -0
  127. package/src/pages/publish.tsx +391 -0
  128. package/src/pages/types.ts +49 -0
  129. package/src/pages/upload.tsx +413 -0
  130. package/src/pages/utils.ts +12 -0
  131. package/src/parse.ts +209 -125
  132. package/src/paths.ts +6 -6
  133. package/src/preview.ts +31 -0
  134. package/src/proxy.ts +410 -389
  135. package/src/publish.ts +773 -534
  136. package/src/pubsub/index.ts +286 -0
  137. package/src/pubsub/pubsub-commands.tsx +623 -0
  138. package/src/r2.ts +100 -19
  139. package/src/selfsigned.d.ts +23 -23
  140. package/src/sites.tsx +278 -201
  141. package/src/tail/filters.ts +111 -109
  142. package/src/tail/index.ts +230 -217
  143. package/src/tail/printing.ts +86 -46
  144. package/src/update-check.ts +11 -11
  145. package/src/user/choose-account.tsx +69 -0
  146. package/src/user/env-vars.ts +46 -0
  147. package/src/user/generate-auth-url.ts +33 -0
  148. package/src/user/generate-random-state.ts +16 -0
  149. package/src/user/index.ts +3 -0
  150. package/src/user/user.tsx +1191 -0
  151. package/src/whoami.tsx +141 -42
  152. package/src/worker.ts +123 -99
  153. package/src/zones.ts +167 -0
  154. package/templates/checked-fetch.js +17 -0
  155. package/templates/first-party-worker-module-facade.ts +18 -0
  156. package/templates/format-dev-errors.ts +32 -0
  157. package/templates/new-worker-scheduled.js +3 -3
  158. package/templates/new-worker-scheduled.ts +15 -15
  159. package/templates/new-worker.js +3 -3
  160. package/templates/new-worker.ts +15 -15
  161. package/templates/no-op-worker.js +10 -0
  162. package/templates/pages-shim.ts +9 -0
  163. package/templates/pages-template-plugin.ts +167 -0
  164. package/templates/pages-template-worker.ts +172 -0
  165. package/templates/serve-static-assets.ts +63 -0
  166. package/templates/service-bindings-module-facade.js +54 -0
  167. package/templates/service-bindings-sw-facade.js +42 -0
  168. package/templates/tsconfig.json +95 -95
  169. package/wrangler-dist/cli.d.ts +338 -0
  170. package/wrangler-dist/cli.js +95449 -67524
  171. package/pages/functions/buildPlugin.ts +0 -105
  172. package/pages/functions/buildWorker.ts +0 -151
  173. package/pages/functions/filepath-routing.ts +0 -189
  174. package/pages/functions/identifiers.ts +0 -78
  175. package/pages/functions/routes.ts +0 -156
  176. package/pages/functions/template-plugin.ts +0 -147
  177. package/pages/functions/template-worker.ts +0 -143
  178. package/src/__tests__/helpers/faye-websocket.d.ts +0 -6
  179. package/src/pages.tsx +0 -2038
  180. package/src/user.tsx +0 -1203
  181. package/templates/static-asset-facade.js +0 -47
  182. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  183. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  184. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  185. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  186. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  187. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  188. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  189. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  190. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  191. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  192. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  193. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  194. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  195. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  196. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  197. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  198. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  199. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  200. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  201. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  202. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  203. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  204. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  205. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  206. package/vendor/wrangler-mime/LICENSE +0 -21
  207. package/vendor/wrangler-mime/Mime.js +0 -97
  208. package/vendor/wrangler-mime/README.md +0 -187
  209. package/vendor/wrangler-mime/cli.js +0 -46
  210. package/vendor/wrangler-mime/index.js +0 -4
  211. package/vendor/wrangler-mime/lite.js +0 -4
  212. package/vendor/wrangler-mime/package.json +0 -52
  213. package/vendor/wrangler-mime/types/other.js +0 -1
  214. package/vendor/wrangler-mime/types/standard.js +0 -1
package/src/kv.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { URLSearchParams } from "node:url";
2
+ import { FormData } from "undici";
2
3
  import { fetchListResult, fetchResult, fetchKVGetValue } from "./cfetch";
3
4
  import { logger } from "./logger";
4
5
  import type { Config } from "./config";
@@ -10,9 +11,9 @@ const API_MAX = 10000;
10
11
  const BATCH_KEY_MAX = API_MAX / 2;
11
12
 
12
13
  type KvArgs = {
13
- binding?: string;
14
- "namespace-id"?: string;
15
- preview?: boolean;
14
+ binding?: string;
15
+ "namespace-id"?: string;
16
+ preview?: boolean;
16
17
  };
17
18
 
18
19
  /**
@@ -21,388 +22,409 @@ type KvArgs = {
21
22
  * @returns the generated id of the created namespace.
22
23
  */
23
24
  export async function createKVNamespace(
24
- accountId: string,
25
- title: string
25
+ accountId: string,
26
+ title: string
26
27
  ): Promise<string> {
27
- const response = await fetchResult<{ id: string }>(
28
- `/accounts/${accountId}/storage/kv/namespaces`,
29
- {
30
- method: "POST",
31
- headers: {
32
- "Content-Type": "application/json",
33
- },
34
- body: JSON.stringify({
35
- title,
36
- }),
37
- }
38
- );
39
-
40
- return response.id;
28
+ const response = await fetchResult<{ id: string }>(
29
+ `/accounts/${accountId}/storage/kv/namespaces`,
30
+ {
31
+ method: "POST",
32
+ headers: {
33
+ "Content-Type": "application/json",
34
+ },
35
+ body: JSON.stringify({
36
+ title,
37
+ }),
38
+ }
39
+ );
40
+
41
+ return response.id;
41
42
  }
42
43
 
43
44
  /**
44
45
  * The information about a namespace that is returned from `listNamespaces()`.
45
46
  */
46
47
  export interface KVNamespaceInfo {
47
- id: string;
48
- title: string;
49
- supports_url_encoding?: boolean;
48
+ id: string;
49
+ title: string;
50
+ supports_url_encoding?: boolean;
50
51
  }
51
52
 
52
53
  /**
53
54
  * Fetch a list of all the namespaces under the given `accountId`.
54
55
  */
55
56
  export async function listKVNamespaces(
56
- accountId: string
57
+ accountId: string
57
58
  ): Promise<KVNamespaceInfo[]> {
58
- const pageSize = 100;
59
- let page = 1;
60
- const results: KVNamespaceInfo[] = [];
61
- while (results.length % pageSize === 0) {
62
- const json = await fetchResult<KVNamespaceInfo[]>(
63
- `/accounts/${accountId}/storage/kv/namespaces`,
64
- {},
65
- new URLSearchParams({
66
- per_page: pageSize.toString(),
67
- order: "title",
68
- direction: "asc",
69
- page: page.toString(),
70
- })
71
- );
72
- page++;
73
- results.push(...json);
74
- if (json.length < pageSize) {
75
- break;
76
- }
77
- }
78
- return results;
59
+ const pageSize = 100;
60
+ let page = 1;
61
+ const results: KVNamespaceInfo[] = [];
62
+ while (results.length % pageSize === 0) {
63
+ const json = await fetchResult<KVNamespaceInfo[]>(
64
+ `/accounts/${accountId}/storage/kv/namespaces`,
65
+ {},
66
+ new URLSearchParams({
67
+ per_page: pageSize.toString(),
68
+ order: "title",
69
+ direction: "asc",
70
+ page: page.toString(),
71
+ })
72
+ );
73
+ page++;
74
+ results.push(...json);
75
+ if (json.length < pageSize) {
76
+ break;
77
+ }
78
+ }
79
+ return results;
79
80
  }
80
81
 
81
82
  export interface NamespaceKeyInfo {
82
- name: string;
83
- expiration?: number;
84
- metadata?: { [key: string]: unknown };
83
+ name: string;
84
+ expiration?: number;
85
+ metadata?: { [key: string]: unknown };
85
86
  }
86
87
 
87
88
  export async function listKVNamespaceKeys(
88
- accountId: string,
89
- namespaceId: string,
90
- prefix = ""
89
+ accountId: string,
90
+ namespaceId: string,
91
+ prefix = ""
91
92
  ) {
92
- return await fetchListResult<NamespaceKeyInfo>(
93
- `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/keys`,
94
- {},
95
- new URLSearchParams({ prefix })
96
- );
93
+ return await fetchListResult<NamespaceKeyInfo>(
94
+ `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/keys`,
95
+ {},
96
+ new URLSearchParams({ prefix })
97
+ );
97
98
  }
98
99
 
99
100
  export async function deleteKVNamespace(
100
- accountId: string,
101
- namespaceId: string
101
+ accountId: string,
102
+ namespaceId: string
102
103
  ) {
103
- return await fetchResult<{ id: string }>(
104
- `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}`,
105
- { method: "DELETE" }
106
- );
104
+ return await fetchResult<{ id: string }>(
105
+ `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}`,
106
+ { method: "DELETE" }
107
+ );
107
108
  }
108
109
 
109
110
  /**
110
111
  * Information about a key-value pair, including its "metadata" fields.
111
112
  */
112
113
  export interface KeyValue {
113
- key: string;
114
- value: string;
115
- expiration?: number;
116
- expiration_ttl?: number;
117
- metadata?: object;
118
- base64?: boolean;
114
+ key: string;
115
+ value: string | Buffer;
116
+ expiration?: number;
117
+ expiration_ttl?: number;
118
+ metadata?: object;
119
+ base64?: boolean;
119
120
  }
120
121
 
121
122
  const KeyValueKeys = new Set([
122
- "key",
123
- "value",
124
- "expiration",
125
- "expiration_ttl",
126
- "metadata",
127
- "base64",
123
+ "key",
124
+ "value",
125
+ "expiration",
126
+ "expiration_ttl",
127
+ "metadata",
128
+ "base64",
128
129
  ]);
129
130
 
130
131
  /**
131
132
  * The object has the specified property.
132
133
  */
133
134
  function hasProperty<T extends object>(
134
- obj: object,
135
- property: keyof T
135
+ obj: object,
136
+ property: keyof T
136
137
  ): obj is T {
137
- return property in obj;
138
+ return property in obj;
138
139
  }
139
140
 
140
141
  /**
141
142
  * The object has a required property of the specified type.
142
143
  */
143
144
  function hasTypedProperty<T extends object>(
144
- obj: object,
145
- property: keyof T,
146
- type: string
145
+ obj: object,
146
+ property: keyof T,
147
+ type: string
147
148
  ): obj is T {
148
- return hasProperty(obj, property) && typeof obj[property] === type;
149
+ return hasProperty(obj, property) && typeof obj[property] === type;
149
150
  }
150
151
 
151
152
  /**
152
153
  * The object an optional property, of the specified type.
153
154
  */
154
155
  function hasOptionalTypedProperty<T extends object>(
155
- obj: object,
156
- property: keyof T,
157
- type: string
156
+ obj: object,
157
+ property: keyof T,
158
+ type: string
158
159
  ): obj is Omit<T, typeof property> | T {
159
- return !hasProperty(obj, property) || typeof obj[property] === type;
160
+ return !hasProperty(obj, property) || typeof obj[property] === type;
160
161
  }
161
162
 
162
163
  /**
163
164
  * Is the given object a valid `KeyValue` type?
164
165
  */
165
166
  export function isKVKeyValue(keyValue: unknown): keyValue is KeyValue {
166
- if (
167
- keyValue === null ||
168
- typeof keyValue !== "object" ||
169
- !hasTypedProperty(keyValue, "key", "string") ||
170
- !hasTypedProperty(keyValue, "value", "string") ||
171
- !hasOptionalTypedProperty(keyValue, "expiration", "number") ||
172
- !hasOptionalTypedProperty(keyValue, "expiration_ttl", "number") ||
173
- !hasOptionalTypedProperty(keyValue, "base64", "boolean") ||
174
- !hasOptionalTypedProperty(keyValue, "metadata", "object")
175
- ) {
176
- return false;
177
- }
178
- return true;
167
+ if (
168
+ keyValue === null ||
169
+ typeof keyValue !== "object" ||
170
+ !hasTypedProperty(keyValue, "key", "string") ||
171
+ !hasTypedProperty(keyValue, "value", "string") ||
172
+ !hasOptionalTypedProperty(keyValue, "expiration", "number") ||
173
+ !hasOptionalTypedProperty(keyValue, "expiration_ttl", "number") ||
174
+ !hasOptionalTypedProperty(keyValue, "base64", "boolean") ||
175
+ !hasOptionalTypedProperty(keyValue, "metadata", "object")
176
+ ) {
177
+ return false;
178
+ }
179
+ return true;
179
180
  }
180
181
 
181
182
  /**
182
183
  * Get all the properties on the `keyValue` that are not expected.
183
184
  */
184
185
  export function unexpectedKVKeyValueProps(keyValue: KeyValue): string[] {
185
- const props = Object.keys(keyValue);
186
- return props.filter((prop) => !KeyValueKeys.has(prop));
186
+ const props = Object.keys(keyValue);
187
+ return props.filter((prop) => !KeyValueKeys.has(prop));
188
+ }
189
+
190
+ /**
191
+ * Turn object with fields into FormData
192
+ */
193
+ function asFormData(fields: Record<string, unknown>): FormData {
194
+ const formData = new FormData();
195
+
196
+ for (const [name, value] of Object.entries(fields)) {
197
+ formData.append(name, value);
198
+ }
199
+
200
+ return formData;
187
201
  }
188
202
 
189
203
  export async function putKVKeyValue(
190
- accountId: string,
191
- namespaceId: string,
192
- keyValue: KeyValue
204
+ accountId: string,
205
+ namespaceId: string,
206
+ keyValue: KeyValue
193
207
  ) {
194
- let searchParams: URLSearchParams | undefined;
195
- if (keyValue.expiration || keyValue.expiration_ttl) {
196
- searchParams = new URLSearchParams();
197
- if (keyValue.expiration) {
198
- searchParams.set("expiration", `${keyValue.expiration}`);
199
- }
200
- if (keyValue.expiration_ttl) {
201
- searchParams.set("expiration_ttl", `${keyValue.expiration_ttl}`);
202
- }
203
- }
204
- return await fetchResult(
205
- `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/values/${encodeURIComponent(
206
- keyValue.key
207
- )}`,
208
- { method: "PUT", body: keyValue.value },
209
- searchParams
210
- );
208
+ let searchParams: URLSearchParams | undefined;
209
+ if (keyValue.expiration || keyValue.expiration_ttl) {
210
+ searchParams = new URLSearchParams();
211
+ if (keyValue.expiration) {
212
+ searchParams.set("expiration", `${keyValue.expiration}`);
213
+ }
214
+ if (keyValue.expiration_ttl) {
215
+ searchParams.set("expiration_ttl", `${keyValue.expiration_ttl}`);
216
+ }
217
+ }
218
+ return await fetchResult(
219
+ `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/values/${encodeURIComponent(
220
+ keyValue.key
221
+ )}`,
222
+ {
223
+ method: "PUT",
224
+ body: keyValue.metadata
225
+ ? asFormData({
226
+ value: keyValue.value,
227
+ metadata: JSON.stringify(keyValue.metadata),
228
+ })
229
+ : keyValue.value,
230
+ },
231
+ searchParams
232
+ );
211
233
  }
212
234
 
213
235
  export async function getKVKeyValue(
214
- accountId: string,
215
- namespaceId: string,
216
- key: string
217
- ): Promise<string> {
218
- return await fetchKVGetValue(accountId, namespaceId, encodeURIComponent(key));
236
+ accountId: string,
237
+ namespaceId: string,
238
+ key: string
239
+ ): Promise<ArrayBuffer> {
240
+ return await fetchKVGetValue(accountId, namespaceId, encodeURIComponent(key));
219
241
  }
220
242
 
221
243
  export async function deleteKVKeyValue(
222
- accountId: string,
223
- namespaceId: string,
224
- key: string
244
+ accountId: string,
245
+ namespaceId: string,
246
+ key: string
225
247
  ) {
226
- return await fetchResult(
227
- `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/values/${encodeURIComponent(
228
- key
229
- )}`,
230
- { method: "DELETE" }
231
- );
248
+ return await fetchResult(
249
+ `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/values/${encodeURIComponent(
250
+ key
251
+ )}`,
252
+ { method: "DELETE" }
253
+ );
232
254
  }
233
255
 
234
256
  /**
235
257
  * Formatter for converting e.g. 5328 --> 5,328
236
258
  */
237
259
  const formatNumber = new Intl.NumberFormat("en-US", {
238
- notation: "standard",
260
+ notation: "standard",
239
261
  }).format;
240
262
 
241
263
  /**
242
264
  * Helper function for bulk requests, logs ongoing output to console.
243
265
  */
244
266
  function logBulkProgress(
245
- operation: "put" | "delete",
246
- index: number,
247
- total: number
267
+ operation: "put" | "delete",
268
+ index: number,
269
+ total: number
248
270
  ) {
249
- logger.log(
250
- `${operation === "put" ? "Uploaded" : "Deleted"} ${Math.floor(
251
- (100 * index) / total
252
- )}% (${formatNumber(index)} out of ${formatNumber(total)})`
253
- );
271
+ logger.log(
272
+ `${operation === "put" ? "Uploaded" : "Deleted"} ${Math.floor(
273
+ (100 * index) / total
274
+ )}% (${formatNumber(index)} out of ${formatNumber(total)})`
275
+ );
254
276
  }
255
277
 
256
278
  export async function putKVBulkKeyValue(
257
- accountId: string,
258
- namespaceId: string,
259
- keyValues: KeyValue[],
260
- quiet = false
279
+ accountId: string,
280
+ namespaceId: string,
281
+ keyValues: KeyValue[],
282
+ quiet = false
261
283
  ) {
262
- for (let index = 0; index < keyValues.length; index += BATCH_KEY_MAX) {
263
- if (!quiet && keyValues.length > BATCH_KEY_MAX) {
264
- logBulkProgress("put", index, keyValues.length);
265
- }
266
-
267
- await fetchResult(
268
- `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/bulk`,
269
- {
270
- method: "PUT",
271
- body: JSON.stringify(keyValues.slice(index, index + BATCH_KEY_MAX)),
272
- headers: { "Content-Type": "application/json" },
273
- }
274
- );
275
- }
276
-
277
- if (!quiet && keyValues.length > BATCH_KEY_MAX) {
278
- logBulkProgress("put", keyValues.length, keyValues.length);
279
- }
284
+ for (let index = 0; index < keyValues.length; index += BATCH_KEY_MAX) {
285
+ if (!quiet && keyValues.length > BATCH_KEY_MAX) {
286
+ logBulkProgress("put", index, keyValues.length);
287
+ }
288
+
289
+ await fetchResult(
290
+ `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/bulk`,
291
+ {
292
+ method: "PUT",
293
+ body: JSON.stringify(keyValues.slice(index, index + BATCH_KEY_MAX)),
294
+ headers: { "Content-Type": "application/json" },
295
+ }
296
+ );
297
+ }
298
+
299
+ if (!quiet && keyValues.length > BATCH_KEY_MAX) {
300
+ logBulkProgress("put", keyValues.length, keyValues.length);
301
+ }
280
302
  }
281
303
 
282
304
  export async function deleteKVBulkKeyValue(
283
- accountId: string,
284
- namespaceId: string,
285
- keys: string[],
286
- quiet = false
305
+ accountId: string,
306
+ namespaceId: string,
307
+ keys: string[],
308
+ quiet = false
287
309
  ) {
288
- for (let index = 0; index < keys.length; index += BATCH_KEY_MAX) {
289
- if (!quiet && keys.length > BATCH_KEY_MAX) {
290
- logBulkProgress("delete", index, keys.length);
291
- }
292
-
293
- await fetchResult(
294
- `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/bulk`,
295
- {
296
- method: "DELETE",
297
- body: JSON.stringify(keys.slice(index, index + BATCH_KEY_MAX)),
298
- headers: { "Content-Type": "application/json" },
299
- }
300
- );
301
- }
302
- if (!quiet && keys.length > BATCH_KEY_MAX) {
303
- logBulkProgress("delete", keys.length, keys.length);
304
- }
310
+ for (let index = 0; index < keys.length; index += BATCH_KEY_MAX) {
311
+ if (!quiet && keys.length > BATCH_KEY_MAX) {
312
+ logBulkProgress("delete", index, keys.length);
313
+ }
314
+
315
+ await fetchResult(
316
+ `/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/bulk`,
317
+ {
318
+ method: "DELETE",
319
+ body: JSON.stringify(keys.slice(index, index + BATCH_KEY_MAX)),
320
+ headers: { "Content-Type": "application/json" },
321
+ }
322
+ );
323
+ }
324
+ if (!quiet && keys.length > BATCH_KEY_MAX) {
325
+ logBulkProgress("delete", keys.length, keys.length);
326
+ }
305
327
  }
306
328
 
307
329
  export function getKVNamespaceId(
308
- { preview, binding, "namespace-id": namespaceId }: KvArgs,
309
- config: Config
330
+ { preview, binding, "namespace-id": namespaceId }: KvArgs,
331
+ config: Config
310
332
  ): string {
311
- // nice
312
- if (namespaceId) {
313
- return namespaceId;
314
- }
315
-
316
- // begin pre-flight checks
317
-
318
- // `--binding` is only valid if there's a wrangler configuration.
319
- if (binding && !config) {
320
- throw new Error("--binding specified, but no config file was found.");
321
- }
322
-
323
- // there's no config. abort here
324
- if (!config) {
325
- throw new Error(
326
- "Failed to find a config file.\n" +
327
- "Either use --namespace-id to upload directly or create a configuration file with a binding."
328
- );
329
- }
330
-
331
- // there's no KV namespaces
332
- if (!config.kv_namespaces || config.kv_namespaces.length === 0) {
333
- throw new Error(
334
- "No KV Namespaces configured! Either use --namespace-id to upload directly or add a KV namespace to your wrangler config file."
335
- );
336
- }
337
-
338
- const namespace = config.kv_namespaces.find((ns) => ns.binding === binding);
339
-
340
- // we couldn't find a namespace with that binding
341
- if (!namespace) {
342
- throw new Error(
343
- `A namespace with binding name "${binding}" was not found in the configured "kv_namespaces".`
344
- );
345
- }
346
-
347
- // end pre-flight checks
348
-
349
- // we're in preview mode, `--preview true` or `--preview` was passed
350
- if (preview && namespace.preview_id) {
351
- namespaceId = namespace.preview_id;
352
- // We don't want to execute code below if preview is set to true, so we just return. Otherwise we will get errors!
353
- return namespaceId;
354
- } else if (preview) {
355
- throw new Error(
356
- `No preview ID found for ${binding}. Add one to your wrangler config file to use a separate namespace for previewing your worker.`
357
- );
358
- }
359
-
360
- // either `--preview false`, or preview wasn't passed
361
- // TODO: should we care? or should we just treat false and undefined the same
362
- const previewIsDefined = typeof preview !== "undefined";
363
-
364
- // --preview false was passed
365
- if (previewIsDefined && namespace.id) {
366
- namespaceId = namespace.id;
367
- // We don't want to execute code below if preview is set to true, so we just return. Otherwise we can get error!
368
- return namespaceId;
369
- } else if (previewIsDefined) {
370
- throw new Error(
371
- `No namespace ID found for ${binding}. Add one to your wrangler config file to use a separate namespace for previewing your worker.`
372
- );
373
- }
374
-
375
- // `--preview` wasn't passed
376
- const bindingHasOnlyOneId =
377
- (namespace.id && !namespace.preview_id) ||
378
- (!namespace.id && namespace.preview_id);
379
- if (bindingHasOnlyOneId) {
380
- namespaceId = namespace.id || namespace.preview_id;
381
- } else {
382
- throw new Error(
383
- `${binding} has both a namespace ID and a preview ID. Specify "--preview" or "--preview false" to avoid writing data to the wrong namespace.`
384
- );
385
- }
386
-
387
- // shouldn't happen. we should be able to prove this with strong typing.
388
- // TODO: when we add strongly typed commands, rewrite these checks so they're exhaustive
389
- if (!namespaceId) {
390
- throw Error(
391
- "Something went wrong trying to determine which namespace to upload to.\n" +
392
- "Please create a github issue with the command you just ran along with your wrangler configuration."
393
- );
394
- }
395
-
396
- return namespaceId;
333
+ // nice
334
+ if (namespaceId) {
335
+ return namespaceId;
336
+ }
337
+
338
+ // begin pre-flight checks
339
+
340
+ // `--binding` is only valid if there's a wrangler configuration.
341
+ if (binding && !config) {
342
+ throw new Error("--binding specified, but no config file was found.");
343
+ }
344
+
345
+ // there's no config. abort here
346
+ if (!config) {
347
+ throw new Error(
348
+ "Failed to find a config file.\n" +
349
+ "Either use --namespace-id to upload directly or create a configuration file with a binding."
350
+ );
351
+ }
352
+
353
+ // there's no KV namespaces
354
+ if (!config.kv_namespaces || config.kv_namespaces.length === 0) {
355
+ throw new Error(
356
+ "No KV Namespaces configured! Either use --namespace-id to upload directly or add a KV namespace to your wrangler config file."
357
+ );
358
+ }
359
+
360
+ const namespace = config.kv_namespaces.find((ns) => ns.binding === binding);
361
+
362
+ // we couldn't find a namespace with that binding
363
+ if (!namespace) {
364
+ throw new Error(
365
+ `A namespace with binding name "${binding}" was not found in the configured "kv_namespaces".`
366
+ );
367
+ }
368
+
369
+ // end pre-flight checks
370
+
371
+ // we're in preview mode, `--preview true` or `--preview` was passed
372
+ if (preview && namespace.preview_id) {
373
+ namespaceId = namespace.preview_id;
374
+ // We don't want to execute code below if preview is set to true, so we just return. Otherwise we will get errors!
375
+ return namespaceId;
376
+ } else if (preview) {
377
+ throw new Error(
378
+ `No preview ID found for ${binding}. Add one to your wrangler config file to use a separate namespace for previewing your worker.`
379
+ );
380
+ }
381
+
382
+ // either `--preview false`, or preview wasn't passed
383
+ // TODO: should we care? or should we just treat false and undefined the same
384
+ const previewIsDefined = typeof preview !== "undefined";
385
+
386
+ // --preview false was passed
387
+ if (previewIsDefined && namespace.id) {
388
+ namespaceId = namespace.id;
389
+ // We don't want to execute code below if preview is set to true, so we just return. Otherwise we can get error!
390
+ return namespaceId;
391
+ } else if (previewIsDefined) {
392
+ throw new Error(
393
+ `No namespace ID found for ${binding}. Add one to your wrangler config file to use a separate namespace for previewing your worker.`
394
+ );
395
+ }
396
+
397
+ // `--preview` wasn't passed
398
+ const bindingHasOnlyOneId =
399
+ (namespace.id && !namespace.preview_id) ||
400
+ (!namespace.id && namespace.preview_id);
401
+ if (bindingHasOnlyOneId) {
402
+ namespaceId = namespace.id || namespace.preview_id;
403
+ } else {
404
+ throw new Error(
405
+ `${binding} has both a namespace ID and a preview ID. Specify "--preview" or "--preview false" to avoid writing data to the wrong namespace.`
406
+ );
407
+ }
408
+
409
+ // shouldn't happen. we should be able to prove this with strong typing.
410
+ // TODO: when we add strongly typed commands, rewrite these checks so they're exhaustive
411
+ if (!namespaceId) {
412
+ throw Error(
413
+ "Something went wrong trying to determine which namespace to upload to.\n" +
414
+ "Please create a github issue with the command you just ran along with your wrangler configuration."
415
+ );
416
+ }
417
+
418
+ return namespaceId;
397
419
  }
398
420
 
399
421
  /**
400
422
  * KV namespace binding names must be valid JS identifiers.
401
423
  */
402
424
  export function isValidKVNamespaceBinding(
403
- binding: string | undefined
425
+ binding: string | undefined
404
426
  ): binding is string {
405
- return (
406
- typeof binding === "string" && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(binding)
407
- );
427
+ return (
428
+ typeof binding === "string" && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(binding)
429
+ );
408
430
  }