netlify-cli 8.11.1 → 8.13.2

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.
@@ -0,0 +1,278 @@
1
+ /* eslint-disable eslint-comments/disable-enable-pair */
2
+ /* eslint-disable fp/no-loops */
3
+ const os = require('os')
4
+
5
+ const { GraphQL, InternalConsole, OneGraphClient } = require('netlify-onegraph-internal')
6
+ const { NetlifyGraph } = require('netlify-onegraph-internal')
7
+
8
+ const { chalk, error, log, warn } = require('../../utils')
9
+
10
+ const { createCLISession, createPersistedQuery, ensureAppForSite, updateCLISessionMetadata } = OneGraphClient
11
+
12
+ const {
13
+ generateFunctionsFile,
14
+ generateHandler,
15
+ readGraphQLOperationsSourceFile,
16
+ writeGraphQLOperationsSourceFile,
17
+ writeGraphQLSchemaFile,
18
+ } = require('./cli-netlify-graph')
19
+
20
+ const { parse } = GraphQL
21
+ const { defaultExampleOperationsDoc, extractFunctionsFromOperationDoc } = NetlifyGraph
22
+
23
+ const internalConsole = {
24
+ log,
25
+ warn,
26
+ error,
27
+ debug: console.debug,
28
+ }
29
+
30
+ InternalConsole.registerConsole(internalConsole)
31
+
32
+ /**
33
+ * Start polling for CLI events for a given session to process locally
34
+ * @param {object} input
35
+ * @param {string} input.appId The app to query against, typically the siteId
36
+ * @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
37
+ * @param {NetlifyGraphConfig} input.netlifyGraphConfig A standalone config object that contains all the information necessary for Netlify Graph to process events
38
+ * @param {function} input.onClose A function to call when the polling loop is closed
39
+ * @param {function} input.onError A function to call when an error occurs
40
+ * @param {function} input.onEvents A function to call when CLI events are received and need to be processed
41
+ * @param {string} input.sessionId The session id to monitor CLI events for
42
+ * @param {state} input.state A function to call to set/get the current state of the local Netlify project
43
+ * @returns
44
+ */
45
+ const monitorCLISessionEvents = (input) => {
46
+ const { appId, netlifyGraphConfig, netlifyToken, onClose, onError, onEvents, sessionId, state } = input
47
+
48
+ const frequency = 5000
49
+ let shouldClose = false
50
+
51
+ const enabledServiceWatcher = async (innerNetlifyToken, siteId) => {
52
+ const enabledServices = state.get('oneGraphEnabledServices') || ['onegraph']
53
+ const enabledServicesInfo = await OneGraphClient.fetchEnabledServices(innerNetlifyToken, siteId)
54
+ if (!enabledServicesInfo) {
55
+ warn('Unable to fetch enabled services for site for code generation')
56
+ return
57
+ }
58
+ const newEnabledServices = enabledServicesInfo.map((service) => service.service)
59
+ const enabledServicesCompareKey = enabledServices.sort().join(',')
60
+ const newEnabledServicesCompareKey = newEnabledServices.sort().join(',')
61
+
62
+ if (enabledServicesCompareKey !== newEnabledServicesCompareKey) {
63
+ log(
64
+ `${chalk.magenta(
65
+ 'Reloading',
66
+ )} Netlify Graph schema..., ${enabledServicesCompareKey} => ${newEnabledServicesCompareKey}`,
67
+ )
68
+ await refetchAndGenerateFromOneGraph({ netlifyGraphConfig, state, netlifyToken: innerNetlifyToken, siteId })
69
+ log(`${chalk.green('Reloaded')} Netlify Graph schema and regenerated functions`)
70
+ }
71
+ }
72
+
73
+ const close = () => {
74
+ shouldClose = true
75
+ }
76
+
77
+ let handle
78
+
79
+ const helper = async () => {
80
+ if (shouldClose) {
81
+ clearTimeout(handle)
82
+ onClose()
83
+ }
84
+
85
+ const next = await OneGraphClient.fetchCliSessionEvents({ appId, authToken: netlifyToken, sessionId })
86
+
87
+ if (next.errors) {
88
+ next.errors.forEach((fetchEventError) => {
89
+ onError(fetchEventError)
90
+ })
91
+ }
92
+
93
+ const { events } = next
94
+
95
+ if (events.length !== 0) {
96
+ const ackIds = await onEvents(events)
97
+ await OneGraphClient.ackCLISessionEvents({ appId, authToken: netlifyToken, sessionId, eventIds: ackIds })
98
+ }
99
+
100
+ await enabledServiceWatcher(netlifyToken, appId)
101
+
102
+ handle = setTimeout(helper, frequency)
103
+ }
104
+
105
+ // Fire immediately to start rather than waiting the initial `frequency`
106
+ helper()
107
+
108
+ return close
109
+ }
110
+
111
+ /**
112
+ * Fetch the schema for a site, and regenerate all of the downstream files
113
+ * @param {object} input
114
+ * @param {string} input.siteId The id of the site to query against
115
+ * @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
116
+ * @param {NetlifyGraphConfig} input.netlifyGraphConfig A standalone config object that contains all the information necessary for Netlify Graph to process events
117
+ * @param {state} input.state A function to call to set/get the current state of the local Netlify project
118
+ * @returns {Promise<void>}
119
+ */
120
+ const refetchAndGenerateFromOneGraph = async (input) => {
121
+ const { netlifyGraphConfig, netlifyToken, siteId, state } = input
122
+ await OneGraphClient.ensureAppForSite(netlifyToken, siteId)
123
+
124
+ const enabledServicesInfo = await OneGraphClient.fetchEnabledServices(netlifyToken, siteId)
125
+ if (!enabledServicesInfo) {
126
+ warn('Unable to fetch enabled services for site for code generation')
127
+ return
128
+ }
129
+
130
+ const enabledServices = enabledServicesInfo
131
+ .map((service) => service.service)
132
+ .sort((aString, bString) => aString.localeCompare(bString))
133
+ const schema = await OneGraphClient.fetchOneGraphSchema(siteId, enabledServices)
134
+
135
+ let currentOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
136
+ if (currentOperationsDoc.trim().length === 0) {
137
+ currentOperationsDoc = defaultExampleOperationsDoc
138
+ }
139
+
140
+ const parsedDoc = parse(currentOperationsDoc)
141
+ const operations = extractFunctionsFromOperationDoc(parsedDoc)
142
+
143
+ generateFunctionsFile(netlifyGraphConfig, schema, currentOperationsDoc, operations)
144
+ writeGraphQLSchemaFile(netlifyGraphConfig, schema)
145
+ state.set('oneGraphEnabledServices', enabledServices)
146
+ }
147
+
148
+ /**
149
+ *
150
+ * @param {object} input
151
+ * @param {string} input.siteId The site id to query against
152
+ * @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
153
+ * @param {string} input.docId The GraphQL operations document id to fetch
154
+ * @param {string} input.schema The GraphQL schema to use when generating code
155
+ * @param {NetlifyGraphConfig} input.netlifyGraphConfig A standalone config object that contains all the information necessary for Netlify Graph to process events
156
+ * @returns
157
+ */
158
+ const updateGraphQLOperationsFile = async (input) => {
159
+ const { docId, netlifyGraphConfig, netlifyToken, schema, siteId } = input
160
+ const persistedDoc = await OneGraphClient.fetchPersistedQuery(netlifyToken, siteId, docId)
161
+ if (!persistedDoc) {
162
+ warn('No persisted doc found for:', docId)
163
+ return
164
+ }
165
+
166
+ const doc = persistedDoc.query
167
+
168
+ writeGraphQLOperationsSourceFile(netlifyGraphConfig, doc)
169
+ const appOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
170
+ const parsedDoc = parse(appOperationsDoc, {
171
+ noLocation: true,
172
+ })
173
+ const operations = extractFunctionsFromOperationDoc(parsedDoc)
174
+ generateFunctionsFile(netlifyGraphConfig, schema, appOperationsDoc, operations)
175
+ }
176
+
177
+ const handleCliSessionEvent = async ({ event, netlifyGraphConfig, netlifyToken, schema, siteId }) => {
178
+ const { __typename, payload } = await event
179
+ switch (__typename) {
180
+ case 'OneGraphNetlifyCliSessionTestEvent':
181
+ await handleCliSessionEvent({ netlifyToken, event: payload, netlifyGraphConfig, schema, siteId })
182
+ break
183
+ case 'OneGraphNetlifyCliSessionGenerateHandlerEvent':
184
+ await generateHandler(netlifyGraphConfig, schema, payload.operationId, payload)
185
+ break
186
+ case 'OneGraphNetlifyCliSessionPersistedLibraryUpdatedEvent':
187
+ await updateGraphQLOperationsFile({ netlifyToken, docId: payload.docId, netlifyGraphConfig, schema, siteId })
188
+ break
189
+ default: {
190
+ warn(`Unrecognized event received, you may need to upgrade your CLI version`, __typename, payload)
191
+ break
192
+ }
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Load the CLI session id from the local state
198
+ * @param {state} state
199
+ * @returns
200
+ */
201
+ const loadCLISession = (state) => state.get('oneGraphSessionId')
202
+
203
+ /**
204
+ * Idemponentially save the CLI session id to the local state and start monitoring for CLI events and upstream schema changes
205
+ * @param {object} input
206
+ * @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
207
+ * @param {NetlifyGraphConfig} input.netlifyGraphConfig A standalone config object that contains all the information necessary for Netlify Graph to process events
208
+ * @param {state} input.state A function to call to set/get the current state of the local Netlify project
209
+ * @param {site} input.site The site object
210
+ */
211
+ const startOneGraphCLISession = async (input) => {
212
+ const { netlifyGraphConfig, netlifyToken, site, state } = input
213
+ OneGraphClient.ensureAppForSite(netlifyToken, site.id)
214
+ let oneGraphSessionId = loadCLISession(state)
215
+ if (!oneGraphSessionId) {
216
+ const sessionName = generateSessionName()
217
+ const sessionMetadata = {}
218
+ const oneGraphSession = await OneGraphClient.createCLISession(netlifyToken, site.id, sessionName, sessionMetadata)
219
+ state.set('oneGraphSessionId', oneGraphSession.id)
220
+ oneGraphSessionId = state.get('oneGraphSessionId')
221
+ }
222
+
223
+ const enabledServices = []
224
+ const schema = await OneGraphClient.fetchOneGraphSchema(site.id, enabledServices)
225
+
226
+ monitorCLISessionEvents({
227
+ appId: site.id,
228
+ netlifyToken,
229
+ netlifyGraphConfig,
230
+ sessionId: oneGraphSessionId,
231
+ state,
232
+ onEvents: async (events) => {
233
+ for (const event of events) {
234
+ const eventName = OneGraphClient.friendlyEventName(event)
235
+ log(`${chalk.magenta('Handling')} Netlify Graph: ${eventName}...`)
236
+ await handleCliSessionEvent({ netlifyToken, event, netlifyGraphConfig, schema, siteId: site.id })
237
+ log(`${chalk.green('Finished handling')} Netlify Graph: ${eventName}...`)
238
+ }
239
+ return events.map((event) => event.id)
240
+ },
241
+ onError: (fetchEventError) => {
242
+ error(`Netlify Graph upstream error: ${fetchEventError}`)
243
+ },
244
+ onClose: () => {
245
+ log('Netlify Graph upstream closed')
246
+ },
247
+ })
248
+ }
249
+
250
+ /**
251
+ * Generate a session name that can be identified as belonging to the current checkout
252
+ * @returns {string} The name of the session to create
253
+ */
254
+ const generateSessionName = () => {
255
+ const userInfo = os.userInfo({ encoding: 'utf-8' })
256
+ const sessionName = `${userInfo.username}-${Date.now()}`
257
+ log(`Generated Netlify Graph session name: ${sessionName}`)
258
+ return sessionName
259
+ }
260
+
261
+ const OneGraphCliClient = {
262
+ ackCLISessionEvents: OneGraphClient.ackCLISessionEvents,
263
+ createCLISession,
264
+ createPersistedQuery,
265
+ fetchCliSessionEvents: OneGraphClient.fetchCliSessionEvents,
266
+ ensureAppForSite,
267
+ updateCLISessionMetadata,
268
+ }
269
+
270
+ module.exports = {
271
+ OneGraphCliClient,
272
+ handleCliSessionEvent,
273
+ generateSessionName,
274
+ loadCLISession,
275
+ monitorCLISessionEvents,
276
+ refetchAndGenerateFromOneGraph,
277
+ startOneGraphCLISession,
278
+ }
@@ -0,0 +1,278 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const process = require('process')
4
+
5
+ const { GraphQL, InternalConsole, NetlifyGraph } = require('netlify-onegraph-internal')
6
+
7
+ const { detectServerSettings, error, getFunctionsDir, log, warn } = require('../../utils')
8
+
9
+ const { printSchema } = GraphQL
10
+
11
+ const internalConsole = {
12
+ log,
13
+ warn,
14
+ error,
15
+ debug: console.debug,
16
+ }
17
+
18
+ InternalConsole.registerConsole(internalConsole)
19
+
20
+ /**
21
+ * Remove any relative path components from the given path
22
+ * @param {string[]} items Filesystem path items to filter
23
+ * @return {string[]} Filtered filesystem path items
24
+ */
25
+ const filterRelativePathItems = (items) => items.filter((part) => part !== '')
26
+
27
+ /**
28
+ * Return a full NetlifyGraph config with any defaults overridden by netlify.toml
29
+ * @param {import('../base-command').BaseCommand} command
30
+ * @return {NetlifyGraphConfig} NetlifyGraphConfig
31
+ */
32
+ const getNetlifyGraphConfig = async ({ command, options }) => {
33
+ const { config, site } = command.netlify
34
+ config.dev = { ...config.dev }
35
+ config.build = { ...config.build }
36
+ const userSpecifiedConfig = (config && config.graph) || {}
37
+ /** @type {import('./types').DevConfig} */
38
+ const devConfig = {
39
+ framework: '#auto',
40
+ ...(config.functionsDirectory && { functions: config.functionsDirectory }),
41
+ ...(config.build.publish && { publish: config.build.publish }),
42
+ ...config.dev,
43
+ ...options,
44
+ }
45
+
46
+ /** @type {Partial<import('../../utils/types').ServerSettings>} */
47
+ let settings = {}
48
+ try {
49
+ settings = await detectServerSettings(devConfig, options, site.root)
50
+ } catch (detectServerSettingsError) {
51
+ error(detectServerSettingsError)
52
+ }
53
+
54
+ const siteRoot = [path.sep, ...filterRelativePathItems(site.root.split(path.sep))]
55
+
56
+ const tsConfig = 'tsconfig.json'
57
+ const autodetectedLanguage = fs.existsSync(tsConfig) ? 'typescript' : 'javascript'
58
+
59
+ const framework = settings.framework || userSpecifiedConfig.framework
60
+ const isNextjs = framework === 'Next.js'
61
+ const detectedFunctionsPathString = getFunctionsDir({ config, options })
62
+ const detectedFunctionsPath = detectedFunctionsPathString ? detectedFunctionsPathString.split(path.sep) : null
63
+ const functionsPath = filterRelativePathItems(isNextjs ? [...siteRoot, 'pages', 'api'] : [...detectedFunctionsPath])
64
+ const netlifyGraphPath = filterRelativePathItems(
65
+ isNextjs
66
+ ? [...siteRoot, 'lib', 'netlifyGraph']
67
+ : [...siteRoot, ...NetlifyGraph.defaultNetlifyGraphConfig.netlifyGraphPath],
68
+ )
69
+ const baseConfig = { ...NetlifyGraph.defaultNetlifyGraphConfig, ...userSpecifiedConfig }
70
+ const netlifyGraphImplementationFilename = [...netlifyGraphPath, `index.${baseConfig.extension}`]
71
+ const netlifyGraphTypeDefinitionsFilename = [...netlifyGraphPath, `index.d.ts`]
72
+ const graphQLOperationsSourceFilename = [...netlifyGraphPath, NetlifyGraph.defaultSourceOperationsFilename]
73
+ const graphQLSchemaFilename = [...netlifyGraphPath, NetlifyGraph.defaultGraphQLSchemaFilename]
74
+ const netlifyGraphRequirePath = isNextjs ? ['..', '..', 'lib', 'netlifyGraph'] : [`./netlifyGraph`]
75
+ const language = userSpecifiedConfig.language || autodetectedLanguage
76
+ const moduleType = baseConfig.moduleType || isNextjs ? 'esm' : 'commonjs'
77
+ const fullConfig = {
78
+ ...baseConfig,
79
+ functionsPath,
80
+ netlifyGraphPath,
81
+ netlifyGraphImplementationFilename,
82
+ netlifyGraphTypeDefinitionsFilename,
83
+ graphQLOperationsSourceFilename,
84
+ graphQLSchemaFilename,
85
+ netlifyGraphRequirePath,
86
+ framework,
87
+ language,
88
+ moduleType,
89
+ }
90
+
91
+ return fullConfig
92
+ }
93
+
94
+ /**
95
+ * Given a NetlifyGraphConfig, ensure that the netlifyGraphPath exists
96
+ * @param {NetlifyGraphConfig} netlifyGraphConfig
97
+ */
98
+ const ensureNetlifyGraphPath = (netlifyGraphConfig) => {
99
+ fs.mkdirSync(path.resolve(...netlifyGraphConfig.netlifyGraphPath), { recursive: true })
100
+ }
101
+
102
+ /**
103
+ * Given a NetlifyGraphConfig, ensure that the functionsPath exists
104
+ * @param {NetlifyGraphConfig} netlifyGraphConfig
105
+ */
106
+ const ensureFunctionsPath = (netlifyGraphConfig) => {
107
+ fs.mkdirSync(path.resolve(...netlifyGraphConfig.functionsPath), { recursive: true })
108
+ }
109
+
110
+ /**
111
+ * Generate a library file with type definitions for a given NetlifyGraphConfig, operationsDoc, and schema, writing them to the filesystem
112
+ * @param {NetlifyGraphConfig} netlifyGraphConfig
113
+ * @param {GraphQLSchema} schema The schema to use when generating the functions and their types
114
+ * @param {string} operationsDoc The GraphQL operations doc to use when generating the functions
115
+ * @param {NetlifyGraph.ParsedFunction} queries The parsed queries with metadata to use when generating library functions
116
+ */
117
+ const generateFunctionsFile = (netlifyGraphConfig, schema, operationsDoc, queries) => {
118
+ const { clientSource, typeDefinitionsSource } = NetlifyGraph.generateFunctionsSource(
119
+ netlifyGraphConfig,
120
+ schema,
121
+ operationsDoc,
122
+ queries,
123
+ )
124
+
125
+ ensureNetlifyGraphPath(netlifyGraphConfig)
126
+ fs.writeFileSync(path.resolve(...netlifyGraphConfig.netlifyGraphImplementationFilename), clientSource, 'utf8')
127
+ fs.writeFileSync(
128
+ path.resolve(...netlifyGraphConfig.netlifyGraphTypeDefinitionsFilename),
129
+ typeDefinitionsSource,
130
+ 'utf8',
131
+ )
132
+ }
133
+
134
+ /**
135
+ * Using the given NetlifyGraphConfig, read the GraphQL operations file and return the _unparsed_ GraphQL operations doc
136
+ * @param {NetlifyGraphConfig} netlifyGraphConfig
137
+ * @returns {string} GraphQL operations doc
138
+ */
139
+ const readGraphQLOperationsSourceFile = (netlifyGraphConfig) => {
140
+ ensureNetlifyGraphPath(netlifyGraphConfig)
141
+
142
+ const fullFilename = path.resolve(...netlifyGraphConfig.graphQLOperationsSourceFilename)
143
+ if (!fs.existsSync(fullFilename)) {
144
+ fs.writeFileSync(fullFilename, '')
145
+ fs.closeSync(fs.openSync(fullFilename, 'w'))
146
+ }
147
+
148
+ const source = fs.readFileSync(fullFilename, 'utf8')
149
+
150
+ return source
151
+ }
152
+
153
+ /**
154
+ * Write an operations doc to the filesystem using the given NetlifyGraphConfig
155
+ * @param {NetlifyGraphConfig} netlifyGraphConfig
156
+ * @param {string} operationsDoc The GraphQL operations doc to write
157
+ */
158
+ const writeGraphQLOperationsSourceFile = (netlifyGraphConfig, operationDocString) => {
159
+ const graphqlSource = operationDocString
160
+
161
+ ensureNetlifyGraphPath(netlifyGraphConfig)
162
+ fs.writeFileSync(path.resolve(...netlifyGraphConfig.graphQLOperationsSourceFilename), graphqlSource, 'utf8')
163
+ }
164
+
165
+ /**
166
+ * Write a GraphQL Schema printed in SDL format to the filesystem using the given NetlifyGraphConfig
167
+ * @param {NetlifyGraphConfig} netlifyGraphConfig
168
+ * @param {GraphQLSchema} schema The GraphQL schema to print and write to the filesystem
169
+ */
170
+ const writeGraphQLSchemaFile = (netlifyGraphConfig, schema) => {
171
+ const graphqlSource = printSchema(schema)
172
+
173
+ ensureNetlifyGraphPath(netlifyGraphConfig)
174
+ fs.writeFileSync(path.resolve(...netlifyGraphConfig.graphQLSchemaFilename), graphqlSource, 'utf8')
175
+ }
176
+
177
+ /**
178
+ * Using the given NetlifyGraphConfig, read the GraphQL schema file and return it _unparsed_
179
+ * @param {NetlifyGraphConfig} netlifyGraphConfig
180
+ * @returns {string} GraphQL schema
181
+ */
182
+ const readGraphQLSchemaFile = (netlifyGraphConfig) => {
183
+ ensureNetlifyGraphPath(netlifyGraphConfig)
184
+ return fs.readFileSync(path.resolve(...netlifyGraphConfig.graphQLSchemaFilename), 'utf8')
185
+ }
186
+
187
+ /**
188
+ * Given a NetlifyGraphConfig, read the appropriate files and write a handler for the given operationId to the filesystem
189
+ * @param {NetlifyGraphConfig} netlifyGraphConfig
190
+ * @param {GraphQLSchema} schema The GraphQL schema to use when generating the handler
191
+ * @param {string} operationId The operationId to use when generating the handler
192
+ * @param {object} handlerOptions The options to use when generating the handler
193
+ * @returns
194
+ */
195
+ const generateHandler = (netlifyGraphConfig, schema, operationId, handlerOptions) => {
196
+ let currentOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
197
+ if (currentOperationsDoc.trim().length === 0) {
198
+ currentOperationsDoc = NetlifyGraph.defaultExampleOperationsDoc
199
+ }
200
+
201
+ const result = NetlifyGraph.generateHandlerSource({
202
+ handlerOptions,
203
+ schema,
204
+ netlifyGraphConfig,
205
+ operationId,
206
+ operationsDoc: currentOperationsDoc,
207
+ })
208
+
209
+ if (!result) {
210
+ warn(`No handler was generated for operationId ${operationId}`)
211
+ return
212
+ }
213
+
214
+ const { exportedFiles, operation } = result
215
+
216
+ ensureFunctionsPath(netlifyGraphConfig)
217
+
218
+ if (!exportedFiles) {
219
+ return
220
+ }
221
+
222
+ exportedFiles.forEach((exportedFile) => {
223
+ const { content } = exportedFile
224
+ const isNamed = exportedFile.kind === 'NamedExportedFile'
225
+
226
+ let filenameArr
227
+
228
+ if (isNamed) {
229
+ filenameArr = [...exportedFile.name]
230
+ } else {
231
+ const operationName = (operation.name && operation.name.value) || 'Unnamed'
232
+ const fileExtension = netlifyGraphConfig.language === 'typescript' ? 'ts' : netlifyGraphConfig.extension
233
+ const defaultBaseFilename = `${operationName}.${fileExtension}`
234
+ const baseFilename = defaultBaseFilename
235
+
236
+ filenameArr = [path.sep, ...netlifyGraphConfig.functionsPath, baseFilename]
237
+ }
238
+
239
+ const absoluteFilename = path.resolve(...filenameArr)
240
+
241
+ fs.writeFileSync(absoluteFilename, content)
242
+ })
243
+ }
244
+
245
+ // Export the minimal set of functions that are required for Netlify Graph
246
+ const { buildSchema, parse } = GraphQL
247
+
248
+ /**
249
+ *
250
+ * @param {object} options
251
+ * @param {string} options.siteName The name of the site as used in the Netlify UI url scheme
252
+ * @param {string} options.oneGraphSessionId The oneGraph session id to use when generating the graph-edit link
253
+ * @returns {string} The url to the Netlify Graph UI for the current session
254
+ */
255
+ const getGraphEditUrlBySiteName = ({ oneGraphSessionId, siteName }) => {
256
+ const host = 'app.netlify.com' || process.env.NETLIFY_APP_HOST
257
+ // http because app.netlify.com will redirect to https, and localhost will still work for development
258
+ const url = `http://${host}/sites/${siteName}/graph/explorer?cliSessionId=${oneGraphSessionId}`
259
+
260
+ return url
261
+ }
262
+
263
+ module.exports = {
264
+ buildSchema,
265
+ defaultExampleOperationsDoc: NetlifyGraph.defaultExampleOperationsDoc,
266
+ extractFunctionsFromOperationDoc: NetlifyGraph.extractFunctionsFromOperationDoc,
267
+ generateFunctionsSource: NetlifyGraph.generateFunctionsSource,
268
+ generateFunctionsFile,
269
+ generateHandlerSource: NetlifyGraph.generateHandlerSource,
270
+ generateHandler,
271
+ getGraphEditUrlBySiteName,
272
+ getNetlifyGraphConfig,
273
+ parse,
274
+ readGraphQLOperationsSourceFile,
275
+ readGraphQLSchemaFile,
276
+ writeGraphQLOperationsSourceFile,
277
+ writeGraphQLSchemaFile,
278
+ }