wrangler 0.0.0-e043479 → 0.0.0-e0b9366
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/package.json +10 -4
- package/pages/functions/filepath-routing.test.ts +125 -25
- package/pages/functions/filepath-routing.ts +6 -3
- package/src/__tests__/configuration.test.ts +479 -114
- package/src/__tests__/dev.test.tsx +162 -8
- package/src/__tests__/dev2.test.tsx +152 -0
- package/src/__tests__/guess-worker-format.test.ts +9 -17
- package/src/__tests__/helpers/mock-account-id.ts +4 -0
- package/src/__tests__/helpers/mock-cfetch.ts +3 -3
- package/src/__tests__/helpers/mock-kv.ts +9 -16
- package/src/__tests__/helpers/run-in-tmp.ts +3 -0
- package/src/__tests__/https-options.test.ts +127 -0
- package/src/__tests__/index.test.ts +125 -0
- package/src/__tests__/jest.setup.ts +1 -1
- package/src/__tests__/kv.test.ts +27 -53
- package/src/__tests__/logout.test.ts +15 -13
- package/src/__tests__/pages.test.ts +44 -0
- package/src/__tests__/publish.test.ts +504 -32
- package/src/__tests__/route.test.ts +45 -0
- package/src/__tests__/whoami.test.tsx +21 -7
- package/src/bundle.ts +20 -11
- package/src/cfetch/internal.ts +11 -5
- package/src/config/config.ts +53 -44
- package/src/config/validation-helpers.ts +110 -12
- package/src/config/validation.ts +59 -41
- package/src/{api/preview.ts → create-worker-preview.ts} +23 -4
- package/src/{api/form_data.ts → create-worker-upload-form.ts} +1 -1
- package/src/dev/dev.tsx +357 -0
- package/src/dev/local.tsx +241 -0
- package/src/dev/remote.tsx +201 -0
- package/src/dev/use-esbuild.ts +100 -0
- package/src/entry.ts +111 -9
- package/src/https-options.ts +122 -0
- package/src/index.tsx +171 -109
- package/src/inspect.ts +9 -1
- package/src/{kv.tsx → kv.ts} +0 -0
- package/src/module-collection.ts +85 -2
- package/src/open-in-browser.ts +14 -2
- package/src/pages.tsx +1 -1
- package/src/proxy.ts +102 -40
- package/src/publish.ts +41 -50
- package/src/reporting.ts +25 -9
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +51 -16
- package/src/user.tsx +132 -77
- package/src/{api/worker.ts → worker.ts} +0 -23
- package/wrangler-dist/cli.js +5012 -3107
- package/wrangler-dist/cli.js.map +3 -3
- package/src/__tests__/helpers/mock-user.ts +0 -27
- package/src/dev.tsx +0 -960
- package/src/guess-worker-format.ts +0 -68
|
@@ -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
|
@@ -4,32 +4,31 @@ import ignore from "ignore";
|
|
|
4
4
|
import xxhash from "xxhash-wasm";
|
|
5
5
|
import {
|
|
6
6
|
createNamespace,
|
|
7
|
+
getKeyValue,
|
|
7
8
|
listNamespaceKeys,
|
|
8
9
|
listNamespaces,
|
|
9
10
|
putBulkKeyValue,
|
|
10
11
|
} from "./kv";
|
|
11
12
|
import type { Config } from "./config";
|
|
12
|
-
import type { KeyValue } from "./kv";
|
|
13
|
+
import type { KeyValue, NamespaceKeyInfo } from "./kv";
|
|
13
14
|
import type { XXHashAPI } from "xxhash-wasm";
|
|
14
15
|
|
|
15
16
|
/** Paths to always ignore. */
|
|
16
|
-
const ALWAYS_IGNORE = ["node_modules"];
|
|
17
|
-
const HIDDEN_FILES_TO_INCLUDE = [
|
|
17
|
+
const ALWAYS_IGNORE = new Set(["node_modules"]);
|
|
18
|
+
const HIDDEN_FILES_TO_INCLUDE = new Set([
|
|
18
19
|
".well-known", // See https://datatracker.ietf.org/doc/html/rfc8615
|
|
19
|
-
];
|
|
20
|
+
]);
|
|
21
|
+
const FIVE_MINUTES = 60 * 5; // expressed in seconds, since that's what the api expects
|
|
20
22
|
|
|
21
23
|
async function* getFilesInFolder(dirPath: string): AsyncIterable<string> {
|
|
22
24
|
const files = await readdir(dirPath, { withFileTypes: true });
|
|
23
25
|
for (const file of files) {
|
|
24
26
|
// Skip files that we never want to process.
|
|
25
|
-
if (ALWAYS_IGNORE.
|
|
27
|
+
if (ALWAYS_IGNORE.has(file.name)) {
|
|
26
28
|
continue;
|
|
27
29
|
}
|
|
28
30
|
// Skip hidden files (starting with .) except for some special ones
|
|
29
|
-
if (
|
|
30
|
-
file.name.startsWith(".") &&
|
|
31
|
-
!HIDDEN_FILES_TO_INCLUDE.some((p) => file.name === p)
|
|
32
|
-
) {
|
|
31
|
+
if (file.name.startsWith(".") && !HIDDEN_FILES_TO_INCLUDE.has(file.name)) {
|
|
33
32
|
continue;
|
|
34
33
|
}
|
|
35
34
|
// TODO: follow symlinks??
|
|
@@ -126,16 +125,18 @@ export async function syncAssets(
|
|
|
126
125
|
|
|
127
126
|
// let's get all the keys in this namespace
|
|
128
127
|
const result = await listNamespaceKeys(accountId, namespace);
|
|
129
|
-
const
|
|
128
|
+
const keyMap = result.reduce<Record<string, NamespaceKeyInfo>>(
|
|
129
|
+
(km, key) => Object.assign(km, { [key.name]: key }),
|
|
130
|
+
{}
|
|
131
|
+
);
|
|
130
132
|
|
|
131
133
|
const manifest: Record<string, string> = {};
|
|
132
|
-
const
|
|
134
|
+
const toUpload: KeyValue[] = [];
|
|
133
135
|
|
|
134
136
|
const include = createPatternMatcher(siteAssets.includePatterns, false);
|
|
135
137
|
const exclude = createPatternMatcher(siteAssets.excludePatterns, true);
|
|
136
138
|
const hasher = await xxhash();
|
|
137
139
|
|
|
138
|
-
// TODO: this can be more efficient by parallelising
|
|
139
140
|
for await (const file of getFilesInFolder(siteAssets.baseDirectory)) {
|
|
140
141
|
if (!include(file)) {
|
|
141
142
|
continue;
|
|
@@ -148,13 +149,13 @@ export async function syncAssets(
|
|
|
148
149
|
console.log(`reading ${file}...`);
|
|
149
150
|
const content = await readFile(file, "base64");
|
|
150
151
|
|
|
151
|
-
const assetKey =
|
|
152
|
+
const assetKey = hashAsset(hasher, file, content);
|
|
152
153
|
validateAssetKey(assetKey);
|
|
153
154
|
|
|
154
155
|
// now put each of the files into kv
|
|
155
|
-
if (!
|
|
156
|
+
if (!(assetKey in keyMap) || keyMap[assetKey].expiration) {
|
|
156
157
|
console.log(`uploading as ${assetKey}...`);
|
|
157
|
-
|
|
158
|
+
toUpload.push({
|
|
158
159
|
key: assetKey,
|
|
159
160
|
value: content,
|
|
160
161
|
base64: true,
|
|
@@ -162,9 +163,43 @@ export async function syncAssets(
|
|
|
162
163
|
} else {
|
|
163
164
|
console.log(`skipping - already uploaded`);
|
|
164
165
|
}
|
|
166
|
+
// remove the key from the set so we know we've seen it
|
|
167
|
+
delete keyMap[assetKey];
|
|
165
168
|
manifest[path.relative(siteAssets.baseDirectory, file)] = assetKey;
|
|
166
169
|
}
|
|
167
|
-
|
|
170
|
+
|
|
171
|
+
// `keyMap` now contains the assets that we need to expire
|
|
172
|
+
|
|
173
|
+
let toExpire: KeyValue[] = [];
|
|
174
|
+
for (const asset of Object.values(keyMap)) {
|
|
175
|
+
if (!asset.expiration) {
|
|
176
|
+
console.log(`expiring unused ${asset.name}...`);
|
|
177
|
+
toExpire.push({
|
|
178
|
+
key: asset.name,
|
|
179
|
+
value: "", // we'll fill all the values in one go
|
|
180
|
+
// we use expiration_ttl, since we can't trust the time
|
|
181
|
+
// that a deploy source might provide (eg - https://github.com/cloudflare/wrangler/issues/2224)
|
|
182
|
+
expiration_ttl: FIVE_MINUTES,
|
|
183
|
+
base64: true,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// TODO: batch these in groups if it causes problems
|
|
189
|
+
toExpire = await Promise.all(
|
|
190
|
+
toExpire.map(async (asset) => ({
|
|
191
|
+
...asset,
|
|
192
|
+
// it would be great if we didn't have to do this fetch at all
|
|
193
|
+
value: await getKeyValue(accountId, namespace, asset.key),
|
|
194
|
+
}))
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
await putBulkKeyValue(
|
|
198
|
+
accountId,
|
|
199
|
+
namespace,
|
|
200
|
+
toUpload.concat(toExpire),
|
|
201
|
+
() => {}
|
|
202
|
+
);
|
|
168
203
|
return { manifest, namespace };
|
|
169
204
|
}
|
|
170
205
|
|
package/src/user.tsx
CHANGED
|
@@ -207,7 +207,7 @@
|
|
|
207
207
|
|
|
208
208
|
import assert from "node:assert";
|
|
209
209
|
import { webcrypto as crypto } from "node:crypto";
|
|
210
|
-
import {
|
|
210
|
+
import { writeFileSync, mkdirSync, rmSync } from "node:fs";
|
|
211
211
|
import http from "node:http";
|
|
212
212
|
import os from "node:os";
|
|
213
213
|
import path from "node:path";
|
|
@@ -222,6 +222,7 @@ import { fetch } from "undici";
|
|
|
222
222
|
import { getCloudflareApiBaseUrl } from "./cfetch";
|
|
223
223
|
import { getEnvironmentVariableFactory } from "./environment-variables";
|
|
224
224
|
import openInBrowser from "./open-in-browser";
|
|
225
|
+
import { readFileSync } from "./parse";
|
|
225
226
|
import type { Item as SelectInputItem } from "ink-select-input/build/SelectInput";
|
|
226
227
|
import type { ParsedUrlQuery } from "node:querystring";
|
|
227
228
|
import type { Response } from "undici";
|
|
@@ -251,17 +252,45 @@ interface PKCECodes {
|
|
|
251
252
|
codeVerifier: string;
|
|
252
253
|
}
|
|
253
254
|
|
|
254
|
-
|
|
255
|
-
|
|
255
|
+
/**
|
|
256
|
+
* The module level state of the authentication flow.
|
|
257
|
+
*/
|
|
258
|
+
interface State extends AuthTokens {
|
|
256
259
|
authorizationCode?: string;
|
|
257
260
|
codeChallenge?: string;
|
|
258
261
|
codeVerifier?: string;
|
|
259
262
|
hasAuthCodeBeenExchangedForAccessToken?: boolean;
|
|
260
|
-
refreshToken?: RefreshToken; // persist
|
|
261
263
|
stateQueryParam?: string;
|
|
262
264
|
scopes?: Scope[];
|
|
263
265
|
}
|
|
264
266
|
|
|
267
|
+
/**
|
|
268
|
+
* The tokens related to authentication.
|
|
269
|
+
*/
|
|
270
|
+
interface AuthTokens {
|
|
271
|
+
accessToken?: AccessToken;
|
|
272
|
+
refreshToken?: RefreshToken;
|
|
273
|
+
/** @deprecated - this field was only provided by the deprecated `wrangler1 config` command. */
|
|
274
|
+
apiToken?: string;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* The path to the config file that holds user authentication data,
|
|
279
|
+
* relative to the user's home directory.
|
|
280
|
+
*/
|
|
281
|
+
export const USER_AUTH_CONFIG_FILE = ".wrangler/config/default.toml";
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* The data that may be read from the `USER_CONFIG_FILE`.
|
|
285
|
+
*/
|
|
286
|
+
export interface UserAuthConfig {
|
|
287
|
+
oauth_token?: string;
|
|
288
|
+
refresh_token?: string;
|
|
289
|
+
expiration_time?: string;
|
|
290
|
+
/** @deprecated - this field was only provided by the deprecated `wrangler1 config` command. */
|
|
291
|
+
api_token?: string;
|
|
292
|
+
}
|
|
293
|
+
|
|
265
294
|
interface RefreshToken {
|
|
266
295
|
value: string;
|
|
267
296
|
}
|
|
@@ -285,6 +314,8 @@ const Scopes = {
|
|
|
285
314
|
"workers_scripts:write":
|
|
286
315
|
"See and change Cloudflare Workers scripts, durable objects, subdomains, triggers, and tail data.",
|
|
287
316
|
"workers_tail:read": "See Cloudflare Workers tail and script data.",
|
|
317
|
+
"pages:write":
|
|
318
|
+
"See and change Cloudflare Pages projects, settings and deployments.",
|
|
288
319
|
"zone:read": "Grants read level access to account zone.",
|
|
289
320
|
} as const;
|
|
290
321
|
|
|
@@ -309,60 +340,63 @@ const TOKEN_URL = "https://dash.cloudflare.com/oauth2/token";
|
|
|
309
340
|
const CALLBACK_URL = "http://localhost:8976/oauth/callback";
|
|
310
341
|
const REVOKE_URL = "https://dash.cloudflare.com/oauth2/revoke";
|
|
311
342
|
|
|
312
|
-
|
|
313
|
-
let initialised = false;
|
|
343
|
+
let LocalState: State = getAuthTokens();
|
|
314
344
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
345
|
+
/**
|
|
346
|
+
* Compute the current auth tokens.
|
|
347
|
+
*/
|
|
348
|
+
function getAuthTokens(): AuthTokens {
|
|
319
349
|
// get refreshToken/accessToken from fs if exists
|
|
320
350
|
try {
|
|
321
351
|
// if the environment variable is available, use that
|
|
322
352
|
const apiTokenFromEnv = getCloudflareAPITokenFromEnv();
|
|
323
353
|
if (apiTokenFromEnv) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
354
|
+
return {
|
|
355
|
+
accessToken: {
|
|
356
|
+
value: apiTokenFromEnv,
|
|
357
|
+
expiry: "3021-12-31T23:59:59+00:00",
|
|
358
|
+
},
|
|
327
359
|
};
|
|
328
|
-
initialised = true;
|
|
329
|
-
return;
|
|
330
360
|
}
|
|
331
361
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
);
|
|
337
|
-
const { oauth_token, refresh_token, expiration_time } = toml as {
|
|
338
|
-
oauth_token: string;
|
|
339
|
-
refresh_token: string;
|
|
340
|
-
expiration_time: string;
|
|
341
|
-
};
|
|
362
|
+
// otherwise try loading from the user auth config file.
|
|
363
|
+
const { oauth_token, refresh_token, expiration_time, api_token } =
|
|
364
|
+
readAuthConfigFile();
|
|
365
|
+
|
|
342
366
|
if (oauth_token) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
367
|
+
return {
|
|
368
|
+
accessToken: {
|
|
369
|
+
value: oauth_token,
|
|
370
|
+
// If there is no `expiration_time` field then set it to an old date, to cause it to expire immediately.
|
|
371
|
+
expiry: expiration_time ?? "2000-01-01:00:00:00+00:00",
|
|
372
|
+
},
|
|
373
|
+
refreshToken: { value: refresh_token ?? "" },
|
|
374
|
+
};
|
|
375
|
+
} else if (api_token) {
|
|
376
|
+
return { apiToken: api_token };
|
|
377
|
+
} else {
|
|
378
|
+
return {};
|
|
347
379
|
}
|
|
348
|
-
} catch
|
|
349
|
-
|
|
350
|
-
// console.error(err);
|
|
380
|
+
} catch {
|
|
381
|
+
return {};
|
|
351
382
|
}
|
|
352
|
-
initialised = true;
|
|
353
383
|
}
|
|
354
384
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
);
|
|
361
|
-
}
|
|
385
|
+
/**
|
|
386
|
+
* Run the initialisation of the auth state, in the case that something changed.
|
|
387
|
+
*/
|
|
388
|
+
export function reinitialiseAuthTokens(): void {
|
|
389
|
+
LocalState = getAuthTokens();
|
|
362
390
|
}
|
|
363
391
|
|
|
364
392
|
export function getAPIToken(): string | undefined {
|
|
365
|
-
|
|
393
|
+
if (LocalState.apiToken) {
|
|
394
|
+
console.warn(
|
|
395
|
+
"It looks like you have used Wrangler 1's `config` command to login with an API token.\n" +
|
|
396
|
+
"This is no longer supported in the current version of Wrangler.\n" +
|
|
397
|
+
"If you wish to authenticate via an API token then please set the `CLOUDFLARE_API_TOKEN` environment variable."
|
|
398
|
+
);
|
|
399
|
+
}
|
|
366
400
|
return LocalState.accessToken?.value;
|
|
367
401
|
}
|
|
368
402
|
|
|
@@ -798,21 +832,24 @@ function generateRandomState(lengthOfState: number): string {
|
|
|
798
832
|
.join("");
|
|
799
833
|
}
|
|
800
834
|
|
|
801
|
-
|
|
802
|
-
|
|
835
|
+
export function writeAuthConfigFile(config: UserAuthConfig) {
|
|
836
|
+
mkdirSync(path.join(os.homedir(), ".wrangler/config/"), {
|
|
803
837
|
recursive: true,
|
|
804
838
|
});
|
|
805
|
-
|
|
806
|
-
path.join(os.homedir(),
|
|
807
|
-
|
|
808
|
-
oauth_token = "${tokenData.token?.value || ""}"
|
|
809
|
-
refresh_token = "${tokenData.refreshToken?.value}"
|
|
810
|
-
expiration_time = "${tokenData.token?.expiry}"
|
|
811
|
-
`,
|
|
839
|
+
writeFileSync(
|
|
840
|
+
path.join(os.homedir(), USER_AUTH_CONFIG_FILE),
|
|
841
|
+
TOML.stringify(config as TOML.JsonMap),
|
|
812
842
|
{ encoding: "utf-8" }
|
|
813
843
|
);
|
|
814
844
|
}
|
|
815
845
|
|
|
846
|
+
function readAuthConfigFile(): UserAuthConfig {
|
|
847
|
+
const toml = TOML.parse(
|
|
848
|
+
readFileSync(path.join(os.homedir(), USER_AUTH_CONFIG_FILE))
|
|
849
|
+
);
|
|
850
|
+
return toml;
|
|
851
|
+
}
|
|
852
|
+
|
|
816
853
|
type LoginProps = {
|
|
817
854
|
scopes?: Scope[];
|
|
818
855
|
};
|
|
@@ -822,7 +859,7 @@ export async function loginOrRefreshIfRequired(
|
|
|
822
859
|
): Promise<boolean> {
|
|
823
860
|
// TODO: if there already is a token, then try refreshing
|
|
824
861
|
// TODO: ask permission before opening browser
|
|
825
|
-
if (!
|
|
862
|
+
if (!getAPIToken()) {
|
|
826
863
|
// Not logged in.
|
|
827
864
|
// If we are not interactive, we cannot ask the user to login
|
|
828
865
|
return isInteractive && (await login());
|
|
@@ -834,6 +871,7 @@ export async function loginOrRefreshIfRequired(
|
|
|
834
871
|
}
|
|
835
872
|
|
|
836
873
|
export async function login(props?: LoginProps): Promise<boolean> {
|
|
874
|
+
console.log("Attempting to login via OAuth...");
|
|
837
875
|
const urlToOpen = await getAuthURL(props?.scopes);
|
|
838
876
|
await openInBrowser(urlToOpen);
|
|
839
877
|
let server: http.Server;
|
|
@@ -892,8 +930,12 @@ export async function login(props?: LoginProps): Promise<boolean> {
|
|
|
892
930
|
finish(false, new ErrorNoAuthCode());
|
|
893
931
|
return;
|
|
894
932
|
} else {
|
|
895
|
-
const
|
|
896
|
-
|
|
933
|
+
const exchange = await exchangeAuthCodeForAccessToken();
|
|
934
|
+
writeAuthConfigFile({
|
|
935
|
+
oauth_token: exchange.token?.value ?? "",
|
|
936
|
+
expiration_time: exchange.token?.expiry,
|
|
937
|
+
refresh_token: exchange.refreshToken?.value,
|
|
938
|
+
});
|
|
897
939
|
res.writeHead(307, {
|
|
898
940
|
Location:
|
|
899
941
|
"https://welcome.developers.workers.dev/wrangler-oauth-consent-granted",
|
|
@@ -901,9 +943,7 @@ export async function login(props?: LoginProps): Promise<boolean> {
|
|
|
901
943
|
res.end(() => {
|
|
902
944
|
finish(true);
|
|
903
945
|
});
|
|
904
|
-
console.log(
|
|
905
|
-
`Successfully configured. You can find your configuration file at: ${os.homedir()}/.wrangler/config/default.toml`
|
|
906
|
-
);
|
|
946
|
+
console.log(`Successfully logged in.`);
|
|
907
947
|
|
|
908
948
|
return;
|
|
909
949
|
}
|
|
@@ -920,18 +960,22 @@ export async function login(props?: LoginProps): Promise<boolean> {
|
|
|
920
960
|
/**
|
|
921
961
|
* Checks to see if the access token has expired.
|
|
922
962
|
*/
|
|
923
|
-
|
|
924
|
-
throwIfNotInitialised();
|
|
963
|
+
function isAccessTokenExpired(): boolean {
|
|
925
964
|
const { accessToken } = LocalState;
|
|
926
965
|
return Boolean(accessToken && new Date() >= new Date(accessToken.expiry));
|
|
927
966
|
}
|
|
928
967
|
|
|
929
|
-
|
|
930
|
-
throwIfNotInitialised();
|
|
968
|
+
async function refreshToken(): Promise<boolean> {
|
|
931
969
|
// refresh
|
|
932
970
|
try {
|
|
933
|
-
const
|
|
934
|
-
|
|
971
|
+
const {
|
|
972
|
+
token: { value: oauth_token, expiry: expiration_time } = {
|
|
973
|
+
value: "",
|
|
974
|
+
expiry: "",
|
|
975
|
+
},
|
|
976
|
+
refreshToken: { value: refresh_token } = {},
|
|
977
|
+
} = await exchangeRefreshTokenForAccessToken();
|
|
978
|
+
writeAuthConfigFile({ oauth_token, expiration_time, refresh_token });
|
|
935
979
|
return true;
|
|
936
980
|
} catch (err) {
|
|
937
981
|
console.error(err);
|
|
@@ -940,10 +984,28 @@ export async function refreshToken(): Promise<boolean> {
|
|
|
940
984
|
}
|
|
941
985
|
|
|
942
986
|
export async function logout(): Promise<void> {
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
987
|
+
if (!LocalState.accessToken) {
|
|
988
|
+
if (!LocalState.refreshToken) {
|
|
989
|
+
console.log("Not logged in, exiting...");
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
const body =
|
|
994
|
+
`client_id=${encodeURIComponent(CLIENT_ID)}&` +
|
|
995
|
+
`token_type_hint=refresh_token&` +
|
|
996
|
+
`token=${encodeURIComponent(LocalState.refreshToken?.value || "")}`;
|
|
997
|
+
|
|
998
|
+
const response = await fetch(REVOKE_URL, {
|
|
999
|
+
method: "POST",
|
|
1000
|
+
body,
|
|
1001
|
+
headers: {
|
|
1002
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
1003
|
+
},
|
|
1004
|
+
});
|
|
1005
|
+
await response.text(); // blank text? would be nice if it was something meaningful
|
|
1006
|
+
console.log(
|
|
1007
|
+
"💁 Wrangler is configured with an OAuth token. The token has been successfully revoked"
|
|
1008
|
+
);
|
|
947
1009
|
}
|
|
948
1010
|
const body =
|
|
949
1011
|
`client_id=${encodeURIComponent(CLIENT_ID)}&` +
|
|
@@ -958,19 +1020,12 @@ export async function logout(): Promise<void> {
|
|
|
958
1020
|
},
|
|
959
1021
|
});
|
|
960
1022
|
await response.text(); // blank text? would be nice if it was something meaningful
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
);
|
|
964
|
-
// delete the file
|
|
965
|
-
await rm(path.join(os.homedir(), ".wrangler/config/default.toml"));
|
|
966
|
-
console.log(
|
|
967
|
-
`Removing ${os.homedir()}/.wrangler/config/default.toml.. success!`
|
|
968
|
-
);
|
|
1023
|
+
rmSync(path.join(os.homedir(), USER_AUTH_CONFIG_FILE));
|
|
1024
|
+
console.log(`Successfully logged out.`);
|
|
969
1025
|
}
|
|
970
1026
|
|
|
971
|
-
export function listScopes(): void {
|
|
972
|
-
|
|
973
|
-
console.log("💁 Available scopes:");
|
|
1027
|
+
export function listScopes(message = "💁 Available scopes:"): void {
|
|
1028
|
+
console.log(message);
|
|
974
1029
|
const data = ScopeKeys.map((scope: Scope) => ({
|
|
975
1030
|
Scope: scope,
|
|
976
1031
|
Description: Scopes[scope],
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import { fetch } from "undici";
|
|
2
|
-
import { previewToken } from "./preview";
|
|
3
|
-
import type { CfPreviewToken } from "./preview";
|
|
4
|
-
|
|
5
1
|
/**
|
|
6
2
|
* A Cloudflare account.
|
|
7
3
|
*/
|
|
@@ -165,22 +161,3 @@ export interface CfWorkerContext {
|
|
|
165
161
|
legacyEnv: boolean | undefined;
|
|
166
162
|
zone: { id: string; host: string } | undefined;
|
|
167
163
|
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* A stub to create a Cloudflare Worker preview.
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
* const {value, host} = await createWorker(init, acct);
|
|
174
|
-
*/
|
|
175
|
-
export async function createWorker(
|
|
176
|
-
init: CfWorkerInit,
|
|
177
|
-
account: CfAccount,
|
|
178
|
-
ctx: CfWorkerContext
|
|
179
|
-
): Promise<CfPreviewToken> {
|
|
180
|
-
const token = await previewToken(account, init, ctx);
|
|
181
|
-
const response = await fetch(token.prewarmUrl.href, { method: "POST" });
|
|
182
|
-
if (!response.ok) {
|
|
183
|
-
// console.error("worker failed to prewarm: ", response.statusText);
|
|
184
|
-
}
|
|
185
|
-
return token;
|
|
186
|
-
}
|