netlify 27.10.1 → 27.11.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/dist/commands/agents/agents-create.js +19 -33
- package/dist/commands/base-command.d.ts +1 -1
- package/dist/commands/base-command.js +8 -11
- package/dist/commands/clone/clone.js +5 -10
- package/dist/commands/completion/completion.js +5 -9
- package/dist/commands/create/create-action.js +16 -28
- package/dist/commands/database/db-init.js +17 -31
- package/dist/commands/database/db-migration-new.js +13 -23
- package/dist/commands/database/db-migration-pull.js +5 -9
- package/dist/commands/database/db-reset.js +5 -9
- package/dist/commands/deploy/deploy.js +23 -36
- package/dist/commands/env/env-list.js +5 -9
- package/dist/commands/functions/functions-create.js +35 -71
- package/dist/commands/functions/functions-invoke.js +5 -10
- package/dist/commands/init/init.js +12 -25
- package/dist/commands/link/link.js +26 -52
- package/dist/commands/logs/build.js +2 -4
- package/dist/commands/main.js +10 -17
- package/dist/commands/recipes/recipes.js +6 -16
- package/dist/commands/sites/sites-create.js +12 -22
- package/dist/commands/sites/sites-delete.js +3 -7
- package/dist/commands/switch/switch.js +5 -9
- package/dist/lib/edge-functions/editor-helper.js +3 -5
- package/dist/recipes/ai-context/index.js +9 -17
- package/dist/recipes/blobs-migrate/index.js +3 -7
- package/dist/recipes/vscode/index.js +6 -10
- package/dist/utils/build-info.js +3 -6
- package/dist/utils/deploy/deploy-site.js +21 -12
- package/dist/utils/deploy/upload-files.js +6 -2
- package/dist/utils/deploy/util.d.ts +1 -0
- package/dist/utils/deploy/util.js +1 -0
- package/dist/utils/exit-codes.d.ts +2 -0
- package/dist/utils/exit-codes.js +2 -0
- package/dist/utils/gh-auth.js +10 -22
- package/dist/utils/github-api.d.ts +22 -0
- package/dist/utils/github-api.js +47 -0
- package/dist/utils/init/config-github.js +29 -45
- package/dist/utils/init/config-manual.js +8 -28
- package/dist/utils/init/utils.js +14 -38
- package/dist/utils/prompts/confirm-prompt.js +4 -15
- package/dist/utils/proxy.js +7 -48
- package/dist/utils/redirects.js +3 -2
- package/dist/utils/rules-proxy.js +31 -29
- package/dist/utils/types.d.ts +2 -2
- package/package.json +10 -14
|
@@ -5,9 +5,9 @@ import { createRequire } from 'module';
|
|
|
5
5
|
import path, { dirname, join, relative } from 'path';
|
|
6
6
|
import process from 'process';
|
|
7
7
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
8
|
+
import { confirm, input, search, select, Separator } from '@inquirer/prompts';
|
|
8
9
|
import { findUp } from 'find-up';
|
|
9
10
|
import fuzzy from 'fuzzy';
|
|
10
|
-
import inquirer from 'inquirer';
|
|
11
11
|
import fetch from 'node-fetch';
|
|
12
12
|
import { createSpinner } from 'nanospinner';
|
|
13
13
|
import { fileExistsAsync } from '../../lib/fs.js';
|
|
@@ -57,18 +57,12 @@ const getNameFromArgs = async function (argumentName, options, defaultName) {
|
|
|
57
57
|
validateFunctionName(argumentName);
|
|
58
58
|
return argumentName;
|
|
59
59
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
validate: (val) => isValidFunctionName(val),
|
|
67
|
-
// make sure it is not undefined and is a valid filename.
|
|
68
|
-
// this has some nuance i have ignored, eg crossenv and i18n concerns
|
|
69
|
-
},
|
|
70
|
-
]);
|
|
71
|
-
return name;
|
|
60
|
+
return await input({
|
|
61
|
+
message: 'Name your function:',
|
|
62
|
+
default: defaultName,
|
|
63
|
+
// this has some nuance i have ignored, eg crossenv and i18n concerns
|
|
64
|
+
validate: (val) => isValidFunctionName(val),
|
|
65
|
+
});
|
|
72
66
|
};
|
|
73
67
|
// @ts-expect-error TS(7006) FIXME: Parameter 'registry' implicitly has an 'any' type.
|
|
74
68
|
const filterRegistry = function (registry, input) {
|
|
@@ -140,7 +134,7 @@ const formatRegistryArrayForInquirer = async function (lang, funcType) {
|
|
|
140
134
|
// @ts-expect-error TS(7031) FIXME: Binding element 'languageFromFlag' implicitly has ... Remove this comment to see the full error message
|
|
141
135
|
const pickTemplate = async function ({ language: languageFromFlag, template: templateFromFlag }, funcType) {
|
|
142
136
|
const specialCommands = [
|
|
143
|
-
new
|
|
137
|
+
new Separator(),
|
|
144
138
|
{
|
|
145
139
|
name: `Clone template from GitHub URL`,
|
|
146
140
|
value: 'url',
|
|
@@ -151,20 +145,17 @@ const pickTemplate = async function ({ language: languageFromFlag, template: tem
|
|
|
151
145
|
value: 'report',
|
|
152
146
|
short: 'gh-report',
|
|
153
147
|
},
|
|
154
|
-
new
|
|
148
|
+
new Separator(),
|
|
155
149
|
];
|
|
156
150
|
let language = languageFromFlag;
|
|
157
151
|
if (language === undefined) {
|
|
158
152
|
const langs = funcType === 'edge'
|
|
159
153
|
? languages.filter((lang) => lang.value === 'javascript' || lang.value === 'typescript')
|
|
160
154
|
: languages.filter(Boolean);
|
|
161
|
-
|
|
155
|
+
language = await select({
|
|
162
156
|
choices: langs,
|
|
163
157
|
message: 'Select the language of your function',
|
|
164
|
-
name: 'language',
|
|
165
|
-
type: 'list',
|
|
166
158
|
});
|
|
167
|
-
language = languageFromPrompt;
|
|
168
159
|
}
|
|
169
160
|
let templatesForLanguage;
|
|
170
161
|
try {
|
|
@@ -180,12 +171,9 @@ const pickTemplate = async function ({ language: languageFromFlag, template: tem
|
|
|
180
171
|
}
|
|
181
172
|
return match.value;
|
|
182
173
|
}
|
|
183
|
-
const
|
|
184
|
-
name: 'chosenTemplate',
|
|
174
|
+
const chosenTemplate = await search({
|
|
185
175
|
message: 'Pick a template',
|
|
186
|
-
|
|
187
|
-
type: 'autocomplete',
|
|
188
|
-
source(_answersSoFar, input) {
|
|
176
|
+
source(input) {
|
|
189
177
|
// if Edge Functions template, don't show url option
|
|
190
178
|
// @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Separator... Remove this comment to see the full error message
|
|
191
179
|
const edgeCommands = specialCommands.filter((val) => val.value !== 'url');
|
|
@@ -207,15 +195,10 @@ const selectTypeOfFunc = async () => {
|
|
|
207
195
|
{ name: 'Edge function (Deno)', value: 'edge' },
|
|
208
196
|
{ name: 'Serverless function (Node)', value: 'serverless' },
|
|
209
197
|
];
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
type: 'list',
|
|
215
|
-
choices: functionTypes,
|
|
216
|
-
},
|
|
217
|
-
]);
|
|
218
|
-
return functionType;
|
|
198
|
+
return await select({
|
|
199
|
+
message: "Select the type of function you'd like to create",
|
|
200
|
+
choices: functionTypes,
|
|
201
|
+
});
|
|
219
202
|
};
|
|
220
203
|
/**
|
|
221
204
|
* @param {import('../base-command.js').default} command
|
|
@@ -248,14 +231,10 @@ const promptFunctionsDirectory = async (command) => {
|
|
|
248
231
|
if (!site.id) {
|
|
249
232
|
return logAndThrowError(`${NETLIFYDEVERR} No project id found, please run inside a project directory or \`netlify link\``);
|
|
250
233
|
}
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
message: 'Enter the path, relative to your project, where your functions should live:',
|
|
256
|
-
default: 'netlify/functions',
|
|
257
|
-
},
|
|
258
|
-
]);
|
|
234
|
+
const functionsDir = await input({
|
|
235
|
+
message: 'Enter the path, relative to your project, where your functions should live:',
|
|
236
|
+
default: 'netlify/functions',
|
|
237
|
+
});
|
|
259
238
|
try {
|
|
260
239
|
log(`${NETLIFYDEVLOG} updating project settings with ${chalk.magenta.inverse(functionsDir)}`);
|
|
261
240
|
await api.updateSite({
|
|
@@ -405,16 +384,10 @@ const scaffoldFromTemplate = async function (command, options, argumentName, fun
|
|
|
405
384
|
// pull the rest of the metadata from the template
|
|
406
385
|
const chosenTemplate = await pickTemplate(options, funcType);
|
|
407
386
|
if (chosenTemplate === 'url') {
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
type: 'input',
|
|
413
|
-
validate: (/** @type {string} */ val) => Boolean(validateRepoURL(val)),
|
|
414
|
-
// make sure it is not undefined and is a valid filename.
|
|
415
|
-
// this has some nuance i have ignored, eg crossenv and i18n concerns
|
|
416
|
-
},
|
|
417
|
-
]);
|
|
387
|
+
const chosenUrl = await input({
|
|
388
|
+
message: 'URL to clone: ',
|
|
389
|
+
validate: (val) => Boolean(validateRepoURL(val)),
|
|
390
|
+
});
|
|
418
391
|
options.url = chosenUrl.trim();
|
|
419
392
|
try {
|
|
420
393
|
await downloadFromURL(command, options, argumentName, functionsDir);
|
|
@@ -522,14 +495,10 @@ const handleAddonDidInstall = async ({ addonCreated, addonDidInstall, command, f
|
|
|
522
495
|
if (!addonCreated || !addonDidInstall) {
|
|
523
496
|
return;
|
|
524
497
|
}
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
message: `This template has an optional setup script that runs after addon install. This can be helpful for first time users to try out templates. Run the script?`,
|
|
530
|
-
default: false,
|
|
531
|
-
},
|
|
532
|
-
]);
|
|
498
|
+
const confirmPostInstall = await confirm({
|
|
499
|
+
message: `This template has an optional setup script that runs after addon install. This can be helpful for first time users to try out templates. Run the script?`,
|
|
500
|
+
default: false,
|
|
501
|
+
});
|
|
533
502
|
if (!confirmPostInstall) {
|
|
534
503
|
return;
|
|
535
504
|
}
|
|
@@ -590,19 +559,14 @@ const registerEFInToml = async (funcName, options) => {
|
|
|
590
559
|
if (!fs.existsSync(configFilePath)) {
|
|
591
560
|
log(`${NETLIFYDEVLOG} \`${relConfigFilePath}\` file does not exist yet. Creating it...`);
|
|
592
561
|
}
|
|
593
|
-
let
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
validate: (val) => Boolean(val),
|
|
600
|
-
// Make sure route isn't undefined and is valid
|
|
601
|
-
// Todo: add more validation?
|
|
602
|
-
},
|
|
603
|
-
]);
|
|
562
|
+
let funcPath = await input({
|
|
563
|
+
message: `What route do you want your edge function to be invoked on?`,
|
|
564
|
+
default: '/test',
|
|
565
|
+
// Todo: add more validation?
|
|
566
|
+
validate: (val) => Boolean(val),
|
|
567
|
+
});
|
|
604
568
|
// Make sure path begins with a '/'
|
|
605
|
-
if (funcPath
|
|
569
|
+
if (!funcPath.startsWith('/')) {
|
|
606
570
|
funcPath = `/${funcPath}`;
|
|
607
571
|
}
|
|
608
572
|
const functionRegister = `\n\n[[edge_functions]]\nfunction = "${funcName}"\npath = "${funcPath}"`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import
|
|
4
|
+
import { select } from '@inquirer/prompts';
|
|
5
5
|
import fetch from 'node-fetch';
|
|
6
6
|
import { NETLIFYDEVWARN, chalk, logAndThrowError, exit } from '../../utils/command-helpers.js';
|
|
7
7
|
import { BACKGROUND, CLOCKWORK_USERAGENT, getFunctions } from '../../utils/functions/index.js';
|
|
@@ -94,15 +94,10 @@ const getNameFromArgs = async function (functions, options, argumentName) {
|
|
|
94
94
|
}
|
|
95
95
|
console.warn(`Function name ${chalk.yellow(functionToTrigger)} supplied but no matching function found in your functions folder, forcing you to pick a valid one...`);
|
|
96
96
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
name: 'trigger',
|
|
102
|
-
choices: functionNames,
|
|
103
|
-
},
|
|
104
|
-
]);
|
|
105
|
-
return trigger;
|
|
97
|
+
return await select({
|
|
98
|
+
message: 'Pick a function to trigger',
|
|
99
|
+
choices: functionNames,
|
|
100
|
+
});
|
|
106
101
|
};
|
|
107
102
|
/**
|
|
108
103
|
* get the function name out of the argument or options
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { confirm, select } from '@inquirer/prompts';
|
|
2
2
|
import { isEmpty } from '../../utils/object-utilities.js';
|
|
3
3
|
import { chalk, exit, log, netlifyCommand } from '../../utils/command-helpers.js';
|
|
4
4
|
import getRepoData from '../../utils/get-repo-data.js';
|
|
@@ -38,13 +38,9 @@ const createNewSiteAndExit = async ({ command, state, disableLinking, customizeE
|
|
|
38
38
|
log();
|
|
39
39
|
persistState({ state, siteInfo });
|
|
40
40
|
if (!disableLinking) {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
name: 'shouldConfigureBuild',
|
|
45
|
-
message: `Do you want to configure build settings? We'll suggest settings for your project automatically`,
|
|
46
|
-
},
|
|
47
|
-
]);
|
|
41
|
+
const shouldConfigureBuild = await confirm({
|
|
42
|
+
message: `Do you want to configure build settings? We'll suggest settings for your project automatically`,
|
|
43
|
+
});
|
|
48
44
|
if (shouldConfigureBuild) {
|
|
49
45
|
const { cachedConfig: { configPath }, config, repositoryRoot, } = command.netlify;
|
|
50
46
|
const { baseDir, buildCmd, buildDir, functionsDir } = await getBuildSettings({
|
|
@@ -112,14 +108,10 @@ git remote add origin https://github.com/YourUserName/RepoName.git
|
|
|
112
108
|
}
|
|
113
109
|
const NEW_SITE_NO_GIT = 'Yes, create and deploy project manually';
|
|
114
110
|
const NO_ABORT = 'No, I will connect this directory with GitHub first';
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
message: 'Do you want to create a Netlify project without a git repository?',
|
|
120
|
-
choices: [NEW_SITE_NO_GIT, NO_ABORT],
|
|
121
|
-
},
|
|
122
|
-
]);
|
|
111
|
+
const noGitRemoteChoice = await select({
|
|
112
|
+
message: 'Do you want to create a Netlify project without a git repository?',
|
|
113
|
+
choices: [NEW_SITE_NO_GIT, NO_ABORT],
|
|
114
|
+
});
|
|
123
115
|
if (noGitRemoteChoice === NEW_SITE_NO_GIT) {
|
|
124
116
|
// TODO(ndhoule): Shove a custom error message in here
|
|
125
117
|
return createNewSiteAndExit({ state, command, disableLinking, customizeExitMessage });
|
|
@@ -133,15 +125,10 @@ const createOrLinkSiteToRepo = async (command) => {
|
|
|
133
125
|
const NEW_SITE = '+ Create & configure a new project';
|
|
134
126
|
const EXISTING_SITE = '⇄ Connect this directory to an existing Netlify project';
|
|
135
127
|
const initializeOpts = [EXISTING_SITE, NEW_SITE];
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
name: 'initChoice',
|
|
141
|
-
message: 'What would you like to do?',
|
|
142
|
-
choices: initializeOpts,
|
|
143
|
-
},
|
|
144
|
-
]);
|
|
128
|
+
const initChoice = await select({
|
|
129
|
+
message: 'What would you like to do?',
|
|
130
|
+
choices: initializeOpts,
|
|
131
|
+
});
|
|
145
132
|
// create site or search for one
|
|
146
133
|
if (initChoice === NEW_SITE) {
|
|
147
134
|
await track('sites_initStarted', {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
|
-
import
|
|
2
|
+
import { input, select } from '@inquirer/prompts';
|
|
3
3
|
import { isEmpty } from '../../utils/object-utilities.js';
|
|
4
4
|
import { listSites } from '../../lib/api.js';
|
|
5
5
|
import { startSpinner } from '../../lib/spinner.js';
|
|
@@ -43,17 +43,13 @@ To search for projects:
|
|
|
43
43
|
return firstSite;
|
|
44
44
|
}
|
|
45
45
|
spinner.warn({ text: `Found ${matchingSites.length} projects connected to ${repoUrl}` });
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
name:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
value: matchingSite,
|
|
54
|
-
})),
|
|
55
|
-
},
|
|
56
|
-
]);
|
|
46
|
+
const selectedSite = await select({
|
|
47
|
+
message: 'Which project do you want to link?',
|
|
48
|
+
choices: matchingSites.map((matchingSite) => ({
|
|
49
|
+
name: `${matchingSite.name} - ${matchingSite.ssl_url}`,
|
|
50
|
+
value: matchingSite,
|
|
51
|
+
})),
|
|
52
|
+
});
|
|
57
53
|
if (!selectedSite) {
|
|
58
54
|
return logAndThrowError('No project selected');
|
|
59
55
|
}
|
|
@@ -77,14 +73,10 @@ const linkPrompt = async (command, options) => {
|
|
|
77
73
|
log();
|
|
78
74
|
log(`${chalk.cyanBright(`${netlifyCommand()} link`)} will connect this folder to a project on Netlify`);
|
|
79
75
|
log();
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
message: 'How do you want to link this folder to a project?',
|
|
85
|
-
choices: linkChoices,
|
|
86
|
-
},
|
|
87
|
-
]);
|
|
76
|
+
const linkType = await select({
|
|
77
|
+
message: 'How do you want to link this folder to a project?',
|
|
78
|
+
choices: linkChoices,
|
|
79
|
+
});
|
|
88
80
|
let kind;
|
|
89
81
|
switch (linkType) {
|
|
90
82
|
case GIT_REMOTE_PROMPT: {
|
|
@@ -96,13 +88,9 @@ const linkPrompt = async (command, options) => {
|
|
|
96
88
|
}
|
|
97
89
|
case SITE_NAME_PROMPT: {
|
|
98
90
|
kind = 'byName';
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
name: 'searchTerm',
|
|
103
|
-
message: 'Enter the project name (or just part of it):',
|
|
104
|
-
},
|
|
105
|
-
]);
|
|
91
|
+
const searchTerm = await input({
|
|
92
|
+
message: 'Enter the project name (or just part of it):',
|
|
93
|
+
});
|
|
106
94
|
log(`Looking for projects with names containing '${searchTerm}'...`);
|
|
107
95
|
log();
|
|
108
96
|
let matchingSites = [];
|
|
@@ -134,15 +122,10 @@ To create a new project:
|
|
|
134
122
|
}
|
|
135
123
|
if (matchingSites.length > 1) {
|
|
136
124
|
log(`Found ${matchingSites.length} matching projects!`);
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
message: 'Which project do you want to link?',
|
|
142
|
-
paginated: true,
|
|
143
|
-
choices: matchingSites.map((matchingSite) => ({ name: matchingSite.name, value: matchingSite })),
|
|
144
|
-
},
|
|
145
|
-
]);
|
|
125
|
+
const selectedSite = await select({
|
|
126
|
+
message: 'Which project do you want to link?',
|
|
127
|
+
choices: matchingSites.map((matchingSite) => ({ name: matchingSite.name, value: matchingSite })),
|
|
128
|
+
});
|
|
146
129
|
if (!selectedSite) {
|
|
147
130
|
return logAndThrowError('No project selected');
|
|
148
131
|
}
|
|
@@ -168,15 +151,10 @@ To create a new project:
|
|
|
168
151
|
if (!sites || sites.length === 0) {
|
|
169
152
|
return logAndThrowError(`You don't have any projects yet. Run ${chalk.cyanBright(`${netlifyCommand()} sites:create`)} to create a project.`);
|
|
170
153
|
}
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
message: 'Which project do you want to link?',
|
|
176
|
-
paginated: true,
|
|
177
|
-
choices: sites.map((matchingSite) => ({ name: matchingSite.name, value: matchingSite })),
|
|
178
|
-
},
|
|
179
|
-
]);
|
|
154
|
+
const selectedSite = await select({
|
|
155
|
+
message: 'Which project do you want to link?',
|
|
156
|
+
choices: sites.map((matchingSite) => ({ name: matchingSite.name, value: matchingSite })),
|
|
157
|
+
});
|
|
180
158
|
if (!selectedSite) {
|
|
181
159
|
return logAndThrowError('No project selected');
|
|
182
160
|
}
|
|
@@ -185,13 +163,9 @@ To create a new project:
|
|
|
185
163
|
}
|
|
186
164
|
case SITE_ID_PROMPT: {
|
|
187
165
|
kind = 'bySiteId';
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
name: 'siteId',
|
|
192
|
-
message: 'What is the project ID?',
|
|
193
|
-
},
|
|
194
|
-
]);
|
|
166
|
+
const siteId = await input({
|
|
167
|
+
message: 'What is the project ID?',
|
|
168
|
+
});
|
|
195
169
|
try {
|
|
196
170
|
site = await api.getSite({ siteId });
|
|
197
171
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { select } from '@inquirer/prompts';
|
|
2
2
|
import { log, chalk } from '../../utils/command-helpers.js';
|
|
3
3
|
import { getWebSocket } from '../../utils/websockets/index.js';
|
|
4
4
|
export function getName({ deploy, userId }) {
|
|
@@ -41,9 +41,7 @@ export const logsBuild = async (_options, command) => {
|
|
|
41
41
|
}
|
|
42
42
|
let [deploy] = deploys;
|
|
43
43
|
if (deploys.length > 1) {
|
|
44
|
-
const
|
|
45
|
-
name: 'result',
|
|
46
|
-
type: 'list',
|
|
44
|
+
const result = await select({
|
|
47
45
|
message: `Select a deploy\n\n${chalk.yellow('*')} indicates a deploy created by you`,
|
|
48
46
|
choices: deploys.map((dep) => ({
|
|
49
47
|
name: getName({ deploy: dep, userId }),
|
package/dist/commands/main.js
CHANGED
|
@@ -2,7 +2,7 @@ import process from 'process';
|
|
|
2
2
|
import { Option } from 'commander';
|
|
3
3
|
import envinfo from 'envinfo';
|
|
4
4
|
import { closest } from 'fastest-levenshtein';
|
|
5
|
-
import
|
|
5
|
+
import { confirm } from '@inquirer/prompts';
|
|
6
6
|
import { getGlobalConfigStore } from '@netlify/dev-utils';
|
|
7
7
|
import { BANG, chalk, logAndThrowError, exit, log, NETLIFY_CYAN, USER_AGENT, logError, } from '../utils/command-helpers.js';
|
|
8
8
|
import execa from '../utils/execa.js';
|
|
@@ -170,22 +170,15 @@ const mainCommand = async function (options, command) {
|
|
|
170
170
|
logError(`Run ${NETLIFY_CYAN(`${command.name()} help`)} for a list of available commands.`);
|
|
171
171
|
exit(EXIT_CODES.USAGE_ERROR);
|
|
172
172
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
prompt.ui.close();
|
|
183
|
-
resolve(false);
|
|
184
|
-
}, SUGGESTION_TIMEOUT);
|
|
185
|
-
prompt.then((value) => {
|
|
186
|
-
resolve(value.suggestion);
|
|
187
|
-
});
|
|
188
|
-
});
|
|
173
|
+
let applySuggestion = false;
|
|
174
|
+
try {
|
|
175
|
+
applySuggestion = await confirm({ message: `Did you mean ${chalk.blue(suggestion)}`, default: false }, { signal: AbortSignal.timeout(SUGGESTION_TIMEOUT) });
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
if (!(error instanceof Error && error.name === 'AbortPromptError')) {
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
189
182
|
// create new log line
|
|
190
183
|
log();
|
|
191
184
|
if (!applySuggestion) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { basename } from 'path';
|
|
2
2
|
import { closest } from 'fastest-levenshtein';
|
|
3
|
-
import
|
|
3
|
+
import { confirm } from '@inquirer/prompts';
|
|
4
4
|
import { NETLIFYDEVERR, chalk, log } from '../../utils/command-helpers.js';
|
|
5
5
|
import { getRecipe, listRecipes } from './common.js';
|
|
6
6
|
const SUGGESTION_TIMEOUT = 1e4;
|
|
@@ -29,21 +29,11 @@ export const recipesCommand = async (recipeName, options, command) => {
|
|
|
29
29
|
const recipes = await listRecipes();
|
|
30
30
|
const recipeNames = recipes.map(({ name }) => name);
|
|
31
31
|
const suggestion = closest(recipeName, recipeNames);
|
|
32
|
-
const applySuggestion = await
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
default: false,
|
|
38
|
-
});
|
|
39
|
-
setTimeout(() => {
|
|
40
|
-
// @ts-expect-error TS(2445) FIXME: Property 'close' is protected and only accessible ... Remove this comment to see the full error message
|
|
41
|
-
prompt.ui.close();
|
|
42
|
-
resolve(false);
|
|
43
|
-
}, SUGGESTION_TIMEOUT);
|
|
44
|
-
prompt.then((value) => {
|
|
45
|
-
resolve(value.suggestion);
|
|
46
|
-
});
|
|
32
|
+
const applySuggestion = await confirm({ message: `Did you mean ${chalk.blue(suggestion)}`, default: false }, { signal: AbortSignal.timeout(SUGGESTION_TIMEOUT) }).catch((error) => {
|
|
33
|
+
if (error instanceof Error && error.name === 'AbortPromptError') {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
throw error;
|
|
47
37
|
});
|
|
48
38
|
if (applySuggestion) {
|
|
49
39
|
return recipesCommand(suggestion, options, command);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { input, select } from '@inquirer/prompts';
|
|
2
2
|
import { pick } from '../../utils/object-utilities.js';
|
|
3
3
|
import prettyjson from 'prettyjson';
|
|
4
4
|
import { chalk, logAndThrowError, log, logJson, warn } from '../../utils/command-helpers.js';
|
|
@@ -11,15 +11,10 @@ import { MAX_SITE_NAME_LENGTH } from '../../utils/validation.js';
|
|
|
11
11
|
import { link } from '../link/link.js';
|
|
12
12
|
export const getSiteNameInput = async (name) => {
|
|
13
13
|
if (!name) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
message: 'Project name (leave blank for a random name; you can change it later):',
|
|
19
|
-
validate: (input) => /^[a-zA-Z\d-]+$/.test(input || undefined) || 'Only alphanumeric characters and hyphens are allowed',
|
|
20
|
-
},
|
|
21
|
-
]);
|
|
22
|
-
name = typeof nameInput === 'string' ? nameInput : '';
|
|
14
|
+
name = await input({
|
|
15
|
+
message: 'Project name (leave blank for a random name; you can change it later):',
|
|
16
|
+
validate: (value) => !value || /^[a-zA-Z\d-]+$/.test(value) || 'Only alphanumeric characters and hyphens are allowed',
|
|
17
|
+
});
|
|
23
18
|
}
|
|
24
19
|
return { name };
|
|
25
20
|
};
|
|
@@ -34,18 +29,13 @@ export const sitesCreate = async (options, command) => {
|
|
|
34
29
|
log(`Using team: ${team.name}`);
|
|
35
30
|
}
|
|
36
31
|
else {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
name: account.name,
|
|
45
|
-
})),
|
|
46
|
-
},
|
|
47
|
-
]);
|
|
48
|
-
accountSlug = accountSlugInput;
|
|
32
|
+
accountSlug = await select({
|
|
33
|
+
message: 'Team:',
|
|
34
|
+
choices: accounts.map((account) => ({
|
|
35
|
+
value: account.slug,
|
|
36
|
+
name: account.name,
|
|
37
|
+
})),
|
|
38
|
+
});
|
|
49
39
|
}
|
|
50
40
|
}
|
|
51
41
|
let site;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { confirm } from '@inquirer/prompts';
|
|
2
2
|
import { chalk, logAndThrowError, exit, log } from '../../utils/command-helpers.js';
|
|
3
3
|
export const sitesDelete = async (siteId, options, command) => {
|
|
4
4
|
command.setAnalyticsPayload({ force: options.force });
|
|
@@ -27,9 +27,7 @@ export const sitesDelete = async (siteId, options, command) => {
|
|
|
27
27
|
log();
|
|
28
28
|
log(chalk.bold('Be careful here. There is no undo!'));
|
|
29
29
|
log();
|
|
30
|
-
const
|
|
31
|
-
type: 'confirm',
|
|
32
|
-
name: 'wantsToDelete',
|
|
30
|
+
const wantsToDelete = await confirm({
|
|
33
31
|
message: `WARNING: Are you sure you want to delete the "${siteData.name}" project?`,
|
|
34
32
|
default: false,
|
|
35
33
|
});
|
|
@@ -47,9 +45,7 @@ export const sitesDelete = async (siteId, options, command) => {
|
|
|
47
45
|
log();
|
|
48
46
|
log(`Verify this project ID "${siteId}" supplied is correct and proceed.`);
|
|
49
47
|
log('To skip this prompt, pass a --force flag to the delete command');
|
|
50
|
-
const
|
|
51
|
-
type: 'confirm',
|
|
52
|
-
name: 'wantsToDelete',
|
|
48
|
+
const wantsToDelete = await confirm({
|
|
53
49
|
message: `Verify & Proceed with deletion of project "${siteId}"?`,
|
|
54
50
|
default: false,
|
|
55
51
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { select } from '@inquirer/prompts';
|
|
2
2
|
import { chalk, log } from '../../utils/command-helpers.js';
|
|
3
3
|
import { login } from '../login/login.js';
|
|
4
4
|
const LOGIN_NEW = 'I would like to login to a new account';
|
|
@@ -16,14 +16,10 @@ export const switchCommand = async (options, command) => {
|
|
|
16
16
|
log(`No account found matching ${chalk.bold(options.email)}, showing all available accounts.`);
|
|
17
17
|
log('');
|
|
18
18
|
}
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
message: 'Please select the account you want to use:',
|
|
24
|
-
choices: [...Object.entries(availableUsersChoices).map(([, val]) => val), LOGIN_NEW],
|
|
25
|
-
},
|
|
26
|
-
]);
|
|
19
|
+
const accountSwitchChoice = await select({
|
|
20
|
+
message: 'Please select the account you want to use:',
|
|
21
|
+
choices: [...Object.entries(availableUsersChoices).map(([, val]) => val), LOGIN_NEW],
|
|
22
|
+
});
|
|
27
23
|
if (accountSwitchChoice === LOGIN_NEW) {
|
|
28
24
|
await login({ new: true }, command);
|
|
29
25
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { env, stdin, stdout } from 'process';
|
|
2
|
-
import
|
|
2
|
+
import { confirm } from '@inquirer/prompts';
|
|
3
3
|
import { runRecipe } from '../../commands/recipes/recipes.js';
|
|
4
4
|
const STATE_PROMPT_PROPERTY = 'promptVSCodeSettings';
|
|
5
5
|
// @ts-expect-error TS(7031) FIXME: Binding element 'NETLIFYDEVLOG' implicitly has an ... Remove this comment to see the full error message
|
|
@@ -18,13 +18,11 @@ export const promptEditorHelper = async ({ NETLIFYDEVLOG, chalk, config, log, re
|
|
|
18
18
|
}
|
|
19
19
|
state.set(STATE_PROMPT_PROPERTY, true);
|
|
20
20
|
const message = 'Would you like to configure VS Code to use Edge Functions?';
|
|
21
|
-
const
|
|
22
|
-
type: 'confirm',
|
|
23
|
-
name: 'confirm',
|
|
21
|
+
const confirmed = await confirm({
|
|
24
22
|
message,
|
|
25
23
|
default: true,
|
|
26
24
|
});
|
|
27
|
-
if (!
|
|
25
|
+
if (!confirmed) {
|
|
28
26
|
log(`${NETLIFYDEVLOG} You can start this configuration manually by running ${chalk.magenta.bold('netlify recipes vscode')}.`);
|
|
29
27
|
return;
|
|
30
28
|
}
|