@blinkk/root 3.0.5 → 3.1.1

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.
Files changed (44) hide show
  1. package/dist/build-worker.js +108 -0
  2. package/dist/build-worker.js.map +7 -0
  3. package/dist/chunk-3PWR4F2R.js +77 -0
  4. package/dist/chunk-3PWR4F2R.js.map +7 -0
  5. package/dist/{chunk-VQPDCDKL.js → chunk-E4F6CMO3.js} +469 -536
  6. package/dist/chunk-E4F6CMO3.js.map +7 -0
  7. package/dist/{chunk-6P3B7ZXL.js → chunk-I3RCAIW7.js} +1 -62
  8. package/dist/chunk-I3RCAIW7.js.map +7 -0
  9. package/dist/chunk-KHO3HMX6.js +291 -0
  10. package/dist/chunk-KHO3HMX6.js.map +7 -0
  11. package/dist/chunk-M3E4RKS7.js +374 -0
  12. package/dist/chunk-M3E4RKS7.js.map +7 -0
  13. package/dist/{chunk-6NBKAR5Y.js → chunk-TM6QRBGS.js} +31 -1
  14. package/dist/chunk-TM6QRBGS.js.map +7 -0
  15. package/dist/chunk-WX62JK5E.js +81 -0
  16. package/dist/chunk-WX62JK5E.js.map +7 -0
  17. package/dist/{chunk-7PSEEE6C.js → chunk-YU22SAIG.js} +31 -317
  18. package/dist/chunk-YU22SAIG.js.map +7 -0
  19. package/dist/cli/build-page.d.ts +57 -0
  20. package/dist/cli/build-worker-pool.d.ts +46 -0
  21. package/dist/cli/build-worker.d.ts +4 -0
  22. package/dist/cli/build.d.ts +6 -0
  23. package/dist/cli.js +8 -4
  24. package/dist/core/config.d.ts +11 -3
  25. package/dist/core/security.d.ts +14 -0
  26. package/dist/core.js.map +2 -2
  27. package/dist/functions.js +8 -4
  28. package/dist/functions.js.map +1 -1
  29. package/dist/jsx/types.d.ts +1 -0
  30. package/dist/middleware/common.d.ts +18 -0
  31. package/dist/middleware/compression.d.ts +12 -0
  32. package/dist/middleware/middleware.d.ts +1 -0
  33. package/dist/middleware.js +6 -1
  34. package/dist/node.js +7 -5
  35. package/dist/render/asset-map/build-asset-map.d.ts +11 -1
  36. package/dist/render/html-transform.d.ts +15 -0
  37. package/dist/render/render.d.ts +15 -9
  38. package/dist/render.js +45 -104
  39. package/dist/render.js.map +2 -2
  40. package/package.json +2 -2
  41. package/dist/chunk-6NBKAR5Y.js.map +0 -7
  42. package/dist/chunk-6P3B7ZXL.js.map +0 -7
  43. package/dist/chunk-7PSEEE6C.js.map +0 -7
  44. package/dist/chunk-VQPDCDKL.js.map +0 -7
@@ -1,22 +1,23 @@
1
1
  import {
2
- RouteTrie,
3
- htmlMinify,
4
- htmlPretty,
5
- isValidTagName,
6
- parseTagNames
7
- } from "./chunk-6P3B7ZXL.js";
2
+ collectPods,
3
+ createViteServer,
4
+ preactToRootJsxPlugin,
5
+ rootPodsVitePlugin
6
+ } from "./chunk-YU22SAIG.js";
8
7
  import {
9
- headersMiddleware,
10
- rootProjectMiddleware,
11
- sessionMiddleware,
12
- trailingSlashMiddleware
13
- } from "./chunk-6NBKAR5Y.js";
8
+ RouteTrie
9
+ } from "./chunk-I3RCAIW7.js";
10
+ import {
11
+ BuildAssetMap,
12
+ ElementGraph,
13
+ buildPage,
14
+ getElements,
15
+ getElementsDirs
16
+ } from "./chunk-M3E4RKS7.js";
14
17
  import {
15
18
  bundleRootConfig,
16
- collectPods,
17
19
  copyDir,
18
20
  copyGlob,
19
- createViteServer,
20
21
  dirExists,
21
22
  directoryContains,
22
23
  fileExists,
@@ -28,144 +29,35 @@ import {
28
29
  loadRootConfig,
29
30
  loadRootConfigWithDeps,
30
31
  makeDir,
31
- preactToRootJsxPlugin,
32
32
  rmDir,
33
- rootPodsVitePlugin,
34
33
  writeFile,
35
34
  writeJson
36
- } from "./chunk-7PSEEE6C.js";
35
+ } from "./chunk-KHO3HMX6.js";
37
36
  import {
38
37
  configureServerPlugins,
39
38
  getVitePlugins
40
39
  } from "./chunk-XSNCF7WU.js";
40
+ import {
41
+ compressionMiddleware,
42
+ headersMiddleware,
43
+ rootProjectMiddleware,
44
+ securityHeadersMiddleware,
45
+ sessionMiddleware,
46
+ trailingSlashMiddleware
47
+ } from "./chunk-TM6QRBGS.js";
41
48
 
42
49
  // src/cli/cli.ts
43
50
  import { Command, InvalidArgumentError } from "commander";
44
51
  import { bgGreen, black } from "kleur/colors";
45
52
 
46
53
  // src/cli/build.ts
47
- import path3 from "node:path";
48
- import { fileURLToPath } from "node:url";
54
+ import os from "node:os";
55
+ import path2 from "node:path";
56
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
49
57
  import fsExtra from "fs-extra";
50
58
  import { dim as dim2, cyan } from "kleur/colors";
51
- import glob2 from "tiny-glob";
52
- import { build as viteBuild } from "vite";
53
-
54
- // src/node/element-graph.ts
55
- import fs from "node:fs";
56
- import path from "node:path";
57
59
  import glob from "tiny-glob";
58
- import { searchForWorkspaceRoot } from "vite";
59
- var ElementGraph = class _ElementGraph {
60
- /**
61
- * Element tagName => sourceFile.
62
- */
63
- sourceFiles = {};
64
- /**
65
- * Element tagName => set of element tagName dependencies.
66
- */
67
- deps = {};
68
- constructor(sourceFiles) {
69
- this.sourceFiles = sourceFiles;
70
- }
71
- toJson() {
72
- for (const tagName in this.sourceFiles) {
73
- this.deps[tagName] ??= this.parseDepsFromSource(tagName);
74
- }
75
- return {
76
- sourceFiles: this.sourceFiles,
77
- deps: this.deps
78
- };
79
- }
80
- static fromJson(data) {
81
- const graph = new _ElementGraph(data.sourceFiles);
82
- graph.deps = data.deps;
83
- return graph;
84
- }
85
- getDeps(tagName, visited) {
86
- visited ??= /* @__PURE__ */ new Set();
87
- if (visited.has(tagName)) {
88
- return [];
89
- }
90
- visited.add(tagName);
91
- this.deps[tagName] ??= this.parseDepsFromSource(tagName);
92
- const deps = new Set(this.deps[tagName]);
93
- for (const depTagName of this.deps[tagName]) {
94
- for (const childDep of this.getDeps(depTagName, visited)) {
95
- deps.add(childDep);
96
- }
97
- }
98
- return Array.from(deps);
99
- }
100
- /**
101
- * Parses an element's source file for usage of other custom elements.
102
- */
103
- parseDepsFromSource(tagName) {
104
- const srcFile = this.sourceFiles[tagName];
105
- if (!srcFile) {
106
- throw new Error(`could not find file path for tagName <${tagName}>`);
107
- }
108
- const src = fs.readFileSync(srcFile.filePath, "utf-8");
109
- const tagNames = parseTagNames(src);
110
- const deps = /* @__PURE__ */ new Set();
111
- for (const depTagName of tagNames) {
112
- if (depTagName !== tagName && depTagName in this.sourceFiles) {
113
- deps.add(depTagName);
114
- }
115
- }
116
- return Array.from(deps);
117
- }
118
- };
119
- async function getElements(rootConfig, pods) {
120
- const rootDir = rootConfig.rootDir;
121
- const elementsDirs = getElementsDirs(rootConfig, pods);
122
- const excludePatterns = rootConfig.elements?.exclude || [];
123
- const excludeElement = (moduleId) => {
124
- return excludePatterns.some((pattern) => Boolean(moduleId.match(pattern)));
125
- };
126
- const elementFilePaths = {};
127
- for (const dirPath of elementsDirs) {
128
- if (await isDirectory(dirPath)) {
129
- const files = await glob("**/*", { cwd: dirPath });
130
- files.forEach((file) => {
131
- const parts = path.parse(file);
132
- if (isJsFile(parts.base) && isValidTagName(parts.name)) {
133
- const tagName = parts.name;
134
- const filePath = path.join(dirPath, file);
135
- const relPath = path.relative(rootDir, filePath);
136
- if (!excludeElement(relPath)) {
137
- elementFilePaths[tagName] = { filePath, relPath };
138
- }
139
- }
140
- });
141
- }
142
- }
143
- const graph = new ElementGraph(elementFilePaths);
144
- return graph;
145
- }
146
- function getElementsDirs(rootConfig, pods) {
147
- const rootDir = rootConfig.rootDir;
148
- const workspaceRoot = searchForWorkspaceRoot(rootDir);
149
- const elementsDirs = [path.join(rootDir, "elements")];
150
- const elementsInclude = rootConfig.elements?.include || [];
151
- for (const dirPath of elementsInclude) {
152
- const elementsDir = path.resolve(rootDir, dirPath);
153
- if (!directoryContains(rootDir, elementsDir)) {
154
- throw new Error(
155
- `the elements dir (${dirPath}) should be within the project's workspace (${workspaceRoot})`
156
- );
157
- }
158
- elementsDirs.push(elementsDir);
159
- }
160
- if (pods) {
161
- for (const pod of pods) {
162
- for (const dir of pod.elementsDirs) {
163
- elementsDirs.push(dir);
164
- }
165
- }
166
- }
167
- return elementsDirs;
168
- }
60
+ import { build as viteBuild } from "vite";
169
61
 
170
62
  // src/node/vite-plugin-prune-empty-chunks.ts
171
63
  import { dim } from "kleur/colors";
@@ -232,167 +124,6 @@ function removeSideEffectImport(code, fileName) {
232
124
  return code.replace(re, "");
233
125
  }
234
126
 
235
- // src/render/asset-map/build-asset-map.ts
236
- import fs2 from "node:fs";
237
- import path2 from "node:path";
238
- var BuildAssetMap = class _BuildAssetMap {
239
- rootConfig;
240
- srcToAsset;
241
- constructor(rootConfig) {
242
- this.rootConfig = rootConfig;
243
- this.srcToAsset = /* @__PURE__ */ new Map();
244
- }
245
- async get(src) {
246
- const asset = this.srcToAsset.get(src);
247
- if (asset) {
248
- return asset;
249
- }
250
- const realSrc = realPathRelativeTo(this.rootConfig.rootDir, src);
251
- if (realSrc !== src) {
252
- const asset2 = this.srcToAsset.get(realSrc);
253
- if (asset2) {
254
- return asset2;
255
- }
256
- }
257
- console.log(`could not find build asset: ${src}`);
258
- return null;
259
- }
260
- add(asset) {
261
- this.srcToAsset.set(asset.src, asset);
262
- }
263
- toJson() {
264
- const result = {};
265
- for (const src of this.srcToAsset.keys()) {
266
- result[src] = this.srcToAsset.get(src).toJson();
267
- }
268
- return result;
269
- }
270
- static fromViteManifest(rootConfig, clientManifest, elementsGraph) {
271
- const assetMap = new _BuildAssetMap(rootConfig);
272
- const elementFiles = /* @__PURE__ */ new Set();
273
- Object.values(elementsGraph.sourceFiles).forEach((elementSource) => {
274
- elementFiles.add(elementSource.relPath);
275
- const realSrc = realPathRelativeTo(
276
- rootConfig.rootDir,
277
- elementSource.relPath
278
- );
279
- if (realSrc !== elementSource.filePath) {
280
- elementFiles.add(realSrc);
281
- }
282
- });
283
- Object.keys(clientManifest).forEach((manifestKey) => {
284
- const src = manifestKey;
285
- const manifestChunk = clientManifest[manifestKey];
286
- const isElement = elementFiles.has(src);
287
- const assetUrl = src.startsWith("routes/") && isJsFile(src) ? "" : `/${manifestChunk.file}`;
288
- const assetData = {
289
- src,
290
- assetUrl,
291
- importedModules: manifestChunk.imports || [],
292
- importedCss: (manifestChunk.css || []).map((relPath) => `/${relPath}`),
293
- isElement
294
- };
295
- assetMap.add(new BuildAsset(assetMap, assetData));
296
- });
297
- return assetMap;
298
- }
299
- static fromRootManifest(rootConfig, rootManifest) {
300
- const assetMap = new _BuildAssetMap(rootConfig);
301
- Object.keys(rootManifest).forEach((moduleId) => {
302
- const assetData = rootManifest[moduleId];
303
- assetMap.add(new BuildAsset(assetMap, assetData));
304
- });
305
- return assetMap;
306
- }
307
- };
308
- function realPathRelativeTo(rootDir, src) {
309
- const fullPath = path2.resolve(rootDir, src);
310
- if (!fs2.existsSync(fullPath)) {
311
- return src;
312
- }
313
- const realpath = fs2.realpathSync(path2.resolve(rootDir, src));
314
- return path2.relative(rootDir, realpath);
315
- }
316
- var BuildAsset = class {
317
- src;
318
- assetUrl;
319
- assetMap;
320
- importedModules;
321
- importedCss;
322
- isElement;
323
- constructor(assetMap, assetData) {
324
- this.assetMap = assetMap;
325
- this.src = assetData.src;
326
- this.assetUrl = assetData.assetUrl;
327
- this.importedModules = assetData.importedModules;
328
- this.importedCss = assetData.importedCss;
329
- this.isElement = assetData.isElement;
330
- }
331
- async getCssDeps() {
332
- const visited = /* @__PURE__ */ new Set();
333
- const deps = /* @__PURE__ */ new Set();
334
- await this.collectCss(this, deps, visited);
335
- return Array.from(deps);
336
- }
337
- async getJsDeps() {
338
- const visited = /* @__PURE__ */ new Set();
339
- const deps = /* @__PURE__ */ new Set();
340
- await this.collectJs(this, deps, visited);
341
- return Array.from(deps);
342
- }
343
- async collectJs(asset, urls, visited) {
344
- if (!asset) {
345
- return;
346
- }
347
- if (!asset.src) {
348
- return;
349
- }
350
- if (visited.has(asset.src)) {
351
- return;
352
- }
353
- visited.add(asset.src);
354
- if (asset.isElement) {
355
- urls.add(asset.assetUrl);
356
- }
357
- await Promise.all(
358
- asset.importedModules.map(async (src) => {
359
- const importedAsset = await this.assetMap.get(src);
360
- this.collectJs(importedAsset, urls, visited);
361
- })
362
- );
363
- }
364
- async collectCss(asset, urls, visited) {
365
- if (!asset) {
366
- return;
367
- }
368
- if (!asset.src) {
369
- return;
370
- }
371
- if (visited.has(asset.src)) {
372
- return;
373
- }
374
- visited.add(asset.src);
375
- if (asset.importedCss) {
376
- asset.importedCss.forEach((cssUrl) => urls.add(cssUrl));
377
- }
378
- await Promise.all(
379
- asset.importedModules.map(async (moduleId) => {
380
- const importedAsset = await this.assetMap.get(moduleId);
381
- this.collectCss(importedAsset, urls, visited);
382
- })
383
- );
384
- }
385
- toJson() {
386
- return {
387
- src: this.src,
388
- assetUrl: this.assetUrl,
389
- importedModules: this.importedModules,
390
- importedCss: this.importedCss,
391
- isElement: this.isElement
392
- };
393
- }
394
- };
395
-
396
127
  // src/utils/batch.ts
397
128
  async function batchAsyncCalls(data, concurrency, asyncFunction) {
398
129
  const result = new Array(data.length);
@@ -411,14 +142,144 @@ async function batchAsyncCalls(data, concurrency, asyncFunction) {
411
142
  return result;
412
143
  }
413
144
 
145
+ // src/cli/build-worker-pool.ts
146
+ import path from "node:path";
147
+ import { fileURLToPath } from "node:url";
148
+ import { Worker } from "node:worker_threads";
149
+ var __dirname = path.dirname(fileURLToPath(import.meta.url));
150
+ var BuildPageError = class extends Error {
151
+ urlPath;
152
+ params;
153
+ routeSrc;
154
+ workerError;
155
+ constructor(urlPath, params, routeSrc, workerError) {
156
+ super(
157
+ `BuildError: ${urlPath} (${routeSrc || "unknown route"}) failed to build.`
158
+ );
159
+ this.urlPath = urlPath;
160
+ this.params = params;
161
+ this.routeSrc = routeSrc;
162
+ this.workerError = workerError;
163
+ }
164
+ };
165
+ var BuildWorker = class {
166
+ worker;
167
+ pool;
168
+ concurrency;
169
+ inFlight = /* @__PURE__ */ new Map();
170
+ isReady = false;
171
+ ready;
172
+ constructor(pool, options) {
173
+ this.pool = pool;
174
+ this.concurrency = options.workerConcurrency;
175
+ this.worker = new Worker(path.resolve(__dirname, "./build-worker.js"), {
176
+ workerData: { rootDir: options.rootDir, mode: options.mode }
177
+ });
178
+ let onReady;
179
+ let onFailed;
180
+ this.ready = new Promise((resolve, reject) => {
181
+ onReady = resolve;
182
+ onFailed = reject;
183
+ });
184
+ this.worker.on("message", (msg) => {
185
+ if (msg.type === "ready") {
186
+ this.isReady = true;
187
+ onReady();
188
+ this.next();
189
+ } else if (msg.type === "result") {
190
+ const pending = this.inFlight.get(msg.id);
191
+ this.inFlight.delete(msg.id);
192
+ pending?.resolve(msg.result);
193
+ this.next();
194
+ } else if (msg.type === "error") {
195
+ const pending = this.inFlight.get(msg.id);
196
+ this.inFlight.delete(msg.id);
197
+ pending?.reject(
198
+ new BuildPageError(msg.urlPath, msg.params, msg.routeSrc, msg.error)
199
+ );
200
+ this.next();
201
+ } else if (msg.type === "fatal") {
202
+ const err = new Error(`build worker failed: ${msg.error}`);
203
+ onFailed(err);
204
+ this.failAll(err);
205
+ }
206
+ });
207
+ this.worker.on("error", (err) => {
208
+ onFailed(err);
209
+ this.failAll(err);
210
+ });
211
+ this.worker.on("exit", (code) => {
212
+ if (code !== 0) {
213
+ const err = new Error(`build worker exited with code ${code}`);
214
+ onFailed(err);
215
+ this.failAll(err);
216
+ }
217
+ });
218
+ }
219
+ failAll(err) {
220
+ const pendingTasks = Array.from(this.inFlight.values());
221
+ this.inFlight.clear();
222
+ pendingTasks.forEach((pending) => pending.reject(err));
223
+ }
224
+ /** Pulls tasks off the pool's queue until at max concurrency. */
225
+ next() {
226
+ if (!this.isReady) {
227
+ return;
228
+ }
229
+ while (this.inFlight.size < this.concurrency) {
230
+ const pending = this.pool.dequeue();
231
+ if (!pending) {
232
+ return;
233
+ }
234
+ this.inFlight.set(pending.id, pending);
235
+ const req = {
236
+ type: "render",
237
+ id: pending.id,
238
+ task: pending.task
239
+ };
240
+ this.worker.postMessage(req);
241
+ }
242
+ }
243
+ async terminate() {
244
+ await this.worker.terminate();
245
+ }
246
+ };
247
+ var BuildWorkerPool = class {
248
+ workers = [];
249
+ queue = [];
250
+ nextTaskId = 0;
251
+ constructor(options) {
252
+ for (let i = 0; i < options.numWorkers; i++) {
253
+ this.workers.push(new BuildWorker(this, options));
254
+ }
255
+ }
256
+ /** Waits for all workers to finish initializing. */
257
+ async ready() {
258
+ await Promise.all(this.workers.map((worker) => worker.ready));
259
+ }
260
+ /** Schedules a page build and resolves when the page finishes. */
261
+ run(task) {
262
+ return new Promise((resolve, reject) => {
263
+ this.queue.push({ id: this.nextTaskId++, task, resolve, reject });
264
+ this.workers.forEach((worker) => worker.next());
265
+ });
266
+ }
267
+ dequeue() {
268
+ return this.queue.shift();
269
+ }
270
+ async terminate() {
271
+ await Promise.all(this.workers.map((worker) => worker.terminate()));
272
+ }
273
+ };
274
+
414
275
  // src/cli/build.ts
415
- var __dirname = path3.dirname(fileURLToPath(import.meta.url));
276
+ var __dirname2 = path2.dirname(fileURLToPath2(import.meta.url));
416
277
  async function build(rootProjectDir, options) {
417
278
  const mode = options?.mode || "production";
418
279
  process.env.NODE_ENV = mode;
419
- const rootDir = path3.resolve(rootProjectDir || process.cwd());
280
+ const rootDir = path2.resolve(rootProjectDir || process.cwd());
420
281
  const rootConfig = await loadRootConfig(rootDir, { command: "build" });
421
- const distDir = path3.join(rootDir, "dist");
282
+ const distDir = path2.join(rootDir, "dist");
422
283
  const ssrOnly = options?.ssrOnly || false;
423
284
  console.log();
424
285
  console.log(`${dim2("\u2503")} project: ${rootDir}`);
@@ -429,12 +290,12 @@ async function build(rootProjectDir, options) {
429
290
  await makeDir(distDir);
430
291
  const pods = await collectPods(rootConfig);
431
292
  const routeFiles = [];
432
- if (await isDirectory(path3.join(rootDir, "routes"))) {
433
- const pageFiles = await glob2("routes/**/*", { cwd: rootDir });
293
+ if (await isDirectory(path2.join(rootDir, "routes"))) {
294
+ const pageFiles = await glob("routes/**/*", { cwd: rootDir });
434
295
  pageFiles.forEach((file) => {
435
- const parts = path3.parse(file);
296
+ const parts = path2.parse(file);
436
297
  if (!parts.name.startsWith("_") && isJsFile(parts.base)) {
437
- routeFiles.push(path3.resolve(rootDir, file));
298
+ routeFiles.push(path2.resolve(rootDir, file));
438
299
  }
439
300
  });
440
301
  }
@@ -448,12 +309,12 @@ async function build(rootProjectDir, options) {
448
309
  return sourceFile.filePath;
449
310
  });
450
311
  const bundleScripts = [];
451
- if (await isDirectory(path3.join(rootDir, "bundles"))) {
452
- const bundleFiles = await glob2("bundles/*", { cwd: rootDir });
312
+ if (await isDirectory(path2.join(rootDir, "bundles"))) {
313
+ const bundleFiles = await glob("bundles/*", { cwd: rootDir });
453
314
  bundleFiles.forEach((file) => {
454
- const parts = path3.parse(file);
315
+ const parts = path2.parse(file);
455
316
  if (isJsFile(parts.base)) {
456
- bundleScripts.push(path3.resolve(rootDir, file));
317
+ bundleScripts.push(path2.resolve(rootDir, file));
457
318
  }
458
319
  });
459
320
  }
@@ -483,7 +344,7 @@ async function build(rootProjectDir, options) {
483
344
  plugins: vitePlugins
484
345
  };
485
346
  const ssrInput = {
486
- render: path3.resolve(__dirname, "./render.js")
347
+ render: path2.resolve(__dirname2, "./render.js")
487
348
  };
488
349
  rootPlugins.forEach((plugin) => {
489
350
  if (plugin.ssrInput) {
@@ -514,7 +375,7 @@ async function build(rootProjectDir, options) {
514
375
  sanitizeFileName
515
376
  }
516
377
  },
517
- outDir: path3.join(distDir, "server"),
378
+ outDir: path2.join(distDir, "server"),
518
379
  ssr: true,
519
380
  ssrManifest: false,
520
381
  cssCodeSplit: true,
@@ -547,7 +408,7 @@ async function build(rootProjectDir, options) {
547
408
  ...viteConfig?.build?.rolldownOptions?.output
548
409
  }
549
410
  },
550
- outDir: path3.join(distDir, ".build/routes"),
411
+ outDir: path2.join(distDir, ".build/routes"),
551
412
  ssr: true,
552
413
  ssrManifest: false,
553
414
  ssrEmitAssets: true,
@@ -578,7 +439,7 @@ async function build(rootProjectDir, options) {
578
439
  ...viteConfig?.build?.rolldownOptions?.output
579
440
  }
580
441
  },
581
- outDir: path3.join(distDir, ".build/client"),
442
+ outDir: path2.join(distDir, ".build/client"),
582
443
  ssr: false,
583
444
  ssrManifest: false,
584
445
  manifest: true,
@@ -591,21 +452,21 @@ async function build(rootProjectDir, options) {
591
452
  });
592
453
  } else {
593
454
  await writeFile(
594
- path3.join(distDir, ".build/client/.vite/manifest.json"),
455
+ path2.join(distDir, ".build/client/.vite/manifest.json"),
595
456
  "{}"
596
457
  );
597
458
  }
598
- await bundleRootConfig(rootDir, path3.join(distDir, "root.config.js"));
459
+ await bundleRootConfig(rootDir, path2.join(distDir, "root.config.js"));
599
460
  await copyGlob(
600
461
  "**/*.css",
601
- path3.join(distDir, ".build/routes"),
602
- path3.join(distDir, ".build/client")
462
+ path2.join(distDir, ".build/routes"),
463
+ path2.join(distDir, ".build/client")
603
464
  );
604
465
  const routesManifest = await loadJson(
605
- path3.join(distDir, ".build/routes/.vite/manifest.json")
466
+ path2.join(distDir, ".build/routes/.vite/manifest.json")
606
467
  );
607
468
  const clientManifest = await loadJson(
608
- path3.join(distDir, ".build/client/.vite/manifest.json")
469
+ path2.join(distDir, ".build/client/.vite/manifest.json")
609
470
  );
610
471
  function collectRouteCss(asset, cssDeps, visited) {
611
472
  if (!asset || !asset.file || visited.has(asset.file)) {
@@ -634,24 +495,31 @@ async function build(rootProjectDir, options) {
634
495
  clientManifest[manifestKey] = asset;
635
496
  }
636
497
  });
498
+ const podRoutes = pods.flatMap(
499
+ (pod) => pod.routeFiles.map((route) => ({
500
+ src: `pod/${pod.name}/${route.relPath}`,
501
+ filePath: route.filePath
502
+ }))
503
+ );
637
504
  const assetMap = BuildAssetMap.fromViteManifest(
638
505
  rootConfig,
639
506
  clientManifest,
640
- elementGraph
507
+ elementGraph,
508
+ podRoutes
641
509
  );
642
510
  const rootManifest = assetMap.toJson();
643
511
  await writeFile(
644
- path3.join(distDir, ".root/manifest.json"),
512
+ path2.join(distDir, ".root/manifest.json"),
645
513
  JSON.stringify(rootManifest, null, 2)
646
514
  );
647
515
  const elementGraphJson = elementGraph.toJson();
648
516
  await writeFile(
649
- path3.join(distDir, ".root/elements.json"),
517
+ path2.join(distDir, ".root/elements.json"),
650
518
  JSON.stringify(elementGraphJson, null, 2)
651
519
  );
652
- const buildDir = path3.join(distDir, "html");
653
- const publicDir = path3.join(rootDir, "public");
654
- if (fsExtra.existsSync(path3.join(rootDir, "public"))) {
520
+ const buildDir = path2.join(distDir, "html");
521
+ const publicDir = path2.join(rootDir, "public");
522
+ if (fsExtra.existsSync(path2.join(rootDir, "public"))) {
655
523
  fsExtra.copySync(publicDir, buildDir, { dereference: true });
656
524
  } else {
657
525
  await makeDir(buildDir);
@@ -663,8 +531,8 @@ async function build(rootProjectDir, options) {
663
531
  }
664
532
  seenAssets.add(assetUrl);
665
533
  const assetRelPath = assetUrl.slice(1);
666
- const assetFrom = path3.join(distDir, ".build/client", assetRelPath);
667
- const assetTo = path3.join(buildDir, assetRelPath);
534
+ const assetFrom = path2.join(distDir, ".build/client", assetRelPath);
535
+ const assetTo = path2.join(buildDir, assetRelPath);
668
536
  if (!await fileExists(assetFrom)) {
669
537
  console.log(`${assetFrom} does not exist`);
670
538
  return;
@@ -694,7 +562,7 @@ async function build(rootProjectDir, options) {
694
562
  })
695
563
  );
696
564
  if (!ssrOnly) {
697
- const render = await import(path3.join(distDir, "server/render.js"));
565
+ const render = await import(path2.join(distDir, "server/render.js"));
698
566
  const renderer = new render.Renderer(rootConfig, { assetMap, elementGraph });
699
567
  let sitemap = await renderer.getSitemap();
700
568
  if (options?.filter) {
@@ -714,97 +582,118 @@ async function build(rootProjectDir, options) {
714
582
  );
715
583
  }
716
584
  const domain = rootConfig.domain;
717
- console.log("\nhtml output:");
718
- const batchSize = Number(options?.concurrency || 10);
719
- await batchAsyncCalls(
720
- Object.entries(sitemap),
721
- batchSize,
722
- async ([urlPath, sitemapItem]) => {
723
- if (rootConfig.build?.excludeDefaultLocaleFromIntlPaths) {
724
- const defaultLocale = rootConfig.i18n?.defaultLocale || "en";
725
- if (sitemapItem.locale === defaultLocale) {
726
- return;
727
- }
585
+ const addSitemapXmlItem = (urlPath, sitemapItem, outFilePath) => {
586
+ if (!rootConfig.sitemap || !outFilePath.endsWith("index.html")) {
587
+ return;
588
+ }
589
+ const sitemapXmlItem = {
590
+ url: `${domain}${urlPath}`,
591
+ locale: sitemapItem.locale,
592
+ alts: []
593
+ };
594
+ sitemapXmlItems.push(sitemapXmlItem);
595
+ if (sitemapItem.alts) {
596
+ Object.entries(sitemapItem.alts).forEach(([altLocale, item]) => {
597
+ sitemapXmlItem.alts.push({
598
+ url: `${domain}${item.urlPath}`,
599
+ locale: altLocale,
600
+ hreflang: item.hrefLang
601
+ });
602
+ });
603
+ }
604
+ };
605
+ const onPageResult = (sitemapItem, result) => {
606
+ if (result.notFound || !result.outFilePath) {
607
+ return;
608
+ }
609
+ if (!result.staticContent) {
610
+ addSitemapXmlItem(result.urlPath, sitemapItem, result.outFilePath);
611
+ }
612
+ printFileOutput(
613
+ fileSize(path2.join(buildDir, result.outFilePath)),
614
+ "dist/html/",
615
+ result.outFilePath
616
+ );
617
+ };
618
+ const sitemapEntries = Object.entries(sitemap).filter(([, sitemapItem]) => {
619
+ if (rootConfig.build?.excludeDefaultLocaleFromIntlPaths) {
620
+ const defaultLocale = rootConfig.i18n?.defaultLocale || "en";
621
+ if (sitemapItem.locale === defaultLocale) {
622
+ return false;
728
623
  }
729
- try {
730
- const routeModule = sitemapItem.route.module;
731
- if (routeModule.getStaticContent) {
732
- let props;
733
- if (routeModule.getStaticProps) {
734
- props = await routeModule.getStaticProps({
735
- rootConfig,
736
- params: sitemapItem.params
624
+ }
625
+ return true;
626
+ });
627
+ console.log("\nhtml output:");
628
+ const concurrency = Number(options?.concurrency || 10);
629
+ const numThreads = resolveNumThreads(
630
+ options?.threads,
631
+ sitemapEntries.length
632
+ );
633
+ if (numThreads > 0) {
634
+ const pool = new BuildWorkerPool({
635
+ numWorkers: numThreads,
636
+ workerConcurrency: Math.max(Math.ceil(concurrency / numThreads), 1),
637
+ rootDir,
638
+ mode
639
+ });
640
+ try {
641
+ await pool.ready();
642
+ await Promise.all(
643
+ sitemapEntries.map(async ([urlPath, sitemapItem]) => {
644
+ try {
645
+ const result = await pool.run({
646
+ urlPath,
647
+ params: sitemapItem.params,
648
+ routeSrc: sitemapItem.route.src,
649
+ locale: sitemapItem.locale
737
650
  });
738
- if (props?.notFound) {
739
- return;
651
+ onPageResult(sitemapItem, result);
652
+ } catch (e) {
653
+ if (e instanceof BuildPageError) {
654
+ logBuildError(
655
+ {
656
+ route: sitemapItem.route,
657
+ params: sitemapItem.params,
658
+ urlPath
659
+ },
660
+ new Error(e.workerError)
661
+ );
740
662
  }
741
- } else {
742
- props = { rootConfig, params: sitemapItem.params };
743
- }
744
- const result = await routeModule.getStaticContent(props);
745
- let body;
746
- if (typeof result === "string") {
747
- body = result;
748
- } else if (result && typeof result === "object") {
749
- body = result.body;
750
- } else {
751
- body = "";
752
- }
753
- const outFilePath2 = urlPath.slice(1);
754
- const outPath2 = path3.join(buildDir, outFilePath2);
755
- await makeDir(path3.dirname(outPath2));
756
- await writeFile(outPath2, normalizeLineEndings(body));
757
- printFileOutput(fileSize(outPath2), "dist/html/", outFilePath2);
758
- return;
759
- }
760
- const data = await renderer.renderRoute(sitemapItem.route, {
761
- routeParams: sitemapItem.params
762
- });
763
- if (data.notFound) {
764
- return;
765
- }
766
- let outFilePath = path3.join(urlPath.slice(1), "index.html");
767
- if (outFilePath.endsWith("404/index.html")) {
768
- outFilePath = outFilePath.replace("404/index.html", "404.html");
769
- }
770
- const outPath = path3.join(buildDir, outFilePath);
771
- if (rootConfig.sitemap && outFilePath.endsWith("index.html")) {
772
- const sitemapXmlItem = {
773
- url: `${domain}${urlPath}`,
774
- locale: sitemapItem.locale,
775
- alts: []
776
- };
777
- sitemapXmlItems.push(sitemapXmlItem);
778
- if (sitemapItem.alts) {
779
- Object.entries(sitemapItem.alts).forEach(([altLocale, item]) => {
780
- sitemapXmlItem.alts.push({
781
- url: `${domain}${item.urlPath}`,
782
- locale: altLocale,
783
- hreflang: item.hrefLang
784
- });
785
- });
663
+ throw e;
786
664
  }
665
+ })
666
+ );
667
+ } finally {
668
+ await pool.terminate();
669
+ }
670
+ } else {
671
+ await batchAsyncCalls(
672
+ sitemapEntries,
673
+ concurrency,
674
+ async ([urlPath, sitemapItem]) => {
675
+ try {
676
+ const result = await buildPage(
677
+ renderer,
678
+ rootConfig,
679
+ buildDir,
680
+ sitemapItem.route,
681
+ { urlPath, params: sitemapItem.params }
682
+ );
683
+ onPageResult(sitemapItem, result);
684
+ } catch (e) {
685
+ logBuildError(
686
+ { route: sitemapItem.route, params: sitemapItem.params, urlPath },
687
+ e
688
+ );
689
+ throw new Error(
690
+ `BuildError: ${urlPath} (${sitemapItem.route.src}) failed to build.`,
691
+ { cause: e }
692
+ );
787
693
  }
788
- let html = data.html || "";
789
- if (rootConfig.prettyHtml) {
790
- html = await htmlPretty(html, rootConfig.prettyHtmlOptions);
791
- } else if (rootConfig.minifyHtml) {
792
- html = await htmlMinify(html, rootConfig.minifyHtmlOptions);
793
- }
794
- await writeFile(outPath, normalizeLineEndings(html));
795
- printFileOutput(fileSize(outPath), "dist/html/", outFilePath);
796
- } catch (e) {
797
- logBuildError(
798
- { route: sitemapItem.route, params: sitemapItem.params, urlPath },
799
- e
800
- );
801
- throw new Error(
802
- `BuildError: ${urlPath} (${sitemapItem.route.src}) failed to build.`,
803
- { cause: e }
804
- );
805
694
  }
806
- }
807
- );
695
+ );
696
+ }
808
697
  if (rootConfig.sitemap) {
809
698
  const sitemapXmlBuilder = [];
810
699
  sitemapXmlItems.sort((a, b) => a.url.localeCompare(b.url));
@@ -830,7 +719,7 @@ async function build(rootProjectDir, options) {
830
719
  "</urlset>"
831
720
  ];
832
721
  const sitemapXml = sitemapXmlLines.join("\n");
833
- const outPath = path3.join(buildDir, "sitemap.xml");
722
+ const outPath = path2.join(buildDir, "sitemap.xml");
834
723
  await writeFile(outPath, sitemapXml);
835
724
  printFileOutput(fileSize(outPath), "dist/html/", "sitemap.xml");
836
725
  }
@@ -844,6 +733,27 @@ async function build(rootProjectDir, options) {
844
733
  function isRouteFile(filepath) {
845
734
  return filepath.startsWith("routes") && isJsFile(filepath);
846
735
  }
736
+ var MIN_PAGES_PER_THREAD = 10;
737
+ function resolveNumThreads(threads, numPages) {
738
+ if (threads === void 0 || threads === false) {
739
+ return 0;
740
+ }
741
+ if (threads === true || threads === "auto") {
742
+ const maxByCpu = Math.max(os.availableParallelism() - 1, 1);
743
+ const maxByPages = Math.floor(numPages / MIN_PAGES_PER_THREAD);
744
+ const numThreads = Math.min(maxByCpu, maxByPages);
745
+ if (numThreads <= 1) {
746
+ return 0;
747
+ }
748
+ console.log(`rendering with ${numThreads} worker threads`);
749
+ return numThreads;
750
+ }
751
+ const num = parseInt(threads);
752
+ if (isNaN(num) || num < 0) {
753
+ throw new Error(`invalid --threads value: ${threads}`);
754
+ }
755
+ return num;
756
+ }
847
757
  function fileSize(filepath) {
848
758
  const stats = fsExtra.statSync(filepath);
849
759
  const bytes = stats.size;
@@ -892,18 +802,15 @@ function formatParams(params) {
892
802
  return ` ${key}: ${value}`;
893
803
  }).join("\n");
894
804
  }
895
- function normalizeLineEndings(str) {
896
- return str.replace(/\r\n?/g, "\n");
897
- }
898
805
 
899
806
  // src/cli/codegen.ts
900
- import { promises as fs3 } from "node:fs";
901
- import path4 from "node:path";
902
- import { fileURLToPath as fileURLToPath2 } from "node:url";
903
- import glob3 from "tiny-glob";
904
- var __dirname2 = path4.dirname(fileURLToPath2(import.meta.url));
807
+ import { promises as fs } from "node:fs";
808
+ import path3 from "node:path";
809
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
810
+ import glob2 from "tiny-glob";
811
+ var __dirname3 = path3.dirname(fileURLToPath3(import.meta.url));
905
812
  async function codegen(type, name, options) {
906
- const rootDir = path4.resolve(process.cwd());
813
+ const rootDir = path3.resolve(process.cwd());
907
814
  const project = new Project(rootDir);
908
815
  await project.generateCode(type, name, options);
909
816
  }
@@ -913,8 +820,8 @@ var Project = class {
913
820
  constructor(rootDir) {
914
821
  this.rootDir = rootDir;
915
822
  this.tplDirs = [
916
- path4.join(rootDir, "codegen"),
917
- path4.join(__dirname2, "../codegen")
823
+ path3.join(rootDir, "codegen"),
824
+ path3.join(__dirname3, "../codegen")
918
825
  ];
919
826
  }
920
827
  async generateCode(type, name, options) {
@@ -924,7 +831,7 @@ var Project = class {
924
831
  return;
925
832
  }
926
833
  const outname = options?.out || `${type}s`;
927
- const outdir = path4.join(this.rootDir, outname, name);
834
+ const outdir = path3.join(this.rootDir, outname, name);
928
835
  if (await dirExists(outdir)) {
929
836
  await rmDir(outdir);
930
837
  }
@@ -933,7 +840,7 @@ var Project = class {
933
840
  const tpl = await files[tplName].read();
934
841
  const content = tpl.replaceAll("[[name]]", name).replaceAll("[[name:camel_upper]]", toCamelCaseUpper(name));
935
842
  const filename = tplName.replace("[name]", name);
936
- const filepath = path4.join(outdir, filename);
843
+ const filepath = path3.join(outdir, filename);
937
844
  await writeFile(filepath, content);
938
845
  console.log(`saved ${filepath}`);
939
846
  }
@@ -944,7 +851,7 @@ var Project = class {
944
851
  */
945
852
  async loadFiles(type) {
946
853
  for (const tplDir of this.tplDirs) {
947
- const typeDir = path4.join(tplDir, type);
854
+ const typeDir = path3.join(tplDir, type);
948
855
  if (await dirExists(typeDir)) {
949
856
  return this.loadTplFiles(typeDir);
950
857
  }
@@ -956,12 +863,12 @@ var Project = class {
956
863
  */
957
864
  async loadTplFiles(dirpath) {
958
865
  const tplFiles = {};
959
- const files = await glob3("*.tpl", { cwd: dirpath });
866
+ const files = await glob2("*.tpl", { cwd: dirpath });
960
867
  for (const filename of files) {
961
- const filepath = path4.join(dirpath, filename);
868
+ const filepath = path3.join(dirpath, filename);
962
869
  const name = filename.slice(0, -4);
963
870
  tplFiles[name] = {
964
- read: () => fs3.readFile(filepath, "utf-8")
871
+ read: () => fs.readFile(filepath, "utf-8")
965
872
  };
966
873
  }
967
874
  return tplFiles;
@@ -977,23 +884,23 @@ function toTitleCase(str) {
977
884
  }
978
885
 
979
886
  // src/cli/create-package.ts
980
- import { promises as fs4 } from "node:fs";
981
- import path5 from "node:path";
887
+ import { promises as fs2 } from "node:fs";
888
+ import path4 from "node:path";
982
889
  import { build as esbuild } from "esbuild";
983
890
  async function createPackage(rootProjectDir, options) {
984
891
  const mode = options?.mode || "production";
985
892
  process.env.NODE_ENV = mode;
986
- const rootDir = path5.resolve(rootProjectDir || process.cwd());
987
- const distDir = path5.join(rootDir, "dist");
893
+ const rootDir = path4.resolve(rootProjectDir || process.cwd());
894
+ const distDir = path4.join(rootDir, "dist");
988
895
  const target = options?.target || await getDefaultTarget(rootDir);
989
- const outDir = path5.resolve(options?.out || target || "out");
896
+ const outDir = path4.resolve(options?.out || target || "out");
990
897
  await build(rootProjectDir, { ssrOnly: true, mode });
991
898
  await rmDir(outDir);
992
899
  await makeDir(outDir);
993
- await copyDir(distDir, path5.resolve(outDir, "dist"));
994
- const collectionsDir = path5.resolve(rootDir, "collections");
900
+ await copyDir(distDir, path4.resolve(outDir, "dist"));
901
+ const collectionsDir = path4.resolve(rootDir, "collections");
995
902
  if (await dirExists(collectionsDir)) {
996
- await copyDir(collectionsDir, path5.join(outDir, "collections"));
903
+ await copyDir(collectionsDir, path4.join(outDir, "collections"));
997
904
  }
998
905
  const packageJson = await generatePackageJson(rootDir, options);
999
906
  if (options?.version && packageJson.dependencies) {
@@ -1008,21 +915,21 @@ async function createPackage(rootProjectDir, options) {
1008
915
  }
1009
916
  }
1010
917
  if (target === "appengine") {
1011
- const appYamlPath = options?.appYaml || path5.join(rootDir, "app.yaml");
918
+ const appYamlPath = options?.appYaml || path4.join(rootDir, "app.yaml");
1012
919
  await onAppEngine({ packageJson, outDir, appYamlPath });
1013
920
  } else if (target === "firebase") {
1014
921
  await onFirebase({ rootDir, packageJson, outDir });
1015
922
  }
1016
- await writeJson(path5.resolve(outDir, "package.json"), packageJson);
923
+ await writeJson(path4.resolve(outDir, "package.json"), packageJson);
1017
924
  console.log("done!");
1018
925
  console.log(`saved package to ${outDir}`);
1019
926
  }
1020
927
  async function getDefaultTarget(rootDir) {
1021
- const firebaseConfigPath = path5.resolve(rootDir, "firebase.json");
928
+ const firebaseConfigPath = path4.resolve(rootDir, "firebase.json");
1022
929
  if (await fileExists(firebaseConfigPath)) {
1023
930
  return "firebase";
1024
931
  }
1025
- const appEngineConfigPath = path5.resolve(rootDir, "app.yaml");
932
+ const appEngineConfigPath = path4.resolve(rootDir, "app.yaml");
1026
933
  if (await fileExists(appEngineConfigPath)) {
1027
934
  return "appengine";
1028
935
  }
@@ -1030,7 +937,7 @@ async function getDefaultTarget(rootDir) {
1030
937
  }
1031
938
  async function generatePackageJson(rootDir, options) {
1032
939
  const packageJson = await loadJson(
1033
- path5.resolve(rootDir, "package.json")
940
+ path4.resolve(rootDir, "package.json")
1034
941
  );
1035
942
  const allDeps = flattenPackageDepsFromMonorepo(rootDir);
1036
943
  packageJson.dependencies ??= {};
@@ -1057,7 +964,7 @@ async function generatePackageJson(rootDir, options) {
1057
964
  async function onAppEngine(options) {
1058
965
  const { outDir, packageJson, appYamlPath } = options;
1059
966
  if (await fileExists(appYamlPath)) {
1060
- await fs4.copyFile(appYamlPath, path5.resolve(outDir, "app.yaml"));
967
+ await fs2.copyFile(appYamlPath, path4.resolve(outDir, "app.yaml"));
1061
968
  }
1062
969
  if (packageJson.scripts?.start) {
1063
970
  packageJson.scripts = { start: packageJson.scripts.start };
@@ -1067,11 +974,11 @@ async function onAppEngine(options) {
1067
974
  }
1068
975
  async function onFirebase(options) {
1069
976
  const { rootDir, outDir, packageJson } = options;
1070
- const outBasename = path5.basename(outDir);
977
+ const outBasename = path4.basename(outDir);
1071
978
  if (outBasename === "functions") {
1072
- const indexTsFile = path5.resolve(rootDir, "index.ts");
979
+ const indexTsFile = path4.resolve(rootDir, "index.ts");
1073
980
  if (await fileExists(indexTsFile)) {
1074
- await bundleTsFile(indexTsFile, path5.resolve(outDir, "index.js"));
981
+ await bundleTsFile(indexTsFile, path4.resolve(outDir, "index.js"));
1075
982
  }
1076
983
  }
1077
984
  if (packageJson.scripts?.start) {
@@ -1096,7 +1003,7 @@ async function bundleTsFile(srcPath, outPath) {
1096
1003
  setup(build2) {
1097
1004
  build2.onResolve({ filter: /.*/ }, (args) => {
1098
1005
  const id = args.path;
1099
- if (id[0] !== "." && !path5.isAbsolute(id)) {
1006
+ if (id[0] !== "." && !path4.isAbsolute(id)) {
1100
1007
  return {
1101
1008
  external: true
1102
1009
  };
@@ -1110,13 +1017,13 @@ async function bundleTsFile(srcPath, outPath) {
1110
1017
  }
1111
1018
 
1112
1019
  // src/cli/dev.ts
1113
- import path12 from "node:path";
1114
- import { fileURLToPath as fileURLToPath3 } from "node:url";
1020
+ import path11 from "node:path";
1021
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
1115
1022
  import cookieParser from "cookie-parser";
1116
1023
  import { default as express } from "express";
1117
1024
  import { dim as dim5 } from "kleur/colors";
1118
1025
  import sirv from "sirv";
1119
- import glob4 from "tiny-glob";
1026
+ import glob3 from "tiny-glob";
1120
1027
 
1121
1028
  // src/middleware/hooks.ts
1122
1029
  function hooksMiddleware() {
@@ -1204,8 +1111,8 @@ function testIsRedirectValid(url) {
1204
1111
  }
1205
1112
 
1206
1113
  // src/render/asset-map/dev-asset-map.ts
1207
- import path6 from "node:path";
1208
- import { searchForWorkspaceRoot as searchForWorkspaceRoot2 } from "vite";
1114
+ import path5 from "node:path";
1115
+ import { searchForWorkspaceRoot } from "vite";
1209
1116
  var DevServerAssetMap = class {
1210
1117
  rootConfig;
1211
1118
  moduleGraph;
@@ -1214,7 +1121,7 @@ var DevServerAssetMap = class {
1214
1121
  this.moduleGraph = moduleGraph;
1215
1122
  }
1216
1123
  async get(src) {
1217
- const file = path6.resolve(this.rootConfig.rootDir, src);
1124
+ const file = path5.resolve(this.rootConfig.rootDir, src);
1218
1125
  const viteModules = this.moduleGraph.getModulesByFile(file);
1219
1126
  if (viteModules && viteModules.size > 0) {
1220
1127
  const [viteModule] = viteModules;
@@ -1232,7 +1139,7 @@ var DevServerAssetMap = class {
1232
1139
  getJsDeps: async () => [assetUrl]
1233
1140
  };
1234
1141
  }
1235
- const workspaceRoot = searchForWorkspaceRoot2(this.rootConfig.rootDir);
1142
+ const workspaceRoot = searchForWorkspaceRoot(this.rootConfig.rootDir);
1236
1143
  if (await directoryContains(workspaceRoot, file)) {
1237
1144
  const assetUrl = `/@fs/${file}`;
1238
1145
  return {
@@ -1246,7 +1153,7 @@ var DevServerAssetMap = class {
1246
1153
  return null;
1247
1154
  }
1248
1155
  filePathToSrc(file) {
1249
- return path6.relative(this.rootConfig.rootDir, file);
1156
+ return path5.relative(this.rootConfig.rootDir, file);
1250
1157
  }
1251
1158
  };
1252
1159
  var DevServerAsset = class _DevServerAsset {
@@ -1288,7 +1195,7 @@ var DevServerAsset = class _DevServerAsset {
1288
1195
  return;
1289
1196
  }
1290
1197
  visited.add(asset.moduleId);
1291
- const parts = path6.parse(asset.assetUrl);
1198
+ const parts = path5.parse(asset.assetUrl);
1292
1199
  if ([".js", ".jsx", ".ts", ".tsx"].includes(parts.ext) && asset.moduleId.includes("/elements/")) {
1293
1200
  urls.add(asset.assetUrl);
1294
1201
  }
@@ -1315,7 +1222,7 @@ var DevServerAsset = class _DevServerAsset {
1315
1222
  }
1316
1223
  visited.add(asset.assetUrl);
1317
1224
  if (asset.src.endsWith(".scss")) {
1318
- const parts = path6.parse(asset.src);
1225
+ const parts = path5.parse(asset.src);
1319
1226
  if (!parts.name.startsWith("_")) {
1320
1227
  urls.add(asset.assetUrl);
1321
1228
  }
@@ -1396,19 +1303,19 @@ function getSessionCookieSecret(rootConfig, rootDir) {
1396
1303
 
1397
1304
  // src/cli/secrets.ts
1398
1305
  import { spawn as spawn3 } from "node:child_process";
1399
- import fs8 from "node:fs";
1400
- import path10 from "node:path";
1306
+ import fs6 from "node:fs";
1307
+ import path9 from "node:path";
1401
1308
  import * as readline from "node:readline";
1402
1309
  import { dim as dim3, green, red, yellow } from "kleur/colors";
1403
1310
 
1404
1311
  // src/secrets/manifest.ts
1405
- import fs5 from "node:fs";
1406
- import path7 from "node:path";
1312
+ import fs3 from "node:fs";
1313
+ import path6 from "node:path";
1407
1314
  var MANIFEST_FILENAME = ".root.secrets.json";
1408
1315
  var GSM_KEY_RE = /^[A-Za-z0-9_-]{1,255}$/;
1409
1316
  var ENV_NAME_RE = /^[A-Za-z0-9_]+$/;
1410
1317
  function manifestPath(dir) {
1411
- return path7.join(dir, MANIFEST_FILENAME);
1318
+ return path6.join(dir, MANIFEST_FILENAME);
1412
1319
  }
1413
1320
  function isValidEnvName(name) {
1414
1321
  return ENV_NAME_RE.test(name);
@@ -1416,7 +1323,7 @@ function isValidEnvName(name) {
1416
1323
  async function readManifest(filePath) {
1417
1324
  let raw;
1418
1325
  try {
1419
- raw = await fs5.promises.readFile(filePath, "utf8");
1326
+ raw = await fs3.promises.readFile(filePath, "utf8");
1420
1327
  } catch (err) {
1421
1328
  if (err.code === "ENOENT") {
1422
1329
  return null;
@@ -1443,8 +1350,8 @@ async function writeManifest(filePath, manifest) {
1443
1350
  ...manifest.import ? { import: manifest.import } : {},
1444
1351
  secrets: sortedSecrets
1445
1352
  };
1446
- await fs5.promises.mkdir(path7.dirname(filePath), { recursive: true });
1447
- await fs5.promises.writeFile(
1353
+ await fs3.promises.mkdir(path6.dirname(filePath), { recursive: true });
1354
+ await fs3.promises.writeFile(
1448
1355
  filePath,
1449
1356
  JSON.stringify(ordered, null, 2) + "\n",
1450
1357
  "utf8"
@@ -1472,7 +1379,7 @@ async function resolveManagedKeys(rootDir) {
1472
1379
  }
1473
1380
  let shared;
1474
1381
  if (site.import) {
1475
- const sharedPath = path7.resolve(rootDir, site.import.manifest);
1382
+ const sharedPath = path6.resolve(rootDir, site.import.manifest);
1476
1383
  const loaded = await readManifest(sharedPath);
1477
1384
  if (!loaded) {
1478
1385
  throw new Error(`imported manifest not found: ${sharedPath}`);
@@ -1599,16 +1506,16 @@ function validateManifest(value, filePath) {
1599
1506
 
1600
1507
  // src/secrets/secrets.ts
1601
1508
  import { spawn as spawn2 } from "node:child_process";
1602
- import fs7 from "node:fs";
1603
- import path9 from "node:path";
1509
+ import fs5 from "node:fs";
1510
+ import path8 from "node:path";
1604
1511
 
1605
1512
  // src/secrets/env-file.ts
1606
- import fs6 from "node:fs";
1607
- import path8 from "node:path";
1513
+ import fs4 from "node:fs";
1514
+ import path7 from "node:path";
1608
1515
  import dotenv from "dotenv";
1609
1516
  async function readEnvFile(envPath2) {
1610
1517
  try {
1611
- return await fs6.promises.readFile(envPath2, "utf8");
1518
+ return await fs4.promises.readFile(envPath2, "utf8");
1612
1519
  } catch (err) {
1613
1520
  if (err.code === "ENOENT") {
1614
1521
  return "";
@@ -1617,11 +1524,11 @@ async function readEnvFile(envPath2) {
1617
1524
  }
1618
1525
  }
1619
1526
  async function writeEnvFile(envPath2, content) {
1620
- const dir = path8.dirname(envPath2);
1621
- await fs6.promises.mkdir(dir, { recursive: true });
1622
- const tmp = path8.join(dir, `.env.tmp-${process.pid}-${Date.now()}`);
1623
- await fs6.promises.writeFile(tmp, content, "utf8");
1624
- await fs6.promises.rename(tmp, envPath2);
1527
+ const dir = path7.dirname(envPath2);
1528
+ await fs4.promises.mkdir(dir, { recursive: true });
1529
+ const tmp = path7.join(dir, `.env.tmp-${process.pid}-${Date.now()}`);
1530
+ await fs4.promises.writeFile(tmp, content, "utf8");
1531
+ await fs4.promises.rename(tmp, envPath2);
1625
1532
  }
1626
1533
  function parseEnv(content) {
1627
1534
  return dotenv.parse(content);
@@ -1839,10 +1746,10 @@ function hashValue(salt, value) {
1839
1746
  // src/secrets/secrets.ts
1840
1747
  var STATE_FILENAME = "secrets-sync.json";
1841
1748
  function localStatePath(rootDir) {
1842
- return path9.join(rootDir, ".root", STATE_FILENAME);
1749
+ return path8.join(rootDir, ".root", STATE_FILENAME);
1843
1750
  }
1844
1751
  function envPath(rootDir) {
1845
- return path9.join(rootDir, ".env");
1752
+ return path8.join(rootDir, ".env");
1846
1753
  }
1847
1754
  var inFlight = /* @__PURE__ */ new Map();
1848
1755
  function syncSecrets(options) {
@@ -2068,7 +1975,7 @@ async function pushEnvToSecrets(options) {
2068
1975
  };
2069
1976
  }
2070
1977
  async function sharedImportedNames(rootDir, manifestFilePath) {
2071
- if (path9.resolve(manifestFilePath) !== path9.resolve(manifestPath(rootDir))) {
1978
+ if (path8.resolve(manifestFilePath) !== path8.resolve(manifestPath(rootDir))) {
2072
1979
  return /* @__PURE__ */ new Set();
2073
1980
  }
2074
1981
  try {
@@ -2131,7 +2038,7 @@ function isSyncDisabledByEnv() {
2131
2038
  }
2132
2039
  async function readLocalState(rootDir) {
2133
2040
  try {
2134
- const raw = await fs7.promises.readFile(localStatePath(rootDir), "utf8");
2041
+ const raw = await fs5.promises.readFile(localStatePath(rootDir), "utf8");
2135
2042
  const parsed = JSON.parse(raw);
2136
2043
  if (parsed && typeof parsed === "object" && typeof parsed.salt === "string" && parsed.secrets && typeof parsed.secrets === "object") {
2137
2044
  return {
@@ -2145,8 +2052,8 @@ async function readLocalState(rootDir) {
2145
2052
  }
2146
2053
  async function writeLocalState(rootDir, state) {
2147
2054
  const file = localStatePath(rootDir);
2148
- await fs7.promises.mkdir(path9.dirname(file), { recursive: true });
2149
- await fs7.promises.writeFile(
2055
+ await fs5.promises.mkdir(path8.dirname(file), { recursive: true });
2056
+ await fs5.promises.writeFile(
2150
2057
  file,
2151
2058
  JSON.stringify(state, null, 2) + "\n",
2152
2059
  "utf8"
@@ -2212,7 +2119,7 @@ function registerSecretsCommands(program) {
2212
2119
  }
2213
2120
  async function secretsInit(opts) {
2214
2121
  const rootDir = process.cwd();
2215
- const target = opts.manifest ? path10.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
2122
+ const target = opts.manifest ? path9.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
2216
2123
  if (await readManifest(target)) {
2217
2124
  console.log(
2218
2125
  `${BAR} ${yellow("secrets:")} manifest already exists at ${rel(rootDir, target)}`
@@ -2245,7 +2152,7 @@ async function secretsInit(opts) {
2245
2152
  }
2246
2153
  async function secretsSet(name, opts) {
2247
2154
  const rootDir = process.cwd();
2248
- const manifestFilePath = opts.manifest ? path10.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
2155
+ const manifestFilePath = opts.manifest ? path9.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
2249
2156
  const secretValue = await readSecretValue(name);
2250
2157
  if (!secretValue) {
2251
2158
  throw new Error("no value provided on stdin");
@@ -2258,7 +2165,7 @@ async function secretsSet(name, opts) {
2258
2165
  }
2259
2166
  async function secretsRm(name, opts) {
2260
2167
  const rootDir = process.cwd();
2261
- const manifestFilePath = opts.manifest ? path10.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
2168
+ const manifestFilePath = opts.manifest ? path9.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
2262
2169
  await removeSecret({ rootDir, manifestFilePath, name });
2263
2170
  console.log(`${BAR} ${green("secrets:")} removed ${name}`);
2264
2171
  console.log(
@@ -2267,7 +2174,7 @@ async function secretsRm(name, opts) {
2267
2174
  }
2268
2175
  async function secretsPush(opts) {
2269
2176
  const rootDir = process.cwd();
2270
- const manifestFilePath = opts.manifest ? path10.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
2177
+ const manifestFilePath = opts.manifest ? path9.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
2271
2178
  const only = opts.keys ? opts.keys.split(",").map((k) => k.trim()).filter(Boolean) : void 0;
2272
2179
  const confirm = opts.yes ? void 0 : async (names, gsmKey) => {
2273
2180
  if (!process.stdin.isTTY) {
@@ -2444,10 +2351,11 @@ function printPushResult(result, rootDir, manifestFilePath) {
2444
2351
  console.log();
2445
2352
  }
2446
2353
  async function ensureRootGitignored(rootDir) {
2447
- const gitignore = path10.join(rootDir, ".gitignore");
2354
+ const gitRoot = await gitToplevel(rootDir) ?? rootDir;
2355
+ const gitignore = path9.join(gitRoot, ".gitignore");
2448
2356
  let content = "";
2449
2357
  try {
2450
- content = await fs8.promises.readFile(gitignore, "utf8");
2358
+ content = await fs6.promises.readFile(gitignore, "utf8");
2451
2359
  } catch {
2452
2360
  }
2453
2361
  const lines = content.split(/\r?\n/).map((line) => line.trim());
@@ -2455,7 +2363,7 @@ async function ensureRootGitignored(rootDir) {
2455
2363
  return false;
2456
2364
  }
2457
2365
  const prefix = content && !content.endsWith("\n") ? "\n" : "";
2458
- await fs8.promises.writeFile(gitignore, `${content}${prefix}.root/
2366
+ await fs6.promises.writeFile(gitignore, `${content}${prefix}.root/
2459
2367
  `, "utf8");
2460
2368
  return true;
2461
2369
  }
@@ -2467,6 +2375,27 @@ async function warnIfEnvNotIgnored(rootDir) {
2467
2375
  );
2468
2376
  }
2469
2377
  }
2378
+ function gitToplevel(rootDir) {
2379
+ return new Promise((resolve) => {
2380
+ try {
2381
+ const child = spawn3("git", ["rev-parse", "--show-toplevel"], {
2382
+ cwd: rootDir
2383
+ });
2384
+ let stdout = "";
2385
+ child.stdout.setEncoding("utf8");
2386
+ child.stdout.on("data", (chunk) => {
2387
+ stdout += chunk;
2388
+ });
2389
+ child.on("error", () => resolve(void 0));
2390
+ child.on("close", (code) => {
2391
+ const toplevel = stdout.trim();
2392
+ resolve(code === 0 && toplevel ? toplevel : void 0);
2393
+ });
2394
+ } catch {
2395
+ resolve(void 0);
2396
+ }
2397
+ });
2398
+ }
2470
2399
  function isPathGitIgnored(rootDir, relPath) {
2471
2400
  return new Promise((resolve) => {
2472
2401
  try {
@@ -2562,7 +2491,7 @@ function withTimeout(promise, ms) {
2562
2491
  });
2563
2492
  }
2564
2493
  function rel(rootDir, filePath) {
2565
- return path10.relative(rootDir, filePath) || path10.basename(filePath);
2494
+ return path9.relative(rootDir, filePath) || path9.basename(filePath);
2566
2495
  }
2567
2496
  function firstLine(text) {
2568
2497
  return String(text).split("\n")[0];
@@ -2579,8 +2508,8 @@ function action(fn) {
2579
2508
  }
2580
2509
 
2581
2510
  // src/cli/startup/startup-tasks.ts
2582
- import os from "node:os";
2583
- import path11 from "node:path";
2511
+ import os2 from "node:os";
2512
+ import path10 from "node:path";
2584
2513
 
2585
2514
  // src/cli/startup/check-version.ts
2586
2515
  import { dim as dim4, green as green2, yellow as yellow2 } from "kleur/colors";
@@ -2663,7 +2592,7 @@ function printUpdateNotice(current, latest) {
2663
2592
 
2664
2593
  // src/cli/startup/startup-tasks.ts
2665
2594
  var STARTUP_TASKS = [checkVersionTask];
2666
- var STATE_FILE = path11.join(os.homedir(), ".root", "startup-tasks.json");
2595
+ var STATE_FILE = path10.join(os2.homedir(), ".root", "startup-tasks.json");
2667
2596
  async function runStartupTasks(ctx) {
2668
2597
  try {
2669
2598
  const state = await readState();
@@ -2714,13 +2643,13 @@ async function writeState(state) {
2714
2643
  }
2715
2644
 
2716
2645
  // src/cli/dev.ts
2717
- var __dirname3 = path12.dirname(fileURLToPath3(import.meta.url));
2646
+ var __dirname4 = path11.dirname(fileURLToPath4(import.meta.url));
2718
2647
  var DEV_SERVER_404_LOG_IGNORE_PATHS = /* @__PURE__ */ new Set([
2719
2648
  "/.well-known/appspecific/com.chrome.devtools.json"
2720
2649
  ]);
2721
2650
  async function dev(rootProjectDir, options) {
2722
2651
  process.env.NODE_ENV = "development";
2723
- const rootDir = path12.resolve(rootProjectDir || process.cwd());
2652
+ const rootDir = path11.resolve(rootProjectDir || process.cwd());
2724
2653
  const defaultPort = parseInt(process.env.PORT || "4007");
2725
2654
  const host = options?.host || "localhost";
2726
2655
  const port = await findOpenPort(defaultPort, defaultPort + 10);
@@ -2748,7 +2677,7 @@ async function dev(rootProjectDir, options) {
2748
2677
  "rootConfigDependencies"
2749
2678
  );
2750
2679
  const dependencies = [
2751
- path12.resolve(rootDir, "root.config.ts"),
2680
+ path11.resolve(rootDir, "root.config.ts"),
2752
2681
  ...rootConfigDependencies
2753
2682
  ];
2754
2683
  viteServer.watcher.add(dependencies);
@@ -2776,7 +2705,7 @@ ${dim5("\u2503")} root.config.ts changed. restarting server...`
2776
2705
  await start2();
2777
2706
  }
2778
2707
  async function createDevServer(options) {
2779
- const rootDir = path12.resolve(options?.rootDir || process.cwd());
2708
+ const rootDir = path11.resolve(options?.rootDir || process.cwd());
2780
2709
  const { rootConfig, dependencies } = await loadRootConfigWithDeps(rootDir, {
2781
2710
  command: "dev"
2782
2711
  });
@@ -2791,6 +2720,7 @@ async function createDevServer(options) {
2791
2720
  });
2792
2721
  server.set("viteServer", viteServer);
2793
2722
  server.use(rootProjectMiddleware({ rootConfig }));
2723
+ server.use(securityHeadersMiddleware({ rootConfig }));
2794
2724
  server.use(viteMiddleware);
2795
2725
  server.use(hooksMiddleware());
2796
2726
  const sessionCookieSecret = getSessionCookieSecret(rootConfig, rootDir);
@@ -2812,7 +2742,7 @@ async function createDevServer(options) {
2812
2742
  if (rootConfig.server?.headers) {
2813
2743
  server.use(headersMiddleware({ rootConfig }));
2814
2744
  }
2815
- const publicDir = path12.join(rootDir, "public");
2745
+ const publicDir = path11.join(rootDir, "public");
2816
2746
  if (await dirExists(publicDir)) {
2817
2747
  server.use(rootPublicDirMiddleware({ publicDir, viteServer }));
2818
2748
  }
@@ -2840,10 +2770,10 @@ async function createViteMiddleware(options) {
2840
2770
  return sourceFile.relPath;
2841
2771
  });
2842
2772
  const bundleScripts = [];
2843
- if (await isDirectory(path12.join(rootDir, "bundles"))) {
2844
- const bundleFiles = await glob4("bundles/*", { cwd: rootDir });
2773
+ if (await isDirectory(path11.join(rootDir, "bundles"))) {
2774
+ const bundleFiles = await glob3("bundles/*", { cwd: rootDir });
2845
2775
  bundleFiles.forEach((file) => {
2846
- const parts = path12.parse(file);
2776
+ const parts = path11.parse(file);
2847
2777
  if (isJsFile(parts.base)) {
2848
2778
  bundleScripts.push(file);
2849
2779
  }
@@ -2860,7 +2790,7 @@ async function createViteMiddleware(options) {
2860
2790
  optimizeDeps
2861
2791
  });
2862
2792
  function isInElementsDir(changedFilePath) {
2863
- const filePath = path12.resolve(changedFilePath);
2793
+ const filePath = path11.resolve(changedFilePath);
2864
2794
  const elementsDirs = getElementsDirs(rootConfig, pods);
2865
2795
  return elementsDirs.some((dirPath) => filePath.startsWith(dirPath));
2866
2796
  }
@@ -2879,7 +2809,7 @@ async function createViteMiddleware(options) {
2879
2809
  const viteMiddleware = async (req, res, next) => {
2880
2810
  try {
2881
2811
  req.viteServer = viteServer;
2882
- const renderModulePath = path12.resolve(__dirname3, "./render.js");
2812
+ const renderModulePath = path11.resolve(__dirname4, "./render.js");
2883
2813
  const render = await viteServer.ssrLoadModule(
2884
2814
  renderModulePath
2885
2815
  );
@@ -2903,7 +2833,7 @@ function rootPublicDirMiddleware(options) {
2903
2833
  handler = sirv(publicDir, sirvOptions);
2904
2834
  }, 1e3);
2905
2835
  function isInPublicDir(changedFilePath) {
2906
- const filePath = path12.resolve(changedFilePath);
2836
+ const filePath = path11.resolve(changedFilePath);
2907
2837
  return filePath.startsWith(publicDir);
2908
2838
  }
2909
2839
  const watcher = options.viteServer.watcher;
@@ -2935,7 +2865,7 @@ function rootDevServer404Middleware() {
2935
2865
  }
2936
2866
  if (req.renderer) {
2937
2867
  const url = req.path;
2938
- const ext = path12.extname(url);
2868
+ const ext = path11.extname(url);
2939
2869
  if (!ext) {
2940
2870
  const renderer = req.renderer;
2941
2871
  const data = await renderer.renderDevServer404(req);
@@ -2953,7 +2883,7 @@ function rootDevServer500Middleware() {
2953
2883
  console.error(String(err.stack || err));
2954
2884
  if (req.renderer) {
2955
2885
  const url = req.path;
2956
- const ext = path12.extname(url);
2886
+ const ext = path11.extname(url);
2957
2887
  if (!ext) {
2958
2888
  const renderer = req.renderer;
2959
2889
  const data = await renderer.renderDevServer500(req, err);
@@ -2979,7 +2909,7 @@ function debounce(fn, timeout) {
2979
2909
 
2980
2910
  // src/cli/gae-deploy.ts
2981
2911
  import { execSync } from "node:child_process";
2982
- import fs9 from "node:fs";
2912
+ import fs7 from "node:fs";
2983
2913
  import yaml from "js-yaml";
2984
2914
  async function gaeDeploy(appDir, options) {
2985
2915
  if (!appDir) {
@@ -2993,10 +2923,10 @@ async function gaeDeploy(appDir, options) {
2993
2923
  }
2994
2924
  process.chdir(appDir);
2995
2925
  const appYamlPath = "app.yaml";
2996
- if (!fs9.existsSync(appYamlPath)) {
2926
+ if (!fs7.existsSync(appYamlPath)) {
2997
2927
  throw new Error(`[gae-deplopy] Missing: ${appYamlPath}`);
2998
2928
  }
2999
- const appYaml = yaml.load(fs9.readFileSync(appYamlPath, "utf8"));
2929
+ const appYaml = yaml.load(fs7.readFileSync(appYamlPath, "utf8"));
3000
2930
  const service = appYaml.service;
3001
2931
  if (!service) {
3002
2932
  throw new Error(
@@ -3022,7 +2952,7 @@ async function gaeDeploy(appDir, options) {
3022
2952
  { stdio: "inherit" }
3023
2953
  );
3024
2954
  if (backupAppYaml) {
3025
- fs9.copyFileSync(backupAppYaml, "app.yaml");
2955
+ fs7.copyFileSync(backupAppYaml, "app.yaml");
3026
2956
  }
3027
2957
  if (options?.healthcheckUrl) {
3028
2958
  const healthcheckPassed = await testHealth(
@@ -3109,8 +3039,8 @@ function testIsEnvPlaceholder(envValue) {
3109
3039
  }
3110
3040
  function updateAppYamlEnv(appYamlPath, appYaml) {
3111
3041
  const backupAppYaml = `${appYamlPath}.bak`;
3112
- fs9.copyFileSync(appYamlPath, backupAppYaml);
3113
- let content = fs9.readFileSync(appYamlPath, "utf8");
3042
+ fs7.copyFileSync(appYamlPath, backupAppYaml);
3043
+ let content = fs7.readFileSync(appYamlPath, "utf8");
3114
3044
  const envVars = appYaml.env_variables;
3115
3045
  Object.entries(envVars).forEach(([envVar, envValue]) => {
3116
3046
  if (testIsEnvPlaceholder(envValue)) {
@@ -3123,7 +3053,7 @@ function updateAppYamlEnv(appYamlPath, appYaml) {
3123
3053
  }
3124
3054
  }
3125
3055
  });
3126
- fs9.writeFileSync(appYamlPath, content, "utf8");
3056
+ fs7.writeFileSync(appYamlPath, content, "utf8");
3127
3057
  return backupAppYaml;
3128
3058
  }
3129
3059
  function getTimestamp() {
@@ -3147,15 +3077,14 @@ function testManagedVersion(service, appInfo, prefix) {
3147
3077
  }
3148
3078
 
3149
3079
  // src/cli/preview.ts
3150
- import path13 from "node:path";
3151
- import compression from "compression";
3080
+ import path12 from "node:path";
3152
3081
  import cookieParser2 from "cookie-parser";
3153
3082
  import { default as express2 } from "express";
3154
3083
  import { dim as dim6 } from "kleur/colors";
3155
3084
  import sirv2 from "sirv";
3156
3085
  async function preview(rootProjectDir, options) {
3157
3086
  process.env.NODE_ENV = "development";
3158
- const rootDir = path13.resolve(rootProjectDir || process.cwd());
3087
+ const rootDir = path12.resolve(rootProjectDir || process.cwd());
3159
3088
  const server = await createPreviewServer({ rootDir });
3160
3089
  const port = parseInt(process.env.PORT || "4007");
3161
3090
  const host = options?.host || "localhost";
@@ -3169,11 +3098,12 @@ async function preview(rootProjectDir, options) {
3169
3098
  async function createPreviewServer(options) {
3170
3099
  const rootDir = options.rootDir;
3171
3100
  const rootConfig = await loadBundledConfig(rootDir, { command: "preview" });
3172
- const distDir = path13.join(rootDir, "dist");
3101
+ const distDir = path12.join(rootDir, "dist");
3173
3102
  const server = express2();
3174
3103
  server.disable("x-powered-by");
3175
- server.use(compression());
3104
+ server.use(compressionMiddleware());
3176
3105
  server.use(rootProjectMiddleware({ rootConfig }));
3106
+ server.use(securityHeadersMiddleware({ rootConfig }));
3177
3107
  server.use(await rootPreviewRendererMiddleware({ rootConfig, distDir }));
3178
3108
  server.use(hooksMiddleware());
3179
3109
  const sessionCookieSecret = getSessionCookieSecret(rootConfig, rootDir);
@@ -3195,7 +3125,7 @@ async function createPreviewServer(options) {
3195
3125
  if (rootConfig.server?.headers) {
3196
3126
  server.use(headersMiddleware({ rootConfig }));
3197
3127
  }
3198
- const publicDir = path13.join(distDir, "html");
3128
+ const publicDir = path12.join(distDir, "html");
3199
3129
  server.use(sirv2(publicDir, { dev: false }));
3200
3130
  server.use(trailingSlashMiddleware({ rootConfig }));
3201
3131
  server.use(rootPreviewServerMiddleware());
@@ -3214,14 +3144,14 @@ async function createPreviewServer(options) {
3214
3144
  }
3215
3145
  async function rootPreviewRendererMiddleware(options) {
3216
3146
  const { distDir, rootConfig } = options;
3217
- const render = await import(path13.join(distDir, "server/render.js"));
3218
- const manifestPath2 = path13.join(distDir, ".root/manifest.json");
3147
+ const render = await import(path12.join(distDir, "server/render.js"));
3148
+ const manifestPath2 = path12.join(distDir, ".root/manifest.json");
3219
3149
  if (!await fileExists(manifestPath2)) {
3220
3150
  throw new Error(
3221
3151
  `could not find ${manifestPath2}. run \`root build\` before \`root preview\`.`
3222
3152
  );
3223
3153
  }
3224
- const elementGraphJsonPath = path13.join(distDir, ".root/elements.json");
3154
+ const elementGraphJsonPath = path12.join(distDir, ".root/elements.json");
3225
3155
  if (!await fileExists(elementGraphJsonPath)) {
3226
3156
  throw new Error(
3227
3157
  `could not find ${elementGraphJsonPath}. run \`root build\` before \`root preview\`.`
@@ -3261,7 +3191,7 @@ function rootPreviewServer404Middleware() {
3261
3191
  console.error(`\u2753 404 ${req.originalUrl}`);
3262
3192
  if (req.renderer) {
3263
3193
  const url = req.path;
3264
- const ext = path13.extname(url);
3194
+ const ext = path12.extname(url);
3265
3195
  if (!ext) {
3266
3196
  const renderer = req.renderer;
3267
3197
  const data = await renderer.render404({ currentPath: url });
@@ -3279,7 +3209,7 @@ function rootPreviewServer500Middleware() {
3279
3209
  console.error(String(err.stack || err));
3280
3210
  if (req.renderer) {
3281
3211
  const url = req.path;
3282
- const ext = path13.extname(url);
3212
+ const ext = path12.extname(url);
3283
3213
  if (!ext) {
3284
3214
  const renderer = req.renderer;
3285
3215
  const data = await renderer.renderDevServer500(req, err);
@@ -3293,15 +3223,14 @@ function rootPreviewServer500Middleware() {
3293
3223
  }
3294
3224
 
3295
3225
  // src/cli/start.ts
3296
- import path14 from "node:path";
3297
- import compression2 from "compression";
3226
+ import path13 from "node:path";
3298
3227
  import cookieParser3 from "cookie-parser";
3299
3228
  import { default as express3 } from "express";
3300
3229
  import { dim as dim7 } from "kleur/colors";
3301
3230
  import sirv3 from "sirv";
3302
3231
  async function start(rootProjectDir, options) {
3303
3232
  process.env.NODE_ENV = "production";
3304
- const rootDir = path14.resolve(rootProjectDir || process.cwd());
3233
+ const rootDir = path13.resolve(rootProjectDir || process.cwd());
3305
3234
  const server = await createProdServer({ rootDir });
3306
3235
  const port = parseInt(process.env.PORT || "4007");
3307
3236
  const host = options?.host || "localhost";
@@ -3315,11 +3244,12 @@ async function start(rootProjectDir, options) {
3315
3244
  async function createProdServer(options) {
3316
3245
  const rootDir = options.rootDir;
3317
3246
  const rootConfig = await loadBundledConfig(rootDir, { command: "start" });
3318
- const distDir = path14.join(rootDir, "dist");
3247
+ const distDir = path13.join(rootDir, "dist");
3319
3248
  const server = express3();
3320
3249
  server.disable("x-powered-by");
3321
- server.use(compression2());
3250
+ server.use(compressionMiddleware());
3322
3251
  server.use(rootProjectMiddleware({ rootConfig }));
3252
+ server.use(securityHeadersMiddleware({ rootConfig }));
3323
3253
  server.use(await rootProdRendererMiddleware({ rootConfig, distDir }));
3324
3254
  server.use(hooksMiddleware());
3325
3255
  const sessionCookieSecret = getSessionCookieSecret(rootConfig, rootDir);
@@ -3341,7 +3271,7 @@ async function createProdServer(options) {
3341
3271
  if (rootConfig.server?.headers) {
3342
3272
  server.use(headersMiddleware({ rootConfig }));
3343
3273
  }
3344
- const publicDir = path14.join(distDir, "html");
3274
+ const publicDir = path13.join(distDir, "html");
3345
3275
  server.use(sirv3(publicDir, { dev: false }));
3346
3276
  server.use(trailingSlashMiddleware({ rootConfig }));
3347
3277
  server.use(rootProdServerMiddleware());
@@ -3360,14 +3290,14 @@ async function createProdServer(options) {
3360
3290
  }
3361
3291
  async function rootProdRendererMiddleware(options) {
3362
3292
  const { distDir, rootConfig } = options;
3363
- const render = await import(path14.join(distDir, "server/render.js"));
3364
- const manifestPath2 = path14.join(distDir, ".root/manifest.json");
3293
+ const render = await import(path13.join(distDir, "server/render.js"));
3294
+ const manifestPath2 = path13.join(distDir, ".root/manifest.json");
3365
3295
  if (!await fileExists(manifestPath2)) {
3366
3296
  throw new Error(
3367
3297
  `could not find ${manifestPath2}. run \`root build\` before \`root start\`.`
3368
3298
  );
3369
3299
  }
3370
- const elementGraphJsonPath = path14.join(distDir, ".root/elements.json");
3300
+ const elementGraphJsonPath = path13.join(distDir, ".root/elements.json");
3371
3301
  if (!await fileExists(elementGraphJsonPath)) {
3372
3302
  throw new Error(
3373
3303
  `could not find ${elementGraphJsonPath}. run \`root build\` before \`root start\`.`
@@ -3407,7 +3337,7 @@ function rootProdServer404Middleware() {
3407
3337
  console.error(`\u2753 404 ${req.originalUrl}`);
3408
3338
  if (req.renderer) {
3409
3339
  const url = req.path;
3410
- const ext = path14.extname(url);
3340
+ const ext = path13.extname(url);
3411
3341
  if (!ext) {
3412
3342
  const renderer = req.renderer;
3413
3343
  const data = await renderer.render404({ currentPath: url });
@@ -3425,7 +3355,7 @@ function rootProdServer500Middleware() {
3425
3355
  console.error(String(err.stack || err));
3426
3356
  if (req.renderer) {
3427
3357
  const url = req.path;
3428
- const ext = path14.extname(url);
3358
+ const ext = path13.extname(url);
3429
3359
  if (!ext) {
3430
3360
  const renderer = req.renderer;
3431
3361
  const data = await renderer.renderError(err);
@@ -3466,6 +3396,9 @@ var CliRunner = class {
3466
3396
  "-c, --concurrency <num>",
3467
3397
  "number of files to build concurrently",
3468
3398
  "10"
3399
+ ).option(
3400
+ "--threads [num]",
3401
+ 'renders pages using worker threads; pass a number for exactly N workers, or omit the value (or pass "auto") to pick based on cpu cores and page count'
3469
3402
  ).option(
3470
3403
  "--filter <urlPathRegex>",
3471
3404
  'builds the url paths that match the given regex, e.g. "/products/.*"',
@@ -3532,4 +3465,4 @@ export {
3532
3465
  createProdServer,
3533
3466
  CliRunner
3534
3467
  };
3535
- //# sourceMappingURL=chunk-VQPDCDKL.js.map
3468
+ //# sourceMappingURL=chunk-E4F6CMO3.js.map