@gigadrive/network-config 3.1.2 → 3.3.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/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/detection/detect-framework.ts
2
- import { FileSystem as FileSystem4, Path as Path3 } from "@effect/platform";
3
- import { Effect as Effect6 } from "effect";
2
+ import { FileSystem as FileSystem6, Path as Path5 } from "@effect/platform";
3
+ import { Effect as Effect8 } from "effect";
4
4
 
5
5
  // src/detection/detect-package-manager.ts
6
6
  import { FileSystem, Path } from "@effect/platform";
@@ -220,6 +220,141 @@ var nestjs = {
220
220
  };
221
221
 
222
222
  // src/detection/frameworks/nextjs.ts
223
+ import { FileSystem as FileSystem4, Path as Path3 } from "@effect/platform";
224
+ import { Effect as Effect4 } from "effect";
225
+
226
+ // src/build-output-v3/get-default-path-map.ts
227
+ import { FileSystem as FileSystem3, Path as Path2 } from "@effect/platform";
228
+ import { Effect as Effect3 } from "effect";
229
+ var getDefaultPathMap = Effect3.fn("getDefaultPathMap")(function* (directory) {
230
+ const fs = yield* FileSystem3.FileSystem;
231
+ const pathService = yield* Path2.Path;
232
+ const result = {};
233
+ const exists = yield* fs.exists(directory).pipe(Effect3.catchAll(() => Effect3.succeed(false)));
234
+ if (!exists) {
235
+ return result;
236
+ }
237
+ const MAX_DEPTH = 100;
238
+ const processDirectory = (currentPath, basePath = "", depth = 0) => Effect3.gen(function* () {
239
+ if (depth > MAX_DEPTH) return;
240
+ const entries = yield* fs.readDirectory(currentPath).pipe(Effect3.catchAll(() => Effect3.succeed([])));
241
+ for (const name of entries) {
242
+ const fullPath = pathService.join(currentPath, name);
243
+ const relativePath = basePath ? pathService.join(basePath, name) : name;
244
+ const stat = yield* fs.stat(fullPath).pipe(Effect3.catchAll(() => Effect3.succeed(null)));
245
+ if (!stat) continue;
246
+ if (stat.type === "Directory") {
247
+ yield* processDirectory(fullPath, relativePath, depth + 1);
248
+ } else {
249
+ result[fullPath] = relativePath;
250
+ }
251
+ }
252
+ });
253
+ yield* processDirectory(directory);
254
+ return result;
255
+ });
256
+
257
+ // src/detection/frameworks/nextjs.ts
258
+ var isRecord2 = (value) => typeof value === "object" && value !== null;
259
+ var normalizeRelativePath = (value, allowCurrentDirectory = false) => {
260
+ const normalized = value.replaceAll("\\", "/").replace(/^\.\//, "").replace(/\/+$/, "");
261
+ if (!allowCurrentDirectory && (!normalized || normalized === ".") || normalized.startsWith("/") || /^[A-Za-z]:/.test(normalized) || normalized.includes(":") || normalized.split("/").some((segment) => segment === "..")) {
262
+ return void 0;
263
+ }
264
+ return normalized || ".";
265
+ };
266
+ var parseBuildManifest = (content) => {
267
+ try {
268
+ const value = JSON.parse(content);
269
+ if (!isRecord2(value) || value.version !== 1 || value.output !== "standalone" && value.output !== "export" || typeof value.distDir !== "string" || typeof value.repoRootToProject !== "string") {
270
+ return void 0;
271
+ }
272
+ const distDir = normalizeRelativePath(value.distDir);
273
+ const repoRootToProject = normalizeRelativePath(value.repoRootToProject, true);
274
+ return distDir && repoRootToProject ? { version: 1, output: value.output, distDir, repoRootToProject } : void 0;
275
+ } catch {
276
+ return void 0;
277
+ }
278
+ };
279
+ var toPortablePath = (value) => value.replaceAll("\\", "/");
280
+ var createStaticExportConfig = Effect4.fn("nextjs.createStaticExportConfig")(function* (defaults, projectFolder) {
281
+ const pathService = yield* Path3.Path;
282
+ const outputDirectory = pathService.join(projectFolder, "out");
283
+ const files = yield* getDefaultPathMap(outputDirectory);
284
+ const assetPaths = [];
285
+ const assetOverrides = {};
286
+ for (const absolutePath of Object.keys(files)) {
287
+ const projectRelativePath = toPortablePath(pathService.relative(projectFolder, absolutePath));
288
+ const outputRelativePath = toPortablePath(pathService.relative(outputDirectory, absolutePath));
289
+ assetPaths.push(projectRelativePath);
290
+ const routePath = outputRelativePath === "index.html" ? "" : outputRelativePath.endsWith("/index.html") ? outputRelativePath.slice(0, -"/index.html".length) : outputRelativePath;
291
+ assetOverrides[projectRelativePath] = { path: routePath };
292
+ }
293
+ return {
294
+ ...defaults,
295
+ entrypoint: void 0,
296
+ routes: [],
297
+ assetsDir: "out",
298
+ assetsPrefixToStrip: "",
299
+ assetPaths,
300
+ assetOverrides,
301
+ package: void 0
302
+ };
303
+ });
304
+ var createStandaloneConfig = Effect4.fn("nextjs.createStandaloneConfig")(function* (defaults, projectFolder, manifest) {
305
+ const fs = yield* FileSystem4.FileSystem;
306
+ const pathService = yield* Path3.Path;
307
+ const standaloneRoot = pathService.join(projectFolder, manifest.distDir, "standalone");
308
+ const monorepoServer = pathService.join(standaloneRoot, manifest.repoRootToProject, "server.js");
309
+ const rootServer = pathService.join(standaloneRoot, "server.js");
310
+ const monorepoServerExists = yield* fs.exists(monorepoServer).pipe(Effect4.catchAll(() => Effect4.succeed(false)));
311
+ const serverPath = monorepoServerExists ? monorepoServer : rootServer;
312
+ const serverExists = yield* fs.exists(serverPath).pipe(Effect4.catchAll(() => Effect4.succeed(false)));
313
+ if (!serverExists) return defaults;
314
+ const serverDirectory = pathService.dirname(serverPath);
315
+ const entrypoint = toPortablePath(pathService.relative(standaloneRoot, serverPath));
316
+ const publicDirectory = pathService.join(projectFolder, "public");
317
+ const staticDirectory = pathService.join(projectFolder, manifest.distDir, "static");
318
+ const [publicFiles, staticFiles] = yield* Effect4.all([
319
+ getDefaultPathMap(publicDirectory),
320
+ getDefaultPathMap(staticDirectory)
321
+ ]);
322
+ const assetPaths = [];
323
+ const assetOverrides = {};
324
+ const filePathMap = {};
325
+ for (const [absolutePath, relativePath] of Object.entries(publicFiles)) {
326
+ const portableRelativePath = toPortablePath(relativePath);
327
+ const projectRelativePath = toPortablePath(pathService.relative(projectFolder, absolutePath));
328
+ assetPaths.push(projectRelativePath);
329
+ assetOverrides[projectRelativePath] = { path: portableRelativePath };
330
+ filePathMap[absolutePath] = toPortablePath(
331
+ pathService.relative(standaloneRoot, pathService.join(serverDirectory, "public", relativePath))
332
+ );
333
+ }
334
+ for (const [absolutePath, relativePath] of Object.entries(staticFiles)) {
335
+ const portableRelativePath = toPortablePath(relativePath);
336
+ const projectRelativePath = toPortablePath(pathService.relative(projectFolder, absolutePath));
337
+ assetPaths.push(projectRelativePath);
338
+ assetOverrides[projectRelativePath] = { path: `_next/static/${portableRelativePath}` };
339
+ filePathMap[absolutePath] = toPortablePath(
340
+ pathService.relative(standaloneRoot, pathService.join(serverDirectory, manifest.distDir, "static", relativePath))
341
+ );
342
+ }
343
+ return {
344
+ ...defaults,
345
+ entrypoint,
346
+ routes: [{ source: "/*", destination: entrypoint }],
347
+ assetsDir: manifest.distDir,
348
+ assetsPrefixToStrip: "",
349
+ assetPaths,
350
+ assetOverrides,
351
+ package: {
352
+ trace: false,
353
+ rootOverwrite: standaloneRoot,
354
+ filePathMap
355
+ }
356
+ };
357
+ });
223
358
  var nextjs = {
224
359
  slug: "nextjs",
225
360
  name: "Next.js",
@@ -237,6 +372,13 @@ var nextjs = {
237
372
  populateAssetCache: true,
238
373
  routes: [{ source: "/*", destination: ".next/standalone/server.js" }],
239
374
  environmentVariables: { NODE_ENV: "production" }
375
+ }),
376
+ refineDefaultConfig: (defaults, projectFolder) => Effect4.gen(function* () {
377
+ const fs = yield* FileSystem4.FileSystem;
378
+ const manifestContent = yield* fs.readFileString(`${projectFolder}/.gigadrive/nextjs.json`).pipe(Effect4.catchAll(() => Effect4.succeed(void 0)));
379
+ const manifest = manifestContent ? parseBuildManifest(manifestContent) : void 0;
380
+ if (!manifest) return defaults;
381
+ return manifest.output === "export" ? yield* createStaticExportConfig(defaults, projectFolder) : yield* createStandaloneConfig(defaults, projectFolder, manifest);
240
382
  })
241
383
  };
242
384
 
@@ -370,7 +512,7 @@ var FRAMEWORK_DEFINITIONS = [
370
512
  ].sort((a, b) => b.priority - a.priority);
371
513
 
372
514
  // src/detection/generate-config.ts
373
- import { Effect as Effect3 } from "effect";
515
+ import { Effect as Effect5 } from "effect";
374
516
 
375
517
  // src/regions.ts
376
518
  var REGION_DEFINITIONS = [
@@ -410,11 +552,11 @@ var getInstallCommand = (pm) => {
410
552
  return "npm install";
411
553
  }
412
554
  };
413
- var generateConfig = Effect3.fn("generateConfig")(function* (framework, packageManager, refinedDefaults) {
555
+ var generateConfig = Effect5.fn("generateConfig")(function* (framework, packageManager, refinedDefaults) {
414
556
  const defaults = refinedDefaults ?? framework.getDefaultConfig(packageManager);
415
557
  const installCmd = defaults.installCommand ?? getInstallCommand(packageManager);
416
558
  const commands = [installCmd, ...defaults.commands];
417
- yield* Effect3.logDebug(`Generating config for ${framework.name}`, {
559
+ yield* Effect5.logDebug(`Generating config for ${framework.name}`, {
418
560
  runtime: defaults.runtime,
419
561
  entrypoint: defaults.entrypoint,
420
562
  commands
@@ -447,10 +589,11 @@ var generateConfig = Effect3.fn("generateConfig")(function* (framework, packageM
447
589
  warnings: [`Auto-detected framework: ${framework.name}. Create a gigadrive.yaml to customize.`],
448
590
  errors: []
449
591
  };
450
- if (defaults.assetsDir) {
592
+ if (defaults.assetsDir || defaults.assetPaths) {
451
593
  config.assets = {
452
- paths: [],
453
- prefixToStrip: defaults.assetsDir + "/",
594
+ paths: defaults.assetPaths ? [...defaults.assetPaths] : [],
595
+ prefixToStrip: defaults.assetsPrefixToStrip ?? (defaults.assetsDir ? defaults.assetsDir + "/" : ""),
596
+ overrides: defaults.assetOverrides ? { ...defaults.assetOverrides } : void 0,
454
597
  dynamicRoutes: true,
455
598
  populateCache: defaults.populateAssetCache ?? false
456
599
  };
@@ -459,8 +602,8 @@ var generateConfig = Effect3.fn("generateConfig")(function* (framework, packageM
459
602
  });
460
603
 
461
604
  // src/detection/read-dependencies.ts
462
- import { FileSystem as FileSystem3, Path as Path2 } from "@effect/platform";
463
- import { Effect as Effect5 } from "effect";
605
+ import { FileSystem as FileSystem5, Path as Path4 } from "@effect/platform";
606
+ import { Effect as Effect7 } from "effect";
464
607
 
465
608
  // src/detection/types.ts
466
609
  import { Schema } from "effect";
@@ -493,25 +636,25 @@ var MANIFEST_CONFIG = {
493
636
  node: { file: "package.json", depKeys: ["dependencies", "devDependencies"] },
494
637
  php: { file: "composer.json", depKeys: ["require", "require-dev"] }
495
638
  };
496
- var readManifest = Effect5.fn("readManifest")(function* (filePath) {
497
- const fs = yield* FileSystem3.FileSystem;
498
- const exists = yield* fs.exists(filePath).pipe(Effect5.catchAll(() => Effect5.succeed(false)));
639
+ var readManifest = Effect7.fn("readManifest")(function* (filePath) {
640
+ const fs = yield* FileSystem5.FileSystem;
641
+ const exists = yield* fs.exists(filePath).pipe(Effect7.catchAll(() => Effect7.succeed(false)));
499
642
  if (!exists) {
500
- return yield* Effect5.fail(new ManifestNotFoundError({ message: "Manifest not found", filePath }));
643
+ return yield* Effect7.fail(new ManifestNotFoundError({ message: "Manifest not found", filePath }));
501
644
  }
502
- const content = yield* fs.readFileString(filePath).pipe(Effect5.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
503
- const parsed = yield* Effect5.try({
645
+ const content = yield* fs.readFileString(filePath).pipe(Effect7.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
646
+ const parsed = yield* Effect7.try({
504
647
  try: () => JSON.parse(content),
505
648
  catch: () => new ManifestParseError({ message: "Failed to parse manifest JSON", filePath })
506
649
  });
507
650
  return parsed;
508
651
  });
509
- var readDependencies = Effect5.fn("readDependencies")(function* (projectFolder, language) {
510
- const pathService = yield* Path2.Path;
652
+ var readDependencies = Effect7.fn("readDependencies")(function* (projectFolder, language) {
653
+ const pathService = yield* Path4.Path;
511
654
  const config = MANIFEST_CONFIG[language];
512
655
  const filePath = pathService.join(projectFolder, config.file);
513
656
  const manifest = yield* readManifest(filePath).pipe(
514
- Effect5.catchTag("ManifestNotFoundError", () => Effect5.succeed(null))
657
+ Effect7.catchTag("ManifestNotFoundError", () => Effect7.succeed(null))
515
658
  );
516
659
  if (!manifest) {
517
660
  return /* @__PURE__ */ new Set();
@@ -529,9 +672,9 @@ var readDependencies = Effect5.fn("readDependencies")(function* (projectFolder,
529
672
  });
530
673
 
531
674
  // src/detection/detect-framework.ts
532
- var matchesDetectionItem = Effect6.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
533
- const fs = yield* FileSystem4.FileSystem;
534
- const pathService = yield* Path3.Path;
675
+ var matchesDetectionItem = Effect8.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
676
+ const fs = yield* FileSystem6.FileSystem;
677
+ const pathService = yield* Path5.Path;
535
678
  if (item.matchPackage != null) {
536
679
  const deps = yield* cachedReadDeps(`${projectFolder}\0${framework.language}`);
537
680
  if (!deps.has(item.matchPackage)) {
@@ -540,12 +683,12 @@ var matchesDetectionItem = Effect6.fn("matchesDetectionItem")(function* (item, p
540
683
  }
541
684
  if (item.path != null) {
542
685
  const filePath = pathService.join(projectFolder, item.path);
543
- const exists = yield* fs.exists(filePath).pipe(Effect6.catchAll(() => Effect6.succeed(false)));
686
+ const exists = yield* fs.exists(filePath).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
544
687
  if (!exists) {
545
688
  return false;
546
689
  }
547
690
  if (item.matchContent != null) {
548
- const content = yield* fs.readFileString(filePath).pipe(Effect6.catchAll(() => Effect6.succeed("")));
691
+ const content = yield* fs.readFileString(filePath).pipe(Effect8.catchAll(() => Effect8.succeed("")));
549
692
  let regexMatch = false;
550
693
  try {
551
694
  regexMatch = new RegExp(item.matchContent).test(content);
@@ -558,7 +701,7 @@ var matchesDetectionItem = Effect6.fn("matchesDetectionItem")(function* (item, p
558
701
  }
559
702
  return true;
560
703
  });
561
- var matchesFramework = Effect6.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
704
+ var matchesFramework = Effect8.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
562
705
  for (const detector of framework.detectors) {
563
706
  const matches = yield* matchesDetectionItem(detector, projectFolder, framework, cachedReadDeps);
564
707
  if (!matches) {
@@ -567,9 +710,9 @@ var matchesFramework = Effect6.fn("matchesFramework")(function* (framework, proj
567
710
  }
568
711
  return true;
569
712
  });
570
- var detectFramework = Effect6.fn("detectFramework")(function* (projectFolder) {
571
- yield* Effect6.logDebug(`Detecting framework in ${projectFolder}`);
572
- const cachedReadDeps = yield* Effect6.cachedFunction((key) => {
713
+ var detectFramework = Effect8.fn("detectFramework")(function* (projectFolder) {
714
+ yield* Effect8.logDebug(`Detecting framework in ${projectFolder}`);
715
+ const cachedReadDeps = yield* Effect8.cachedFunction((key) => {
573
716
  const sepIndex = key.lastIndexOf("\0");
574
717
  const folder = key.slice(0, sepIndex);
575
718
  const language = key.slice(sepIndex + 1);
@@ -578,7 +721,7 @@ var detectFramework = Effect6.fn("detectFramework")(function* (projectFolder) {
578
721
  for (const framework of FRAMEWORK_DEFINITIONS) {
579
722
  const matches = yield* matchesFramework(framework, projectFolder, cachedReadDeps);
580
723
  if (matches) {
581
- yield* Effect6.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
724
+ yield* Effect8.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
582
725
  const detectedPackageManager = yield* detectPackageManager(projectFolder);
583
726
  const packageManager = framework.language === "php" ? "composer" : detectedPackageManager;
584
727
  const defaults = framework.getDefaultConfig(packageManager);
@@ -587,7 +730,7 @@ var detectFramework = Effect6.fn("detectFramework")(function* (projectFolder) {
587
730
  return { framework, packageManager, config };
588
731
  }
589
732
  }
590
- return yield* Effect6.fail(
733
+ return yield* Effect8.fail(
591
734
  new FrameworkNotDetectedError({
592
735
  message: `No framework detected in project directory`,
593
736
  directory: projectFolder
@@ -596,9 +739,9 @@ var detectFramework = Effect6.fn("detectFramework")(function* (projectFolder) {
596
739
  });
597
740
 
598
741
  // src/detection/merge-config.ts
599
- import { Effect as Effect7 } from "effect";
600
- var mergeWithFrameworkDefaults = Effect7.fn("mergeWithFrameworkDefaults")(function* (userConfig, frameworkConfig) {
601
- yield* Effect7.logDebug("Merging user config with framework defaults");
742
+ import { Effect as Effect9 } from "effect";
743
+ var mergeWithFrameworkDefaults = Effect9.fn("mergeWithFrameworkDefaults")(function* (userConfig, frameworkConfig) {
744
+ yield* Effect9.logDebug("Merging user config with framework defaults");
602
745
  const merged = {
603
746
  regions: userConfig.regions,
604
747
  commands: userConfig.commands.length > 0 ? userConfig.commands : frameworkConfig.commands,
@@ -668,12 +811,16 @@ var filterFunctionsFromAssets = (config) => {
668
811
  };
669
812
  };
670
813
 
814
+ // src/normalized-config.ts
815
+ var DEFAULT_FUNCTION_DURATION_SECONDS = 30;
816
+ var MAX_FUNCTION_DURATION_SECONDS = 28800;
817
+
671
818
  // src/parse-config.ts
672
- import { Effect as Effect13 } from "effect";
819
+ import { Effect as Effect14 } from "effect";
673
820
 
674
821
  // src/services/raw-config-reader.ts
675
- import { FileSystem as FileSystem5, Path as Path4 } from "@effect/platform";
676
- import { Effect as Effect8 } from "effect";
822
+ import { FileSystem as FileSystem7, Path as Path6 } from "@effect/platform";
823
+ import { Effect as Effect10 } from "effect";
677
824
  import { parse as parseYaml } from "yaml";
678
825
  var ALLOWED_CONFIG_NAMES = [
679
826
  "gigadrive.yaml",
@@ -682,34 +829,34 @@ var ALLOWED_CONFIG_NAMES = [
682
829
  "nebula.yml",
683
830
  "nebula.json"
684
831
  ];
685
- var RawConfigReader = class extends Effect8.Service()("RawConfigReader", {
686
- effect: Effect8.gen(function* () {
687
- const fs = yield* FileSystem5.FileSystem;
688
- const pathService = yield* Path4.Path;
689
- const findConfig = Effect8.fn("RawConfigReader.findConfig")(function* (projectFolder) {
832
+ var RawConfigReader = class extends Effect10.Service()("RawConfigReader", {
833
+ effect: Effect10.gen(function* () {
834
+ const fs = yield* FileSystem7.FileSystem;
835
+ const pathService = yield* Path6.Path;
836
+ const findConfig = Effect10.fn("RawConfigReader.findConfig")(function* (projectFolder) {
690
837
  for (const name of ALLOWED_CONFIG_NAMES) {
691
838
  const filePath = pathService.join(projectFolder, name);
692
- const exists = yield* fs.exists(filePath).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
839
+ const exists = yield* fs.exists(filePath).pipe(Effect10.catchAll(() => Effect10.succeed(false)));
693
840
  if (exists) {
694
841
  return filePath;
695
842
  }
696
843
  }
697
844
  return null;
698
845
  });
699
- const readRawConfig = Effect8.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
700
- const exists = yield* fs.exists(filePath).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
846
+ const readRawConfig = Effect10.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
847
+ const exists = yield* fs.exists(filePath).pipe(Effect10.catchAll(() => Effect10.succeed(false)));
701
848
  if (!exists) {
702
- return yield* Effect8.fail(
849
+ return yield* Effect10.fail(
703
850
  new ConfigFileNotFoundError({ message: `Config file not found at ${filePath}`, filePath })
704
851
  );
705
852
  }
706
853
  const fileContents = yield* fs.readFileString(filePath).pipe(
707
- Effect8.mapError(
854
+ Effect10.mapError(
708
855
  () => new ConfigFileParseError({ message: `Failed to read config file at ${filePath}`, filePath })
709
856
  )
710
857
  );
711
858
  if (fileContents.length === 0) {
712
- return yield* Effect8.fail(
859
+ return yield* Effect10.fail(
713
860
  new ConfigFileEmptyError({ message: `Config file is empty at ${filePath}`, filePath })
714
861
  );
715
862
  }
@@ -724,7 +871,7 @@ var RawConfigReader = class extends Effect8.Service()("RawConfigReader", {
724
871
  parsed = parseYaml(fileContents);
725
872
  }
726
873
  } catch (error) {
727
- return yield* Effect8.fail(
874
+ return yield* Effect10.fail(
728
875
  new ConfigFileParseError({
729
876
  message: `Failed to parse config file at ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`,
730
877
  filePath,
@@ -733,21 +880,21 @@ var RawConfigReader = class extends Effect8.Service()("RawConfigReader", {
733
880
  );
734
881
  }
735
882
  if (parsed == null) {
736
- return yield* Effect8.fail(
883
+ return yield* Effect10.fail(
737
884
  new ConfigFileParseError({ message: `Config file could not be parsed at ${filePath}`, filePath })
738
885
  );
739
886
  }
740
887
  if (!options?.disableVersionCheck && typeof parsed.version !== "number") {
741
- return yield* Effect8.fail(
888
+ return yield* Effect10.fail(
742
889
  new ConfigVersionError({ message: `Config file is missing version at ${filePath}`, filePath })
743
890
  );
744
891
  }
745
892
  return parsed;
746
893
  });
747
894
  const readConfigFile = (configFilePath) => readRawConfig(configFilePath, { disableVersionCheck: true }).pipe(
748
- Effect8.map((parsed) => parsed),
749
- Effect8.catchTag("ConfigFileNotFoundError", () => Effect8.succeed(null)),
750
- Effect8.withSpan("RawConfigReader.readConfigFile")
895
+ Effect10.map((parsed) => parsed),
896
+ Effect10.catchTag("ConfigFileNotFoundError", () => Effect10.succeed(null)),
897
+ Effect10.withSpan("RawConfigReader.readConfigFile")
751
898
  );
752
899
  return { findConfig, readRawConfig, readConfigFile };
753
900
  })
@@ -757,17 +904,17 @@ var RawConfigReader = class extends Effect8.Service()("RawConfigReader", {
757
904
  // src/services/schema-validator.ts
758
905
  import Ajv from "ajv";
759
906
  import addFormats from "ajv-formats";
760
- import { Effect as Effect9 } from "effect";
761
- var SchemaValidator = class extends Effect9.Service()("SchemaValidator", {
762
- effect: Effect9.gen(function* () {
907
+ import { Effect as Effect11 } from "effect";
908
+ var SchemaValidator = class extends Effect11.Service()("SchemaValidator", {
909
+ effect: Effect11.gen(function* () {
763
910
  const ajv = new Ajv();
764
911
  addFormats(ajv);
765
- const validate = Effect9.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
912
+ const validate = Effect11.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
766
913
  const compiledValidate = ajv.compile(schema);
767
914
  const valid = compiledValidate(config);
768
915
  if (!valid) {
769
916
  const errors = compiledValidate.errors?.map((e) => `${e.instancePath || "/"} ${e.message ?? ""}`.trim()) ?? [];
770
- return yield* Effect9.fail(
917
+ return yield* Effect11.fail(
771
918
  new ConfigSchemaValidationError({
772
919
  message: `Config file at ${filePath} is invalid: ${ajv.errorsText(compiledValidate.errors)}`,
773
920
  filePath,
@@ -782,16 +929,16 @@ var SchemaValidator = class extends Effect9.Service()("SchemaValidator", {
782
929
  };
783
930
 
784
931
  // src/services/v4-config-parser.ts
785
- import { FileSystem as FileSystem6, Path as Path5 } from "@effect/platform";
932
+ import { FileSystem as FileSystem8, Path as Path7 } from "@effect/platform";
786
933
  import { getFilesForPattern } from "@gigadrive/build-utils";
787
- import { Effect as Effect10 } from "effect";
934
+ import { Effect as Effect12 } from "effect";
788
935
  import { minimatch } from "minimatch";
789
936
  import safeRegex from "safe-regex2";
790
937
  var MAX_ASSET_DEPTH = 100;
791
938
  var DISALLOWED_ASSET_EXTENSIONS = [".htaccess", ".htpasswd"];
792
939
  var DEFAULT_FUNCTION_SETTINGS = {
793
940
  memory: 128,
794
- max_duration: 30,
941
+ max_duration: DEFAULT_FUNCTION_DURATION_SECONDS,
795
942
  schedule: void 0,
796
943
  symlinks: void 0,
797
944
  excludeFiles: void 0,
@@ -855,7 +1002,7 @@ var mapRoute = (route, entrypoints) => ({
855
1002
  negativeRequirements: route.missing,
856
1003
  status: route.statusCode
857
1004
  });
858
- var parseEntrypoints = Effect10.fn("parseEntrypoints")(function* (config, projectFolder) {
1005
+ var parseEntrypoints = Effect12.fn("parseEntrypoints")(function* (config, projectFolder) {
859
1006
  const entrypoints = [];
860
1007
  if (config.functions == null) return entrypoints;
861
1008
  for (const [fnPath, func] of Object.entries(config.functions)) {
@@ -865,7 +1012,7 @@ var parseEntrypoints = Effect10.fn("parseEntrypoints")(function* (config, projec
865
1012
  functionPath: fnPath
866
1013
  });
867
1014
  }
868
- const matchedFiles = yield* Effect10.tryPromise({
1015
+ const matchedFiles = yield* Effect12.tryPromise({
869
1016
  try: () => getFilesForPattern(fnPath, projectFolder, func.excludeFiles),
870
1017
  catch: (error) => new FunctionConfigError({
871
1018
  message: `Failed to resolve files for function pattern '${fnPath}': ${error instanceof Error ? error.message : String(error)}`,
@@ -888,7 +1035,7 @@ var parseEntrypoints = Effect10.fn("parseEntrypoints")(function* (config, projec
888
1035
  path: file,
889
1036
  runtime,
890
1037
  memory: settings.memory ?? 128,
891
- maxDuration: settings.max_duration ?? 30,
1038
+ maxDuration: settings.max_duration ?? DEFAULT_FUNCTION_DURATION_SECONDS,
892
1039
  schedule: func.schedule,
893
1040
  symlinks: func.symlinks,
894
1041
  streaming,
@@ -901,14 +1048,14 @@ var parseEntrypoints = Effect10.fn("parseEntrypoints")(function* (config, projec
901
1048
  }
902
1049
  return entrypoints;
903
1050
  });
904
- var collectAssets = Effect10.fn("collectAssets")(function* (config, projectFolder) {
1051
+ var collectAssets = Effect12.fn("collectAssets")(function* (config, projectFolder) {
905
1052
  if (config.assets == null) return [];
906
- const fs = yield* FileSystem6.FileSystem;
907
- const pathService = yield* Path5.Path;
1053
+ const fs = yield* FileSystem8.FileSystem;
1054
+ const pathService = yield* Path7.Path;
908
1055
  const assetsPath = pathService.join(projectFolder, config.assets);
909
- const assetsExist = yield* fs.exists(assetsPath).pipe(Effect10.catchAll(() => Effect10.succeed(false)));
1056
+ const assetsExist = yield* fs.exists(assetsPath).pipe(Effect12.catchAll(() => Effect12.succeed(false)));
910
1057
  if (!assetsExist) return [];
911
- const stat = yield* fs.stat(assetsPath).pipe(Effect10.catchAll(() => Effect10.succeed(null)));
1058
+ const stat = yield* fs.stat(assetsPath).pipe(Effect12.catchAll(() => Effect12.succeed(null)));
912
1059
  if (!stat || stat.type !== "Directory") return [];
913
1060
  const allFiles = yield* collectFilesRecursively(assetsPath);
914
1061
  const assets = [];
@@ -919,18 +1066,18 @@ var collectAssets = Effect10.fn("collectAssets")(function* (config, projectFolde
919
1066
  }
920
1067
  return assets;
921
1068
  });
922
- var collectFilesRecursively = Effect10.fn("collectFilesRecursively")(
1069
+ var collectFilesRecursively = Effect12.fn("collectFilesRecursively")(
923
1070
  function* (basePath, relativePath = "", depth = 0) {
924
1071
  if (depth > MAX_ASSET_DEPTH) return [];
925
- const fs = yield* FileSystem6.FileSystem;
926
- const pathSvc = yield* Path5.Path;
1072
+ const fs = yield* FileSystem8.FileSystem;
1073
+ const pathSvc = yield* Path7.Path;
927
1074
  const currentPath = relativePath ? pathSvc.join(basePath, relativePath) : basePath;
928
- const entries = yield* fs.readDirectory(currentPath).pipe(Effect10.catchAll(() => Effect10.succeed([])));
1075
+ const entries = yield* fs.readDirectory(currentPath).pipe(Effect12.catchAll(() => Effect12.succeed([])));
929
1076
  const result = [];
930
1077
  for (const name of entries) {
931
1078
  const fullPath = pathSvc.join(currentPath, name);
932
1079
  const entryRelative = relativePath ? pathSvc.join(relativePath, name) : name;
933
- const stat = yield* fs.stat(fullPath).pipe(Effect10.catchAll(() => Effect10.succeed(null)));
1080
+ const stat = yield* fs.stat(fullPath).pipe(Effect12.catchAll(() => Effect12.succeed(null)));
934
1081
  if (!stat) continue;
935
1082
  if (stat.type === "Directory") {
936
1083
  const nested = yield* collectFilesRecursively(basePath, entryRelative, depth + 1);
@@ -942,16 +1089,16 @@ var collectFilesRecursively = Effect10.fn("collectFilesRecursively")(
942
1089
  return result;
943
1090
  }
944
1091
  );
945
- var V4ConfigParser = class extends Effect10.Service()("V4ConfigParser", {
1092
+ var V4ConfigParser = class extends Effect12.Service()("V4ConfigParser", {
946
1093
  accessors: true,
947
- effect: Effect10.succeed({
1094
+ effect: Effect12.succeed({
948
1095
  /**
949
1096
  * Parses a ConfigV4 into a NormalizedConfig.
950
1097
  *
951
1098
  * @param config - The raw V4 config object
952
1099
  * @param projectFolder - Absolute path to the project root
953
1100
  */
954
- parse: Effect10.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
1101
+ parse: Effect12.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
955
1102
  const entrypoints = yield* parseEntrypoints(config, projectFolder);
956
1103
  const assets = yield* collectAssets(config, projectFolder);
957
1104
  return {
@@ -975,10 +1122,10 @@ var V4ConfigParser = class extends Effect10.Service()("V4ConfigParser", {
975
1122
  };
976
1123
 
977
1124
  // src/services/vercel-build-output-parser.ts
978
- import { Path as Path7 } from "@effect/platform";
1125
+ import { Path as Path8 } from "@effect/platform";
979
1126
  import { getFilesForPattern as getFilesForPattern2 } from "@gigadrive/build-utils";
980
1127
  import { deepMerge } from "@gigadrive/commons";
981
- import { Effect as Effect12 } from "effect";
1128
+ import { Effect as Effect13 } from "effect";
982
1129
 
983
1130
  // src/build-output-v3/determine-repo-root.ts
984
1131
  import path from "path";
@@ -1013,37 +1160,6 @@ var determineRepoRoot = (projectFolder, config) => {
1013
1160
  return projectFolder;
1014
1161
  };
1015
1162
 
1016
- // src/build-output-v3/get-default-path-map.ts
1017
- import { FileSystem as FileSystem7, Path as Path6 } from "@effect/platform";
1018
- import { Effect as Effect11 } from "effect";
1019
- var getDefaultPathMap = Effect11.fn("getDefaultPathMap")(function* (directory) {
1020
- const fs = yield* FileSystem7.FileSystem;
1021
- const pathService = yield* Path6.Path;
1022
- const result = {};
1023
- const exists = yield* fs.exists(directory).pipe(Effect11.catchAll(() => Effect11.succeed(false)));
1024
- if (!exists) {
1025
- return result;
1026
- }
1027
- const MAX_DEPTH = 100;
1028
- const processDirectory = (currentPath, basePath = "", depth = 0) => Effect11.gen(function* () {
1029
- if (depth > MAX_DEPTH) return;
1030
- const entries = yield* fs.readDirectory(currentPath).pipe(Effect11.catchAll(() => Effect11.succeed([])));
1031
- for (const name of entries) {
1032
- const fullPath = pathService.join(currentPath, name);
1033
- const relativePath = basePath ? pathService.join(basePath, name) : name;
1034
- const stat = yield* fs.stat(fullPath).pipe(Effect11.catchAll(() => Effect11.succeed(null)));
1035
- if (!stat) continue;
1036
- if (stat.type === "Directory") {
1037
- yield* processDirectory(fullPath, relativePath, depth + 1);
1038
- } else {
1039
- result[fullPath] = relativePath;
1040
- }
1041
- }
1042
- });
1043
- yield* processDirectory(directory);
1044
- return result;
1045
- });
1046
-
1047
1163
  // src/build-output-v3/get-monorepo-files.ts
1048
1164
  function getMonorepoFiles(directory, filePathMaps) {
1049
1165
  const result = [];
@@ -1105,11 +1221,11 @@ var translateVercelRuntime = (runtime) => {
1105
1221
  var CONFIG_PATH = ".vercel/output/config.json";
1106
1222
  var FUNCTIONS_FOLDER = ".vercel/output/functions";
1107
1223
  var FUNCTION_CONFIGS_PATTERN = `${FUNCTIONS_FOLDER}/**/*.func/.vc-config.json`;
1108
- var VercelBuildOutputParser = class extends Effect12.Service()("VercelBuildOutputParser", {
1109
- effect: Effect12.gen(function* () {
1224
+ var VercelBuildOutputParser = class extends Effect13.Service()("VercelBuildOutputParser", {
1225
+ effect: Effect13.gen(function* () {
1110
1226
  const rawConfigReader = yield* RawConfigReader;
1111
- const pathService = yield* Path7.Path;
1112
- const parse = Effect12.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
1227
+ const pathService = yield* Path8.Path;
1228
+ const parse = Effect13.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
1113
1229
  const config = yield* rawConfigReader.readConfigFile(pathService.join(projectFolder, CONFIG_PATH));
1114
1230
  if (!config || typeof config.version !== "number" || config.version < 3) {
1115
1231
  return parseResult;
@@ -1120,8 +1236,8 @@ var VercelBuildOutputParser = class extends Effect12.Service()("VercelBuildOutpu
1120
1236
  merged.regions = [...new Set(merged.regions)];
1121
1237
  return merged;
1122
1238
  });
1123
- const loadFunctions = Effect12.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
1124
- const functionConfigs = yield* Effect12.tryPromise({
1239
+ const loadFunctions = Effect13.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
1240
+ const functionConfigs = yield* Effect13.tryPromise({
1125
1241
  try: () => getFilesForPattern2(FUNCTION_CONFIGS_PATTERN, projectFolder),
1126
1242
  catch: (error) => new ConfigFileParseError({
1127
1243
  message: `Failed to scan for function configs: ${error instanceof Error ? error.message : String(error)}`,
@@ -1293,8 +1409,8 @@ var schema_default = {
1293
1409
  },
1294
1410
  max_duration: {
1295
1411
  type: "number",
1296
- description: "The max duration in seconds for the function after which it will be terminated. Defaults to 30.",
1297
- maximum: 900,
1412
+ description: "The maximum lifetime in seconds of one HTTP request, response stream, or WebSocket connection. Defaults to 30. The reusable execution environment is not terminated with the invocation.",
1413
+ maximum: 28800,
1298
1414
  minimum: 1
1299
1415
  },
1300
1416
  runtime: {
@@ -1577,7 +1693,7 @@ var schema_default = {
1577
1693
  };
1578
1694
 
1579
1695
  // src/parse-config.ts
1580
- var parseConfigRaw = Effect13.fn("parseConfigRaw")(function* (filePath, projectFolder) {
1696
+ var parseConfigRaw = Effect14.fn("parseConfigRaw")(function* (filePath, projectFolder) {
1581
1697
  const rawReader = yield* RawConfigReader;
1582
1698
  const validator = yield* SchemaValidator;
1583
1699
  const v4Parser = yield* V4ConfigParser;
@@ -1588,7 +1704,7 @@ var parseConfigRaw = Effect13.fn("parseConfigRaw")(function* (filePath, projectF
1588
1704
  };
1589
1705
  const schema = schemaMap[version];
1590
1706
  if (!schema) {
1591
- return yield* Effect13.fail(
1707
+ return yield* Effect14.fail(
1592
1708
  new ConfigVersionError({
1593
1709
  message: `Config file at ${filePath} has an unsupported version: ${version}`,
1594
1710
  filePath,
@@ -1599,11 +1715,11 @@ var parseConfigRaw = Effect13.fn("parseConfigRaw")(function* (filePath, projectF
1599
1715
  yield* validator.validate(parsed, schema, filePath);
1600
1716
  return yield* v4Parser.parse(parsed, projectFolder);
1601
1717
  });
1602
- var parseConfig = Effect13.fn("parseConfig")(function* (filePath, projectFolder) {
1718
+ var parseConfig = Effect14.fn("parseConfig")(function* (filePath, projectFolder) {
1603
1719
  const parseResult = yield* parseConfigRaw(filePath, projectFolder);
1604
1720
  return yield* postProcessConfig(parseResult, projectFolder);
1605
1721
  });
1606
- var postProcessConfig = Effect13.fn("postProcessConfig")(function* (config, projectFolder) {
1722
+ var postProcessConfig = Effect14.fn("postProcessConfig")(function* (config, projectFolder) {
1607
1723
  const vercelParser = yield* VercelBuildOutputParser;
1608
1724
  let result = yield* vercelParser.parse(config, projectFolder);
1609
1725
  if (result.entrypoints.length === 0 && (result.assets?.paths?.length || 0) === 0 && result.routes.length === 0) {
@@ -1643,9 +1759,11 @@ export {
1643
1759
  ConfigFileParseError,
1644
1760
  ConfigSchemaValidationError,
1645
1761
  ConfigVersionError,
1762
+ DEFAULT_FUNCTION_DURATION_SECONDS,
1646
1763
  FRAMEWORK_DEFINITIONS,
1647
1764
  FrameworkNotDetectedError,
1648
1765
  FunctionConfigError,
1766
+ MAX_FUNCTION_DURATION_SECONDS,
1649
1767
  ManifestNotFoundError,
1650
1768
  ManifestParseError,
1651
1769
  ManifestReadError,