netlify-cli 9.4.4 → 9.5.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
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.5.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "netlify-cli",
|
|
9
|
-
"version": "9.
|
|
9
|
+
"version": "9.5.0",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"@netlify/framework-info": "^9.0.0",
|
|
16
16
|
"@netlify/local-functions-proxy": "^1.1.1",
|
|
17
17
|
"@netlify/plugin-edge-handlers": "^3.0.6",
|
|
18
|
-
"@netlify/plugins-list": "^6.
|
|
18
|
+
"@netlify/plugins-list": "^6.11.0",
|
|
19
19
|
"@netlify/routing-local-proxy": "^0.34.1",
|
|
20
20
|
"@netlify/zip-it-and-ship-it": "^5.7.5",
|
|
21
21
|
"@octokit/rest": "^18.0.0",
|
|
@@ -4132,9 +4132,9 @@
|
|
|
4132
4132
|
}
|
|
4133
4133
|
},
|
|
4134
4134
|
"node_modules/@netlify/plugins-list": {
|
|
4135
|
-
"version": "6.
|
|
4136
|
-
"resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.
|
|
4137
|
-
"integrity": "sha512-
|
|
4135
|
+
"version": "6.11.0",
|
|
4136
|
+
"resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.11.0.tgz",
|
|
4137
|
+
"integrity": "sha512-b6+htKVooVnUPbq2zlCPUcWJSvR18a20cl1W3MS3EThEbXM/CCQWcCEqjwk+Q5VCH2hoJoaHlLhO/lIHpwn8Ig==",
|
|
4138
4138
|
"engines": {
|
|
4139
4139
|
"node": "^12.20.0 || ^14.14.0 || >=16.0.0"
|
|
4140
4140
|
}
|
|
@@ -26586,9 +26586,9 @@
|
|
|
26586
26586
|
}
|
|
26587
26587
|
},
|
|
26588
26588
|
"@netlify/plugins-list": {
|
|
26589
|
-
"version": "6.
|
|
26590
|
-
"resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.
|
|
26591
|
-
"integrity": "sha512-
|
|
26589
|
+
"version": "6.11.0",
|
|
26590
|
+
"resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.11.0.tgz",
|
|
26591
|
+
"integrity": "sha512-b6+htKVooVnUPbq2zlCPUcWJSvR18a20cl1W3MS3EThEbXM/CCQWcCEqjwk+Q5VCH2hoJoaHlLhO/lIHpwn8Ig=="
|
|
26592
26592
|
},
|
|
26593
26593
|
"@netlify/routing-local-proxy": {
|
|
26594
26594
|
"version": "0.34.1",
|
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.
|
|
4
|
+
"version": "9.5.0",
|
|
5
5
|
"author": "Netlify Inc.",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"Abraham Schilling <AbrahamSchilling@gmail.com> (https://gitlab.com/n4bb12)",
|
|
@@ -204,7 +204,7 @@
|
|
|
204
204
|
"@netlify/framework-info": "^9.0.0",
|
|
205
205
|
"@netlify/local-functions-proxy": "^1.1.1",
|
|
206
206
|
"@netlify/plugin-edge-handlers": "^3.0.6",
|
|
207
|
-
"@netlify/plugins-list": "^6.
|
|
207
|
+
"@netlify/plugins-list": "^6.11.0",
|
|
208
208
|
"@netlify/routing-local-proxy": "^0.34.1",
|
|
209
209
|
"@netlify/zip-it-and-ship-it": "^5.7.5",
|
|
210
210
|
"@octokit/rest": "^18.0.0",
|
package/src/commands/dev/dev.js
CHANGED
|
@@ -14,6 +14,7 @@ const { startFunctionsServer } = require('../../lib/functions/server')
|
|
|
14
14
|
const {
|
|
15
15
|
OneGraphCliClient,
|
|
16
16
|
loadCLISession,
|
|
17
|
+
markCliSessionInactive,
|
|
17
18
|
persistNewOperationsDocForSession,
|
|
18
19
|
startOneGraphCLISession,
|
|
19
20
|
} = require('../../lib/one-graph/cli-client')
|
|
@@ -78,6 +79,30 @@ const isNonExistingCommandError = ({ command, error: commandError }) => {
|
|
|
78
79
|
)
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
/**
|
|
83
|
+
* @type {(() => Promise<void>)[]} - array of functions to run before the process exits
|
|
84
|
+
*/
|
|
85
|
+
const cleanupWork = []
|
|
86
|
+
|
|
87
|
+
let cleanupStarted = false
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param {object} input
|
|
91
|
+
* @param {number=} input.exitCode The exit code to return when exiting the process after cleanup
|
|
92
|
+
*/
|
|
93
|
+
const cleanupBeforeExit = async ({ exitCode }) => {
|
|
94
|
+
// If cleanup has started, then wherever started it will be responsible for exiting
|
|
95
|
+
if (!cleanupStarted) {
|
|
96
|
+
cleanupStarted = true
|
|
97
|
+
try {
|
|
98
|
+
// eslint-disable-next-line no-unused-vars
|
|
99
|
+
const cleanupFinished = await Promise.all(cleanupWork.map((cleanup) => cleanup()))
|
|
100
|
+
} finally {
|
|
101
|
+
process.exit(exitCode)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
81
106
|
/**
|
|
82
107
|
* Run a command and pipe stdout, stderr and stdin
|
|
83
108
|
* @param {string} command
|
|
@@ -100,30 +125,29 @@ const runCommand = (command, env = {}) => {
|
|
|
100
125
|
|
|
101
126
|
// we can't try->await->catch since we don't want to block on the framework server which
|
|
102
127
|
// is a long running process
|
|
103
|
-
// eslint-disable-next-line promise/catch-or-return
|
|
104
|
-
commandProcess
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
process.on(signal, () => {
|
|
124
|
-
commandProcess.kill('SIGTERM', { forceKillAfterTimeout: 500 })
|
|
125
|
-
process.exit()
|
|
128
|
+
// eslint-disable-next-line promise/catch-or-return
|
|
129
|
+
commandProcess
|
|
130
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
131
|
+
.then(async () => {
|
|
132
|
+
const result = await commandProcess
|
|
133
|
+
const [commandWithoutArgs] = command.split(' ')
|
|
134
|
+
if (result.failed && isNonExistingCommandError({ command: commandWithoutArgs, error: result })) {
|
|
135
|
+
log(
|
|
136
|
+
NETLIFYDEVERR,
|
|
137
|
+
`Failed running command: ${command}. Please verify ${chalk.magenta(`'${commandWithoutArgs}'`)} exists`,
|
|
138
|
+
)
|
|
139
|
+
} else {
|
|
140
|
+
const errorMessage = result.failed
|
|
141
|
+
? `${NETLIFYDEVERR} ${result.shortMessage}`
|
|
142
|
+
: `${NETLIFYDEVWARN} "${command}" exited with code ${result.exitCode}`
|
|
143
|
+
|
|
144
|
+
log(`${errorMessage}. Shutting down Netlify Dev server`)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return await cleanupBeforeExit({ exitCode: 1 })
|
|
126
148
|
})
|
|
149
|
+
;['SIGINT', 'SIGTERM', 'SIGQUIT', 'SIGHUP', 'exit'].forEach((signal) => {
|
|
150
|
+
process.on(signal, async () => await cleanupBeforeExit({}))
|
|
127
151
|
})
|
|
128
152
|
|
|
129
153
|
return commandProcess
|
|
@@ -336,12 +360,18 @@ const dev = async (options, command) => {
|
|
|
336
360
|
const oneGraphSessionId = loadCLISession(state)
|
|
337
361
|
|
|
338
362
|
await persistNewOperationsDocForSession({
|
|
363
|
+
netlifyGraphConfig,
|
|
339
364
|
netlifyToken,
|
|
340
365
|
oneGraphSessionId,
|
|
341
366
|
operationsDoc: graphqlDocument,
|
|
342
367
|
siteId: site.id,
|
|
368
|
+
siteRoot: site.root,
|
|
343
369
|
})
|
|
344
370
|
|
|
371
|
+
const cleanupSession = () => markCliSessionInactive({ netlifyToken, sessionId: oneGraphSessionId, siteId: site.id })
|
|
372
|
+
|
|
373
|
+
cleanupWork.push(cleanupSession)
|
|
374
|
+
|
|
345
375
|
const graphEditUrl = getGraphEditUrlBySiteId({ siteId: site.id, oneGraphSessionId })
|
|
346
376
|
|
|
347
377
|
log(
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
const gitRepoInfo = require('git-repo-info')
|
|
3
3
|
|
|
4
|
-
const {
|
|
5
|
-
OneGraphCliClient,
|
|
6
|
-
createCLISession,
|
|
7
|
-
generateSessionName,
|
|
8
|
-
loadCLISession,
|
|
9
|
-
upsertMergeCLISessionMetadata,
|
|
10
|
-
} = require('../../lib/one-graph/cli-client')
|
|
4
|
+
const { OneGraphCliClient, ensureCLISession, upsertMergeCLISessionMetadata } = require('../../lib/one-graph/cli-client')
|
|
11
5
|
const {
|
|
12
6
|
defaultExampleOperationsDoc,
|
|
13
7
|
getGraphEditUrlBySiteId,
|
|
@@ -48,13 +42,12 @@ const graphEdit = async (options, command) => {
|
|
|
48
42
|
|
|
49
43
|
await ensureAppForSite(netlifyToken, siteId)
|
|
50
44
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
state
|
|
56
|
-
|
|
57
|
-
}
|
|
45
|
+
const oneGraphSessionId = await ensureCLISession({
|
|
46
|
+
metadata: {},
|
|
47
|
+
netlifyToken,
|
|
48
|
+
site,
|
|
49
|
+
state,
|
|
50
|
+
})
|
|
58
51
|
|
|
59
52
|
const { branch } = gitRepoInfo()
|
|
60
53
|
const persistedDoc = await createPersistedQuery(netlifyToken, {
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
+
const inquirer = require('inquirer')
|
|
3
|
+
const { GraphQL } = require('netlify-onegraph-internal')
|
|
4
|
+
|
|
2
5
|
const {
|
|
3
6
|
buildSchema,
|
|
7
|
+
defaultExampleOperationsDoc,
|
|
8
|
+
extractFunctionsFromOperationDoc,
|
|
4
9
|
generateHandlerByOperationName,
|
|
5
10
|
getNetlifyGraphConfig,
|
|
11
|
+
readGraphQLOperationsSourceFile,
|
|
6
12
|
readGraphQLSchemaFile,
|
|
7
13
|
} = require('../../lib/one-graph/cli-netlify-graph')
|
|
8
14
|
const { error, log } = require('../../utils')
|
|
9
15
|
|
|
16
|
+
const { parse } = GraphQL
|
|
17
|
+
|
|
10
18
|
/**
|
|
11
19
|
* Creates the `netlify graph:handler` command
|
|
12
|
-
* @param {string}
|
|
20
|
+
* @param {string} userOperationName
|
|
13
21
|
* @param {import('commander').OptionValues} options
|
|
14
22
|
* @param {import('../base-command').BaseCommand} command
|
|
15
23
|
* @returns
|
|
16
24
|
*/
|
|
17
|
-
const graphHandler = async (
|
|
25
|
+
const graphHandler = async (userOperationName, options, command) => {
|
|
18
26
|
const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options })
|
|
19
27
|
|
|
20
28
|
const schemaString = readGraphQLSchemaFile(netlifyGraphConfig)
|
|
@@ -31,6 +39,64 @@ const graphHandler = async (operationName, options, command) => {
|
|
|
31
39
|
error(`Failed to parse Netlify GraphQL schema`)
|
|
32
40
|
}
|
|
33
41
|
|
|
42
|
+
let operationName
|
|
43
|
+
if (!userOperationName) {
|
|
44
|
+
try {
|
|
45
|
+
let currentOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
|
|
46
|
+
if (currentOperationsDoc.trim().length === 0) {
|
|
47
|
+
currentOperationsDoc = defaultExampleOperationsDoc
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const parsedDoc = parse(currentOperationsDoc)
|
|
51
|
+
const { functions } = extractFunctionsFromOperationDoc(parsedDoc)
|
|
52
|
+
|
|
53
|
+
const sorted = Object.values(functions).sort((aItem, bItem) =>
|
|
54
|
+
aItem.operationName.localeCompare(bItem.operationName),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
const perPage = 50
|
|
58
|
+
|
|
59
|
+
const allOperationChoices = sorted.map((operation) => ({
|
|
60
|
+
name: `${operation.operationName} (${operation.kind})`,
|
|
61
|
+
value: operation.operationName,
|
|
62
|
+
}))
|
|
63
|
+
|
|
64
|
+
const filterOperationNames = (operationChoices, input) =>
|
|
65
|
+
operationChoices.filter((operation) => operation.value.toLowerCase().match(input.toLowerCase()))
|
|
66
|
+
|
|
67
|
+
// eslint-disable-next-line node/global-require
|
|
68
|
+
const inquirerAutocompletePrompt = require('inquirer-autocomplete-prompt')
|
|
69
|
+
/** multiple matching detectors, make the user choose */
|
|
70
|
+
inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt)
|
|
71
|
+
|
|
72
|
+
const { selectedOperationName } = await inquirer.prompt({
|
|
73
|
+
name: 'selectedOperationName',
|
|
74
|
+
message: `For which operation would you like to generate a handler?`,
|
|
75
|
+
type: 'autocomplete',
|
|
76
|
+
pageSize: perPage,
|
|
77
|
+
source(_, input) {
|
|
78
|
+
if (!input || input === '') {
|
|
79
|
+
return allOperationChoices
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const filteredChoices = filterOperationNames(allOperationChoices, input)
|
|
83
|
+
// only show filtered results
|
|
84
|
+
return filteredChoices
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
if (selectedOperationName) {
|
|
89
|
+
operationName = selectedOperationName
|
|
90
|
+
}
|
|
91
|
+
} catch (parseError) {
|
|
92
|
+
parseError(`Error parsing operations library: ${parseError}`)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!operationName) {
|
|
97
|
+
error(`No operation name provided`)
|
|
98
|
+
}
|
|
99
|
+
|
|
34
100
|
generateHandlerByOperationName({ logger: log, netlifyGraphConfig, schema, operationName, handlerOptions: {} })
|
|
35
101
|
}
|
|
36
102
|
|
|
@@ -42,7 +108,7 @@ const graphHandler = async (operationName, options, command) => {
|
|
|
42
108
|
const createGraphHandlerCommand = (program) =>
|
|
43
109
|
program
|
|
44
110
|
.command('graph:handler')
|
|
45
|
-
.argument('
|
|
111
|
+
.argument('[name]', 'Operation name')
|
|
46
112
|
.description(
|
|
47
113
|
'Generate a handler for a Graph operation given its name. See `graph:operations` for a list of operations.',
|
|
48
114
|
)
|
|
@@ -24,7 +24,13 @@ const {
|
|
|
24
24
|
|
|
25
25
|
const { parse } = GraphQL
|
|
26
26
|
const { defaultExampleOperationsDoc, extractFunctionsFromOperationDoc } = NetlifyGraph
|
|
27
|
-
const {
|
|
27
|
+
const {
|
|
28
|
+
createPersistedQuery,
|
|
29
|
+
ensureAppForSite,
|
|
30
|
+
executeMarkCliSessionActiveHeartbeat,
|
|
31
|
+
executeMarkCliSessionInactive,
|
|
32
|
+
updateCLISessionMetadata,
|
|
33
|
+
} = OneGraphClient
|
|
28
34
|
|
|
29
35
|
const internalConsole = {
|
|
30
36
|
log,
|
|
@@ -51,13 +57,31 @@ InternalConsole.registerConsole(internalConsole)
|
|
|
51
57
|
* @param {function} input.onEvents A function to call when CLI events are received and need to be processed
|
|
52
58
|
* @param {string} input.sessionId The session id to monitor CLI events for
|
|
53
59
|
* @param {StateConfig} input.state A function to call to set/get the current state of the local Netlify project
|
|
60
|
+
* @param {any} input.site The site object
|
|
54
61
|
* @returns
|
|
55
62
|
*/
|
|
56
63
|
const monitorCLISessionEvents = (input) => {
|
|
57
|
-
const { appId, netlifyGraphConfig, netlifyToken, onClose, onError, onEvents, sessionId, state } = input
|
|
64
|
+
const { appId, netlifyGraphConfig, netlifyToken, onClose, onError, onEvents, sessionId, site, state } = input
|
|
58
65
|
|
|
59
66
|
const frequency = 5000
|
|
67
|
+
// 30 minutes
|
|
68
|
+
const defaultHeartbeatFrequency = 1_800_000
|
|
60
69
|
let shouldClose = false
|
|
70
|
+
let nextMarkActiveHeartbeat = defaultHeartbeatFrequency
|
|
71
|
+
|
|
72
|
+
const markActiveHelper = async () => {
|
|
73
|
+
const fullSession = await OneGraphClient.fetchCliSession({ authToken: netlifyToken, appId, sessionId })
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
const heartbeatIntervalms = fullSession.session.cliHeartbeatIntervalMs || defaultHeartbeatFrequency
|
|
76
|
+
nextMarkActiveHeartbeat = heartbeatIntervalms
|
|
77
|
+
const markCLISessionActiveResult = await executeMarkCliSessionActiveHeartbeat(netlifyToken, site.id, sessionId)
|
|
78
|
+
if (markCLISessionActiveResult.errors && markCLISessionActiveResult.errors.length !== 0) {
|
|
79
|
+
warn(`Failed to mark CLI session active: ${markCLISessionActiveResult.errors.join(', ')}`)
|
|
80
|
+
}
|
|
81
|
+
setTimeout(markActiveHelper, nextMarkActiveHeartbeat)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
setTimeout(markActiveHelper, nextMarkActiveHeartbeat)
|
|
61
85
|
|
|
62
86
|
const enabledServiceWatcher = async (innerNetlifyToken, siteId) => {
|
|
63
87
|
const enabledServices = state.get('oneGraphEnabledServices') || ['onegraph']
|
|
@@ -371,6 +395,7 @@ const upsertMergeCLISessionMetadata = async ({ netlifyToken, newMetadata, oneGra
|
|
|
371
395
|
|
|
372
396
|
const detectedMetadata = detectLocalCLISessionMetadata({ siteRoot })
|
|
373
397
|
|
|
398
|
+
// @ts-ignore
|
|
374
399
|
const finalMetadata = { ...metadata, ...detectedMetadata, ...newMetadata }
|
|
375
400
|
return OneGraphClient.updateCLISessionMetadata(netlifyToken, siteId, oneGraphSessionId, finalMetadata)
|
|
376
401
|
}
|
|
@@ -429,19 +454,13 @@ const loadCLISession = (state) => state.get('oneGraphSessionId')
|
|
|
429
454
|
const startOneGraphCLISession = async (input) => {
|
|
430
455
|
const { netlifyGraphConfig, netlifyToken, site, state } = input
|
|
431
456
|
OneGraphClient.ensureAppForSite(netlifyToken, site.id)
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
sessionName,
|
|
440
|
-
metadata: sessionMetadata,
|
|
441
|
-
})
|
|
442
|
-
state.set('oneGraphSessionId', oneGraphSession.id)
|
|
443
|
-
oneGraphSessionId = state.get('oneGraphSessionId')
|
|
444
|
-
}
|
|
457
|
+
|
|
458
|
+
const oneGraphSessionId = await ensureCLISession({
|
|
459
|
+
metadata: {},
|
|
460
|
+
netlifyToken,
|
|
461
|
+
site,
|
|
462
|
+
state,
|
|
463
|
+
})
|
|
445
464
|
|
|
446
465
|
const enabledServices = []
|
|
447
466
|
const schema = await OneGraphClient.fetchOneGraphSchema(site.id, enabledServices)
|
|
@@ -481,6 +500,7 @@ const startOneGraphCLISession = async (input) => {
|
|
|
481
500
|
netlifyToken,
|
|
482
501
|
netlifyGraphConfig,
|
|
483
502
|
sessionId: oneGraphSessionId,
|
|
503
|
+
site,
|
|
484
504
|
state,
|
|
485
505
|
onEvents: async (events) => {
|
|
486
506
|
for (const event of events) {
|
|
@@ -500,6 +520,20 @@ const startOneGraphCLISession = async (input) => {
|
|
|
500
520
|
})
|
|
501
521
|
}
|
|
502
522
|
|
|
523
|
+
/**
|
|
524
|
+
* Mark a session as inactive so it doesn't show up in any UI lists, and potentially becomes available to GC later
|
|
525
|
+
* @param {object} input
|
|
526
|
+
* @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
|
|
527
|
+
* @param {string} input.siteId A function to call to set/get the current state of the local Netlify project
|
|
528
|
+
* @param {string} input.sessionId The session id to monitor CLI events for
|
|
529
|
+
*/
|
|
530
|
+
const markCliSessionInactive = async ({ netlifyToken, sessionId, siteId }) => {
|
|
531
|
+
const result = await executeMarkCliSessionInactive(netlifyToken, siteId, sessionId)
|
|
532
|
+
if (result.errors) {
|
|
533
|
+
warn(`Unable to mark CLI session ${sessionId} inactive: ${JSON.stringify(result.errors, null, 2)}`)
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
503
537
|
/**
|
|
504
538
|
* Generate a session name that can be identified as belonging to the current checkout
|
|
505
539
|
* @returns {string} The name of the session to create
|
|
@@ -511,6 +545,70 @@ const generateSessionName = () => {
|
|
|
511
545
|
return sessionName
|
|
512
546
|
}
|
|
513
547
|
|
|
548
|
+
/**
|
|
549
|
+
* Ensures a cli session exists for the current checkout, or errors out if it doesn't and cannot create one.
|
|
550
|
+
*/
|
|
551
|
+
const ensureCLISession = async ({ metadata, netlifyToken, site, state }) => {
|
|
552
|
+
let oneGraphSessionId = loadCLISession(state)
|
|
553
|
+
let parentCliSessionId = null
|
|
554
|
+
|
|
555
|
+
// Validate that session still exists and we can access it
|
|
556
|
+
try {
|
|
557
|
+
if (oneGraphSessionId) {
|
|
558
|
+
const sessionEvents = await OneGraphClient.fetchCliSessionEvents({
|
|
559
|
+
appId: site.id,
|
|
560
|
+
authToken: netlifyToken,
|
|
561
|
+
sessionId: oneGraphSessionId,
|
|
562
|
+
})
|
|
563
|
+
if (sessionEvents.errors) {
|
|
564
|
+
warn(`Unable to fetch cli session: ${JSON.stringify(sessionEvents.errors, null, 2)}`)
|
|
565
|
+
log(`Creating new cli session`)
|
|
566
|
+
parentCliSessionId = oneGraphSessionId
|
|
567
|
+
oneGraphSessionId = null
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
} catch (fetchSessionError) {
|
|
571
|
+
warn(`Unable to fetch cli session events: ${JSON.stringify(fetchSessionError, null, 2)}`)
|
|
572
|
+
oneGraphSessionId = null
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (!oneGraphSessionId) {
|
|
576
|
+
// If we can't access the session in the state.json or it doesn't exist, create a new one
|
|
577
|
+
const sessionName = generateSessionName()
|
|
578
|
+
const detectedMetadata = detectLocalCLISessionMetadata({ siteRoot: site.root })
|
|
579
|
+
const newSessionMetadata = parentCliSessionId ? { parentCliSessionId } : {}
|
|
580
|
+
const sessionMetadata = {
|
|
581
|
+
...detectedMetadata,
|
|
582
|
+
...newSessionMetadata,
|
|
583
|
+
...metadata,
|
|
584
|
+
}
|
|
585
|
+
const oneGraphSession = await createCLISession({
|
|
586
|
+
netlifyToken,
|
|
587
|
+
siteId: site.id,
|
|
588
|
+
sessionName,
|
|
589
|
+
metadata: sessionMetadata,
|
|
590
|
+
})
|
|
591
|
+
state.set('oneGraphSessionId', oneGraphSession.id)
|
|
592
|
+
oneGraphSessionId = state.get('oneGraphSessionId')
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (!oneGraphSessionId) {
|
|
596
|
+
error('Unable to create or access Netlify Graph CLI session')
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const { errors: markCLISessionActiveErrors } = await executeMarkCliSessionActiveHeartbeat(
|
|
600
|
+
netlifyToken,
|
|
601
|
+
site.id,
|
|
602
|
+
oneGraphSessionId,
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
if (markCLISessionActiveErrors) {
|
|
606
|
+
warn(`Unable to mark cli session active: ${JSON.stringify(markCLISessionActiveErrors, null, 2)}`)
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return oneGraphSessionId
|
|
610
|
+
}
|
|
611
|
+
|
|
514
612
|
const OneGraphCliClient = {
|
|
515
613
|
ackCLISessionEvents: OneGraphClient.ackCLISessionEvents,
|
|
516
614
|
createPersistedQuery,
|
|
@@ -522,10 +620,12 @@ const OneGraphCliClient = {
|
|
|
522
620
|
module.exports = {
|
|
523
621
|
OneGraphCliClient,
|
|
524
622
|
createCLISession,
|
|
623
|
+
ensureCLISession,
|
|
525
624
|
extractFunctionsFromOperationDoc,
|
|
526
625
|
handleCliSessionEvent,
|
|
527
626
|
generateSessionName,
|
|
528
627
|
loadCLISession,
|
|
628
|
+
markCliSessionInactive,
|
|
529
629
|
monitorCLISessionEvents,
|
|
530
630
|
persistNewOperationsDocForSession,
|
|
531
631
|
refetchAndGenerateFromOneGraph,
|