netlify-cli 15.9.1-rc.0 → 15.10.0-rc.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/bin/run.mjs +6 -5
- package/npm-shrinkwrap.json +235 -734
- package/package.json +5 -5
- package/src/commands/base-command.mjs +122 -79
- package/src/commands/build/build.mjs +9 -1
- package/src/commands/deploy/deploy.mjs +1 -0
- package/src/commands/dev/dev.mjs +2 -3
- package/src/commands/functions/functions-create.mjs +118 -86
- package/src/commands/functions/functions-invoke.mjs +2 -2
- package/src/commands/functions/functions-list.mjs +2 -2
- package/src/commands/serve/serve.mjs +4 -6
- package/src/functions-templates/typescript/hello-world/package-lock.json +6 -6
- package/src/lib/edge-functions/bootstrap.mjs +1 -1
- package/src/lib/edge-functions/headers.mjs +1 -0
- package/src/lib/edge-functions/proxy.mjs +1 -0
- package/src/lib/functions/runtimes/js/index.mjs +1 -1
- package/src/lib/functions/runtimes/js/worker.mjs +1 -1
- package/src/recipes/vscode/index.mjs +24 -6
- package/src/utils/build-info.mjs +81 -0
- package/src/utils/detect-server-settings.mjs +26 -87
- package/src/utils/framework-server.mjs +4 -3
- package/src/utils/functions/functions.mjs +1 -5
- package/src/utils/proxy.mjs +0 -3
- package/src/utils/read-repo-url.mjs +4 -0
- package/src/utils/run-build.mjs +40 -65
- package/src/utils/shell.mjs +10 -4
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
3
|
"description": "Netlify command line tool",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.10.0-rc.0",
|
|
5
5
|
"author": "Netlify Inc.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
@@ -44,15 +44,14 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@bugsnag/js": "7.20.2",
|
|
46
46
|
"@fastify/static": "6.10.2",
|
|
47
|
-
"@netlify/build": "29.17.
|
|
48
|
-
"@netlify/build-info": "7.7.
|
|
47
|
+
"@netlify/build": "29.17.3",
|
|
48
|
+
"@netlify/build-info": "7.7.3",
|
|
49
49
|
"@netlify/config": "20.6.4",
|
|
50
|
-
"@netlify/edge-bundler": "8.
|
|
50
|
+
"@netlify/edge-bundler": "8.17.1",
|
|
51
51
|
"@netlify/local-functions-proxy": "1.1.1",
|
|
52
52
|
"@netlify/serverless-functions-api": "1.5.2",
|
|
53
53
|
"@netlify/zip-it-and-ship-it": "9.13.1",
|
|
54
54
|
"@octokit/rest": "19.0.13",
|
|
55
|
-
"@skn0tt/lambda-local": "2.0.3",
|
|
56
55
|
"ansi-escapes": "6.2.0",
|
|
57
56
|
"ansi-styles": "6.2.1",
|
|
58
57
|
"ansi-to-html": "0.7.2",
|
|
@@ -107,6 +106,7 @@
|
|
|
107
106
|
"isexe": "2.0.0",
|
|
108
107
|
"jsonwebtoken": "9.0.1",
|
|
109
108
|
"jwt-decode": "3.1.2",
|
|
109
|
+
"lambda-local": "2.1.1",
|
|
110
110
|
"listr": "0.14.3",
|
|
111
111
|
"locate-path": "7.2.0",
|
|
112
112
|
"lodash": "4.17.21",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
import {
|
|
2
|
+
import { existsSync } from 'fs'
|
|
3
|
+
import { join, relative, resolve } from 'path'
|
|
3
4
|
import process from 'process'
|
|
4
5
|
import { format } from 'util'
|
|
5
6
|
|
|
@@ -9,7 +10,7 @@ import { NodeFS, NoopLogger } from '@netlify/build-info/node'
|
|
|
9
10
|
import { resolveConfig } from '@netlify/config'
|
|
10
11
|
import { Command, Option } from 'commander'
|
|
11
12
|
import debug from 'debug'
|
|
12
|
-
import
|
|
13
|
+
import { findUp } from 'find-up'
|
|
13
14
|
import inquirer from 'inquirer'
|
|
14
15
|
import inquirerAutocompletePrompt from 'inquirer-autocomplete-prompt'
|
|
15
16
|
import merge from 'lodash/merge.js'
|
|
@@ -38,20 +39,27 @@ import { identify, reportError, track } from '../utils/telemetry/index.mjs'
|
|
|
38
39
|
|
|
39
40
|
// load the autocomplete plugin
|
|
40
41
|
inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt)
|
|
41
|
-
|
|
42
|
+
/** Netlify CLI client id. Lives in bot@netlify.com */
|
|
42
43
|
// TODO: setup client for multiple environments
|
|
43
44
|
const CLIENT_ID = 'd6f37de6614df7ae58664cfca524744d73807a377f5ee71f1a254f78412e3750'
|
|
44
45
|
|
|
45
46
|
const NANO_SECS_TO_MSECS = 1e6
|
|
46
|
-
|
|
47
|
+
/** The fallback width for the help terminal */
|
|
47
48
|
const FALLBACK_HELP_CMD_WIDTH = 80
|
|
48
49
|
|
|
49
50
|
const HELP_$ = NETLIFY_CYAN('$')
|
|
50
|
-
|
|
51
|
+
/** indent on commands or description on the help page */
|
|
51
52
|
const HELP_INDENT_WIDTH = 2
|
|
52
|
-
|
|
53
|
+
/** separator width between term and description */
|
|
53
54
|
const HELP_SEPARATOR_WIDTH = 5
|
|
54
55
|
|
|
56
|
+
/**
|
|
57
|
+
* A list of commands where we don't have to perform the workspace selection at.
|
|
58
|
+
* Those commands work with the system or are not writing any config files that need to be
|
|
59
|
+
* workspace aware.
|
|
60
|
+
*/
|
|
61
|
+
const COMMANDS_WITHOUT_WORKSPACE_OPTIONS = new Set(['recipes', 'completion', 'status', 'switch', 'login', 'lm'])
|
|
62
|
+
|
|
55
63
|
/**
|
|
56
64
|
* Formats a help list correctly with the correct indent
|
|
57
65
|
* @param {string[]} textArray
|
|
@@ -78,10 +86,14 @@ const getDuration = function (startTime) {
|
|
|
78
86
|
*/
|
|
79
87
|
async function selectWorkspace(project, filter) {
|
|
80
88
|
const selected = project.workspace?.packages.find((pkg) => {
|
|
81
|
-
if (
|
|
89
|
+
if (
|
|
90
|
+
project.relativeBaseDirectory &&
|
|
91
|
+
project.relativeBaseDirectory.length !== 0 &&
|
|
92
|
+
pkg.path.startsWith(project.relativeBaseDirectory)
|
|
93
|
+
) {
|
|
82
94
|
return true
|
|
83
95
|
}
|
|
84
|
-
return pkg.name === filter
|
|
96
|
+
return (pkg.name && pkg.name === filter) || pkg.path === filter
|
|
85
97
|
})
|
|
86
98
|
|
|
87
99
|
if (!selected) {
|
|
@@ -96,9 +108,9 @@ async function selectWorkspace(project, filter) {
|
|
|
96
108
|
(project.workspace?.packages || [])
|
|
97
109
|
.filter((pkg) => pkg.path.includes(input))
|
|
98
110
|
.map((pkg) => ({
|
|
99
|
-
name: `${pkg.name
|
|
100
|
-
|
|
101
|
-
}`,
|
|
111
|
+
name: `${pkg.name ? `${chalk.bold(pkg.name)} ` : ''}${pkg.path} ${chalk.dim(
|
|
112
|
+
`--filter ${pkg.name || pkg.path}`,
|
|
113
|
+
)}`,
|
|
102
114
|
value: pkg.path,
|
|
103
115
|
})),
|
|
104
116
|
})
|
|
@@ -131,6 +143,12 @@ export default class BaseCommand extends Command {
|
|
|
131
143
|
// eslint-disable-next-line workspace/no-process-cwd
|
|
132
144
|
workingDir = process.cwd()
|
|
133
145
|
|
|
146
|
+
/**
|
|
147
|
+
* The workspace root if inside a mono repository.
|
|
148
|
+
* Must not be the repository root!
|
|
149
|
+
* @type {string|undefined}
|
|
150
|
+
*/
|
|
151
|
+
jsWorkspaceRoot
|
|
134
152
|
/**
|
|
135
153
|
* The current workspace package we should execute the commands in
|
|
136
154
|
* @type {string|undefined}
|
|
@@ -144,57 +162,61 @@ export default class BaseCommand extends Command {
|
|
|
144
162
|
* @returns
|
|
145
163
|
*/
|
|
146
164
|
createCommand(name) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
.addOption(
|
|
164
|
-
new Option(
|
|
165
|
-
'--httpProxyCertificateFilename [file]',
|
|
166
|
-
'Old, prefer --http-proxy-certificate-filename. Certificate file to use when connecting using a proxy server.',
|
|
167
|
-
)
|
|
168
|
-
.default(process.env.NETLIFY_PROXY_CERTIFICATE_FILENAME)
|
|
169
|
-
.hideHelp(true),
|
|
165
|
+
const base = new BaseCommand(name)
|
|
166
|
+
// If --silent or --json flag passed disable logger
|
|
167
|
+
.addOption(new Option('--json', 'Output return values as JSON').hideHelp(true))
|
|
168
|
+
.addOption(new Option('--silent', 'Silence CLI output').hideHelp(true))
|
|
169
|
+
.addOption(new Option('--cwd <cwd>').hideHelp(true))
|
|
170
|
+
.addOption(new Option('-o, --offline').hideHelp(true))
|
|
171
|
+
.addOption(new Option('--auth <token>', 'Netlify auth token').hideHelp(true))
|
|
172
|
+
.addOption(
|
|
173
|
+
new Option('--httpProxy [address]', 'Old, prefer --http-proxy. Proxy server address to route requests through.')
|
|
174
|
+
.default(process.env.HTTP_PROXY || process.env.HTTPS_PROXY)
|
|
175
|
+
.hideHelp(true),
|
|
176
|
+
)
|
|
177
|
+
.addOption(
|
|
178
|
+
new Option(
|
|
179
|
+
'--httpProxyCertificateFilename [file]',
|
|
180
|
+
'Old, prefer --http-proxy-certificate-filename. Certificate file to use when connecting using a proxy server.',
|
|
170
181
|
)
|
|
171
|
-
|
|
182
|
+
.default(process.env.NETLIFY_PROXY_CERTIFICATE_FILENAME)
|
|
183
|
+
.hideHelp(true),
|
|
184
|
+
)
|
|
185
|
+
.addOption(
|
|
186
|
+
new Option(
|
|
172
187
|
'--http-proxy-certificate-filename [file]',
|
|
173
188
|
'Certificate file to use when connecting using a proxy server',
|
|
174
|
-
process.env.NETLIFY_PROXY_CERTIFICATE_FILENAME,
|
|
175
|
-
)
|
|
176
|
-
.option(
|
|
177
|
-
'--http-proxy [address]',
|
|
178
|
-
'Proxy server address to route requests through.',
|
|
179
|
-
process.env.HTTP_PROXY || process.env.HTTPS_PROXY,
|
|
180
189
|
)
|
|
181
|
-
|
|
190
|
+
.default(process.env.NETLIFY_PROXY_CERTIFICATE_FILENAME)
|
|
191
|
+
.hideHelp(true),
|
|
192
|
+
)
|
|
193
|
+
.addOption(
|
|
194
|
+
new Option('--httpProxy [address]', 'Proxy server address to route requests through.')
|
|
195
|
+
.default(process.env.HTTP_PROXY || process.env.HTTPS_PROXY)
|
|
196
|
+
.hideHelp(true),
|
|
197
|
+
)
|
|
198
|
+
.option('--debug', 'Print debugging information')
|
|
199
|
+
|
|
200
|
+
// only add the `--config` or `--filter` option to commands that are workspace aware
|
|
201
|
+
if (!COMMANDS_WITHOUT_WORKSPACE_OPTIONS.has(name)) {
|
|
202
|
+
base
|
|
182
203
|
.option('--config <configFilePath>', 'Custom path to a netlify configuration file')
|
|
183
204
|
.option(
|
|
184
205
|
'--filter <app>',
|
|
185
206
|
'Optional name of an application to run the command in.\nThis option is needed for working in Monorepos',
|
|
186
207
|
)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return base.hook('preAction', async (_parentCommand, actionCommand) => {
|
|
211
|
+
if (actionCommand.opts()?.debug) {
|
|
212
|
+
process.env.DEBUG = '*'
|
|
213
|
+
}
|
|
214
|
+
debug(`${name}:preAction`)('start')
|
|
215
|
+
this.analytics = { startTime: process.hrtime.bigint() }
|
|
216
|
+
// @ts-ignore cannot type actionCommand as BaseCommand
|
|
217
|
+
await this.init(actionCommand)
|
|
218
|
+
debug(`${name}:preAction`)('end')
|
|
219
|
+
})
|
|
198
220
|
}
|
|
199
221
|
|
|
200
222
|
/** @private */
|
|
@@ -234,18 +256,22 @@ export default class BaseCommand extends Command {
|
|
|
234
256
|
return padLeft(term, HELP_INDENT_WIDTH)
|
|
235
257
|
}
|
|
236
258
|
|
|
259
|
+
/**
|
|
260
|
+
* @param {BaseCommand} command
|
|
261
|
+
*/
|
|
237
262
|
const getCommands = (command) => {
|
|
238
263
|
const parentCommand = this.name() === 'netlify' ? command : command.parent
|
|
239
|
-
return
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
264
|
+
return (
|
|
265
|
+
parentCommand?.commands.filter((cmd) => {
|
|
266
|
+
if (cmd._hidden) return false
|
|
267
|
+
// the root command
|
|
268
|
+
if (this.name() === 'netlify') {
|
|
269
|
+
// don't include subcommands on the main page
|
|
270
|
+
return !cmd.name().includes(':')
|
|
271
|
+
}
|
|
272
|
+
return cmd.name().startsWith(`${command.name()}:`)
|
|
273
|
+
}) || []
|
|
274
|
+
)
|
|
249
275
|
}
|
|
250
276
|
|
|
251
277
|
/**
|
|
@@ -338,9 +364,8 @@ export default class BaseCommand extends Command {
|
|
|
338
364
|
}
|
|
339
365
|
|
|
340
366
|
// Aliases
|
|
341
|
-
|
|
367
|
+
|
|
342
368
|
if (command._aliases.length !== 0) {
|
|
343
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
344
369
|
const aliases = command._aliases.map((alias) => formatItem(`${parentCommand.name()} ${alias}`, null, true))
|
|
345
370
|
output = [...output, chalk.bold('ALIASES'), formatHelpList(aliases), '']
|
|
346
371
|
}
|
|
@@ -511,13 +536,26 @@ export default class BaseCommand extends Command {
|
|
|
511
536
|
})
|
|
512
537
|
})
|
|
513
538
|
const frameworks = await this.project.detectFrameworks()
|
|
539
|
+
/** @type { string|undefined} */
|
|
540
|
+
let packageConfig = flags.config ? resolve(flags.config) : undefined
|
|
514
541
|
// check if we have detected multiple projects inside which one we have to perform our operations.
|
|
515
542
|
// only ask to select one if on the workspace root
|
|
516
|
-
if (
|
|
543
|
+
if (
|
|
544
|
+
!COMMANDS_WITHOUT_WORKSPACE_OPTIONS.has(actionCommand.name()) &&
|
|
545
|
+
this.project.workspace?.packages.length &&
|
|
546
|
+
this.project.workspace.isRoot
|
|
547
|
+
) {
|
|
517
548
|
this.workspacePackage = await selectWorkspace(this.project, actionCommand.opts().filter)
|
|
518
549
|
this.workingDir = join(this.project.jsWorkspaceRoot, this.workspacePackage)
|
|
519
550
|
}
|
|
520
551
|
|
|
552
|
+
this.jsWorkspaceRoot = this.project.jsWorkspaceRoot
|
|
553
|
+
// detect if a toml exists in this package.
|
|
554
|
+
const tomlFile = join(this.workingDir, 'netlify.toml')
|
|
555
|
+
if (!packageConfig && existsSync(tomlFile)) {
|
|
556
|
+
packageConfig = tomlFile
|
|
557
|
+
}
|
|
558
|
+
|
|
521
559
|
// ==================================================
|
|
522
560
|
// Retrieve Site id and build state from the state.json
|
|
523
561
|
// ==================================================
|
|
@@ -541,9 +579,10 @@ export default class BaseCommand extends Command {
|
|
|
541
579
|
// configuration file and the API
|
|
542
580
|
// ==================================================
|
|
543
581
|
const cachedConfig = await actionCommand.getConfig({
|
|
544
|
-
cwd: this.workingDir,
|
|
582
|
+
cwd: this.jsWorkspaceRoot || this.workingDir,
|
|
583
|
+
repositoryRoot: rootDir,
|
|
545
584
|
// The config flag needs to be resolved from the actual process working directory
|
|
546
|
-
configFilePath:
|
|
585
|
+
configFilePath: packageConfig,
|
|
547
586
|
state,
|
|
548
587
|
token,
|
|
549
588
|
...apiUrlOpts,
|
|
@@ -588,11 +627,20 @@ export default class BaseCommand extends Command {
|
|
|
588
627
|
actionCommand.project = this.project
|
|
589
628
|
actionCommand.workingDir = this.workingDir
|
|
590
629
|
actionCommand.workspacePackage = this.workspacePackage
|
|
630
|
+
actionCommand.jsWorkspaceRoot = this.jsWorkspaceRoot
|
|
631
|
+
|
|
632
|
+
// Either an existing configuration file from `@netlify/config` or a file path
|
|
633
|
+
// that should be used for creating it.
|
|
634
|
+
const configFilePath = configPath || join(this.workingDir, 'netlify.toml')
|
|
635
|
+
|
|
591
636
|
actionCommand.netlify = {
|
|
592
637
|
// api methods
|
|
593
638
|
api,
|
|
594
639
|
apiOpts,
|
|
640
|
+
// The Absolute Repository root (detected through @netlify/config)
|
|
595
641
|
repositoryRoot,
|
|
642
|
+
configFilePath,
|
|
643
|
+
relConfigFilePath: relative(repositoryRoot, configFilePath),
|
|
596
644
|
// current site context
|
|
597
645
|
site: {
|
|
598
646
|
root: buildDir,
|
|
@@ -683,24 +731,19 @@ export default class BaseCommand extends Command {
|
|
|
683
731
|
* @returns {'production' | 'dev'}
|
|
684
732
|
*/
|
|
685
733
|
getDefaultContext() {
|
|
686
|
-
|
|
687
|
-
return 'production'
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
return 'dev'
|
|
734
|
+
return this.name() === 'serve' ? 'production' : 'dev'
|
|
691
735
|
}
|
|
692
736
|
}
|
|
693
737
|
|
|
694
738
|
/**
|
|
695
739
|
* Retrieves the repository root through a git command.
|
|
696
740
|
* Returns undefined if not a git project.
|
|
741
|
+
* @param {string} [cwd] The optional current working directory
|
|
697
742
|
* @returns {Promise<string|undefined>}
|
|
698
743
|
*/
|
|
699
|
-
async function getRepositoryRoot() {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
return res
|
|
703
|
-
} catch {
|
|
704
|
-
// noop
|
|
744
|
+
async function getRepositoryRoot(cwd) {
|
|
745
|
+
const res = await findUp('.git', { cwd, type: 'directory' })
|
|
746
|
+
if (res) {
|
|
747
|
+
return join(res, '..')
|
|
705
748
|
}
|
|
706
749
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import process from 'process'
|
|
3
3
|
|
|
4
4
|
import { getBuildOptions, runBuild } from '../../lib/build.mjs'
|
|
5
|
+
import { detectFrameworkSettings } from '../../utils/build-info.mjs'
|
|
5
6
|
import { error, exit, getToken } from '../../utils/command-helpers.mjs'
|
|
6
7
|
import { getEnvelopeEnv, normalizeContext } from '../../utils/env/index.mjs'
|
|
7
8
|
|
|
@@ -33,11 +34,18 @@ const injectEnv = async function (command, { api, buildOptions, context, siteInf
|
|
|
33
34
|
* @param {import('../base-command.mjs').default} command
|
|
34
35
|
*/
|
|
35
36
|
const build = async (options, command) => {
|
|
37
|
+
const { cachedConfig, siteInfo } = command.netlify
|
|
36
38
|
command.setAnalyticsPayload({ dry: options.dry })
|
|
37
39
|
// Retrieve Netlify Build options
|
|
38
40
|
const [token] = await getToken()
|
|
41
|
+
const settings = await detectFrameworkSettings(command, 'build')
|
|
42
|
+
|
|
43
|
+
// override the build command with the detection result if no command is specified through the config
|
|
44
|
+
if (!cachedConfig.config.build.command) {
|
|
45
|
+
cachedConfig.config.build.command = settings?.buildCommand
|
|
46
|
+
cachedConfig.config.build.commandOrigin = 'heuristics'
|
|
47
|
+
}
|
|
39
48
|
|
|
40
|
-
const { cachedConfig, siteInfo } = command.netlify
|
|
41
49
|
const buildOptions = await getBuildOptions({
|
|
42
50
|
cachedConfig,
|
|
43
51
|
token,
|
|
@@ -72,6 +72,7 @@ const triggerDeploy = async ({ api, options, siteData, siteId }) => {
|
|
|
72
72
|
* @returns {Promise<string>}
|
|
73
73
|
*/
|
|
74
74
|
const getDeployFolder = async ({ config, options, site, siteData, workingDir }) => {
|
|
75
|
+
console.log()
|
|
75
76
|
let deployFolder
|
|
76
77
|
if (options.dir) {
|
|
77
78
|
deployFolder = resolve(workingDir, options.dir)
|
package/src/commands/dev/dev.mjs
CHANGED
|
@@ -102,6 +102,7 @@ const dev = async (options, command) => {
|
|
|
102
102
|
autoLaunch: Boolean(options.open),
|
|
103
103
|
...(config.functionsDirectory && { functions: config.functionsDirectory }),
|
|
104
104
|
...(config.build.publish && { publish: config.build.publish }),
|
|
105
|
+
...(config.build.base && { base: config.build.base }),
|
|
105
106
|
...config.dev,
|
|
106
107
|
...options,
|
|
107
108
|
}
|
|
@@ -151,11 +152,9 @@ const dev = async (options, command) => {
|
|
|
151
152
|
log(`${NETLIFYDEVWARN} Setting up local development server`)
|
|
152
153
|
|
|
153
154
|
const { configPath: configPathOverride } = await runDevTimeline({
|
|
154
|
-
|
|
155
|
+
command,
|
|
155
156
|
options,
|
|
156
157
|
settings,
|
|
157
|
-
projectDir: command.workingDir,
|
|
158
|
-
site,
|
|
159
158
|
env: {
|
|
160
159
|
URL: url,
|
|
161
160
|
DEPLOY_URL: url,
|