netlify-cli 10.13.0 → 10.14.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 +2 -1
- package/npm-shrinkwrap.json +912 -450
- package/package.json +6 -5
- package/src/commands/functions/functions-invoke.js +4 -4
- package/src/commands/graph/graph-init.js +148 -0
- 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 +1 -1
- 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/one-graph/cli-client.js +134 -96
- package/src/utils/dot-env.js +1 -1
- package/src/utils/init/utils.js +1 -1
|
@@ -24,13 +24,6 @@ const {
|
|
|
24
24
|
|
|
25
25
|
const { parse } = GraphQL
|
|
26
26
|
const { defaultExampleOperationsDoc, extractFunctionsFromOperationDoc } = NetlifyGraph
|
|
27
|
-
const {
|
|
28
|
-
ensureAppForSite,
|
|
29
|
-
executeCreatePersistedQueryMutation,
|
|
30
|
-
executeMarkCliSessionActiveHeartbeat,
|
|
31
|
-
executeMarkCliSessionInactive,
|
|
32
|
-
updateCLISessionMetadata,
|
|
33
|
-
} = OneGraphClient
|
|
34
27
|
|
|
35
28
|
const internalConsole = {
|
|
36
29
|
log,
|
|
@@ -71,18 +64,25 @@ const monitorCLISessionEvents = (input) => {
|
|
|
71
64
|
let nextMarkActiveHeartbeat = defaultHeartbeatFrequency
|
|
72
65
|
|
|
73
66
|
const markActiveHelper = async () => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
67
|
+
try {
|
|
68
|
+
const graphJwt = await OneGraphClient.getGraphJwtForSite({ siteId: appId, nfToken: netlifyToken })
|
|
69
|
+
const fullSession = await OneGraphClient.fetchCliSession({
|
|
70
|
+
jwt: graphJwt.jwt,
|
|
71
|
+
appId,
|
|
72
|
+
sessionId: currentSessionId,
|
|
73
|
+
})
|
|
74
|
+
const heartbeatIntervalms = fullSession.session.cliHeartbeatIntervalMs || defaultHeartbeatFrequency
|
|
75
|
+
nextMarkActiveHeartbeat = heartbeatIntervalms
|
|
76
|
+
const markCLISessionActiveResult = await OneGraphClient.executeMarkCliSessionActiveHeartbeat(
|
|
77
|
+
graphJwt.jwt,
|
|
78
|
+
site.id,
|
|
79
|
+
currentSessionId,
|
|
80
|
+
)
|
|
81
|
+
if (markCLISessionActiveResult.errors && markCLISessionActiveResult.errors.length !== 0) {
|
|
82
|
+
warn(`Failed to mark CLI session active: ${markCLISessionActiveResult.errors.join(', ')}`)
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
warn(`Unable to reach Netlify Graph servers in order to mark CLI session active`)
|
|
86
86
|
}
|
|
87
87
|
setTimeout(markActiveHelper, nextMarkActiveHeartbeat)
|
|
88
88
|
}
|
|
@@ -92,23 +92,27 @@ const monitorCLISessionEvents = (input) => {
|
|
|
92
92
|
const enabledServiceWatcher = async (jwt, { appId: siteId, sessionId }) => {
|
|
93
93
|
const enabledServices = state.get('oneGraphEnabledServices') || ['onegraph']
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
95
|
+
try {
|
|
96
|
+
const enabledServicesInfo = await OneGraphClient.fetchEnabledServicesForSession(jwt, siteId, sessionId)
|
|
97
|
+
if (!enabledServicesInfo) {
|
|
98
|
+
warn('Unable to fetch enabled services for site for code generation')
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
const newEnabledServices = enabledServicesInfo.map((service) => service.graphQLField)
|
|
102
|
+
const enabledServicesCompareKey = enabledServices.sort().join(',')
|
|
103
|
+
const newEnabledServicesCompareKey = newEnabledServices.sort().join(',')
|
|
104
|
+
|
|
105
|
+
if (enabledServicesCompareKey !== newEnabledServicesCompareKey) {
|
|
106
|
+
log(
|
|
107
|
+
`${chalk.magenta(
|
|
108
|
+
'Reloading',
|
|
109
|
+
)} Netlify Graph schema..., ${enabledServicesCompareKey} => ${newEnabledServicesCompareKey}`,
|
|
110
|
+
)
|
|
111
|
+
await refetchAndGenerateFromOneGraph({ netlifyGraphConfig, state, jwt, siteId, sessionId })
|
|
112
|
+
log(`${chalk.green('Reloaded')} Netlify Graph schema and regenerated functions`)
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
warn(`Unable to reach Netlify Graph servers in order to fetch enabled Graph services`)
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
118
|
|
|
@@ -119,39 +123,43 @@ const monitorCLISessionEvents = (input) => {
|
|
|
119
123
|
let handle
|
|
120
124
|
|
|
121
125
|
const helper = async () => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const graphJwt = await OneGraphClient.getGraphJwtForSite({ siteId: appId, nfToken: netlifyToken })
|
|
128
|
-
const next = await OneGraphClient.fetchCliSessionEvents({ appId, jwt: graphJwt.jwt, sessionId: currentSessionId })
|
|
126
|
+
try {
|
|
127
|
+
if (shouldClose) {
|
|
128
|
+
clearTimeout(handle)
|
|
129
|
+
onClose && onClose()
|
|
130
|
+
}
|
|
129
131
|
|
|
130
|
-
|
|
131
|
-
next.
|
|
132
|
-
onError(fetchEventError)
|
|
133
|
-
})
|
|
134
|
-
}
|
|
132
|
+
const graphJwt = await OneGraphClient.getGraphJwtForSite({ siteId: appId, nfToken: netlifyToken })
|
|
133
|
+
const next = await OneGraphClient.fetchCliSessionEvents({ appId, jwt: graphJwt.jwt, sessionId: currentSessionId })
|
|
135
134
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
let ackIds = []
|
|
140
|
-
try {
|
|
141
|
-
ackIds = await onEvents(events)
|
|
142
|
-
} catch (eventHandlerError) {
|
|
143
|
-
warn(`Error handling event: ${eventHandlerError}`)
|
|
144
|
-
} finally {
|
|
145
|
-
await OneGraphClient.ackCLISessionEvents({
|
|
146
|
-
appId,
|
|
147
|
-
jwt: graphJwt.jwt,
|
|
148
|
-
sessionId: currentSessionId,
|
|
149
|
-
eventIds: ackIds,
|
|
135
|
+
if (next && next.errors) {
|
|
136
|
+
next.errors.forEach((fetchEventError) => {
|
|
137
|
+
onError(fetchEventError)
|
|
150
138
|
})
|
|
151
139
|
}
|
|
152
|
-
}
|
|
153
140
|
|
|
154
|
-
|
|
141
|
+
const events = (next && next.events) || []
|
|
142
|
+
|
|
143
|
+
if (events.length !== 0) {
|
|
144
|
+
let ackIds = []
|
|
145
|
+
try {
|
|
146
|
+
ackIds = await onEvents(events)
|
|
147
|
+
} catch (eventHandlerError) {
|
|
148
|
+
warn(`Error handling event: ${eventHandlerError}`)
|
|
149
|
+
} finally {
|
|
150
|
+
await OneGraphClient.ackCLISessionEvents({
|
|
151
|
+
appId,
|
|
152
|
+
jwt: graphJwt.jwt,
|
|
153
|
+
sessionId: currentSessionId,
|
|
154
|
+
eventIds: ackIds,
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
await enabledServiceWatcher(graphJwt.jwt, { appId, sessionId: currentSessionId })
|
|
160
|
+
} catch {
|
|
161
|
+
warn(`Unable to reach Netlify Graph servers in order to sync Graph session`)
|
|
162
|
+
}
|
|
155
163
|
|
|
156
164
|
handle = setTimeout(helper, frequency)
|
|
157
165
|
}
|
|
@@ -172,7 +180,11 @@ const monitorCLISessionEvents = (input) => {
|
|
|
172
180
|
* @returns {Promise<any>}
|
|
173
181
|
*/
|
|
174
182
|
const monitorOperationFile = async ({ netlifyGraphConfig, onAdd, onChange, onUnlink }) => {
|
|
175
|
-
|
|
183
|
+
if (!netlifyGraphConfig.graphQLOperationsSourceFilename) {
|
|
184
|
+
error('Please configure `graphQLOperationsSourceFilename` in your `netlify.toml` [graph] section')
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const filePath = path.resolve(...(netlifyGraphConfig.graphQLOperationsSourceFilename || []))
|
|
176
188
|
const newWatcher = await watchDebounced([filePath], {
|
|
177
189
|
depth: 1,
|
|
178
190
|
onAdd,
|
|
@@ -211,6 +223,10 @@ const refetchAndGenerateFromOneGraph = async (input) => {
|
|
|
211
223
|
|
|
212
224
|
const schema = await OneGraphClient.fetchOneGraphSchemaForServices(siteId, enabledServices)
|
|
213
225
|
|
|
226
|
+
if (!schema) {
|
|
227
|
+
error('Unable to fetch schema from Netlify Graph')
|
|
228
|
+
}
|
|
229
|
+
|
|
214
230
|
let currentOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
|
|
215
231
|
if (currentOperationsDoc.trim().length === 0) {
|
|
216
232
|
currentOperationsDoc = defaultExampleOperationsDoc
|
|
@@ -280,29 +296,33 @@ const quickHash = (input) => {
|
|
|
280
296
|
* @returns
|
|
281
297
|
*/
|
|
282
298
|
const updateGraphQLOperationsFileFromPersistedDoc = async (input) => {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
299
|
+
try {
|
|
300
|
+
const { docId, logger, netlifyGraphConfig, netlifyToken, schema, siteId } = input
|
|
301
|
+
const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
|
|
302
|
+
const persistedDoc = await OneGraphClient.fetchPersistedQuery(jwt, siteId, docId)
|
|
303
|
+
if (!persistedDoc) {
|
|
304
|
+
warn(`No persisted doc found for: ${docId}`)
|
|
305
|
+
return
|
|
306
|
+
}
|
|
290
307
|
|
|
291
|
-
|
|
292
|
-
|
|
308
|
+
// Sorts the operations stably, prepends the @netlify directive, etc.
|
|
309
|
+
const operationsDocString = normalizeOperationsDoc(persistedDoc.query)
|
|
293
310
|
|
|
294
|
-
|
|
295
|
-
|
|
311
|
+
writeGraphQLOperationsSourceFile({ logger, netlifyGraphConfig, operationsDocString })
|
|
312
|
+
regenerateFunctionsFileFromOperationsFile({ netlifyGraphConfig, schema })
|
|
296
313
|
|
|
297
|
-
|
|
314
|
+
const hash = quickHash(operationsDocString)
|
|
298
315
|
|
|
299
|
-
|
|
316
|
+
const relevantHasLength = 10
|
|
300
317
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
318
|
+
if (witnessedIncomingDocumentHashes.length > relevantHasLength) {
|
|
319
|
+
witnessedIncomingDocumentHashes.shift()
|
|
320
|
+
}
|
|
304
321
|
|
|
305
|
-
|
|
322
|
+
witnessedIncomingDocumentHashes.push(hash)
|
|
323
|
+
} catch {
|
|
324
|
+
warn(`Unable to reach Netlify Graph servers in order to update Graph operations file`)
|
|
325
|
+
}
|
|
306
326
|
}
|
|
307
327
|
|
|
308
328
|
const handleCliSessionEvent = async ({
|
|
@@ -357,15 +377,19 @@ const handleCliSessionEvent = async ({
|
|
|
357
377
|
},
|
|
358
378
|
}
|
|
359
379
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
380
|
+
try {
|
|
381
|
+
const graphJwt = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
|
|
382
|
+
|
|
383
|
+
await OneGraphClient.executeCreateCLISessionEventMutation(
|
|
384
|
+
{
|
|
385
|
+
sessionId,
|
|
386
|
+
payload: fileWrittenEvent,
|
|
387
|
+
},
|
|
388
|
+
{ accessToken: graphJwt.jwt },
|
|
389
|
+
)
|
|
390
|
+
} catch {
|
|
391
|
+
warn(`Unable to reach Netlify Graph servers in order to notify handler files written to disk`)
|
|
392
|
+
}
|
|
369
393
|
}
|
|
370
394
|
break
|
|
371
395
|
}
|
|
@@ -500,9 +524,23 @@ const persistNewOperationsDocForSession = async ({
|
|
|
500
524
|
siteId,
|
|
501
525
|
siteRoot,
|
|
502
526
|
}) => {
|
|
527
|
+
try {
|
|
528
|
+
GraphQL.parse(operationsDoc)
|
|
529
|
+
} catch (parseError) {
|
|
530
|
+
// TODO: We should send a message to the web UI that the current GraphQL operations file can't be sync because it's invalid
|
|
531
|
+
warn(
|
|
532
|
+
`Unable to sync Graph operations file. Please ensure that your GraphQL operations file is valid GraphQL. Found error: ${JSON.stringify(
|
|
533
|
+
parseError,
|
|
534
|
+
null,
|
|
535
|
+
2,
|
|
536
|
+
)}`,
|
|
537
|
+
)
|
|
538
|
+
return
|
|
539
|
+
}
|
|
540
|
+
|
|
503
541
|
const { branch } = gitRepoInfo()
|
|
504
542
|
const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
|
|
505
|
-
const persistedResult = await executeCreatePersistedQueryMutation(
|
|
543
|
+
const persistedResult = await OneGraphClient.executeCreatePersistedQueryMutation(
|
|
506
544
|
{
|
|
507
545
|
appId: siteId,
|
|
508
546
|
description: 'Temporary snapshot of local queries',
|
|
@@ -663,7 +701,7 @@ const startOneGraphCLISession = async (input) => {
|
|
|
663
701
|
*/
|
|
664
702
|
const markCliSessionInactive = async ({ netlifyToken, sessionId, siteId }) => {
|
|
665
703
|
const { jwt } = await OneGraphClient.getGraphJwtForSite({ siteId, nfToken: netlifyToken })
|
|
666
|
-
const result = await executeMarkCliSessionInactive(jwt, siteId, sessionId)
|
|
704
|
+
const result = await OneGraphClient.executeMarkCliSessionInactive(jwt, siteId, sessionId)
|
|
667
705
|
if (result.errors) {
|
|
668
706
|
warn(`Unable to mark CLI session ${sessionId} inactive: ${JSON.stringify(result.errors, null, 2)}`)
|
|
669
707
|
}
|
|
@@ -733,7 +771,7 @@ const ensureCLISession = async (input) => {
|
|
|
733
771
|
}
|
|
734
772
|
|
|
735
773
|
state.set('oneGraphSessionId', oneGraphSessionId)
|
|
736
|
-
const { errors: markCLISessionActiveErrors } = await executeMarkCliSessionActiveHeartbeat(
|
|
774
|
+
const { errors: markCLISessionActiveErrors } = await OneGraphClient.executeMarkCliSessionActiveHeartbeat(
|
|
737
775
|
jwt,
|
|
738
776
|
site.id,
|
|
739
777
|
oneGraphSessionId,
|
|
@@ -751,8 +789,8 @@ const OneGraphCliClient = {
|
|
|
751
789
|
executeCreatePersistedQueryMutation: OneGraphClient.executeCreatePersistedQueryMutation,
|
|
752
790
|
executeCreateApiTokenMutation: OneGraphClient.executeCreateApiTokenMutation,
|
|
753
791
|
fetchCliSessionEvents: OneGraphClient.fetchCliSessionEvents,
|
|
754
|
-
ensureAppForSite,
|
|
755
|
-
updateCLISessionMetadata,
|
|
792
|
+
ensureAppForSite: OneGraphClient.ensureAppForSite,
|
|
793
|
+
updateCLISessionMetadata: OneGraphClient.updateCLISessionMetadata,
|
|
756
794
|
getGraphJwtForSite: OneGraphClient.getGraphJwtForSite,
|
|
757
795
|
}
|
|
758
796
|
|
package/src/utils/dot-env.js
CHANGED
|
@@ -20,7 +20,7 @@ const loadDotEnvFiles = async function ({ envFiles, projectDir }) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// in the user configuration, the order is highest to lowest
|
|
23
|
-
const defaultEnvFiles = ['.env.development', '.env']
|
|
23
|
+
const defaultEnvFiles = ['.env.development.local', '.env.local', '.env.development', '.env']
|
|
24
24
|
|
|
25
25
|
const tryLoadDotEnvFiles = async ({ projectDir, dotenvFiles = defaultEnvFiles }) => {
|
|
26
26
|
const results = await Promise.all(
|
package/src/utils/init/utils.js
CHANGED
|
@@ -199,7 +199,7 @@ const getNetlifyToml = ({
|
|
|
199
199
|
# port = 3000 # Port that the dev server will be listening on
|
|
200
200
|
# publish = "dist" # Folder with the static content for _redirect file
|
|
201
201
|
|
|
202
|
-
## more info on configuring this file: https://
|
|
202
|
+
## more info on configuring this file: https://docs.netlify.com/configure-builds/file-based-configuration/
|
|
203
203
|
`
|
|
204
204
|
|
|
205
205
|
const saveNetlifyToml = async ({ baseDir, buildCmd, buildDir, config, configPath, functionsDir, repositoryRoot }) => {
|