netlify-cli 8.15.2 → 8.16.0-rc-eh
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/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/src/commands/deploy/deploy.js +0 -7
- package/src/commands/functions/functions-invoke.js +1 -1
- package/src/lib/edge-handlers/index.js +23 -0
- package/src/utils/deploy/deploy-site.js +26 -4
- package/src/utils/deploy/hash-files.js +12 -7
- package/src/utils/deploy/hasher-segments.js +10 -2
- package/src/utils/functions/get-functions.js +1 -9
- package/src/utils/functions/index.js +2 -1
- package/src/utils/init/utils.js +2 -2
- package/src/utils/functions/edge-handlers.js +0 -88
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.16.0-rc-eh",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "netlify-cli",
|
|
9
|
-
"version": "8.
|
|
9
|
+
"version": "8.16.0-rc-eh",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
package/package.json
CHANGED
|
@@ -20,7 +20,6 @@ const {
|
|
|
20
20
|
NETLIFYDEVERR,
|
|
21
21
|
NETLIFYDEVLOG,
|
|
22
22
|
chalk,
|
|
23
|
-
deployEdgeHandlers,
|
|
24
23
|
deploySite,
|
|
25
24
|
error,
|
|
26
25
|
exit,
|
|
@@ -313,12 +312,6 @@ const runDeploy = async ({
|
|
|
313
312
|
results = await api.createSiteDeploy({ siteId, title, body: { draft, branch: alias } })
|
|
314
313
|
deployId = results.id
|
|
315
314
|
|
|
316
|
-
await deployEdgeHandlers({
|
|
317
|
-
site,
|
|
318
|
-
deployId,
|
|
319
|
-
api,
|
|
320
|
-
silent,
|
|
321
|
-
})
|
|
322
315
|
const internalFunctionsFolder = await getInternalFunctionsDir({ base: site.root })
|
|
323
316
|
|
|
324
317
|
// The order of the directories matter: zip-it-and-ship-it will prioritize
|
|
@@ -156,7 +156,7 @@ const functionsInvoke = async (nameArgument, options, command) => {
|
|
|
156
156
|
console.warn(`${NETLIFYDEVWARN} "port" flag was not specified. Attempting to connect to localhost:8888 by default`)
|
|
157
157
|
const port = options.port || DEFAULT_PORT
|
|
158
158
|
|
|
159
|
-
const functions = await getFunctions(functionsDir
|
|
159
|
+
const functions = await getFunctions(functionsDir)
|
|
160
160
|
const functionToTrigger = await getNameFromArgs(functions, options, nameArgument)
|
|
161
161
|
const functionObj = functions.find((func) => func.name === functionToTrigger)
|
|
162
162
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
const path = require('path')
|
|
3
|
+
|
|
4
|
+
const { getPathInProject } = require('../settings')
|
|
5
|
+
|
|
6
|
+
const EDGE_HANDLERS_FOLDER = 'edge-handlers-dist'
|
|
7
|
+
const PUBLIC_URL_PATH = '.netlify/internal/edge-handlers'
|
|
8
|
+
|
|
9
|
+
const internalPath = getPathInProject([EDGE_HANDLERS_FOLDER])
|
|
10
|
+
|
|
11
|
+
const deployFileNormalizer = (file) => {
|
|
12
|
+
const isEdgeHandler = file.root === internalPath
|
|
13
|
+
const normalizedPath = isEdgeHandler ? path.join(PUBLIC_URL_PATH, file.normalizedPath) : file.normalizedPath
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
...file,
|
|
17
|
+
normalizedPath,
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const isEdgeHandlerFile = (filePath) => filePath.startsWith(`${PUBLIC_URL_PATH}${path.sep}`)
|
|
22
|
+
|
|
23
|
+
module.exports = { deployFileNormalizer, internalPath, isEdgeHandlerFile }
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const cleanDeep = require('clean-deep')
|
|
2
2
|
const tempy = require('tempy')
|
|
3
3
|
|
|
4
|
+
const edgeHandlers = require('../../lib/edge-handlers')
|
|
4
5
|
const { rmdirRecursiveAsync } = require('../../lib/fs')
|
|
5
6
|
const { warn } = require('../command-helpers')
|
|
6
7
|
|
|
@@ -52,9 +53,18 @@ const deploySite = async (
|
|
|
52
53
|
phase: 'start',
|
|
53
54
|
})
|
|
54
55
|
|
|
56
|
+
const edgeHandlersPath = edgeHandlers.internalPath
|
|
55
57
|
const [{ files, filesShaMap }, { fnShaMap, functionSchedules, functions, functionsWithNativeModules }] =
|
|
56
58
|
await Promise.all([
|
|
57
|
-
hashFiles(
|
|
59
|
+
hashFiles({
|
|
60
|
+
assetType,
|
|
61
|
+
concurrentHash,
|
|
62
|
+
directories: [configPath, dir, edgeHandlersPath],
|
|
63
|
+
filter,
|
|
64
|
+
hashAlgorithm,
|
|
65
|
+
normalizer: edgeHandlers.deployFileNormalizer,
|
|
66
|
+
statusCb,
|
|
67
|
+
}),
|
|
58
68
|
hashFns(fnDir, {
|
|
59
69
|
functionsConfig,
|
|
60
70
|
tmpDir,
|
|
@@ -67,13 +77,18 @@ const deploySite = async (
|
|
|
67
77
|
skipFunctionsCache,
|
|
68
78
|
}),
|
|
69
79
|
])
|
|
70
|
-
const
|
|
80
|
+
const edgeHandlersCount = Object.keys(files).filter(edgeHandlers.isEdgeHandlerFile).length
|
|
81
|
+
const filesCount = Object.keys(files).length - edgeHandlersCount
|
|
71
82
|
const functionsCount = Object.keys(functions).length
|
|
72
|
-
const
|
|
83
|
+
const stats = buildStatsString([
|
|
84
|
+
filesCount > 0 && `${filesCount} files`,
|
|
85
|
+
functionsCount > 0 && `${functionsCount} functions`,
|
|
86
|
+
edgeHandlersCount > 0 && `${edgeHandlersCount} Edge Handlers`,
|
|
87
|
+
])
|
|
73
88
|
|
|
74
89
|
statusCb({
|
|
75
90
|
type: 'hashing',
|
|
76
|
-
msg: `Finished hashing ${
|
|
91
|
+
msg: `Finished hashing ${stats}`,
|
|
77
92
|
phase: 'stop',
|
|
78
93
|
})
|
|
79
94
|
|
|
@@ -163,4 +178,11 @@ For more information, visit https://ntl.fyi/cli-native-modules.`)
|
|
|
163
178
|
return deployManifest
|
|
164
179
|
}
|
|
165
180
|
|
|
181
|
+
const buildStatsString = (possibleParts) => {
|
|
182
|
+
const parts = possibleParts.filter(Boolean)
|
|
183
|
+
const message = parts.slice(0, -1).join(', ')
|
|
184
|
+
|
|
185
|
+
return parts.length > 1 ? `${message} and ${parts[parts.length - 1]}` : message
|
|
186
|
+
}
|
|
187
|
+
|
|
166
188
|
module.exports = { deploySite }
|
|
@@ -5,16 +5,21 @@ const pump = promisify(require('pump'))
|
|
|
5
5
|
|
|
6
6
|
const { fileFilterCtor, fileNormalizerCtor, hasherCtor, manifestCollectorCtor } = require('./hasher-segments')
|
|
7
7
|
|
|
8
|
-
const hashFiles = async (
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
const hashFiles = async ({
|
|
9
|
+
assetType = 'file',
|
|
10
|
+
concurrentHash,
|
|
11
|
+
directories,
|
|
12
|
+
filter,
|
|
13
|
+
hashAlgorithm = 'sha1',
|
|
14
|
+
normalizer,
|
|
15
|
+
statusCb,
|
|
16
|
+
}) => {
|
|
13
17
|
if (!filter) throw new Error('Missing filter function option')
|
|
14
|
-
|
|
18
|
+
|
|
19
|
+
const fileStream = walker(directories, { filter })
|
|
15
20
|
const fileFilter = fileFilterCtor()
|
|
16
21
|
const hasher = hasherCtor({ concurrentHash, hashAlgorithm })
|
|
17
|
-
const fileNormalizer = fileNormalizerCtor({ assetType })
|
|
22
|
+
const fileNormalizer = fileNormalizerCtor({ assetType, normalizer })
|
|
18
23
|
|
|
19
24
|
// Written to by manifestCollector
|
|
20
25
|
// normalizedPath: hash (wanted by deploy API)
|
|
@@ -24,8 +24,16 @@ const hasherCtor = ({ concurrentHash, hashAlgorithm }) => {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// Inject normalized file names into normalizedPath and assetType
|
|
27
|
-
const fileNormalizerCtor = ({ assetType }) =>
|
|
28
|
-
map((fileObj) =>
|
|
27
|
+
const fileNormalizerCtor = ({ assetType, normalizer: normalizeFunction }) =>
|
|
28
|
+
map((fileObj) => {
|
|
29
|
+
const normalizedFile = { ...fileObj, assetType, normalizedPath: normalizePath(fileObj.relname) }
|
|
30
|
+
|
|
31
|
+
if (normalizeFunction !== undefined) {
|
|
32
|
+
return normalizeFunction(normalizedFile)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return normalizedFile
|
|
36
|
+
})
|
|
29
37
|
|
|
30
38
|
// A writable stream segment ctor that normalizes file paths, and writes shaMap's
|
|
31
39
|
const manifestCollectorCtor = (filesObj, shaMap, { assetType, statusCb }) => {
|
|
@@ -13,14 +13,7 @@ const addFunctionProps = ({ mainFile, name, runtime, schedule }) => {
|
|
|
13
13
|
|
|
14
14
|
const JS = 'js'
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
* @param {Record<string, { schedule?: string }>} functionConfigRecord
|
|
18
|
-
* @returns {Record<string, { schedule?: string }>}
|
|
19
|
-
*/
|
|
20
|
-
const extractSchedule = (functionConfigRecord) =>
|
|
21
|
-
Object.fromEntries(Object.entries(functionConfigRecord).map(([name, { schedule }]) => [name, { schedule }]))
|
|
22
|
-
|
|
23
|
-
const getFunctions = async (functionsSrcDir, config = {}) => {
|
|
16
|
+
const getFunctions = async (functionsSrcDir) => {
|
|
24
17
|
if (!(await fileExistsAsync(functionsSrcDir))) {
|
|
25
18
|
return []
|
|
26
19
|
}
|
|
@@ -29,7 +22,6 @@ const getFunctions = async (functionsSrcDir, config = {}) => {
|
|
|
29
22
|
// eslint-disable-next-line node/global-require
|
|
30
23
|
const { listFunctions } = require('@netlify/zip-it-and-ship-it')
|
|
31
24
|
const functions = await listFunctions(functionsSrcDir, {
|
|
32
|
-
config: config.functions ? extractSchedule(config.functions) : undefined,
|
|
33
25
|
parseISC: true,
|
|
34
26
|
})
|
|
35
27
|
const functionsWithProps = functions.filter(({ runtime }) => runtime === JS).map((func) => addFunctionProps(func))
|
package/src/utils/init/utils.js
CHANGED
|
@@ -123,8 +123,8 @@ const getPromptInputs = async ({
|
|
|
123
123
|
.map(({ name }) => `${name} plugin`)
|
|
124
124
|
.map(formatTitle)
|
|
125
125
|
.join(', ')}${EOL}➡️ OK to install??`,
|
|
126
|
-
choices: infos.map((
|
|
127
|
-
default: infos.map((
|
|
126
|
+
choices: infos.map(({ name, package }) => ({ name: `${name} plugin`, value: package })),
|
|
127
|
+
default: infos.map(({ package }) => package),
|
|
128
128
|
},
|
|
129
129
|
]
|
|
130
130
|
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
const fs = require('fs').promises
|
|
3
|
-
const path = require('path')
|
|
4
|
-
|
|
5
|
-
const { cancelDeploy, uploadEdgeHandlers } = require('../../lib/api')
|
|
6
|
-
const { readFileAsyncCatchError } = require('../../lib/fs')
|
|
7
|
-
const { startSpinner, stopSpinner } = require('../../lib/spinner')
|
|
8
|
-
const { error } = require('../command-helpers')
|
|
9
|
-
|
|
10
|
-
const MANIFEST_FILENAME = 'manifest.json'
|
|
11
|
-
const EDGE_HANDLERS_FOLDER = '.netlify/edge-handlers'
|
|
12
|
-
|
|
13
|
-
const validateEdgeHandlerFolder = async ({ site }) => {
|
|
14
|
-
try {
|
|
15
|
-
const resolvedFolder = path.resolve(site.root, EDGE_HANDLERS_FOLDER)
|
|
16
|
-
const stat = await fs.stat(resolvedFolder)
|
|
17
|
-
if (!stat.isDirectory()) {
|
|
18
|
-
error(`Edge Handlers folder ${EDGE_HANDLERS_FOLDER} must be a path to a directory`)
|
|
19
|
-
}
|
|
20
|
-
return resolvedFolder
|
|
21
|
-
} catch {
|
|
22
|
-
// ignore errors at the moment
|
|
23
|
-
// TODO: report error if 'edge_handlers' config exists after
|
|
24
|
-
// https://github.com/netlify/build/pull/1829 is published
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const readBundleAndManifest = async ({ edgeHandlersResolvedFolder }) => {
|
|
29
|
-
const manifestPath = path.resolve(edgeHandlersResolvedFolder, MANIFEST_FILENAME)
|
|
30
|
-
const { content: manifest, error: manifestError } = await readFileAsyncCatchError(manifestPath)
|
|
31
|
-
if (manifestError) {
|
|
32
|
-
error(`Could not read Edge Handlers manifest file ${manifestPath}: ${manifestError.message}`)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
let manifestJson
|
|
36
|
-
try {
|
|
37
|
-
manifestJson = JSON.parse(manifest)
|
|
38
|
-
} catch (error_) {
|
|
39
|
-
error(`Edge Handlers manifest file is not a valid JSON file: ${error_.message}`)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (!manifestJson.sha) {
|
|
43
|
-
error(`Edge Handlers manifest file is missing the 'sha' property`)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const bundlePath = path.resolve(edgeHandlersResolvedFolder, manifestJson.sha)
|
|
47
|
-
const { content: bundleBuffer, error: bundleError } = await readFileAsyncCatchError(bundlePath)
|
|
48
|
-
|
|
49
|
-
if (bundleError) {
|
|
50
|
-
error(`Could not read Edge Handlers bundle file ${bundlePath}: ${bundleError.message}`)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return { bundleBuffer, manifest: manifestJson }
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const deployEdgeHandlers = async ({ api, deployId, silent, site }) => {
|
|
57
|
-
const edgeHandlersResolvedFolder = await validateEdgeHandlerFolder({ site })
|
|
58
|
-
if (edgeHandlersResolvedFolder) {
|
|
59
|
-
let spinner
|
|
60
|
-
try {
|
|
61
|
-
spinner = silent
|
|
62
|
-
? null
|
|
63
|
-
: startSpinner({ text: `Deploying Edge Handlers from directory ${edgeHandlersResolvedFolder}` })
|
|
64
|
-
|
|
65
|
-
const { bundleBuffer, manifest } = await readBundleAndManifest({ edgeHandlersResolvedFolder })
|
|
66
|
-
// returns false if the bundle exists, true on success, throws on error
|
|
67
|
-
const success = await uploadEdgeHandlers({
|
|
68
|
-
api,
|
|
69
|
-
deployId,
|
|
70
|
-
bundleBuffer,
|
|
71
|
-
manifest,
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
const text = success
|
|
75
|
-
? `Finished deploying Edge Handlers from directory: ${edgeHandlersResolvedFolder}`
|
|
76
|
-
: `Skipped deploying Edge Handlers since the bundle already exists`
|
|
77
|
-
stopSpinner({ spinner, text, error: false })
|
|
78
|
-
} catch (error_) {
|
|
79
|
-
const text = `Failed deploying Edge Handlers: ${error_.message}`
|
|
80
|
-
stopSpinner({ spinner, text, error: true })
|
|
81
|
-
await cancelDeploy({ api, deployId })
|
|
82
|
-
// no need to report the error again
|
|
83
|
-
error('')
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
module.exports = { deployEdgeHandlers }
|