wrangler 0.0.0-e88a54e → 0.0.0-e95e5a0
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 +25 -14
- package/bin/wrangler.js +13 -1
- package/miniflare-dist/index.mjs +4828 -21
- package/package.json +29 -24
- package/pages/functions/buildPlugin.ts +92 -0
- package/pages/functions/buildWorker.ts +80 -4
- package/pages/functions/filepath-routing.test.ts +11 -0
- package/pages/functions/filepath-routing.ts +8 -0
- package/pages/functions/routes.ts +6 -1
- package/pages/functions/template-plugin.ts +146 -0
- package/pages/functions/template-worker.ts +21 -8
- package/src/__tests__/config-cache.test.ts +36 -0
- package/src/__tests__/configuration.test.ts +530 -201
- package/src/__tests__/dev.test.tsx +284 -18
- package/src/__tests__/guess-worker-format.test.ts +28 -1
- package/src/__tests__/helpers/mock-cfetch.ts +5 -1
- package/src/__tests__/helpers/mock-console.ts +20 -3
- 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-oauth-flow.ts +255 -0
- package/src/__tests__/helpers/run-in-tmp.ts +7 -0
- package/src/__tests__/helpers/write-worker-source.ts +31 -0
- package/src/__tests__/https-options.test.ts +5 -2
- package/src/__tests__/index.test.ts +27 -769
- package/src/__tests__/init.test.ts +1516 -0
- package/src/__tests__/jest.setup.ts +4 -4
- package/src/__tests__/kv.test.ts +133 -61
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +311 -26
- package/src/__tests__/publish.test.ts +2789 -618
- package/src/__tests__/r2.test.ts +26 -10
- package/src/__tests__/route.test.ts +4 -4
- package/src/__tests__/secret.test.ts +55 -34
- package/src/__tests__/tail.test.ts +146 -20
- package/src/__tests__/user.test.ts +131 -0
- package/src/__tests__/whoami.test.tsx +14 -9
- package/src/bundle.ts +30 -3
- package/src/cfetch/internal.ts +0 -2
- package/src/cli.ts +5 -11
- package/src/config/README.md +1 -1
- package/src/config/config.ts +20 -4
- package/src/config/environment.ts +32 -4
- package/src/config/index.ts +4 -3
- package/src/config/validation-helpers.ts +96 -7
- package/src/config/validation.ts +388 -54
- package/src/config-cache.ts +45 -0
- package/src/create-worker-preview.ts +22 -13
- package/src/create-worker-upload-form.ts +32 -9
- package/src/dev/dev-vars.ts +36 -0
- package/src/dev/dev.tsx +132 -78
- package/src/dev/local.tsx +101 -21
- package/src/dev/remote.tsx +23 -13
- package/src/dev/use-esbuild.ts +23 -5
- package/src/dialogs.tsx +16 -6
- package/src/entry.ts +83 -24
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +3 -2
- package/src/index.tsx +689 -394
- package/src/inspect.ts +17 -11
- package/src/intl-polyfill.d.ts +139 -0
- package/src/logger.ts +66 -0
- package/src/miniflare-cli/index.ts +4 -0
- package/src/miniflare-cli/request-context.ts +40 -0
- package/src/module-collection.ts +7 -7
- package/src/open-in-browser.ts +5 -4
- package/src/package-manager.ts +9 -8
- package/src/pages.tsx +875 -56
- package/src/parse.ts +1 -1
- package/src/proxy.ts +28 -19
- package/src/publish.ts +263 -141
- package/src/sites.tsx +27 -14
- 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 +116 -41
- package/src/whoami.tsx +2 -1
- package/src/worker.ts +15 -6
- package/templates/gitignore +171 -0
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +21162 -50227
- package/miniflare-dist/index.mjs.map +0 -7
- package/src/__tests__/dev2.test.tsx +0 -154
- package/src/__tests__/logout.test.ts +0 -52
- package/src/__tests__/sentry.test.ts +0 -146
- package/src/reporting.ts +0 -131
- package/wrangler-dist/cli.js.map +0 -7
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { render } from "ink-testing-library";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { writeAuthConfigFile } from "../user";
|
|
4
4
|
import { getUserInfo, WhoAmI } from "../whoami";
|
|
5
5
|
import { setMockResponse } from "./helpers/mock-cfetch";
|
|
6
6
|
import { mockConsoleMethods } from "./helpers/mock-console";
|
|
7
|
+
import { useMockIsTTY } from "./helpers/mock-istty";
|
|
7
8
|
import { runInTempDir } from "./helpers/run-in-tmp";
|
|
8
9
|
import type { UserInfo } from "../whoami";
|
|
9
10
|
|
|
10
11
|
describe("getUserInfo()", () => {
|
|
11
12
|
runInTempDir({ homedir: "./home" });
|
|
12
13
|
const std = mockConsoleMethods();
|
|
14
|
+
const { setIsTTY } = useMockIsTTY();
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
setIsTTY(true);
|
|
18
|
+
});
|
|
13
19
|
|
|
14
20
|
it("should return undefined if there is no config file", async () => {
|
|
15
21
|
const userInfo = await getUserInfo();
|
|
@@ -18,16 +24,12 @@ describe("getUserInfo()", () => {
|
|
|
18
24
|
|
|
19
25
|
it("should return undefined if there is an empty config file", async () => {
|
|
20
26
|
writeAuthConfigFile({});
|
|
21
|
-
// Now that we have changed the auth tokens in the wrangler.toml we must reinitialize the user auth state.
|
|
22
|
-
reinitialiseAuthTokens();
|
|
23
27
|
const userInfo = await getUserInfo();
|
|
24
28
|
expect(userInfo).toBeUndefined();
|
|
25
29
|
});
|
|
26
30
|
|
|
27
31
|
it("should return the user's email and accounts if authenticated via config token", async () => {
|
|
28
32
|
writeAuthConfigFile({ oauth_token: "some-oauth-token" });
|
|
29
|
-
// Now that we have changed the auth tokens in the wrangler.toml we must reinitialize the user auth state.
|
|
30
|
-
reinitialiseAuthTokens();
|
|
31
33
|
|
|
32
34
|
setMockResponse("/user", () => {
|
|
33
35
|
return { email: "user@example.com" };
|
|
@@ -56,12 +58,15 @@ describe("getUserInfo()", () => {
|
|
|
56
58
|
|
|
57
59
|
it("should display a warning message if the config file contains a legacy api_token field", async () => {
|
|
58
60
|
writeAuthConfigFile({ api_token: "API_TOKEN" });
|
|
59
|
-
await reinitialiseAuthTokens();
|
|
60
61
|
await getUserInfo();
|
|
61
62
|
expect(std.warn).toMatchInlineSnapshot(`
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
"[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mIt looks like you have used Wrangler 1's \`config\` command to login with an API token.[0m
|
|
64
|
+
|
|
65
|
+
This is no longer supported in the current version of Wrangler.
|
|
66
|
+
If you wish to authenticate via an API token then please set the \`CLOUDFLARE_API_TOKEN\`
|
|
67
|
+
environment variable.
|
|
68
|
+
|
|
69
|
+
"
|
|
65
70
|
`);
|
|
66
71
|
});
|
|
67
72
|
});
|
package/src/bundle.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import NodeGlobalsPolyfills from "@esbuild-plugins/node-globals-polyfill";
|
|
5
|
+
import NodeModulesPolyfills from "@esbuild-plugins/node-modules-polyfill";
|
|
4
6
|
import * as esbuild from "esbuild";
|
|
5
7
|
import createModuleCollector from "./module-collection";
|
|
6
8
|
import type { Config } from "./config";
|
|
@@ -26,10 +28,21 @@ export async function bundleWorker(
|
|
|
26
28
|
jsxFragment: string | undefined;
|
|
27
29
|
rules: Config["rules"];
|
|
28
30
|
watch?: esbuild.WatchMode;
|
|
31
|
+
tsconfig: string | undefined;
|
|
32
|
+
minify: boolean | undefined;
|
|
33
|
+
nodeCompat: boolean | undefined;
|
|
29
34
|
}
|
|
30
35
|
): Promise<BundleResult> {
|
|
31
|
-
const {
|
|
32
|
-
|
|
36
|
+
const {
|
|
37
|
+
serveAssetsFromWorker,
|
|
38
|
+
jsxFactory,
|
|
39
|
+
jsxFragment,
|
|
40
|
+
rules,
|
|
41
|
+
watch,
|
|
42
|
+
tsconfig,
|
|
43
|
+
minify,
|
|
44
|
+
nodeCompat,
|
|
45
|
+
} = options;
|
|
33
46
|
const entryDirectory = path.dirname(entry.file);
|
|
34
47
|
const moduleCollector = createModuleCollector({
|
|
35
48
|
wrangler1xlegacyModuleReferences: {
|
|
@@ -54,17 +67,31 @@ export async function bundleWorker(
|
|
|
54
67
|
outdir: destination,
|
|
55
68
|
external: ["__STATIC_CONTENT_MANIFEST"],
|
|
56
69
|
format: "esm",
|
|
70
|
+
target: "es2020",
|
|
57
71
|
sourcemap: true,
|
|
72
|
+
minify,
|
|
58
73
|
metafile: true,
|
|
59
74
|
conditions: ["worker", "browser"],
|
|
75
|
+
...(process.env.NODE_ENV && {
|
|
76
|
+
define: {
|
|
77
|
+
"process.env.NODE_ENV": `"${process.env.NODE_ENV}"`,
|
|
78
|
+
...(nodeCompat ? { global: "globalThis" } : {}),
|
|
79
|
+
},
|
|
80
|
+
}),
|
|
60
81
|
loader: {
|
|
61
82
|
".js": "jsx",
|
|
62
83
|
".mjs": "jsx",
|
|
63
84
|
".cjs": "jsx",
|
|
64
85
|
},
|
|
65
|
-
plugins: [
|
|
86
|
+
plugins: [
|
|
87
|
+
moduleCollector.plugin,
|
|
88
|
+
...(nodeCompat
|
|
89
|
+
? [NodeGlobalsPolyfills({ buffer: true }), NodeModulesPolyfills()]
|
|
90
|
+
: []),
|
|
91
|
+
],
|
|
66
92
|
...(jsxFactory && { jsxFactory }),
|
|
67
93
|
...(jsxFragment && { jsxFragment }),
|
|
94
|
+
...(tsconfig && { tsconfig }),
|
|
68
95
|
watch,
|
|
69
96
|
});
|
|
70
97
|
|
package/src/cfetch/internal.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { fetch, Headers } from "undici";
|
|
2
2
|
import { getEnvironmentVariableFactory } from "../environment-variables";
|
|
3
3
|
import { ParseError, parseJSON } from "../parse";
|
|
4
|
-
import { reportError } from "../reporting";
|
|
5
4
|
import { getAPIToken, loginOrRefreshIfRequired } from "../user";
|
|
6
5
|
import type { URLSearchParams } from "node:url";
|
|
7
6
|
import type { RequestInit, HeadersInit } from "undici";
|
|
@@ -48,7 +47,6 @@ export async function fetchInternal<ResponseType>(
|
|
|
48
47
|
try {
|
|
49
48
|
return parseJSON(jsonText) as ResponseType;
|
|
50
49
|
} catch (err) {
|
|
51
|
-
await reportError(err as Error);
|
|
52
50
|
throw new ParseError({
|
|
53
51
|
text: "Received a malformed response from the API",
|
|
54
52
|
notes: [
|
package/src/cli.ts
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
|
+
import "dotenv/config"; // Grab locally specified env params from a `.env` file.
|
|
1
2
|
import process from "process";
|
|
2
3
|
import { hideBin } from "yargs/helpers";
|
|
3
|
-
import {
|
|
4
|
+
import { FatalError } from "./errors";
|
|
4
5
|
import { main } from ".";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
initReporting();
|
|
8
|
-
} catch (error) {}
|
|
9
|
-
|
|
10
|
-
process.on("uncaughtExceptionMonitor", async (err, origin) => {
|
|
11
|
-
await reportError(err, origin);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
main(hideBin(process.argv)).catch(() => {
|
|
7
|
+
main(hideBin(process.argv)).catch((e) => {
|
|
15
8
|
// The logging of any error that was thrown from `main()` is handled in the `yargs.fail()` handler.
|
|
16
9
|
// Here we just want to ensure that the process exits with a non-zero code.
|
|
17
10
|
// We don't want to do this inside the `main()` function, since that would kill the process when running our tests.
|
|
18
|
-
|
|
11
|
+
const exitCode = (e instanceof FatalError && e.code) || 1;
|
|
12
|
+
process.exit(exitCode);
|
|
19
13
|
});
|
package/src/config/README.md
CHANGED
|
@@ -48,7 +48,7 @@ This function will return:
|
|
|
48
48
|
- a `Diagnostics` object, which contains any errors or warnings from the validation process
|
|
49
49
|
|
|
50
50
|
The field values may have been parsed directly from the `RawConfig`, inherited into a named environment from the top-level environment, or given a default value.
|
|
51
|
-
Generally, if there are any warnings they should be presented to the user via `
|
|
51
|
+
Generally, if there are any warnings they should be presented to the user via `logger.warn()` messages,
|
|
52
52
|
and if there are any errors then an `Error` should be thrown describing these errors.
|
|
53
53
|
|
|
54
54
|
The `Diagnostics` object is hierarchical: each `Diagnostics` instance can contain a collection of child `Diagnostics` instance.
|
package/src/config/config.ts
CHANGED
|
@@ -135,6 +135,17 @@ export interface ConfigFields<Dev extends RawDevConfig> {
|
|
|
135
135
|
[key: string]: string;
|
|
136
136
|
}
|
|
137
137
|
| undefined;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* A list of data files that your worker should be bound to. This is
|
|
141
|
+
* the "legacy" way of binding to a data file. ES module workers should
|
|
142
|
+
* do proper module imports.
|
|
143
|
+
*/
|
|
144
|
+
data_blobs:
|
|
145
|
+
| {
|
|
146
|
+
[key: string]: string;
|
|
147
|
+
}
|
|
148
|
+
| undefined;
|
|
138
149
|
}
|
|
139
150
|
|
|
140
151
|
export interface DevConfig {
|
|
@@ -142,7 +153,6 @@ export interface DevConfig {
|
|
|
142
153
|
* IP address for the local dev server to listen on,
|
|
143
154
|
*
|
|
144
155
|
* @default `localhost`
|
|
145
|
-
* @todo this needs to be implemented
|
|
146
156
|
*/
|
|
147
157
|
ip: string;
|
|
148
158
|
|
|
@@ -157,7 +167,6 @@ export interface DevConfig {
|
|
|
157
167
|
* Protocol that local wrangler dev server listens to requests on.
|
|
158
168
|
*
|
|
159
169
|
* @default `http`
|
|
160
|
-
* @todo this needs to be implemented
|
|
161
170
|
*/
|
|
162
171
|
local_protocol: "http" | "https";
|
|
163
172
|
|
|
@@ -168,13 +177,14 @@ export interface DevConfig {
|
|
|
168
177
|
* See https://github.com/cloudflare/wrangler2/issues/583
|
|
169
178
|
*
|
|
170
179
|
* @default `https`
|
|
180
|
+
* @todo this needs to be implemented https://github.com/cloudflare/wrangler2/issues/583
|
|
171
181
|
*/
|
|
172
182
|
upstream_protocol: "https" | "http";
|
|
173
183
|
|
|
174
184
|
/**
|
|
175
|
-
* Host to forward requests to, defaults to the
|
|
185
|
+
* Host to forward requests to, defaults to the host of the first route of project
|
|
176
186
|
*/
|
|
177
|
-
host:
|
|
187
|
+
host: Config["route"];
|
|
178
188
|
}
|
|
179
189
|
|
|
180
190
|
export type RawDevConfig = Partial<DevConfig>;
|
|
@@ -197,6 +207,12 @@ export interface DeprecatedConfigFields {
|
|
|
197
207
|
* @breaking
|
|
198
208
|
*/
|
|
199
209
|
webpack_config?: string;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Configuration only used by a standalone use of the miniflare binary.
|
|
213
|
+
* @deprecated
|
|
214
|
+
*/
|
|
215
|
+
miniflare?: unknown;
|
|
200
216
|
}
|
|
201
217
|
|
|
202
218
|
interface EnvironmentMap {
|
|
@@ -64,7 +64,7 @@ interface EnvironmentInheritable {
|
|
|
64
64
|
* @breaking
|
|
65
65
|
* @inheritable
|
|
66
66
|
*/
|
|
67
|
-
workers_dev: boolean;
|
|
67
|
+
workers_dev: boolean | undefined;
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* A list of routes that your worker should be published to.
|
|
@@ -74,7 +74,13 @@ interface EnvironmentInheritable {
|
|
|
74
74
|
*
|
|
75
75
|
* @inheritable
|
|
76
76
|
*/
|
|
77
|
-
routes:
|
|
77
|
+
routes:
|
|
78
|
+
| (
|
|
79
|
+
| string
|
|
80
|
+
| { pattern: string; zone_id: string }
|
|
81
|
+
| { pattern: string; zone_name: string }
|
|
82
|
+
)[]
|
|
83
|
+
| undefined;
|
|
78
84
|
|
|
79
85
|
/**
|
|
80
86
|
* A route that your worker should be published to. Literally
|
|
@@ -85,7 +91,18 @@ interface EnvironmentInheritable {
|
|
|
85
91
|
*
|
|
86
92
|
* @inheritable
|
|
87
93
|
*/
|
|
88
|
-
route:
|
|
94
|
+
route:
|
|
95
|
+
| (
|
|
96
|
+
| string
|
|
97
|
+
| { pattern: string; zone_id: string }
|
|
98
|
+
| { pattern: string; zone_name: string }
|
|
99
|
+
)
|
|
100
|
+
| undefined;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Path to a custom tsconfig
|
|
104
|
+
*/
|
|
105
|
+
tsconfig: string | undefined;
|
|
89
106
|
|
|
90
107
|
/**
|
|
91
108
|
* The function to use to replace jsx syntax.
|
|
@@ -126,7 +143,7 @@ interface EnvironmentInheritable {
|
|
|
126
143
|
*
|
|
127
144
|
* @inheritable
|
|
128
145
|
*/
|
|
129
|
-
usage_model:
|
|
146
|
+
usage_model: "bundled" | "unbound" | undefined;
|
|
130
147
|
|
|
131
148
|
/**
|
|
132
149
|
* An ordered list of rules that define which modules to import,
|
|
@@ -160,6 +177,17 @@ interface EnvironmentInheritable {
|
|
|
160
177
|
upload?: DeprecatedUpload;
|
|
161
178
|
};
|
|
162
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Minify the script before uploading.
|
|
182
|
+
* @inheritable
|
|
183
|
+
*/
|
|
184
|
+
minify: boolean | undefined;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Add polyfills for node builtin modules and globals
|
|
188
|
+
*/
|
|
189
|
+
node_compat: boolean | undefined;
|
|
190
|
+
|
|
163
191
|
/**
|
|
164
192
|
* TODO: remove this as it has been deprecated.
|
|
165
193
|
*
|
package/src/config/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { findUpSync } from "find-up";
|
|
2
|
+
import { logger } from "../logger";
|
|
2
3
|
import { parseTOML, readFileSync } from "../parse";
|
|
3
4
|
import { normalizeAndValidateConfig } from "./validation";
|
|
4
5
|
import type { Config, RawConfig } from "./config";
|
|
@@ -21,7 +22,7 @@ export type {
|
|
|
21
22
|
*/
|
|
22
23
|
export function readConfig(
|
|
23
24
|
configPath: string | undefined,
|
|
24
|
-
|
|
25
|
+
args: unknown
|
|
25
26
|
): Config {
|
|
26
27
|
let rawConfig: RawConfig = {};
|
|
27
28
|
if (!configPath) {
|
|
@@ -37,11 +38,11 @@ export function readConfig(
|
|
|
37
38
|
const { config, diagnostics } = normalizeAndValidateConfig(
|
|
38
39
|
rawConfig,
|
|
39
40
|
configPath,
|
|
40
|
-
|
|
41
|
+
args
|
|
41
42
|
);
|
|
42
43
|
|
|
43
44
|
if (diagnostics.hasWarnings()) {
|
|
44
|
-
|
|
45
|
+
logger.warn(diagnostics.renderWarnings());
|
|
45
46
|
}
|
|
46
47
|
if (diagnostics.hasErrors()) {
|
|
47
48
|
throw new Error(diagnostics.renderErrors());
|
|
@@ -14,13 +14,15 @@ export function deprecated<T extends object>(
|
|
|
14
14
|
fieldPath: DeepKeyOf<T>,
|
|
15
15
|
message: string,
|
|
16
16
|
remove: boolean,
|
|
17
|
-
|
|
17
|
+
title = "Deprecation",
|
|
18
|
+
type: "warning" | "error" = "warning"
|
|
18
19
|
): void {
|
|
20
|
+
const BOLD = "\x1b[1m";
|
|
21
|
+
const NORMAL = "\x1b[0m";
|
|
22
|
+
const diagnosticMessage = `${BOLD}${title}${NORMAL}: "${fieldPath}":\n${message}`;
|
|
19
23
|
const result = unwindPropertyPath(config, fieldPath);
|
|
20
24
|
if (result !== undefined && result.field in result.container) {
|
|
21
|
-
|
|
22
|
-
`DEPRECATION: "${fieldPath}":\n${message}`
|
|
23
|
-
);
|
|
25
|
+
diagnostics[`${type}s`].push(diagnosticMessage);
|
|
24
26
|
if (remove) {
|
|
25
27
|
delete (result.container as Record<string, unknown>)[result.field];
|
|
26
28
|
}
|
|
@@ -58,11 +60,14 @@ export function inheritable<K extends keyof Environment>(
|
|
|
58
60
|
rawEnv: RawEnvironment,
|
|
59
61
|
field: K,
|
|
60
62
|
validate: ValidatorFn,
|
|
61
|
-
defaultValue: Environment[K]
|
|
63
|
+
defaultValue: Environment[K],
|
|
64
|
+
transformFn: TransformFn<Environment[K]> = (v) => v
|
|
62
65
|
): Environment[K] {
|
|
63
66
|
validate(diagnostics, field, rawEnv[field], topLevelEnv);
|
|
64
67
|
return (
|
|
65
|
-
(rawEnv[field] as Environment[K]) ??
|
|
68
|
+
(rawEnv[field] as Environment[K]) ??
|
|
69
|
+
transformFn(topLevelEnv?.[field]) ??
|
|
70
|
+
defaultValue
|
|
66
71
|
);
|
|
67
72
|
}
|
|
68
73
|
|
|
@@ -76,6 +81,7 @@ export function inheritableInLegacyEnvironments<K extends keyof Environment>(
|
|
|
76
81
|
rawEnv: RawEnvironment,
|
|
77
82
|
field: K,
|
|
78
83
|
validate: ValidatorFn,
|
|
84
|
+
transformFn: TransformFn<Environment[K]> = (v) => v,
|
|
79
85
|
defaultValue: Environment[K]
|
|
80
86
|
): Environment[K] {
|
|
81
87
|
return topLevelEnv === undefined || isLegacyEnv === true
|
|
@@ -85,7 +91,8 @@ export function inheritableInLegacyEnvironments<K extends keyof Environment>(
|
|
|
85
91
|
rawEnv,
|
|
86
92
|
field,
|
|
87
93
|
validate,
|
|
88
|
-
defaultValue
|
|
94
|
+
defaultValue,
|
|
95
|
+
transformFn
|
|
89
96
|
)
|
|
90
97
|
: notAllowedInNamedServiceEnvironment(
|
|
91
98
|
diagnostics,
|
|
@@ -95,6 +102,19 @@ export function inheritableInLegacyEnvironments<K extends keyof Environment>(
|
|
|
95
102
|
);
|
|
96
103
|
}
|
|
97
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Type of function that is used to transform an inheritable environment field.
|
|
107
|
+
*/
|
|
108
|
+
type TransformFn<T> = (fieldValue: T | undefined) => T | undefined;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Transform an environment field by appending current environment name to it.
|
|
112
|
+
*/
|
|
113
|
+
export const appendEnvName =
|
|
114
|
+
(envName: string): TransformFn<string | undefined> =>
|
|
115
|
+
(fieldValue) =>
|
|
116
|
+
fieldValue ? `${fieldValue}-${envName}` : undefined;
|
|
117
|
+
|
|
98
118
|
/**
|
|
99
119
|
* Log an error if this named environment is trying to override the value in the top-level
|
|
100
120
|
* environment, which is not allow for this field.
|
|
@@ -207,6 +227,25 @@ export const isString: ValidatorFn = (diagnostics, field, value) => {
|
|
|
207
227
|
return true;
|
|
208
228
|
};
|
|
209
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Validate that the `name` field is compliant with EWC constraints.
|
|
232
|
+
*/
|
|
233
|
+
export const isValidName: ValidatorFn = (diagnostics, field, value) => {
|
|
234
|
+
if (
|
|
235
|
+
(typeof value === "string" && /^$|^[a-z0-9_ ][a-z0-9-_ ]*$/.test(value)) ||
|
|
236
|
+
value === undefined
|
|
237
|
+
) {
|
|
238
|
+
return true;
|
|
239
|
+
} else {
|
|
240
|
+
diagnostics.errors.push(
|
|
241
|
+
`Expected "${field}" to be of type string, alphanumeric and lowercase with dashes only but got ${JSON.stringify(
|
|
242
|
+
value
|
|
243
|
+
)}.`
|
|
244
|
+
);
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
210
249
|
/**
|
|
211
250
|
* Validate that the field is an array of strings.
|
|
212
251
|
*/
|
|
@@ -484,3 +523,53 @@ export const validateAdditionalProperties = (
|
|
|
484
523
|
}
|
|
485
524
|
return true;
|
|
486
525
|
};
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Get the names of the bindings collection in `value`.
|
|
529
|
+
*
|
|
530
|
+
* Will return an empty array if it doesn't understand the value
|
|
531
|
+
* passed in, so another form of validation should be
|
|
532
|
+
* performed externally.
|
|
533
|
+
*/
|
|
534
|
+
export const getBindingNames = (value: unknown): string[] => {
|
|
535
|
+
if (typeof value !== "object" || value === null) {
|
|
536
|
+
return [];
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (isBindingList(value)) {
|
|
540
|
+
return value.bindings.map(({ name }) => name);
|
|
541
|
+
} else if (isNamespaceList(value)) {
|
|
542
|
+
return value.map(({ binding }) => binding);
|
|
543
|
+
} else if (isRecord(value)) {
|
|
544
|
+
return Object.keys(value);
|
|
545
|
+
} else {
|
|
546
|
+
return [];
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
const isBindingList = (
|
|
551
|
+
value: unknown
|
|
552
|
+
): value is {
|
|
553
|
+
bindings: {
|
|
554
|
+
name: string;
|
|
555
|
+
}[];
|
|
556
|
+
} =>
|
|
557
|
+
isRecord(value) &&
|
|
558
|
+
"bindings" in value &&
|
|
559
|
+
Array.isArray(value.bindings) &&
|
|
560
|
+
value.bindings.every(
|
|
561
|
+
(binding) =>
|
|
562
|
+
isRecord(binding) && "name" in binding && typeof binding.name === "string"
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
const isNamespaceList = (value: unknown): value is { binding: string }[] =>
|
|
566
|
+
Array.isArray(value) &&
|
|
567
|
+
value.every(
|
|
568
|
+
(entry) =>
|
|
569
|
+
isRecord(entry) && "binding" in entry && typeof entry.binding === "string"
|
|
570
|
+
);
|
|
571
|
+
|
|
572
|
+
const isRecord = (
|
|
573
|
+
value: unknown
|
|
574
|
+
): value is Record<string | number | symbol, unknown> =>
|
|
575
|
+
typeof value === "object" && value !== null && !Array.isArray(value);
|