netlify-cli 9.2.0 → 9.4.2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "9.2.0",
4
+ "version": "9.4.2",
5
5
  "author": "Netlify Inc.",
6
6
  "contributors": [
7
7
  "Abraham Schilling <AbrahamSchilling@gmail.com> (https://gitlab.com/n4bb12)",
@@ -116,6 +116,7 @@
116
116
  "Tim Trautman (timtrautman.com)",
117
117
  "Tom Dyson (https://wagtail.io/)",
118
118
  "Travis Horn <travis@travishorn.com> (https://twitter.com/horn_travis)",
119
+ "Try Ajitiono <ballinst@gmail.com> (https://twitter.com/Ajiballinst)",
119
120
  "Victor Dadfar",
120
121
  "Wayne (https://twitter.com/waynehoover_)",
121
122
  "XhmikosR <xhmikosr@gmail.com> (https://twitter.com/xhmikosr)",
@@ -164,7 +165,6 @@
164
165
  "url": "https://github.com/netlify/cli/issues"
165
166
  },
166
167
  "scripts": {
167
- "snap": "ava --verbose -u tests/integration/**/*graph*.test.js",
168
168
  "prepare": "husky install node_modules/@netlify/eslint-config-node/.husky/",
169
169
  "start": "node ./bin/run",
170
170
  "test": "run-s format test:dev",
@@ -199,12 +199,12 @@
199
199
  "prettier": "--ignore-path .gitignore --loglevel=warn \"{src,tools,scripts,site,tests,.github}/**/*.{mjs,cjs,js,md,yml,json,html}\" \"*.{mjs,cjs,js,yml,json,html}\" \".*.{mjs,cjs,js,yml,json,html}\" \"!CHANGELOG.md\" \"!npm-shrinkwrap.json\" \"!site/package-lock.json\" \"!.github/**/*.md\""
200
200
  },
201
201
  "dependencies": {
202
- "@netlify/build": "^26.2.6",
203
- "@netlify/config": "^17.0.7",
202
+ "@netlify/build": "^26.3.1",
203
+ "@netlify/config": "^17.0.8",
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.10.1",
207
+ "@netlify/plugins-list": "^6.10.2",
208
208
  "@netlify/routing-local-proxy": "^0.34.1",
209
209
  "@netlify/zip-it-and-ship-it": "^5.7.4",
210
210
  "@octokit/rest": "^18.0.0",
@@ -271,7 +271,7 @@
271
271
  "multiparty": "^4.2.1",
272
272
  "netlify": "^11.0.0",
273
273
  "netlify-headers-parser": "^6.0.1",
274
- "netlify-onegraph-internal": "0.0.39",
274
+ "netlify-onegraph-internal": "0.0.50",
275
275
  "netlify-redirect-parser": "^13.0.2",
276
276
  "netlify-redirector": "^0.2.1",
277
277
  "node-fetch": "^2.6.0",
@@ -1,9 +1,10 @@
1
1
  // @ts-check
2
2
  const fs = require('fs')
3
3
  const path = require('path')
4
+ const process = require('process')
4
5
 
5
6
  const { getNetlifyGraphConfig } = require('../../lib/one-graph/cli-netlify-graph')
6
- const { NETLIFYDEVERR, chalk, error } = require('../../utils')
7
+ const { NETLIFYDEVERR, chalk, error, log } = require('../../utils')
7
8
 
8
9
  /**
9
10
  * Creates the `netlify graph:config:write` command
@@ -33,8 +34,10 @@ const graphConfigWrite = async (options, command) => {
33
34
  }
34
35
 
35
36
  const filePath = path.resolve(...netlifyGraphConfig.graphQLConfigJsonFilename)
36
-
37
37
  fs.writeFileSync(filePath, JSON.stringify(graphQLConfig, null, 2))
38
+
39
+ const relativePath = path.relative(process.cwd(), filePath)
40
+ log(`Wrote ${chalk.cyan(relativePath)}`)
38
41
  }
39
42
 
40
43
  /**
@@ -1,17 +1,23 @@
1
1
  // @ts-check
2
2
  const gitRepoInfo = require('git-repo-info')
3
3
 
4
- const { OneGraphCliClient, generateSessionName, loadCLISession } = require('../../lib/one-graph/cli-client')
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,
8
14
  getNetlifyGraphConfig,
9
15
  readGraphQLOperationsSourceFile,
10
16
  } = require('../../lib/one-graph/cli-netlify-graph')
11
- const { NETLIFYDEVERR, chalk, error } = require('../../utils')
17
+ const { NETLIFYDEVERR, chalk, error, log } = require('../../utils')
12
18
  const { openBrowser } = require('../../utils/open-browser')
13
19
 
14
- const { createCLISession, createPersistedQuery, ensureAppForSite, updateCLISessionMetadata } = OneGraphCliClient
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, null)
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,10 +64,20 @@ const graphEdit = async (options, command) => {
59
64
  tags: ['netlify-cli', `session:${oneGraphSessionId}`, `git-branch:${branch}`],
60
65
  })
61
66
 
62
- await updateCLISessionMetadata(netlifyToken, siteId, oneGraphSessionId, { docId: persistedDoc.id })
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
 
80
+ log(`Opening graph:edit session at ${chalk.cyan(graphEditUrl)}`)
66
81
  await openBrowser({ url: graphEditUrl })
67
82
  }
68
83
 
@@ -5,7 +5,7 @@ const {
5
5
  getNetlifyGraphConfig,
6
6
  readGraphQLSchemaFile,
7
7
  } = require('../../lib/one-graph/cli-netlify-graph')
8
- const { error } = require('../../utils')
8
+ const { error, log } = require('../../utils')
9
9
 
10
10
  /**
11
11
  * Creates the `netlify graph:handler` command
@@ -31,7 +31,7 @@ const graphHandler = async (operationName, options, command) => {
31
31
  error(`Failed to parse Netlify GraphQL schema`)
32
32
  }
33
33
 
34
- generateHandlerByOperationName(netlifyGraphConfig, schema, operationName, {})
34
+ generateHandlerByOperationName({ logger: log, netlifyGraphConfig, schema, operationName, handlerOptions: {} })
35
35
  }
36
36
 
37
37
  /**
@@ -9,7 +9,7 @@ const {
9
9
  readGraphQLOperationsSourceFile,
10
10
  readGraphQLSchemaFile,
11
11
  } = require('../../lib/one-graph/cli-netlify-graph')
12
- const { error } = require('../../utils')
12
+ const { error, log } = require('../../utils')
13
13
 
14
14
  /**
15
15
  * Creates the `netlify graph:library` command
@@ -42,7 +42,14 @@ const graphLibrary = async (options, command) => {
42
42
  const parsedDoc = parse(currentOperationsDoc)
43
43
  const { fragments, functions } = extractFunctionsFromOperationDoc(parsedDoc)
44
44
 
45
- generateFunctionsFile({ netlifyGraphConfig, schema, operationsDoc: currentOperationsDoc, functions, fragments })
45
+ generateFunctionsFile({
46
+ logger: log,
47
+ netlifyGraphConfig,
48
+ schema,
49
+ operationsDoc: currentOperationsDoc,
50
+ functions,
51
+ fragments,
52
+ })
46
53
  }
47
54
 
48
55
  /**
@@ -8,7 +8,7 @@ const {
8
8
  refetchAndGenerateFromOneGraph,
9
9
  } = require('../../lib/one-graph/cli-client')
10
10
  const { buildSchema, getNetlifyGraphConfig, readGraphQLSchemaFile } = require('../../lib/one-graph/cli-netlify-graph')
11
- const { chalk, error, warn } = require('../../utils')
11
+ const { chalk, error, log, warn } = require('../../utils')
12
12
 
13
13
  /**
14
14
  * Creates the `netlify graph:pull` command
@@ -31,12 +31,14 @@ const graphPull = async (options, command) => {
31
31
  const netlifyToken = await command.authenticate()
32
32
  const siteId = site.id
33
33
 
34
- await refetchAndGenerateFromOneGraph({ netlifyGraphConfig, netlifyToken, state, siteId })
34
+ await refetchAndGenerateFromOneGraph({ logger: log, netlifyGraphConfig, netlifyToken, state, siteId })
35
35
 
36
36
  const oneGraphSessionId = loadCLISession(state)
37
37
 
38
38
  if (!oneGraphSessionId) {
39
- warn('No local Netlify Graph session found, skipping command queue drain')
39
+ warn(
40
+ 'No local Netlify Graph session found, skipping command queue drain. Create a new session by running `netlify graph:edit`.',
41
+ )
40
42
  return
41
43
  }
42
44
 
@@ -15,7 +15,7 @@
15
15
  "author": "Netlify",
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
- "axios": "^0.25.0",
18
+ "axios": "^0.26.0",
19
19
  "bad-words": "^3.0.3"
20
20
  }
21
21
  }
@@ -9,16 +9,16 @@
9
9
  "version": "1.0.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "axios": "^0.25.0",
12
+ "axios": "^0.26.0",
13
13
  "qs": "^6.7.0"
14
14
  }
15
15
  },
16
16
  "node_modules/axios": {
17
- "version": "0.25.0",
18
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
19
- "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
17
+ "version": "0.26.0",
18
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz",
19
+ "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==",
20
20
  "dependencies": {
21
- "follow-redirects": "^1.14.7"
21
+ "follow-redirects": "^1.14.8"
22
22
  }
23
23
  },
24
24
  "node_modules/call-bind": {
@@ -34,9 +34,9 @@
34
34
  }
35
35
  },
36
36
  "node_modules/follow-redirects": {
37
- "version": "1.14.7",
38
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
39
- "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
37
+ "version": "1.14.8",
38
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
39
+ "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
40
40
  "funding": [
41
41
  {
42
42
  "type": "individual",
@@ -130,11 +130,11 @@
130
130
  },
131
131
  "dependencies": {
132
132
  "axios": {
133
- "version": "0.25.0",
134
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
135
- "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
133
+ "version": "0.26.0",
134
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz",
135
+ "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==",
136
136
  "requires": {
137
- "follow-redirects": "^1.14.7"
137
+ "follow-redirects": "^1.14.8"
138
138
  }
139
139
  },
140
140
  "call-bind": {
@@ -147,9 +147,9 @@
147
147
  }
148
148
  },
149
149
  "follow-redirects": {
150
- "version": "1.14.7",
151
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
152
- "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ=="
150
+ "version": "1.14.8",
151
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
152
+ "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
153
153
  },
154
154
  "function-bind": {
155
155
  "version": "1.1.1",
@@ -15,7 +15,7 @@
15
15
  "author": "Netlify",
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
- "axios": "^0.25.0",
18
+ "axios": "^0.26.0",
19
19
  "qs": "^6.7.0"
20
20
  }
21
21
  }
@@ -10,7 +10,7 @@
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@netlify/functions": "^0.11.0",
13
- "@types/node": "^14.18.10",
13
+ "@types/node": "^14.18.11",
14
14
  "typescript": "^4.0.0"
15
15
  }
16
16
  },
@@ -26,9 +26,9 @@
26
26
  }
27
27
  },
28
28
  "node_modules/@types/node": {
29
- "version": "14.18.10",
30
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.10.tgz",
31
- "integrity": "sha512-6iihJ/Pp5fsFJ/aEDGyvT4pHGmCpq7ToQ/yf4bl5SbVAvwpspYJ+v3jO7n8UyjhQVHTy+KNszOozDdv+O6sovQ=="
29
+ "version": "14.18.11",
30
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.11.tgz",
31
+ "integrity": "sha512-zCoCEMA+IPpsRkyCFBqew5vGb7r8RSiB3uwdu/map7uwLAfu1MTazW26/pUDWoNnF88vJz4W3U56i5gtXNqxGg=="
32
32
  },
33
33
  "node_modules/is-promise": {
34
34
  "version": "4.0.0",
@@ -58,9 +58,9 @@
58
58
  }
59
59
  },
60
60
  "@types/node": {
61
- "version": "14.18.10",
62
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.10.tgz",
63
- "integrity": "sha512-6iihJ/Pp5fsFJ/aEDGyvT4pHGmCpq7ToQ/yf4bl5SbVAvwpspYJ+v3jO7n8UyjhQVHTy+KNszOozDdv+O6sovQ=="
61
+ "version": "14.18.11",
62
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.11.tgz",
63
+ "integrity": "sha512-zCoCEMA+IPpsRkyCFBqew5vGb7r8RSiB3uwdu/map7uwLAfu1MTazW26/pUDWoNnF88vJz4W3U56i5gtXNqxGg=="
64
64
  },
65
65
  "is-promise": {
66
66
  "version": "4.0.0",
@@ -10,7 +10,7 @@ const { GraphQL, InternalConsole, OneGraphClient } = require('netlify-onegraph-i
10
10
  const { NetlifyGraph } = require('netlify-onegraph-internal')
11
11
 
12
12
  // eslint-disable-next-line no-unused-vars
13
- const { StateConfig, chalk, error, log, warn } = require('../../utils')
13
+ const { StateConfig, USER_AGENT, chalk, error, log, warn } = require('../../utils')
14
14
  const { watchDebounced } = require('../functions/watcher')
15
15
 
16
16
  const {
@@ -24,7 +24,7 @@ const {
24
24
 
25
25
  const { parse } = GraphQL
26
26
  const { defaultExampleOperationsDoc, extractFunctionsFromOperationDoc } = NetlifyGraph
27
- const { createCLISession, createPersistedQuery, ensureAppForSite, updateCLISessionMetadata } = OneGraphClient
27
+ const { createPersistedQuery, ensureAppForSite, updateCLISessionMetadata } = OneGraphClient
28
28
 
29
29
  const internalConsole = {
30
30
  log,
@@ -147,10 +147,11 @@ const monitorOperationFile = async ({ netlifyGraphConfig, onAdd, onChange, onUnl
147
147
  * @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
148
148
  * @param {NetlifyGraph.NetlifyGraphConfig} input.netlifyGraphConfig A standalone config object that contains all the information necessary for Netlify Graph to process events
149
149
  * @param {StateConfig} input.state A function to call to set/get the current state of the local Netlify project
150
+ * @param {(message: string) => void=} input.logger A function that if provided will be used to log messages
150
151
  * @returns {Promise<void>}
151
152
  */
152
153
  const refetchAndGenerateFromOneGraph = async (input) => {
153
- const { netlifyGraphConfig, netlifyToken, siteId, state } = input
154
+ const { logger, netlifyGraphConfig, netlifyToken, siteId, state } = input
154
155
  await OneGraphClient.ensureAppForSite(netlifyToken, siteId)
155
156
 
156
157
  const enabledServicesInfo = await OneGraphClient.fetchEnabledServices(netlifyToken, siteId)
@@ -162,6 +163,7 @@ const refetchAndGenerateFromOneGraph = async (input) => {
162
163
  const enabledServices = enabledServicesInfo
163
164
  .map((service) => service.service)
164
165
  .sort((aString, bString) => aString.localeCompare(bString))
166
+
165
167
  const schema = await OneGraphClient.fetchOneGraphSchema(siteId, enabledServices)
166
168
 
167
169
  let currentOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
@@ -172,8 +174,15 @@ const refetchAndGenerateFromOneGraph = async (input) => {
172
174
  const parsedDoc = parse(currentOperationsDoc)
173
175
  const { fragments, functions } = extractFunctionsFromOperationDoc(parsedDoc)
174
176
 
175
- generateFunctionsFile({ netlifyGraphConfig, schema, operationsDoc: currentOperationsDoc, functions, fragments })
176
- writeGraphQLSchemaFile(netlifyGraphConfig, schema)
177
+ generateFunctionsFile({
178
+ logger,
179
+ netlifyGraphConfig,
180
+ schema,
181
+ operationsDoc: currentOperationsDoc,
182
+ functions,
183
+ fragments,
184
+ })
185
+ writeGraphQLSchemaFile({ logger, netlifyGraphConfig, schema })
177
186
  state.set('oneGraphEnabledServices', enabledServices)
178
187
  }
179
188
 
@@ -220,12 +229,13 @@ const quickHash = (input) => {
220
229
  * @param {string} input.siteId The site id to query against
221
230
  * @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
222
231
  * @param {string} input.docId The GraphQL operations document id to fetch
232
+ * @param {(message: string) => void=} input.logger A function that if provided will be used to log messages
223
233
  * @param {GraphQL.GraphQLSchema} input.schema The GraphQL schema to use when generating code
224
234
  * @param {NetlifyGraph.NetlifyGraphConfig} input.netlifyGraphConfig A standalone config object that contains all the information necessary for Netlify Graph to process events
225
235
  * @returns
226
236
  */
227
237
  const updateGraphQLOperationsFileFromPersistedDoc = async (input) => {
228
- const { docId, netlifyGraphConfig, netlifyToken, schema, siteId } = input
238
+ const { docId, logger, netlifyGraphConfig, netlifyToken, schema, siteId } = input
229
239
  const persistedDoc = await OneGraphClient.fetchPersistedQuery(netlifyToken, siteId, docId)
230
240
  if (!persistedDoc) {
231
241
  warn(`No persisted doc found for: ${docId}`)
@@ -233,12 +243,12 @@ const updateGraphQLOperationsFileFromPersistedDoc = async (input) => {
233
243
  }
234
244
 
235
245
  // Sorts the operations stably, prepends the @netlify directive, etc.
236
- const doc = normalizeOperationsDoc(persistedDoc.query)
246
+ const operationsDocString = normalizeOperationsDoc(persistedDoc.query)
237
247
 
238
- writeGraphQLOperationsSourceFile(netlifyGraphConfig, doc)
248
+ writeGraphQLOperationsSourceFile({ logger, netlifyGraphConfig, operationsDocString })
239
249
  regenerateFunctionsFileFromOperationsFile({ netlifyGraphConfig, schema })
240
250
 
241
- const hash = quickHash(doc)
251
+ const hash = quickHash(operationsDocString)
242
252
 
243
253
  const relevantHasLength = 10
244
254
 
@@ -260,7 +270,12 @@ const handleCliSessionEvent = async ({ event, netlifyGraphConfig, netlifyToken,
260
270
  warn(`No operation id found in payload, ${JSON.stringify(payload, null, 2)}`)
261
271
  return
262
272
  }
263
- generateHandlerByOperationId(netlifyGraphConfig, schema, payload.operationId.id, payload)
273
+ generateHandlerByOperationId({
274
+ netlifyGraphConfig,
275
+ schema,
276
+ operationId: payload.operationId.id,
277
+ handlerOptions: payload,
278
+ })
264
279
  break
265
280
  case 'OneGraphNetlifyCliSessionPersistedLibraryUpdatedEvent':
266
281
  await updateGraphQLOperationsFileFromPersistedDoc({
@@ -284,9 +299,91 @@ const handleCliSessionEvent = async ({ event, netlifyGraphConfig, netlifyToken,
284
299
  }
285
300
  }
286
301
 
287
- const persistNewOperationsDocForSession = async ({ netlifyToken, oneGraphSessionId, operationsDoc, siteId }) => {
302
+ /**
303
+ *
304
+ * @param {object} input
305
+ * @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
306
+ * @param {string} input.oneGraphSessionId The id of the cli session to fetch the current metadata for
307
+ * @param {object} input.siteId The site object that contains the root file path for the site
308
+ */
309
+ const getCLISession = async ({ netlifyToken, oneGraphSessionId, siteId }) => {
310
+ const input = {
311
+ appId: siteId,
312
+ sessionId: oneGraphSessionId,
313
+ authToken: netlifyToken,
314
+ desiredEventCount: 1,
315
+ }
316
+ return await OneGraphClient.fetchCliSession(input)
317
+ }
318
+
319
+ /**
320
+ *
321
+ * @param {object} input
322
+ * @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
323
+ * @param {string} input.oneGraphSessionId The id of the cli session to fetch the current metadata for
324
+ * @param {string} input.siteId The site object that contains the root file path for the site
325
+ */
326
+ const getCLISessionMetadata = async ({ netlifyToken, oneGraphSessionId, siteId }) => {
327
+ const { errors, session } = await getCLISession({ netlifyToken, oneGraphSessionId, siteId })
328
+ return { metadata: session && session.metadata, errors }
329
+ }
330
+
331
+ /**
332
+ * Look at the current project, filesystem, etc. and determine relevant metadata for a cli session
333
+ * @param {object} input
334
+ * @param {string} input.siteRoot The root file path for the site
335
+ * @returns {Record<string, any>} Any locally detected facts that are relevant to include in the cli session metadata
336
+ */
337
+ const detectLocalCLISessionMetadata = ({ siteRoot }) => {
288
338
  const { branch } = gitRepoInfo()
339
+ const hostname = os.hostname()
340
+ const userInfo = os.userInfo({ encoding: 'utf-8' })
341
+ const { username } = userInfo
342
+ const cliVersion = USER_AGENT
343
+
344
+ const detectedMetadata = {
345
+ gitBranch: branch,
346
+ hostname,
347
+ username,
348
+ siteRoot,
349
+ cliVersion,
350
+ }
351
+
352
+ return detectedMetadata
353
+ }
354
+
355
+ /**
356
+ * Fetch the existing cli session metadata if it exists, and mutate it remotely with the passed in metadata
357
+ * @param {object} input
358
+ * @param {NetlifyGraph.NetlifyGraphConfig} input.netlifyGraphConfig The (typically netlify) access token that is used for authentication, if any
359
+ * @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
360
+ * @param {string} input.oneGraphSessionId The id of the cli session to fetch the current metadata for
361
+ * @param {string} input.siteId The site object that contains the root file path for the site
362
+ * @param {string} input.siteRoot The root file path for the site
363
+ * @param {object} input.newMetadata The metadata to merge into (with priority) the existing metadata
364
+ * @returns {Promise<object>}
365
+ */
366
+ const upsertMergeCLISessionMetadata = async ({ netlifyToken, newMetadata, oneGraphSessionId, siteId, siteRoot }) => {
367
+ const { errors, metadata } = await getCLISessionMetadata({ netlifyToken, oneGraphSessionId, siteId })
368
+ if (errors) {
369
+ warn(`Error fetching cli session metadata: ${JSON.stringify(errors, null, 2)}`)
370
+ }
371
+
372
+ const detectedMetadata = detectLocalCLISessionMetadata({ siteRoot })
289
373
 
374
+ const finalMetadata = { ...metadata, ...detectedMetadata, ...newMetadata }
375
+ return OneGraphClient.updateCLISessionMetadata(netlifyToken, siteId, oneGraphSessionId, finalMetadata)
376
+ }
377
+
378
+ const persistNewOperationsDocForSession = async ({
379
+ netlifyGraphConfig,
380
+ netlifyToken,
381
+ oneGraphSessionId,
382
+ operationsDoc,
383
+ siteId,
384
+ siteRoot,
385
+ }) => {
386
+ const { branch } = gitRepoInfo()
290
387
  const payload = {
291
388
  appId: siteId,
292
389
  description: 'Temporary snapshot of local queries',
@@ -295,13 +392,25 @@ const persistNewOperationsDocForSession = async ({ netlifyToken, oneGraphSession
295
392
  }
296
393
  const persistedDoc = await createPersistedQuery(netlifyToken, payload)
297
394
  const newMetadata = await { docId: persistedDoc.id }
298
- const result = await OneGraphClient.updateCLISessionMetadata(netlifyToken, siteId, oneGraphSessionId, newMetadata)
395
+ const result = await upsertMergeCLISessionMetadata({
396
+ netlifyGraphConfig,
397
+ netlifyToken,
398
+ siteId,
399
+ oneGraphSessionId,
400
+ newMetadata,
401
+ siteRoot,
402
+ })
299
403
 
300
404
  if (result.errors) {
301
405
  warn(`Unable to update session metadata with updated operations doc ${JSON.stringify(result.errors, null, 2)}`)
302
406
  }
303
407
  }
304
408
 
409
+ const createCLISession = ({ metadata, netlifyToken, sessionName, siteId }) => {
410
+ const result = OneGraphClient.createCLISession(netlifyToken, siteId, sessionName, metadata)
411
+ return result
412
+ }
413
+
305
414
  /**
306
415
  * Load the CLI session id from the local state
307
416
  * @param {StateConfig} state
@@ -324,7 +433,12 @@ const startOneGraphCLISession = async (input) => {
324
433
  if (!oneGraphSessionId) {
325
434
  const sessionName = generateSessionName()
326
435
  const sessionMetadata = {}
327
- const oneGraphSession = await OneGraphClient.createCLISession(netlifyToken, site.id, sessionName, sessionMetadata)
436
+ const oneGraphSession = await createCLISession({
437
+ netlifyToken,
438
+ siteId: site.id,
439
+ sessionName,
440
+ metadata: sessionMetadata,
441
+ })
328
442
  state.set('oneGraphSessionId', oneGraphSession.id)
329
443
  oneGraphSessionId = state.get('oneGraphSessionId')
330
444
  }
@@ -339,10 +453,12 @@ const startOneGraphCLISession = async (input) => {
339
453
  regenerateFunctionsFileFromOperationsFile({ netlifyGraphConfig, schema })
340
454
  const newOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
341
455
  await persistNewOperationsDocForSession({
456
+ netlifyGraphConfig,
342
457
  netlifyToken,
343
458
  oneGraphSessionId,
344
459
  operationsDoc: newOperationsDoc,
345
460
  siteId: site.id,
461
+ siteRoot: site.root,
346
462
  })
347
463
  },
348
464
  onAdd: async (filePath) => {
@@ -350,10 +466,12 @@ const startOneGraphCLISession = async (input) => {
350
466
  regenerateFunctionsFileFromOperationsFile({ netlifyGraphConfig, schema })
351
467
  const newOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
352
468
  await persistNewOperationsDocForSession({
469
+ netlifyGraphConfig,
353
470
  netlifyToken,
354
471
  oneGraphSessionId,
355
472
  operationsDoc: newOperationsDoc,
356
473
  siteId: site.id,
474
+ siteRoot: site.root,
357
475
  })
358
476
  },
359
477
  })
@@ -395,7 +513,6 @@ const generateSessionName = () => {
395
513
 
396
514
  const OneGraphCliClient = {
397
515
  ackCLISessionEvents: OneGraphClient.ackCLISessionEvents,
398
- createCLISession,
399
516
  createPersistedQuery,
400
517
  fetchCliSessionEvents: OneGraphClient.fetchCliSessionEvents,
401
518
  ensureAppForSite,
@@ -404,6 +521,7 @@ const OneGraphCliClient = {
404
521
 
405
522
  module.exports = {
406
523
  OneGraphCliClient,
524
+ createCLISession,
407
525
  extractFunctionsFromOperationDoc,
408
526
  handleCliSessionEvent,
409
527
  generateSessionName,
@@ -412,4 +530,5 @@ module.exports = {
412
530
  persistNewOperationsDocForSession,
413
531
  refetchAndGenerateFromOneGraph,
414
532
  startOneGraphCLISession,
533
+ upsertMergeCLISessionMetadata,
415
534
  }