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.
- package/bin/wrangler.js +2 -2
- package/package.json +5 -3
- package/pages/functions/buildPlugin.ts +13 -0
- package/pages/functions/buildWorker.ts +13 -0
- package/src/__tests__/configuration.test.ts +217 -29
- package/src/__tests__/dev.test.tsx +71 -9
- package/src/__tests__/index.test.ts +30 -16
- package/src/__tests__/init.test.ts +61 -20
- package/src/__tests__/kv.test.ts +109 -103
- package/src/__tests__/pages.test.ts +363 -33
- package/src/__tests__/parse.test.ts +5 -1
- package/src/__tests__/publish.test.ts +486 -72
- package/src/__tests__/r2.test.ts +47 -24
- package/src/__tests__/secret.test.ts +35 -0
- package/src/abort.d.ts +3 -0
- package/src/bundle.ts +32 -1
- package/src/cfetch/index.ts +4 -2
- package/src/cfetch/internal.ts +11 -9
- package/src/config/environment.ts +40 -14
- package/src/config/index.ts +162 -0
- package/src/config/validation.ts +126 -37
- package/src/create-worker-preview.ts +17 -7
- package/src/create-worker-upload-form.ts +22 -8
- package/src/dev/dev.tsx +5 -4
- package/src/dev/local.tsx +6 -0
- package/src/dev/remote.tsx +15 -1
- package/src/durable.ts +102 -0
- package/src/index.tsx +185 -98
- package/src/inspect.ts +39 -0
- package/src/kv.ts +111 -24
- package/src/open-in-browser.ts +5 -12
- package/src/pages.tsx +206 -65
- package/src/parse.ts +21 -4
- package/src/proxy.ts +38 -22
- package/src/publish.ts +227 -113
- package/src/sites.tsx +13 -16
- package/src/worker.ts +8 -0
- package/templates/new-worker.ts +16 -1
- package/wrangler-dist/cli.js +32273 -19295
package/src/__tests__/r2.test.ts
CHANGED
|
@@ -17,6 +17,33 @@ describe("wrangler", () => {
|
|
|
17
17
|
|
|
18
18
|
describe("r2", () => {
|
|
19
19
|
describe("bucket", () => {
|
|
20
|
+
it("should show the correct help when an invalid command is passed", async () => {
|
|
21
|
+
await expect(() =>
|
|
22
|
+
runWrangler("r2 bucket foo")
|
|
23
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown argument: foo"`);
|
|
24
|
+
expect(std.err).toMatchInlineSnapshot(`
|
|
25
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mUnknown argument: foo[0m
|
|
26
|
+
|
|
27
|
+
"
|
|
28
|
+
`);
|
|
29
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
30
|
+
"
|
|
31
|
+
wrangler r2 bucket
|
|
32
|
+
|
|
33
|
+
Manage R2 buckets
|
|
34
|
+
|
|
35
|
+
Commands:
|
|
36
|
+
wrangler r2 bucket create <name> Create a new R2 bucket
|
|
37
|
+
wrangler r2 bucket list List R2 buckets
|
|
38
|
+
wrangler r2 bucket delete <name> Delete an R2 bucket
|
|
39
|
+
|
|
40
|
+
Flags:
|
|
41
|
+
-c, --config Path to .toml configuration file [string]
|
|
42
|
+
-h, --help Show help [boolean]
|
|
43
|
+
-v, --version Show version number [boolean]"
|
|
44
|
+
`);
|
|
45
|
+
});
|
|
46
|
+
|
|
20
47
|
describe("list", () => {
|
|
21
48
|
function mockListRequest(buckets: R2BucketInfo[]) {
|
|
22
49
|
const requests = { count: 0 };
|
|
@@ -69,10 +96,7 @@ describe("wrangler", () => {
|
|
|
69
96
|
);
|
|
70
97
|
expect(std.out).toMatchInlineSnapshot(`
|
|
71
98
|
"
|
|
72
|
-
|
|
73
|
-
`);
|
|
74
|
-
expect(std.err).toMatchInlineSnapshot(`
|
|
75
|
-
"wrangler r2 bucket create <name>
|
|
99
|
+
wrangler r2 bucket create <name>
|
|
76
100
|
|
|
77
101
|
Create a new R2 bucket
|
|
78
102
|
|
|
@@ -82,8 +106,10 @@ describe("wrangler", () => {
|
|
|
82
106
|
Flags:
|
|
83
107
|
-c, --config Path to .toml configuration file [string]
|
|
84
108
|
-h, --help Show help [boolean]
|
|
85
|
-
-v, --version Show version number [boolean]
|
|
86
|
-
|
|
109
|
+
-v, --version Show version number [boolean]"
|
|
110
|
+
`);
|
|
111
|
+
expect(std.err).toMatchInlineSnapshot(`
|
|
112
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mNot enough non-option arguments: got 0, need at least 1[0m
|
|
87
113
|
|
|
88
114
|
"
|
|
89
115
|
`);
|
|
@@ -97,10 +123,7 @@ describe("wrangler", () => {
|
|
|
97
123
|
);
|
|
98
124
|
expect(std.out).toMatchInlineSnapshot(`
|
|
99
125
|
"
|
|
100
|
-
|
|
101
|
-
`);
|
|
102
|
-
expect(std.err).toMatchInlineSnapshot(`
|
|
103
|
-
"wrangler r2 bucket create <name>
|
|
126
|
+
wrangler r2 bucket create <name>
|
|
104
127
|
|
|
105
128
|
Create a new R2 bucket
|
|
106
129
|
|
|
@@ -110,8 +133,10 @@ describe("wrangler", () => {
|
|
|
110
133
|
Flags:
|
|
111
134
|
-c, --config Path to .toml configuration file [string]
|
|
112
135
|
-h, --help Show help [boolean]
|
|
113
|
-
-v, --version Show version number [boolean]
|
|
114
|
-
|
|
136
|
+
-v, --version Show version number [boolean]"
|
|
137
|
+
`);
|
|
138
|
+
expect(std.err).toMatchInlineSnapshot(`
|
|
139
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mUnknown arguments: def, ghi[0m
|
|
115
140
|
|
|
116
141
|
"
|
|
117
142
|
`);
|
|
@@ -151,10 +176,7 @@ describe("wrangler", () => {
|
|
|
151
176
|
);
|
|
152
177
|
expect(std.out).toMatchInlineSnapshot(`
|
|
153
178
|
"
|
|
154
|
-
|
|
155
|
-
`);
|
|
156
|
-
expect(std.err).toMatchInlineSnapshot(`
|
|
157
|
-
"wrangler r2 bucket delete <name>
|
|
179
|
+
wrangler r2 bucket delete <name>
|
|
158
180
|
|
|
159
181
|
Delete an R2 bucket
|
|
160
182
|
|
|
@@ -164,8 +186,10 @@ describe("wrangler", () => {
|
|
|
164
186
|
Flags:
|
|
165
187
|
-c, --config Path to .toml configuration file [string]
|
|
166
188
|
-h, --help Show help [boolean]
|
|
167
|
-
-v, --version Show version number [boolean]
|
|
168
|
-
|
|
189
|
+
-v, --version Show version number [boolean]"
|
|
190
|
+
`);
|
|
191
|
+
expect(std.err).toMatchInlineSnapshot(`
|
|
192
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mNot enough non-option arguments: got 0, need at least 1[0m
|
|
169
193
|
|
|
170
194
|
"
|
|
171
195
|
`);
|
|
@@ -179,10 +203,7 @@ describe("wrangler", () => {
|
|
|
179
203
|
);
|
|
180
204
|
expect(std.out).toMatchInlineSnapshot(`
|
|
181
205
|
"
|
|
182
|
-
|
|
183
|
-
`);
|
|
184
|
-
expect(std.err).toMatchInlineSnapshot(`
|
|
185
|
-
"wrangler r2 bucket delete <name>
|
|
206
|
+
wrangler r2 bucket delete <name>
|
|
186
207
|
|
|
187
208
|
Delete an R2 bucket
|
|
188
209
|
|
|
@@ -192,8 +213,10 @@ describe("wrangler", () => {
|
|
|
192
213
|
Flags:
|
|
193
214
|
-c, --config Path to .toml configuration file [string]
|
|
194
215
|
-h, --help Show help [boolean]
|
|
195
|
-
-v, --version Show version number [boolean]
|
|
196
|
-
|
|
216
|
+
-v, --version Show version number [boolean]"
|
|
217
|
+
`);
|
|
218
|
+
expect(std.err).toMatchInlineSnapshot(`
|
|
219
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mUnknown arguments: def, ghi[0m
|
|
197
220
|
|
|
198
221
|
"
|
|
199
222
|
`);
|
|
@@ -60,6 +60,22 @@ describe("wrangler secret", () => {
|
|
|
60
60
|
describe("interactive", () => {
|
|
61
61
|
useMockStdin({ isTTY: true });
|
|
62
62
|
|
|
63
|
+
it("should trim stdin secret value", async () => {
|
|
64
|
+
mockPrompt({
|
|
65
|
+
text: "Enter a secret value:",
|
|
66
|
+
type: "password",
|
|
67
|
+
result: `hunter2
|
|
68
|
+
`,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
mockPutRequest({ name: `secret-name`, text: `hunter2` });
|
|
72
|
+
await runWrangler("secret put secret-name --name script-name");
|
|
73
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
74
|
+
"🌀 Creating the secret for script script-name
|
|
75
|
+
✨ Success! Uploaded secret secret-name"
|
|
76
|
+
`);
|
|
77
|
+
});
|
|
78
|
+
|
|
63
79
|
it("should create a secret", async () => {
|
|
64
80
|
mockPrompt({
|
|
65
81
|
text: "Enter a secret value:",
|
|
@@ -146,6 +162,25 @@ describe("wrangler secret", () => {
|
|
|
146
162
|
describe("non-interactive", () => {
|
|
147
163
|
const mockStdIn = useMockStdin({ isTTY: false });
|
|
148
164
|
|
|
165
|
+
it("should trim stdin secret value, from piped input", async () => {
|
|
166
|
+
mockPutRequest({ name: "the-key", text: "the-secret" });
|
|
167
|
+
// Pipe the secret in as three chunks to test that we reconstitute it correctly.
|
|
168
|
+
mockStdIn.send(
|
|
169
|
+
`the`,
|
|
170
|
+
`-`,
|
|
171
|
+
`secret
|
|
172
|
+
` // whitespace & newline being removed
|
|
173
|
+
);
|
|
174
|
+
await runWrangler("secret put the-key --name script-name");
|
|
175
|
+
|
|
176
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
177
|
+
"🌀 Creating the secret for script script-name
|
|
178
|
+
✨ Success! Uploaded secret the-key"
|
|
179
|
+
`);
|
|
180
|
+
expect(std.warn).toMatchInlineSnapshot(`""`);
|
|
181
|
+
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
182
|
+
});
|
|
183
|
+
|
|
149
184
|
it("should create a secret, from piped input", async () => {
|
|
150
185
|
mockPutRequest({ name: "the-key", text: "the-secret" });
|
|
151
186
|
// Pipe the secret in as three chunks to test that we reconstitute it correctly.
|
package/src/abort.d.ts
ADDED
package/src/bundle.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
|
+
import { builtinModules } from "node:module";
|
|
3
4
|
import * as path from "node:path";
|
|
4
5
|
import NodeGlobalsPolyfills from "@esbuild-plugins/node-globals-polyfill";
|
|
5
6
|
import NodeModulesPolyfills from "@esbuild-plugins/node-modules-polyfill";
|
|
@@ -16,6 +17,33 @@ type BundleResult = {
|
|
|
16
17
|
stop: (() => void) | undefined;
|
|
17
18
|
};
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Searches for any uses of node's builtin modules, and throws an error if it
|
|
22
|
+
* finds anything. This plugin is only used when nodeCompat is not enabled.
|
|
23
|
+
* Supports both regular node builtins, and the new "node:<MODULE>" format.
|
|
24
|
+
*/
|
|
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
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
19
47
|
/**
|
|
20
48
|
* Generate a bundle for the worker identified by the arguments passed in.
|
|
21
49
|
*/
|
|
@@ -60,6 +88,7 @@ export async function bundleWorker(
|
|
|
60
88
|
format: entry.format,
|
|
61
89
|
rules,
|
|
62
90
|
});
|
|
91
|
+
|
|
63
92
|
const result = await esbuild.build({
|
|
64
93
|
...getEntryPoint(entry.file, serveAssetsFromWorker),
|
|
65
94
|
bundle: true,
|
|
@@ -87,7 +116,9 @@ export async function bundleWorker(
|
|
|
87
116
|
moduleCollector.plugin,
|
|
88
117
|
...(nodeCompat
|
|
89
118
|
? [NodeGlobalsPolyfills({ buffer: true }), NodeModulesPolyfills()]
|
|
90
|
-
:
|
|
119
|
+
: // we use checkForNodeBuiltinsPlugin to throw a nicer error
|
|
120
|
+
// if we find node builtins when nodeCompat isn't turned on
|
|
121
|
+
[checkForNodeBuiltinsPlugin]),
|
|
91
122
|
],
|
|
92
123
|
...(jsxFactory && { jsxFactory }),
|
|
93
124
|
...(jsxFragment && { jsxFragment }),
|
package/src/cfetch/index.ts
CHANGED
|
@@ -27,12 +27,14 @@ export { fetchKVGetValue } from "./internal";
|
|
|
27
27
|
export async function fetchResult<ResponseType>(
|
|
28
28
|
resource: string,
|
|
29
29
|
init: RequestInit = {},
|
|
30
|
-
queryParams?: URLSearchParams
|
|
30
|
+
queryParams?: URLSearchParams,
|
|
31
|
+
abortSignal?: AbortSignal
|
|
31
32
|
): Promise<ResponseType> {
|
|
32
33
|
const json = await fetchInternal<FetchResult<ResponseType>>(
|
|
33
34
|
resource,
|
|
34
35
|
init,
|
|
35
|
-
queryParams
|
|
36
|
+
queryParams,
|
|
37
|
+
abortSignal
|
|
36
38
|
);
|
|
37
39
|
if (json.success) {
|
|
38
40
|
return json.result;
|
package/src/cfetch/internal.ts
CHANGED
|
@@ -26,12 +26,13 @@ export const getCloudflareAPIBaseURL = getEnvironmentVariableFactory({
|
|
|
26
26
|
export async function fetchInternal<ResponseType>(
|
|
27
27
|
resource: string,
|
|
28
28
|
init: RequestInit = {},
|
|
29
|
-
queryParams?: URLSearchParams
|
|
29
|
+
queryParams?: URLSearchParams,
|
|
30
|
+
abortSignal?: AbortSignal
|
|
30
31
|
): Promise<ResponseType> {
|
|
31
32
|
await requireLoggedIn();
|
|
32
33
|
const apiToken = requireApiToken();
|
|
33
34
|
const headers = cloneHeaders(init.headers);
|
|
34
|
-
|
|
35
|
+
addAuthorizationHeaderIfUnspecified(headers, apiToken);
|
|
35
36
|
|
|
36
37
|
const queryString = queryParams ? `?${queryParams.toString()}` : "";
|
|
37
38
|
const method = init.method ?? "GET";
|
|
@@ -41,11 +42,12 @@ export async function fetchInternal<ResponseType>(
|
|
|
41
42
|
method,
|
|
42
43
|
...init,
|
|
43
44
|
headers,
|
|
45
|
+
signal: abortSignal,
|
|
44
46
|
}
|
|
45
47
|
);
|
|
46
48
|
const jsonText = await response.text();
|
|
47
49
|
try {
|
|
48
|
-
return parseJSON(jsonText)
|
|
50
|
+
return parseJSON<ResponseType>(jsonText);
|
|
49
51
|
} catch (err) {
|
|
50
52
|
throw new ParseError({
|
|
51
53
|
text: "Received a malformed response from the API",
|
|
@@ -94,16 +96,13 @@ function requireApiToken(): string {
|
|
|
94
96
|
return authToken;
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
function
|
|
99
|
+
function addAuthorizationHeaderIfUnspecified(
|
|
98
100
|
headers: Record<string, string>,
|
|
99
101
|
apiToken: string
|
|
100
102
|
): void {
|
|
101
|
-
if ("Authorization" in headers) {
|
|
102
|
-
|
|
103
|
-
"The request already specifies an authorisation header - cannot add a new one."
|
|
104
|
-
);
|
|
103
|
+
if (!("Authorization" in headers)) {
|
|
104
|
+
headers["Authorization"] = `Bearer ${apiToken}`;
|
|
105
105
|
}
|
|
106
|
-
headers["Authorization"] = `Bearer ${apiToken}`;
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
/**
|
|
@@ -112,6 +111,9 @@ function addAuthorizationHeader(
|
|
|
112
111
|
* doesn't return json. We inline the implementation and try not to share
|
|
113
112
|
* any code with the other calls. We should push back on any new APIs that
|
|
114
113
|
* try to introduce non-"standard" response structures.
|
|
114
|
+
*
|
|
115
|
+
* Note: any calls to fetchKVGetValue must call encodeURIComponent on key
|
|
116
|
+
* before passing it
|
|
115
117
|
*/
|
|
116
118
|
|
|
117
119
|
export async function fetchKVGetValue(
|
|
@@ -8,6 +8,24 @@ export interface Environment
|
|
|
8
8
|
extends EnvironmentInheritable,
|
|
9
9
|
EnvironmentNonInheritable {}
|
|
10
10
|
|
|
11
|
+
export type SimpleRoute = string;
|
|
12
|
+
export type ZoneIdRoute = {
|
|
13
|
+
pattern: string;
|
|
14
|
+
zone_id: string;
|
|
15
|
+
custom_domain?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export type ZoneNameRoute = {
|
|
18
|
+
pattern: string;
|
|
19
|
+
zone_name: string;
|
|
20
|
+
custom_domain?: boolean;
|
|
21
|
+
};
|
|
22
|
+
export type CustomDomainRoute = { pattern: string; custom_domain: boolean };
|
|
23
|
+
export type Route =
|
|
24
|
+
| SimpleRoute
|
|
25
|
+
| ZoneIdRoute
|
|
26
|
+
| ZoneNameRoute
|
|
27
|
+
| CustomDomainRoute;
|
|
28
|
+
|
|
11
29
|
/**
|
|
12
30
|
* The `EnvironmentInheritable` interface declares all the configuration fields for an environment
|
|
13
31
|
* that can be inherited (and overridden) from the top-level environment.
|
|
@@ -74,13 +92,7 @@ interface EnvironmentInheritable {
|
|
|
74
92
|
*
|
|
75
93
|
* @inheritable
|
|
76
94
|
*/
|
|
77
|
-
routes:
|
|
78
|
-
| (
|
|
79
|
-
| string
|
|
80
|
-
| { pattern: string; zone_id: string }
|
|
81
|
-
| { pattern: string; zone_name: string }
|
|
82
|
-
)[]
|
|
83
|
-
| undefined;
|
|
95
|
+
routes: Route[] | undefined;
|
|
84
96
|
|
|
85
97
|
/**
|
|
86
98
|
* A route that your worker should be published to. Literally
|
|
@@ -91,13 +103,7 @@ interface EnvironmentInheritable {
|
|
|
91
103
|
*
|
|
92
104
|
* @inheritable
|
|
93
105
|
*/
|
|
94
|
-
route:
|
|
95
|
-
| (
|
|
96
|
-
| string
|
|
97
|
-
| { pattern: string; zone_id: string }
|
|
98
|
-
| { pattern: string; zone_name: string }
|
|
99
|
-
)
|
|
100
|
-
| undefined;
|
|
106
|
+
route: Route | undefined;
|
|
101
107
|
|
|
102
108
|
/**
|
|
103
109
|
* Path to a custom tsconfig
|
|
@@ -236,6 +242,8 @@ interface EnvironmentNonInheritable {
|
|
|
236
242
|
class_name: string;
|
|
237
243
|
/** The script where the Durable Object is defined (if it's external to this worker) */
|
|
238
244
|
script_name?: string;
|
|
245
|
+
/** The service environment of the script_name to bind to */
|
|
246
|
+
environment?: string;
|
|
239
247
|
}[];
|
|
240
248
|
};
|
|
241
249
|
|
|
@@ -279,6 +287,24 @@ interface EnvironmentNonInheritable {
|
|
|
279
287
|
preview_bucket_name?: string;
|
|
280
288
|
}[];
|
|
281
289
|
|
|
290
|
+
/**
|
|
291
|
+
* Specifies service bindings (worker-to-worker) that are bound to this Worker environment.
|
|
292
|
+
*
|
|
293
|
+
* NOTE: This field is not automatically inherited from the top level environment,
|
|
294
|
+
* and so must be specified in every named environment.
|
|
295
|
+
*
|
|
296
|
+
* @default `[]`
|
|
297
|
+
* @nonInheritable
|
|
298
|
+
*/
|
|
299
|
+
services: {
|
|
300
|
+
/** The binding name used to refer to the bound service. */
|
|
301
|
+
binding: string;
|
|
302
|
+
/** The name of the service. */
|
|
303
|
+
service: string;
|
|
304
|
+
/** The environment of the service (e.g. production, staging, etc). */
|
|
305
|
+
environment?: string;
|
|
306
|
+
}[];
|
|
307
|
+
|
|
282
308
|
/**
|
|
283
309
|
* "Unsafe" tables for features that aren't directly supported by wrangler.
|
|
284
310
|
*
|
package/src/config/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { findUpSync } from "find-up";
|
|
|
2
2
|
import { logger } from "../logger";
|
|
3
3
|
import { parseTOML, readFileSync } from "../parse";
|
|
4
4
|
import { normalizeAndValidateConfig } from "./validation";
|
|
5
|
+
import type { CfWorkerInit } from "../worker";
|
|
5
6
|
import type { Config, RawConfig } from "./config";
|
|
6
7
|
|
|
7
8
|
export type {
|
|
@@ -61,3 +62,164 @@ export function findWranglerToml(
|
|
|
61
62
|
const configPath = findUpSync("wrangler.toml", { cwd: referencePath });
|
|
62
63
|
return configPath;
|
|
63
64
|
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Print all the bindings a worker using a given config would have access to
|
|
68
|
+
*/
|
|
69
|
+
export function printBindings(bindings: CfWorkerInit["bindings"]) {
|
|
70
|
+
const truncate = (item: string | Record<string, unknown>) => {
|
|
71
|
+
const s = typeof item === "string" ? item : JSON.stringify(item);
|
|
72
|
+
const maxLength = 40;
|
|
73
|
+
if (s.length < maxLength) {
|
|
74
|
+
return s;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return `${s.substring(0, maxLength - 3)}...`;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const output: { type: string; entries: { key: string; value: string }[] }[] =
|
|
81
|
+
[];
|
|
82
|
+
|
|
83
|
+
const {
|
|
84
|
+
data_blobs,
|
|
85
|
+
durable_objects,
|
|
86
|
+
kv_namespaces,
|
|
87
|
+
r2_buckets,
|
|
88
|
+
services,
|
|
89
|
+
text_blobs,
|
|
90
|
+
unsafe,
|
|
91
|
+
vars,
|
|
92
|
+
wasm_modules,
|
|
93
|
+
} = bindings;
|
|
94
|
+
|
|
95
|
+
if (data_blobs !== undefined && Object.keys(data_blobs).length > 0) {
|
|
96
|
+
output.push({
|
|
97
|
+
type: "Data Blobs",
|
|
98
|
+
entries: Object.entries(data_blobs).map(([key, value]) => ({
|
|
99
|
+
key,
|
|
100
|
+
value: truncate(value),
|
|
101
|
+
})),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (durable_objects !== undefined && durable_objects.bindings.length > 0) {
|
|
106
|
+
output.push({
|
|
107
|
+
type: "Durable Objects",
|
|
108
|
+
entries: durable_objects.bindings.map(
|
|
109
|
+
({ name, class_name, script_name, environment }) => {
|
|
110
|
+
let value = class_name;
|
|
111
|
+
if (script_name) {
|
|
112
|
+
value += ` (defined in ${script_name})`;
|
|
113
|
+
}
|
|
114
|
+
if (environment) {
|
|
115
|
+
value += ` - ${environment}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
key: name,
|
|
120
|
+
value,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
),
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (kv_namespaces !== undefined && kv_namespaces.length > 0) {
|
|
128
|
+
output.push({
|
|
129
|
+
type: "KV Namespaces",
|
|
130
|
+
entries: kv_namespaces.map(({ binding, id }) => {
|
|
131
|
+
return {
|
|
132
|
+
key: binding,
|
|
133
|
+
value: id,
|
|
134
|
+
};
|
|
135
|
+
}),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (r2_buckets !== undefined && r2_buckets.length > 0) {
|
|
140
|
+
output.push({
|
|
141
|
+
type: "R2 Buckets",
|
|
142
|
+
entries: r2_buckets.map(({ binding, bucket_name }) => {
|
|
143
|
+
return {
|
|
144
|
+
key: binding,
|
|
145
|
+
value: bucket_name,
|
|
146
|
+
};
|
|
147
|
+
}),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (services !== undefined && services.length > 0) {
|
|
152
|
+
output.push({
|
|
153
|
+
type: "Services",
|
|
154
|
+
entries: services.map(({ binding, service, environment }) => {
|
|
155
|
+
let value = service;
|
|
156
|
+
if (environment) {
|
|
157
|
+
value += ` - ${environment}`;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
key: binding,
|
|
162
|
+
value,
|
|
163
|
+
};
|
|
164
|
+
}),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (text_blobs !== undefined && Object.keys(text_blobs).length > 0) {
|
|
169
|
+
output.push({
|
|
170
|
+
type: "Text Blobs",
|
|
171
|
+
entries: Object.entries(text_blobs).map(([key, value]) => ({
|
|
172
|
+
key,
|
|
173
|
+
value: truncate(value),
|
|
174
|
+
})),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (unsafe !== undefined && unsafe.length > 0) {
|
|
179
|
+
output.push({
|
|
180
|
+
type: "Unsafe",
|
|
181
|
+
entries: unsafe.map(({ name, type }) => ({
|
|
182
|
+
key: type,
|
|
183
|
+
value: name,
|
|
184
|
+
})),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (vars !== undefined && Object.keys(vars).length > 0) {
|
|
189
|
+
output.push({
|
|
190
|
+
type: "Vars",
|
|
191
|
+
entries: Object.entries(vars).map(([key, value]) => ({
|
|
192
|
+
key,
|
|
193
|
+
value: `"${truncate(`${value}`)}"`,
|
|
194
|
+
})),
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (wasm_modules !== undefined && Object.keys(wasm_modules).length > 0) {
|
|
199
|
+
output.push({
|
|
200
|
+
type: "Wasm Modules",
|
|
201
|
+
entries: Object.entries(wasm_modules).map(([key, value]) => ({
|
|
202
|
+
key,
|
|
203
|
+
value: truncate(value),
|
|
204
|
+
})),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (output.length === 0) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const message = [
|
|
213
|
+
`Your worker has access to the following bindings:`,
|
|
214
|
+
...output
|
|
215
|
+
.map((bindingGroup) => {
|
|
216
|
+
return [
|
|
217
|
+
`- ${bindingGroup.type}:`,
|
|
218
|
+
bindingGroup.entries.map(({ key, value }) => ` - ${key}: ${value}`),
|
|
219
|
+
];
|
|
220
|
+
})
|
|
221
|
+
.flat(2),
|
|
222
|
+
].join("\n");
|
|
223
|
+
|
|
224
|
+
logger.log(message);
|
|
225
|
+
}
|