wrangler 0.0.0-e3cab74 → 0.0.0-e452a35
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/Cloudflare_CA.pem +18 -0
- package/README.md +27 -14
- package/bin/wrangler.js +49 -5
- package/miniflare-dist/index.mjs +4886 -0
- package/package.json +42 -28
- package/pages/functions/buildPlugin.ts +105 -0
- package/pages/functions/buildWorker.ts +93 -4
- package/pages/functions/filepath-routing.test.ts +136 -25
- package/pages/functions/filepath-routing.ts +14 -3
- package/pages/functions/routes.ts +6 -1
- package/pages/functions/template-plugin.ts +147 -0
- package/pages/functions/template-worker.ts +21 -8
- package/src/__tests__/config-cache.test.ts +36 -0
- package/src/__tests__/configuration.test.ts +1514 -367
- package/src/__tests__/dev.test.tsx +870 -84
- package/src/__tests__/guess-worker-format.test.ts +37 -18
- package/src/__tests__/helpers/mock-account-id.ts +22 -4
- package/src/__tests__/helpers/mock-cfetch.ts +8 -4
- package/src/__tests__/helpers/mock-console.ts +35 -10
- package/src/__tests__/helpers/mock-dialogs.ts +26 -1
- package/src/__tests__/helpers/mock-http-server.ts +46 -0
- package/src/__tests__/helpers/mock-istty.ts +27 -0
- package/src/__tests__/helpers/mock-kv.ts +9 -16
- package/src/__tests__/helpers/mock-oauth-flow.ts +255 -0
- package/src/__tests__/helpers/mock-stdin.ts +103 -0
- package/src/__tests__/helpers/run-in-tmp.ts +10 -0
- package/src/__tests__/helpers/write-worker-source.ts +31 -0
- package/src/__tests__/https-options.test.ts +130 -0
- package/src/__tests__/index.test.ts +137 -747
- package/src/__tests__/init.test.ts +1557 -0
- package/src/__tests__/jest.setup.ts +28 -8
- package/src/__tests__/kv.test.ts +598 -258
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +657 -0
- package/src/__tests__/parse.test.ts +8 -0
- package/src/__tests__/publish.test.ts +4003 -941
- package/src/__tests__/r2.test.ts +69 -34
- package/src/__tests__/route.test.ts +45 -0
- package/src/__tests__/secret.test.ts +228 -73
- package/src/__tests__/tail.test.ts +146 -20
- package/src/__tests__/user.test.ts +131 -0
- package/src/__tests__/whoami.test.tsx +26 -7
- package/src/abort.d.ts +3 -0
- package/src/bundle.ts +74 -7
- package/src/cfetch/index.ts +21 -4
- package/src/cfetch/internal.ts +20 -14
- package/src/cli.ts +5 -11
- package/src/config/README.md +7 -7
- package/src/config/config.ts +69 -100
- package/src/config/environment.ts +119 -4
- package/src/config/index.ts +177 -4
- package/src/config/validation-helpers.ts +228 -23
- package/src/config/validation.ts +687 -174
- package/src/config-cache.ts +45 -0
- package/src/{api/preview.ts → create-worker-preview.ts} +74 -36
- package/src/{api/form_data.ts → create-worker-upload-form.ts} +55 -18
- package/src/dev/dev-vars.ts +36 -0
- package/src/dev/dev.tsx +422 -0
- package/src/dev/local.tsx +318 -0
- package/src/dev/remote.tsx +227 -0
- package/src/dev/use-esbuild.ts +118 -0
- package/src/dialogs.tsx +16 -6
- package/src/durable.ts +102 -0
- package/src/entry.ts +279 -14
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +123 -0
- package/src/index.tsx +1268 -806
- package/src/inspect.ts +64 -11
- package/src/intl-polyfill.d.ts +139 -0
- package/src/{kv.tsx → kv.ts} +195 -62
- package/src/logger.ts +66 -0
- package/src/miniflare-cli/README.md +30 -0
- package/src/miniflare-cli/enum-keys.ts +17 -0
- package/src/miniflare-cli/index.ts +41 -0
- package/src/miniflare-cli/request-context.ts +40 -0
- package/src/module-collection.ts +94 -6
- package/src/open-in-browser.ts +9 -3
- package/src/package-manager.ts +9 -8
- package/src/pages.tsx +1057 -75
- package/src/parse.ts +24 -5
- package/src/proxy.ts +143 -54
- package/src/publish.ts +444 -229
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +98 -44
- package/src/tail/index.ts +2 -2
- package/src/tail/printing.ts +13 -8
- package/src/update-check.ts +19 -0
- package/src/user.tsx +263 -109
- package/src/whoami.tsx +2 -1
- package/src/{api/worker.ts → worker.ts} +24 -30
- package/templates/gitignore +171 -0
- package/templates/new-worker.ts +16 -1
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +55345 -69246
- package/src/__tests__/helpers/mock-user.ts +0 -27
- package/src/__tests__/logout.test.ts +0 -50
- package/src/__tests__/sentry.test.ts +0 -146
- package/src/dev.tsx +0 -961
- package/src/guess-worker-format.ts +0 -68
- package/src/reporting.ts +0 -115
- package/wrangler-dist/cli.js.map +0 -7
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
declare module "selfsigned" {
|
|
2
|
+
import type { pki } from "node-forge";
|
|
3
|
+
|
|
4
|
+
export type Attributes = pki.CertificateField[];
|
|
5
|
+
|
|
6
|
+
export interface Options {
|
|
7
|
+
days?: number;
|
|
8
|
+
keySize?: number;
|
|
9
|
+
extensions?: unknown[];
|
|
10
|
+
algorithm?: string;
|
|
11
|
+
pkcs7?: boolean;
|
|
12
|
+
clientCertificate?: boolean;
|
|
13
|
+
clientCertificateCN?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface Certificate {
|
|
17
|
+
private: string;
|
|
18
|
+
public: string;
|
|
19
|
+
cert: string;
|
|
20
|
+
fingerprint: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function generate(attrs?: Attributes, options?: Options): Certificate;
|
|
24
|
+
export function generate(
|
|
25
|
+
attrs: Attributes,
|
|
26
|
+
options: Options,
|
|
27
|
+
callback: (err: Error, certificate: Certificate) => void
|
|
28
|
+
): void;
|
|
29
|
+
}
|
package/src/sites.tsx
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
1
2
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
import ignore from "ignore";
|
|
4
5
|
import xxhash from "xxhash-wasm";
|
|
5
6
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
createKVNamespace,
|
|
8
|
+
listKVNamespaceKeys,
|
|
9
|
+
listKVNamespaces,
|
|
10
|
+
putKVBulkKeyValue,
|
|
11
|
+
deleteKVBulkKeyValue,
|
|
10
12
|
} from "./kv";
|
|
13
|
+
import { logger } from "./logger";
|
|
11
14
|
import type { Config } from "./config";
|
|
15
|
+
import type { KeyValue } from "./kv";
|
|
12
16
|
import type { XXHashAPI } from "xxhash-wasm";
|
|
13
17
|
|
|
14
18
|
/** Paths to always ignore. */
|
|
15
|
-
const ALWAYS_IGNORE = ["node_modules"];
|
|
16
|
-
const HIDDEN_FILES_TO_INCLUDE = [
|
|
19
|
+
const ALWAYS_IGNORE = new Set(["node_modules"]);
|
|
20
|
+
const HIDDEN_FILES_TO_INCLUDE = new Set([
|
|
17
21
|
".well-known", // See https://datatracker.ietf.org/doc/html/rfc8615
|
|
18
|
-
];
|
|
22
|
+
]);
|
|
19
23
|
|
|
20
24
|
async function* getFilesInFolder(dirPath: string): AsyncIterable<string> {
|
|
21
25
|
const files = await readdir(dirPath, { withFileTypes: true });
|
|
22
26
|
for (const file of files) {
|
|
23
27
|
// Skip files that we never want to process.
|
|
24
|
-
if (ALWAYS_IGNORE.
|
|
28
|
+
if (ALWAYS_IGNORE.has(file.name)) {
|
|
25
29
|
continue;
|
|
26
30
|
}
|
|
27
31
|
// Skip hidden files (starting with .) except for some special ones
|
|
28
|
-
if (
|
|
29
|
-
file.name.startsWith(".") &&
|
|
30
|
-
!HIDDEN_FILES_TO_INCLUDE.some((p) => file.name === p)
|
|
31
|
-
) {
|
|
32
|
+
if (file.name.startsWith(".") && !HIDDEN_FILES_TO_INCLUDE.has(file.name)) {
|
|
32
33
|
continue;
|
|
33
34
|
}
|
|
34
35
|
// TODO: follow symlinks??
|
|
@@ -75,15 +76,15 @@ async function createKVNamespaceIfNotAlreadyExisting(
|
|
|
75
76
|
) {
|
|
76
77
|
// check if it already exists
|
|
77
78
|
// TODO: this is super inefficient, should be made better
|
|
78
|
-
const namespaces = await
|
|
79
|
+
const namespaces = await listKVNamespaces(accountId);
|
|
79
80
|
const found = namespaces.find((x) => x.title === title);
|
|
80
81
|
if (found) {
|
|
81
82
|
return { created: false, id: found.id };
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
// else we make the namespace
|
|
85
|
-
const id = await
|
|
86
|
-
|
|
86
|
+
const id = await createKVNamespace(accountId, title);
|
|
87
|
+
logger.log(`🌀 Created namespace for Workers Site "${title}"`);
|
|
87
88
|
|
|
88
89
|
return {
|
|
89
90
|
created: true,
|
|
@@ -103,10 +104,11 @@ async function createKVNamespaceIfNotAlreadyExisting(
|
|
|
103
104
|
* asset in the KV namespace.
|
|
104
105
|
*/
|
|
105
106
|
export async function syncAssets(
|
|
106
|
-
accountId: string,
|
|
107
|
+
accountId: string | undefined,
|
|
107
108
|
scriptName: string,
|
|
108
109
|
siteAssets: AssetPaths | undefined,
|
|
109
|
-
preview: boolean
|
|
110
|
+
preview: boolean,
|
|
111
|
+
dryRun: boolean | undefined
|
|
110
112
|
): Promise<{
|
|
111
113
|
manifest: { [filePath: string]: string } | undefined;
|
|
112
114
|
namespace: string | undefined;
|
|
@@ -115,59 +117,88 @@ export async function syncAssets(
|
|
|
115
117
|
return { manifest: undefined, namespace: undefined };
|
|
116
118
|
}
|
|
117
119
|
|
|
120
|
+
if (dryRun) {
|
|
121
|
+
logger.log("(Note: doing a dry run, not uploading or deleting anything.)");
|
|
122
|
+
return { manifest: undefined, namespace: undefined };
|
|
123
|
+
}
|
|
124
|
+
assert(accountId, "Missing accountId");
|
|
125
|
+
|
|
118
126
|
const title = `__${scriptName}-workers_sites_assets${
|
|
119
127
|
preview ? "_preview" : ""
|
|
120
128
|
}`;
|
|
129
|
+
|
|
121
130
|
const { id: namespace } = await createKVNamespaceIfNotAlreadyExisting(
|
|
122
131
|
title,
|
|
123
132
|
accountId
|
|
124
133
|
);
|
|
125
134
|
|
|
126
135
|
// let's get all the keys in this namespace
|
|
127
|
-
const
|
|
128
|
-
const
|
|
136
|
+
const namespaceKeysResponse = await listKVNamespaceKeys(accountId, namespace);
|
|
137
|
+
const namespaceKeys = new Set(namespaceKeysResponse.map((x) => x.name));
|
|
129
138
|
|
|
130
139
|
const manifest: Record<string, string> = {};
|
|
131
|
-
const
|
|
132
|
-
key: string;
|
|
133
|
-
value: string;
|
|
134
|
-
base64: boolean;
|
|
135
|
-
}[] = [];
|
|
140
|
+
const toUpload: KeyValue[] = [];
|
|
136
141
|
|
|
137
142
|
const include = createPatternMatcher(siteAssets.includePatterns, false);
|
|
138
143
|
const exclude = createPatternMatcher(siteAssets.excludePatterns, true);
|
|
139
144
|
const hasher = await xxhash();
|
|
140
145
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
146
|
+
const assetDirectory = path.join(
|
|
147
|
+
siteAssets.baseDirectory,
|
|
148
|
+
siteAssets.assetDirectory
|
|
149
|
+
);
|
|
150
|
+
for await (const absAssetFile of getFilesInFolder(assetDirectory)) {
|
|
151
|
+
const assetFile = path.relative(siteAssets.baseDirectory, absAssetFile);
|
|
152
|
+
if (!include(assetFile)) {
|
|
144
153
|
continue;
|
|
145
154
|
}
|
|
146
|
-
if (exclude(
|
|
155
|
+
if (exclude(assetFile)) {
|
|
147
156
|
continue;
|
|
148
157
|
}
|
|
149
158
|
|
|
150
|
-
await validateAssetSize(
|
|
151
|
-
|
|
152
|
-
const content = await readFile(
|
|
159
|
+
await validateAssetSize(absAssetFile, assetFile);
|
|
160
|
+
logger.log(`Reading ${assetFile}...`);
|
|
161
|
+
const content = await readFile(absAssetFile, "base64");
|
|
153
162
|
|
|
154
|
-
const assetKey =
|
|
163
|
+
const assetKey = hashAsset(hasher, assetFile, content);
|
|
155
164
|
validateAssetKey(assetKey);
|
|
156
165
|
|
|
157
166
|
// now put each of the files into kv
|
|
158
|
-
if (!
|
|
159
|
-
|
|
160
|
-
|
|
167
|
+
if (!namespaceKeys.has(assetKey)) {
|
|
168
|
+
logger.log(`Uploading as ${assetKey}...`);
|
|
169
|
+
toUpload.push({
|
|
161
170
|
key: assetKey,
|
|
162
171
|
value: content,
|
|
163
172
|
base64: true,
|
|
164
173
|
});
|
|
165
174
|
} else {
|
|
166
|
-
|
|
175
|
+
logger.log(`Skipping - already uploaded.`);
|
|
167
176
|
}
|
|
168
|
-
|
|
177
|
+
|
|
178
|
+
// remove the key from the set so we know what we've already uploaded
|
|
179
|
+
namespaceKeys.delete(assetKey);
|
|
180
|
+
|
|
181
|
+
// prevent causing different manifest keys on windows
|
|
182
|
+
const maifestKey = urlSafe(
|
|
183
|
+
path.relative(siteAssets.assetDirectory, absAssetFile)
|
|
184
|
+
);
|
|
185
|
+
manifest[maifestKey] = assetKey;
|
|
169
186
|
}
|
|
170
|
-
|
|
187
|
+
|
|
188
|
+
// keys now contains all the files we're deleting
|
|
189
|
+
for (const key of namespaceKeys) {
|
|
190
|
+
logger.log(`Deleting ${key} from the asset store...`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
await Promise.all([
|
|
194
|
+
// upload all the new assets
|
|
195
|
+
putKVBulkKeyValue(accountId, namespace, toUpload),
|
|
196
|
+
// delete all the unused assets
|
|
197
|
+
deleteKVBulkKeyValue(accountId, namespace, Array.from(namespaceKeys)),
|
|
198
|
+
]);
|
|
199
|
+
|
|
200
|
+
logger.log("↗️ Done syncing assets");
|
|
201
|
+
|
|
171
202
|
return { manifest, namespace };
|
|
172
203
|
}
|
|
173
204
|
|
|
@@ -183,11 +214,14 @@ function createPatternMatcher(
|
|
|
183
214
|
}
|
|
184
215
|
}
|
|
185
216
|
|
|
186
|
-
async function validateAssetSize(
|
|
187
|
-
|
|
217
|
+
async function validateAssetSize(
|
|
218
|
+
absFilePath: string,
|
|
219
|
+
relativeFilePath: string
|
|
220
|
+
) {
|
|
221
|
+
const { size } = await stat(absFilePath);
|
|
188
222
|
if (size > 25 * 1024 * 1024) {
|
|
189
223
|
throw new Error(
|
|
190
|
-
`File ${
|
|
224
|
+
`File ${relativeFilePath} is too big, it should be under 25 MiB. See https://developers.cloudflare.com/workers/platform/limits#kv-limits`
|
|
191
225
|
);
|
|
192
226
|
}
|
|
193
227
|
}
|
|
@@ -213,8 +247,23 @@ function urlSafe(filePath: string): string {
|
|
|
213
247
|
* Information about the assets that should be uploaded
|
|
214
248
|
*/
|
|
215
249
|
export interface AssetPaths {
|
|
250
|
+
/**
|
|
251
|
+
* Absolute path to the root of the project.
|
|
252
|
+
*
|
|
253
|
+
* This is the directory containing wrangler.toml or cwd if no config.
|
|
254
|
+
*/
|
|
216
255
|
baseDirectory: string;
|
|
256
|
+
/**
|
|
257
|
+
* The path to the assets directory, relative to the `baseDirectory`.
|
|
258
|
+
*/
|
|
259
|
+
assetDirectory: string;
|
|
260
|
+
/**
|
|
261
|
+
* An array of patterns that match files that should be uploaded.
|
|
262
|
+
*/
|
|
217
263
|
includePatterns: string[];
|
|
264
|
+
/**
|
|
265
|
+
* An array of patterns that match files that should not be uploaded.
|
|
266
|
+
*/
|
|
218
267
|
excludePatterns: string[];
|
|
219
268
|
}
|
|
220
269
|
|
|
@@ -227,13 +276,18 @@ export interface AssetPaths {
|
|
|
227
276
|
*/
|
|
228
277
|
export function getAssetPaths(
|
|
229
278
|
config: Config,
|
|
230
|
-
|
|
279
|
+
assetDirectory = config.site?.bucket,
|
|
231
280
|
includePatterns = config.site?.include ?? [],
|
|
232
281
|
excludePatterns = config.site?.exclude ?? []
|
|
233
|
-
):
|
|
234
|
-
|
|
282
|
+
): AssetPaths | undefined {
|
|
283
|
+
const baseDirectory = path.resolve(
|
|
284
|
+
path.dirname(config.configPath ?? "wrangler.toml")
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
return assetDirectory
|
|
235
288
|
? {
|
|
236
289
|
baseDirectory,
|
|
290
|
+
assetDirectory,
|
|
237
291
|
includePatterns,
|
|
238
292
|
excludePatterns,
|
|
239
293
|
}
|
package/src/tail/index.ts
CHANGED
|
@@ -161,7 +161,7 @@ export type TailEventMessage = {
|
|
|
161
161
|
* Any logs sent out by the worker
|
|
162
162
|
*/
|
|
163
163
|
logs: {
|
|
164
|
-
message: unknown;
|
|
164
|
+
message: unknown[];
|
|
165
165
|
level: string; // TODO: make this a union of possible values
|
|
166
166
|
timestamp: number;
|
|
167
167
|
}[];
|
|
@@ -179,7 +179,7 @@ export type TailEventMessage = {
|
|
|
179
179
|
* Until workers-types exposes individual types for export, we'll have
|
|
180
180
|
* to just re-define these types ourselves.
|
|
181
181
|
*/
|
|
182
|
-
event: RequestEvent | ScheduledEvent;
|
|
182
|
+
event: RequestEvent | ScheduledEvent | undefined | null;
|
|
183
183
|
};
|
|
184
184
|
|
|
185
185
|
/**
|
package/src/tail/printing.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logger } from "../logger";
|
|
1
2
|
import type { RequestEvent, ScheduledEvent, TailEventMessage } from ".";
|
|
2
3
|
import type { Outcome } from "./filters";
|
|
3
4
|
import type WebSocket from "ws";
|
|
@@ -12,25 +13,29 @@ export function prettyPrintLogs(data: WebSocket.RawData): void {
|
|
|
12
13
|
).toLocaleString();
|
|
13
14
|
const outcome = prettifyOutcome(eventMessage.outcome);
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
logger.log(`"${cronPattern}" @ ${datetime} - ${outcome}`);
|
|
16
17
|
} else {
|
|
17
|
-
const requestMethod = eventMessage.event
|
|
18
|
-
const url = eventMessage.event
|
|
18
|
+
const requestMethod = eventMessage.event?.request.method.toUpperCase();
|
|
19
|
+
const url = eventMessage.event?.request.url;
|
|
19
20
|
const outcome = prettifyOutcome(eventMessage.outcome);
|
|
20
21
|
const datetime = new Date(eventMessage.eventTimestamp).toLocaleString();
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
logger.log(
|
|
24
|
+
url
|
|
25
|
+
? `${requestMethod} ${url} - ${outcome} @ ${datetime}`
|
|
26
|
+
: `[missing request] - ${outcome} @ ${datetime}`
|
|
27
|
+
);
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
if (eventMessage.logs.length > 0) {
|
|
26
31
|
eventMessage.logs.forEach(({ level, message }) => {
|
|
27
|
-
|
|
32
|
+
logger.log(` (${level})`, ...message);
|
|
28
33
|
});
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
if (eventMessage.exceptions.length > 0) {
|
|
32
37
|
eventMessage.exceptions.forEach(({ name, message }) => {
|
|
33
|
-
|
|
38
|
+
logger.error(` ${name}:`, message);
|
|
34
39
|
});
|
|
35
40
|
}
|
|
36
41
|
}
|
|
@@ -40,9 +45,9 @@ export function jsonPrintLogs(data: WebSocket.RawData): void {
|
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
function isScheduledEvent(
|
|
43
|
-
event: RequestEvent | ScheduledEvent
|
|
48
|
+
event: RequestEvent | ScheduledEvent | undefined | null
|
|
44
49
|
): event is ScheduledEvent {
|
|
45
|
-
return "cron" in event;
|
|
50
|
+
return Boolean(event && "cron" in event);
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
function prettifyOutcome(outcome: Outcome): string {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import checkForUpdate from "update-check";
|
|
3
|
+
import pkg from "../package.json";
|
|
4
|
+
|
|
5
|
+
export async function updateCheck(): Promise<string> {
|
|
6
|
+
let update = null;
|
|
7
|
+
try {
|
|
8
|
+
// default cache for update check is 1 day
|
|
9
|
+
update = await checkForUpdate(pkg, {
|
|
10
|
+
distTag: pkg.version.startsWith("0.0.0") ? "beta" : "latest",
|
|
11
|
+
});
|
|
12
|
+
} catch (err) {
|
|
13
|
+
// ignore error
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (update) return `(update available ${chalk.green(update.latest)})`;
|
|
17
|
+
|
|
18
|
+
return "";
|
|
19
|
+
}
|