@netlify/dev 1.1.2 → 2.0.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/main.cjs CHANGED
@@ -30,11 +30,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/main.ts
31
31
  var main_exports = {};
32
32
  __export(main_exports, {
33
- handle: () => handle
33
+ handle: () => handle,
34
+ start: () => start
34
35
  });
35
36
  module.exports = __toCommonJS(main_exports);
36
- var import_node_path2 = __toESM(require("path"), 1);
37
- var import_node_process2 = __toESM(require("process"), 1);
37
+ var import_node_path3 = __toESM(require("path"), 1);
38
+ var import_node_process3 = __toESM(require("process"), 1);
38
39
  var import_dev = require("@netlify/functions/dev");
39
40
  var import_redirects = require("@netlify/redirects");
40
41
  var import_static = require("@netlify/static");
@@ -47,17 +48,17 @@ var import_dev_utils = require("@netlify/dev-utils");
47
48
 
48
49
  // src/lib/fs.ts
49
50
  var import_node_fs = require("fs");
50
- var isDirectory = async (path3) => {
51
+ var isDirectory = async (path4) => {
51
52
  try {
52
- const stat = await import_node_fs.promises.stat(path3);
53
+ const stat = await import_node_fs.promises.stat(path4);
53
54
  return stat.isDirectory();
54
55
  } catch {
55
56
  }
56
57
  return false;
57
58
  };
58
- var isFile = async (path3) => {
59
+ var isFile = async (path4) => {
59
60
  try {
60
- const stat = await import_node_fs.promises.stat(path3);
61
+ const stat = await import_node_fs.promises.stat(path4);
61
62
  return stat.isFile();
62
63
  } catch {
63
64
  }
@@ -86,63 +87,151 @@ var getConfig = async ({
86
87
  return { config, siteID };
87
88
  };
88
89
 
90
+ // src/lib/runtime.ts
91
+ var import_node_path2 = __toESM(require("path"), 1);
92
+ var import_node_process2 = __toESM(require("process"), 1);
93
+ var import_server = require("@netlify/blobs/server");
94
+ var import_runtime = require("@netlify/runtime");
95
+ var restoreEnvironment = (snapshot) => {
96
+ for (const key in snapshot) {
97
+ if (snapshot[key] === void 0) {
98
+ delete import_node_process2.default.env[key];
99
+ } else {
100
+ import_node_process2.default.env[key] = snapshot[key];
101
+ }
102
+ }
103
+ };
104
+ var getRuntime = async ({ blobs, deployID, projectRoot, siteID }) => {
105
+ const blobsToken = Math.random().toString().slice(2);
106
+ const blobsServer = blobs ? new import_server.BlobsServer({
107
+ directory: import_node_path2.default.join(projectRoot, ".netlify", "blobs-serve"),
108
+ token: blobsToken
109
+ }) : null;
110
+ const blobsServerDetails = await blobsServer?.start();
111
+ const envSnapshot = {};
112
+ const env = {
113
+ delete: (key) => {
114
+ envSnapshot[key] = envSnapshot[key] || import_node_process2.default.env[key];
115
+ delete import_node_process2.default.env[key];
116
+ },
117
+ get: (key) => import_node_process2.default.env[key],
118
+ has: (key) => Boolean(import_node_process2.default.env[key]),
119
+ set: (key, value) => {
120
+ envSnapshot[key] = envSnapshot[key] || import_node_process2.default.env[key];
121
+ import_node_process2.default.env[key] = value;
122
+ },
123
+ toObject: () => import_node_process2.default.env
124
+ };
125
+ (0, import_runtime.startRuntime)({
126
+ blobs: blobsServerDetails ? {
127
+ edgeURL: `http://localhost:${blobsServerDetails.port}`,
128
+ uncachedEdgeURL: `http://localhost:${blobsServerDetails.port}`,
129
+ primaryRegion: "us-east-2",
130
+ token: blobsToken
131
+ } : void 0,
132
+ cache: {
133
+ getCacheAPIContext: () => null,
134
+ purgeToken: ""
135
+ },
136
+ deployID,
137
+ env,
138
+ getRequestContext: () => null,
139
+ siteID
140
+ });
141
+ return {
142
+ stop: async () => {
143
+ restoreEnvironment(envSnapshot);
144
+ await blobsServer?.stop();
145
+ }
146
+ };
147
+ };
148
+
89
149
  // src/main.ts
150
+ var defaultFeatures = {
151
+ blobs: true,
152
+ functions: true,
153
+ redirects: true,
154
+ static: true
155
+ };
90
156
  var notFoundHandler = async () => new Response("Not found", { status: 404 });
91
157
  var handle = async (request, options) => {
92
- const { projectRoot = import_node_process2.default.cwd() } = options ?? {};
158
+ const { features = defaultFeatures, projectRoot = import_node_process3.default.cwd() } = options ?? {};
93
159
  const { config, siteID } = await getConfig({ projectRoot }) ?? {};
94
- const userFunctionsPath = config?.config.functionsDirectory ?? import_node_path2.default.join(projectRoot, "netlify/functions");
160
+ const userFunctionsPath = config?.config.functionsDirectory ?? import_node_path3.default.join(projectRoot, "netlify/functions");
95
161
  const userFunctionsPathExists = await isDirectory(userFunctionsPath);
96
- const functions = new import_dev.FunctionsHandler({
162
+ const functions = features.functions ? new import_dev.FunctionsHandler({
97
163
  config,
98
- destPath: import_node_path2.default.join(projectRoot, ".netlify", "functions-serve"),
164
+ destPath: import_node_path3.default.join(projectRoot, ".netlify", "functions-serve"),
99
165
  projectRoot,
100
166
  settings: {},
101
167
  siteId: siteID,
102
168
  timeouts: {},
103
169
  userFunctionsPath: userFunctionsPathExists ? userFunctionsPath : void 0
104
- });
105
- const redirects = new import_redirects.RedirectsHandler({
170
+ }) : null;
171
+ const redirects = features.redirects ? new import_redirects.RedirectsHandler({
106
172
  configPath: config?.configPath,
107
173
  configRedirects: config?.config.redirects,
108
174
  jwtRoleClaim: "",
109
175
  jwtSecret: "",
110
176
  notFoundHandler,
111
177
  projectDir: projectRoot
112
- });
113
- const staticFiles = new import_static.StaticHandler({
178
+ }) : null;
179
+ const staticFiles = features.static ? new import_static.StaticHandler({
114
180
  directory: config?.config.build.publish ?? projectRoot
181
+ }) : null;
182
+ const runtime = await getRuntime({
183
+ blobs: Boolean(features.blobs),
184
+ deployID: "0",
185
+ projectRoot,
186
+ siteID: siteID ?? "0"
115
187
  });
116
- const functionMatch = await functions.match(request);
188
+ const functionMatch = await functions?.match(request);
117
189
  if (functionMatch) {
118
190
  if (functionMatch.preferStatic) {
119
- const staticMatch2 = await staticFiles.match(request);
191
+ const staticMatch2 = await staticFiles?.match(request);
120
192
  if (staticMatch2) {
121
193
  return staticMatch2.handle();
122
194
  }
123
195
  }
124
196
  return functionMatch.handle(request);
125
197
  }
126
- const redirectMatch = await redirects.match(request);
198
+ const redirectMatch = await redirects?.match(request);
127
199
  if (redirectMatch) {
128
- const functionMatch2 = await functions.match(new Request(redirectMatch.target));
200
+ const functionMatch2 = await functions?.match(new Request(redirectMatch.target));
129
201
  if (functionMatch2 && !functionMatch2.preferStatic) {
130
202
  return functionMatch2.handle(request);
131
203
  }
132
- const response = await redirects.handle(request, redirectMatch, async (maybeStaticFile) => {
133
- const staticMatch2 = await staticFiles.match(maybeStaticFile);
204
+ const response = await redirects?.handle(request, redirectMatch, async (maybeStaticFile) => {
205
+ const staticMatch2 = await staticFiles?.match(maybeStaticFile);
134
206
  return staticMatch2?.handle;
135
207
  });
136
208
  if (response) {
137
209
  return response;
138
210
  }
139
211
  }
140
- const staticMatch = await staticFiles.match(request);
212
+ const staticMatch = await staticFiles?.match(request);
141
213
  if (staticMatch) {
142
214
  return staticMatch.handle();
143
215
  }
216
+ await runtime.stop();
217
+ };
218
+ var start = async (options) => {
219
+ const { projectRoot = import_node_process3.default.cwd() } = options ?? {};
220
+ const { siteID } = await getConfig({ projectRoot }) ?? {};
221
+ const runtime = await getRuntime({
222
+ blobs: true,
223
+ deployID: "0",
224
+ projectRoot,
225
+ siteID: siteID ?? "0"
226
+ });
227
+ return {
228
+ stop: async () => {
229
+ await runtime.stop();
230
+ }
231
+ };
144
232
  };
145
233
  // Annotate the CommonJS export names for ESM import in node:
146
234
  0 && (module.exports = {
147
- handle
235
+ handle,
236
+ start
148
237
  });
package/dist/main.d.cts CHANGED
@@ -1,6 +1,19 @@
1
+ interface Features {
2
+ blobs?: boolean;
3
+ functions?: boolean;
4
+ redirects?: boolean;
5
+ static?: boolean;
6
+ }
1
7
  interface HandleOptions {
8
+ features?: Features;
2
9
  projectRoot?: string;
3
10
  }
4
11
  declare const handle: (request: Request, options?: HandleOptions) => Promise<Response | undefined>;
12
+ interface StartOptions {
13
+ projectRoot?: string;
14
+ }
15
+ declare const start: (options?: StartOptions) => Promise<{
16
+ stop: () => Promise<void>;
17
+ }>;
5
18
 
6
- export { handle };
19
+ export { handle, start };
package/dist/main.d.ts CHANGED
@@ -1,6 +1,19 @@
1
+ interface Features {
2
+ blobs?: boolean;
3
+ functions?: boolean;
4
+ redirects?: boolean;
5
+ static?: boolean;
6
+ }
1
7
  interface HandleOptions {
8
+ features?: Features;
2
9
  projectRoot?: string;
3
10
  }
4
11
  declare const handle: (request: Request, options?: HandleOptions) => Promise<Response | undefined>;
12
+ interface StartOptions {
13
+ projectRoot?: string;
14
+ }
15
+ declare const start: (options?: StartOptions) => Promise<{
16
+ stop: () => Promise<void>;
17
+ }>;
5
18
 
6
- export { handle };
19
+ export { handle, start };
package/dist/main.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/main.ts
2
- import path2 from "node:path";
3
- import process2 from "node:process";
2
+ import path3 from "node:path";
3
+ import process3 from "node:process";
4
4
  import { FunctionsHandler } from "@netlify/functions/dev";
5
5
  import { RedirectsHandler } from "@netlify/redirects";
6
6
  import { StaticHandler } from "@netlify/static";
@@ -13,17 +13,17 @@ import { getAPIToken, LocalState } from "@netlify/dev-utils";
13
13
 
14
14
  // src/lib/fs.ts
15
15
  import { promises as fs } from "node:fs";
16
- var isDirectory = async (path3) => {
16
+ var isDirectory = async (path4) => {
17
17
  try {
18
- const stat = await fs.stat(path3);
18
+ const stat = await fs.stat(path4);
19
19
  return stat.isDirectory();
20
20
  } catch {
21
21
  }
22
22
  return false;
23
23
  };
24
- var isFile = async (path3) => {
24
+ var isFile = async (path4) => {
25
25
  try {
26
- const stat = await fs.stat(path3);
26
+ const stat = await fs.stat(path4);
27
27
  return stat.isFile();
28
28
  } catch {
29
29
  }
@@ -52,62 +52,150 @@ var getConfig = async ({
52
52
  return { config, siteID };
53
53
  };
54
54
 
55
+ // src/lib/runtime.ts
56
+ import path2 from "node:path";
57
+ import process2 from "node:process";
58
+ import { BlobsServer } from "@netlify/blobs/server";
59
+ import { startRuntime } from "@netlify/runtime";
60
+ var restoreEnvironment = (snapshot) => {
61
+ for (const key in snapshot) {
62
+ if (snapshot[key] === void 0) {
63
+ delete process2.env[key];
64
+ } else {
65
+ process2.env[key] = snapshot[key];
66
+ }
67
+ }
68
+ };
69
+ var getRuntime = async ({ blobs, deployID, projectRoot, siteID }) => {
70
+ const blobsToken = Math.random().toString().slice(2);
71
+ const blobsServer = blobs ? new BlobsServer({
72
+ directory: path2.join(projectRoot, ".netlify", "blobs-serve"),
73
+ token: blobsToken
74
+ }) : null;
75
+ const blobsServerDetails = await blobsServer?.start();
76
+ const envSnapshot = {};
77
+ const env = {
78
+ delete: (key) => {
79
+ envSnapshot[key] = envSnapshot[key] || process2.env[key];
80
+ delete process2.env[key];
81
+ },
82
+ get: (key) => process2.env[key],
83
+ has: (key) => Boolean(process2.env[key]),
84
+ set: (key, value) => {
85
+ envSnapshot[key] = envSnapshot[key] || process2.env[key];
86
+ process2.env[key] = value;
87
+ },
88
+ toObject: () => process2.env
89
+ };
90
+ startRuntime({
91
+ blobs: blobsServerDetails ? {
92
+ edgeURL: `http://localhost:${blobsServerDetails.port}`,
93
+ uncachedEdgeURL: `http://localhost:${blobsServerDetails.port}`,
94
+ primaryRegion: "us-east-2",
95
+ token: blobsToken
96
+ } : void 0,
97
+ cache: {
98
+ getCacheAPIContext: () => null,
99
+ purgeToken: ""
100
+ },
101
+ deployID,
102
+ env,
103
+ getRequestContext: () => null,
104
+ siteID
105
+ });
106
+ return {
107
+ stop: async () => {
108
+ restoreEnvironment(envSnapshot);
109
+ await blobsServer?.stop();
110
+ }
111
+ };
112
+ };
113
+
55
114
  // src/main.ts
115
+ var defaultFeatures = {
116
+ blobs: true,
117
+ functions: true,
118
+ redirects: true,
119
+ static: true
120
+ };
56
121
  var notFoundHandler = async () => new Response("Not found", { status: 404 });
57
122
  var handle = async (request, options) => {
58
- const { projectRoot = process2.cwd() } = options ?? {};
123
+ const { features = defaultFeatures, projectRoot = process3.cwd() } = options ?? {};
59
124
  const { config, siteID } = await getConfig({ projectRoot }) ?? {};
60
- const userFunctionsPath = config?.config.functionsDirectory ?? path2.join(projectRoot, "netlify/functions");
125
+ const userFunctionsPath = config?.config.functionsDirectory ?? path3.join(projectRoot, "netlify/functions");
61
126
  const userFunctionsPathExists = await isDirectory(userFunctionsPath);
62
- const functions = new FunctionsHandler({
127
+ const functions = features.functions ? new FunctionsHandler({
63
128
  config,
64
- destPath: path2.join(projectRoot, ".netlify", "functions-serve"),
129
+ destPath: path3.join(projectRoot, ".netlify", "functions-serve"),
65
130
  projectRoot,
66
131
  settings: {},
67
132
  siteId: siteID,
68
133
  timeouts: {},
69
134
  userFunctionsPath: userFunctionsPathExists ? userFunctionsPath : void 0
70
- });
71
- const redirects = new RedirectsHandler({
135
+ }) : null;
136
+ const redirects = features.redirects ? new RedirectsHandler({
72
137
  configPath: config?.configPath,
73
138
  configRedirects: config?.config.redirects,
74
139
  jwtRoleClaim: "",
75
140
  jwtSecret: "",
76
141
  notFoundHandler,
77
142
  projectDir: projectRoot
78
- });
79
- const staticFiles = new StaticHandler({
143
+ }) : null;
144
+ const staticFiles = features.static ? new StaticHandler({
80
145
  directory: config?.config.build.publish ?? projectRoot
146
+ }) : null;
147
+ const runtime = await getRuntime({
148
+ blobs: Boolean(features.blobs),
149
+ deployID: "0",
150
+ projectRoot,
151
+ siteID: siteID ?? "0"
81
152
  });
82
- const functionMatch = await functions.match(request);
153
+ const functionMatch = await functions?.match(request);
83
154
  if (functionMatch) {
84
155
  if (functionMatch.preferStatic) {
85
- const staticMatch2 = await staticFiles.match(request);
156
+ const staticMatch2 = await staticFiles?.match(request);
86
157
  if (staticMatch2) {
87
158
  return staticMatch2.handle();
88
159
  }
89
160
  }
90
161
  return functionMatch.handle(request);
91
162
  }
92
- const redirectMatch = await redirects.match(request);
163
+ const redirectMatch = await redirects?.match(request);
93
164
  if (redirectMatch) {
94
- const functionMatch2 = await functions.match(new Request(redirectMatch.target));
165
+ const functionMatch2 = await functions?.match(new Request(redirectMatch.target));
95
166
  if (functionMatch2 && !functionMatch2.preferStatic) {
96
167
  return functionMatch2.handle(request);
97
168
  }
98
- const response = await redirects.handle(request, redirectMatch, async (maybeStaticFile) => {
99
- const staticMatch2 = await staticFiles.match(maybeStaticFile);
169
+ const response = await redirects?.handle(request, redirectMatch, async (maybeStaticFile) => {
170
+ const staticMatch2 = await staticFiles?.match(maybeStaticFile);
100
171
  return staticMatch2?.handle;
101
172
  });
102
173
  if (response) {
103
174
  return response;
104
175
  }
105
176
  }
106
- const staticMatch = await staticFiles.match(request);
177
+ const staticMatch = await staticFiles?.match(request);
107
178
  if (staticMatch) {
108
179
  return staticMatch.handle();
109
180
  }
181
+ await runtime.stop();
182
+ };
183
+ var start = async (options) => {
184
+ const { projectRoot = process3.cwd() } = options ?? {};
185
+ const { siteID } = await getConfig({ projectRoot }) ?? {};
186
+ const runtime = await getRuntime({
187
+ blobs: true,
188
+ deployID: "0",
189
+ projectRoot,
190
+ siteID: siteID ?? "0"
191
+ });
192
+ return {
193
+ stop: async () => {
194
+ await runtime.stop();
195
+ }
196
+ };
110
197
  };
111
198
  export {
112
- handle
199
+ handle,
200
+ start
113
201
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/dev",
3
- "version": "1.1.2",
3
+ "version": "2.0.0",
4
4
  "description": "Local development emulation for Netlify",
5
5
  "type": "module",
6
6
  "engines": {
@@ -46,14 +46,16 @@
46
46
  "author": "Netlify Inc.",
47
47
  "devDependencies": {
48
48
  "tmp-promise": "^3.0.3",
49
- "tsup": "^7.2.0",
50
- "vitest": "^0.34.0"
49
+ "tsup": "^8.0.0",
50
+ "vitest": "^3.0.0"
51
51
  },
52
52
  "dependencies": {
53
+ "@netlify/blobs": "9.0.0",
53
54
  "@netlify/config": "^22.0.0",
54
- "@netlify/dev-utils": "1.1.0",
55
- "@netlify/functions": "3.1.2",
56
- "@netlify/redirects": "1.1.0",
57
- "@netlify/static": "1.1.0"
55
+ "@netlify/dev-utils": "2.0.0",
56
+ "@netlify/functions": "3.1.3",
57
+ "@netlify/redirects": "1.1.1",
58
+ "@netlify/runtime": "2.0.0",
59
+ "@netlify/static": "1.1.1"
58
60
  }
59
61
  }