@netlify/dev 4.1.1 → 4.1.3
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/main.cjs +44 -14
- package/dist/main.d.cts +28 -0
- package/dist/main.d.ts +28 -0
- package/dist/main.js +52 -15
- package/package.json +10 -10
package/dist/main.cjs
CHANGED
|
@@ -345,37 +345,50 @@ var NetlifyDev = class {
|
|
|
345
345
|
this.#projectRoot = projectRoot;
|
|
346
346
|
this.#staticHandlerAdditionalDirectories = options.staticFiles?.directories ?? [];
|
|
347
347
|
}
|
|
348
|
-
|
|
349
|
-
|
|
348
|
+
/**
|
|
349
|
+
* Runs a request through the Netlify request chain and returns a `Response`
|
|
350
|
+
* if there's a match. We must not disturb the incoming request unless we
|
|
351
|
+
* know we will be returning a response, so this method takes a read-only
|
|
352
|
+
* request that is safe to access (used for matching) and a getter for the
|
|
353
|
+
* actual request (used for handling matches).
|
|
354
|
+
*
|
|
355
|
+
* @param readRequest Read-only version of the request (without a body)
|
|
356
|
+
* @param getWriteRequest Getter for the actual request (with a body)
|
|
357
|
+
* @param destPath Destination directory for compiled files
|
|
358
|
+
* @param options Options object
|
|
359
|
+
* @returns
|
|
360
|
+
*/
|
|
361
|
+
async handleInEphemeralDirectory(readRequest, getWriteRequest, destPath, options = {}) {
|
|
362
|
+
const edgeFunctionMatch = await this.#edgeFunctionsHandler?.match(readRequest);
|
|
350
363
|
if (edgeFunctionMatch) {
|
|
351
364
|
return {
|
|
352
|
-
response: await edgeFunctionMatch.handle(
|
|
365
|
+
response: await edgeFunctionMatch.handle(getWriteRequest()),
|
|
353
366
|
type: "edge-function"
|
|
354
367
|
};
|
|
355
368
|
}
|
|
356
|
-
const functionMatch = await this.#functionsHandler?.match(
|
|
369
|
+
const functionMatch = await this.#functionsHandler?.match(readRequest, destPath);
|
|
357
370
|
if (functionMatch) {
|
|
358
371
|
if (functionMatch.preferStatic) {
|
|
359
|
-
const staticMatch2 = await this.#staticHandler?.match(
|
|
372
|
+
const staticMatch2 = await this.#staticHandler?.match(readRequest);
|
|
360
373
|
if (staticMatch2) {
|
|
361
374
|
const response = await staticMatch2.handle();
|
|
362
|
-
await this.#headersHandler?.apply(
|
|
375
|
+
await this.#headersHandler?.apply(readRequest, response, options.headersCollector);
|
|
363
376
|
return { response, type: "static" };
|
|
364
377
|
}
|
|
365
378
|
}
|
|
366
|
-
return { response: await functionMatch.handle(
|
|
379
|
+
return { response: await functionMatch.handle(getWriteRequest()), type: "function" };
|
|
367
380
|
}
|
|
368
|
-
const redirectMatch = await this.#redirectsHandler?.match(
|
|
381
|
+
const redirectMatch = await this.#redirectsHandler?.match(readRequest);
|
|
369
382
|
if (redirectMatch) {
|
|
370
383
|
const functionMatch2 = await this.#functionsHandler?.match(new Request(redirectMatch.target), destPath);
|
|
371
384
|
if (functionMatch2 && !functionMatch2.preferStatic) {
|
|
372
385
|
return {
|
|
373
|
-
response: await functionMatch2.handle(
|
|
386
|
+
response: await functionMatch2.handle(getWriteRequest()),
|
|
374
387
|
type: "function"
|
|
375
388
|
};
|
|
376
389
|
}
|
|
377
390
|
const response = await this.#redirectsHandler?.handle(
|
|
378
|
-
|
|
391
|
+
getWriteRequest(),
|
|
379
392
|
redirectMatch,
|
|
380
393
|
async (maybeStaticFile) => {
|
|
381
394
|
const staticMatch2 = await this.#staticHandler?.match(maybeStaticFile);
|
|
@@ -393,17 +406,17 @@ var NetlifyDev = class {
|
|
|
393
406
|
return { response, type: "redirect" };
|
|
394
407
|
}
|
|
395
408
|
}
|
|
396
|
-
const { pathname } = new URL(
|
|
409
|
+
const { pathname } = new URL(readRequest.url);
|
|
397
410
|
if (pathname.startsWith("/.netlify/images")) {
|
|
398
411
|
this.#logger.error(
|
|
399
|
-
|
|
412
|
+
`The Netlify Image CDN is currently only supported in the Netlify CLI. Run ${(0, import_dev_utils.netlifyCommand)("npx netlify dev")} to get started.`
|
|
400
413
|
);
|
|
401
414
|
return;
|
|
402
415
|
}
|
|
403
|
-
const staticMatch = await this.#staticHandler?.match(
|
|
416
|
+
const staticMatch = await this.#staticHandler?.match(readRequest);
|
|
404
417
|
if (staticMatch) {
|
|
405
418
|
const response = await staticMatch.handle();
|
|
406
|
-
await this.#headersHandler?.apply(
|
|
419
|
+
await this.#headersHandler?.apply(readRequest, response, options.headersCollector);
|
|
407
420
|
return { response, type: "static" };
|
|
408
421
|
}
|
|
409
422
|
}
|
|
@@ -424,10 +437,19 @@ var NetlifyDev = class {
|
|
|
424
437
|
});
|
|
425
438
|
return config;
|
|
426
439
|
}
|
|
440
|
+
/**
|
|
441
|
+
* Runs a `Request` through the Netlify request chain. If there is a match,
|
|
442
|
+
* it returns the resulting `Response` object; if not, it returns `undefined`.
|
|
443
|
+
*/
|
|
427
444
|
async handle(request, options = {}) {
|
|
428
445
|
const result = await this.handleAndIntrospect(request, options);
|
|
429
446
|
return result?.response;
|
|
430
447
|
}
|
|
448
|
+
/**
|
|
449
|
+
* Runs a `Request` through the Netlify request chain. If there is a match,
|
|
450
|
+
* it returns an object with the resulting `Response` object and information
|
|
451
|
+
* about the match; if not, it returns `undefined`.
|
|
452
|
+
*/
|
|
431
453
|
async handleAndIntrospect(request, options = {}) {
|
|
432
454
|
await import_node_fs2.promises.mkdir(this.#functionsServePath, { recursive: true });
|
|
433
455
|
const destPath = await import_node_fs2.promises.mkdtemp(import_node_path2.default.join(this.#functionsServePath, `_`));
|
|
@@ -443,6 +465,11 @@ var NetlifyDev = class {
|
|
|
443
465
|
}
|
|
444
466
|
}
|
|
445
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* Runs a Node.js `IncomingMessage` through the Netlify request chain. If
|
|
470
|
+
* there is a match, it returns an object with the resulting `Response`
|
|
471
|
+
* object and information about the match; if not, it returns `undefined`.
|
|
472
|
+
*/
|
|
446
473
|
async handleAndIntrospectNodeRequest(request, options = {}) {
|
|
447
474
|
await import_node_fs2.promises.mkdir(this.#functionsServePath, { recursive: true });
|
|
448
475
|
const destPath = await import_node_fs2.promises.mkdtemp(import_node_path2.default.join(this.#functionsServePath, `_`));
|
|
@@ -566,6 +593,9 @@ var NetlifyDev = class {
|
|
|
566
593
|
async stop() {
|
|
567
594
|
await Promise.allSettled(this.#cleanupJobs.map((task) => task()));
|
|
568
595
|
}
|
|
596
|
+
getEnabledFeatures() {
|
|
597
|
+
return Object.entries(this.#features).filter(([_, enabled]) => enabled).map(([feature]) => feature);
|
|
598
|
+
}
|
|
569
599
|
};
|
|
570
600
|
// Annotate the CommonJS export names for ESM import in node:
|
|
571
601
|
0 && (module.exports = {
|
package/dist/main.d.cts
CHANGED
|
@@ -87,13 +87,40 @@ type ResponseType = 'edge-function' | 'function' | 'redirect' | 'static';
|
|
|
87
87
|
declare class NetlifyDev {
|
|
88
88
|
#private;
|
|
89
89
|
constructor(options: NetlifyDevOptions);
|
|
90
|
+
/**
|
|
91
|
+
* Runs a request through the Netlify request chain and returns a `Response`
|
|
92
|
+
* if there's a match. We must not disturb the incoming request unless we
|
|
93
|
+
* know we will be returning a response, so this method takes a read-only
|
|
94
|
+
* request that is safe to access (used for matching) and a getter for the
|
|
95
|
+
* actual request (used for handling matches).
|
|
96
|
+
*
|
|
97
|
+
* @param readRequest Read-only version of the request (without a body)
|
|
98
|
+
* @param getWriteRequest Getter for the actual request (with a body)
|
|
99
|
+
* @param destPath Destination directory for compiled files
|
|
100
|
+
* @param options Options object
|
|
101
|
+
* @returns
|
|
102
|
+
*/
|
|
90
103
|
private handleInEphemeralDirectory;
|
|
91
104
|
private getConfig;
|
|
105
|
+
/**
|
|
106
|
+
* Runs a `Request` through the Netlify request chain. If there is a match,
|
|
107
|
+
* it returns the resulting `Response` object; if not, it returns `undefined`.
|
|
108
|
+
*/
|
|
92
109
|
handle(request: Request, options?: HandleOptions): Promise<Response | undefined>;
|
|
110
|
+
/**
|
|
111
|
+
* Runs a `Request` through the Netlify request chain. If there is a match,
|
|
112
|
+
* it returns an object with the resulting `Response` object and information
|
|
113
|
+
* about the match; if not, it returns `undefined`.
|
|
114
|
+
*/
|
|
93
115
|
handleAndIntrospect(request: Request, options?: HandleOptions): Promise<{
|
|
94
116
|
response: Response;
|
|
95
117
|
type: ResponseType;
|
|
96
118
|
} | undefined>;
|
|
119
|
+
/**
|
|
120
|
+
* Runs a Node.js `IncomingMessage` through the Netlify request chain. If
|
|
121
|
+
* there is a match, it returns an object with the resulting `Response`
|
|
122
|
+
* object and information about the match; if not, it returns `undefined`.
|
|
123
|
+
*/
|
|
97
124
|
handleAndIntrospectNodeRequest(request: IncomingMessage, options?: HandleOptions): Promise<{
|
|
98
125
|
response: Response;
|
|
99
126
|
type: ResponseType;
|
|
@@ -103,6 +130,7 @@ declare class NetlifyDev {
|
|
|
103
130
|
serverAddress: string | undefined;
|
|
104
131
|
}>;
|
|
105
132
|
stop(): Promise<void>;
|
|
133
|
+
getEnabledFeatures(): string[];
|
|
106
134
|
}
|
|
107
135
|
|
|
108
136
|
export { type Features, NetlifyDev, type ResponseType };
|
package/dist/main.d.ts
CHANGED
|
@@ -87,13 +87,40 @@ type ResponseType = 'edge-function' | 'function' | 'redirect' | 'static';
|
|
|
87
87
|
declare class NetlifyDev {
|
|
88
88
|
#private;
|
|
89
89
|
constructor(options: NetlifyDevOptions);
|
|
90
|
+
/**
|
|
91
|
+
* Runs a request through the Netlify request chain and returns a `Response`
|
|
92
|
+
* if there's a match. We must not disturb the incoming request unless we
|
|
93
|
+
* know we will be returning a response, so this method takes a read-only
|
|
94
|
+
* request that is safe to access (used for matching) and a getter for the
|
|
95
|
+
* actual request (used for handling matches).
|
|
96
|
+
*
|
|
97
|
+
* @param readRequest Read-only version of the request (without a body)
|
|
98
|
+
* @param getWriteRequest Getter for the actual request (with a body)
|
|
99
|
+
* @param destPath Destination directory for compiled files
|
|
100
|
+
* @param options Options object
|
|
101
|
+
* @returns
|
|
102
|
+
*/
|
|
90
103
|
private handleInEphemeralDirectory;
|
|
91
104
|
private getConfig;
|
|
105
|
+
/**
|
|
106
|
+
* Runs a `Request` through the Netlify request chain. If there is a match,
|
|
107
|
+
* it returns the resulting `Response` object; if not, it returns `undefined`.
|
|
108
|
+
*/
|
|
92
109
|
handle(request: Request, options?: HandleOptions): Promise<Response | undefined>;
|
|
110
|
+
/**
|
|
111
|
+
* Runs a `Request` through the Netlify request chain. If there is a match,
|
|
112
|
+
* it returns an object with the resulting `Response` object and information
|
|
113
|
+
* about the match; if not, it returns `undefined`.
|
|
114
|
+
*/
|
|
93
115
|
handleAndIntrospect(request: Request, options?: HandleOptions): Promise<{
|
|
94
116
|
response: Response;
|
|
95
117
|
type: ResponseType;
|
|
96
118
|
} | undefined>;
|
|
119
|
+
/**
|
|
120
|
+
* Runs a Node.js `IncomingMessage` through the Netlify request chain. If
|
|
121
|
+
* there is a match, it returns an object with the resulting `Response`
|
|
122
|
+
* object and information about the match; if not, it returns `undefined`.
|
|
123
|
+
*/
|
|
97
124
|
handleAndIntrospectNodeRequest(request: IncomingMessage, options?: HandleOptions): Promise<{
|
|
98
125
|
response: Response;
|
|
99
126
|
type: ResponseType;
|
|
@@ -103,6 +130,7 @@ declare class NetlifyDev {
|
|
|
103
130
|
serverAddress: string | undefined;
|
|
104
131
|
}>;
|
|
105
132
|
stop(): Promise<void>;
|
|
133
|
+
getEnabledFeatures(): string[];
|
|
106
134
|
}
|
|
107
135
|
|
|
108
136
|
export { type Features, NetlifyDev, type ResponseType };
|
package/dist/main.js
CHANGED
|
@@ -3,7 +3,14 @@ import { promises as fs2 } from "fs";
|
|
|
3
3
|
import path2 from "path";
|
|
4
4
|
import process2 from "process";
|
|
5
5
|
import { resolveConfig } from "@netlify/config";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
ensureNetlifyIgnore,
|
|
8
|
+
getAPIToken,
|
|
9
|
+
mockLocation,
|
|
10
|
+
LocalState,
|
|
11
|
+
HTTPServer,
|
|
12
|
+
netlifyCommand
|
|
13
|
+
} from "@netlify/dev-utils";
|
|
7
14
|
import { EdgeFunctionsHandler } from "@netlify/edge-functions/dev";
|
|
8
15
|
import { FunctionsHandler } from "@netlify/functions/dev";
|
|
9
16
|
import { HeadersHandler } from "@netlify/headers";
|
|
@@ -311,37 +318,50 @@ var NetlifyDev = class {
|
|
|
311
318
|
this.#projectRoot = projectRoot;
|
|
312
319
|
this.#staticHandlerAdditionalDirectories = options.staticFiles?.directories ?? [];
|
|
313
320
|
}
|
|
314
|
-
|
|
315
|
-
|
|
321
|
+
/**
|
|
322
|
+
* Runs a request through the Netlify request chain and returns a `Response`
|
|
323
|
+
* if there's a match. We must not disturb the incoming request unless we
|
|
324
|
+
* know we will be returning a response, so this method takes a read-only
|
|
325
|
+
* request that is safe to access (used for matching) and a getter for the
|
|
326
|
+
* actual request (used for handling matches).
|
|
327
|
+
*
|
|
328
|
+
* @param readRequest Read-only version of the request (without a body)
|
|
329
|
+
* @param getWriteRequest Getter for the actual request (with a body)
|
|
330
|
+
* @param destPath Destination directory for compiled files
|
|
331
|
+
* @param options Options object
|
|
332
|
+
* @returns
|
|
333
|
+
*/
|
|
334
|
+
async handleInEphemeralDirectory(readRequest, getWriteRequest, destPath, options = {}) {
|
|
335
|
+
const edgeFunctionMatch = await this.#edgeFunctionsHandler?.match(readRequest);
|
|
316
336
|
if (edgeFunctionMatch) {
|
|
317
337
|
return {
|
|
318
|
-
response: await edgeFunctionMatch.handle(
|
|
338
|
+
response: await edgeFunctionMatch.handle(getWriteRequest()),
|
|
319
339
|
type: "edge-function"
|
|
320
340
|
};
|
|
321
341
|
}
|
|
322
|
-
const functionMatch = await this.#functionsHandler?.match(
|
|
342
|
+
const functionMatch = await this.#functionsHandler?.match(readRequest, destPath);
|
|
323
343
|
if (functionMatch) {
|
|
324
344
|
if (functionMatch.preferStatic) {
|
|
325
|
-
const staticMatch2 = await this.#staticHandler?.match(
|
|
345
|
+
const staticMatch2 = await this.#staticHandler?.match(readRequest);
|
|
326
346
|
if (staticMatch2) {
|
|
327
347
|
const response = await staticMatch2.handle();
|
|
328
|
-
await this.#headersHandler?.apply(
|
|
348
|
+
await this.#headersHandler?.apply(readRequest, response, options.headersCollector);
|
|
329
349
|
return { response, type: "static" };
|
|
330
350
|
}
|
|
331
351
|
}
|
|
332
|
-
return { response: await functionMatch.handle(
|
|
352
|
+
return { response: await functionMatch.handle(getWriteRequest()), type: "function" };
|
|
333
353
|
}
|
|
334
|
-
const redirectMatch = await this.#redirectsHandler?.match(
|
|
354
|
+
const redirectMatch = await this.#redirectsHandler?.match(readRequest);
|
|
335
355
|
if (redirectMatch) {
|
|
336
356
|
const functionMatch2 = await this.#functionsHandler?.match(new Request(redirectMatch.target), destPath);
|
|
337
357
|
if (functionMatch2 && !functionMatch2.preferStatic) {
|
|
338
358
|
return {
|
|
339
|
-
response: await functionMatch2.handle(
|
|
359
|
+
response: await functionMatch2.handle(getWriteRequest()),
|
|
340
360
|
type: "function"
|
|
341
361
|
};
|
|
342
362
|
}
|
|
343
363
|
const response = await this.#redirectsHandler?.handle(
|
|
344
|
-
|
|
364
|
+
getWriteRequest(),
|
|
345
365
|
redirectMatch,
|
|
346
366
|
async (maybeStaticFile) => {
|
|
347
367
|
const staticMatch2 = await this.#staticHandler?.match(maybeStaticFile);
|
|
@@ -359,17 +379,17 @@ var NetlifyDev = class {
|
|
|
359
379
|
return { response, type: "redirect" };
|
|
360
380
|
}
|
|
361
381
|
}
|
|
362
|
-
const { pathname } = new URL(
|
|
382
|
+
const { pathname } = new URL(readRequest.url);
|
|
363
383
|
if (pathname.startsWith("/.netlify/images")) {
|
|
364
384
|
this.#logger.error(
|
|
365
|
-
|
|
385
|
+
`The Netlify Image CDN is currently only supported in the Netlify CLI. Run ${netlifyCommand("npx netlify dev")} to get started.`
|
|
366
386
|
);
|
|
367
387
|
return;
|
|
368
388
|
}
|
|
369
|
-
const staticMatch = await this.#staticHandler?.match(
|
|
389
|
+
const staticMatch = await this.#staticHandler?.match(readRequest);
|
|
370
390
|
if (staticMatch) {
|
|
371
391
|
const response = await staticMatch.handle();
|
|
372
|
-
await this.#headersHandler?.apply(
|
|
392
|
+
await this.#headersHandler?.apply(readRequest, response, options.headersCollector);
|
|
373
393
|
return { response, type: "static" };
|
|
374
394
|
}
|
|
375
395
|
}
|
|
@@ -390,10 +410,19 @@ var NetlifyDev = class {
|
|
|
390
410
|
});
|
|
391
411
|
return config;
|
|
392
412
|
}
|
|
413
|
+
/**
|
|
414
|
+
* Runs a `Request` through the Netlify request chain. If there is a match,
|
|
415
|
+
* it returns the resulting `Response` object; if not, it returns `undefined`.
|
|
416
|
+
*/
|
|
393
417
|
async handle(request, options = {}) {
|
|
394
418
|
const result = await this.handleAndIntrospect(request, options);
|
|
395
419
|
return result?.response;
|
|
396
420
|
}
|
|
421
|
+
/**
|
|
422
|
+
* Runs a `Request` through the Netlify request chain. If there is a match,
|
|
423
|
+
* it returns an object with the resulting `Response` object and information
|
|
424
|
+
* about the match; if not, it returns `undefined`.
|
|
425
|
+
*/
|
|
397
426
|
async handleAndIntrospect(request, options = {}) {
|
|
398
427
|
await fs2.mkdir(this.#functionsServePath, { recursive: true });
|
|
399
428
|
const destPath = await fs2.mkdtemp(path2.join(this.#functionsServePath, `_`));
|
|
@@ -409,6 +438,11 @@ var NetlifyDev = class {
|
|
|
409
438
|
}
|
|
410
439
|
}
|
|
411
440
|
}
|
|
441
|
+
/**
|
|
442
|
+
* Runs a Node.js `IncomingMessage` through the Netlify request chain. If
|
|
443
|
+
* there is a match, it returns an object with the resulting `Response`
|
|
444
|
+
* object and information about the match; if not, it returns `undefined`.
|
|
445
|
+
*/
|
|
412
446
|
async handleAndIntrospectNodeRequest(request, options = {}) {
|
|
413
447
|
await fs2.mkdir(this.#functionsServePath, { recursive: true });
|
|
414
448
|
const destPath = await fs2.mkdtemp(path2.join(this.#functionsServePath, `_`));
|
|
@@ -532,6 +566,9 @@ var NetlifyDev = class {
|
|
|
532
566
|
async stop() {
|
|
533
567
|
await Promise.allSettled(this.#cleanupJobs.map((task) => task()));
|
|
534
568
|
}
|
|
569
|
+
getEnabledFeatures() {
|
|
570
|
+
return Object.entries(this.#features).filter(([_, enabled]) => enabled).map(([feature]) => feature);
|
|
571
|
+
}
|
|
535
572
|
};
|
|
536
573
|
export {
|
|
537
574
|
NetlifyDev
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/dev",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.3",
|
|
4
4
|
"description": "Emulation of the Netlify environment for local development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -47,20 +47,20 @@
|
|
|
47
47
|
"author": "Netlify Inc.",
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@netlify/api": "^14.0.3",
|
|
50
|
-
"@netlify/types": "2.0.
|
|
50
|
+
"@netlify/types": "2.0.2",
|
|
51
51
|
"tsup": "^8.0.0",
|
|
52
52
|
"vitest": "^3.0.0"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@netlify/blobs": "9.1.
|
|
55
|
+
"@netlify/blobs": "9.1.5",
|
|
56
56
|
"@netlify/config": "^23.0.8",
|
|
57
|
-
"@netlify/dev-utils": "3.1.
|
|
58
|
-
"@netlify/edge-functions": "2.14.
|
|
59
|
-
"@netlify/functions": "4.1.
|
|
60
|
-
"@netlify/headers": "2.0.
|
|
61
|
-
"@netlify/redirects": "3.0.
|
|
62
|
-
"@netlify/runtime": "4.0.
|
|
63
|
-
"@netlify/static": "3.0.
|
|
57
|
+
"@netlify/dev-utils": "3.1.1",
|
|
58
|
+
"@netlify/edge-functions": "2.14.2",
|
|
59
|
+
"@netlify/functions": "4.1.2",
|
|
60
|
+
"@netlify/headers": "2.0.1",
|
|
61
|
+
"@netlify/redirects": "3.0.1",
|
|
62
|
+
"@netlify/runtime": "4.0.2",
|
|
63
|
+
"@netlify/static": "3.0.1",
|
|
64
64
|
"ulid": "^3.0.0"
|
|
65
65
|
}
|
|
66
66
|
}
|