wrangler 0.0.0-e1c615f → 0.0.0-e3cab74
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 +28 -13
- package/pages/functions/buildWorker.ts +6 -1
- package/pages/functions/filepath-routing.test.ts +112 -28
- package/pages/functions/filepath-routing.ts +88 -131
- package/pages/functions/routes.ts +11 -18
- package/pages/functions/template-worker.ts +21 -28
- package/src/__tests__/configuration.test.ts +2185 -0
- package/src/__tests__/dev.test.tsx +56 -9
- package/src/__tests__/guess-worker-format.test.ts +66 -0
- package/src/__tests__/{clipboardy-mock.js → helpers/clipboardy-mock.js} +0 -0
- package/src/__tests__/helpers/cmd-shim.d.ts +11 -0
- package/src/__tests__/helpers/faye-websocket.d.ts +6 -0
- package/src/__tests__/helpers/mock-account-id.ts +30 -0
- package/src/__tests__/helpers/mock-bin.ts +36 -0
- package/src/__tests__/{mock-cfetch.ts → helpers/mock-cfetch.ts} +53 -17
- package/src/__tests__/helpers/mock-console.ts +62 -0
- package/src/__tests__/{mock-dialogs.ts → helpers/mock-dialogs.ts} +1 -1
- package/src/__tests__/helpers/mock-kv.ts +40 -0
- package/src/__tests__/helpers/mock-user.ts +27 -0
- package/src/__tests__/helpers/mock-web-socket.ts +29 -0
- package/src/__tests__/helpers/run-in-tmp.ts +29 -0
- package/src/__tests__/helpers/run-wrangler.ts +16 -0
- package/src/__tests__/helpers/write-wrangler-toml.ts +17 -0
- package/src/__tests__/index.test.ts +655 -76
- package/src/__tests__/jest.setup.ts +37 -2
- package/src/__tests__/kv.test.ts +441 -398
- package/src/__tests__/logout.test.ts +50 -0
- package/src/__tests__/package-manager.test.ts +206 -0
- package/src/__tests__/parse.test.ts +322 -0
- package/src/__tests__/publish.test.ts +2406 -0
- package/src/__tests__/r2.test.ts +198 -0
- package/src/__tests__/secret.test.ts +326 -0
- package/src/__tests__/sentry.test.ts +146 -0
- package/src/__tests__/tail.test.ts +564 -0
- package/src/__tests__/whoami.test.tsx +86 -0
- package/src/api/form_data.ts +112 -26
- package/src/api/preview.ts +34 -15
- package/src/api/worker.ts +58 -27
- package/src/bundle.ts +133 -0
- package/src/cfetch/index.ts +21 -19
- package/src/cfetch/internal.ts +85 -21
- package/src/cli.ts +10 -0
- package/src/config/README.md +107 -0
- package/src/config/config.ts +265 -0
- package/src/config/diagnostics.ts +80 -0
- package/src/config/environment.ts +305 -0
- package/src/config/index.ts +52 -0
- package/src/config/validation-helpers.ts +370 -0
- package/src/config/validation.ts +1017 -0
- package/src/dev.tsx +455 -368
- package/src/dialogs.tsx +2 -2
- package/src/entry.ts +57 -0
- package/src/environment-variables.ts +33 -0
- package/src/guess-worker-format.ts +68 -0
- package/src/index.tsx +1044 -646
- package/src/inspect.ts +609 -0
- package/src/kv.tsx +47 -39
- package/src/module-collection.ts +142 -36
- package/src/open-in-browser.ts +13 -0
- package/src/package-manager.ts +126 -0
- package/src/pages.tsx +139 -62
- package/src/parse.ts +183 -0
- package/src/paths.ts +26 -0
- package/src/proxy.ts +350 -77
- package/src/publish.ts +307 -289
- package/src/r2.ts +50 -0
- package/src/reporting.ts +115 -0
- package/src/sites.tsx +183 -56
- package/src/tail/filters.ts +279 -0
- package/src/tail/index.ts +299 -0
- package/src/tail/printing.ts +62 -0
- package/src/user.tsx +137 -110
- package/src/whoami.tsx +69 -0
- package/templates/new-worker.js +15 -0
- package/templates/new-worker.ts +15 -0
- package/{static-asset-facade.js → templates/static-asset-facade.js} +0 -0
- package/templates/tsconfig.json +105 -0
- package/wrangler-dist/cli.js +127861 -111486
- package/wrangler-dist/cli.js.map +3 -3
- package/src/__tests__/run-in-tmp.ts +0 -19
- package/src/__tests__/run-wrangler.ts +0 -32
- package/src/api/inspect.ts +0 -430
- package/src/config.ts +0 -131
- package/src/tail.tsx +0 -73
package/src/user.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Based heavily on code from https://github.com/BitySA/oauth2-auth-code-pkce */
|
|
2
2
|
|
|
3
|
-
/*
|
|
3
|
+
/*
|
|
4
4
|
|
|
5
5
|
Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -205,25 +205,42 @@
|
|
|
205
205
|
limitations under the License.
|
|
206
206
|
*/
|
|
207
207
|
|
|
208
|
-
import
|
|
209
|
-
import { render } from "ink";
|
|
210
|
-
import Table from "ink-table";
|
|
211
|
-
import SelectInput from "ink-select-input";
|
|
212
|
-
import fetch from "node-fetch";
|
|
208
|
+
import assert from "node:assert";
|
|
213
209
|
import { webcrypto as crypto } from "node:crypto";
|
|
214
|
-
import { TextEncoder } from "node:util";
|
|
215
|
-
import open from "open";
|
|
216
|
-
import url from "node:url";
|
|
217
|
-
import http from "node:http";
|
|
218
210
|
import { readFile, writeFile, rm, mkdir } from "node:fs/promises";
|
|
219
|
-
import
|
|
220
|
-
import process from "node:process";
|
|
211
|
+
import http from "node:http";
|
|
221
212
|
import os from "node:os";
|
|
213
|
+
import path from "node:path";
|
|
214
|
+
import url from "node:url";
|
|
215
|
+
import { TextEncoder } from "node:util";
|
|
222
216
|
import TOML from "@iarna/toml";
|
|
223
|
-
import
|
|
217
|
+
import { render, Text } from "ink";
|
|
218
|
+
import SelectInput from "ink-select-input";
|
|
219
|
+
import Table from "ink-table";
|
|
220
|
+
import React from "react";
|
|
221
|
+
import { fetch } from "undici";
|
|
222
|
+
import { getCloudflareApiBaseUrl } from "./cfetch";
|
|
223
|
+
import { getEnvironmentVariableFactory } from "./environment-variables";
|
|
224
|
+
import openInBrowser from "./open-in-browser";
|
|
225
|
+
import type { Item as SelectInputItem } from "ink-select-input/build/SelectInput";
|
|
224
226
|
import type { ParsedUrlQuery } from "node:querystring";
|
|
225
|
-
import {
|
|
226
|
-
|
|
227
|
+
import type { Response } from "undici";
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Try to read the API token from the environment.
|
|
231
|
+
*/
|
|
232
|
+
const getCloudflareAPITokenFromEnv = getEnvironmentVariableFactory({
|
|
233
|
+
variableName: "CLOUDFLARE_API_TOKEN",
|
|
234
|
+
deprecatedName: "CF_API_TOKEN",
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Try to read the account ID from the environment.
|
|
239
|
+
*/
|
|
240
|
+
const getCloudflareAccountIdFromEnv = getEnvironmentVariableFactory({
|
|
241
|
+
variableName: "CLOUDFLARE_ACCOUNT_ID",
|
|
242
|
+
deprecatedName: "CF_ACCOUNT_ID",
|
|
243
|
+
});
|
|
227
244
|
|
|
228
245
|
/**
|
|
229
246
|
* An implementation of rfc6749#section-4.1 and rfc7636.
|
|
@@ -254,38 +271,37 @@ interface AccessToken {
|
|
|
254
271
|
expiry: string;
|
|
255
272
|
}
|
|
256
273
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
"
|
|
271
|
-
"
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
];
|
|
274
|
+
const Scopes = {
|
|
275
|
+
"account:read":
|
|
276
|
+
"See your account info such as account details, analytics, and memberships.",
|
|
277
|
+
"user:read":
|
|
278
|
+
"See your user info such as name, email address, and account memberships.",
|
|
279
|
+
"workers:write":
|
|
280
|
+
"See and change Cloudflare Workers data such as zones, KV storage, namespaces, scripts, and routes.",
|
|
281
|
+
"workers_kv:write":
|
|
282
|
+
"See and change Cloudflare Workers KV Storage data such as keys and namespaces.",
|
|
283
|
+
"workers_routes:write":
|
|
284
|
+
"See and change Cloudflare Workers data such as filters and routes.",
|
|
285
|
+
"workers_scripts:write":
|
|
286
|
+
"See and change Cloudflare Workers scripts, durable objects, subdomains, triggers, and tail data.",
|
|
287
|
+
"workers_tail:read": "See Cloudflare Workers tail and script data.",
|
|
288
|
+
"zone:read": "Grants read level access to account zone.",
|
|
289
|
+
} as const;
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* The possible keys for a Scope.
|
|
293
|
+
*
|
|
294
|
+
* "offline_access" is automatically included.
|
|
295
|
+
*/
|
|
296
|
+
type Scope = keyof typeof Scopes;
|
|
297
|
+
|
|
298
|
+
const ScopeKeys = Object.keys(Scopes) as Scope[];
|
|
299
|
+
|
|
300
|
+
export function validateScopeKeys(
|
|
301
|
+
scopes: string[]
|
|
302
|
+
): scopes is typeof ScopeKeys {
|
|
303
|
+
return scopes.every((scope) => scope in Scopes);
|
|
304
|
+
}
|
|
289
305
|
|
|
290
306
|
const CLIENT_ID = "54d11594-84e4-41aa-b438-e81b8fa78ee7";
|
|
291
307
|
const AUTH_URL = "https://dash.cloudflare.com/oauth2/auth";
|
|
@@ -298,14 +314,15 @@ let initialised = false;
|
|
|
298
314
|
|
|
299
315
|
// we do this because we have some async stuff
|
|
300
316
|
// TODO: this should just happen in the top level
|
|
301
|
-
//
|
|
317
|
+
// and we should figure out how to do top level await
|
|
302
318
|
export async function initialise(): Promise<void> {
|
|
303
|
-
// get
|
|
319
|
+
// get refreshToken/accessToken from fs if exists
|
|
304
320
|
try {
|
|
305
|
-
// if
|
|
306
|
-
|
|
321
|
+
// if the environment variable is available, use that
|
|
322
|
+
const apiTokenFromEnv = getCloudflareAPITokenFromEnv();
|
|
323
|
+
if (apiTokenFromEnv) {
|
|
307
324
|
LocalState.accessToken = {
|
|
308
|
-
value:
|
|
325
|
+
value: apiTokenFromEnv,
|
|
309
326
|
expiry: "3021-12-31T23:59:59+00:00",
|
|
310
327
|
};
|
|
311
328
|
initialised = true;
|
|
@@ -344,11 +361,7 @@ function throwIfNotInitialised() {
|
|
|
344
361
|
}
|
|
345
362
|
}
|
|
346
363
|
|
|
347
|
-
export function getAPIToken(): string {
|
|
348
|
-
if (process.env.CF_API_TOKEN) {
|
|
349
|
-
return process.env.CF_API_TOKEN;
|
|
350
|
-
}
|
|
351
|
-
|
|
364
|
+
export function getAPIToken(): string | undefined {
|
|
352
365
|
throwIfNotInitialised();
|
|
353
366
|
return LocalState.accessToken?.value;
|
|
354
367
|
}
|
|
@@ -548,7 +561,7 @@ function isReturningFromAuthServer(query: ParsedUrlQuery): boolean {
|
|
|
548
561
|
return true;
|
|
549
562
|
}
|
|
550
563
|
|
|
551
|
-
export async function getAuthURL(scopes
|
|
564
|
+
export async function getAuthURL(scopes = ScopeKeys): Promise<string> {
|
|
552
565
|
const { codeChallenge, codeVerifier } = await generatePKCECodes();
|
|
553
566
|
const stateQueryParam = generateRandomState(RECOMMENDED_STATE_LENGTH);
|
|
554
567
|
|
|
@@ -558,22 +571,30 @@ export async function getAuthURL(scopes?: string[]): Promise<string> {
|
|
|
558
571
|
stateQueryParam,
|
|
559
572
|
});
|
|
560
573
|
|
|
561
|
-
// TODO: verify that the scopes passed are legit
|
|
562
|
-
|
|
563
574
|
return (
|
|
564
575
|
AUTH_URL +
|
|
565
576
|
`?response_type=code&` +
|
|
566
577
|
`client_id=${encodeURIComponent(CLIENT_ID)}&` +
|
|
567
578
|
`redirect_uri=${encodeURIComponent(CALLBACK_URL)}&` +
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
)}&` +
|
|
579
|
+
// @ts-expect-error we add offline_access manually
|
|
580
|
+
`scope=${encodeURIComponent(scopes.concat("offline_access").join(" "))}&` +
|
|
571
581
|
`state=${stateQueryParam}&` +
|
|
572
582
|
`code_challenge=${encodeURIComponent(codeChallenge)}&` +
|
|
573
583
|
`code_challenge_method=S256`
|
|
574
584
|
);
|
|
575
585
|
}
|
|
576
586
|
|
|
587
|
+
type TokenResponse =
|
|
588
|
+
| {
|
|
589
|
+
access_token: string;
|
|
590
|
+
expires_in: number;
|
|
591
|
+
refresh_token: string;
|
|
592
|
+
scope: string;
|
|
593
|
+
}
|
|
594
|
+
| {
|
|
595
|
+
error: string;
|
|
596
|
+
};
|
|
597
|
+
|
|
577
598
|
/**
|
|
578
599
|
* Refresh an access token from the remote service.
|
|
579
600
|
*/
|
|
@@ -598,13 +619,12 @@ async function exchangeRefreshTokenForAccessToken(): Promise<AccessContext> {
|
|
|
598
619
|
throw await response.json();
|
|
599
620
|
} else {
|
|
600
621
|
try {
|
|
601
|
-
const json = await response.json();
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
};
|
|
622
|
+
const json = (await response.json()) as TokenResponse;
|
|
623
|
+
if ("error" in json) {
|
|
624
|
+
throw json.error;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const { access_token, expires_in, refresh_token, scope } = json;
|
|
608
628
|
let scopes: Scope[] = [];
|
|
609
629
|
|
|
610
630
|
const accessToken: AccessToken = {
|
|
@@ -632,20 +652,24 @@ async function exchangeRefreshTokenForAccessToken(): Promise<AccessContext> {
|
|
|
632
652
|
refreshToken: LocalState.refreshToken,
|
|
633
653
|
};
|
|
634
654
|
return accessContext;
|
|
635
|
-
} catch (
|
|
636
|
-
const error = err?.error || "There was a network error.";
|
|
655
|
+
} catch (error) {
|
|
637
656
|
switch (error) {
|
|
638
657
|
case "invalid_grant":
|
|
639
|
-
console.
|
|
658
|
+
console.warn(
|
|
640
659
|
"Expired! Auth code or refresh token needs to be renewed."
|
|
641
660
|
);
|
|
642
661
|
// alert("Redirecting to auth server to obtain a new auth grant code.");
|
|
643
662
|
// TODO: return refreshAuthCodeOrRefreshToken();
|
|
644
663
|
break;
|
|
645
664
|
default:
|
|
665
|
+
console.error(error);
|
|
646
666
|
break;
|
|
647
667
|
}
|
|
648
|
-
|
|
668
|
+
if (typeof error === "string") {
|
|
669
|
+
throw toErrorClass(error);
|
|
670
|
+
} else {
|
|
671
|
+
throw error;
|
|
672
|
+
}
|
|
649
673
|
}
|
|
650
674
|
}
|
|
651
675
|
}
|
|
@@ -686,13 +710,11 @@ async function exchangeAuthCodeForAccessToken(): Promise<AccessContext> {
|
|
|
686
710
|
}
|
|
687
711
|
throw toErrorClass(error);
|
|
688
712
|
}
|
|
689
|
-
const json = await response.json();
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
scope: string;
|
|
695
|
-
};
|
|
713
|
+
const json = (await response.json()) as TokenResponse;
|
|
714
|
+
if ("error" in json) {
|
|
715
|
+
throw new Error(json.error);
|
|
716
|
+
}
|
|
717
|
+
const { access_token, expires_in, refresh_token, scope } = json;
|
|
696
718
|
let scopes: Scope[] = [];
|
|
697
719
|
LocalState.hasAuthCodeBeenExchangedForAccessToken = true;
|
|
698
720
|
|
|
@@ -792,7 +814,7 @@ expiration_time = "${tokenData.token?.expiry}"
|
|
|
792
814
|
}
|
|
793
815
|
|
|
794
816
|
type LoginProps = {
|
|
795
|
-
scopes?:
|
|
817
|
+
scopes?: Scope[];
|
|
796
818
|
};
|
|
797
819
|
|
|
798
820
|
export async function loginOrRefreshIfRequired(): Promise<boolean> {
|
|
@@ -810,18 +832,18 @@ export async function loginOrRefreshIfRequired(): Promise<boolean> {
|
|
|
810
832
|
|
|
811
833
|
export async function login(props?: LoginProps): Promise<boolean> {
|
|
812
834
|
const urlToOpen = await getAuthURL(props?.scopes);
|
|
813
|
-
await
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
let server;
|
|
817
|
-
let loginTimeoutHandle;
|
|
835
|
+
await openInBrowser(urlToOpen);
|
|
836
|
+
let server: http.Server;
|
|
837
|
+
let loginTimeoutHandle: NodeJS.Timeout;
|
|
818
838
|
const timerPromise = new Promise<boolean>((resolve) => {
|
|
819
839
|
loginTimeoutHandle = setTimeout(() => {
|
|
820
|
-
console.error(
|
|
840
|
+
console.error(
|
|
841
|
+
"Timed out waiting for authorization code, please try again."
|
|
842
|
+
);
|
|
821
843
|
server.close();
|
|
822
844
|
clearTimeout(loginTimeoutHandle);
|
|
823
845
|
resolve(false);
|
|
824
|
-
}, 60000); // wait for
|
|
846
|
+
}, 60000); // wait for 60 seconds for the user to authorize
|
|
825
847
|
});
|
|
826
848
|
|
|
827
849
|
const loginPromise = new Promise<boolean>((resolve, reject) => {
|
|
@@ -852,8 +874,9 @@ export async function login(props?: LoginProps): Promise<boolean> {
|
|
|
852
874
|
finish(false);
|
|
853
875
|
});
|
|
854
876
|
console.log(
|
|
855
|
-
"Error: Consent denied. You must grant consent to Wrangler in order to login
|
|
856
|
-
|
|
877
|
+
"Error: Consent denied. You must grant consent to Wrangler in order to login.\n" +
|
|
878
|
+
"If you don't want to do this consider passing an API token via the `CLOUDFLARE_API_TOKEN` environment variable"
|
|
879
|
+
);
|
|
857
880
|
|
|
858
881
|
return;
|
|
859
882
|
} else {
|
|
@@ -945,9 +968,9 @@ export async function logout(): Promise<void> {
|
|
|
945
968
|
export function listScopes(): void {
|
|
946
969
|
throwIfNotInitialised();
|
|
947
970
|
console.log("💁 Available scopes:");
|
|
948
|
-
const data =
|
|
971
|
+
const data = ScopeKeys.map((scope: Scope) => ({
|
|
949
972
|
Scope: scope,
|
|
950
|
-
Description:
|
|
973
|
+
Description: Scopes[scope],
|
|
951
974
|
}));
|
|
952
975
|
render(<Table data={data} />);
|
|
953
976
|
// TODO: maybe a good idea to show usage here
|
|
@@ -957,13 +980,14 @@ export async function getAccountId() {
|
|
|
957
980
|
const apiToken = getAPIToken();
|
|
958
981
|
if (!apiToken) return;
|
|
959
982
|
|
|
960
|
-
|
|
961
|
-
|
|
983
|
+
const accountIdFromEnv = getCloudflareAccountIdFromEnv();
|
|
984
|
+
if (accountIdFromEnv) {
|
|
985
|
+
return accountIdFromEnv;
|
|
962
986
|
}
|
|
963
987
|
|
|
964
988
|
let response: Response;
|
|
965
989
|
try {
|
|
966
|
-
response = await fetch(`${
|
|
990
|
+
response = await fetch(`${getCloudflareApiBaseUrl()}/memberships`, {
|
|
967
991
|
method: "GET",
|
|
968
992
|
headers: {
|
|
969
993
|
Authorization: "Bearer " + apiToken,
|
|
@@ -971,14 +995,14 @@ export async function getAccountId() {
|
|
|
971
995
|
});
|
|
972
996
|
} catch (err) {
|
|
973
997
|
// probably offline
|
|
998
|
+
return;
|
|
974
999
|
}
|
|
975
|
-
|
|
976
|
-
let accountId: string;
|
|
977
|
-
|
|
978
|
-
const responseJSON: {
|
|
1000
|
+
|
|
1001
|
+
let accountId: string | undefined;
|
|
1002
|
+
const responseJSON = (await response.json()) as {
|
|
979
1003
|
success: boolean;
|
|
980
1004
|
result: { id: string; account: { id: string; name: string } }[];
|
|
981
|
-
}
|
|
1005
|
+
};
|
|
982
1006
|
|
|
983
1007
|
if (responseJSON.success === true) {
|
|
984
1008
|
if (responseJSON.result.length === 1) {
|
|
@@ -1007,16 +1031,19 @@ type ChooseAccountItem = {
|
|
|
1007
1031
|
};
|
|
1008
1032
|
export function ChooseAccount(props: {
|
|
1009
1033
|
accounts: ChooseAccountItem[];
|
|
1010
|
-
onSelect: (item) => void;
|
|
1034
|
+
onSelect: (item: SelectInputItem<ChooseAccountItem>) => void;
|
|
1011
1035
|
}) {
|
|
1012
1036
|
return (
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1037
|
+
<>
|
|
1038
|
+
<Text bold>Select an account from below:</Text>
|
|
1039
|
+
<SelectInput
|
|
1040
|
+
items={props.accounts.map((item) => ({
|
|
1041
|
+
key: item.id,
|
|
1042
|
+
label: item.name,
|
|
1043
|
+
value: item,
|
|
1044
|
+
}))}
|
|
1045
|
+
onSelect={props.onSelect}
|
|
1046
|
+
/>
|
|
1047
|
+
</>
|
|
1021
1048
|
);
|
|
1022
1049
|
}
|
package/src/whoami.tsx
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Text, render } from "ink";
|
|
2
|
+
import Table from "ink-table";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { fetchListResult, fetchResult } from "./cfetch";
|
|
5
|
+
import { getAPIToken } from "./user";
|
|
6
|
+
|
|
7
|
+
export async function whoami() {
|
|
8
|
+
console.log("Getting User settings...");
|
|
9
|
+
const user = await getUserInfo();
|
|
10
|
+
render(<WhoAmI user={user}></WhoAmI>);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function WhoAmI({ user }: { user: UserInfo | undefined }) {
|
|
14
|
+
return user ? (
|
|
15
|
+
<>
|
|
16
|
+
<Email tokenType={user.authType} email={user.email}></Email>
|
|
17
|
+
<Accounts accounts={user.accounts}></Accounts>
|
|
18
|
+
</>
|
|
19
|
+
) : (
|
|
20
|
+
<Text>You are not authenticated. Please run `wrangler login`.</Text>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function Email(props: { tokenType: string; email: string }) {
|
|
25
|
+
return (
|
|
26
|
+
<Text>
|
|
27
|
+
👋 You are logged in with an {props.tokenType} Token, associated with the
|
|
28
|
+
email '{props.email}'!
|
|
29
|
+
</Text>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function Accounts(props: { accounts: AccountInfo[] }) {
|
|
34
|
+
const accounts = props.accounts.map((account) => ({
|
|
35
|
+
"Account Name": account.name,
|
|
36
|
+
"Account ID": account.id,
|
|
37
|
+
}));
|
|
38
|
+
return <Table data={accounts}></Table>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface UserInfo {
|
|
42
|
+
apiToken: string;
|
|
43
|
+
authType: string;
|
|
44
|
+
email: string;
|
|
45
|
+
accounts: AccountInfo[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function getUserInfo(): Promise<UserInfo | undefined> {
|
|
49
|
+
const apiToken = getAPIToken();
|
|
50
|
+
return apiToken
|
|
51
|
+
? {
|
|
52
|
+
apiToken,
|
|
53
|
+
authType: "OAuth",
|
|
54
|
+
email: await getEmail(),
|
|
55
|
+
accounts: await getAccounts(),
|
|
56
|
+
}
|
|
57
|
+
: undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function getEmail(): Promise<string> {
|
|
61
|
+
const { email } = await fetchResult<{ email: string }>("/user");
|
|
62
|
+
return email;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type AccountInfo = { name: string; id: string };
|
|
66
|
+
|
|
67
|
+
async function getAccounts(): Promise<AccountInfo[]> {
|
|
68
|
+
return await fetchListResult<AccountInfo>("/accounts");
|
|
69
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Welcome to Cloudflare Workers! This is your first worker.
|
|
3
|
+
*
|
|
4
|
+
* - Run `npx wrangler dev src/index.js` in your terminal to start a development server
|
|
5
|
+
* - Open a browser tab at http://localhost:8787/ to see your worker in action
|
|
6
|
+
* - Run `npx wrangler publish src/index.js --name my-worker` to publish your worker
|
|
7
|
+
*
|
|
8
|
+
* Learn more at https://developers.cloudflare.com/workers/
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
async fetch(request) {
|
|
13
|
+
return new Response("Hello World!");
|
|
14
|
+
},
|
|
15
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Welcome to Cloudflare Workers! This is your first worker.
|
|
3
|
+
*
|
|
4
|
+
* - Run `wrangler dev src/index.ts` in your terminal to start a development server
|
|
5
|
+
* - Open a browser tab at http://localhost:8787/ to see your worker in action
|
|
6
|
+
* - Run `wrangler publish src/index.ts --name my-worker` to publish your worker
|
|
7
|
+
*
|
|
8
|
+
* Learn more at https://developers.cloudflare.com/workers/
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
async fetch(request: Request): Promise<Response> {
|
|
13
|
+
return new Response("Hello World!");
|
|
14
|
+
},
|
|
15
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
|
4
|
+
|
|
5
|
+
/* Projects */
|
|
6
|
+
// "incremental": true, /* Enable incremental compilation */
|
|
7
|
+
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
|
8
|
+
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
|
|
9
|
+
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
|
|
10
|
+
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
|
11
|
+
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
|
12
|
+
|
|
13
|
+
/* Language and Environment */
|
|
14
|
+
"target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
|
15
|
+
"lib": [
|
|
16
|
+
"es2021"
|
|
17
|
+
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
|
|
18
|
+
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
|
19
|
+
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
|
20
|
+
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
|
21
|
+
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
|
|
22
|
+
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
|
23
|
+
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
|
|
24
|
+
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
|
|
25
|
+
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
|
26
|
+
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
|
27
|
+
|
|
28
|
+
/* Modules */
|
|
29
|
+
"module": "es2022" /* Specify what module code is generated. */,
|
|
30
|
+
// "rootDir": "./", /* Specify the root folder within your source files. */
|
|
31
|
+
"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
|
|
32
|
+
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
|
33
|
+
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
|
34
|
+
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
|
35
|
+
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
|
|
36
|
+
"types": [
|
|
37
|
+
"@cloudflare/workers-types"
|
|
38
|
+
] /* Specify type package names to be included without being referenced in a source file. */,
|
|
39
|
+
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
|
40
|
+
"resolveJsonModule": true /* Enable importing .json files */,
|
|
41
|
+
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
|
|
42
|
+
|
|
43
|
+
/* JavaScript Support */
|
|
44
|
+
"allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */,
|
|
45
|
+
"checkJs": true /* Enable error reporting in type-checked JavaScript files. */,
|
|
46
|
+
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
|
|
47
|
+
|
|
48
|
+
/* Emit */
|
|
49
|
+
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
|
50
|
+
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
|
51
|
+
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
|
52
|
+
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
|
53
|
+
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
|
|
54
|
+
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
|
55
|
+
// "removeComments": true, /* Disable emitting comments. */
|
|
56
|
+
"noEmit": true /* Disable emitting files from a compilation. */,
|
|
57
|
+
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
|
58
|
+
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
|
|
59
|
+
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
|
60
|
+
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
|
61
|
+
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
|
62
|
+
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
|
63
|
+
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
|
64
|
+
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
|
65
|
+
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
|
66
|
+
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
|
|
67
|
+
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
|
|
68
|
+
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
|
69
|
+
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
|
|
70
|
+
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
|
71
|
+
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
|
72
|
+
|
|
73
|
+
/* Interop Constraints */
|
|
74
|
+
"isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */,
|
|
75
|
+
"allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */,
|
|
76
|
+
// "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
|
|
77
|
+
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
|
78
|
+
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
|
79
|
+
|
|
80
|
+
/* Type Checking */
|
|
81
|
+
"strict": true /* Enable all strict type-checking options. */,
|
|
82
|
+
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
|
|
83
|
+
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
|
|
84
|
+
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
|
85
|
+
// "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
|
|
86
|
+
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
|
87
|
+
// "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
|
|
88
|
+
// "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
|
|
89
|
+
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
|
90
|
+
// "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
|
|
91
|
+
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
|
|
92
|
+
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
|
93
|
+
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
|
94
|
+
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
|
95
|
+
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
|
96
|
+
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
|
97
|
+
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
|
|
98
|
+
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
|
99
|
+
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
|
100
|
+
|
|
101
|
+
/* Completeness */
|
|
102
|
+
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
|
103
|
+
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
|
104
|
+
}
|
|
105
|
+
}
|