@netlify/agent-runner-cli 1.69.3 → 1.70.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/dist/bin-local.js +1 -1
- package/dist/bin.js +1 -1
- package/dist/index.js +1 -1
- package/dist/skills/netlify-blobs/SKILL.md +396 -0
- package/dist/skills/netlify-edge-functions/SKILL.md +478 -0
- package/dist/skills/netlify-image-cdn/SKILL.md +244 -0
- package/dist/skills/netlify-inference/SKILL.md +1 -33
- package/dist/skills/netlify-serverless/SKILL.md +478 -0
- package/package.json +1 -1
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: netlify-edge-functions
|
|
3
|
+
description: Create and deploy Netlify Edge Functions that run on Deno at the network edge. Use when implementing low-latency middleware, request/response transformations, A/B testing, geolocation routing, or authentication checks at the edge.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Netlify Edge Functions
|
|
7
|
+
|
|
8
|
+
Netlify Edge Functions run on Deno at the network edge, providing low-latency middleware and request/response
|
|
9
|
+
transformations. They share the same handler signature pattern as serverless functions (Web API Request/Response) but
|
|
10
|
+
use the Deno runtime with Web APIs built in. Edge functions are configured with a path pattern and only paths matching
|
|
11
|
+
those patterns will run the edge function.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
Create an edge function file in the `netlify/edge-functions/` directory:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// netlify/edge-functions/hello.ts
|
|
19
|
+
import type { Context, Config } from '@netlify/edge-functions'
|
|
20
|
+
|
|
21
|
+
export default async (req: Request, context: Context) => {
|
|
22
|
+
const name = new URL(req.url).searchParams.get('name') || 'world'
|
|
23
|
+
return new Response(`Hello, ${name}!`)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const config: Config = {
|
|
27
|
+
path: '/hello',
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
// netlify/edge-functions/hello.js
|
|
33
|
+
export default async (req, context) => {
|
|
34
|
+
const name = new URL(req.url).searchParams.get('name') || 'world'
|
|
35
|
+
return new Response(`Hello, ${name}!`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const config = {
|
|
39
|
+
path: '/hello',
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Deploy and invoke at the configured `path`.
|
|
44
|
+
|
|
45
|
+
ALWAYS use TypeScript (`.ts`) if other functions in the project are TypeScript or if there are no existing edge functions.
|
|
46
|
+
ONLY use vanilla JavaScript if there are other `.js` files in the edge functions directory. DO NOT put global logic outside
|
|
47
|
+
of the exported function unless it is wrapped in a function definition. ALWAYS use the latest format of an edge
|
|
48
|
+
function structure.
|
|
49
|
+
|
|
50
|
+
If using TypeScript, ensure types are installed from `npm install @netlify/edge-functions`.
|
|
51
|
+
|
|
52
|
+
## Function Structure & Placement
|
|
53
|
+
|
|
54
|
+
**Default directory:** `netlify/edge-functions/` (relative to site base directory)
|
|
55
|
+
|
|
56
|
+
**Naming conventions:**
|
|
57
|
+
- Use `.ts` (TypeScript, recommended) or `.js` (JavaScript) extensions (not `.mts`/`.mjs` — Deno natively supports ESM)
|
|
58
|
+
- Filename becomes the function name
|
|
59
|
+
- One default export per file
|
|
60
|
+
|
|
61
|
+
**Valid function paths:**
|
|
62
|
+
- `netlify/edge-functions/hello.ts`
|
|
63
|
+
- `netlify/edge-functions/hello/index.ts`
|
|
64
|
+
- `netlify/edge-functions/hello/hello.ts`
|
|
65
|
+
|
|
66
|
+
**Custom directory** via `netlify.toml`:
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
[build]
|
|
70
|
+
edge_functions = "my_edge_functions"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Handler Signature
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
export default async (req: Request, context: Context) => Response | void
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The first argument is a standard Web API Request object. The second argument is a Netlify-specific `Context` object.
|
|
80
|
+
Return a standard Web API Response, or return nothing to pass through to the next handler in the chain.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import type { Context } from '@netlify/edge-functions'
|
|
84
|
+
|
|
85
|
+
export default async (req: Request, context: Context) => {
|
|
86
|
+
const body = await req.json()
|
|
87
|
+
return Response.json({ received: body })
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Deno Runtime & Module Support
|
|
92
|
+
|
|
93
|
+
Edge functions use Deno as runtime and should attempt to use built-in methods where possible.
|
|
94
|
+
|
|
95
|
+
### Node.js Built-in Modules
|
|
96
|
+
|
|
97
|
+
Use the `node:` prefix to import Node.js built-in modules:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { Buffer } from 'node:buffer'
|
|
101
|
+
import { randomBytes } from 'node:crypto'
|
|
102
|
+
import process from 'node:process'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### npm Packages (beta)
|
|
106
|
+
|
|
107
|
+
Install via `npm install` and import by package name:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import lodash from 'lodash'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Some npm packages with native binaries (e.g., Prisma) or dynamic imports (e.g., cowsay) may not work.
|
|
114
|
+
|
|
115
|
+
### Deno URL Imports
|
|
116
|
+
|
|
117
|
+
Import modules directly by URL:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import React from 'https://esm.sh/react'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Import Maps
|
|
124
|
+
|
|
125
|
+
Use an import map to alias third-party modules with shorthand names. Define mappings in a separate JSON file (not in
|
|
126
|
+
`deno.json`):
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"imports": {
|
|
131
|
+
"html-rewriter": "https://ghuc.cc/worker-tools/html-rewriter/index.ts"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Enable import maps in `netlify.toml`:
|
|
137
|
+
|
|
138
|
+
```toml
|
|
139
|
+
[functions]
|
|
140
|
+
deno_import_map = "./path/to/your/import_map.json"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Then import by name:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { HTMLRewriter } from 'html-rewriter'
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Available Web APIs
|
|
150
|
+
|
|
151
|
+
Edge functions have access to standard Web APIs:
|
|
152
|
+
|
|
153
|
+
- **Fetch API:** `fetch`, `Request`, `Response`, `URL`, `File`, `Blob`
|
|
154
|
+
- **Encoding:** `TextEncoder`, `TextDecoder`, `TextEncoderStream`, `TextDecoderStream`, `atob`, `btoa`
|
|
155
|
+
- **Crypto:** `crypto.randomUUID()`, `crypto.getRandomValues()`, `crypto.subtle` (SubtleCrypto)
|
|
156
|
+
- **Streams:** `ReadableStream`, `WritableStream`, `TransformStream`
|
|
157
|
+
- **Timers:** `setTimeout`, `clearTimeout`, `setInterval`
|
|
158
|
+
- **Other:** `console.*`, `Performance`, `WebSocket`, `URLPattern`
|
|
159
|
+
|
|
160
|
+
## In-Code Config & Routing
|
|
161
|
+
|
|
162
|
+
Prefer to use in-code configuration via exporting a `config` object. Prefer to provide a friendly path using the
|
|
163
|
+
config object. `path` and `excludedPath` support substring patterns or the URLPattern syntax from the web platform.
|
|
164
|
+
Unless explicitly asked to modify other properties, only set `path`, `pattern`, `excludedPath` when creating functions.
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import type { Config } from '@netlify/edge-functions'
|
|
168
|
+
|
|
169
|
+
export default async (req: Request, context: Context) => {
|
|
170
|
+
return new Response('Hello from the edge')
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export const config: Config = {
|
|
174
|
+
path: '/api/edge/*',
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Config properties:**
|
|
179
|
+
|
|
180
|
+
| Property | Type | Description |
|
|
181
|
+
|----------|------|-------------|
|
|
182
|
+
| `path` | `string \| string[]` | URLPattern expression for paths. Must start with `/` |
|
|
183
|
+
| `excludedPath` | `string \| string[]` | Paths to exclude from execution. Must start with `/` |
|
|
184
|
+
| `pattern` | `RegExp \| RegExp[]` | Regex for path matching (alternative to `path`) |
|
|
185
|
+
| `excludedPattern` | `RegExp \| RegExp[]` | Regex patterns to exclude |
|
|
186
|
+
| `method` | `string \| string[]` | HTTP method(s) to match (`GET`, `POST`, etc.) |
|
|
187
|
+
| `onError` | `'bypass' \| 'fail'` | Error behavior (`'bypass'` serves static/origin) |
|
|
188
|
+
| `cache` | `'manual'` | Enables CDN response caching |
|
|
189
|
+
|
|
190
|
+
**Route parameters:**
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// :param - named parameter
|
|
194
|
+
export const config: Config = { path: '/api/users/:id' }
|
|
195
|
+
// context.params.id = '123' for /api/users/123
|
|
196
|
+
|
|
197
|
+
// * - wildcard
|
|
198
|
+
export const config: Config = { path: '/api/*' }
|
|
199
|
+
// Matches /api/anything/here
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Multiple paths:**
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
export const config: Config = {
|
|
206
|
+
path: ['/api/edge/:name', '/edge/:name'],
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Context Object
|
|
211
|
+
|
|
212
|
+
The `context` parameter provides Netlify-specific metadata. All standard context properties are available:
|
|
213
|
+
|
|
214
|
+
### Standard Properties
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
context.ip // string - client IP address
|
|
218
|
+
context.geo.city // string - city name
|
|
219
|
+
context.geo.country // { code: string, name: string } - ISO 3166
|
|
220
|
+
context.geo.latitude // number
|
|
221
|
+
context.geo.longitude // number
|
|
222
|
+
context.geo.subdivision // { code: string, name: string } - ISO 3166
|
|
223
|
+
context.geo.timezone // string - IANA timezone
|
|
224
|
+
context.geo.postalCode // string
|
|
225
|
+
context.site.id // string - unique site ID
|
|
226
|
+
context.site.name // string - site subdomain name
|
|
227
|
+
context.site.url // string - primary site URL
|
|
228
|
+
context.deploy.context // string - e.g., 'production', 'deploy-preview'
|
|
229
|
+
context.deploy.id // string - unique deploy ID
|
|
230
|
+
context.deploy.published // boolean - is this the published deploy?
|
|
231
|
+
context.account.id // string - team/account ID
|
|
232
|
+
context.requestId // string - unique request identifier
|
|
233
|
+
context.params // route parameters from config.path
|
|
234
|
+
context.server.region // string - e.g., 'us-east-1'
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### `context.cookies`
|
|
238
|
+
|
|
239
|
+
Simplified cookie interface:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
const session = context.cookies.get('session')
|
|
243
|
+
context.cookies.set({ name: 'session', value: 'abc123', path: '/', httpOnly: true })
|
|
244
|
+
context.cookies.delete('session')
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### `context.waitUntil(promise)`
|
|
248
|
+
|
|
249
|
+
Extends execution after the response is sent:
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
export default async (req: Request, context: Context) => {
|
|
253
|
+
context.waitUntil(
|
|
254
|
+
fetch('https://analytics.example.com/track', {
|
|
255
|
+
method: 'POST',
|
|
256
|
+
body: JSON.stringify({ path: new URL(req.url).pathname }),
|
|
257
|
+
}),
|
|
258
|
+
)
|
|
259
|
+
return new Response('OK')
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Edge-Only: `context.next()`
|
|
264
|
+
|
|
265
|
+
Passes the request to the next edge function in the chain or to the origin.
|
|
266
|
+
|
|
267
|
+
**IMPORTANT:** When the goal is to skip edge function execution and let the request proceed normally, prefer an empty
|
|
268
|
+
`return` (or `return undefined`) over `return context.next()`. An empty return is the most performant way to terminate
|
|
269
|
+
execution — calling `context.next()` when you don't need the response is unnecessary and slows down overall execution.
|
|
270
|
+
|
|
271
|
+
ONLY use `context.next()` when you need to read or modify the upstream response (e.g., adding headers, transforming
|
|
272
|
+
the body). Note that empty returns don't set cache-control headers, so the function will always execute on every
|
|
273
|
+
request. To cache responses, you must use `context.next()`, set appropriate cache headers, and return it explicitly.
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
// GOOD: Skip execution and let the request proceed (most performant)
|
|
277
|
+
export default async (req: Request, context: Context) => {
|
|
278
|
+
if (!shouldProcess(req)) {
|
|
279
|
+
return // terminates execution, request proceeds normally
|
|
280
|
+
}
|
|
281
|
+
// ... process request
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// GOOD: Modify the upstream response (valid use of context.next())
|
|
285
|
+
export default async (req: Request, context: Context) => {
|
|
286
|
+
const response = await context.next()
|
|
287
|
+
response.headers.set('x-custom-header', 'value')
|
|
288
|
+
return response
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Optionally use conditional requests:
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
const response = await context.next({ sendConditionalRequest: true })
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Edge-Only: `context.nextRequest()`
|
|
299
|
+
|
|
300
|
+
Passes a modified request to the next handler:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
export default async (req: Request, context: Context) => {
|
|
304
|
+
const modifiedReq = new Request(req.url, {
|
|
305
|
+
headers: { ...Object.fromEntries(req.headers), 'x-added': 'true' },
|
|
306
|
+
})
|
|
307
|
+
return context.nextRequest(modifiedReq)
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Global `Netlify` Object
|
|
312
|
+
|
|
313
|
+
Available in all edge function contexts:
|
|
314
|
+
|
|
315
|
+
### `Netlify.env`
|
|
316
|
+
|
|
317
|
+
Access environment variables:
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
const apiKey = Netlify.env.get('API_KEY') // string | undefined
|
|
321
|
+
const exists = Netlify.env.has('API_KEY') // boolean
|
|
322
|
+
const all = Netlify.env.toObject() // Record<string, string>
|
|
323
|
+
|
|
324
|
+
// Scoped to current invocation only
|
|
325
|
+
Netlify.env.set('TEMP_VAR', 'value')
|
|
326
|
+
Netlify.env.delete('TEMP_VAR')
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
ONLY use `Netlify.env.*` for interacting with environment variables in code. Do not use `process.env` or `Deno.env`.
|
|
330
|
+
|
|
331
|
+
### `Netlify.context`
|
|
332
|
+
|
|
333
|
+
Same as the `context` parameter in the handler. Available from outside the handler scope (e.g., imported modules).
|
|
334
|
+
Returns `null` outside a function invocation.
|
|
335
|
+
|
|
336
|
+
## netlify.toml Configuration
|
|
337
|
+
|
|
338
|
+
ONLY use `netlify.toml` `[[edge_functions]]` blocks for precise function execution order control. DO NOT use
|
|
339
|
+
`netlify.toml` if there are no edge function ordering requirements. When controlling order, include all edge functions.
|
|
340
|
+
|
|
341
|
+
```toml
|
|
342
|
+
[[edge_functions]]
|
|
343
|
+
function = "auth"
|
|
344
|
+
path = "/admin"
|
|
345
|
+
|
|
346
|
+
[[edge_functions]]
|
|
347
|
+
function = "injector"
|
|
348
|
+
path = "/admin"
|
|
349
|
+
cache = "manual"
|
|
350
|
+
|
|
351
|
+
[[edge_functions]]
|
|
352
|
+
function = "auth"
|
|
353
|
+
path = "/blog/*"
|
|
354
|
+
|
|
355
|
+
[[edge_functions]]
|
|
356
|
+
function = "rewriter"
|
|
357
|
+
path = "/blog/*"
|
|
358
|
+
|
|
359
|
+
[[edge_functions]]
|
|
360
|
+
function = "highlight"
|
|
361
|
+
pattern = "/products/(.*)"
|
|
362
|
+
excludedPattern = "/products/things/(.*)"
|
|
363
|
+
|
|
364
|
+
[[edge_functions]]
|
|
365
|
+
function = "common"
|
|
366
|
+
path = "/*"
|
|
367
|
+
excludedPath = "/img/*"
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
**Edge function properties in `netlify.toml`:**
|
|
371
|
+
|
|
372
|
+
| Property | Type | Description |
|
|
373
|
+
|----------|------|-------------|
|
|
374
|
+
| `function` | `string` | Name of the edge function |
|
|
375
|
+
| `path` | `string` | URL pattern to trigger the function (must start with `/`) |
|
|
376
|
+
| `excludedPath` | `string \| string[]` | Routes to exclude from `path` |
|
|
377
|
+
| `pattern` | `string` | Regex-based path matching |
|
|
378
|
+
| `excludedPattern` | `string \| string[]` | Regex patterns to exclude |
|
|
379
|
+
| `cache` | `string` | Set to `'manual'` to enable response caching |
|
|
380
|
+
|
|
381
|
+
## Execution Order
|
|
382
|
+
|
|
383
|
+
When multiple edge functions match the same path, they execute in this order:
|
|
384
|
+
|
|
385
|
+
1. Configuration-based edge functions (`netlify.toml`) run first
|
|
386
|
+
2. Framework-generated edge functions execute before user-defined functions
|
|
387
|
+
3. Non-cached edge functions execute before cached (`cache: 'manual'`) functions
|
|
388
|
+
4. Inline-declared `config` exports override duplicate `netlify.toml` declarations for the same function
|
|
389
|
+
5. Multiple inline edge functions sort alphabetically by filename
|
|
390
|
+
|
|
391
|
+
## Caveats
|
|
392
|
+
|
|
393
|
+
- If an edge function returns a response, redirects for that path DO NOT occur
|
|
394
|
+
- Edge functions DO NOT execute for rewritten static routing targets
|
|
395
|
+
- `fetch()` or `new URL()` with the same site origin triggers a new request chain, re-running matching functions.
|
|
396
|
+
Use `context.next()` to continue processing instead of re-triggering functions
|
|
397
|
+
- Can only rewrite requests to same-site URLs (use `fetch()` for external content)
|
|
398
|
+
- Cached edge function responses override existing static files at the same path
|
|
399
|
+
- Function failure behavior depends on the `onError` configuration
|
|
400
|
+
|
|
401
|
+
## Limits
|
|
402
|
+
|
|
403
|
+
| Resource | Limit |
|
|
404
|
+
|----------|-------|
|
|
405
|
+
| Code size (compressed) | 20 MB |
|
|
406
|
+
| Memory per deployment | 512 MB |
|
|
407
|
+
| CPU time per request | 50 ms (excludes waiting time) |
|
|
408
|
+
| Response header timeout | 40 seconds |
|
|
409
|
+
|
|
410
|
+
**Incompatibilities:**
|
|
411
|
+
- Netlify's split testing feature
|
|
412
|
+
- Custom headers from `_headers` or `netlify.toml` config (use response headers in code instead)
|
|
413
|
+
- Netlify prerendering on paths served by edge functions
|
|
414
|
+
- Not included in Netlify's HIPAA-compliant hosting offering
|
|
415
|
+
|
|
416
|
+
**Restrictions:**
|
|
417
|
+
- Can only rewrite requests to same-site URLs
|
|
418
|
+
- Cached edge functions override existing static files
|
|
419
|
+
- No local caching in development (HTTP cache headers are ignored locally)
|
|
420
|
+
- Multiple framework adapters may generate conflicting edge functions
|
|
421
|
+
|
|
422
|
+
## Common Errors & Solutions
|
|
423
|
+
|
|
424
|
+
### "Edge function not found"
|
|
425
|
+
|
|
426
|
+
**Cause:** Function file not in the correct directory or missing `config.path`.
|
|
427
|
+
|
|
428
|
+
**Fix:**
|
|
429
|
+
|
|
430
|
+
1. Place function in `netlify/edge-functions/` (or configured directory)
|
|
431
|
+
2. Use `.ts` or `.js` extension
|
|
432
|
+
3. Ensure the file has a default export
|
|
433
|
+
4. Ensure the function exports a `config` with a `path` or `pattern`
|
|
434
|
+
|
|
435
|
+
### "CPU time exceeded" (50ms limit)
|
|
436
|
+
|
|
437
|
+
**Cause:** Function CPU-intensive work exceeds the 50ms CPU time limit.
|
|
438
|
+
|
|
439
|
+
**Fix:**
|
|
440
|
+
|
|
441
|
+
1. Optimize hot paths — the 50ms limit is CPU time only, not wall-clock time
|
|
442
|
+
2. Waiting on `fetch()`, `context.next()`, or other I/O does not count against the CPU limit
|
|
443
|
+
3. For heavy computation, offload to a serverless function instead
|
|
444
|
+
|
|
445
|
+
### Module import failures
|
|
446
|
+
|
|
447
|
+
**Cause:** Incompatible npm package or incorrect import syntax.
|
|
448
|
+
|
|
449
|
+
**Fix:**
|
|
450
|
+
|
|
451
|
+
1. Use `node:` prefix for Node.js built-in modules (`node:crypto`, not `crypto`)
|
|
452
|
+
2. Check that npm packages do not rely on native binaries or unsupported dynamic imports
|
|
453
|
+
3. For Deno URL imports, ensure the URL is accessible and returns valid ESM
|
|
454
|
+
|
|
455
|
+
### "CORS errors" in browser
|
|
456
|
+
|
|
457
|
+
**Cause:** Missing CORS headers on function response. NEVER add CORS headers unless explicitly requested by the user.
|
|
458
|
+
|
|
459
|
+
**Fix** (only when user asks for CORS support):
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
return new Response(JSON.stringify(data), {
|
|
463
|
+
headers: {
|
|
464
|
+
'Content-Type': 'application/json',
|
|
465
|
+
'Access-Control-Allow-Origin': '*',
|
|
466
|
+
},
|
|
467
|
+
})
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Environment variable is undefined
|
|
471
|
+
|
|
472
|
+
**Cause:** Variable not available in the function context.
|
|
473
|
+
|
|
474
|
+
**Fix:**
|
|
475
|
+
|
|
476
|
+
1. Use `Netlify.env.get('VAR_NAME')` — do not use `process.env` or `Deno.env`
|
|
477
|
+
2. Ensure the variable is set in Netlify UI with correct scopes (Runtime)
|
|
478
|
+
3. Deploy to Netlify for env var injection
|