netlify-cli 10.15.0 → 10.17.1

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,9 +1,10 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "10.15.0",
4
+ "version": "10.17.1",
5
5
  "author": "Netlify Inc.",
6
6
  "contributors": [
7
+ "@whitep4nth3r (https://twitter.com/whitep4nth3r)",
7
8
  "Abraham Schilling <AbrahamSchilling@gmail.com> (https://gitlab.com/n4bb12)",
8
9
  "Alberto De Agostini (https://twitter.com/albertodeago88)",
9
10
  "Alejandro Ñáñez Ortiz <git@alejandro.dev> (https://twitter.com/alejandronanez)",
@@ -222,11 +223,11 @@
222
223
  "dependencies": {
223
224
  "@netlify/build": "^27.8.1",
224
225
  "@netlify/config": "^18.1.2",
225
- "@netlify/edge-bundler": "^1.8.0",
226
- "@netlify/framework-info": "^9.1.1",
226
+ "@netlify/edge-bundler": "^1.12.1",
227
+ "@netlify/framework-info": "^9.2.0",
227
228
  "@netlify/local-functions-proxy": "^1.1.1",
228
- "@netlify/plugins-list": "^6.36.0",
229
- "@netlify/zip-it-and-ship-it": "^5.13.3",
229
+ "@netlify/plugins-list": "^6.38.0",
230
+ "@netlify/zip-it-and-ship-it": "^5.13.4",
230
231
  "@octokit/rest": "^18.0.0",
231
232
  "@sindresorhus/slugify": "^1.1.0",
232
233
  "ansi-escapes": "^5.0.0",
@@ -291,7 +292,7 @@
291
292
  "multiparty": "^4.2.1",
292
293
  "netlify": "^12.0.0",
293
294
  "netlify-headers-parser": "^6.0.2",
294
- "netlify-onegraph-internal": "0.4.2",
295
+ "netlify-onegraph-internal": "0.8.4",
295
296
  "netlify-redirect-parser": "^13.0.5",
296
297
  "netlify-redirector": "^0.2.1",
297
298
  "node-fetch": "^2.6.0",
@@ -38,6 +38,7 @@ const {
38
38
  error,
39
39
  exit,
40
40
  generateNetlifyGraphJWT,
41
+ getEnvelopeEnv,
41
42
  getSiteInformation,
42
43
  getToken,
43
44
  injectEnvVariables,
@@ -233,6 +234,7 @@ const FRAMEWORK_PORT_TIMEOUT = 6e5
233
234
  * @param {object} params
234
235
  * @param {*} params.addonsUrls
235
236
  * @param {import('../base-command').NetlifyOptions["config"]} params.config
237
+ * @param {import('../base-command').NetlifyOptions["cachedConfig"]['env']} params.env
236
238
  * @param {InspectSettings} params.inspectSettings
237
239
  * @param {() => Promise<object>} params.getUpdatedConfig
238
240
  * @param {string} params.geolocationMode
@@ -247,6 +249,7 @@ const FRAMEWORK_PORT_TIMEOUT = 6e5
247
249
  const startProxyServer = async ({
248
250
  addonsUrls,
249
251
  config,
252
+ env,
250
253
  geoCountry,
251
254
  geolocationMode,
252
255
  getUpdatedConfig,
@@ -261,6 +264,7 @@ const startProxyServer = async ({
261
264
  addonsUrls,
262
265
  config,
263
266
  configPath: site.configPath,
267
+ env,
264
268
  geolocationMode,
265
269
  geoCountry,
266
270
  getUpdatedConfig,
@@ -425,7 +429,12 @@ const dev = async (options, command) => {
425
429
  ...options,
426
430
  }
427
431
 
428
- await injectEnvVariables({ devConfig, env: command.netlify.cachedConfig.env, site })
432
+ let { env } = command.netlify.cachedConfig
433
+ if (siteInfo.use_envelope) {
434
+ env = await getEnvelopeEnv({ api, context: options.context, env, siteInfo })
435
+ }
436
+
437
+ await injectEnvVariables({ devConfig, env, site })
429
438
  await promptEditorHelper({ chalk, config, log, NETLIFYDEVLOG, repositoryRoot, state })
430
439
 
431
440
  const { addonsUrls, capabilities, siteUrl, timeouts } = await getSiteInformation({
@@ -479,6 +488,7 @@ const dev = async (options, command) => {
479
488
  let url = await startProxyServer({
480
489
  addonsUrls,
481
490
  config,
491
+ env: command.netlify.cachedConfig.env,
482
492
  geolocationMode: options.geo,
483
493
  geoCountry: options.country,
484
494
  getUpdatedConfig,
@@ -514,6 +524,9 @@ const dev = async (options, command) => {
514
524
 
515
525
  let stopWatchingCLISessions
516
526
 
527
+ let liveConfig = { ...config }
528
+ let isRestartingSession = false
529
+
517
530
  const createOrResumeSession = async function () {
518
531
  const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options, settings })
519
532
 
@@ -524,6 +537,7 @@ const dev = async (options, command) => {
524
537
  }
525
538
 
526
539
  stopWatchingCLISessions = await startOneGraphCLISession({
540
+ config: liveConfig,
527
541
  netlifyGraphConfig,
528
542
  netlifyToken,
529
543
  site,
@@ -535,6 +549,7 @@ const dev = async (options, command) => {
535
549
  const oneGraphSessionId = loadCLISession(state)
536
550
 
537
551
  await persistNewOperationsDocForSession({
552
+ config: liveConfig,
538
553
  netlifyGraphConfig,
539
554
  netlifyToken,
540
555
  oneGraphSessionId,
@@ -570,10 +585,16 @@ const dev = async (options, command) => {
570
585
  }
571
586
 
572
587
  // Set up a handler for config changes.
573
- configWatcher.on('change', (newConfig) => {
588
+ configWatcher.on('change', async (newConfig) => {
574
589
  command.netlify.config = newConfig
575
- stopWatchingCLISessions()
576
- createOrResumeSession()
590
+ liveConfig = newConfig
591
+ if (isRestartingSession) {
592
+ return
593
+ }
594
+ stopWatchingCLISessions && stopWatchingCLISessions()
595
+ isRestartingSession = true
596
+ await createOrResumeSession()
597
+ isRestartingSession = false
577
598
  })
578
599
 
579
600
  const oneGraphSessionId = await createOrResumeSession()
@@ -606,6 +627,11 @@ const createDevCommand = (program) => {
606
627
  `Local dev server\nThe dev command will run a local dev server with Netlify's proxy and redirect rules`,
607
628
  )
608
629
  .option('-c ,--command <command>', 'command to run')
630
+ .addOption(
631
+ new Option('--context <context>', 'Specify a deploy context for environment variables')
632
+ .choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
633
+ .default('dev'),
634
+ )
609
635
  .option('-p ,--port <port>', 'port of netlify dev', (value) => Number.parseInt(value))
610
636
  .option('--targetPort <port>', 'port of target app server', (value) => Number.parseInt(value))
611
637
  .option('--framework <name>', 'framework to use. Defaults to #auto which automatically detects a framework')
@@ -655,6 +681,7 @@ const createDevCommand = (program) => {
655
681
  'netlify dev',
656
682
  'netlify dev -d public',
657
683
  'netlify dev -c "hugo server -w" --targetPort 1313',
684
+ 'netlify dev --context production',
658
685
  'netlify dev --graph',
659
686
  'netlify dev --edgeInspect',
660
687
  'netlify dev --edgeInspect=127.0.0.1:9229',
@@ -1,5 +1,7 @@
1
1
  // @ts-check
2
- const { log, logJson } = require('../../utils')
2
+ const { Option } = require('commander')
3
+
4
+ const { chalk, error, getEnvelopeEnv, log, logJson } = require('../../utils')
3
5
 
4
6
  /**
5
7
  * The env:get command
@@ -8,6 +10,7 @@ const { log, logJson } = require('../../utils')
8
10
  * @param {import('../base-command').BaseCommand} command
9
11
  */
10
12
  const envGet = async (name, options, command) => {
13
+ const { context, scope } = options
11
14
  const { api, cachedConfig, site } = command.netlify
12
15
  const siteId = site.id
13
16
 
@@ -16,9 +19,21 @@ const envGet = async (name, options, command) => {
16
19
  return false
17
20
  }
18
21
 
19
- const siteData = await api.getSite({ siteId })
22
+ const { siteInfo } = cachedConfig
23
+ let { env } = cachedConfig
24
+
25
+ if (siteInfo.use_envelope) {
26
+ env = await getEnvelopeEnv({ api, context, env, key: name, scope, siteInfo })
27
+ } else if (context !== 'dev' || scope !== 'any') {
28
+ error(
29
+ `To specify a context or scope, please run ${chalk.yellowBright(
30
+ 'netlify open:admin',
31
+ )} to open the Netlify UI and opt in to the new environment variables experience from Site settings`,
32
+ )
33
+ return false
34
+ }
20
35
 
21
- const { value } = cachedConfig.env[name] || {}
36
+ const { value } = env[name] || {}
22
37
 
23
38
  // Return json response for piping commands
24
39
  if (options.json) {
@@ -27,7 +42,9 @@ const envGet = async (name, options, command) => {
27
42
  }
28
43
 
29
44
  if (!value) {
30
- log(`Environment variable ${name} not set for site ${siteData.name}`)
45
+ const withContext = `in the ${chalk.magentaBright(context)} context`
46
+ const withScope = scope === 'any' ? '' : ` in the ${chalk.magentaBright(context)} scope`
47
+ log(`No value set ${withContext}${withScope} for environment variable ${chalk.yellowBright(name)}`)
31
48
  return false
32
49
  }
33
50
 
@@ -43,6 +60,16 @@ const createEnvGetCommand = (program) =>
43
60
  program
44
61
  .command('env:get')
45
62
  .argument('<name>', 'Environment variable name')
63
+ .addOption(
64
+ new Option('-c, --context <context>', 'Specify a deploy context')
65
+ .choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
66
+ .default('dev'),
67
+ )
68
+ .addOption(
69
+ new Option('-s, --scope <scope>', 'Specify a scope')
70
+ .choices(['builds', 'functions', 'post_processing', 'runtime', 'any'])
71
+ .default('any'),
72
+ )
46
73
  .description('Get resolved value of specified environment variable (includes netlify.toml)')
47
74
  .action(async (name, options, command) => {
48
75
  await envGet(name, options, command)
@@ -1,20 +1,33 @@
1
1
  // @ts-check
2
2
  const AsciiTable = require('ascii-table')
3
3
  const { isCI } = require('ci-info')
4
+ const { Option } = require('commander')
4
5
  const inquirer = require('inquirer')
5
6
  const isEmpty = require('lodash/isEmpty')
6
7
 
7
- const { chalk, log, logJson } = require('../../utils')
8
+ const { chalk, error, getEnvelopeEnv, getHumanReadableScopes, log, logJson } = require('../../utils')
8
9
 
9
10
  const [logUpdatePromise, ansiEscapesPromise] = [import('log-update'), import('ansi-escapes')]
10
11
 
11
12
  const MASK_LENGTH = 50
12
13
  const MASK = '*'.repeat(MASK_LENGTH)
13
14
 
14
- const getTable = ({ environment, hideValues }) => {
15
+ const getTable = ({ environment, hideValues, scopesColumn }) => {
15
16
  const table = new AsciiTable(`Environment variables`)
16
- table.setHeading('Key', 'Value')
17
- table.addRowMatrix(Object.entries(environment).map(([key, value]) => [key, hideValues ? MASK : value]))
17
+ const headings = ['Key', 'Value', scopesColumn && 'Scope'].filter(Boolean)
18
+ table.setHeading(...headings)
19
+ table.addRowMatrix(
20
+ Object.entries(environment).map(([key, variable]) =>
21
+ [
22
+ // Key
23
+ key,
24
+ // Value
25
+ hideValues ? MASK : variable.value,
26
+ // Scope
27
+ scopesColumn && getHumanReadableScopes(variable.scopes),
28
+ ].filter(Boolean),
29
+ ),
30
+ )
18
31
  return table.toString()
19
32
  }
20
33
 
@@ -25,6 +38,7 @@ const getTable = ({ environment, hideValues }) => {
25
38
  * @returns {Promise<boolean>}
26
39
  */
27
40
  const envList = async (options, command) => {
41
+ const { context, scope } = options
28
42
  const { api, cachedConfig, site } = command.netlify
29
43
  const siteId = site.id
30
44
 
@@ -33,36 +47,55 @@ const envList = async (options, command) => {
33
47
  return false
34
48
  }
35
49
 
36
- const siteData = await api.getSite({ siteId })
37
- const environment = Object.fromEntries(
38
- Object.entries(cachedConfig.env)
39
- // Omitting general variables to reduce noise.
40
- .filter(([, variable]) => variable.sources[0] !== 'general')
41
- .map(([key, variable]) => [key, variable.value]),
50
+ const { env, siteInfo } = cachedConfig
51
+ const isUsingEnvelope = siteInfo.use_envelope
52
+ let environment = env
53
+
54
+ if (isUsingEnvelope) {
55
+ environment = await getEnvelopeEnv({ api, context, env, scope, siteInfo })
56
+ } else if (context !== 'dev' || scope !== 'any') {
57
+ error(
58
+ `To specify a context or scope, please run ${chalk.yellowBright(
59
+ 'netlify open:admin',
60
+ )} to open the Netlify UI and opt in to the new environment variables experience from Site settings`,
61
+ )
62
+ return false
63
+ }
64
+
65
+ // filter out general sources
66
+ environment = Object.fromEntries(
67
+ Object.entries(environment).filter(([, variable]) => variable.sources[0] !== 'general'),
42
68
  )
43
69
 
44
70
  // Return json response for piping commands
45
71
  if (options.json) {
46
- logJson(environment)
72
+ const envDictionary = Object.fromEntries(
73
+ Object.entries(environment).map(([key, variable]) => [key, variable.value]),
74
+ )
75
+ logJson(envDictionary)
47
76
  return false
48
77
  }
49
78
 
79
+ const forSite = `for site ${chalk.greenBright(siteInfo.name)}`
80
+ const withContext = isUsingEnvelope ? `in the ${chalk.magentaBright(options.context)} context` : ''
81
+ const withScope = isUsingEnvelope && scope !== 'any' ? `and ${chalk.yellowBright(options.scope)} scope` : ''
50
82
  if (isEmpty(environment)) {
51
- log(`No environment variables set for site ${chalk.greenBright(siteData.name)}`)
83
+ log(`No environment variables set ${forSite} ${withContext} ${withScope}`)
52
84
  return false
53
85
  }
54
86
 
55
87
  // List environment in a table
56
- log(`Listing environment variables for site: ${chalk.greenBright(siteData.name)}`)
88
+ const count = Object.keys(environment).length
89
+ log(`${count} environment variable${count === 1 ? '' : 's'} ${forSite} ${withContext} ${withScope}`)
57
90
 
58
91
  if (isCI) {
59
- log(getTable({ environment, hideValues: false }))
92
+ log(getTable({ environment, hideValues: false, scopesColumn: isUsingEnvelope }))
60
93
  return false
61
94
  }
62
95
 
63
96
  const { default: logUpdate } = await logUpdatePromise
64
97
 
65
- logUpdate(getTable({ environment, hideValues: true }))
98
+ logUpdate(getTable({ environment, hideValues: true, scopesColumn: isUsingEnvelope }))
66
99
  const { showValues } = await inquirer.prompt([
67
100
  {
68
101
  type: 'confirm',
@@ -76,7 +109,7 @@ const envList = async (options, command) => {
76
109
  const { default: ansiEscapes } = await ansiEscapesPromise
77
110
  // since inquirer adds a prompt, we need to account for it when printing the table again
78
111
  log(ansiEscapes.eraseLines(3))
79
- logUpdate(getTable({ environment, hideValues: false }))
112
+ logUpdate(getTable({ environment, hideValues: false, scopesColumn: isUsingEnvelope }))
80
113
  log(`${chalk.cyan('?')} Show values? ${chalk.cyan('Yes')}`)
81
114
  }
82
115
  }
@@ -89,6 +122,16 @@ const envList = async (options, command) => {
89
122
  const createEnvListCommand = (program) =>
90
123
  program
91
124
  .command('env:list')
125
+ .addOption(
126
+ new Option('-c, --context <context>', 'Specify a deploy context')
127
+ .choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
128
+ .default('dev'),
129
+ )
130
+ .addOption(
131
+ new Option('-s, --scope <scope>', 'Specify a scope')
132
+ .choices(['builds', 'functions', 'post_processing', 'runtime', 'any'])
133
+ .default('any'),
134
+ )
92
135
  .description('Lists resolved environment variables for site (includes netlify.toml)')
93
136
  .action(async (options, command) => {
94
137
  await envList(options, command)
@@ -21,7 +21,7 @@ const { ensureAppForSite, executeCreatePersistedQueryMutation } = OneGraphCliCli
21
21
  * @returns
22
22
  */
23
23
  const graphEdit = async (options, command) => {
24
- const { site, state } = command.netlify
24
+ const { config, site, state } = command.netlify
25
25
  const siteId = site.id
26
26
 
27
27
  if (!site.id) {
@@ -44,6 +44,7 @@ const graphEdit = async (options, command) => {
44
44
  await ensureAppForSite(netlifyToken, siteId)
45
45
 
46
46
  const oneGraphSessionId = await ensureCLISession({
47
+ config,
47
48
  metadata: {},
48
49
  netlifyToken,
49
50
  site,
@@ -77,7 +78,7 @@ const graphEdit = async (options, command) => {
77
78
 
78
79
  const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
79
80
  await upsertMergeCLISessionMetadata({
80
- netlifyGraphConfig,
81
+ config,
81
82
  jwt,
82
83
  siteId,
83
84
  siteRoot: site.root,
@@ -1,29 +1,27 @@
1
+ /* eslint-disable eslint-comments/disable-enable-pair */
1
2
  // @ts-check
2
- const inquirer = require('inquirer')
3
- const { GraphQL } = require('netlify-onegraph-internal')
4
3
 
5
4
  const {
5
+ autocompleteCodegenModules,
6
+ autocompleteOperationNames,
6
7
  buildSchema,
7
- defaultExampleOperationsDoc,
8
- extractFunctionsFromOperationDoc,
9
8
  generateHandlerByOperationName,
9
+ getCodegenFunctionById,
10
+ getCodegenModule,
10
11
  getNetlifyGraphConfig,
11
- readGraphQLOperationsSourceFile,
12
12
  readGraphQLSchemaFile,
13
13
  } = require('../../lib/one-graph/cli-netlify-graph')
14
14
  const { error, log } = require('../../utils')
15
15
 
16
- const { parse } = GraphQL
17
-
18
16
  /**
19
17
  * Creates the `netlify graph:handler` command
20
- * @param {string} userOperationName
21
18
  * @param {import('commander').OptionValues} options
22
19
  * @param {import('../base-command').BaseCommand} command
23
20
  * @returns
24
21
  */
25
- const graphHandler = async (userOperationName, options, command) => {
22
+ const graphHandler = async (args, options, command) => {
26
23
  const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options })
24
+ const { config } = command.netlify
27
25
 
28
26
  const schemaString = readGraphQLSchemaFile(netlifyGraphConfig)
29
27
 
@@ -35,69 +33,48 @@ const graphHandler = async (userOperationName, options, command) => {
35
33
  error(`Error parsing schema: ${buildSchemaError}`)
36
34
  }
37
35
 
38
- if (!schema) {
39
- error(`Failed to parse Netlify GraphQL schema`)
40
- }
36
+ const userOperationName = args.operationName
37
+ const userCodegenId = options.codegen
41
38
 
42
39
  let operationName = userOperationName
43
40
  if (!operationName) {
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 n/global-require
68
- const inquirerAutocompletePrompt = require('inquirer-autocomplete-prompt')
69
- /** multiple matching detectors, make the user choose */
70
- inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt)
41
+ operationName = await autocompleteOperationNames({ netlifyGraphConfig })
42
+ }
71
43
 
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
- }
44
+ if (!operationName) {
45
+ error(`No operation name provided`)
46
+ }
81
47
 
82
- const filteredChoices = filterOperationNames(allOperationChoices, input)
83
- // only show filtered results
84
- return filteredChoices
85
- },
86
- })
48
+ const codegenModule = await getCodegenModule({ config })
49
+ if (!codegenModule) {
50
+ error(
51
+ `No Netlify Graph codegen module specified in netlify.toml under the [graph] header. Please specify 'codeGenerator' field and try again.`,
52
+ )
53
+ return
54
+ }
87
55
 
88
- if (selectedOperationName) {
89
- operationName = selectedOperationName
90
- }
91
- } catch (parseError) {
92
- parseError(`Error parsing operations library: ${parseError}`)
93
- }
56
+ let codeGenerator = userCodegenId ? await getCodegenFunctionById({ config, id: userCodegenId }) : null
57
+ if (!codeGenerator) {
58
+ codeGenerator = await autocompleteCodegenModules({ config })
94
59
  }
95
60
 
96
- if (!operationName) {
97
- error(`No operation name provided`)
61
+ if (!codeGenerator) {
62
+ error(`Unable to select appropriate Netlify Graph code generator`)
63
+ return
98
64
  }
99
65
 
100
- generateHandlerByOperationName({ logger: log, netlifyGraphConfig, schema, operationName, handlerOptions: {} })
66
+ if (schema) {
67
+ generateHandlerByOperationName({
68
+ generate: codeGenerator.generateHandler,
69
+ logger: log,
70
+ netlifyGraphConfig,
71
+ schema,
72
+ operationName,
73
+ handlerOptions: {},
74
+ })
75
+ } else {
76
+ error(`Failed to parse Netlify GraphQL schema`)
77
+ }
101
78
  }
102
79
 
103
80
  /**
@@ -109,11 +86,12 @@ const createGraphHandlerCommand = (program) =>
109
86
  program
110
87
  .command('graph:handler')
111
88
  .argument('[name]', 'Operation name')
89
+ .option('-c, --codegen <id>', 'The id of the specific code generator to use')
112
90
  .description(
113
91
  'Generate a handler for a Graph operation given its name. See `graph:operations` for a list of operations.',
114
92
  )
115
93
  .action(async (operationName, options, command) => {
116
- await graphHandler(operationName, options, command)
94
+ await graphHandler({ operationName }, options, command)
117
95
  })
118
96
 
119
97
  module.exports = { createGraphHandlerCommand }
@@ -18,7 +18,7 @@ const { ensureAppForSite, executeCreateApiTokenMutation } = OneGraphCliClient
18
18
  * @returns
19
19
  */
20
20
  const graphInit = async (options, command) => {
21
- const { api, site, state } = command.netlify
21
+ const { api, config, site, state } = command.netlify
22
22
  const siteId = site.id
23
23
 
24
24
  if (!siteId) {
@@ -66,6 +66,7 @@ const graphInit = async (options, command) => {
66
66
 
67
67
  const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options })
68
68
  await ensureCLISession({
69
+ config,
69
70
  metadata: {},
70
71
  netlifyToken,
71
72
  site,
@@ -1,4 +1,6 @@
1
1
  // @ts-check
2
+ const { GraphQL } = require('netlify-onegraph-internal')
3
+
2
4
  const { readLockfile } = require('../../lib/one-graph/cli-client')
3
5
  const {
4
6
  buildSchema,
@@ -19,10 +21,19 @@ const { NETLIFYDEVERR, chalk, error, log } = require('../../utils')
19
21
  * @returns
20
22
  */
21
23
  const graphLibrary = async (options, command) => {
24
+ const { config } = command.netlify
22
25
  const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options })
23
26
 
24
27
  const schemaString = readGraphQLSchemaFile(netlifyGraphConfig)
25
28
 
29
+ let currentOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
30
+ if (currentOperationsDoc.trim().length === 0) {
31
+ currentOperationsDoc = defaultExampleOperationsDoc
32
+ }
33
+
34
+ const parsedDoc = parse(currentOperationsDoc)
35
+ const { fragments, functions } = extractFunctionsFromOperationDoc(GraphQL, parsedDoc)
36
+
26
37
  let schema
27
38
 
28
39
  try {
@@ -33,29 +44,24 @@ const graphLibrary = async (options, command) => {
33
44
 
34
45
  if (!schema) {
35
46
  error(`Failed to parse Netlify GraphQL schema`)
47
+ return
36
48
  }
37
49
 
38
- let currentOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
39
- if (currentOperationsDoc.trim().length === 0) {
40
- currentOperationsDoc = defaultExampleOperationsDoc
41
- }
42
-
43
- const parsedDoc = parse(currentOperationsDoc)
44
- const { fragments, functions } = extractFunctionsFromOperationDoc(parsedDoc)
45
-
46
50
  const lockfile = readLockfile({ siteRoot: command.netlify.site.root })
47
51
 
48
- if (lockfile == null) {
52
+ if (lockfile === undefined) {
49
53
  error(
50
54
  `${NETLIFYDEVERR} Error: no lockfile found, unable to run \`netlify graph:library\`. To pull a remote schema (and create a lockfile), run ${chalk.yellow(
51
55
  'netlify graph:pull',
52
56
  )} `,
53
57
  )
58
+ return
54
59
  }
55
60
 
56
- const schemaId = lockfile && lockfile.locked.schemaId
61
+ const { schemaId } = lockfile.locked
57
62
 
58
- generateFunctionsFile({
63
+ const payload = {
64
+ config,
59
65
  logger: log,
60
66
  netlifyGraphConfig,
61
67
  schema,
@@ -63,7 +69,9 @@ const graphLibrary = async (options, command) => {
63
69
  operationsDoc: currentOperationsDoc,
64
70
  functions,
65
71
  fragments,
66
- })
72
+ }
73
+
74
+ generateFunctionsFile(payload)
67
75
  }
68
76
 
69
77
  /**
@@ -26,13 +26,18 @@ const graphOperations = async (options, command) => {
26
26
  }
27
27
 
28
28
  const parsedDoc = parse(currentOperationsDoc)
29
- const { fragments, functions } = extractFunctionsFromOperationDoc(parsedDoc)
29
+ const { fragments, functions } = extractFunctionsFromOperationDoc(GraphQL, parsedDoc)
30
30
 
31
31
  const sorted = {
32
+ /** @type {import('netlify-onegraph-internal/dist/netlifyGraph').ExtractedFunction[]} */
32
33
  queries: [],
34
+ /** @type {import('netlify-onegraph-internal/dist/netlifyGraph').ExtractedFunction[]} */
33
35
  mutations: [],
36
+ /** @type {import('netlify-onegraph-internal/dist/netlifyGraph').ExtractedFunction[]} */
34
37
  subscriptions: [],
38
+ /** @type {import('netlify-onegraph-internal/dist/netlifyGraph').ExtractedFragment[]} */
35
39
  fragments: [],
40
+ /** @type {any[]} */
36
41
  other: [],
37
42
  }
38
43