netlify-cli 10.13.0 → 10.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/npm-shrinkwrap.json +1739 -2024
- package/package.json +8 -7
- package/src/commands/dev/dev.js +18 -3
- package/src/commands/functions/functions-invoke.js +4 -4
- package/src/commands/graph/graph-edit.js +4 -2
- package/src/commands/graph/graph-handler.js +41 -63
- package/src/commands/graph/graph-init.js +152 -0
- package/src/commands/graph/graph-library.js +30 -8
- package/src/commands/graph/graph-operations.js +6 -1
- package/src/commands/graph/graph-pull.js +79 -23
- package/src/commands/graph/graph.js +2 -0
- package/src/commands/login/login.js +1 -1
- package/src/commands/main.js +1 -1
- package/src/functions-templates/go/hello-world/go.mod +2 -2
- package/src/functions-templates/javascript/graphql-gateway/{{name}}.js +1 -1
- package/src/functions-templates/javascript/hello-world/{{name}}.js +1 -1
- package/src/functions-templates/javascript/identity-signup/{{name}}.js +1 -1
- package/src/functions-templates/javascript/serverless-ssr/app/index.js +1 -1
- package/src/functions-templates/javascript/stripe-charge/package-lock.json +6 -6
- package/src/functions-templates/javascript/stripe-subscription/package-lock.json +6 -6
- package/src/functions-templates/rust/hello-world/Cargo.toml +1 -1
- package/src/functions-templates/typescript/hello-world/package-lock.json +6 -6
- package/src/lib/edge-functions/proxy.js +4 -0
- package/src/lib/edge-functions/registry.js +29 -3
- package/src/lib/one-graph/cli-client.js +813 -170
- package/src/lib/one-graph/cli-netlify-graph.js +519 -50
- package/src/utils/dot-env.js +1 -1
- package/src/utils/init/utils.js +1 -1
- package/src/utils/proxy.js +2 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
3
|
"description": "Netlify command line tool",
|
|
4
|
-
"version": "10.
|
|
4
|
+
"version": "10.16.0",
|
|
5
5
|
"author": "Netlify Inc.",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"Abraham Schilling <AbrahamSchilling@gmail.com> (https://gitlab.com/n4bb12)",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"Charlie Depman <cdepman@gmail.com> (depman.dev)",
|
|
27
27
|
"Charlie Depman <cdepman@gmail.com> (depman.dev)",
|
|
28
28
|
"Charlie Depman <cdepman@gmail.com> (depman.dev)",
|
|
29
|
+
"Chris Templin <ctemplin@gmail.com>",
|
|
29
30
|
"Cole Bosmann",
|
|
30
31
|
"Dan Croak (https://twitter.com/croaky)",
|
|
31
32
|
"Dan Loewenherz <dan@lionheartsw.com> (https://twitter.com/dwlz)",
|
|
@@ -219,13 +220,13 @@
|
|
|
219
220
|
"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\" \"!**/*/package-lock.json\" \"!.github/**/*.md\""
|
|
220
221
|
},
|
|
221
222
|
"dependencies": {
|
|
222
|
-
"@netlify/build": "^27.
|
|
223
|
+
"@netlify/build": "^27.8.1",
|
|
223
224
|
"@netlify/config": "^18.1.2",
|
|
224
|
-
"@netlify/edge-bundler": "^1.
|
|
225
|
-
"@netlify/framework-info": "^9.
|
|
225
|
+
"@netlify/edge-bundler": "^1.12.1",
|
|
226
|
+
"@netlify/framework-info": "^9.2.0",
|
|
226
227
|
"@netlify/local-functions-proxy": "^1.1.1",
|
|
227
|
-
"@netlify/plugins-list": "^6.
|
|
228
|
-
"@netlify/zip-it-and-ship-it": "^5.13.
|
|
228
|
+
"@netlify/plugins-list": "^6.37.0",
|
|
229
|
+
"@netlify/zip-it-and-ship-it": "^5.13.4",
|
|
229
230
|
"@octokit/rest": "^18.0.0",
|
|
230
231
|
"@sindresorhus/slugify": "^1.1.0",
|
|
231
232
|
"ansi-escapes": "^5.0.0",
|
|
@@ -290,7 +291,7 @@
|
|
|
290
291
|
"multiparty": "^4.2.1",
|
|
291
292
|
"netlify": "^12.0.0",
|
|
292
293
|
"netlify-headers-parser": "^6.0.2",
|
|
293
|
-
"netlify-onegraph-internal": "0.
|
|
294
|
+
"netlify-onegraph-internal": "0.8.1",
|
|
294
295
|
"netlify-redirect-parser": "^13.0.5",
|
|
295
296
|
"netlify-redirector": "^0.2.1",
|
|
296
297
|
"node-fetch": "^2.6.0",
|
package/src/commands/dev/dev.js
CHANGED
|
@@ -233,6 +233,7 @@ const FRAMEWORK_PORT_TIMEOUT = 6e5
|
|
|
233
233
|
* @param {object} params
|
|
234
234
|
* @param {*} params.addonsUrls
|
|
235
235
|
* @param {import('../base-command').NetlifyOptions["config"]} params.config
|
|
236
|
+
* @param {import('../base-command').NetlifyOptions["cachedConfig"]['env']} params.env
|
|
236
237
|
* @param {InspectSettings} params.inspectSettings
|
|
237
238
|
* @param {() => Promise<object>} params.getUpdatedConfig
|
|
238
239
|
* @param {string} params.geolocationMode
|
|
@@ -247,6 +248,7 @@ const FRAMEWORK_PORT_TIMEOUT = 6e5
|
|
|
247
248
|
const startProxyServer = async ({
|
|
248
249
|
addonsUrls,
|
|
249
250
|
config,
|
|
251
|
+
env,
|
|
250
252
|
geoCountry,
|
|
251
253
|
geolocationMode,
|
|
252
254
|
getUpdatedConfig,
|
|
@@ -261,6 +263,7 @@ const startProxyServer = async ({
|
|
|
261
263
|
addonsUrls,
|
|
262
264
|
config,
|
|
263
265
|
configPath: site.configPath,
|
|
266
|
+
env,
|
|
264
267
|
geolocationMode,
|
|
265
268
|
geoCountry,
|
|
266
269
|
getUpdatedConfig,
|
|
@@ -479,6 +482,7 @@ const dev = async (options, command) => {
|
|
|
479
482
|
let url = await startProxyServer({
|
|
480
483
|
addonsUrls,
|
|
481
484
|
config,
|
|
485
|
+
env: command.netlify.cachedConfig.env,
|
|
482
486
|
geolocationMode: options.geo,
|
|
483
487
|
geoCountry: options.country,
|
|
484
488
|
getUpdatedConfig,
|
|
@@ -514,6 +518,9 @@ const dev = async (options, command) => {
|
|
|
514
518
|
|
|
515
519
|
let stopWatchingCLISessions
|
|
516
520
|
|
|
521
|
+
let liveConfig = { ...config }
|
|
522
|
+
let isRestartingSession = false
|
|
523
|
+
|
|
517
524
|
const createOrResumeSession = async function () {
|
|
518
525
|
const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options, settings })
|
|
519
526
|
|
|
@@ -524,6 +531,7 @@ const dev = async (options, command) => {
|
|
|
524
531
|
}
|
|
525
532
|
|
|
526
533
|
stopWatchingCLISessions = await startOneGraphCLISession({
|
|
534
|
+
config: liveConfig,
|
|
527
535
|
netlifyGraphConfig,
|
|
528
536
|
netlifyToken,
|
|
529
537
|
site,
|
|
@@ -535,6 +543,7 @@ const dev = async (options, command) => {
|
|
|
535
543
|
const oneGraphSessionId = loadCLISession(state)
|
|
536
544
|
|
|
537
545
|
await persistNewOperationsDocForSession({
|
|
546
|
+
config: liveConfig,
|
|
538
547
|
netlifyGraphConfig,
|
|
539
548
|
netlifyToken,
|
|
540
549
|
oneGraphSessionId,
|
|
@@ -570,10 +579,16 @@ const dev = async (options, command) => {
|
|
|
570
579
|
}
|
|
571
580
|
|
|
572
581
|
// Set up a handler for config changes.
|
|
573
|
-
configWatcher.on('change', (newConfig) => {
|
|
582
|
+
configWatcher.on('change', async (newConfig) => {
|
|
574
583
|
command.netlify.config = newConfig
|
|
575
|
-
|
|
576
|
-
|
|
584
|
+
liveConfig = newConfig
|
|
585
|
+
if (isRestartingSession) {
|
|
586
|
+
return
|
|
587
|
+
}
|
|
588
|
+
stopWatchingCLISessions && stopWatchingCLISessions()
|
|
589
|
+
isRestartingSession = true
|
|
590
|
+
await createOrResumeSession()
|
|
591
|
+
isRestartingSession = false
|
|
577
592
|
})
|
|
578
593
|
|
|
579
594
|
const oneGraphSessionId = await createOrResumeSession()
|
|
@@ -8,7 +8,7 @@ const fetch = require('node-fetch')
|
|
|
8
8
|
|
|
9
9
|
const { BACKGROUND, CLOCKWORK_USERAGENT, NETLIFYDEVWARN, chalk, error, exit, getFunctions } = require('../../utils')
|
|
10
10
|
|
|
11
|
-
// https://
|
|
11
|
+
// https://docs.netlify.com/functions/trigger-on-events/
|
|
12
12
|
const events = [
|
|
13
13
|
'deploy-building',
|
|
14
14
|
'deploy-succeeded',
|
|
@@ -161,10 +161,10 @@ const functionsInvoke = async (nameArgument, options, command) => {
|
|
|
161
161
|
}
|
|
162
162
|
} else if (eventTriggeredFunctions.has(functionToTrigger)) {
|
|
163
163
|
/** handle event triggered fns */
|
|
164
|
-
// https://
|
|
164
|
+
// https://docs.netlify.com/functions/trigger-on-events/
|
|
165
165
|
const [name, event] = functionToTrigger.split('-')
|
|
166
166
|
if (name === 'identity') {
|
|
167
|
-
// https://
|
|
167
|
+
// https://docs.netlify.com/functions/functions-and-identity/#trigger-functions-on-identity-events
|
|
168
168
|
body.event = event
|
|
169
169
|
body.user = {
|
|
170
170
|
id: '1111a1a1-a11a-1111-aa11-aaa11111a11a',
|
|
@@ -182,7 +182,7 @@ const functionsInvoke = async (nameArgument, options, command) => {
|
|
|
182
182
|
}
|
|
183
183
|
} else {
|
|
184
184
|
// non identity functions seem to have a different shape
|
|
185
|
-
// https://
|
|
185
|
+
// https://docs.netlify.com/functions/trigger-on-events/#payload
|
|
186
186
|
body.payload = {
|
|
187
187
|
TODO: 'mock up payload data better',
|
|
188
188
|
}
|
|
@@ -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,10 +44,12 @@ 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,
|
|
50
51
|
state,
|
|
52
|
+
netlifyGraphConfig,
|
|
51
53
|
})
|
|
52
54
|
|
|
53
55
|
const { branch } = gitRepoInfo()
|
|
@@ -76,7 +78,7 @@ const graphEdit = async (options, command) => {
|
|
|
76
78
|
|
|
77
79
|
const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
|
|
78
80
|
await upsertMergeCLISessionMetadata({
|
|
79
|
-
|
|
81
|
+
config,
|
|
80
82
|
jwt,
|
|
81
83
|
siteId,
|
|
82
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 (
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
36
|
+
const userOperationName = args.operationName
|
|
37
|
+
const userCodegenId = options.codegen
|
|
41
38
|
|
|
42
39
|
let operationName = userOperationName
|
|
43
40
|
if (!operationName) {
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
89
|
-
|
|
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 (!
|
|
97
|
-
error(`
|
|
61
|
+
if (!codeGenerator) {
|
|
62
|
+
error(`Unable to select appropriate Netlify Graph code generator`)
|
|
63
|
+
return
|
|
98
64
|
}
|
|
99
65
|
|
|
100
|
-
|
|
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 }
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
const { Buffer } = require('buffer')
|
|
3
|
+
|
|
4
|
+
const { OneGraphClient } = require('netlify-onegraph-internal')
|
|
5
|
+
const { v4: uuidv4 } = require('uuid')
|
|
6
|
+
|
|
7
|
+
const { OneGraphCliClient, ensureCLISession } = require('../../lib/one-graph/cli-client')
|
|
8
|
+
const { getNetlifyGraphConfig } = require('../../lib/one-graph/cli-netlify-graph')
|
|
9
|
+
const { NETLIFYDEVERR, chalk, error, exit, getToken, log } = require('../../utils')
|
|
10
|
+
const { msg } = require('../login/login')
|
|
11
|
+
|
|
12
|
+
const { ensureAppForSite, executeCreateApiTokenMutation } = OneGraphCliClient
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Creates the `netlify graph:init` command
|
|
16
|
+
* @param {import('commander').OptionValues} options
|
|
17
|
+
* @param {import('../base-command').BaseCommand} command
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
const graphInit = async (options, command) => {
|
|
21
|
+
const { api, config, site, state } = command.netlify
|
|
22
|
+
const siteId = site.id
|
|
23
|
+
|
|
24
|
+
if (!siteId) {
|
|
25
|
+
error(
|
|
26
|
+
`${NETLIFYDEVERR} Warning: no siteId defined, unable to start Netlify Graph. To enable, run ${chalk.yellow(
|
|
27
|
+
'netlify init',
|
|
28
|
+
)} or ${chalk.yellow('netlify link')}`,
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let [netlifyToken, loginLocation] = await getToken()
|
|
33
|
+
if (!netlifyToken) {
|
|
34
|
+
netlifyToken = await command.authenticate()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let siteData = null
|
|
38
|
+
try {
|
|
39
|
+
// @ts-ignore: we need better types for our api object
|
|
40
|
+
siteData = await api.getSite({ siteId })
|
|
41
|
+
} catch (error_) {
|
|
42
|
+
if (netlifyToken && error_.status === 401) {
|
|
43
|
+
log(`Already logged in ${msg(loginLocation)}`)
|
|
44
|
+
log()
|
|
45
|
+
log(`Run ${chalk.cyanBright('netlify status')} for account details`)
|
|
46
|
+
log()
|
|
47
|
+
log(`or run ${chalk.cyanBright('netlify switch')} to switch accounts`)
|
|
48
|
+
log()
|
|
49
|
+
log(`To see all available commands run: ${chalk.cyanBright('netlify help')}`)
|
|
50
|
+
log()
|
|
51
|
+
return exit()
|
|
52
|
+
}
|
|
53
|
+
throw error_
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (netlifyToken == null) {
|
|
57
|
+
error(
|
|
58
|
+
`${NETLIFYDEVERR} Error: Unable to start Netlify Graph without a login. To enable, run ${chalk.yellow(
|
|
59
|
+
'netlify login',
|
|
60
|
+
)} first`,
|
|
61
|
+
)
|
|
62
|
+
return exit()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
await ensureAppForSite(netlifyToken, siteId)
|
|
66
|
+
|
|
67
|
+
const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options })
|
|
68
|
+
await ensureCLISession({
|
|
69
|
+
config,
|
|
70
|
+
metadata: {},
|
|
71
|
+
netlifyToken,
|
|
72
|
+
site,
|
|
73
|
+
state,
|
|
74
|
+
netlifyGraphConfig,
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
let envChanged = false
|
|
78
|
+
|
|
79
|
+
// Get current environment variables set in the UI
|
|
80
|
+
const {
|
|
81
|
+
build_settings: { env = {} },
|
|
82
|
+
} = siteData
|
|
83
|
+
|
|
84
|
+
const newEnv = {
|
|
85
|
+
...env,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!env.NETLIFY_GRAPH_WEBHOOK_SECRET) {
|
|
89
|
+
envChanged = true
|
|
90
|
+
const secret = Buffer.from(uuidv4()).toString('base64')
|
|
91
|
+
newEnv.NETLIFY_GRAPH_WEBHOOK_SECRET = secret
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!env.NETLIFY_GRAPH_PERSIST_QUERY_TOKEN) {
|
|
95
|
+
const variables = {
|
|
96
|
+
input: {
|
|
97
|
+
appId: siteId,
|
|
98
|
+
scopes: ['MODIFY_SCHEMA', 'PERSIST_QUERY'],
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
|
|
103
|
+
const result = await executeCreateApiTokenMutation(variables, {
|
|
104
|
+
siteId,
|
|
105
|
+
accessToken: jwt,
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
const token =
|
|
109
|
+
result.data &&
|
|
110
|
+
result.data.oneGraph &&
|
|
111
|
+
result.data.oneGraph.createApiToken &&
|
|
112
|
+
result.data.oneGraph.createApiToken.accessToken &&
|
|
113
|
+
result.data.oneGraph.createApiToken.accessToken.token
|
|
114
|
+
|
|
115
|
+
if (token) {
|
|
116
|
+
envChanged = true
|
|
117
|
+
newEnv.NETLIFY_GRAPH_PERSIST_QUERY_TOKEN = token
|
|
118
|
+
} else {
|
|
119
|
+
error(`Unable to create Netlify Graph persist query token: ${JSON.stringify(result.errors, null, 2)}`)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (envChanged) {
|
|
124
|
+
// Apply environment variable updates
|
|
125
|
+
// @ts-ignore
|
|
126
|
+
await api.updateSite({
|
|
127
|
+
siteId,
|
|
128
|
+
body: {
|
|
129
|
+
build_settings: {
|
|
130
|
+
env: newEnv,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
log(`Finished updating Graph-related environment variables for site ${siteData.name}`)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Creates the `netlify graph:init` command
|
|
141
|
+
* @param {import('../base-command').BaseCommand} program
|
|
142
|
+
* @returns
|
|
143
|
+
*/
|
|
144
|
+
const createGraphInitCommand = (program) =>
|
|
145
|
+
program
|
|
146
|
+
.command('graph:init')
|
|
147
|
+
.description('Initialize all the resources for Netlify Graph')
|
|
148
|
+
.action(async (options, command) => {
|
|
149
|
+
await graphInit(options, command)
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
module.exports = { createGraphInitCommand }
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
+
const { GraphQL } = require('netlify-onegraph-internal')
|
|
3
|
+
|
|
4
|
+
const { readLockfile } = require('../../lib/one-graph/cli-client')
|
|
2
5
|
const {
|
|
3
6
|
buildSchema,
|
|
4
7
|
defaultExampleOperationsDoc,
|
|
@@ -9,7 +12,7 @@ const {
|
|
|
9
12
|
readGraphQLOperationsSourceFile,
|
|
10
13
|
readGraphQLSchemaFile,
|
|
11
14
|
} = require('../../lib/one-graph/cli-netlify-graph')
|
|
12
|
-
const { error, log } = require('../../utils')
|
|
15
|
+
const { NETLIFYDEVERR, chalk, error, log } = require('../../utils')
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
18
|
* Creates the `netlify graph:library` command
|
|
@@ -18,10 +21,19 @@ const { error, log } = require('../../utils')
|
|
|
18
21
|
* @returns
|
|
19
22
|
*/
|
|
20
23
|
const graphLibrary = async (options, command) => {
|
|
24
|
+
const { config } = command.netlify
|
|
21
25
|
const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options })
|
|
22
26
|
|
|
23
27
|
const schemaString = readGraphQLSchemaFile(netlifyGraphConfig)
|
|
24
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
|
+
|
|
25
37
|
let schema
|
|
26
38
|
|
|
27
39
|
try {
|
|
@@ -32,24 +44,34 @@ const graphLibrary = async (options, command) => {
|
|
|
32
44
|
|
|
33
45
|
if (!schema) {
|
|
34
46
|
error(`Failed to parse Netlify GraphQL schema`)
|
|
47
|
+
return
|
|
35
48
|
}
|
|
36
49
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
const lockfile = readLockfile({ siteRoot: command.netlify.site.root })
|
|
51
|
+
|
|
52
|
+
if (lockfile === undefined) {
|
|
53
|
+
error(
|
|
54
|
+
`${NETLIFYDEVERR} Error: no lockfile found, unable to run \`netlify graph:library\`. To pull a remote schema (and create a lockfile), run ${chalk.yellow(
|
|
55
|
+
'netlify graph:pull',
|
|
56
|
+
)} `,
|
|
57
|
+
)
|
|
58
|
+
return
|
|
40
59
|
}
|
|
41
60
|
|
|
42
|
-
const
|
|
43
|
-
const { fragments, functions } = extractFunctionsFromOperationDoc(parsedDoc)
|
|
61
|
+
const { schemaId } = lockfile.locked
|
|
44
62
|
|
|
45
|
-
|
|
63
|
+
const payload = {
|
|
64
|
+
config,
|
|
46
65
|
logger: log,
|
|
47
66
|
netlifyGraphConfig,
|
|
48
67
|
schema,
|
|
68
|
+
schemaId,
|
|
49
69
|
operationsDoc: currentOperationsDoc,
|
|
50
70
|
functions,
|
|
51
71
|
fragments,
|
|
52
|
-
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
generateFunctionsFile(payload)
|
|
53
75
|
}
|
|
54
76
|
|
|
55
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
|
|