netlify-cli 16.9.3 → 17.0.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/npm-shrinkwrap.json +17 -3
- package/package.json +3 -2
- package/src/commands/dev/dev.mjs +9 -0
- package/src/lib/blobs/blobs.mjs +50 -0
- 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 +8 -0
- package/src/lib/functions/netlify-function.mjs +18 -1
- package/src/lib/functions/registry.mjs +9 -0
- package/src/lib/functions/runtimes/js/index.mjs +2 -1
- package/src/lib/functions/runtimes/js/worker.mjs +7 -1
- package/src/lib/functions/server.mjs +16 -2
- package/src/utils/proxy-server.mjs +3 -0
- package/src/utils/proxy.mjs +2 -0
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "17.0.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "netlify-cli",
|
|
9
|
-
"version": "
|
|
9
|
+
"version": "17.0.0",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@bugsnag/js": "7.20.2",
|
|
14
14
|
"@fastify/static": "6.10.2",
|
|
15
|
+
"@netlify/blobs": "^4.0.0",
|
|
15
16
|
"@netlify/build": "29.23.4",
|
|
16
17
|
"@netlify/build-info": "7.10.1",
|
|
17
18
|
"@netlify/config": "20.9.0",
|
|
@@ -123,7 +124,7 @@
|
|
|
123
124
|
"ntl": "bin/run.mjs"
|
|
124
125
|
},
|
|
125
126
|
"engines": {
|
|
126
|
-
"node": ">=
|
|
127
|
+
"node": ">=18.18.2"
|
|
127
128
|
}
|
|
128
129
|
},
|
|
129
130
|
"node_modules/@babel/code-frame": {
|
|
@@ -801,6 +802,14 @@
|
|
|
801
802
|
"resolved": "https://registry.npmjs.org/@netlify/binary-info/-/binary-info-1.0.0.tgz",
|
|
802
803
|
"integrity": "sha512-4wMPu9iN3/HL97QblBsBay3E1etIciR84izI3U+4iALY+JHCrI+a2jO0qbAZ/nxKoegypYEaiiqWXylm+/zfrw=="
|
|
803
804
|
},
|
|
805
|
+
"node_modules/@netlify/blobs": {
|
|
806
|
+
"version": "4.0.0",
|
|
807
|
+
"resolved": "https://registry.npmjs.org/@netlify/blobs/-/blobs-4.0.0.tgz",
|
|
808
|
+
"integrity": "sha512-jjAzsH5WCceUz8ubVlYppfhUKuTR4E6OBNherIdH7tYHWy4NnLQ5FQgVP9kR7Ps5HOxl3aPsr5ygu1KQY0mdTQ==",
|
|
809
|
+
"engines": {
|
|
810
|
+
"node": "^14.16.0 || >=16.0.0"
|
|
811
|
+
}
|
|
812
|
+
},
|
|
804
813
|
"node_modules/@netlify/build": {
|
|
805
814
|
"version": "29.23.4",
|
|
806
815
|
"resolved": "https://registry.npmjs.org/@netlify/build/-/build-29.23.4.tgz",
|
|
@@ -16905,6 +16914,11 @@
|
|
|
16905
16914
|
"resolved": "https://registry.npmjs.org/@netlify/binary-info/-/binary-info-1.0.0.tgz",
|
|
16906
16915
|
"integrity": "sha512-4wMPu9iN3/HL97QblBsBay3E1etIciR84izI3U+4iALY+JHCrI+a2jO0qbAZ/nxKoegypYEaiiqWXylm+/zfrw=="
|
|
16907
16916
|
},
|
|
16917
|
+
"@netlify/blobs": {
|
|
16918
|
+
"version": "4.0.0",
|
|
16919
|
+
"resolved": "https://registry.npmjs.org/@netlify/blobs/-/blobs-4.0.0.tgz",
|
|
16920
|
+
"integrity": "sha512-jjAzsH5WCceUz8ubVlYppfhUKuTR4E6OBNherIdH7tYHWy4NnLQ5FQgVP9kR7Ps5HOxl3aPsr5ygu1KQY0mdTQ=="
|
|
16921
|
+
},
|
|
16908
16922
|
"@netlify/build": {
|
|
16909
16923
|
"version": "29.23.4",
|
|
16910
16924
|
"resolved": "https://registry.npmjs.org/@netlify/build/-/build-29.23.4.tgz",
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
3
|
"description": "Netlify command line tool",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "17.0.0",
|
|
5
5
|
"author": "Netlify Inc.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
8
|
-
"node": ">=
|
|
8
|
+
"node": ">=18.18.2"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"/bin",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@bugsnag/js": "7.20.2",
|
|
46
46
|
"@fastify/static": "6.10.2",
|
|
47
|
+
"@netlify/blobs": "^4.0.0",
|
|
47
48
|
"@netlify/build": "29.23.4",
|
|
48
49
|
"@netlify/build-info": "7.10.1",
|
|
49
50
|
"@netlify/config": "20.9.0",
|
package/src/commands/dev/dev.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import process from 'process'
|
|
|
3
3
|
|
|
4
4
|
import { Option } from 'commander'
|
|
5
5
|
|
|
6
|
+
import { getBlobsContext } from '../../lib/blobs/blobs.mjs'
|
|
6
7
|
import { promptEditorHelper } from '../../lib/edge-functions/editor-helper.mjs'
|
|
7
8
|
import { startFunctionsServer } from '../../lib/functions/server.mjs'
|
|
8
9
|
import { printBanner } from '../../utils/banner.mjs'
|
|
@@ -161,8 +162,15 @@ const dev = async (options, command) => {
|
|
|
161
162
|
},
|
|
162
163
|
})
|
|
163
164
|
|
|
165
|
+
const blobsContext = await getBlobsContext({
|
|
166
|
+
debug: options.debug,
|
|
167
|
+
projectRoot: command.workingDir,
|
|
168
|
+
siteID: site.id ?? 'unknown-site-id',
|
|
169
|
+
})
|
|
170
|
+
|
|
164
171
|
const functionsRegistry = await startFunctionsServer({
|
|
165
172
|
api,
|
|
173
|
+
blobsContext,
|
|
166
174
|
command,
|
|
167
175
|
config,
|
|
168
176
|
debug: options.debug,
|
|
@@ -202,6 +210,7 @@ const dev = async (options, command) => {
|
|
|
202
210
|
|
|
203
211
|
await startProxyServer({
|
|
204
212
|
addonsUrls,
|
|
213
|
+
blobsContext,
|
|
205
214
|
config,
|
|
206
215
|
configPath: configPathOverride,
|
|
207
216
|
debug: options.debug,
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
|
|
3
|
+
import { BlobsServer } from '@netlify/blobs'
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
5
|
+
|
|
6
|
+
import { getPathInProject } from '../settings.mjs'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef BlobsContext
|
|
10
|
+
* @type {object}
|
|
11
|
+
* @property {string} edgeURL
|
|
12
|
+
* @property {string} deployID
|
|
13
|
+
* @property {string} siteID
|
|
14
|
+
* @property {string} token
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Starts a local Blobs server and returns a context object that lets functions
|
|
19
|
+
* connect to it.
|
|
20
|
+
*
|
|
21
|
+
* @param {object} options
|
|
22
|
+
* @param {boolean} options.debug
|
|
23
|
+
* @param {string} options.projectRoot
|
|
24
|
+
* @param {string} options.siteID
|
|
25
|
+
* @returns {Promise<BlobsContext>}
|
|
26
|
+
*/
|
|
27
|
+
export const getBlobsContext = async ({ debug, projectRoot, siteID }) => {
|
|
28
|
+
const token = uuidv4()
|
|
29
|
+
const { port } = await startBlobsServer({ debug, projectRoot, token })
|
|
30
|
+
const context = {
|
|
31
|
+
deployID: '0',
|
|
32
|
+
edgeURL: `http://localhost:${port}`,
|
|
33
|
+
siteID,
|
|
34
|
+
token,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return context
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const startBlobsServer = async ({ debug, projectRoot, token }) => {
|
|
41
|
+
const directory = path.resolve(projectRoot, getPathInProject(['blobs']))
|
|
42
|
+
const server = new BlobsServer({
|
|
43
|
+
debug,
|
|
44
|
+
directory,
|
|
45
|
+
token,
|
|
46
|
+
})
|
|
47
|
+
const { port } = await server.start()
|
|
48
|
+
|
|
49
|
+
return { port }
|
|
50
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { env } from 'process'
|
|
2
2
|
|
|
3
|
-
const latestBootstrapURL = 'https://
|
|
3
|
+
const latestBootstrapURL = 'https://6539213a19a93a000876a033--edge.netlify.com/bootstrap/index-combined.ts'
|
|
4
4
|
|
|
5
5
|
export const getBootstrapURL = () => env.NETLIFY_EDGE_BOOTSTRAP || latestBootstrapURL
|
|
@@ -66,6 +66,7 @@ export const createAccountInfoHeader = (accountInfo = {}) => {
|
|
|
66
66
|
*
|
|
67
67
|
* @param {object} config
|
|
68
68
|
* @param {*} config.accountId
|
|
69
|
+
* @param {import("../blobs/blobs.mjs").BlobsContext} config.blobsContext
|
|
69
70
|
* @param {*} config.config
|
|
70
71
|
* @param {*} config.configPath
|
|
71
72
|
* @param {*} config.debug
|
|
@@ -85,6 +86,7 @@ export const createAccountInfoHeader = (accountInfo = {}) => {
|
|
|
85
86
|
*/
|
|
86
87
|
export const initializeProxy = async ({
|
|
87
88
|
accountId,
|
|
89
|
+
blobsContext,
|
|
88
90
|
config,
|
|
89
91
|
configPath,
|
|
90
92
|
debug,
|
|
@@ -151,6 +153,12 @@ export const initializeProxy = async ({
|
|
|
151
153
|
req.headers[headers.Site] = createSiteInfoHeader(siteInfo)
|
|
152
154
|
req.headers[headers.Account] = createAccountInfoHeader({ id: accountId })
|
|
153
155
|
|
|
156
|
+
if (blobsContext?.edgeURL && blobsContext?.token) {
|
|
157
|
+
req.headers[headers.BlobsInfo] = Buffer.from(
|
|
158
|
+
JSON.stringify({ url: blobsContext.edgeURL, token: blobsContext.token }),
|
|
159
|
+
).toString('base64')
|
|
160
|
+
}
|
|
161
|
+
|
|
154
162
|
await registry.initialize()
|
|
155
163
|
|
|
156
164
|
const url = new URL(req.url, `http://${LOCAL_HOST}:${mainPort}`)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
+
import { Buffer } from 'buffer'
|
|
2
3
|
import { basename, extname } from 'path'
|
|
3
4
|
import { version as nodeVersion } from 'process'
|
|
4
5
|
|
|
@@ -23,6 +24,7 @@ const getNextRun = function (schedule) {
|
|
|
23
24
|
|
|
24
25
|
export default class NetlifyFunction {
|
|
25
26
|
constructor({
|
|
27
|
+
blobsContext,
|
|
26
28
|
config,
|
|
27
29
|
directory,
|
|
28
30
|
displayName,
|
|
@@ -34,6 +36,7 @@ export default class NetlifyFunction {
|
|
|
34
36
|
timeoutBackground,
|
|
35
37
|
timeoutSynchronous,
|
|
36
38
|
}) {
|
|
39
|
+
this.blobsContext = blobsContext
|
|
37
40
|
this.buildError = null
|
|
38
41
|
this.config = config
|
|
39
42
|
this.directory = directory
|
|
@@ -181,7 +184,7 @@ export default class NetlifyFunction {
|
|
|
181
184
|
}
|
|
182
185
|
|
|
183
186
|
// Invokes the function and returns its response object.
|
|
184
|
-
async invoke(event, context) {
|
|
187
|
+
async invoke(event, context = {}) {
|
|
185
188
|
await this.buildQueue
|
|
186
189
|
|
|
187
190
|
if (this.buildError) {
|
|
@@ -189,10 +192,24 @@ export default class NetlifyFunction {
|
|
|
189
192
|
}
|
|
190
193
|
|
|
191
194
|
const timeout = this.isBackground ? this.timeoutBackground : this.timeoutSynchronous
|
|
195
|
+
const environment = {}
|
|
196
|
+
|
|
197
|
+
if (this.blobsContext) {
|
|
198
|
+
const payload = JSON.stringify({
|
|
199
|
+
url: this.blobsContext.edgeURL,
|
|
200
|
+
token: this.blobsContext.token,
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
context.custom = {
|
|
204
|
+
...context?.custom,
|
|
205
|
+
blobs: Buffer.from(payload).toString('base64'),
|
|
206
|
+
}
|
|
207
|
+
}
|
|
192
208
|
|
|
193
209
|
try {
|
|
194
210
|
const result = await this.runtime.invokeFunction({
|
|
195
211
|
context,
|
|
212
|
+
environment,
|
|
196
213
|
event,
|
|
197
214
|
func: this,
|
|
198
215
|
timeout,
|
|
@@ -34,6 +34,7 @@ const ZIP_EXTENSION = '.zip'
|
|
|
34
34
|
|
|
35
35
|
export class FunctionsRegistry {
|
|
36
36
|
constructor({
|
|
37
|
+
blobsContext,
|
|
37
38
|
capabilities,
|
|
38
39
|
config,
|
|
39
40
|
debug = false,
|
|
@@ -52,6 +53,13 @@ export class FunctionsRegistry {
|
|
|
52
53
|
this.timeouts = timeouts
|
|
53
54
|
this.settings = settings
|
|
54
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Context object for Netlify Blobs
|
|
58
|
+
*
|
|
59
|
+
* @type {import("../blobs/blobs.mjs").BlobsContext}
|
|
60
|
+
*/
|
|
61
|
+
this.blobsContext = blobsContext
|
|
62
|
+
|
|
55
63
|
/**
|
|
56
64
|
* An object to be shared among all functions in the registry. It can be
|
|
57
65
|
* used to cache the results of the build function — e.g. it's used in
|
|
@@ -493,6 +501,7 @@ export class FunctionsRegistry {
|
|
|
493
501
|
}
|
|
494
502
|
|
|
495
503
|
const func = new NetlifyFunction({
|
|
504
|
+
blobsContext: this.blobsContext,
|
|
496
505
|
config: this.config,
|
|
497
506
|
directory: directories.find((directory) => mainFile.startsWith(directory)),
|
|
498
507
|
mainFile,
|
|
@@ -51,13 +51,14 @@ export const getBuildFunction = async ({ config, directory, errorExit, func, pro
|
|
|
51
51
|
|
|
52
52
|
const workerURL = new URL('worker.mjs', import.meta.url)
|
|
53
53
|
|
|
54
|
-
export const invokeFunction = async ({ context, event, func, timeout }) => {
|
|
54
|
+
export const invokeFunction = async ({ context, environment, event, func, timeout }) => {
|
|
55
55
|
if (func.buildData.runtimeAPIVersion !== 2) {
|
|
56
56
|
return await invokeFunctionDirectly({ context, event, func, timeout })
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
const workerData = {
|
|
60
60
|
clientContext: JSON.stringify(context),
|
|
61
|
+
environment,
|
|
61
62
|
event,
|
|
62
63
|
// If a function builder has defined a `buildPath` property, we use it.
|
|
63
64
|
// Otherwise, we'll invoke the function's main file.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createServer } from 'net'
|
|
2
|
+
import process from 'process'
|
|
2
3
|
import { isMainThread, workerData, parentPort } from 'worker_threads'
|
|
3
4
|
|
|
4
5
|
import { isStream } from 'is-stream'
|
|
@@ -13,7 +14,12 @@ sourceMapSupport.install()
|
|
|
13
14
|
|
|
14
15
|
lambdaLocal.getLogger().level = 'alert'
|
|
15
16
|
|
|
16
|
-
const { clientContext, entryFilePath, event, timeoutMs } = workerData
|
|
17
|
+
const { clientContext, entryFilePath, environment = {}, event, timeoutMs } = workerData
|
|
18
|
+
|
|
19
|
+
// Injecting into the environment any properties passed in by the parent.
|
|
20
|
+
for (const key in environment) {
|
|
21
|
+
process.env[key] = environment[key]
|
|
22
|
+
}
|
|
17
23
|
|
|
18
24
|
const lambdaFunc = await import(entryFilePath)
|
|
19
25
|
|
|
@@ -137,6 +137,7 @@ export const createHandler = function (options) {
|
|
|
137
137
|
'client-ip': [remoteAddress],
|
|
138
138
|
'x-nf-client-connection-ip': [remoteAddress],
|
|
139
139
|
'x-nf-account-id': [options.accountId],
|
|
140
|
+
'x-nf-site-id': [options?.siteInfo?.id],
|
|
140
141
|
[efHeaders.Geo]: Buffer.from(JSON.stringify(geoLocation)).toString('base64'),
|
|
141
142
|
}).reduce((prev, [key, value]) => ({ ...prev, [key]: Array.isArray(value) ? value : [value] }), {})
|
|
142
143
|
const rawQuery = new URLSearchParams(requestQuery).toString()
|
|
@@ -245,6 +246,7 @@ const getFunctionsServer = (options) => {
|
|
|
245
246
|
/**
|
|
246
247
|
*
|
|
247
248
|
* @param {object} options
|
|
249
|
+
* @param {import("../blobs/blobs.mjs").BlobsContext} options.blobsContext
|
|
248
250
|
* @param {import('../../commands/base-command.mjs').default} options.command
|
|
249
251
|
* @param {*} options.capabilities
|
|
250
252
|
* @param {*} options.config
|
|
@@ -258,8 +260,19 @@ const getFunctionsServer = (options) => {
|
|
|
258
260
|
* @returns {Promise<import('./registry.mjs').FunctionsRegistry | undefined>}
|
|
259
261
|
*/
|
|
260
262
|
export const startFunctionsServer = async (options) => {
|
|
261
|
-
const {
|
|
262
|
-
|
|
263
|
+
const {
|
|
264
|
+
blobsContext,
|
|
265
|
+
capabilities,
|
|
266
|
+
command,
|
|
267
|
+
config,
|
|
268
|
+
debug,
|
|
269
|
+
loadDistFunctions,
|
|
270
|
+
settings,
|
|
271
|
+
site,
|
|
272
|
+
siteInfo,
|
|
273
|
+
siteUrl,
|
|
274
|
+
timeouts,
|
|
275
|
+
} = options
|
|
263
276
|
const internalFunctionsDir = await getInternalFunctionsDir({ base: site.root })
|
|
264
277
|
const functionsDirectories = []
|
|
265
278
|
let manifest
|
|
@@ -306,6 +319,7 @@ export const startFunctionsServer = async (options) => {
|
|
|
306
319
|
}
|
|
307
320
|
|
|
308
321
|
const functionsRegistry = new FunctionsRegistry({
|
|
322
|
+
blobsContext,
|
|
309
323
|
capabilities,
|
|
310
324
|
config,
|
|
311
325
|
debug,
|
|
@@ -38,6 +38,7 @@ export const generateInspectSettings = (edgeInspect, edgeInspectBrk) => {
|
|
|
38
38
|
* @param {object} params
|
|
39
39
|
* @param {string=} params.accountId
|
|
40
40
|
* @param {*} params.addonsUrls
|
|
41
|
+
* @param {import("../lib/blobs/blobs.mjs").BlobsContext} blobsContext
|
|
41
42
|
* @param {import('../commands/types.js').NetlifyOptions["config"]} params.config
|
|
42
43
|
* @param {string} [params.configPath] An override for the Netlify config path
|
|
43
44
|
* @param {boolean} params.debug
|
|
@@ -58,6 +59,7 @@ export const generateInspectSettings = (edgeInspect, edgeInspectBrk) => {
|
|
|
58
59
|
export const startProxyServer = async ({
|
|
59
60
|
accountId,
|
|
60
61
|
addonsUrls,
|
|
62
|
+
blobsContext,
|
|
61
63
|
config,
|
|
62
64
|
configPath,
|
|
63
65
|
debug,
|
|
@@ -76,6 +78,7 @@ export const startProxyServer = async ({
|
|
|
76
78
|
}) => {
|
|
77
79
|
const url = await startProxy({
|
|
78
80
|
addonsUrls,
|
|
81
|
+
blobsContext,
|
|
79
82
|
config,
|
|
80
83
|
configPath: configPath || site.configPath,
|
|
81
84
|
debug,
|
package/src/utils/proxy.mjs
CHANGED
|
@@ -675,6 +675,7 @@ export const getProxyUrl = function (settings) {
|
|
|
675
675
|
export const startProxy = async function ({
|
|
676
676
|
accountId,
|
|
677
677
|
addonsUrls,
|
|
678
|
+
blobsContext,
|
|
678
679
|
config,
|
|
679
680
|
configPath,
|
|
680
681
|
debug,
|
|
@@ -693,6 +694,7 @@ export const startProxy = async function ({
|
|
|
693
694
|
const secondaryServerPort = settings.https ? await getAvailablePort() : null
|
|
694
695
|
const functionsServer = settings.functionsPort ? `http://127.0.0.1:${settings.functionsPort}` : null
|
|
695
696
|
const edgeFunctionsProxy = await initializeEdgeFunctionsProxy({
|
|
697
|
+
blobsContext,
|
|
696
698
|
config,
|
|
697
699
|
configPath,
|
|
698
700
|
debug,
|