netlify-cli 10.9.1 → 10.10.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.
Files changed (66) hide show
  1. package/npm-shrinkwrap.json +16 -115
  2. package/package.json +2 -2
  3. package/src/commands/functions/functions-create.js +112 -14
  4. package/src/commands/graph/graph-edit.js +3 -1
  5. package/src/functions-templates/go/hello-world/.netlify-function-template.js +1 -0
  6. package/src/functions-templates/javascript/apollo-graphql/.netlify-function-template.js +1 -0
  7. package/src/functions-templates/javascript/apollo-graphql-rest/.netlify-function-template.js +1 -0
  8. package/src/functions-templates/javascript/auth-fetch/.netlify-function-template.js +1 -0
  9. package/src/functions-templates/javascript/create-user/.netlify-function-template.js +1 -0
  10. package/src/functions-templates/javascript/fauna-crud/.netlify-function-template.js +1 -0
  11. package/src/functions-templates/javascript/fauna-graphql/.netlify-function-template.js +1 -0
  12. package/src/functions-templates/javascript/google-analytics/.netlify-function-template.js +1 -0
  13. package/src/functions-templates/javascript/graphql-gateway/.netlify-function-template.js +1 -0
  14. package/src/functions-templates/javascript/hasura-event-triggered/.netlify-function-template.js +1 -0
  15. package/src/functions-templates/javascript/hello/.netlify-function-template.js +5 -0
  16. package/src/functions-templates/javascript/hello/{{name}}.js +5 -0
  17. package/src/functions-templates/javascript/hello-world/.netlify-function-template.js +1 -0
  18. package/src/functions-templates/javascript/identity-signup/.netlify-function-template.js +1 -0
  19. package/src/functions-templates/javascript/image-external/.netlify-function-template.js +5 -0
  20. package/src/functions-templates/javascript/image-external/{{name}}.js +12 -0
  21. package/src/functions-templates/javascript/localized-content/.netlify-function-template.js +5 -0
  22. package/src/functions-templates/javascript/localized-content/{{name}}.js +15 -0
  23. package/src/functions-templates/javascript/node-fetch/.netlify-function-template.js +1 -0
  24. package/src/functions-templates/javascript/oauth-passport/.netlify-function-template.js +1 -0
  25. package/src/functions-templates/javascript/protected-function/.netlify-function-template.js +1 -0
  26. package/src/functions-templates/javascript/sanity-create/.netlify-function-template.js +1 -0
  27. package/src/functions-templates/javascript/sanity-groq/.netlify-function-template.js +1 -0
  28. package/src/functions-templates/javascript/scheduled-function/.netlify-function-template.js +1 -0
  29. package/src/functions-templates/javascript/send-email/.netlify-function-template.js +1 -0
  30. package/src/functions-templates/javascript/serverless-ssr/.netlify-function-template.js +1 -0
  31. package/src/functions-templates/javascript/set-cookie/.netlify-function-template.js +1 -0
  32. package/src/functions-templates/javascript/set-cookies/.netlify-function-template.js +5 -0
  33. package/src/functions-templates/javascript/set-cookies/{{name}}.js +28 -0
  34. package/src/functions-templates/javascript/set-req-header/.netlify-function-template.js +5 -0
  35. package/src/functions-templates/javascript/set-req-header/{{name}}.js +3 -0
  36. package/src/functions-templates/javascript/set-res-header/.netlify-function-template.js +5 -0
  37. package/src/functions-templates/javascript/set-res-header/{{name}}.js +5 -0
  38. package/src/functions-templates/javascript/slack-rate-limit/.netlify-function-template.js +1 -0
  39. package/src/functions-templates/javascript/stripe-charge/.netlify-function-template.js +1 -0
  40. package/src/functions-templates/javascript/stripe-subscription/.netlify-function-template.js +1 -0
  41. package/src/functions-templates/javascript/submission-created/.netlify-function-template.js +1 -0
  42. package/src/functions-templates/javascript/token-hider/.netlify-function-template.js +1 -0
  43. package/src/functions-templates/javascript/transform-response/.netlify-function-template.js +5 -0
  44. package/src/functions-templates/javascript/transform-response/{{name}}.js +12 -0
  45. package/src/functions-templates/javascript/url-shortener/.netlify-function-template.js +1 -0
  46. package/src/functions-templates/javascript/using-middleware/.netlify-function-template.js +1 -0
  47. package/src/functions-templates/rust/hello-world/.netlify-function-template.js +1 -0
  48. package/src/functions-templates/typescript/abtest/.netlify-function-template.js +5 -0
  49. package/src/functions-templates/typescript/abtest/{{name}}.ts +31 -0
  50. package/src/functions-templates/typescript/geolocation/.netlify-function-template.js +5 -0
  51. package/src/functions-templates/typescript/geolocation/{{name}}.ts +24 -0
  52. package/src/functions-templates/typescript/hello-world/.netlify-function-template.js +1 -0
  53. package/src/functions-templates/typescript/json/.netlify-function-template.js +5 -0
  54. package/src/functions-templates/typescript/json/{{name}}.ts +5 -0
  55. package/src/functions-templates/typescript/log/.netlify-function-template.js +5 -0
  56. package/src/functions-templates/typescript/log/{{name}}.ts +9 -0
  57. package/src/functions-templates/typescript/scheduled-function/.netlify-function-template.js +1 -0
  58. package/src/functions-templates/typescript/set-cookies/.netlify-function-template.js +5 -0
  59. package/src/functions-templates/typescript/set-cookies/{{name}}.ts +29 -0
  60. package/src/functions-templates/typescript/set-req-header/.netlify-function-template.js +5 -0
  61. package/src/functions-templates/typescript/set-req-header/{{name}}.ts +5 -0
  62. package/src/functions-templates/typescript/set-res-header/.netlify-function-template.js +5 -0
  63. package/src/functions-templates/typescript/set-res-header/{{name}}.ts +7 -0
  64. package/src/functions-templates/typescript/transform-response/.netlify-function-template.js +5 -0
  65. package/src/functions-templates/typescript/transform-response/{{name}}.ts +14 -0
  66. package/src/lib/one-graph/cli-client.js +10 -11
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
- "version": "10.9.1",
3
+ "version": "10.10.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "netlify-cli",
9
- "version": "10.9.1",
9
+ "version": "10.10.0",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
@@ -115,7 +115,7 @@
115
115
  "unixify": "^1.0.0",
116
116
  "update-notifier": "^5.0.0",
117
117
  "uuid": "^8.0.0",
118
- "wait-port": "^0.2.14",
118
+ "wait-port": "^0.3.0",
119
119
  "winston": "^3.2.1",
120
120
  "write-file-atomic": "^4.0.0"
121
121
  },
@@ -22454,75 +22454,19 @@
22454
22454
  }
22455
22455
  },
22456
22456
  "node_modules/wait-port": {
22457
- "version": "0.2.14",
22458
- "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-0.2.14.tgz",
22459
- "integrity": "sha512-kIzjWcr6ykl7WFbZd0TMae8xovwqcqbx6FM9l+7agOgUByhzdjfzZBPK2CPufldTOMxbUivss//Sh9MFawmPRQ==",
22457
+ "version": "0.3.0",
22458
+ "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-0.3.0.tgz",
22459
+ "integrity": "sha512-seNQ7j92tG5uaylFK3RrAajajzpNMOr96pcCsD8cWGtVn4XXsFUMf9vzNcZSXVaMEfuZT/0t/Wc0KN+m74QYkw==",
22460
22460
  "dependencies": {
22461
- "chalk": "^2.4.2",
22462
- "commander": "^3.0.2",
22463
- "debug": "^4.1.1"
22461
+ "chalk": "^4.1.2",
22462
+ "commander": "^9.3.0",
22463
+ "debug": "^4.3.4"
22464
22464
  },
22465
22465
  "bin": {
22466
22466
  "wait-port": "bin/wait-port.js"
22467
22467
  },
22468
22468
  "engines": {
22469
- "node": ">=8"
22470
- }
22471
- },
22472
- "node_modules/wait-port/node_modules/ansi-styles": {
22473
- "version": "3.2.1",
22474
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
22475
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
22476
- "dependencies": {
22477
- "color-convert": "^1.9.0"
22478
- },
22479
- "engines": {
22480
- "node": ">=4"
22481
- }
22482
- },
22483
- "node_modules/wait-port/node_modules/chalk": {
22484
- "version": "2.4.2",
22485
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
22486
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
22487
- "dependencies": {
22488
- "ansi-styles": "^3.2.1",
22489
- "escape-string-regexp": "^1.0.5",
22490
- "supports-color": "^5.3.0"
22491
- },
22492
- "engines": {
22493
- "node": ">=4"
22494
- }
22495
- },
22496
- "node_modules/wait-port/node_modules/commander": {
22497
- "version": "3.0.2",
22498
- "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz",
22499
- "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow=="
22500
- },
22501
- "node_modules/wait-port/node_modules/escape-string-regexp": {
22502
- "version": "1.0.5",
22503
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
22504
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
22505
- "engines": {
22506
- "node": ">=0.8.0"
22507
- }
22508
- },
22509
- "node_modules/wait-port/node_modules/has-flag": {
22510
- "version": "3.0.0",
22511
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
22512
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
22513
- "engines": {
22514
- "node": ">=4"
22515
- }
22516
- },
22517
- "node_modules/wait-port/node_modules/supports-color": {
22518
- "version": "5.5.0",
22519
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
22520
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
22521
- "dependencies": {
22522
- "has-flag": "^3.0.0"
22523
- },
22524
- "engines": {
22525
- "node": ">=4"
22469
+ "node": ">=10"
22526
22470
  }
22527
22471
  },
22528
22472
  "node_modules/wcwidth": {
@@ -39552,56 +39496,13 @@
39552
39496
  }
39553
39497
  },
39554
39498
  "wait-port": {
39555
- "version": "0.2.14",
39556
- "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-0.2.14.tgz",
39557
- "integrity": "sha512-kIzjWcr6ykl7WFbZd0TMae8xovwqcqbx6FM9l+7agOgUByhzdjfzZBPK2CPufldTOMxbUivss//Sh9MFawmPRQ==",
39499
+ "version": "0.3.0",
39500
+ "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-0.3.0.tgz",
39501
+ "integrity": "sha512-seNQ7j92tG5uaylFK3RrAajajzpNMOr96pcCsD8cWGtVn4XXsFUMf9vzNcZSXVaMEfuZT/0t/Wc0KN+m74QYkw==",
39558
39502
  "requires": {
39559
- "chalk": "^2.4.2",
39560
- "commander": "^3.0.2",
39561
- "debug": "^4.1.1"
39562
- },
39563
- "dependencies": {
39564
- "ansi-styles": {
39565
- "version": "3.2.1",
39566
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
39567
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
39568
- "requires": {
39569
- "color-convert": "^1.9.0"
39570
- }
39571
- },
39572
- "chalk": {
39573
- "version": "2.4.2",
39574
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
39575
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
39576
- "requires": {
39577
- "ansi-styles": "^3.2.1",
39578
- "escape-string-regexp": "^1.0.5",
39579
- "supports-color": "^5.3.0"
39580
- }
39581
- },
39582
- "commander": {
39583
- "version": "3.0.2",
39584
- "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz",
39585
- "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow=="
39586
- },
39587
- "escape-string-regexp": {
39588
- "version": "1.0.5",
39589
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
39590
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
39591
- },
39592
- "has-flag": {
39593
- "version": "3.0.0",
39594
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
39595
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
39596
- },
39597
- "supports-color": {
39598
- "version": "5.5.0",
39599
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
39600
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
39601
- "requires": {
39602
- "has-flag": "^3.0.0"
39603
- }
39604
- }
39503
+ "chalk": "^4.1.2",
39504
+ "commander": "^9.3.0",
39505
+ "debug": "^4.3.4"
39605
39506
  }
39606
39507
  },
39607
39508
  "wcwidth": {
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.9.1",
4
+ "version": "10.10.0",
5
5
  "author": "Netlify Inc.",
6
6
  "contributors": [
7
7
  "Abraham Schilling <AbrahamSchilling@gmail.com> (https://gitlab.com/n4bb12)",
@@ -321,7 +321,7 @@
321
321
  "unixify": "^1.0.0",
322
322
  "update-notifier": "^5.0.0",
323
323
  "uuid": "^8.0.0",
324
- "wait-port": "^0.2.14",
324
+ "wait-port": "^0.3.0",
325
325
  "winston": "^3.2.1",
326
326
  "write-file-atomic": "^4.0.0"
327
327
  },
@@ -93,13 +93,17 @@ const filterRegistry = function (registry, input) {
93
93
  })
94
94
  }
95
95
 
96
- const formatRegistryArrayForInquirer = function (lang) {
96
+ const formatRegistryArrayForInquirer = function (lang, funcType) {
97
97
  const folderNames = fs.readdirSync(path.join(templatesDir, lang))
98
98
  const registry = folderNames
99
99
  // filter out markdown files
100
100
  .filter((folderName) => !folderName.endsWith('.md'))
101
- // eslint-disable-next-line n/global-require, import/no-dynamic-require
102
- .map((folderName) => require(path.join(templatesDir, lang, folderName, '.netlify-function-template.js')))
101
+
102
+ .map((folderName) =>
103
+ // eslint-disable-next-line n/global-require, import/no-dynamic-require
104
+ require(path.join(templatesDir, lang, folderName, '.netlify-function-template.js')),
105
+ )
106
+ .filter((folderName) => folderName.functionType === funcType)
103
107
  .sort((folderNameA, folderNameB) => {
104
108
  const priorityDiff = (folderNameA.priority || DEFAULT_PRIORITY) - (folderNameB.priority || DEFAULT_PRIORITY)
105
109
 
@@ -128,8 +132,9 @@ const formatRegistryArrayForInquirer = function (lang) {
128
132
  /**
129
133
  * pick template from our existing templates
130
134
  * @param {import('commander').OptionValues} config
135
+ *
131
136
  */
132
- const pickTemplate = async function ({ language: languageFromFlag }) {
137
+ const pickTemplate = async function ({ language: languageFromFlag }, funcType) {
133
138
  const specialCommands = [
134
139
  new inquirer.Separator(),
135
140
  {
@@ -148,8 +153,13 @@ const pickTemplate = async function ({ language: languageFromFlag }) {
148
153
  let language = languageFromFlag
149
154
 
150
155
  if (language === undefined) {
156
+ const langs =
157
+ funcType === 'edge'
158
+ ? languages.filter((lang) => lang.value === 'javascript' || lang.value === 'typescript')
159
+ : languages.filter(Boolean)
160
+
151
161
  const { language: languageFromPrompt } = await inquirer.prompt({
152
- choices: languages.filter(Boolean),
162
+ choices: langs,
153
163
  message: 'Select the language of your function',
154
164
  name: 'language',
155
165
  type: 'list',
@@ -163,7 +173,7 @@ const pickTemplate = async function ({ language: languageFromFlag }) {
163
173
  let templatesForLanguage
164
174
 
165
175
  try {
166
- templatesForLanguage = formatRegistryArrayForInquirer(language)
176
+ templatesForLanguage = formatRegistryArrayForInquirer(language, funcType)
167
177
  } catch {
168
178
  throw error(`Invalid language: ${language}`)
169
179
  }
@@ -173,12 +183,16 @@ const pickTemplate = async function ({ language: languageFromFlag }) {
173
183
  message: 'Pick a template',
174
184
  type: 'autocomplete',
175
185
  source(answersSoFar, input) {
186
+ // if Edge Functions template, don't show url option
187
+ const edgeCommands = specialCommands.filter((val) => val.value !== 'url')
188
+ const parsedSpecialCommands = funcType === 'edge' ? edgeCommands : specialCommands
189
+
176
190
  if (!input || input === '') {
177
191
  // show separators
178
- return [...templatesForLanguage, ...specialCommands]
192
+ return [...templatesForLanguage, ...parsedSpecialCommands]
179
193
  }
180
194
  // only show filtered results sorted by score
181
- const answers = [...filterRegistry(templatesForLanguage, input), ...specialCommands].sort(
195
+ const answers = [...filterRegistry(templatesForLanguage, input), ...parsedSpecialCommands].sort(
182
196
  (answerA, answerB) => answerB.score - answerA.score,
183
197
  )
184
198
  return answers
@@ -189,6 +203,50 @@ const pickTemplate = async function ({ language: languageFromFlag }) {
189
203
 
190
204
  const DEFAULT_PRIORITY = 999
191
205
 
206
+ const selectTypeOfFunc = async () => {
207
+ const functionTypes = [
208
+ { name: 'Edge function (Deno)', value: 'edge' },
209
+ { name: 'Serverless function (Node/Go)', value: 'serverless' },
210
+ ]
211
+
212
+ const { functionType } = await inquirer.prompt([
213
+ {
214
+ name: 'functionType',
215
+ message: "Select the type of function you'd like to create",
216
+ type: 'list',
217
+ choices: functionTypes,
218
+ },
219
+ ])
220
+ return functionType
221
+ }
222
+
223
+ const ensureEdgeFuncDirExists = function (command) {
224
+ const { config, site } = command.netlify
225
+ const siteId = site.id
226
+ let functionsDirHolder = config.build.edge_functions
227
+
228
+ if (!siteId) {
229
+ error(`${NETLIFYDEVERR} No site id found, please run inside a site directory or \`netlify link\``)
230
+ }
231
+
232
+ if (!functionsDirHolder) {
233
+ functionsDirHolder = 'netlify/edge-functions'
234
+ }
235
+
236
+ if (!fs.existsSync(functionsDirHolder)) {
237
+ log(
238
+ `${NETLIFYDEVLOG} Edge Functions directory ${chalk.magenta.inverse(
239
+ functionsDirHolder,
240
+ )} does not exist yet, creating it...`,
241
+ )
242
+
243
+ fs.mkdirSync(functionsDirHolder, { recursive: true })
244
+
245
+ log(`${NETLIFYDEVLOG} Edge Functions directory ${chalk.magenta.inverse(functionsDirHolder)} created.`)
246
+ }
247
+ return functionsDirHolder
248
+ }
249
+
192
250
  /**
193
251
  * Get functions directory (and make it if necessary)
194
252
  * @param {import('../base-command').BaseCommand} command
@@ -248,7 +306,6 @@ const ensureFunctionDirExists = async function (command) {
248
306
 
249
307
  log(`${NETLIFYDEVLOG} functions directory ${chalk.magenta.inverse(functionsDirHolder)} created`)
250
308
  }
251
-
252
309
  return functionsDirHolder
253
310
  }
254
311
 
@@ -371,10 +428,12 @@ const installDeps = async ({ functionPackageJson, functionPath, functionsDir })
371
428
  * @param {import('commander').OptionValues} options
372
429
  * @param {string} argumentName
373
430
  * @param {string} functionsDir
431
+ * @param {string} funcType
374
432
  */
375
- const scaffoldFromTemplate = async function (command, options, argumentName, functionsDir) {
433
+ // eslint-disable-next-line max-params
434
+ const scaffoldFromTemplate = async function (command, options, argumentName, functionsDir, funcType) {
376
435
  // pull the rest of the metadata from the template
377
- const chosenTemplate = await pickTemplate(options)
436
+ const chosenTemplate = await pickTemplate(options, funcType)
378
437
  if (chosenTemplate === 'url') {
379
438
  const { chosenUrl } = await inquirer.prompt([
380
439
  {
@@ -398,7 +457,6 @@ const scaffoldFromTemplate = async function (command, options, argumentName, fun
398
457
  log(`${NETLIFYDEVLOG} Open in browser: https://github.com/netlify/cli/issues/new`)
399
458
  } else {
400
459
  const { onComplete, name: templateName, lang, addons = [] } = chosenTemplate
401
-
402
460
  const pathToTemplate = path.join(templatesDir, lang, templateName)
403
461
  if (!fs.existsSync(pathToTemplate)) {
404
462
  throw new Error(
@@ -444,6 +502,10 @@ const scaffoldFromTemplate = async function (command, options, argumentName, fun
444
502
  spinner.succeed(`Installed dependencies for ${name}`)
445
503
  }
446
504
 
505
+ if (funcType === 'edge') {
506
+ registerEFInToml(name)
507
+ }
508
+
447
509
  await installAddons(command, addons, path.resolve(functionPath))
448
510
  await handleOnComplete({ command, onComplete })
449
511
  }
@@ -565,6 +627,40 @@ const installAddons = async function (command, functionAddons, fnPath) {
565
627
  return Promise.all(arr)
566
628
  }
567
629
 
630
+ const registerEFInToml = async (funcName) => {
631
+ if (!fs.existsSync('netlify.toml')) {
632
+ log(`${NETLIFYDEVLOG} \`netlify.toml\` file does not exist yet. Creating it...`)
633
+ }
634
+
635
+ let { funcPath } = await inquirer.prompt([
636
+ {
637
+ type: 'input',
638
+ name: 'funcPath',
639
+ message: `What route do you want your edge function to be invoked on?`,
640
+ default: '/test',
641
+ validate: (val) => Boolean(val),
642
+ // Make sure route isn't undefined and is valid
643
+ // Todo: add more validation?
644
+ },
645
+ ])
646
+
647
+ // Make sure path begins with a '/'
648
+ if (funcPath[0] !== '/') {
649
+ funcPath = `/${funcPath}`
650
+ }
651
+
652
+ const functionRegister = `\n\n[[edge_functions]]\nfunction = "${funcName}"\npath = "${funcPath}"`
653
+
654
+ try {
655
+ fs.promises.appendFile('netlify.toml', functionRegister)
656
+ log(
657
+ `${NETLIFYDEVLOG} Function '${funcName}' registered for route \`${funcPath}\`. To change, edit your \`netlify.toml\` file.`,
658
+ )
659
+ } catch {
660
+ error(`${NETLIFYDEVERR} Unable to register function. Please check your \`netlify.toml\` file.`)
661
+ }
662
+ }
663
+
568
664
  // we used to allow for a --dir command,
569
665
  // but have retired that to force every scaffolded function to be a directory
570
666
  const ensureFunctionPathIsOk = function (functionsDir, name) {
@@ -582,11 +678,13 @@ const ensureFunctionPathIsOk = function (functionsDir, name) {
582
678
  * @param {import('../base-command').BaseCommand} command
583
679
  */
584
680
  const functionsCreate = async (name, options, command) => {
585
- const functionsDir = await ensureFunctionDirExists(command)
681
+ const functionType = await selectTypeOfFunc()
682
+ const functionsDir =
683
+ functionType === 'edge' ? await ensureEdgeFuncDirExists(command) : await ensureFunctionDirExists(command)
586
684
 
587
685
  /* either download from URL or scaffold from template */
588
686
  const mainFunc = options.url ? downloadFromURL : scaffoldFromTemplate
589
- await mainFunc(command, options, name, functionsDir)
687
+ await mainFunc(command, options, name, functionsDir, functionType)
590
688
  }
591
689
 
592
690
  /**
@@ -1,5 +1,6 @@
1
1
  // @ts-check
2
2
  const gitRepoInfo = require('git-repo-info')
3
+ const { OneGraphClient } = require('netlify-onegraph-internal')
3
4
 
4
5
  const { OneGraphCliClient, ensureCLISession, upsertMergeCLISessionMetadata } = require('../../lib/one-graph/cli-client')
5
6
  const {
@@ -73,9 +74,10 @@ const graphEdit = async (options, command) => {
73
74
 
74
75
  const newMetadata = { docId: persistedDoc.id }
75
76
 
77
+ const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
76
78
  await upsertMergeCLISessionMetadata({
77
79
  netlifyGraphConfig,
78
- netlifyToken,
80
+ jwt,
79
81
  siteId,
80
82
  siteRoot: site.root,
81
83
  oneGraphSessionId,
@@ -2,4 +2,5 @@ module.exports = {
2
2
  name: 'hello-world',
3
3
  priority: 1,
4
4
  description: 'Basic function that shows how to create a handler and return a response',
5
+ functionType: 'serverless',
5
6
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'apollo-graphql',
3
3
  description: 'GraphQL function using Apollo-Server-Lambda!',
4
+ functionType: 'serverless',
4
5
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'apollo-graphql-rest',
3
3
  description: 'GraphQL function to wrap REST API using apollo-server-lambda and apollo-datasource-rest!',
4
+ functionType: 'serverless',
4
5
  }
@@ -1,6 +1,7 @@
1
1
  module.exports = {
2
2
  name: 'auth-fetch',
3
3
  description: 'Use `node-fetch` library and Netlify Identity to access APIs',
4
+ functionType: 'serverless',
4
5
  onComplete() {
5
6
  console.log(`auth-fetch function created from template!`)
6
7
  console.log(
@@ -1,6 +1,7 @@
1
1
  module.exports = {
2
2
  name: 'create-user',
3
3
  description: 'Programmatically create a Netlify Identity user by invoking a function',
4
+ functionType: 'serverless',
4
5
  onComplete() {
5
6
  console.log(`create-user function created from template!`)
6
7
  console.log(
@@ -2,6 +2,7 @@ const execa = require('execa')
2
2
  module.exports = {
3
3
  name: 'fauna-crud',
4
4
  description: 'CRUD function using Fauna DB',
5
+ functionType: 'serverless',
5
6
  addons: [
6
7
  {
7
8
  addonName: 'fauna',
@@ -2,6 +2,7 @@ const execa = require('execa')
2
2
  module.exports = {
3
3
  name: 'fauna-graphql',
4
4
  description: 'GraphQL Backend using Fauna DB',
5
+ functionType: 'serverless',
5
6
  addons: [
6
7
  {
7
8
  addonName: 'fauna',
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'google-analytics',
3
3
  description: 'Google Analytics: proxy for GA on your domain to avoid adblock',
4
+ functionType: 'serverless',
4
5
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'graphql-gateway',
3
3
  description: 'Apollo Server Lambda Gateway stitching schemas from other GraphQL Functions!',
4
+ functionType: 'serverless',
4
5
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'hasura-event-triggered',
3
3
  description: 'Hasura Cleaning: process a Hasura event and fire off a GraphQL mutation with processed text data',
4
+ functionType: 'serverless',
4
5
  }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'hello',
3
+ description: 'Basic function that shows async/await usage, and response formatting',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,5 @@
1
+ export default async (request) => {
2
+ return new Response('Hello, World!', {
3
+ headers: { 'content-type': 'text/html' },
4
+ })
5
+ }
@@ -2,4 +2,5 @@ module.exports = {
2
2
  name: 'hello-world',
3
3
  priority: 1,
4
4
  description: 'Basic function that shows async/await usage, and response formatting',
5
+ functionType: 'serverless',
5
6
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'identity-signup',
3
3
  description: 'Identity Signup: Triggered when a new Netlify Identity user confirms. Assigns roles and extra metadata',
4
+ functionType: 'serverless',
4
5
  }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'image-external',
3
+ description: 'Fetches and serves an image from an external site',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,12 @@
1
+ export default async (request, context) => {
2
+ // Return an internal image using context.rewrite()
3
+ // This image is stored in the /public directory of this project
4
+
5
+ // return context.rewrite("/apple-touch-icon.png");
6
+
7
+ // OR
8
+
9
+ // Use fetch() and return the image response
10
+ const kitten = await fetch('https://placekitten.com/g/300/300')
11
+ return kitten
12
+ }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'localized-content',
3
+ description: 'Uses geolocation data to serve localized countent according to country code',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,15 @@
1
+ export default async (request, context) => {
2
+ const translations = {
3
+ UNKNOWN: 'Hello!',
4
+ US: "Howdy y'all!",
5
+ GB: 'How do you do?',
6
+ AU: "G'day, mate!",
7
+ }
8
+
9
+ const countryCode = context.geo?.country?.code || 'UNKNOWN'
10
+ const countryName = context.geo?.country?.name || 'somewhere in the world'
11
+
12
+ return new Response(`Your personalized greeting for ${countryName} is: ${translations[countryCode]}`, {
13
+ headers: { 'content-type': 'text/html' },
14
+ })
15
+ }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'node-fetch',
3
3
  description: 'Fetch function: uses node-fetch to hit an external API without CORS issues',
4
+ functionType: 'serverless',
4
5
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'oauth-passport',
3
3
  description: 'oauth-passport: template for Oauth workflow using Passport + Express.js',
4
+ functionType: 'serverless',
4
5
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'protected-function',
3
3
  description: 'Function protected Netlify Identity authentication',
4
+ functionType: 'serverless',
4
5
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'sanity-create',
3
3
  description: 'Create documents in Sanity.io',
4
+ functionType: 'serverless',
4
5
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'sanity-groq',
3
3
  description: 'Query a Sanity.io dataset with GROQ',
4
+ functionType: 'serverless',
4
5
  }
@@ -2,4 +2,5 @@ module.exports = {
2
2
  name: 'scheduled-function',
3
3
  priority: 1,
4
4
  description: 'Basic implementation of a scheduled function in JavaScript.',
5
+ functionType: 'serverless',
5
6
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'send-email',
3
3
  description: "Send Email: Send email with no SMTP server via 'sendmail' pkg",
4
+ functionType: 'serverless',
4
5
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'serverless-ssr',
3
3
  description: 'Dynamic serverside rendering via functions',
4
+ functionType: 'serverless',
4
5
  }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'set-cookie',
3
3
  description: 'Set a cookie alongside your function',
4
+ functionType: 'serverless',
4
5
  }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'set-cookies',
3
+ description: 'Create and manage HTTP cookies',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,28 @@
1
+ export default async (request, context) => {
2
+ const url = new URL(request.url)
3
+
4
+ switch (url.searchParams.get('action')) {
5
+ case 'set':
6
+ context.cookies.set({
7
+ name: 'action',
8
+ value: 'hello',
9
+ })
10
+
11
+ return new Response('Cookie value has been set. Reload this page without the "action" parameter to see it.')
12
+
13
+ case 'clear':
14
+ context.cookies.delete('action')
15
+
16
+ return new Response(
17
+ 'Cookie value has been cleared. Reload this page without the "action" parameter to see the new state.',
18
+ )
19
+ default:
20
+ }
21
+
22
+ const value = context.cookies.get('action')
23
+ const message = value
24
+ ? `Cookie value is "${value}". You can clear it by using "?action=clear".`
25
+ : 'Cookie has not been set. You can do so by adding "?action=set" to the URL.'
26
+
27
+ return new Response(message)
28
+ }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'set-req-header',
3
+ description: 'Adds a custom HTTP header to HTTP request.',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,3 @@
1
+ export default async (request, context) => {
2
+ request.headers.set('X-Your-Custom-Header', 'Your custom header value')
3
+ }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'set-res-header',
3
+ description: 'Adds a custom HTTP header to HTTP response.',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,5 @@
1
+ export default async (request, context) => {
2
+ const response = await context.next()
3
+ response.headers.set('X-Your-Custom-Header', 'A custom value')
4
+ return response
5
+ }
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'slack-rate-limit',
3
3
  description: 'Slack Rate-limit: post to Slack, at most once an hour, using Netlify Identity metadata',
4
+ functionType: 'serverless',
4
5
  }
@@ -3,6 +3,7 @@ const chalk = require('chalk')
3
3
  module.exports = {
4
4
  name: 'stripe-charge',
5
5
  description: 'Stripe Charge: Charge a user with Stripe',
6
+ functionType: 'serverless',
6
7
  async onComplete() {
7
8
  console.log(`${chalk.yellow('stripe-charge')} function created from template!`)
8
9
  if (!process.env.STRIPE_SECRET_KEY) {
@@ -3,6 +3,7 @@ const chalk = require('chalk')
3
3
  module.exports = {
4
4
  name: 'stripe-subscription',
5
5
  description: 'Stripe subscription: Create a subscription with Stripe',
6
+ functionType: 'serverless',
6
7
  async onComplete() {
7
8
  console.log(`${chalk.yellow('stripe-subscription')} function created from template!`)
8
9
  if (!process.env.STRIPE_SECRET_KEY) {
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'submission-created',
3
3
  description: 'submission-created: template for event triggered function when a new Netlify Form is submitted',
4
+ functionType: 'serverless',
4
5
  }
@@ -3,6 +3,7 @@ const chalk = require('chalk')
3
3
  module.exports = {
4
4
  name: 'token-hider',
5
5
  description: 'Token Hider: access APIs without exposing your API keys',
6
+ functionType: 'serverless',
6
7
  async onComplete() {
7
8
  console.log(`${chalk.yellow('token-hider')} function created from template!`)
8
9
  if (!process.env.API_URL || !process.env.API_TOKEN) {
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'transform-response',
3
+ description: 'Transform the content of an HTTP response',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,12 @@
1
+ export default async (request, context) => {
2
+ const url = new URL(request.url)
3
+
4
+ // Look for the query parameter, and return if we don't find it
5
+ if (url.searchParams.get('method') !== 'transform') {
6
+ return
7
+ }
8
+
9
+ const response = await context.next()
10
+ const text = await response.text()
11
+ return new Response(text.toUpperCase(), response)
12
+ }
@@ -3,6 +3,7 @@ const chalk = require('chalk')
3
3
  module.exports = {
4
4
  name: 'url-shortener',
5
5
  description: 'URL Shortener: simple URL shortener with Netlify Forms!',
6
+ functionType: 'serverless',
6
7
  async onComplete() {
7
8
  console.log(`${chalk.yellow('url-shortener')} function created from template!`)
8
9
  if (!process.env.ROUTES_FORM_ID || !process.env.API_AUTH) {
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  name: 'using-middleware',
3
3
  description: 'Using Middleware with middy',
4
+ functionType: 'serverless',
4
5
  }
@@ -2,4 +2,5 @@ module.exports = {
2
2
  name: 'hello-world',
3
3
  priority: 1,
4
4
  description: 'Basic function that shows how to create a handler and return a response',
5
+ functionType: 'serverless',
5
6
  }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'abtest',
3
+ description: "Function that randomly assigns users to group 'a' or 'b' and sets this value as a cookie.",
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,31 @@
1
+ import type { Context } from "netlify:edge";
2
+
3
+ export default async (request: Request, context: Context) => {
4
+ // look for existing "test_bucket" cookie
5
+ const bucketName = "test_bucket";
6
+ const bucket = context.cookies.get(bucketName);
7
+
8
+ // return here if we find a cookie
9
+ if (bucket) {
10
+ return new Response(`Welcome back! You were assigned ${bucketName} **${bucket}** when you last visited the site!`);
11
+ }
12
+
13
+ // if no "test_bucket" cookie is found, assign the user to a bucket
14
+ // in this example we're using two buckets (a, b) with an equal weighting of 50/50
15
+ const weighting = 0.5;
16
+
17
+ // get a random number between (0-1)
18
+ // this is a basic example and you may want to experiment
19
+ const random = Math.random();
20
+ const newBucketValue = random <= weighting ? "a" : "b";
21
+
22
+ // set the new "test_bucket" cookie
23
+ context.cookies.set({
24
+ name: bucketName,
25
+ value: newBucketValue,
26
+ });
27
+
28
+ return new Response(
29
+ `Congratulations! You have been assigned ${bucketName} **${newBucketValue}**. View your browser cookies to check it out!`,
30
+ );
31
+ };
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'geolocation',
3
+ description: "Returns info about user's geolocation, which can be used to serve location-specific content.",
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,24 @@
1
+ import { Context } from "netlify:edge";
2
+
3
+ export default async (request: Request, context: Context) => {
4
+ // Here's what's available on context.geo
5
+
6
+ // context: {
7
+ // geo: {
8
+ // city?: string;
9
+ // country?: {
10
+ // code?: string;
11
+ // name?: string;
12
+ // },
13
+ // subdivision?: {
14
+ // code?: string;
15
+ // name?: string;
16
+ // },
17
+ // }
18
+ // }
19
+
20
+ return context.json({
21
+ geo: context.geo,
22
+ header: request.headers.get("x-nf-geo"),
23
+ });
24
+ };
@@ -2,4 +2,5 @@ module.exports = {
2
2
  name: 'hello-world',
3
3
  priority: 1,
4
4
  description: 'Basic function that shows async/await usage, and response formatting',
5
+ functionType: 'serverless',
5
6
  }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'json',
3
+ description: 'Function that returns a simple json response',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,5 @@
1
+ import type { Context } from "netlify:edge";
2
+
3
+ export default async (request: Request, context: Context) => {
4
+ return context.json({ hello: "world" });
5
+ };
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'log',
3
+ description: 'Basic function logging context of request',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,9 @@
1
+ import type { Context } from "netlify:edge";
2
+
3
+ export default async (request: Request, context: Context) => {
4
+ context.log("Hello from the logging service");
5
+
6
+ return new Response("The request to this URL was logged", {
7
+ headers: { "content-type": "text/html" },
8
+ });
9
+ };
@@ -2,4 +2,5 @@ module.exports = {
2
2
  name: 'scheduled-function',
3
3
  priority: 1,
4
4
  description: 'Basic implementation of a scheduled function in TypeScript.',
5
+ functionType: 'serverless',
5
6
  }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'set-cookies',
3
+ description: 'Create and manage HTTP cookies',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,29 @@
1
+ import type { Context } from "netlify:edge";
2
+
3
+ export default async (request: Request, context: Context) => {
4
+ const url = new URL(request.url);
5
+
6
+ switch (url.searchParams.get("action")) {
7
+ case "set":
8
+ context.cookies.set({
9
+ name: "action",
10
+ value: "hello",
11
+ });
12
+
13
+ return new Response('Cookie value has been set. Reload this page without the "action" parameter to see it.');
14
+
15
+ case "clear":
16
+ context.cookies.delete("action");
17
+
18
+ return new Response(
19
+ 'Cookie value has been cleared. Reload this page without the "action" parameter to see the new state.',
20
+ );
21
+ }
22
+
23
+ const value = context.cookies.get("action");
24
+ const message = value
25
+ ? `Cookie value is "${value}". You can clear it by using "?action=clear".`
26
+ : 'Cookie has not been set. You can do so by adding "?action=set" to the URL.';
27
+
28
+ return new Response(message);
29
+ };
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'set-req-header',
3
+ description: 'Adds a custom HTTP header to HTTP request.',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,5 @@
1
+ import type { Context } from "netlify:edge";
2
+
3
+ export default async (request: Request, context: Context) => {
4
+ request.headers.set("X-Your-Custom-Header", "Your custom header value");
5
+ };
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'set-res-header',
3
+ description: 'Adds a custom HTTP header to HTTP response.',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,7 @@
1
+ import type { Context } from "netlify:edge";
2
+
3
+ export default async (request: Request, context: Context) => {
4
+ const response = await context.next();
5
+ response.headers.set("X-Your-Custom-Header", "A custom value");
6
+ return response;
7
+ };
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ name: 'transform-response',
3
+ description: 'Transform the content of an HTTP response',
4
+ functionType: 'edge',
5
+ }
@@ -0,0 +1,14 @@
1
+ import { Context } from "netlify:edge";
2
+
3
+ export default async (request: Request, context: Context) => {
4
+ const url = new URL(request.url);
5
+
6
+ // Look for the query parameter, and return if we don't find it
7
+ if (url.searchParams.get("method") !== "transform") {
8
+ return;
9
+ }
10
+
11
+ const response = await context.next();
12
+ const text = await response.text();
13
+ return new Response(text.toUpperCase(), response);
14
+ };
@@ -75,7 +75,7 @@ const monitorCLISessionEvents = (input) => {
75
75
  // @ts-ignore
76
76
  const heartbeatIntervalms = fullSession.session.cliHeartbeatIntervalMs || defaultHeartbeatFrequency
77
77
  nextMarkActiveHeartbeat = heartbeatIntervalms
78
- const markCLISessionActiveResult = await executeMarkCliSessionActiveHeartbeat(netlifyToken, site.id, sessionId)
78
+ const markCLISessionActiveResult = await executeMarkCliSessionActiveHeartbeat(graphJwt.jwt, site.id, sessionId)
79
79
  if (markCLISessionActiveResult.errors && markCLISessionActiveResult.errors.length !== 0) {
80
80
  warn(`Failed to mark CLI session active: ${markCLISessionActiveResult.errors.join(', ')}`)
81
81
  }
@@ -84,9 +84,8 @@ const monitorCLISessionEvents = (input) => {
84
84
 
85
85
  setTimeout(markActiveHelper, nextMarkActiveHeartbeat)
86
86
 
87
- const enabledServiceWatcher = async (innerNetlifyToken, siteId) => {
87
+ const enabledServiceWatcher = async (jwt, siteId) => {
88
88
  const enabledServices = state.get('oneGraphEnabledServices') || ['onegraph']
89
- const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId: appId, nfToken: netlifyToken })
90
89
 
91
90
  const enabledServicesInfo = await OneGraphClient.fetchEnabledServices(jwt, siteId)
92
91
  if (!enabledServicesInfo) {
@@ -103,7 +102,7 @@ const monitorCLISessionEvents = (input) => {
103
102
  'Reloading',
104
103
  )} Netlify Graph schema..., ${enabledServicesCompareKey} => ${newEnabledServicesCompareKey}`,
105
104
  )
106
- await refetchAndGenerateFromOneGraph({ netlifyGraphConfig, state, netlifyToken: innerNetlifyToken, siteId })
105
+ await refetchAndGenerateFromOneGraph({ netlifyGraphConfig, state, jwt, siteId })
107
106
  log(`${chalk.green('Reloaded')} Netlify Graph schema and regenerated functions`)
108
107
  }
109
108
  }
@@ -142,7 +141,7 @@ const monitorCLISessionEvents = (input) => {
142
141
  }
143
142
  }
144
143
 
145
- await enabledServiceWatcher(netlifyToken, appId)
144
+ await enabledServiceWatcher(graphJwt.jwt, appId)
146
145
 
147
146
  handle = setTimeout(helper, frequency)
148
147
  }
@@ -178,15 +177,14 @@ const monitorOperationFile = async ({ netlifyGraphConfig, onAdd, onChange, onUnl
178
177
  * Fetch the schema for a site, and regenerate all of the downstream files
179
178
  * @param {object} input
180
179
  * @param {string} input.siteId The id of the site to query against
181
- * @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
180
+ * @param {string} input.jwt The Graph JWT
182
181
  * @param {NetlifyGraph.NetlifyGraphConfig} input.netlifyGraphConfig A standalone config object that contains all the information necessary for Netlify Graph to process events
183
182
  * @param {StateConfig} input.state A function to call to set/get the current state of the local Netlify project
184
183
  * @param {(message: string) => void=} input.logger A function that if provided will be used to log messages
185
184
  * @returns {Promise<void>}
186
185
  */
187
186
  const refetchAndGenerateFromOneGraph = async (input) => {
188
- const { logger, netlifyGraphConfig, netlifyToken, siteId, state } = input
189
- const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
187
+ const { jwt, logger, netlifyGraphConfig, siteId, state } = input
190
188
 
191
189
  await OneGraphClient.ensureAppForSite(jwt, siteId)
192
190
 
@@ -577,7 +575,7 @@ const startOneGraphCLISession = async (input) => {
577
575
  const newOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
578
576
  await persistNewOperationsDocForSession({
579
577
  netlifyGraphConfig,
580
- jwt,
578
+ netlifyToken,
581
579
  oneGraphSessionId,
582
580
  operationsDoc: newOperationsDoc,
583
581
  siteId: site.id,
@@ -590,7 +588,7 @@ const startOneGraphCLISession = async (input) => {
590
588
  const newOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
591
589
  await persistNewOperationsDocForSession({
592
590
  netlifyGraphConfig,
593
- jwt,
591
+ netlifyToken,
594
592
  oneGraphSessionId,
595
593
  operationsDoc: newOperationsDoc,
596
594
  siteId: site.id,
@@ -653,7 +651,8 @@ const startOneGraphCLISession = async (input) => {
653
651
  * @param {string} input.sessionId The session id to monitor CLI events for
654
652
  */
655
653
  const markCliSessionInactive = async ({ netlifyToken, sessionId, siteId }) => {
656
- const result = await executeMarkCliSessionInactive(netlifyToken, siteId, sessionId)
654
+ const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
655
+ const result = await executeMarkCliSessionInactive(jwt, siteId, sessionId)
657
656
  if (result.errors) {
658
657
  warn(`Unable to mark CLI session ${sessionId} inactive: ${JSON.stringify(result.errors, null, 2)}`)
659
658
  }