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/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.5",
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.9.0",
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.32",
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",
@@ -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
- let authlifyJWT
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
- config: configWithAuthlify,
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,
@@ -34,8 +34,10 @@ const functionsServe = async (options, command) => {
34
34
 
35
35
  await startFunctionsServer({
36
36
  config,
37
+ api,
37
38
  settings: { functions: functionsDir, functionsPort },
38
39
  site,
40
+ siteInfo,
39
41
  siteUrl,
40
42
  capabilities,
41
43
  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 { 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,
@@ -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 { 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,7 +64,16 @@ 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
 
@@ -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
- generateAuthlifyJWT,
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 createHandler = function ({ config, functionsRegistry }) {
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
- const { authlifyTokenId, netlifyToken, siteId } = config.authlify
111
- event.authlifyToken = generateAuthlifyJWT(netlifyToken, authlifyTokenId, siteId)
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 ({ buildersPrefix, config, functionsPrefix, functionsRegistry, siteUrl }) {
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({ config, functionsRegistry })
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
- buildersPrefix = '',
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 { createCLISession, createPersistedQuery, ensureAppForSite, updateCLISessionMetadata } = OneGraphClient
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
- const doc = persistedDoc.query
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
- const persistNewOperationsDocForSession = async ({ netlifyToken, oneGraphSessionId, operationsDoc, siteId }) => {
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 OneGraphClient.updateCLISessionMetadata(netlifyToken, siteId, oneGraphSessionId, newMetadata)
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 OneGraphClient.createCLISession(netlifyToken, site.id, sessionName, sessionMetadata)
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
- : null
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?cliSessionId=${oneGraphSessionId}`
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?cliSessionId=${oneGraphSessionId}`
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 an Authlify JWT with the following claims:
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 generateAuthlifyJWT = (netlifyToken, authlifyTokenId, siteId) => {
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
- generateAuthlifyJWT,
222
+ generateNetlifyGraphJWT,
223
223
  }