Skip to content

Commit 0349686

Browse files
authored
feat: support ai gateway for local edge functions (#7637)
* feat: support ai gateway for local edge functions * update to published dep * package lock
1 parent e2fd25a commit 0349686

File tree

8 files changed

+4957
-18950
lines changed

8 files changed

+4957
-18950
lines changed

package-lock.json

Lines changed: 4922 additions & 18943 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,8 @@
6565
"@netlify/build-info": "10.0.8",
6666
"@netlify/config": "24.0.4",
6767
"@netlify/dev-utils": "4.2.0",
68-
"@netlify/edge-bundler": "14.5.5",
68+
"@netlify/edge-bundler": "^14.5.6",
6969
"@netlify/edge-functions": "2.18.1",
70-
"@netlify/edge-functions-bootstrap": "2.14.0",
7170
"@netlify/headers-parser": "9.0.2",
7271
"@netlify/local-functions-proxy": "2.0.3",
7372
"@netlify/redirect-parser": "15.0.3",
@@ -159,6 +158,7 @@
159158
"@bugsnag/js": "8.4.0",
160159
"@eslint/compat": "1.3.2",
161160
"@eslint/js": "9.24.0",
161+
"@netlify/edge-functions-bootstrap": "^2.17.1",
162162
"@netlify/functions": "3.0.4",
163163
"@netlify/types": "2.0.3",
164164
"@sindresorhus/slugify": "2.2.1",
@@ -170,6 +170,7 @@
170170
"@types/envinfo": "7.8.4",
171171
"@types/eslint-config-prettier": "6.11.3",
172172
"@types/etag": "1.8.4",
173+
"@types/express": "^4.17.23",
173174
"@types/folder-walker": "3.2.4",
174175
"@types/gitconfiglocal": "2.0.3",
175176
"@types/inquirer": "9.0.9",

src/commands/dev/dev.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ export const dev = async (options: OptionValues, command: BaseCommand) => {
257257

258258
await startProxyServer({
259259
addonsUrls,
260+
aiGatewayContext,
260261
api,
261262
blobsContext,
262263
command,

src/lib/edge-functions/headers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Buffer } from 'buffer'
22

33
export const headers = {
4+
AIGateway: 'x-nf-ai-gateway',
45
BlobsInfo: 'x-nf-blobs-info',
56
DeployID: 'x-nf-deploy-id',
67
DeployContext: 'x-nf-deploy-context',

src/lib/edge-functions/proxy.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { IncomingMessage, ClientRequest } from 'http'
44
import { join, resolve } from 'path'
55

66
import * as bundler from '@netlify/edge-bundler'
7+
import type { AIGatewayContext } from '@netlify/ai/bootstrap'
78
import getAvailablePort from 'get-port'
89

910
import type BaseCommand from '../../commands/base-command.js'
@@ -75,6 +76,7 @@ const createAccountInfoHeader = ({ id }: { id: string }) => {
7576

7677
export const initializeProxy = async ({
7778
accountId,
79+
aiGatewayContext,
7880
blobsContext,
7981
command,
8082
config,
@@ -95,6 +97,7 @@ export const initializeProxy = async ({
9597
state,
9698
}: {
9799
accountId: string
100+
aiGatewayContext?: AIGatewayContext | null
98101
blobsContext: BlobsContextWithEdgeAccess
99102
command: BaseCommand
100103
config: NormalizedCachedConfigConfig
@@ -124,6 +127,7 @@ export const initializeProxy = async ({
124127
// the network if needed. We don't want to wait for that to be completed, or
125128
// the command will be left hanging.
126129
const server = prepareServer({
130+
aiGatewayContext,
127131
command,
128132
config,
129133
configPath,
@@ -162,6 +166,10 @@ export const initializeProxy = async ({
162166
).toString('base64')
163167
}
164168

169+
if (aiGatewayContext) {
170+
req.headers[headers.AIGateway] = Buffer.from(JSON.stringify(aiGatewayContext)).toString('base64')
171+
}
172+
165173
await registry.initialize()
166174

167175
const url = new URL(req.url!, `http://${LOCAL_HOST}:${mainPort}`)
@@ -194,6 +202,7 @@ export const isEdgeFunctionsRequest = (req: IncomingMessage): req is ExtendedInc
194202
Object.hasOwn(req, headersSymbol)
195203

196204
const prepareServer = async ({
205+
aiGatewayContext,
197206
command,
198207
config,
199208
configPath,
@@ -207,6 +216,7 @@ const prepareServer = async ({
207216
projectDir,
208217
repositoryRoot,
209218
}: {
219+
aiGatewayContext?: AIGatewayContext | null
210220
command: BaseCommand
211221
config: NormalizedCachedConfigConfig
212222
configPath: string
@@ -245,8 +255,9 @@ const prepareServer = async ({
245255
servePath,
246256
})
247257
const registry = new EdgeFunctionsRegistry({
248-
command,
258+
aiGatewayContext,
249259
bundler,
260+
command,
250261
config,
251262
configPath,
252263
debug,

src/lib/edge-functions/registry.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { join } from 'path'
33
import { fileURLToPath } from 'url'
44

55
import type { Declaration, EdgeFunction, FunctionConfig, Manifest, ModuleGraph } from '@netlify/edge-bundler'
6+
import type { AIGatewayContext } from '@netlify/ai/bootstrap'
67
import { watchDebounced } from '@netlify/dev-utils'
78

89
import BaseCommand from '../../commands/base-command.js'
@@ -31,19 +32,20 @@ type RunIsolate = Awaited<ReturnType<typeof import('@netlify/edge-bundler').serv
3132
type ModuleJson = ModuleGraph['modules'][number]
3233

3334
interface EdgeFunctionsRegistryOptions {
34-
command: BaseCommand
35+
aiGatewayContext?: AIGatewayContext | null
3536
bundler: typeof import('@netlify/edge-bundler')
37+
command: BaseCommand
3638
config: NormalizedCachedConfigConfig
3739
configPath: string
3840
debug: boolean
3941
directories: string[]
4042
env: Record<string, { sources: string[]; value: string }>
4143
featureFlags: FeatureFlags
4244
getUpdatedConfig: () => Promise<NormalizedCachedConfigConfig>
45+
importMapFromTOML?: string
4346
projectDir: string
4447
runIsolate: RunIsolate
4548
servePath: string
46-
importMapFromTOML?: string
4749
}
4850

4951
/**
@@ -92,6 +94,7 @@ function traverseLocalDependencies(
9294
export class EdgeFunctionsRegistry {
9395
public importMapFromDeployConfig?: string
9496

97+
private aiGatewayContext?: AIGatewayContext | null
9598
private buildError: Error | null = null
9699
private bundler: typeof import('@netlify/edge-bundler')
97100
private configPath: string
@@ -125,6 +128,7 @@ export class EdgeFunctionsRegistry {
125128
private command: BaseCommand
126129

127130
constructor({
131+
aiGatewayContext,
128132
bundler,
129133
command,
130134
config,
@@ -138,6 +142,7 @@ export class EdgeFunctionsRegistry {
138142
runIsolate,
139143
servePath,
140144
}: EdgeFunctionsRegistryOptions) {
145+
this.aiGatewayContext = aiGatewayContext
141146
this.command = command
142147
this.bundler = bundler
143148
this.configPath = configPath

src/utils/proxy-server.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { AIGatewayContext } from '@netlify/ai/bootstrap'
2+
13
import type BaseCommand from '../commands/base-command.js'
24
import type { $TSFixMe, NetlifyOptions } from '../commands/types.js'
35
import type { BlobsContextWithEdgeAccess } from '../lib/blobs/blobs.js'
@@ -42,6 +44,7 @@ export const generateInspectSettings = (
4244
export const startProxyServer = async ({
4345
accountId,
4446
addonsUrls,
47+
aiGatewayContext,
4548
api,
4649
blobsContext,
4750
command,
@@ -65,6 +68,7 @@ export const startProxyServer = async ({
6568
}: {
6669
accountId: string | undefined
6770
addonsUrls: $TSFixMe
71+
aiGatewayContext?: AIGatewayContext | null
6872
api?: NetlifyOptions['api']
6973
blobsContext?: BlobsContextWithEdgeAccess
7074
command: BaseCommand
@@ -89,6 +93,7 @@ export const startProxyServer = async ({
8993
}) => {
9094
const url = await startProxy({
9195
addonsUrls,
96+
aiGatewayContext,
9297
blobsContext,
9398
command,
9499
config,

src/utils/proxy.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import util from 'util'
1414
import zlib from 'zlib'
1515

1616
import { renderFunctionErrorPage } from '@netlify/dev-utils'
17+
import type { AIGatewayContext } from '@netlify/ai/bootstrap'
1718
import contentType from 'content-type'
1819
import cookie from 'cookie'
1920
import { getProperty } from 'dot-prop'
@@ -912,6 +913,7 @@ type EdgeFunctionsProxy = Awaited<ReturnType<typeof initializeEdgeFunctionsProxy
912913
export const startProxy = async function ({
913914
accountId,
914915
addonsUrls,
916+
aiGatewayContext,
915917
api,
916918
blobsContext,
917919
command,
@@ -937,6 +939,7 @@ export const startProxy = async function ({
937939
settings: ServerSettings
938940
disableEdgeFunctions: boolean
939941
getUpdatedConfig: () => Promise<NormalizedCachedConfigConfig>
942+
aiGatewayContext?: AIGatewayContext | null
940943
} & Record<string, $TSFixMe>) {
941944
const secondaryServerPort = settings.https ? await getAvailablePort() : null
942945
const functionsServer = settings.functionsPort ? `http://127.0.0.1:${settings.functionsPort}` : null
@@ -949,8 +952,10 @@ export const startProxy = async function ({
949952
)
950953
} else {
951954
edgeFunctionsProxy = await initializeEdgeFunctionsProxy({
952-
command,
955+
accountId,
956+
aiGatewayContext,
953957
blobsContext,
958+
command,
954959
config,
955960
configPath,
956961
debug,
@@ -966,7 +971,6 @@ export const startProxy = async function ({
966971
projectDir,
967972
repositoryRoot,
968973
siteInfo,
969-
accountId,
970974
state,
971975
})
972976
}

0 commit comments

Comments
 (0)