netlify-cli 9.0.5 → 9.3.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 +1 -0
- package/npm-shrinkwrap.json +517 -672
- package/package.json +3 -3
- package/src/commands/dev/dev.js +6 -41
- package/src/commands/functions/functions-serve.js +2 -0
- package/src/commands/graph/graph-config-write.js +55 -0
- package/src/commands/graph/graph-edit.js +20 -6
- package/src/commands/graph/graph.js +2 -0
- package/src/lib/functions/server.js +58 -23
- package/src/lib/one-graph/cli-client.js +110 -6
- package/src/lib/one-graph/cli-netlify-graph.js +12 -4
- package/src/utils/dev.js +3 -3
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
3
|
"description": "Netlify command line tool",
|
|
4
|
-
"version": "9.0
|
|
4
|
+
"version": "9.3.0",
|
|
5
5
|
"author": "Netlify Inc.",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"Abraham Schilling <AbrahamSchilling@gmail.com> (https://gitlab.com/n4bb12)",
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
"@netlify/framework-info": "^9.0.0",
|
|
204
204
|
"@netlify/local-functions-proxy": "^1.1.1",
|
|
205
205
|
"@netlify/plugin-edge-handlers": "^3.0.6",
|
|
206
|
-
"@netlify/plugins-list": "^6.
|
|
206
|
+
"@netlify/plugins-list": "^6.10.1",
|
|
207
207
|
"@netlify/routing-local-proxy": "^0.34.1",
|
|
208
208
|
"@netlify/zip-it-and-ship-it": "^5.7.4",
|
|
209
209
|
"@octokit/rest": "^18.0.0",
|
|
@@ -270,7 +270,7 @@
|
|
|
270
270
|
"multiparty": "^4.2.1",
|
|
271
271
|
"netlify": "^11.0.0",
|
|
272
272
|
"netlify-headers-parser": "^6.0.1",
|
|
273
|
-
"netlify-onegraph-internal": "0.0.
|
|
273
|
+
"netlify-onegraph-internal": "0.0.42",
|
|
274
274
|
"netlify-redirect-parser": "^13.0.2",
|
|
275
275
|
"netlify-redirector": "^0.2.1",
|
|
276
276
|
"node-fetch": "^2.6.0",
|
package/src/commands/dev/dev.js
CHANGED
|
@@ -32,7 +32,6 @@ const {
|
|
|
32
32
|
detectServerSettings,
|
|
33
33
|
error,
|
|
34
34
|
exit,
|
|
35
|
-
generateAuthlifyJWT,
|
|
36
35
|
getSiteInformation,
|
|
37
36
|
injectEnvVariables,
|
|
38
37
|
log,
|
|
@@ -265,27 +264,7 @@ const dev = async (options, command) => {
|
|
|
265
264
|
}
|
|
266
265
|
|
|
267
266
|
const startNetlifyGraphWatcher = Boolean(options.graph)
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (startNetlifyGraphWatcher) {
|
|
271
|
-
const netlifyToken = await command.authenticate()
|
|
272
|
-
authlifyJWT = generateAuthlifyJWT(netlifyToken, siteInfo.authlify_token_id, site.id)
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
await injectEnvVariables({
|
|
276
|
-
env: Object.assign(
|
|
277
|
-
command.netlify.cachedConfig.env,
|
|
278
|
-
authlifyJWT == null
|
|
279
|
-
? {}
|
|
280
|
-
: {
|
|
281
|
-
ONEGRAPH_AUTHLIFY_TOKEN: {
|
|
282
|
-
sources: ['general'],
|
|
283
|
-
value: authlifyJWT,
|
|
284
|
-
},
|
|
285
|
-
},
|
|
286
|
-
),
|
|
287
|
-
site,
|
|
288
|
-
})
|
|
267
|
+
await injectEnvVariables({ env: command.netlify.cachedConfig.env, site })
|
|
289
268
|
|
|
290
269
|
const { addonsUrls, capabilities, siteUrl, timeouts } = await getSiteInformation({
|
|
291
270
|
// inherited from base command --offline
|
|
@@ -306,28 +285,14 @@ const dev = async (options, command) => {
|
|
|
306
285
|
|
|
307
286
|
command.setAnalyticsPayload({ projectType: settings.framework || 'custom', live: options.live })
|
|
308
287
|
|
|
309
|
-
let configWithAuthlify
|
|
310
|
-
|
|
311
|
-
if (siteInfo.authlify_token_id) {
|
|
312
|
-
const netlifyToken = command.authenticate()
|
|
313
|
-
// Only inject the authlify config if a token ID exists. This prevents
|
|
314
|
-
// calling command.authenticate() (which opens a browser window) if the
|
|
315
|
-
// user hasn't enabled API Authentication
|
|
316
|
-
configWithAuthlify = Object.assign(config, {
|
|
317
|
-
authlify: {
|
|
318
|
-
netlifyToken,
|
|
319
|
-
authlifyTokenId: siteInfo.authlify_token_id,
|
|
320
|
-
siteId: site.id,
|
|
321
|
-
},
|
|
322
|
-
})
|
|
323
|
-
} else {
|
|
324
|
-
configWithAuthlify = config
|
|
325
|
-
}
|
|
326
|
-
|
|
327
288
|
await startFunctionsServer({
|
|
328
|
-
|
|
289
|
+
api,
|
|
290
|
+
command,
|
|
291
|
+
config,
|
|
292
|
+
isGraphEnabled: startNetlifyGraphWatcher,
|
|
329
293
|
settings,
|
|
330
294
|
site,
|
|
295
|
+
siteInfo,
|
|
331
296
|
siteUrl,
|
|
332
297
|
capabilities,
|
|
333
298
|
timeouts,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const path = require('path')
|
|
4
|
+
|
|
5
|
+
const { getNetlifyGraphConfig } = require('../../lib/one-graph/cli-netlify-graph')
|
|
6
|
+
const { NETLIFYDEVERR, chalk, error } = require('../../utils')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates the `netlify graph:config:write` command
|
|
10
|
+
* @param {import('commander').OptionValues} options
|
|
11
|
+
* @param {import('../base-command').BaseCommand} command
|
|
12
|
+
* @returns
|
|
13
|
+
*/
|
|
14
|
+
const graphConfigWrite = async (options, command) => {
|
|
15
|
+
const { site } = command.netlify
|
|
16
|
+
|
|
17
|
+
if (!site.id) {
|
|
18
|
+
error(
|
|
19
|
+
`${NETLIFYDEVERR} Warning: no siteId defined, unable to start Netlify Graph. To enable, run ${chalk.yellow(
|
|
20
|
+
'netlify init',
|
|
21
|
+
)} or ${chalk.yellow('netlify link')}`,
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options })
|
|
26
|
+
|
|
27
|
+
const schemaPath = netlifyGraphConfig.graphQLSchemaFilename.join('/')
|
|
28
|
+
|
|
29
|
+
// Support tools that looks for the schema under different keys
|
|
30
|
+
const graphQLConfig = {
|
|
31
|
+
schema: [schemaPath],
|
|
32
|
+
schemaPath: [schemaPath],
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const filePath = path.resolve(...netlifyGraphConfig.graphQLConfigJsonFilename)
|
|
36
|
+
|
|
37
|
+
fs.writeFileSync(filePath, JSON.stringify(graphQLConfig, null, 2))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates the `netlify graph:config:write` command
|
|
42
|
+
* @param {import('../base-command').BaseCommand} program
|
|
43
|
+
* @returns
|
|
44
|
+
*/
|
|
45
|
+
const createGraphConfigWriteCommand = (program) =>
|
|
46
|
+
program
|
|
47
|
+
.command('graph:config:write')
|
|
48
|
+
.description(
|
|
49
|
+
'Write a .graphqlrc.json file to the current directory for use with local tooling (e.g. the graphql extension for vscode)',
|
|
50
|
+
)
|
|
51
|
+
.action(async (options, command) => {
|
|
52
|
+
await graphConfigWrite(options, command)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
module.exports = { createGraphConfigWriteCommand }
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
const gitRepoInfo = require('git-repo-info')
|
|
3
3
|
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
OneGraphCliClient,
|
|
6
|
+
createCLISession,
|
|
7
|
+
generateSessionName,
|
|
8
|
+
loadCLISession,
|
|
9
|
+
upsertMergeCLISessionMetadata,
|
|
10
|
+
} = require('../../lib/one-graph/cli-client')
|
|
5
11
|
const {
|
|
6
12
|
defaultExampleOperationsDoc,
|
|
7
13
|
getGraphEditUrlBySiteId,
|
|
@@ -11,7 +17,7 @@ const {
|
|
|
11
17
|
const { NETLIFYDEVERR, chalk, error } = require('../../utils')
|
|
12
18
|
const { openBrowser } = require('../../utils/open-browser')
|
|
13
19
|
|
|
14
|
-
const {
|
|
20
|
+
const { createPersistedQuery, ensureAppForSite } = OneGraphCliClient
|
|
15
21
|
|
|
16
22
|
/**
|
|
17
23
|
* Creates the `netlify graph:edit` command
|
|
@@ -32,8 +38,6 @@ const graphEdit = async (options, command) => {
|
|
|
32
38
|
}
|
|
33
39
|
const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options })
|
|
34
40
|
|
|
35
|
-
const { branch } = gitRepoInfo()
|
|
36
|
-
|
|
37
41
|
let graphqlDocument = readGraphQLOperationsSourceFile(netlifyGraphConfig)
|
|
38
42
|
|
|
39
43
|
if (graphqlDocument.trim().length === 0) {
|
|
@@ -47,11 +51,12 @@ const graphEdit = async (options, command) => {
|
|
|
47
51
|
let oneGraphSessionId = loadCLISession(state)
|
|
48
52
|
if (!oneGraphSessionId) {
|
|
49
53
|
const sessionName = generateSessionName()
|
|
50
|
-
const oneGraphSession = await createCLISession(netlifyToken, site.id, sessionName,
|
|
54
|
+
const oneGraphSession = await createCLISession({ netlifyToken, siteId: site.id, sessionName, metadata: {} })
|
|
51
55
|
state.set('oneGraphSessionId', oneGraphSession.id)
|
|
52
56
|
oneGraphSessionId = state.get('oneGraphSessionId')
|
|
53
57
|
}
|
|
54
58
|
|
|
59
|
+
const { branch } = gitRepoInfo()
|
|
55
60
|
const persistedDoc = await createPersistedQuery(netlifyToken, {
|
|
56
61
|
appId: siteId,
|
|
57
62
|
description: 'Temporary snapshot of local queries',
|
|
@@ -59,7 +64,16 @@ const graphEdit = async (options, command) => {
|
|
|
59
64
|
tags: ['netlify-cli', `session:${oneGraphSessionId}`, `git-branch:${branch}`],
|
|
60
65
|
})
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
const newMetadata = { docId: persistedDoc.id }
|
|
68
|
+
|
|
69
|
+
await upsertMergeCLISessionMetadata({
|
|
70
|
+
netlifyGraphConfig,
|
|
71
|
+
netlifyToken,
|
|
72
|
+
siteId,
|
|
73
|
+
siteRoot: site.root,
|
|
74
|
+
oneGraphSessionId,
|
|
75
|
+
newMetadata,
|
|
76
|
+
})
|
|
63
77
|
|
|
64
78
|
const graphEditUrl = getGraphEditUrlBySiteId({ siteId, oneGraphSessionId })
|
|
65
79
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
+
const { createGraphConfigWriteCommand } = require('./graph-config-write')
|
|
2
3
|
const { createGraphEditCommand } = require('./graph-edit')
|
|
3
4
|
const { createGraphHandlerCommand } = require('./graph-handler')
|
|
4
5
|
const { createGraphLibraryCommand } = require('./graph-library')
|
|
@@ -20,6 +21,7 @@ const graph = (options, command) => {
|
|
|
20
21
|
* @returns
|
|
21
22
|
*/
|
|
22
23
|
const createGraphCommand = (program) => {
|
|
24
|
+
createGraphConfigWriteCommand(program)
|
|
23
25
|
createGraphEditCommand(program)
|
|
24
26
|
createGraphHandlerCommand(program)
|
|
25
27
|
createGraphLibraryCommand(program)
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
+
const process = require('process')
|
|
3
|
+
|
|
2
4
|
const jwtDecode = require('jwt-decode')
|
|
3
5
|
|
|
4
6
|
const {
|
|
@@ -6,7 +8,7 @@ const {
|
|
|
6
8
|
NETLIFYDEVERR,
|
|
7
9
|
NETLIFYDEVLOG,
|
|
8
10
|
error: errorExit,
|
|
9
|
-
|
|
11
|
+
generateNetlifyGraphJWT,
|
|
10
12
|
getInternalFunctionsDir,
|
|
11
13
|
log,
|
|
12
14
|
} = require('../../utils')
|
|
@@ -45,7 +47,51 @@ const buildClientContext = function (headers) {
|
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
const
|
|
50
|
+
const startPollingForAPIAuthentication = async function (options) {
|
|
51
|
+
const { api, command, config, site, siteInfo } = options
|
|
52
|
+
const frequency = 5000
|
|
53
|
+
|
|
54
|
+
const helper = async (maybeSiteData) => {
|
|
55
|
+
const siteData = await (maybeSiteData || api.getSite({ siteId: site.id }))
|
|
56
|
+
const authlifyTokenId = siteData && siteData.authlify_token_id
|
|
57
|
+
|
|
58
|
+
const existingAuthlifyTokenId = config && config.netlifyGraphConfig && config.netlifyGraphConfig.authlifyTokenId
|
|
59
|
+
if (authlifyTokenId && authlifyTokenId !== existingAuthlifyTokenId) {
|
|
60
|
+
const netlifyToken = await command.authenticate()
|
|
61
|
+
// Only inject the authlify config if a token ID exists. This prevents
|
|
62
|
+
// calling command.authenticate() (which opens a browser window) if the
|
|
63
|
+
// user hasn't enabled API Authentication
|
|
64
|
+
const netlifyGraphConfig = {
|
|
65
|
+
netlifyToken,
|
|
66
|
+
authlifyTokenId: siteData.authlify_token_id,
|
|
67
|
+
siteId: site.id,
|
|
68
|
+
}
|
|
69
|
+
config.netlifyGraphConfig = netlifyGraphConfig
|
|
70
|
+
|
|
71
|
+
const netlifyGraphJWT = generateNetlifyGraphJWT(netlifyGraphConfig)
|
|
72
|
+
|
|
73
|
+
if (netlifyGraphJWT != null) {
|
|
74
|
+
// XXX(anmonteiro): this name is deprecated. Delete after 3/31/2022
|
|
75
|
+
process.env.ONEGRAPH_AUTHLIFY_TOKEN = netlifyGraphJWT
|
|
76
|
+
process.env.NETLIFY_GRAPH_TOKEN = netlifyGraphJWT
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
delete config.authlify
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
setTimeout(helper, frequency)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
await helper(siteInfo)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const createHandler = function (options) {
|
|
89
|
+
const { config, functionsRegistry } = options
|
|
90
|
+
|
|
91
|
+
if (options.isGraphEnabled) {
|
|
92
|
+
startPollingForAPIAuthentication(options)
|
|
93
|
+
}
|
|
94
|
+
|
|
49
95
|
return async function handler(request, response) {
|
|
50
96
|
// handle proxies without path re-writes (http-servr)
|
|
51
97
|
const cleanPath = request.path.replace(/^\/.netlify\/(functions|builders)/, '')
|
|
@@ -107,8 +153,10 @@ const createHandler = function ({ config, functionsRegistry }) {
|
|
|
107
153
|
}
|
|
108
154
|
|
|
109
155
|
if (config && config.authlify && config.authlify.authlifyTokenId != null) {
|
|
110
|
-
|
|
111
|
-
|
|
156
|
+
// XXX(anmonteiro): this name is deprecated. Delete after 3/31/2022
|
|
157
|
+
const jwt = generateNetlifyGraphJWT(config.netlifyGraphConfig)
|
|
158
|
+
event.authlifyToken = jwt
|
|
159
|
+
event.netlifyGraphToken = jwt
|
|
112
160
|
}
|
|
113
161
|
|
|
114
162
|
const clientContext = buildClientContext(request.headers) || {}
|
|
@@ -160,14 +208,15 @@ const createHandler = function ({ config, functionsRegistry }) {
|
|
|
160
208
|
}
|
|
161
209
|
}
|
|
162
210
|
|
|
163
|
-
const getFunctionsServer = function (
|
|
211
|
+
const getFunctionsServer = function (options) {
|
|
212
|
+
const { buildersPrefix = '', functionsPrefix = '', functionsRegistry, siteUrl } = options
|
|
164
213
|
// performance optimization, load express on demand
|
|
165
214
|
// eslint-disable-next-line node/global-require
|
|
166
215
|
const express = require('express')
|
|
167
216
|
// eslint-disable-next-line node/global-require
|
|
168
217
|
const expressLogging = require('express-logging')
|
|
169
218
|
const app = express()
|
|
170
|
-
const functionHandler = createHandler(
|
|
219
|
+
const functionHandler = createHandler(options)
|
|
171
220
|
|
|
172
221
|
app.set('query parser', 'simple')
|
|
173
222
|
|
|
@@ -195,16 +244,8 @@ const getFunctionsServer = function ({ buildersPrefix, config, functionsPrefix,
|
|
|
195
244
|
return app
|
|
196
245
|
}
|
|
197
246
|
|
|
198
|
-
const startFunctionsServer = async ({
|
|
199
|
-
|
|
200
|
-
capabilities,
|
|
201
|
-
config,
|
|
202
|
-
functionsPrefix = '',
|
|
203
|
-
settings,
|
|
204
|
-
site,
|
|
205
|
-
siteUrl,
|
|
206
|
-
timeouts,
|
|
207
|
-
}) => {
|
|
247
|
+
const startFunctionsServer = async (options) => {
|
|
248
|
+
const { capabilities, config, settings, site, siteUrl, timeouts } = options
|
|
208
249
|
const internalFunctionsDir = await getInternalFunctionsDir({ base: site.root })
|
|
209
250
|
|
|
210
251
|
// The order of the function directories matters. Leftmost directories take
|
|
@@ -223,13 +264,7 @@ const startFunctionsServer = async ({
|
|
|
223
264
|
|
|
224
265
|
await functionsRegistry.scan(functionsDirectories)
|
|
225
266
|
|
|
226
|
-
const server = getFunctionsServer({
|
|
227
|
-
config,
|
|
228
|
-
functionsRegistry,
|
|
229
|
-
siteUrl,
|
|
230
|
-
functionsPrefix,
|
|
231
|
-
buildersPrefix,
|
|
232
|
-
})
|
|
267
|
+
const server = getFunctionsServer(Object.assign(options, { functionsRegistry }))
|
|
233
268
|
|
|
234
269
|
await startWebServer({ server, settings })
|
|
235
270
|
}
|
|
@@ -16,6 +16,7 @@ const { watchDebounced } = require('../functions/watcher')
|
|
|
16
16
|
const {
|
|
17
17
|
generateFunctionsFile,
|
|
18
18
|
generateHandlerByOperationId,
|
|
19
|
+
normalizeOperationsDoc,
|
|
19
20
|
readGraphQLOperationsSourceFile,
|
|
20
21
|
writeGraphQLOperationsSourceFile,
|
|
21
22
|
writeGraphQLSchemaFile,
|
|
@@ -23,7 +24,7 @@ const {
|
|
|
23
24
|
|
|
24
25
|
const { parse } = GraphQL
|
|
25
26
|
const { defaultExampleOperationsDoc, extractFunctionsFromOperationDoc } = NetlifyGraph
|
|
26
|
-
const {
|
|
27
|
+
const { createPersistedQuery, ensureAppForSite, updateCLISessionMetadata } = OneGraphClient
|
|
27
28
|
|
|
28
29
|
const internalConsole = {
|
|
29
30
|
log,
|
|
@@ -231,7 +232,8 @@ const updateGraphQLOperationsFileFromPersistedDoc = async (input) => {
|
|
|
231
232
|
return
|
|
232
233
|
}
|
|
233
234
|
|
|
234
|
-
|
|
235
|
+
// Sorts the operations stably, prepends the @netlify directive, etc.
|
|
236
|
+
const doc = normalizeOperationsDoc(persistedDoc.query)
|
|
235
237
|
|
|
236
238
|
writeGraphQLOperationsSourceFile(netlifyGraphConfig, doc)
|
|
237
239
|
regenerateFunctionsFileFromOperationsFile({ netlifyGraphConfig, schema })
|
|
@@ -282,9 +284,89 @@ const handleCliSessionEvent = async ({ event, netlifyGraphConfig, netlifyToken,
|
|
|
282
284
|
}
|
|
283
285
|
}
|
|
284
286
|
|
|
285
|
-
|
|
287
|
+
/**
|
|
288
|
+
*
|
|
289
|
+
* @param {object} input
|
|
290
|
+
* @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
|
|
291
|
+
* @param {string} input.oneGraphSessionId The id of the cli session to fetch the current metadata for
|
|
292
|
+
* @param {object} input.siteId The site object that contains the root file path for the site
|
|
293
|
+
*/
|
|
294
|
+
const getCLISession = async ({ netlifyToken, oneGraphSessionId, siteId }) => {
|
|
295
|
+
const input = {
|
|
296
|
+
appId: siteId,
|
|
297
|
+
sessionId: oneGraphSessionId,
|
|
298
|
+
authToken: netlifyToken,
|
|
299
|
+
desiredEventCount: 1,
|
|
300
|
+
}
|
|
301
|
+
return await OneGraphClient.fetchCliSession(input)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
*
|
|
306
|
+
* @param {object} input
|
|
307
|
+
* @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
|
|
308
|
+
* @param {string} input.oneGraphSessionId The id of the cli session to fetch the current metadata for
|
|
309
|
+
* @param {string} input.siteId The site object that contains the root file path for the site
|
|
310
|
+
*/
|
|
311
|
+
const getCLISessionMetadata = async ({ netlifyToken, oneGraphSessionId, siteId }) => {
|
|
312
|
+
const { errors, session } = await getCLISession({ netlifyToken, oneGraphSessionId, siteId })
|
|
313
|
+
return { metadata: session && session.metadata, errors }
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Look at the current project, filesystem, etc. and determine relevant metadata for a cli session
|
|
318
|
+
* @param {object} input
|
|
319
|
+
* @param {string} input.siteRoot The root file path for the site
|
|
320
|
+
* @returns {Record<string, any>} Any locally detected facts that are relevant to include in the cli session metadata
|
|
321
|
+
*/
|
|
322
|
+
const detectLocalCLISessionMetadata = ({ siteRoot }) => {
|
|
286
323
|
const { branch } = gitRepoInfo()
|
|
324
|
+
const hostname = os.hostname()
|
|
325
|
+
const userInfo = os.userInfo({ encoding: 'utf-8' })
|
|
326
|
+
const { username } = userInfo
|
|
327
|
+
|
|
328
|
+
const detectedMetadata = {
|
|
329
|
+
gitBranch: branch,
|
|
330
|
+
hostname,
|
|
331
|
+
username,
|
|
332
|
+
siteRoot,
|
|
333
|
+
}
|
|
287
334
|
|
|
335
|
+
return detectedMetadata
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Fetch the existing cli session metadata if it exists, and mutate it remotely with the passed in metadata
|
|
340
|
+
* @param {object} input
|
|
341
|
+
* @param {NetlifyGraph.NetlifyGraphConfig} input.netlifyGraphConfig The (typically netlify) access token that is used for authentication, if any
|
|
342
|
+
* @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
|
|
343
|
+
* @param {string} input.oneGraphSessionId The id of the cli session to fetch the current metadata for
|
|
344
|
+
* @param {string} input.siteId The site object that contains the root file path for the site
|
|
345
|
+
* @param {string} input.siteRoot The root file path for the site
|
|
346
|
+
* @param {object} input.newMetadata The metadata to merge into (with priority) the existing metadata
|
|
347
|
+
* @returns {Promise<object>}
|
|
348
|
+
*/
|
|
349
|
+
const upsertMergeCLISessionMetadata = async ({ netlifyToken, newMetadata, oneGraphSessionId, siteId, siteRoot }) => {
|
|
350
|
+
const { errors, metadata } = await getCLISessionMetadata({ netlifyToken, oneGraphSessionId, siteId })
|
|
351
|
+
if (errors) {
|
|
352
|
+
warn(`Error fetching cli session metadata: ${JSON.stringify(errors, null, 2)}`)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const detectedMetadata = detectLocalCLISessionMetadata({ siteRoot })
|
|
356
|
+
|
|
357
|
+
const finalMetadata = { ...metadata, ...detectedMetadata, ...newMetadata }
|
|
358
|
+
return OneGraphClient.updateCLISessionMetadata(netlifyToken, siteId, oneGraphSessionId, finalMetadata)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const persistNewOperationsDocForSession = async ({
|
|
362
|
+
netlifyGraphConfig,
|
|
363
|
+
netlifyToken,
|
|
364
|
+
oneGraphSessionId,
|
|
365
|
+
operationsDoc,
|
|
366
|
+
siteId,
|
|
367
|
+
siteRoot,
|
|
368
|
+
}) => {
|
|
369
|
+
const { branch } = gitRepoInfo()
|
|
288
370
|
const payload = {
|
|
289
371
|
appId: siteId,
|
|
290
372
|
description: 'Temporary snapshot of local queries',
|
|
@@ -293,13 +375,25 @@ const persistNewOperationsDocForSession = async ({ netlifyToken, oneGraphSession
|
|
|
293
375
|
}
|
|
294
376
|
const persistedDoc = await createPersistedQuery(netlifyToken, payload)
|
|
295
377
|
const newMetadata = await { docId: persistedDoc.id }
|
|
296
|
-
const result = await
|
|
378
|
+
const result = await upsertMergeCLISessionMetadata({
|
|
379
|
+
netlifyGraphConfig,
|
|
380
|
+
netlifyToken,
|
|
381
|
+
siteId,
|
|
382
|
+
oneGraphSessionId,
|
|
383
|
+
newMetadata,
|
|
384
|
+
siteRoot,
|
|
385
|
+
})
|
|
297
386
|
|
|
298
387
|
if (result.errors) {
|
|
299
388
|
warn(`Unable to update session metadata with updated operations doc ${JSON.stringify(result.errors, null, 2)}`)
|
|
300
389
|
}
|
|
301
390
|
}
|
|
302
391
|
|
|
392
|
+
const createCLISession = ({ metadata, netlifyToken, sessionName, siteId }) => {
|
|
393
|
+
const result = OneGraphClient.createCLISession(netlifyToken, siteId, sessionName, metadata)
|
|
394
|
+
return result
|
|
395
|
+
}
|
|
396
|
+
|
|
303
397
|
/**
|
|
304
398
|
* Load the CLI session id from the local state
|
|
305
399
|
* @param {StateConfig} state
|
|
@@ -322,7 +416,12 @@ const startOneGraphCLISession = async (input) => {
|
|
|
322
416
|
if (!oneGraphSessionId) {
|
|
323
417
|
const sessionName = generateSessionName()
|
|
324
418
|
const sessionMetadata = {}
|
|
325
|
-
const oneGraphSession = await
|
|
419
|
+
const oneGraphSession = await createCLISession({
|
|
420
|
+
netlifyToken,
|
|
421
|
+
siteId: site.id,
|
|
422
|
+
sessionName,
|
|
423
|
+
metadata: sessionMetadata,
|
|
424
|
+
})
|
|
326
425
|
state.set('oneGraphSessionId', oneGraphSession.id)
|
|
327
426
|
oneGraphSessionId = state.get('oneGraphSessionId')
|
|
328
427
|
}
|
|
@@ -337,10 +436,12 @@ const startOneGraphCLISession = async (input) => {
|
|
|
337
436
|
regenerateFunctionsFileFromOperationsFile({ netlifyGraphConfig, schema })
|
|
338
437
|
const newOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
|
|
339
438
|
await persistNewOperationsDocForSession({
|
|
439
|
+
netlifyGraphConfig,
|
|
340
440
|
netlifyToken,
|
|
341
441
|
oneGraphSessionId,
|
|
342
442
|
operationsDoc: newOperationsDoc,
|
|
343
443
|
siteId: site.id,
|
|
444
|
+
siteRoot: site.root,
|
|
344
445
|
})
|
|
345
446
|
},
|
|
346
447
|
onAdd: async (filePath) => {
|
|
@@ -348,10 +449,12 @@ const startOneGraphCLISession = async (input) => {
|
|
|
348
449
|
regenerateFunctionsFileFromOperationsFile({ netlifyGraphConfig, schema })
|
|
349
450
|
const newOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
|
|
350
451
|
await persistNewOperationsDocForSession({
|
|
452
|
+
netlifyGraphConfig,
|
|
351
453
|
netlifyToken,
|
|
352
454
|
oneGraphSessionId,
|
|
353
455
|
operationsDoc: newOperationsDoc,
|
|
354
456
|
siteId: site.id,
|
|
457
|
+
siteRoot: site.root,
|
|
355
458
|
})
|
|
356
459
|
},
|
|
357
460
|
})
|
|
@@ -393,7 +496,6 @@ const generateSessionName = () => {
|
|
|
393
496
|
|
|
394
497
|
const OneGraphCliClient = {
|
|
395
498
|
ackCLISessionEvents: OneGraphClient.ackCLISessionEvents,
|
|
396
|
-
createCLISession,
|
|
397
499
|
createPersistedQuery,
|
|
398
500
|
fetchCliSessionEvents: OneGraphClient.fetchCliSessionEvents,
|
|
399
501
|
ensureAppForSite,
|
|
@@ -402,6 +504,7 @@ const OneGraphCliClient = {
|
|
|
402
504
|
|
|
403
505
|
module.exports = {
|
|
404
506
|
OneGraphCliClient,
|
|
507
|
+
createCLISession,
|
|
405
508
|
extractFunctionsFromOperationDoc,
|
|
406
509
|
handleCliSessionEvent,
|
|
407
510
|
generateSessionName,
|
|
@@ -410,4 +513,5 @@ module.exports = {
|
|
|
410
513
|
persistNewOperationsDocForSession,
|
|
411
514
|
refetchAndGenerateFromOneGraph,
|
|
412
515
|
startOneGraphCLISession,
|
|
516
|
+
upsertMergeCLISessionMetadata,
|
|
413
517
|
}
|
|
@@ -3,7 +3,7 @@ const fs = require('fs')
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const process = require('process')
|
|
5
5
|
|
|
6
|
-
const { GraphQL, InternalConsole, NetlifyGraph } = require('netlify-onegraph-internal')
|
|
6
|
+
const { GraphQL, GraphQLHelpers, InternalConsole, NetlifyGraph } = require('netlify-onegraph-internal')
|
|
7
7
|
|
|
8
8
|
const { detectServerSettings, error, execa, getFunctionsDir, log, warn } = require('../../utils')
|
|
9
9
|
|
|
@@ -167,6 +167,8 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
|
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
const defaulFunctionsPath = ['netlify', 'functions']
|
|
171
|
+
|
|
170
172
|
const siteRoot = [path.sep, ...filterRelativePathItems(site.root.split(path.sep))]
|
|
171
173
|
|
|
172
174
|
const tsConfig = 'tsconfig.json'
|
|
@@ -178,7 +180,7 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
|
|
|
178
180
|
const detectedFunctionsPathString = getFunctionsDir({ config, options })
|
|
179
181
|
const detectedFunctionsPath = detectedFunctionsPathString
|
|
180
182
|
? [path.sep, ...detectedFunctionsPathString.split(path.sep)]
|
|
181
|
-
:
|
|
183
|
+
: defaulFunctionsPath
|
|
182
184
|
const baseConfig = { ...NetlifyGraph.defaultNetlifyGraphConfig, ...userSpecifiedConfig }
|
|
183
185
|
const defaultFrameworkConfig = makeDefaultFrameworkConfig({ baseConfig, detectedFunctionsPath, siteRoot })
|
|
184
186
|
|
|
@@ -202,6 +204,10 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
|
|
|
202
204
|
(userSpecifiedConfig.graphQLOperationsSourceFilename &&
|
|
203
205
|
userSpecifiedConfig.graphQLOperationsSourceFilename.split(path.sep)) ||
|
|
204
206
|
defaultFrameworkConfig.graphQLOperationsSourceFilename
|
|
207
|
+
const graphQLConfigJsonFilename =
|
|
208
|
+
(userSpecifiedConfig.graphQLConfigJsonFilename && userSpecifiedConfig.graphQLConfigJsonFilename.split(path.sep)) ||
|
|
209
|
+
defaultFrameworkConfig.graphQLConfigJsonFilename ||
|
|
210
|
+
baseConfig.graphQLConfigJsonFilename
|
|
205
211
|
const graphQLSchemaFilename =
|
|
206
212
|
(userSpecifiedConfig.graphQLSchemaFilename && userSpecifiedConfig.graphQLSchemaFilename.split(path.sep)) ||
|
|
207
213
|
defaultFrameworkConfig.graphQLSchemaFilename
|
|
@@ -229,6 +235,7 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
|
|
|
229
235
|
netlifyGraphTypeDefinitionsFilename,
|
|
230
236
|
graphQLOperationsSourceFilename,
|
|
231
237
|
graphQLSchemaFilename,
|
|
238
|
+
graphQLConfigJsonFilename,
|
|
232
239
|
netlifyGraphRequirePath,
|
|
233
240
|
framework,
|
|
234
241
|
language,
|
|
@@ -473,7 +480,7 @@ const { buildSchema, parse } = GraphQL
|
|
|
473
480
|
const getGraphEditUrlBySiteName = ({ oneGraphSessionId, siteName }) => {
|
|
474
481
|
const host = process.env.NETLIFY_APP_HOST || 'app.netlify.com'
|
|
475
482
|
// http because app.netlify.com will redirect to https, and localhost will still work for development
|
|
476
|
-
const url = `http://${host}/sites/${siteName}/graph/explorer
|
|
483
|
+
const url = `http://${host}/sites/app/${siteName}/graph/explorer/${oneGraphSessionId}`
|
|
477
484
|
|
|
478
485
|
return url
|
|
479
486
|
}
|
|
@@ -488,7 +495,7 @@ const getGraphEditUrlBySiteName = ({ oneGraphSessionId, siteName }) => {
|
|
|
488
495
|
const getGraphEditUrlBySiteId = ({ oneGraphSessionId, siteId }) => {
|
|
489
496
|
const host = process.env.NETLIFY_APP_HOST || 'app.netlify.com'
|
|
490
497
|
// http because app.netlify.com will redirect to https, and localhost will still work for development
|
|
491
|
-
const url = `http://${host}/site-redirect/${siteId}/graph/explorer
|
|
498
|
+
const url = `http://${host}/site-redirect/${siteId}/graph/explorer/${oneGraphSessionId}`
|
|
492
499
|
|
|
493
500
|
return url
|
|
494
501
|
}
|
|
@@ -505,6 +512,7 @@ module.exports = {
|
|
|
505
512
|
getGraphEditUrlBySiteId,
|
|
506
513
|
getGraphEditUrlBySiteName,
|
|
507
514
|
getNetlifyGraphConfig,
|
|
515
|
+
normalizeOperationsDoc: GraphQLHelpers.normalizeOperationsDoc,
|
|
508
516
|
parse,
|
|
509
517
|
readGraphQLOperationsSourceFile,
|
|
510
518
|
readGraphQLSchemaFile,
|
package/src/utils/dev.js
CHANGED
|
@@ -194,12 +194,12 @@ const acquirePort = async ({ configuredPort, defaultPort, errorMessage }) => {
|
|
|
194
194
|
return acquiredPort
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
// Generates
|
|
197
|
+
// Generates a Netlify Graph JWT with the following claims:
|
|
198
198
|
// - site_id
|
|
199
199
|
// - netlify_token -- the bearer token for the Netlify API
|
|
200
200
|
// - authlify_token_id -- the authlify token ID stored for the site after
|
|
201
201
|
// enabling API Authentication.
|
|
202
|
-
const
|
|
202
|
+
const generateNetlifyGraphJWT = ({ authlifyTokenId, netlifyToken, siteId }) => {
|
|
203
203
|
const claims = {
|
|
204
204
|
netlify_token: netlifyToken,
|
|
205
205
|
authlify_token_id: authlifyTokenId,
|
|
@@ -219,5 +219,5 @@ module.exports = {
|
|
|
219
219
|
getSiteInformation,
|
|
220
220
|
injectEnvVariables,
|
|
221
221
|
acquirePort,
|
|
222
|
-
|
|
222
|
+
generateNetlifyGraphJWT,
|
|
223
223
|
}
|