netlify-cli 17.3.2 → 17.4.0
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 +2 -138
- package/npm-shrinkwrap.json +76 -76
- package/package.json +16 -15
- package/src/commands/addons/addons-auth.mjs +27 -30
- package/src/commands/addons/addons-config.mjs +145 -154
- package/src/commands/addons/addons-create.mjs +94 -108
- package/src/commands/addons/addons-delete.mjs +36 -41
- package/src/commands/addons/addons-list.mjs +38 -42
- package/src/commands/addons/addons.mjs +26 -28
- package/src/commands/addons/index.mjs +1 -1
- package/src/commands/api/api.mjs +45 -53
- package/src/commands/api/index.mjs +1 -1
- package/src/commands/base-command.mjs +597 -684
- package/src/commands/blobs/blobs-delete.mjs +35 -0
- package/src/commands/blobs/blobs-get.mjs +44 -0
- package/src/commands/blobs/blobs-list.mjs +48 -0
- package/src/commands/blobs/blobs-set.mjs +54 -0
- package/src/commands/blobs/blobs.mjs +32 -0
- package/src/commands/blobs/index.mjs +1 -0
- package/src/commands/build/build.mjs +55 -67
- package/src/commands/build/index.mjs +1 -1
- package/src/commands/completion/completion.mjs +41 -46
- package/src/commands/completion/index.mjs +1 -1
- package/src/commands/deploy/deploy.mjs +675 -710
- package/src/commands/deploy/index.mjs +1 -1
- package/src/commands/dev/dev-exec.mjs +20 -32
- package/src/commands/dev/dev.mjs +217 -302
- package/src/commands/dev/index.mjs +1 -1
- package/src/commands/dev/types.d.ts +30 -0
- package/src/commands/env/env-clone.mjs +157 -184
- package/src/commands/env/env-get.mjs +49 -68
- package/src/commands/env/env-import.mjs +100 -119
- package/src/commands/env/env-list.mjs +104 -129
- package/src/commands/env/env-set.mjs +160 -185
- package/src/commands/env/env-unset.mjs +104 -122
- package/src/commands/env/env.mjs +28 -30
- package/src/commands/env/index.mjs +1 -1
- package/src/commands/functions/functions-build.mjs +29 -41
- package/src/commands/functions/functions-create.mjs +533 -601
- package/src/commands/functions/functions-invoke.mjs +193 -216
- package/src/commands/functions/functions-list.mjs +45 -55
- package/src/commands/functions/functions-serve.mjs +51 -61
- package/src/commands/functions/functions.mjs +26 -32
- package/src/commands/functions/index.mjs +1 -1
- package/src/commands/index.mjs +2 -2
- package/src/commands/init/index.mjs +1 -1
- package/src/commands/init/init.mjs +138 -167
- package/src/commands/integration/deploy.mjs +337 -399
- package/src/commands/integration/index.mjs +12 -13
- package/src/commands/link/index.mjs +1 -1
- package/src/commands/link/link.mjs +298 -317
- package/src/commands/lm/index.mjs +1 -1
- package/src/commands/lm/lm-info.mjs +23 -31
- package/src/commands/lm/lm-install.mjs +13 -17
- package/src/commands/lm/lm-setup.mjs +80 -84
- package/src/commands/lm/lm-uninstall.mjs +7 -12
- package/src/commands/lm/lm.mjs +18 -22
- package/src/commands/login/index.mjs +1 -1
- package/src/commands/login/login.mjs +35 -41
- package/src/commands/logout/index.mjs +1 -1
- package/src/commands/logout/logout.mjs +25 -31
- package/src/commands/main.mjs +166 -201
- package/src/commands/open/index.mjs +1 -1
- package/src/commands/open/open-admin.mjs +15 -18
- package/src/commands/open/open-site.mjs +16 -19
- package/src/commands/open/open.mjs +24 -27
- package/src/commands/recipes/common.mjs +23 -34
- package/src/commands/recipes/index.mjs +1 -1
- package/src/commands/recipes/recipes-list.mjs +13 -20
- package/src/commands/recipes/recipes.mjs +59 -72
- package/src/commands/serve/index.mjs +1 -1
- package/src/commands/serve/serve.mjs +142 -189
- package/src/commands/sites/index.mjs +2 -2
- package/src/commands/sites/sites-create-template.mjs +214 -236
- package/src/commands/sites/sites-create.mjs +145 -157
- package/src/commands/sites/sites-delete.mjs +75 -81
- package/src/commands/sites/sites-list.mjs +63 -66
- package/src/commands/sites/sites.mjs +18 -20
- package/src/commands/status/index.mjs +1 -1
- package/src/commands/status/status-hooks.mjs +32 -34
- package/src/commands/status/status.mjs +99 -106
- package/src/commands/switch/index.mjs +1 -1
- package/src/commands/switch/switch.mjs +32 -37
- package/src/commands/types.d.ts +31 -0
- package/src/commands/unlink/index.mjs +1 -1
- package/src/commands/unlink/unlink.mjs +23 -29
- package/src/commands/watch/index.mjs +1 -1
- package/src/commands/watch/watch.mjs +91 -105
- package/src/functions-templates/javascript/hello/{{name}}.js +2 -3
- package/src/lib/account.mjs +4 -5
- package/src/lib/api.mjs +22 -20
- package/src/lib/blobs/blobs.mjs +36 -45
- package/src/lib/build.mjs +82 -85
- package/src/lib/completion/constants.mjs +2 -4
- package/src/lib/completion/generate-autocompletion.mjs +33 -36
- package/src/lib/completion/get-autocompletion.mjs +31 -35
- package/src/lib/completion/index.mjs +1 -1
- package/src/lib/completion/script.mjs +12 -19
- package/src/lib/edge-functions/bootstrap.mjs +3 -5
- package/src/lib/edge-functions/consts.mjs +9 -10
- package/src/lib/edge-functions/deploy.mjs +28 -34
- package/src/lib/edge-functions/editor-helper.mjs +29 -42
- package/src/lib/edge-functions/headers.mjs +24 -26
- package/src/lib/edge-functions/internal.mjs +38 -44
- package/src/lib/edge-functions/proxy.mjs +229 -228
- package/src/lib/edge-functions/registry.mjs +473 -574
- package/src/lib/exec-fetcher.mjs +115 -122
- package/src/lib/fs.mjs +28 -27
- package/src/lib/functions/background.mjs +16 -20
- package/src/lib/functions/config.mjs +12 -9
- package/src/lib/functions/form-submissions-handler.mjs +143 -149
- package/src/lib/functions/local-proxy.mjs +40 -44
- package/src/lib/functions/memoized-build.mjs +19 -21
- package/src/lib/functions/netlify-function.mjs +269 -249
- package/src/lib/functions/registry.mjs +509 -568
- package/src/lib/functions/runtimes/go/index.mjs +62 -71
- package/src/lib/functions/runtimes/index.mjs +8 -15
- package/src/lib/functions/runtimes/js/builders/netlify-lambda.mjs +55 -64
- package/src/lib/functions/runtimes/js/builders/zisi.mjs +135 -154
- package/src/lib/functions/runtimes/js/constants.mjs +1 -1
- package/src/lib/functions/runtimes/js/index.mjs +92 -109
- package/src/lib/functions/runtimes/js/worker.mjs +43 -45
- package/src/lib/functions/runtimes/rust/index.mjs +64 -73
- package/src/lib/functions/scheduled.mjs +70 -88
- package/src/lib/functions/server.mjs +269 -327
- package/src/lib/functions/synchronous.mjs +118 -147
- package/src/lib/functions/utils.mjs +38 -46
- package/src/lib/geo-location.mjs +69 -81
- package/src/lib/http-agent.mjs +87 -90
- package/src/lib/images/proxy.mjs +97 -99
- package/src/lib/log.mjs +6 -9
- package/src/lib/path.mjs +2 -1
- package/src/lib/render-error-template.mjs +19 -20
- package/src/lib/settings.mjs +17 -19
- package/src/lib/spinner.mjs +21 -23
- package/src/lib/string.mjs +4 -2
- package/src/recipes/vscode/index.mjs +69 -85
- package/src/recipes/vscode/settings.mjs +53 -58
- package/src/utils/addons/compare.mjs +31 -32
- package/src/utils/addons/diffs/index.mjs +16 -17
- package/src/utils/addons/diffs/options.mjs +99 -101
- package/src/utils/addons/prepare.mjs +100 -97
- package/src/utils/addons/prompts.mjs +73 -76
- package/src/utils/addons/render.mjs +33 -36
- package/src/utils/addons/validation.mjs +19 -15
- package/src/utils/banner.mjs +11 -16
- package/src/utils/build-info.mjs +65 -66
- package/src/utils/command-helpers.mjs +185 -199
- package/src/utils/create-deferred.mjs +9 -12
- package/src/utils/create-stream-promise.mjs +54 -47
- package/src/utils/deploy/constants.mjs +9 -11
- package/src/utils/deploy/deploy-site.mjs +162 -182
- package/src/utils/deploy/hash-config.mjs +21 -21
- package/src/utils/deploy/hash-files.mjs +34 -38
- package/src/utils/deploy/hash-fns.mjs +149 -154
- package/src/utils/deploy/hasher-segments.mjs +58 -52
- package/src/utils/deploy/upload-files.mjs +99 -113
- package/src/utils/deploy/util.mjs +85 -91
- package/src/utils/detect-server-settings.mjs +236 -268
- package/src/utils/dev.mjs +163 -178
- package/src/utils/dot-env.mjs +37 -42
- package/src/utils/env/index.mjs +148 -148
- package/src/utils/execa.mjs +9 -13
- package/src/utils/feature-flags.mjs +6 -5
- package/src/utils/framework-server.mjs +43 -52
- package/src/utils/functions/constants.mjs +1 -1
- package/src/utils/functions/functions.mjs +30 -40
- package/src/utils/functions/get-functions.mjs +28 -29
- package/src/utils/functions/index.mjs +3 -3
- package/src/utils/get-global-config.mjs +33 -36
- package/src/utils/get-package-json.mjs +14 -15
- package/src/utils/get-repo-data.mjs +54 -64
- package/src/utils/get-site.mjs +14 -14
- package/src/utils/gh-auth.mjs +79 -100
- package/src/utils/gitignore.mjs +37 -40
- package/src/utils/headers.mjs +33 -35
- package/src/utils/hooks/requires-site-info.mjs +26 -22
- package/src/utils/init/config-github.mjs +207 -219
- package/src/utils/init/config-manual.mjs +83 -100
- package/src/utils/init/config.mjs +25 -26
- package/src/utils/init/node-version.mjs +23 -30
- package/src/utils/init/plugins.mjs +12 -8
- package/src/utils/init/utils.mjs +152 -172
- package/src/utils/live-tunnel.mjs +118 -141
- package/src/utils/lm/install.mjs +220 -259
- package/src/utils/lm/requirements.mjs +54 -63
- package/src/utils/lm/steps.mjs +31 -31
- package/src/utils/lm/ui.mjs +13 -20
- package/src/utils/open-browser.mjs +31 -32
- package/src/utils/parse-raw-flags.mjs +39 -35
- package/src/utils/proxy-server.mjs +84 -71
- package/src/utils/proxy.mjs +696 -750
- package/src/utils/read-repo-url.mjs +48 -47
- package/src/utils/redirects.mjs +49 -49
- package/src/utils/request-id.mjs +2 -4
- package/src/utils/rules-proxy.mjs +96 -100
- package/src/utils/run-build.mjs +109 -132
- package/src/utils/shell.mjs +99 -106
- package/src/utils/sign-redirect.mjs +14 -14
- package/src/utils/sites/utils.mjs +48 -55
- package/src/utils/state-config.mjs +101 -101
- package/src/utils/static-server.mjs +28 -34
- package/src/utils/telemetry/index.mjs +2 -2
- package/src/utils/telemetry/report-error.mjs +45 -49
- package/src/utils/telemetry/request.mjs +36 -43
- package/src/utils/telemetry/telemetry.mjs +90 -105
- package/src/utils/telemetry/utils.mjs +5 -6
- package/src/utils/telemetry/validation.mjs +55 -53
- package/src/utils/types.d.ts +46 -0
- package/src/utils/validation.mjs +10 -13
package/src/utils/init/utils.mjs
CHANGED
|
@@ -1,58 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { detectBuildSettings } from '../build-info.mjs'
|
|
11
|
-
import { chalk, error as failAndExit, log, warn } from '../command-helpers.mjs'
|
|
12
|
-
|
|
13
|
-
import { getRecommendPlugins, getUIPlugins } from './plugins.mjs'
|
|
14
|
-
|
|
1
|
+
import { writeFile } from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import cleanDeep from 'clean-deep';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import { fileExistsAsync } from '../../lib/fs.mjs';
|
|
6
|
+
import { normalizeBackslash } from '../../lib/path.mjs';
|
|
7
|
+
import { detectBuildSettings } from '../build-info.mjs';
|
|
8
|
+
import { chalk, error as failAndExit, log, warn } from '../command-helpers.mjs';
|
|
9
|
+
import { getRecommendPlugins, getUIPlugins } from './plugins.mjs';
|
|
15
10
|
// these plugins represent runtimes that are
|
|
16
11
|
// expected to be "automatically" installed. Even though
|
|
17
12
|
// they can be installed on package/toml, we always
|
|
18
13
|
// want them installed in the site settings. When installed
|
|
19
14
|
// there our build will automatically install the latest without
|
|
20
15
|
// user management of the versioning.
|
|
21
|
-
const pluginsToAlwaysInstall = new Set(['@netlify/plugin-nextjs'])
|
|
22
|
-
|
|
16
|
+
const pluginsToAlwaysInstall = new Set(['@netlify/plugin-nextjs']);
|
|
23
17
|
/**
|
|
24
18
|
* Retrieve a list of plugins to auto install
|
|
25
19
|
* @param {string[]=} pluginsInstalled
|
|
26
20
|
* @param {string[]=} pluginsRecommended
|
|
27
21
|
* @returns
|
|
28
22
|
*/
|
|
29
|
-
export const getPluginsToAutoInstall = (pluginsInstalled = [], pluginsRecommended = []) =>
|
|
30
|
-
|
|
31
|
-
(acc, plugin) =>
|
|
32
|
-
pluginsInstalled.includes(plugin) && !pluginsToAlwaysInstall.has(plugin) ? acc : [...acc, plugin],
|
|
33
|
-
|
|
34
|
-
/** @type {string[]} */ ([]),
|
|
35
|
-
)
|
|
36
|
-
|
|
23
|
+
export const getPluginsToAutoInstall = (pluginsInstalled = [], pluginsRecommended = []) => pluginsRecommended.reduce((acc, plugin) => pluginsInstalled.includes(plugin) && !pluginsToAlwaysInstall.has(plugin) ? acc : [...acc, plugin],
|
|
24
|
+
/** @type {string[]} */ ([]));
|
|
37
25
|
/**
|
|
38
26
|
*
|
|
39
27
|
* @param {Partial<import('@netlify/build-info').Settings>} settings
|
|
40
28
|
* @param {*} config
|
|
41
29
|
* @param {import('../../commands/base-command.mjs').default} command
|
|
42
30
|
*/
|
|
31
|
+
// @ts-expect-error TS(7006) FIXME: Parameter 'settings' implicitly has an 'any' type.
|
|
43
32
|
const normalizeSettings = (settings, config, command) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
33
|
+
const plugins = getPluginsToAutoInstall(settings.plugins_from_config_file, settings.plugins_recommended);
|
|
34
|
+
const recommendedPlugins = getRecommendPlugins(plugins, config);
|
|
35
|
+
return {
|
|
36
|
+
defaultBaseDir: settings.baseDirectory ?? command.project.relativeBaseDirectory ?? '',
|
|
37
|
+
defaultBuildCmd: config.build.command || settings.buildCommand,
|
|
38
|
+
defaultBuildDir: settings.dist,
|
|
39
|
+
defaultFunctionsDir: config.build.functions || 'netlify/functions',
|
|
40
|
+
recommendedPlugins,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
56
43
|
/**
|
|
57
44
|
*
|
|
58
45
|
* @param {object} param0
|
|
@@ -61,71 +48,61 @@ const normalizeSettings = (settings, config, command) => {
|
|
|
61
48
|
* @param {string=} param0.defaultBuildDir
|
|
62
49
|
* @returns
|
|
63
50
|
*/
|
|
51
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'defaultBaseDir' implicitly has an... Remove this comment to see the full error message
|
|
64
52
|
const getPromptInputs = ({ defaultBaseDir, defaultBuildCmd, defaultBuildDir }) => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
53
|
+
const inputs = [
|
|
54
|
+
defaultBaseDir !== undefined &&
|
|
55
|
+
defaultBaseDir !== '' && {
|
|
56
|
+
type: 'input',
|
|
57
|
+
name: 'baseDir',
|
|
58
|
+
message: 'Base directory `(blank for current dir):',
|
|
59
|
+
default: defaultBaseDir,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: 'input',
|
|
63
|
+
name: 'buildCmd',
|
|
64
|
+
message: 'Your build command (hugo build/yarn run build/etc):',
|
|
65
|
+
// @ts-expect-error TS(7006) FIXME: Parameter 'val' implicitly has an 'any' type.
|
|
66
|
+
filter: (val) => (val === '' ? '# no build command' : val),
|
|
67
|
+
default: defaultBuildCmd,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
type: 'input',
|
|
71
|
+
name: 'buildDir',
|
|
72
|
+
message: 'Directory to deploy (blank for current dir):',
|
|
73
|
+
default: defaultBuildDir,
|
|
74
|
+
},
|
|
75
|
+
].filter(Boolean);
|
|
76
|
+
return inputs.filter(Boolean);
|
|
77
|
+
};
|
|
91
78
|
/**
|
|
92
79
|
* @param {object} param0
|
|
93
80
|
* @param {*} param0.config
|
|
94
81
|
* @param {import('../../commands/base-command.mjs').default} param0.command
|
|
95
82
|
*/
|
|
83
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'command' implicitly has an 'any' ... Remove this comment to see the full error message
|
|
96
84
|
export const getBuildSettings = async ({ command, config }) => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const pluginsToInstall = recommendedPlugins.map((plugin) => ({ package: plugin }))
|
|
119
|
-
const normalizedBaseDir = baseDir ? normalizeBackslash(baseDir) : undefined
|
|
120
|
-
|
|
121
|
-
return { baseDir: normalizedBaseDir, buildCmd, buildDir, functionsDir: defaultFunctionsDir, pluginsToInstall }
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const getNetlifyToml = ({
|
|
125
|
-
command = '# no build command',
|
|
126
|
-
functions = 'functions',
|
|
127
|
-
publish = '.',
|
|
128
|
-
}) => `# example netlify.toml
|
|
85
|
+
const settings = await detectBuildSettings(command);
|
|
86
|
+
// TODO: add prompt for asking to choose the build command
|
|
87
|
+
/** @type {Partial<import('@netlify/build-info').Settings>} */
|
|
88
|
+
// eslint-disable-next-line unicorn/explicit-length-check
|
|
89
|
+
const setting = settings.length > 0 ? settings[0] : {};
|
|
90
|
+
const { defaultBaseDir, defaultBuildCmd, defaultBuildDir, defaultFunctionsDir, recommendedPlugins } = await normalizeSettings(setting, config, command);
|
|
91
|
+
if (recommendedPlugins.length !== 0 && setting.framework?.name) {
|
|
92
|
+
log(`Configuring ${formatTitle(setting.framework?.name)} runtime...`);
|
|
93
|
+
log();
|
|
94
|
+
}
|
|
95
|
+
const { baseDir, buildCmd, buildDir } = await inquirer.prompt(getPromptInputs({
|
|
96
|
+
defaultBaseDir,
|
|
97
|
+
defaultBuildCmd,
|
|
98
|
+
defaultBuildDir,
|
|
99
|
+
}));
|
|
100
|
+
// @ts-expect-error TS(7006) FIXME: Parameter 'plugin' implicitly has an 'any' type.
|
|
101
|
+
const pluginsToInstall = recommendedPlugins.map((plugin) => ({ package: plugin }));
|
|
102
|
+
const normalizedBaseDir = baseDir ? normalizeBackslash(baseDir) : undefined;
|
|
103
|
+
return { baseDir: normalizedBaseDir, buildCmd, buildDir, functionsDir: defaultFunctionsDir, pluginsToInstall };
|
|
104
|
+
};
|
|
105
|
+
const getNetlifyToml = ({ command = '# no build command', functions = 'functions', publish = '.', }) => `# example netlify.toml
|
|
129
106
|
[build]
|
|
130
107
|
command = "${command}"
|
|
131
108
|
functions = "${functions}"
|
|
@@ -145,89 +122,92 @@ const getNetlifyToml = ({
|
|
|
145
122
|
# port = 3000 # Port that the dev server will be listening on
|
|
146
123
|
# publish = "dist" # Folder with the static content for _redirect file
|
|
147
124
|
|
|
148
|
-
## more info on configuring this file: https://
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (configPath === undefined && Object.keys(cleanDeep(config)).length !== 0) {
|
|
170
|
-
return
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const { makeNetlifyTOML } = await inquirer.prompt([
|
|
174
|
-
{
|
|
175
|
-
type: 'confirm',
|
|
176
|
-
name: 'makeNetlifyTOML',
|
|
177
|
-
message: 'No netlify.toml detected. Would you like to create one with these build settings?',
|
|
178
|
-
default: true,
|
|
179
|
-
},
|
|
180
|
-
])
|
|
181
|
-
if (makeNetlifyTOML) {
|
|
182
|
-
try {
|
|
183
|
-
await writeFile(
|
|
184
|
-
tomlPath,
|
|
185
|
-
getNetlifyToml({ command: buildCmd, publish: buildDir, functions: functionsDir }),
|
|
186
|
-
'utf-8',
|
|
187
|
-
)
|
|
188
|
-
} catch (error) {
|
|
189
|
-
warn(`Failed saving Netlify toml file: ${error.message}`)
|
|
125
|
+
## more info on configuring this file: https://ntl.fyi/file-based-build-config
|
|
126
|
+
`;
|
|
127
|
+
export const saveNetlifyToml = async ({
|
|
128
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'baseDir' implicitly has an 'any' ... Remove this comment to see the full error message
|
|
129
|
+
baseDir,
|
|
130
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'buildCmd' implicitly has an 'any'... Remove this comment to see the full error message
|
|
131
|
+
buildCmd,
|
|
132
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'buildDir' implicitly has an 'any'... Remove this comment to see the full error message
|
|
133
|
+
buildDir,
|
|
134
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'config' implicitly has an 'any' t... Remove this comment to see the full error message
|
|
135
|
+
config,
|
|
136
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'configPath' implicitly has an 'an... Remove this comment to see the full error message
|
|
137
|
+
configPath,
|
|
138
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'functionsDir' implicitly has an '... Remove this comment to see the full error message
|
|
139
|
+
functionsDir,
|
|
140
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'repositoryRoot' implicitly has an... Remove this comment to see the full error message
|
|
141
|
+
repositoryRoot, }) => {
|
|
142
|
+
const tomlPathParts = [repositoryRoot, baseDir, 'netlify.toml'].filter(Boolean);
|
|
143
|
+
const tomlPath = path.join(...tomlPathParts);
|
|
144
|
+
if (await fileExistsAsync(tomlPath)) {
|
|
145
|
+
return;
|
|
190
146
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
147
|
+
// We don't want to create a `netlify.toml` file that overrides existing configuration
|
|
148
|
+
// In a monorepo the configuration can come from a repo level netlify.toml
|
|
149
|
+
// so we make sure it doesn't by checking `configPath === undefined`
|
|
150
|
+
// @ts-expect-error TS(2349)
|
|
151
|
+
if (configPath === undefined && Object.keys(cleanDeep(config)).length !== 0) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const { makeNetlifyTOML } = await inquirer.prompt([
|
|
155
|
+
{
|
|
156
|
+
type: 'confirm',
|
|
157
|
+
name: 'makeNetlifyTOML',
|
|
158
|
+
message: 'No netlify.toml detected. Would you like to create one with these build settings?',
|
|
159
|
+
default: true,
|
|
160
|
+
},
|
|
161
|
+
]);
|
|
162
|
+
if (makeNetlifyTOML) {
|
|
163
|
+
try {
|
|
164
|
+
await writeFile(tomlPath, getNetlifyToml({ command: buildCmd, publish: buildDir, functions: functionsDir }), 'utf-8');
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
|
|
168
|
+
warn(`Failed saving Netlify toml file: ${error.message}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'error' implicitly has an 'any' ty... Remove this comment to see the full error message
|
|
194
173
|
export const formatErrorMessage = ({ error, message }) => {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
174
|
+
const errorMessage = error.json ? `${error.message} - ${JSON.stringify(error.json)}` : error.message;
|
|
175
|
+
return `${message} with error: ${chalk.red(errorMessage)}`;
|
|
176
|
+
};
|
|
199
177
|
/**
|
|
200
178
|
* @param {string} title
|
|
201
179
|
*/
|
|
202
|
-
|
|
203
|
-
|
|
180
|
+
// @ts-expect-error TS(7006) FIXME: Parameter 'title' implicitly has an 'any' type.
|
|
181
|
+
const formatTitle = (title) => chalk.cyan(title);
|
|
182
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'api' implicitly has an 'any' type... Remove this comment to see the full error message
|
|
204
183
|
export const createDeployKey = async ({ api }) => {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
184
|
+
try {
|
|
185
|
+
const deployKey = await api.createDeployKey();
|
|
186
|
+
return deployKey;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
const message = formatErrorMessage({ message: 'Failed creating deploy key', error });
|
|
190
|
+
failAndExit(message);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'api' implicitly has an 'any' type... Remove this comment to see the full error message
|
|
214
194
|
export const updateSite = async ({ api, options, siteId }) => {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
|
|
195
|
+
try {
|
|
196
|
+
const updatedSite = await api.updateSite({ siteId, body: options });
|
|
197
|
+
return updatedSite;
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
const message = formatErrorMessage({ message: 'Failed updating site with repo information', error });
|
|
201
|
+
failAndExit(message);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'api' implicitly has an 'any' type... Remove this comment to see the full error message
|
|
224
205
|
export const setupSite = async ({ api, configPlugins, pluginsToInstall, repo, siteId }) => {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
206
|
+
const updatedSite = await updateSite({
|
|
207
|
+
siteId,
|
|
208
|
+
api,
|
|
209
|
+
// merge existing plugins with new ones
|
|
210
|
+
options: { repo, plugins: [...getUIPlugins(configPlugins), ...pluginsToInstall] },
|
|
211
|
+
});
|
|
212
|
+
return updatedSite;
|
|
213
|
+
};
|
|
@@ -1,149 +1,126 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const PACKAGE_NAME = 'live-tunnel-client'
|
|
15
|
-
const EXEC_NAME = PACKAGE_NAME
|
|
16
|
-
const SLUG_LOCAL_STATE_KEY = 'liveTunnelSlug'
|
|
17
|
-
|
|
1
|
+
import process from 'process';
|
|
2
|
+
// @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'node... Remove this comment to see the full error message
|
|
3
|
+
import fetch from 'node-fetch';
|
|
4
|
+
import pWaitFor from 'p-wait-for';
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
import { fetchLatestVersion, shouldFetchLatestVersion } from '../lib/exec-fetcher.mjs';
|
|
7
|
+
import { getPathInHome } from '../lib/settings.mjs';
|
|
8
|
+
import { NETLIFYDEVERR, NETLIFYDEVLOG, chalk, log } from './command-helpers.mjs';
|
|
9
|
+
// @ts-expect-error TS(7034) FIXME: Variable 'execa' implicitly has type 'any' in some... Remove this comment to see the full error message
|
|
10
|
+
import execa from './execa.mjs';
|
|
11
|
+
const PACKAGE_NAME = 'live-tunnel-client';
|
|
12
|
+
const EXEC_NAME = PACKAGE_NAME;
|
|
13
|
+
const SLUG_LOCAL_STATE_KEY = 'liveTunnelSlug';
|
|
18
14
|
// 1 second
|
|
19
|
-
const TUNNEL_POLL_INTERVAL = 1e3
|
|
15
|
+
const TUNNEL_POLL_INTERVAL = 1e3;
|
|
20
16
|
// 5 minutes
|
|
21
|
-
const TUNNEL_POLL_TIMEOUT = 3e5
|
|
22
|
-
|
|
17
|
+
const TUNNEL_POLL_TIMEOUT = 3e5;
|
|
18
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'netlifyApiToken' implicitly has a... Remove this comment to see the full error message
|
|
23
19
|
const createTunnel = async function ({ netlifyApiToken, siteId, slug }) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const data = await response.json()
|
|
46
|
-
|
|
47
|
-
if (response.status !== 201) {
|
|
48
|
-
throw new Error(data.message)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return data
|
|
52
|
-
}
|
|
53
|
-
|
|
20
|
+
await installTunnelClient();
|
|
21
|
+
if (!siteId) {
|
|
22
|
+
console.error(`${NETLIFYDEVERR} Error: no siteId defined, did you forget to run ${chalk.yellow('netlify init')} or ${chalk.yellow('netlify link')}?`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
const url = `https://api.netlify.com/api/v1/live_sessions?site_id=${siteId}&slug=${slug}`;
|
|
26
|
+
const response = await fetch(url, {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: {
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
|
+
Authorization: `Bearer ${netlifyApiToken}`,
|
|
31
|
+
},
|
|
32
|
+
body: JSON.stringify({}),
|
|
33
|
+
});
|
|
34
|
+
const data = await response.json();
|
|
35
|
+
if (response.status !== 201) {
|
|
36
|
+
throw new Error(data.message);
|
|
37
|
+
}
|
|
38
|
+
return data;
|
|
39
|
+
};
|
|
40
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'localPort' implicitly has an 'any... Remove this comment to see the full error message
|
|
54
41
|
const connectTunnel = function ({ localPort, netlifyApiToken, session }) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
42
|
+
const execPath = getPathInHome(['tunnel', 'bin', EXEC_NAME]);
|
|
43
|
+
const args = ['connect', '-s', session.id, '-t', netlifyApiToken, '-l', localPort];
|
|
44
|
+
if (process.env.DEBUG) {
|
|
45
|
+
args.push('-v');
|
|
46
|
+
log(execPath, args);
|
|
47
|
+
}
|
|
48
|
+
// @ts-expect-error TS(7005) FIXME: Variable 'execa' implicitly has an 'any' type.
|
|
49
|
+
const ps = execa(execPath, args, { stdio: 'inherit' });
|
|
50
|
+
// @ts-expect-error TS(7006) FIXME: Parameter 'code' implicitly has an 'any' type.
|
|
51
|
+
ps.on('close', (code) => process.exit(code));
|
|
52
|
+
ps.on('SIGINT', process.exit);
|
|
53
|
+
ps.on('SIGTERM', process.exit);
|
|
54
|
+
};
|
|
68
55
|
const installTunnelClient = async function () {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
log(`${NETLIFYDEVLOG} Installing Live Tunnel Client`)
|
|
82
|
-
|
|
83
|
-
await fetchLatestVersion({
|
|
84
|
-
packageName: PACKAGE_NAME,
|
|
85
|
-
execName: EXEC_NAME,
|
|
86
|
-
destination: binPath,
|
|
87
|
-
extension: process.platform === 'win32' ? 'zip' : 'tar.gz',
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export const startLiveTunnel = async ({ localPort, netlifyApiToken, siteId, slug }) => {
|
|
92
|
-
const session = await createTunnel({
|
|
93
|
-
siteId,
|
|
94
|
-
netlifyApiToken,
|
|
95
|
-
slug,
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
const isLiveTunnelReady = async function () {
|
|
99
|
-
const url = `https://api.netlify.com/api/v1/live_sessions/${session.id}`
|
|
100
|
-
const response = await fetch(url, {
|
|
101
|
-
method: 'GET',
|
|
102
|
-
headers: {
|
|
103
|
-
'Content-Type': 'application/json',
|
|
104
|
-
Authorization: `Bearer ${netlifyApiToken}`,
|
|
105
|
-
},
|
|
106
|
-
})
|
|
107
|
-
const data = await response.json()
|
|
108
|
-
|
|
109
|
-
if (response.status !== 200) {
|
|
110
|
-
throw new Error(data.message)
|
|
56
|
+
const binPath = getPathInHome(['tunnel', 'bin']);
|
|
57
|
+
// @ts-expect-error TS(2345) FIXME: Argument of type '{ binPath: string; packageName: ... Remove this comment to see the full error message
|
|
58
|
+
const shouldFetch = await shouldFetchLatestVersion({
|
|
59
|
+
binPath,
|
|
60
|
+
packageName: PACKAGE_NAME,
|
|
61
|
+
execArgs: ['version'],
|
|
62
|
+
pattern: `${PACKAGE_NAME}\\/v?([^\\s]+)`,
|
|
63
|
+
execName: EXEC_NAME,
|
|
64
|
+
});
|
|
65
|
+
if (!shouldFetch) {
|
|
66
|
+
return;
|
|
111
67
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
68
|
+
log(`${NETLIFYDEVLOG} Installing Live Tunnel Client`);
|
|
69
|
+
// @ts-expect-error TS(2345) FIXME: Argument of type '{ packageName: string; execName:... Remove this comment to see the full error message
|
|
70
|
+
await fetchLatestVersion({
|
|
71
|
+
packageName: PACKAGE_NAME,
|
|
72
|
+
execName: EXEC_NAME,
|
|
73
|
+
destination: binPath,
|
|
74
|
+
extension: process.platform === 'win32' ? 'zip' : 'tar.gz',
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
// @ts-expect-error TS(7031) FIXME: Binding element 'localPort' implicitly has an 'any... Remove this comment to see the full error message
|
|
78
|
+
export const startLiveTunnel = async ({ localPort, netlifyApiToken, siteId, slug }) => {
|
|
79
|
+
const session = await createTunnel({
|
|
80
|
+
siteId,
|
|
81
|
+
netlifyApiToken,
|
|
82
|
+
slug,
|
|
83
|
+
});
|
|
84
|
+
const isLiveTunnelReady = async function () {
|
|
85
|
+
const url = `https://api.netlify.com/api/v1/live_sessions/${session.id}`;
|
|
86
|
+
const response = await fetch(url, {
|
|
87
|
+
method: 'GET',
|
|
88
|
+
headers: {
|
|
89
|
+
'Content-Type': 'application/json',
|
|
90
|
+
Authorization: `Bearer ${netlifyApiToken}`,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
const data = await response.json();
|
|
94
|
+
if (response.status !== 200) {
|
|
95
|
+
throw new Error(data.message);
|
|
96
|
+
}
|
|
97
|
+
return data.state === 'online';
|
|
98
|
+
};
|
|
99
|
+
connectTunnel({ session, netlifyApiToken, localPort });
|
|
100
|
+
// Waiting for the live session to have a state of `online`.
|
|
101
|
+
await pWaitFor(isLiveTunnelReady, {
|
|
102
|
+
interval: TUNNEL_POLL_INTERVAL,
|
|
103
|
+
timeout: TUNNEL_POLL_TIMEOUT,
|
|
104
|
+
});
|
|
105
|
+
return session.session_url;
|
|
106
|
+
};
|
|
107
|
+
// @ts-expect-error TS(7006) FIXME: Parameter 'state' implicitly has an 'any' type.
|
|
127
108
|
export const getLiveTunnelSlug = (state, override) => {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
109
|
+
if (override !== undefined) {
|
|
110
|
+
return override;
|
|
111
|
+
}
|
|
112
|
+
const newSlug = generateRandomSlug();
|
|
113
|
+
try {
|
|
114
|
+
const existingSlug = state.get(SLUG_LOCAL_STATE_KEY);
|
|
115
|
+
if (existingSlug !== undefined) {
|
|
116
|
+
return existingSlug;
|
|
117
|
+
}
|
|
118
|
+
state.set(SLUG_LOCAL_STATE_KEY, newSlug);
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
|
|
122
|
+
log(`${NETLIFYDEVERR} Could not read or write local state file: ${error.message}`);
|
|
139
123
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
log(`${NETLIFYDEVERR} Could not read or write local state file: ${error.message}`)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return newSlug
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const generateRandomSlug = () => uuidv4().slice(0, 8)
|
|
124
|
+
return newSlug;
|
|
125
|
+
};
|
|
126
|
+
const generateRandomSlug = () => uuidv4().slice(0, 8);
|