wrangler 0.0.0-e7a0cd5b → 0.0.0-e87ad068
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/README.md +3 -3
- package/bin/wrangler.js +30 -10
- package/miniflare-dist/index.mjs +254 -128
- package/package.json +27 -19
- package/src/__tests__/api-dev.test.ts +65 -36
- package/src/__tests__/api-devregistry.test.ts +121 -0
- package/src/__tests__/api.test.ts +27 -5
- package/src/__tests__/configuration.test.ts +797 -98
- package/src/__tests__/constellation.test.ts +371 -0
- package/src/__tests__/d1/d1.test.ts +82 -0
- package/src/__tests__/d1/execute.test.ts +66 -0
- package/src/__tests__/d1/migrate.test.ts +257 -0
- package/src/__tests__/d1/splitter.test.ts +255 -0
- package/src/__tests__/delete.test.ts +91 -49
- package/src/__tests__/deployments.test.ts +330 -56
- package/src/__tests__/dev.test.tsx +198 -90
- package/src/__tests__/generate.test.ts +12 -10
- package/src/__tests__/guess-worker-format.test.ts +35 -0
- package/src/__tests__/helpers/end-event-loop.ts +6 -0
- package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
- package/src/__tests__/helpers/mock-console.ts +6 -0
- package/src/__tests__/helpers/mock-dialogs.ts +71 -85
- package/src/__tests__/helpers/mock-get-pages-upload-token.ts +25 -0
- package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -5
- package/src/__tests__/helpers/mock-known-routes.ts +7 -2
- package/src/__tests__/helpers/mock-kv.ts +29 -16
- package/src/__tests__/helpers/mock-oauth-flow.ts +103 -92
- package/src/__tests__/helpers/mock-process.ts +8 -13
- package/src/__tests__/helpers/mock-set-timeout.ts +16 -0
- package/src/__tests__/helpers/msw/blob-worker.cjs +19 -0
- package/src/__tests__/helpers/msw/handlers/deployments.ts +128 -27
- package/src/__tests__/helpers/msw/handlers/namespaces.ts +18 -41
- package/src/__tests__/helpers/msw/handlers/oauth.ts +13 -18
- package/src/__tests__/helpers/msw/handlers/r2.ts +14 -34
- package/src/__tests__/helpers/msw/handlers/script.ts +9 -28
- package/src/__tests__/helpers/msw/handlers/user.ts +13 -24
- package/src/__tests__/helpers/msw/handlers/zones.ts +6 -8
- package/src/__tests__/helpers/msw/index.ts +32 -1
- package/src/__tests__/helpers/msw/read-file-sync.js +61 -0
- package/src/__tests__/helpers/string-dynamic-values-matcher.ts +28 -0
- package/src/__tests__/helpers/worker-scripts/parent-worker.js +4 -1
- package/src/__tests__/index.test.ts +92 -72
- package/src/__tests__/init.test.ts +1033 -631
- package/src/__tests__/jest.setup.ts +19 -42
- package/src/__tests__/kv.test.ts +355 -231
- package/src/__tests__/logger.test.ts +68 -2
- package/src/__tests__/logout.test.ts +47 -0
- package/src/__tests__/metrics.test.ts +94 -51
- package/src/__tests__/middleware.scheduled.test.ts +42 -32
- package/src/__tests__/middleware.test.ts +212 -122
- package/src/__tests__/mtls-certificates.test.ts +589 -0
- package/src/__tests__/pages/deployment-list.test.ts +80 -0
- package/src/__tests__/pages/functions-build.test.ts +529 -0
- package/src/__tests__/pages/pages.test.ts +81 -0
- package/src/__tests__/pages/project-create.test.ts +63 -0
- package/src/__tests__/pages/project-list.test.ts +110 -0
- package/src/__tests__/pages/project-upload.test.ts +500 -0
- package/src/__tests__/pages/publish.test.ts +2864 -0
- package/src/__tests__/pages-deployment-tail.test.ts +957 -0
- package/src/__tests__/parse.test.ts +106 -0
- package/src/__tests__/publish.test.ts +2227 -1005
- package/src/__tests__/pubsub.test.ts +226 -100
- package/src/__tests__/queues.test.ts +238 -77
- package/src/__tests__/r2.test.ts +55 -57
- package/src/__tests__/secret.test.ts +179 -130
- package/src/__tests__/tail.test.ts +313 -113
- package/src/__tests__/test-old-node-version.js +3 -3
- package/src/__tests__/traverse-module-graph.test.ts +220 -0
- package/src/__tests__/tsconfig-sanity.ts +12 -0
- package/src/__tests__/tsconfig.json +8 -0
- package/src/__tests__/tsconfig.tsbuildinfo +1 -0
- package/src/__tests__/type-generation.test.ts +43 -26
- package/src/__tests__/unstableDev.test.ts +61 -0
- package/src/__tests__/user.test.ts +35 -72
- package/src/__tests__/whoami.test.tsx +8 -114
- package/src/__tests__/worker-namespace.test.ts +83 -69
- package/src/api/dev.ts +180 -60
- package/src/api/index.ts +10 -1
- package/src/api/mtls-certificate.ts +148 -0
- package/src/api/pages/create-worker-bundle-contents.ts +80 -0
- package/src/api/pages/index.ts +5 -0
- package/src/api/pages/publish.tsx +371 -0
- package/src/bundle.ts +315 -148
- package/src/cfetch/index.ts +0 -2
- package/src/cfetch/internal.ts +33 -33
- package/src/cli.ts +4 -4
- package/src/config/config.ts +14 -7
- package/src/config/environment.ts +120 -24
- package/src/config/index.ts +117 -35
- package/src/config/validation-helpers.ts +1 -1
- package/src/config/validation.ts +430 -19
- package/src/constellation/createProject.tsx +51 -0
- package/src/constellation/deleteProject.ts +51 -0
- package/src/constellation/deleteProjectModel.ts +76 -0
- package/src/constellation/index.ts +75 -0
- package/src/constellation/listCatalog.tsx +35 -0
- package/src/constellation/listModel.tsx +49 -0
- package/src/constellation/listProject.tsx +28 -0
- package/src/constellation/listRuntime.tsx +28 -0
- package/src/constellation/options.ts +17 -0
- package/src/constellation/types.ts +17 -0
- package/src/constellation/uploadModel.tsx +84 -0
- package/src/constellation/utils.ts +90 -0
- package/src/create-worker-preview.ts +19 -8
- package/src/create-worker-upload-form.ts +81 -18
- package/src/d1/backups.tsx +47 -46
- package/src/d1/constants.ts +5 -0
- package/src/d1/create.tsx +85 -37
- package/src/d1/{delete.tsx → delete.ts} +12 -15
- package/src/d1/execute.tsx +228 -156
- package/src/d1/index.ts +31 -7
- package/src/d1/list.tsx +27 -13
- package/src/d1/migrations/apply.tsx +235 -0
- package/src/d1/migrations/create.tsx +79 -0
- package/src/d1/migrations/helpers.ts +171 -0
- package/src/d1/migrations/index.ts +3 -0
- package/src/d1/migrations/list.tsx +95 -0
- package/src/d1/migrations/options.ts +23 -0
- package/src/d1/options.ts +12 -2
- package/src/d1/splitter.ts +161 -0
- package/src/d1/types.ts +32 -0
- package/src/d1/utils.ts +12 -2
- package/src/delete.ts +8 -16
- package/src/deployments.ts +340 -46
- package/src/deprecated/index.ts +8 -302
- package/src/dev/dev.tsx +66 -46
- package/src/dev/local.tsx +339 -104
- package/src/dev/remote.tsx +36 -3
- package/src/dev/start-server.ts +146 -101
- package/src/dev/use-esbuild.ts +82 -56
- package/src/dev/validate-dev-props.ts +9 -0
- package/src/{dev-registry.tsx → dev-registry.ts} +13 -1
- package/src/dev.tsx +202 -125
- package/src/dialogs.ts +136 -0
- package/src/dispatch-namespace.ts +21 -17
- package/src/docs/helpers.ts +50 -0
- package/src/docs/index.ts +54 -0
- package/src/entry.ts +26 -11
- package/src/environment-variables/factory.ts +89 -0
- package/src/environment-variables/misc-variables.ts +30 -0
- package/src/generate/index.ts +303 -0
- package/src/git-client.ts +15 -4
- package/src/{index.tsx → index.ts} +148 -63
- package/src/init.ts +301 -197
- package/src/inspect.ts +122 -6
- package/src/jest.d.ts +4 -0
- package/src/kv/helpers.ts +7 -4
- package/src/kv/index.ts +15 -17
- package/src/logger.ts +36 -5
- package/src/metrics/metrics-config.ts +3 -3
- package/src/metrics/send-event.ts +6 -1
- package/src/miniflare-cli/assets.ts +64 -28
- package/src/miniflare-cli/index.ts +6 -9
- package/src/miniflare-cli/tsconfig.json +9 -0
- package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
- package/src/miniflare-cli/types.ts +11 -0
- package/src/module-collection.ts +92 -26
- package/src/mtls-certificate/cli.ts +155 -0
- package/src/pages/build.ts +423 -0
- package/src/pages/buildFunctions.ts +140 -0
- package/src/pages/deployment-tails.ts +281 -0
- package/src/pages/deployments.tsx +11 -33
- package/src/pages/{dev.tsx → dev.ts} +192 -126
- package/src/pages/errors.ts +1 -0
- package/src/pages/functions/buildPlugin.ts +73 -69
- package/src/pages/functions/buildWorker.ts +342 -117
- package/src/pages/functions/tsconfig.json +8 -0
- package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
- package/src/pages/{functions.tsx → functions.ts} +8 -4
- package/src/pages/{index.tsx → index.ts} +11 -3
- package/src/pages/projects.tsx +12 -22
- package/src/pages/prompt-select-project.tsx +31 -0
- package/src/pages/publish.tsx +45 -214
- package/src/pages/types.ts +6 -9
- package/src/pages/upload.tsx +58 -14
- package/src/pages/utils.ts +14 -3
- package/src/parse.ts +23 -1
- package/src/paths.ts +1 -1
- package/src/proxy.ts +5 -0
- package/src/publish/index.ts +20 -16
- package/src/publish/publish.ts +81 -48
- package/src/pubsub/{pubsub-commands.tsx → pubsub-commands.ts} +19 -20
- package/src/queues/cli/commands/consumer/add.ts +24 -24
- package/src/queues/cli/commands/consumer/index.ts +3 -6
- package/src/queues/cli/commands/consumer/remove.ts +11 -18
- package/src/queues/cli/commands/create.ts +8 -8
- package/src/queues/cli/commands/delete.ts +8 -8
- package/src/queues/cli/commands/index.ts +6 -4
- package/src/queues/cli/commands/list.ts +8 -8
- package/src/queues/client.ts +1 -0
- package/src/queues/utils.ts +18 -0
- package/src/r2/constants.ts +4 -0
- package/src/r2/helpers.ts +1 -0
- package/src/r2/index.ts +40 -28
- package/src/secret/index.ts +18 -17
- package/src/{sites.tsx → sites.ts} +165 -53
- package/src/tail/createTail.ts +103 -3
- package/src/tail/filters.ts +1 -1
- package/src/tail/index.ts +8 -11
- package/src/tail/printing.ts +27 -0
- package/src/traverse-module-graph.ts +54 -0
- package/src/tsconfig-sanity.ts +16 -0
- package/src/type-generation.ts +85 -57
- package/src/user/access.ts +0 -1
- package/src/user/auth-variables.ts +113 -0
- package/src/user/choose-account.tsx +1 -31
- package/src/user/index.ts +0 -1
- package/src/user/{user.tsx → user.ts} +124 -82
- package/src/utils/render.ts +93 -0
- package/src/{whoami.tsx → whoami.ts} +37 -71
- package/src/worker.ts +61 -3
- package/src/yargs-types.ts +22 -5
- package/templates/__tests__/tsconfig-sanity.ts +12 -0
- package/templates/__tests__/tsconfig.json +8 -0
- package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
- package/templates/checked-fetch.js +9 -3
- package/templates/d1-beta-facade.js +95 -25
- package/templates/facade.d.ts +14 -0
- package/templates/first-party-worker-module-facade.ts +4 -3
- package/templates/format-dev-errors.ts +8 -6
- package/templates/gitignore +1 -0
- package/templates/init-tests/test-jest-new-worker.js +3 -5
- package/templates/init-tests/test-vitest-new-worker.js +3 -5
- package/templates/init-tests/test-vitest-new-worker.ts +25 -0
- package/templates/middleware/loader-modules.ts +2 -2
- package/templates/middleware/loader-sw.ts +51 -31
- package/templates/middleware/middleware-miniflare3-json-error.ts +32 -0
- package/templates/new-worker.ts +3 -0
- package/templates/pages-dev-pipeline.ts +4 -1
- package/templates/pages-dev-util.ts +4 -1
- package/templates/pages-shim.ts +4 -1
- package/templates/pages-template-plugin.ts +19 -10
- package/templates/serve-static-assets.ts +17 -14
- package/templates/service-bindings-module-facade.js +1 -0
- package/templates/tsconfig-sanity.ts +11 -0
- package/templates/tsconfig.init.json +105 -0
- package/templates/tsconfig.json +5 -103
- package/templates/tsconfig.tsbuildinfo +1 -0
- package/wrangler-dist/cli.d.ts +902 -77
- package/wrangler-dist/cli.js +131685 -140615
- package/wrangler-dist/wasm-sync.wasm +0 -0
- package/src/__tests__/api-devregistry.test.js +0 -57
- package/src/__tests__/d1.test.ts +0 -72
- package/src/__tests__/dialogs.test.tsx +0 -40
- package/src/__tests__/helpers/mock-cfetch.ts +0 -333
- package/src/__tests__/pages.test.ts +0 -2223
- package/src/d1/types.tsx +0 -14
- package/src/dialogs.tsx +0 -163
- package/src/environment-variables.ts +0 -50
- package/src/pages/build.tsx +0 -238
- package/src/user/env-vars.ts +0 -46
- package/templates/experimental-local-cache-stubs.js +0 -27
- /package/src/{bundle-reporter.tsx → bundle-reporter.ts} +0 -0
- /package/src/dev/{get-local-persistence-path.tsx → get-local-persistence-path.ts} +0 -0
- /package/src/pages/{hash.tsx → hash.ts} +0 -0
|
@@ -214,28 +214,61 @@ import url from "node:url";
|
|
|
214
214
|
import { TextEncoder } from "node:util";
|
|
215
215
|
import TOML from "@iarna/toml";
|
|
216
216
|
import { HostURL } from "@webcontainer/env";
|
|
217
|
-
import { render } from "ink";
|
|
218
|
-
import Table from "ink-table";
|
|
219
|
-
import React from "react";
|
|
220
217
|
import { fetch } from "undici";
|
|
221
218
|
import {
|
|
222
219
|
getConfigCache,
|
|
223
220
|
purgeConfigCaches,
|
|
224
221
|
saveToConfigCache,
|
|
225
222
|
} from "../config-cache";
|
|
223
|
+
import { NoDefaultValueProvided, select } from "../dialogs";
|
|
226
224
|
import { getGlobalWranglerConfigPath } from "../global-wrangler-config-path";
|
|
227
225
|
import { CI } from "../is-ci";
|
|
228
226
|
import isInteractive from "../is-interactive";
|
|
229
227
|
import { logger } from "../logger";
|
|
230
228
|
import openInBrowser from "../open-in-browser";
|
|
231
229
|
import { parseTOML, readFileSync } from "../parse";
|
|
232
|
-
import {
|
|
233
|
-
import {
|
|
230
|
+
import { domainUsesAccess } from "./access";
|
|
231
|
+
import {
|
|
232
|
+
getAuthDomainFromEnv,
|
|
233
|
+
getAuthUrlFromEnv,
|
|
234
|
+
getClientIdFromEnv,
|
|
235
|
+
getCloudflareAccessToken,
|
|
236
|
+
getCloudflareAPITokenFromEnv,
|
|
237
|
+
getCloudflareGlobalAuthEmailFromEnv,
|
|
238
|
+
getCloudflareGlobalAuthKeyFromEnv,
|
|
239
|
+
getRevokeUrlFromEnv,
|
|
240
|
+
getTokenUrlFromEnv,
|
|
241
|
+
} from "./auth-variables";
|
|
242
|
+
import { getAccountChoices } from "./choose-account";
|
|
234
243
|
import { generateAuthUrl } from "./generate-auth-url";
|
|
235
244
|
import { generateRandomState } from "./generate-random-state";
|
|
236
|
-
import type {
|
|
245
|
+
import type { ChooseAccountItem } from "./choose-account";
|
|
237
246
|
import type { ParsedUrlQuery } from "node:querystring";
|
|
238
247
|
|
|
248
|
+
export type ApiCredentials =
|
|
249
|
+
| {
|
|
250
|
+
apiToken: string;
|
|
251
|
+
}
|
|
252
|
+
| {
|
|
253
|
+
authKey: string;
|
|
254
|
+
authEmail: string;
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Try to read an API token or Global Auth from the environment.
|
|
259
|
+
*/
|
|
260
|
+
export function getAuthFromEnv(): ApiCredentials | undefined {
|
|
261
|
+
const globalApiKey = getCloudflareGlobalAuthKeyFromEnv();
|
|
262
|
+
const globalApiEmail = getCloudflareGlobalAuthEmailFromEnv();
|
|
263
|
+
const apiToken = getCloudflareAPITokenFromEnv();
|
|
264
|
+
|
|
265
|
+
if (globalApiKey && globalApiEmail) {
|
|
266
|
+
return { authKey: globalApiKey, authEmail: globalApiEmail };
|
|
267
|
+
} else if (apiToken) {
|
|
268
|
+
return { apiToken };
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
239
272
|
/**
|
|
240
273
|
* An implementation of rfc6749#section-4.1 and rfc7636.
|
|
241
274
|
*/
|
|
@@ -264,7 +297,7 @@ interface AuthTokens {
|
|
|
264
297
|
accessToken?: AccessToken;
|
|
265
298
|
refreshToken?: RefreshToken;
|
|
266
299
|
scopes?: Scope[];
|
|
267
|
-
/** @deprecated - this field was only provided by the deprecated `
|
|
300
|
+
/** @deprecated - this field was only provided by the deprecated v1 `wrangler config` command. */
|
|
268
301
|
apiToken?: string;
|
|
269
302
|
}
|
|
270
303
|
|
|
@@ -282,7 +315,7 @@ export interface UserAuthConfig {
|
|
|
282
315
|
refresh_token?: string;
|
|
283
316
|
expiration_time?: string;
|
|
284
317
|
scopes?: string[];
|
|
285
|
-
/** @deprecated - this field was only provided by the deprecated `
|
|
318
|
+
/** @deprecated - this field was only provided by the deprecated v1 `wrangler config` command. */
|
|
286
319
|
api_token?: string;
|
|
287
320
|
}
|
|
288
321
|
|
|
@@ -313,6 +346,8 @@ const Scopes = {
|
|
|
313
346
|
"pages:write":
|
|
314
347
|
"See and change Cloudflare Pages projects, settings and deployments.",
|
|
315
348
|
"zone:read": "Grants read level access to account zone.",
|
|
349
|
+
"ssl_certs:write": "See and manage mTLS certificates for your account",
|
|
350
|
+
"constellation:write": "Manage Constellation projects/models",
|
|
316
351
|
} as const;
|
|
317
352
|
|
|
318
353
|
/**
|
|
@@ -330,11 +365,6 @@ export function validateScopeKeys(
|
|
|
330
365
|
return scopes.every((scope) => scope in Scopes);
|
|
331
366
|
}
|
|
332
367
|
|
|
333
|
-
const CLIENT_ID = "54d11594-84e4-41aa-b438-e81b8fa78ee7";
|
|
334
|
-
const AUTH_URL = "https://dash.cloudflare.com/oauth2/auth";
|
|
335
|
-
const TOKEN_URL = "https://dash.cloudflare.com/oauth2/token";
|
|
336
|
-
const REVOKE_URL = "https://dash.cloudflare.com/oauth2/revoke";
|
|
337
|
-
|
|
338
368
|
/**
|
|
339
369
|
* To allow OAuth callbacks in environments such as WebContainer we need to
|
|
340
370
|
* create a host URL which only resolves `localhost` to a WebContainer
|
|
@@ -374,7 +404,7 @@ function getAuthTokens(config?: UserAuthConfig): AuthTokens | undefined {
|
|
|
374
404
|
};
|
|
375
405
|
} else if (api_token) {
|
|
376
406
|
logger.warn(
|
|
377
|
-
"It looks like you have used Wrangler
|
|
407
|
+
"It looks like you have used Wrangler v1's `config` command to login with an API token.\n" +
|
|
378
408
|
"This is no longer supported in the current version of Wrangler.\n" +
|
|
379
409
|
"If you wish to authenticate via an API token then please set the `CLOUDFLARE_API_TOKEN` environment variable."
|
|
380
410
|
);
|
|
@@ -386,7 +416,7 @@ function getAuthTokens(config?: UserAuthConfig): AuthTokens | undefined {
|
|
|
386
416
|
}
|
|
387
417
|
|
|
388
418
|
/**
|
|
389
|
-
* Run the
|
|
419
|
+
* Run the initialization of the auth state, in the case that something changed.
|
|
390
420
|
*
|
|
391
421
|
* This runs automatically whenever `writeAuthConfigFile` is run, so generally
|
|
392
422
|
* you won't need to call it yourself.
|
|
@@ -625,8 +655,8 @@ export async function getAuthURL(scopes = ScopeKeys): Promise<string> {
|
|
|
625
655
|
});
|
|
626
656
|
|
|
627
657
|
return generateAuthUrl({
|
|
628
|
-
authUrl:
|
|
629
|
-
clientId:
|
|
658
|
+
authUrl: getAuthUrlFromEnv(),
|
|
659
|
+
clientId: getClientIdFromEnv(),
|
|
630
660
|
callbackUrl: CALLBACK_URL,
|
|
631
661
|
scopes,
|
|
632
662
|
stateQueryParam,
|
|
@@ -653,19 +683,14 @@ async function exchangeRefreshTokenForAccessToken(): Promise<AccessContext> {
|
|
|
653
683
|
logger.warn("No refresh token is present.");
|
|
654
684
|
}
|
|
655
685
|
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
const response = await fetch(TOKEN_URL, {
|
|
662
|
-
method: "POST",
|
|
663
|
-
body,
|
|
664
|
-
headers: {
|
|
665
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
666
|
-
},
|
|
686
|
+
const params = new URLSearchParams({
|
|
687
|
+
grant_type: "refresh_token",
|
|
688
|
+
refresh_token: LocalState.refreshToken?.value ?? "",
|
|
689
|
+
client_id: getClientIdFromEnv(),
|
|
667
690
|
});
|
|
668
691
|
|
|
692
|
+
const response = await fetchAuthToken(params);
|
|
693
|
+
|
|
669
694
|
if (response.status >= 400) {
|
|
670
695
|
let tokenExchangeResErr = undefined;
|
|
671
696
|
|
|
@@ -743,20 +768,15 @@ async function exchangeAuthCodeForAccessToken(): Promise<AccessContext> {
|
|
|
743
768
|
logger.warn("No authorization grant code is being passed.");
|
|
744
769
|
}
|
|
745
770
|
|
|
746
|
-
const
|
|
747
|
-
`
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
const response = await fetch(TOKEN_URL, {
|
|
754
|
-
method: "POST",
|
|
755
|
-
body,
|
|
756
|
-
headers: {
|
|
757
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
758
|
-
},
|
|
771
|
+
const params = new URLSearchParams({
|
|
772
|
+
grant_type: `authorization_code`,
|
|
773
|
+
code: authorizationCode ?? "",
|
|
774
|
+
redirect_uri: CALLBACK_URL,
|
|
775
|
+
client_id: getClientIdFromEnv(),
|
|
776
|
+
code_verifier: codeVerifier,
|
|
759
777
|
});
|
|
778
|
+
|
|
779
|
+
const response = await fetchAuthToken(params);
|
|
760
780
|
if (!response.ok) {
|
|
761
781
|
const { error } = (await response.json()) as { error: string };
|
|
762
782
|
// .catch((_) => ({ error: "invalid_json" }));
|
|
@@ -875,6 +895,7 @@ export function readAuthConfigFile(): UserAuthConfig {
|
|
|
875
895
|
|
|
876
896
|
type LoginProps = {
|
|
877
897
|
scopes?: Scope[];
|
|
898
|
+
browser: boolean;
|
|
878
899
|
};
|
|
879
900
|
|
|
880
901
|
export async function loginOrRefreshIfRequired(): Promise<boolean> {
|
|
@@ -901,7 +922,9 @@ export async function loginOrRefreshIfRequired(): Promise<boolean> {
|
|
|
901
922
|
}
|
|
902
923
|
}
|
|
903
924
|
|
|
904
|
-
export async function login(
|
|
925
|
+
export async function login(
|
|
926
|
+
props: LoginProps = { browser: true }
|
|
927
|
+
): Promise<boolean> {
|
|
905
928
|
logger.log("Attempting to login via OAuth...");
|
|
906
929
|
const urlToOpen = await getAuthURL(props?.scopes);
|
|
907
930
|
let server: http.Server;
|
|
@@ -914,7 +937,7 @@ export async function login(props?: LoginProps): Promise<boolean> {
|
|
|
914
937
|
server.close();
|
|
915
938
|
clearTimeout(loginTimeoutHandle);
|
|
916
939
|
resolve(false);
|
|
917
|
-
},
|
|
940
|
+
}, 120000); // wait for 120 seconds for the user to authorize
|
|
918
941
|
});
|
|
919
942
|
|
|
920
943
|
const loginPromise = new Promise<boolean>((resolve, reject) => {
|
|
@@ -986,9 +1009,12 @@ export async function login(props?: LoginProps): Promise<boolean> {
|
|
|
986
1009
|
|
|
987
1010
|
server.listen(8976);
|
|
988
1011
|
});
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1012
|
+
if (props?.browser) {
|
|
1013
|
+
logger.log(`Opening a link in your default browser: ${urlToOpen}`);
|
|
1014
|
+
await openInBrowser(urlToOpen);
|
|
1015
|
+
} else {
|
|
1016
|
+
logger.log(`Visit this link to authenticate: ${urlToOpen}`);
|
|
1017
|
+
}
|
|
992
1018
|
|
|
993
1019
|
return Promise.race([timerPromise, loginPromise]);
|
|
994
1020
|
}
|
|
@@ -1032,11 +1058,11 @@ export async function logout(): Promise<void> {
|
|
|
1032
1058
|
}
|
|
1033
1059
|
|
|
1034
1060
|
const body =
|
|
1035
|
-
`client_id=${encodeURIComponent(
|
|
1061
|
+
`client_id=${encodeURIComponent(getClientIdFromEnv())}&` +
|
|
1036
1062
|
`token_type_hint=refresh_token&` +
|
|
1037
1063
|
`token=${encodeURIComponent(LocalState.refreshToken?.value || "")}`;
|
|
1038
1064
|
|
|
1039
|
-
const response = await fetch(
|
|
1065
|
+
const response = await fetch(getRevokeUrlFromEnv(), {
|
|
1040
1066
|
method: "POST",
|
|
1041
1067
|
body,
|
|
1042
1068
|
headers: {
|
|
@@ -1049,11 +1075,11 @@ export async function logout(): Promise<void> {
|
|
|
1049
1075
|
);
|
|
1050
1076
|
}
|
|
1051
1077
|
const body =
|
|
1052
|
-
`client_id=${encodeURIComponent(
|
|
1078
|
+
`client_id=${encodeURIComponent(getClientIdFromEnv())}&` +
|
|
1053
1079
|
`token_type_hint=refresh_token&` +
|
|
1054
1080
|
`token=${encodeURIComponent(LocalState.refreshToken?.value || "")}`;
|
|
1055
1081
|
|
|
1056
|
-
const response = await fetch(
|
|
1082
|
+
const response = await fetch(getRevokeUrlFromEnv(), {
|
|
1057
1083
|
method: "POST",
|
|
1058
1084
|
body,
|
|
1059
1085
|
headers: {
|
|
@@ -1071,8 +1097,7 @@ export function listScopes(message = "💁 Available scopes:"): void {
|
|
|
1071
1097
|
Scope: scope,
|
|
1072
1098
|
Description: Scopes[scope],
|
|
1073
1099
|
}));
|
|
1074
|
-
|
|
1075
|
-
unmount();
|
|
1100
|
+
logger.table(data);
|
|
1076
1101
|
// TODO: maybe a good idea to show usage here
|
|
1077
1102
|
}
|
|
1078
1103
|
|
|
@@ -1091,36 +1116,32 @@ export async function getAccountId(): Promise<string | undefined> {
|
|
|
1091
1116
|
return accounts[0].id;
|
|
1092
1117
|
}
|
|
1093
1118
|
|
|
1094
|
-
|
|
1095
|
-
const
|
|
1096
|
-
(
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1119
|
+
try {
|
|
1120
|
+
const accountID = await select("Select an account", {
|
|
1121
|
+
choices: accounts.map((account) => ({
|
|
1122
|
+
title: account.name,
|
|
1123
|
+
value: account.id,
|
|
1124
|
+
})),
|
|
1125
|
+
});
|
|
1126
|
+
const account = accounts.find(
|
|
1127
|
+
(a) => a.id === accountID
|
|
1128
|
+
) as ChooseAccountItem;
|
|
1129
|
+
saveAccountToCache({ id: account.id, name: account.name });
|
|
1130
|
+
return accountID;
|
|
1131
|
+
} catch (e) {
|
|
1132
|
+
// Did we try to select an account in CI or a non-interactive terminal?
|
|
1133
|
+
if (e instanceof NoDefaultValueProvided) {
|
|
1134
|
+
throw new Error(
|
|
1135
|
+
`More than one account available but unable to select one in non-interactive mode.
|
|
1136
|
+
Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.
|
|
1137
|
+
Available accounts are (\`<name>\`: \`<account_id>\`):
|
|
1138
|
+
${accounts
|
|
1139
|
+
.map((account) => ` \`${account.name}\`: \`${account.id}\``)
|
|
1140
|
+
.join("\n")}`
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
throw e;
|
|
1114
1144
|
}
|
|
1115
|
-
|
|
1116
|
-
throw new Error(
|
|
1117
|
-
"More than one account available but unable to select one in non-interactive mode.\n" +
|
|
1118
|
-
`Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.\n` +
|
|
1119
|
-
`Available accounts are ("<name>" - "<id>"):\n` +
|
|
1120
|
-
accounts
|
|
1121
|
-
.map((account) => ` "${account.name}" - "${account.id}")`)
|
|
1122
|
-
.join("\n")
|
|
1123
|
-
);
|
|
1124
1145
|
}
|
|
1125
1146
|
|
|
1126
1147
|
/**
|
|
@@ -1133,7 +1154,7 @@ export async function requireAuth(config: {
|
|
|
1133
1154
|
if (!loggedIn) {
|
|
1134
1155
|
if (!isInteractive() || CI.isCI()) {
|
|
1135
1156
|
throw new Error(
|
|
1136
|
-
"In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. Please go to https://developers.cloudflare.com/api/
|
|
1157
|
+
"In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. Please go to https://developers.cloudflare.com/fundamentals/api/get-started/create-token/ for instructions on how to create an api token, and assign its value to CLOUDFLARE_API_TOKEN."
|
|
1137
1158
|
);
|
|
1138
1159
|
} else {
|
|
1139
1160
|
// didn't login, let's just quit
|
|
@@ -1190,3 +1211,24 @@ export function getAccountFromCache():
|
|
|
1190
1211
|
export function getScopes(): Scope[] | undefined {
|
|
1191
1212
|
return LocalState.scopes;
|
|
1192
1213
|
}
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* Make a request to the Cloudflare OAuth endpoint to get a token.
|
|
1217
|
+
*
|
|
1218
|
+
* Note that the `body` of the POST request is form-urlencoded so
|
|
1219
|
+
* can be represented by a URLSearchParams object.
|
|
1220
|
+
*/
|
|
1221
|
+
async function fetchAuthToken(body: URLSearchParams) {
|
|
1222
|
+
const headers: Record<string, string> = {
|
|
1223
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
1224
|
+
};
|
|
1225
|
+
if (await domainUsesAccess(getAuthDomainFromEnv())) {
|
|
1226
|
+
// We are trying to access the staging API so we need an "access token".
|
|
1227
|
+
headers["Cookie"] = `CF_Authorization=${await getCloudflareAccessToken()}`;
|
|
1228
|
+
}
|
|
1229
|
+
return await fetch(getTokenUrlFromEnv(), {
|
|
1230
|
+
method: "POST",
|
|
1231
|
+
body: body.toString(),
|
|
1232
|
+
headers,
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import { render as inkRender } from "ink";
|
|
3
|
+
import type { ReactElement } from "react";
|
|
4
|
+
import type { WriteStream } from "tty";
|
|
5
|
+
|
|
6
|
+
export function renderToString(tree: ReactElement): string {
|
|
7
|
+
const { output, cleanup } = render(tree);
|
|
8
|
+
cleanup();
|
|
9
|
+
return output;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// The code below is mostly copied from ink-render-string.
|
|
13
|
+
// See https://github.com/zhanwang626/ink-render-string.git.
|
|
14
|
+
|
|
15
|
+
// MIT License
|
|
16
|
+
|
|
17
|
+
// Copyright (c) 2021 Zhan Wang
|
|
18
|
+
|
|
19
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
20
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
21
|
+
// in the Software without restriction, including without limitation the rights
|
|
22
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
23
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
24
|
+
// furnished to do so, subject to the following conditions:
|
|
25
|
+
|
|
26
|
+
// The above copyright notice and this permission notice shall be included in all
|
|
27
|
+
// copies or substantial portions of the Software.
|
|
28
|
+
|
|
29
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
30
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
31
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
32
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
33
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
34
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
35
|
+
// SOFTWARE.
|
|
36
|
+
|
|
37
|
+
interface Instance {
|
|
38
|
+
output: string;
|
|
39
|
+
unmount: () => void;
|
|
40
|
+
cleanup: () => void;
|
|
41
|
+
stdout: OutputStream;
|
|
42
|
+
stderr: OutputStream;
|
|
43
|
+
frames: string[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const LASTFRAME_UNDEFINED = "value of stdout.lastframe() is undefined";
|
|
47
|
+
|
|
48
|
+
export class OutputStream extends EventEmitter {
|
|
49
|
+
readonly frames: string[] = [];
|
|
50
|
+
private _lastFrame?: string;
|
|
51
|
+
|
|
52
|
+
get columns(): number {
|
|
53
|
+
return this._originalStream.columns;
|
|
54
|
+
}
|
|
55
|
+
get rows(): number {
|
|
56
|
+
return this._originalStream.rows;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
constructor(private _originalStream: WriteStream) {
|
|
60
|
+
super();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
write = (frame: string) => {
|
|
64
|
+
this.frames.push(frame);
|
|
65
|
+
this._lastFrame = frame;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
lastFrame = () => {
|
|
69
|
+
return this._lastFrame;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const render = (tree: ReactElement): Instance => {
|
|
74
|
+
const stdout = new OutputStream(process.stdout);
|
|
75
|
+
const stderr = new OutputStream(process.stderr);
|
|
76
|
+
|
|
77
|
+
const instance = inkRender(tree, {
|
|
78
|
+
stdout: stdout as unknown as WriteStream,
|
|
79
|
+
stderr: stderr as unknown as WriteStream,
|
|
80
|
+
debug: true,
|
|
81
|
+
exitOnCtrlC: false,
|
|
82
|
+
patchConsole: false,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
output: stdout.lastFrame() ?? LASTFRAME_UNDEFINED,
|
|
87
|
+
stdout,
|
|
88
|
+
stderr,
|
|
89
|
+
cleanup: instance.cleanup,
|
|
90
|
+
unmount: instance.unmount,
|
|
91
|
+
frames: stdout.frames,
|
|
92
|
+
};
|
|
93
|
+
};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import Table from "ink-table";
|
|
3
|
-
import React, { Fragment } from "react";
|
|
1
|
+
import chalk from "chalk";
|
|
4
2
|
import { fetchListResult, fetchResult } from "./cfetch";
|
|
5
3
|
import { logger } from "./logger";
|
|
6
4
|
import { getAPIToken, getAuthFromEnv, getScopes } from "./user";
|
|
@@ -8,82 +6,50 @@ import { getAPIToken, getAuthFromEnv, getScopes } from "./user";
|
|
|
8
6
|
export async function whoami() {
|
|
9
7
|
logger.log("Getting User settings...");
|
|
10
8
|
const user = await getUserInfo();
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return user ? (
|
|
17
|
-
<>
|
|
18
|
-
<Email tokenType={user.authType} email={user.email}></Email>
|
|
19
|
-
<Accounts accounts={user.accounts}></Accounts>
|
|
20
|
-
<Permissions
|
|
21
|
-
tokenType={user.authType}
|
|
22
|
-
tokenPermissions={user.tokenPermissions}
|
|
23
|
-
/>
|
|
24
|
-
</>
|
|
25
|
-
) : (
|
|
26
|
-
<Text>You are not authenticated. Please run `wrangler login`.</Text>
|
|
27
|
-
);
|
|
28
|
-
}
|
|
9
|
+
if (user === undefined) {
|
|
10
|
+
return void logger.log(
|
|
11
|
+
"You are not authenticated. Please run `wrangler login`."
|
|
12
|
+
);
|
|
13
|
+
}
|
|
29
14
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
15
|
+
if (user.email !== undefined) {
|
|
16
|
+
logger.log(
|
|
17
|
+
`👋 You are logged in with an ${
|
|
18
|
+
user.authType
|
|
19
|
+
}, associated with the email ${chalk.blue(user.email)}!`
|
|
20
|
+
);
|
|
21
|
+
} else {
|
|
22
|
+
logger.log(
|
|
23
|
+
`👋 You are logged in with an ${user.authType}. Unable to retrieve email for this user. Are you missing the \`User->User Details->Read\` permission?`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
logger.table(
|
|
27
|
+
user.accounts.map((account) => ({
|
|
28
|
+
"Account Name": account.name,
|
|
29
|
+
"Account ID": account.id,
|
|
30
|
+
}))
|
|
42
31
|
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function Accounts(props: { accounts: AccountInfo[] }) {
|
|
46
|
-
const accounts = props.accounts.map((account) => ({
|
|
47
|
-
"Account Name": account.name,
|
|
48
|
-
"Account ID": account.id,
|
|
49
|
-
}));
|
|
50
|
-
return <Table data={accounts}></Table>;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function Permissions(props: {
|
|
54
|
-
tokenPermissions: string[] | undefined;
|
|
55
|
-
tokenType: string;
|
|
56
|
-
}) {
|
|
57
32
|
const permissions =
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
{permissions.map(([scope, access], index) => (
|
|
68
|
-
<Fragment key={`${scope}${index}`}>
|
|
69
|
-
<Text>
|
|
70
|
-
- {scope} {access && `(${access})`}
|
|
71
|
-
</Text>
|
|
72
|
-
</Fragment>
|
|
73
|
-
))}
|
|
74
|
-
</>
|
|
75
|
-
) : null
|
|
76
|
-
) : (
|
|
77
|
-
<Text>
|
|
78
|
-
🔓 To see token permissions visit
|
|
79
|
-
https://dash.cloudflare.com/profile/api-tokens
|
|
80
|
-
</Text>
|
|
33
|
+
user.tokenPermissions?.map((scope) => scope.split(":")) ?? [];
|
|
34
|
+
|
|
35
|
+
if (user.authType !== "OAuth Token") {
|
|
36
|
+
return void logger.log(
|
|
37
|
+
`🔓 To see token permissions visit https://dash.cloudflare.com/profile/api-tokens`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
logger.log(
|
|
41
|
+
`🔓 Token Permissions: If scopes are missing, you may need to logout and re-login.`
|
|
81
42
|
);
|
|
43
|
+
logger.log(`Scope (Access)`);
|
|
44
|
+
for (const [scope, access] of permissions) {
|
|
45
|
+
logger.log(`- ${scope} ${access ? `(${access})` : ``}`);
|
|
46
|
+
}
|
|
82
47
|
}
|
|
83
48
|
|
|
49
|
+
type AuthType = "Global API Key" | "API Token" | "OAuth Token";
|
|
84
50
|
export interface UserInfo {
|
|
85
51
|
apiToken: string;
|
|
86
|
-
authType:
|
|
52
|
+
authType: AuthType;
|
|
87
53
|
email: string | undefined;
|
|
88
54
|
accounts: AccountInfo[];
|
|
89
55
|
tokenPermissions: string[] | undefined;
|