@gigadrive/network-config 2.1.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +434 -12
- package/dist/index.d.ts +434 -12
- package/dist/index.js +45029 -13602
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1098 -374
- package/dist/index.mjs.map +1 -1
- package/dist/v4/schema.json +1 -1
- package/package.json +13 -8
- package/src/v4/schema.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,28 +1,908 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
// src/detection/detect-framework.ts
|
|
2
|
+
import { FileSystem as FileSystem3, Path as Path3 } from "@effect/platform";
|
|
3
|
+
import { Effect as Effect4 } from "effect";
|
|
4
|
+
|
|
5
|
+
// src/detection/detect-package-manager.ts
|
|
6
|
+
import { FileSystem, Path } from "@effect/platform";
|
|
7
|
+
import { Effect } from "effect";
|
|
8
|
+
var LOCKFILE_MAP = [
|
|
9
|
+
{ files: ["bun.lockb", "bun.lock"], pm: "bun" },
|
|
10
|
+
{ files: ["pnpm-lock.yaml"], pm: "pnpm" },
|
|
11
|
+
{ files: ["yarn.lock"], pm: "yarn" },
|
|
12
|
+
{ files: ["package-lock.json"], pm: "npm" },
|
|
13
|
+
{ files: ["composer.lock"], pm: "composer" }
|
|
14
|
+
];
|
|
15
|
+
var detectPackageManager = Effect.fn("detectPackageManager")(function* (projectFolder) {
|
|
16
|
+
const fs = yield* FileSystem.FileSystem;
|
|
17
|
+
const pathService = yield* Path.Path;
|
|
18
|
+
for (const { files, pm } of LOCKFILE_MAP) {
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
const exists = yield* fs.exists(pathService.join(projectFolder, file)).pipe(Effect.catchAll(() => Effect.succeed(false)));
|
|
21
|
+
if (exists) {
|
|
22
|
+
yield* Effect.logDebug(`Detected package manager: ${pm} (via ${file})`);
|
|
23
|
+
return pm;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
yield* Effect.logDebug("No lockfile found, defaulting to npm");
|
|
28
|
+
return "npm";
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// src/detection/frameworks/astro.ts
|
|
32
|
+
var astro = {
|
|
33
|
+
slug: "astro",
|
|
34
|
+
name: "Astro",
|
|
35
|
+
language: "node",
|
|
36
|
+
detectors: [{ matchPackage: "astro" }],
|
|
37
|
+
priority: 85,
|
|
38
|
+
getDefaultConfig: () => ({
|
|
39
|
+
runtime: "node-22",
|
|
40
|
+
memory: 256,
|
|
41
|
+
maxDuration: 30,
|
|
42
|
+
streaming: true,
|
|
43
|
+
commands: ["astro build"],
|
|
44
|
+
entrypoint: "dist/server/entry.mjs",
|
|
45
|
+
assetsDir: "dist/client",
|
|
46
|
+
populateAssetCache: true,
|
|
47
|
+
routes: [{ source: "/*", destination: "dist/server/entry.mjs" }],
|
|
48
|
+
environmentVariables: { NODE_ENV: "production" }
|
|
49
|
+
})
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// src/detection/frameworks/elysia.ts
|
|
53
|
+
var elysia = {
|
|
54
|
+
slug: "elysia",
|
|
55
|
+
name: "Elysia",
|
|
56
|
+
language: "node",
|
|
57
|
+
detectors: [{ matchPackage: "elysia" }],
|
|
58
|
+
priority: 45,
|
|
59
|
+
getDefaultConfig: () => ({
|
|
60
|
+
runtime: "bun-1",
|
|
61
|
+
memory: 128,
|
|
62
|
+
maxDuration: 30,
|
|
63
|
+
streaming: true,
|
|
64
|
+
commands: [],
|
|
65
|
+
entrypoint: "src/index.ts",
|
|
66
|
+
routes: [{ source: "/*", destination: "src/index.ts" }],
|
|
67
|
+
environmentVariables: { NODE_ENV: "production" }
|
|
68
|
+
})
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/detection/frameworks/express.ts
|
|
72
|
+
var express = {
|
|
73
|
+
slug: "express",
|
|
74
|
+
name: "Express",
|
|
75
|
+
language: "node",
|
|
76
|
+
detectors: [{ matchPackage: "express" }],
|
|
77
|
+
priority: 10,
|
|
78
|
+
getDefaultConfig: () => ({
|
|
79
|
+
runtime: "node-22",
|
|
80
|
+
memory: 128,
|
|
81
|
+
maxDuration: 30,
|
|
82
|
+
streaming: true,
|
|
83
|
+
commands: [],
|
|
84
|
+
entrypoint: "index.js",
|
|
85
|
+
routes: [{ source: "/*", destination: "index.js" }],
|
|
86
|
+
environmentVariables: { NODE_ENV: "production" }
|
|
87
|
+
})
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// src/detection/frameworks/fastify.ts
|
|
91
|
+
var fastify = {
|
|
92
|
+
slug: "fastify",
|
|
93
|
+
name: "Fastify",
|
|
94
|
+
language: "node",
|
|
95
|
+
detectors: [{ matchPackage: "fastify" }],
|
|
96
|
+
priority: 40,
|
|
97
|
+
getDefaultConfig: () => ({
|
|
98
|
+
runtime: "node-22",
|
|
99
|
+
memory: 128,
|
|
100
|
+
maxDuration: 30,
|
|
101
|
+
streaming: true,
|
|
102
|
+
commands: [],
|
|
103
|
+
entrypoint: "src/index.ts",
|
|
104
|
+
routes: [{ source: "/*", destination: "src/index.ts" }],
|
|
105
|
+
environmentVariables: { NODE_ENV: "production" }
|
|
106
|
+
})
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// src/detection/frameworks/hono.ts
|
|
110
|
+
var hono = {
|
|
111
|
+
slug: "hono",
|
|
112
|
+
name: "Hono",
|
|
113
|
+
language: "node",
|
|
114
|
+
detectors: [{ matchPackage: "hono" }],
|
|
115
|
+
priority: 50,
|
|
116
|
+
getDefaultConfig: () => ({
|
|
117
|
+
runtime: "node-22",
|
|
118
|
+
memory: 128,
|
|
119
|
+
maxDuration: 30,
|
|
120
|
+
streaming: true,
|
|
121
|
+
commands: [],
|
|
122
|
+
entrypoint: "src/index.ts",
|
|
123
|
+
routes: [{ source: "/*", destination: "src/index.ts" }],
|
|
124
|
+
environmentVariables: { NODE_ENV: "production" }
|
|
125
|
+
})
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// src/detection/frameworks/laravel.ts
|
|
129
|
+
var laravel = {
|
|
130
|
+
slug: "laravel",
|
|
131
|
+
name: "Laravel",
|
|
132
|
+
language: "php",
|
|
133
|
+
detectors: [{ matchPackage: "laravel/framework" }, { path: "artisan" }],
|
|
134
|
+
priority: 80,
|
|
135
|
+
getDefaultConfig: () => ({
|
|
136
|
+
runtime: "php-84",
|
|
137
|
+
memory: 256,
|
|
138
|
+
maxDuration: 30,
|
|
139
|
+
streaming: false,
|
|
140
|
+
commands: ["composer require bref/laravel-bridge --update-with-dependencies", "bun install", "bun run build"],
|
|
141
|
+
entrypoint: "public/index.php",
|
|
142
|
+
assetsDir: "public",
|
|
143
|
+
populateAssetCache: true,
|
|
144
|
+
excludeFiles: ["tests/", "storage/", ".ddev", "node_modules/"],
|
|
145
|
+
routes: [{ source: "/*", destination: "public/index.php" }],
|
|
146
|
+
environmentVariables: {
|
|
147
|
+
APP_NAME: "Laravel",
|
|
148
|
+
APP_ENV: "production",
|
|
149
|
+
APP_DEBUG: "false",
|
|
150
|
+
LOG_CHANNEL: "stderr",
|
|
151
|
+
LOG_DEPRECATIONS_CHANNEL: "stderr",
|
|
152
|
+
LOG_LEVEL: "debug",
|
|
153
|
+
BROADCAST_DRIVER: "log",
|
|
154
|
+
SESSION_DRIVER: "cookie"
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// src/detection/frameworks/nestjs.ts
|
|
160
|
+
var nestjs = {
|
|
161
|
+
slug: "nestjs",
|
|
162
|
+
name: "NestJS",
|
|
163
|
+
language: "node",
|
|
164
|
+
detectors: [{ matchPackage: "@nestjs/core" }],
|
|
165
|
+
priority: 90,
|
|
166
|
+
getDefaultConfig: () => ({
|
|
167
|
+
runtime: "node-22",
|
|
168
|
+
memory: 256,
|
|
169
|
+
maxDuration: 30,
|
|
170
|
+
streaming: true,
|
|
171
|
+
commands: ["nest build"],
|
|
172
|
+
entrypoint: "dist/main.js",
|
|
173
|
+
routes: [{ source: "/*", destination: "dist/main.js" }],
|
|
174
|
+
environmentVariables: { NODE_ENV: "production" }
|
|
175
|
+
})
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// src/detection/frameworks/nextjs.ts
|
|
179
|
+
var nextjs = {
|
|
180
|
+
slug: "nextjs",
|
|
181
|
+
name: "Next.js",
|
|
182
|
+
language: "node",
|
|
183
|
+
detectors: [{ matchPackage: "next" }],
|
|
184
|
+
priority: 100,
|
|
185
|
+
getDefaultConfig: () => ({
|
|
186
|
+
runtime: "node-22",
|
|
187
|
+
memory: 256,
|
|
188
|
+
maxDuration: 30,
|
|
189
|
+
streaming: true,
|
|
190
|
+
commands: ["next build"],
|
|
191
|
+
entrypoint: ".next/standalone/server.js",
|
|
192
|
+
assetsDir: ".next/static",
|
|
193
|
+
populateAssetCache: true,
|
|
194
|
+
routes: [{ source: "/*", destination: ".next/standalone/server.js" }],
|
|
195
|
+
environmentVariables: { NODE_ENV: "production" }
|
|
196
|
+
})
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// src/detection/frameworks/nuxt.ts
|
|
200
|
+
var nuxt = {
|
|
201
|
+
slug: "nuxt",
|
|
202
|
+
name: "Nuxt",
|
|
203
|
+
language: "node",
|
|
204
|
+
detectors: [{ matchPackage: "nuxt" }],
|
|
205
|
+
priority: 95,
|
|
206
|
+
getDefaultConfig: () => ({
|
|
207
|
+
runtime: "node-22",
|
|
208
|
+
memory: 256,
|
|
209
|
+
maxDuration: 30,
|
|
210
|
+
streaming: true,
|
|
211
|
+
commands: ["nuxt build"],
|
|
212
|
+
entrypoint: ".output/server/index.mjs",
|
|
213
|
+
assetsDir: ".output/public",
|
|
214
|
+
populateAssetCache: true,
|
|
215
|
+
routes: [{ source: "/*", destination: ".output/server/index.mjs" }],
|
|
216
|
+
environmentVariables: { NODE_ENV: "production", NITRO_PRESET: "node-server" }
|
|
217
|
+
})
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// src/detection/frameworks/remix.ts
|
|
221
|
+
var remix = {
|
|
222
|
+
slug: "remix",
|
|
223
|
+
name: "Remix",
|
|
224
|
+
language: "node",
|
|
225
|
+
detectors: [{ matchPackage: "@remix-run/dev" }],
|
|
226
|
+
priority: 90,
|
|
227
|
+
getDefaultConfig: () => ({
|
|
228
|
+
runtime: "node-22",
|
|
229
|
+
memory: 256,
|
|
230
|
+
maxDuration: 30,
|
|
231
|
+
streaming: true,
|
|
232
|
+
commands: ["remix build"],
|
|
233
|
+
entrypoint: "build/server/index.js",
|
|
234
|
+
assetsDir: "build/client",
|
|
235
|
+
populateAssetCache: true,
|
|
236
|
+
routes: [{ source: "/*", destination: "build/server/index.js" }],
|
|
237
|
+
environmentVariables: { NODE_ENV: "production" }
|
|
238
|
+
})
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// src/detection/frameworks/sveltekit.ts
|
|
242
|
+
var sveltekit = {
|
|
243
|
+
slug: "sveltekit",
|
|
244
|
+
name: "SvelteKit",
|
|
245
|
+
language: "node",
|
|
246
|
+
detectors: [{ matchPackage: "@sveltejs/kit" }],
|
|
247
|
+
priority: 90,
|
|
248
|
+
getDefaultConfig: () => ({
|
|
249
|
+
runtime: "node-22",
|
|
250
|
+
memory: 256,
|
|
251
|
+
maxDuration: 30,
|
|
252
|
+
streaming: true,
|
|
253
|
+
commands: ["vite build"],
|
|
254
|
+
entrypoint: "build/index.js",
|
|
255
|
+
assetsDir: "build/client",
|
|
256
|
+
populateAssetCache: true,
|
|
257
|
+
routes: [{ source: "/*", destination: "build/index.js" }],
|
|
258
|
+
environmentVariables: { NODE_ENV: "production" }
|
|
259
|
+
})
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// src/detection/frameworks/symfony.ts
|
|
263
|
+
var symfony = {
|
|
264
|
+
slug: "symfony",
|
|
265
|
+
name: "Symfony",
|
|
266
|
+
language: "php",
|
|
267
|
+
detectors: [{ matchPackage: "symfony/framework-bundle" }, { path: "bin/console" }],
|
|
268
|
+
priority: 80,
|
|
269
|
+
getDefaultConfig: () => ({
|
|
270
|
+
runtime: "php-84",
|
|
271
|
+
memory: 512,
|
|
272
|
+
maxDuration: 30,
|
|
273
|
+
streaming: false,
|
|
274
|
+
installCommand: "composer install --prefer-dist --optimize-autoloader --no-dev",
|
|
275
|
+
commands: ["bun install", "bun run build"],
|
|
276
|
+
entrypoint: "public/index.php",
|
|
277
|
+
assetsDir: "public",
|
|
278
|
+
populateAssetCache: true,
|
|
279
|
+
excludeFiles: ["tests/*", ".ddev", "var"],
|
|
280
|
+
symlinks: { var: "/tmp" },
|
|
281
|
+
routes: [{ source: "/*", destination: "public/index.php" }],
|
|
282
|
+
environmentVariables: {
|
|
283
|
+
APP_ENV: "prod",
|
|
284
|
+
APP_DEBUG: "false",
|
|
285
|
+
APP_SECRET: "please_change_this_value_in_your_settings",
|
|
286
|
+
MESSENGER_TRANSPORT_DSN: "doctrine://default?auto_setup=0"
|
|
287
|
+
}
|
|
288
|
+
})
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
// src/detection/frameworks/vite.ts
|
|
292
|
+
var vite = {
|
|
293
|
+
slug: "vite",
|
|
294
|
+
name: "Vite",
|
|
295
|
+
language: "node",
|
|
296
|
+
detectors: [{ matchPackage: "vite" }],
|
|
297
|
+
priority: 5,
|
|
298
|
+
getDefaultConfig: () => ({
|
|
299
|
+
runtime: "node-22",
|
|
300
|
+
memory: 128,
|
|
301
|
+
maxDuration: 30,
|
|
302
|
+
streaming: false,
|
|
303
|
+
commands: ["vite build"],
|
|
304
|
+
assetsDir: "dist",
|
|
305
|
+
populateAssetCache: true,
|
|
306
|
+
routes: [],
|
|
307
|
+
environmentVariables: { NODE_ENV: "production" }
|
|
308
|
+
})
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// src/detection/frameworks/index.ts
|
|
312
|
+
var FRAMEWORK_DEFINITIONS = [
|
|
313
|
+
nextjs,
|
|
314
|
+
nuxt,
|
|
315
|
+
nestjs,
|
|
316
|
+
remix,
|
|
317
|
+
sveltekit,
|
|
318
|
+
astro,
|
|
319
|
+
laravel,
|
|
320
|
+
symfony,
|
|
321
|
+
hono,
|
|
322
|
+
elysia,
|
|
323
|
+
fastify,
|
|
324
|
+
express,
|
|
325
|
+
vite
|
|
326
|
+
].sort((a, b) => b.priority - a.priority);
|
|
327
|
+
|
|
328
|
+
// src/detection/generate-config.ts
|
|
329
|
+
import { Effect as Effect2 } from "effect";
|
|
330
|
+
|
|
331
|
+
// src/regions.ts
|
|
332
|
+
var REGION_DEFINITIONS = [
|
|
333
|
+
"us-east-1",
|
|
334
|
+
"us-east-2",
|
|
335
|
+
"us-west-1",
|
|
336
|
+
"us-west-2",
|
|
337
|
+
"ap-south-1",
|
|
338
|
+
"ap-northeast-3",
|
|
339
|
+
"ap-northeast-2",
|
|
340
|
+
"ap-southeast-1",
|
|
341
|
+
"ap-southeast-2",
|
|
342
|
+
"ap-northeast-1",
|
|
343
|
+
"ca-central-1",
|
|
344
|
+
"eu-central-1",
|
|
345
|
+
"eu-west-1",
|
|
346
|
+
"eu-west-2",
|
|
347
|
+
"eu-west-3",
|
|
348
|
+
"eu-north-1",
|
|
349
|
+
"sa-east-1"
|
|
350
|
+
];
|
|
351
|
+
var AVAILABLE_REGIONS = [...REGION_DEFINITIONS];
|
|
352
|
+
|
|
353
|
+
// src/detection/generate-config.ts
|
|
354
|
+
var getInstallCommand = (pm) => {
|
|
355
|
+
switch (pm) {
|
|
356
|
+
case "bun":
|
|
357
|
+
return "bun install";
|
|
358
|
+
case "pnpm":
|
|
359
|
+
return "pnpm install";
|
|
360
|
+
case "yarn":
|
|
361
|
+
return "yarn install";
|
|
362
|
+
case "composer":
|
|
363
|
+
return "composer install";
|
|
364
|
+
case "npm":
|
|
365
|
+
default:
|
|
366
|
+
return "npm install";
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
var generateConfig = Effect2.fn("generateConfig")(function* (framework, packageManager) {
|
|
370
|
+
const defaults = framework.getDefaultConfig(packageManager);
|
|
371
|
+
const installCmd = defaults.installCommand ?? getInstallCommand(packageManager);
|
|
372
|
+
const commands = [installCmd, ...defaults.commands];
|
|
373
|
+
yield* Effect2.logDebug(`Generating config for ${framework.name}`, {
|
|
374
|
+
runtime: defaults.runtime,
|
|
375
|
+
entrypoint: defaults.entrypoint,
|
|
376
|
+
commands
|
|
377
|
+
});
|
|
378
|
+
const entrypoints = defaults.entrypoint ? [
|
|
379
|
+
{
|
|
380
|
+
path: defaults.entrypoint,
|
|
381
|
+
runtime: defaults.runtime,
|
|
382
|
+
memory: defaults.memory,
|
|
383
|
+
maxDuration: defaults.maxDuration,
|
|
384
|
+
streaming: defaults.streaming,
|
|
385
|
+
symlinks: defaults.symlinks
|
|
386
|
+
}
|
|
387
|
+
] : [];
|
|
388
|
+
const routes = defaults.entrypoint ? defaults.routes.map((route) => ({
|
|
389
|
+
path: route.source,
|
|
390
|
+
destination: route.destination,
|
|
391
|
+
handler: defaults.streaming ? "SERVERLESS_FUNCTION_STREAMING" : "SERVERLESS_FUNCTION",
|
|
392
|
+
methods: ["ANY"],
|
|
393
|
+
headers: {}
|
|
394
|
+
})) : [];
|
|
395
|
+
const config = {
|
|
396
|
+
regions: [...AVAILABLE_REGIONS],
|
|
397
|
+
environmentVariables: { ...defaults.environmentVariables },
|
|
398
|
+
commands,
|
|
399
|
+
entrypoints,
|
|
400
|
+
routes,
|
|
401
|
+
excludeFiles: defaults.excludeFiles && defaults.excludeFiles.length > 0 ? [...defaults.excludeFiles] : void 0,
|
|
402
|
+
warnings: [`Auto-detected framework: ${framework.name}. Create a gigadrive.yaml to customize.`],
|
|
403
|
+
errors: []
|
|
404
|
+
};
|
|
405
|
+
if (defaults.assetsDir) {
|
|
406
|
+
config.assets = {
|
|
407
|
+
paths: [],
|
|
408
|
+
prefixToStrip: defaults.assetsDir + "/",
|
|
409
|
+
dynamicRoutes: true,
|
|
410
|
+
populateCache: defaults.populateAssetCache ?? false
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
return config;
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
// src/detection/read-dependencies.ts
|
|
417
|
+
import { FileSystem as FileSystem2, Path as Path2 } from "@effect/platform";
|
|
418
|
+
import { Effect as Effect3 } from "effect";
|
|
419
|
+
|
|
420
|
+
// src/detection/types.ts
|
|
421
|
+
import { Schema } from "effect";
|
|
422
|
+
var ManifestNotFoundError = class extends Schema.TaggedError()("ManifestNotFoundError", {
|
|
423
|
+
message: Schema.String,
|
|
424
|
+
filePath: Schema.String
|
|
425
|
+
}) {
|
|
426
|
+
};
|
|
427
|
+
var ManifestReadError = class extends Schema.TaggedError()("ManifestReadError", {
|
|
428
|
+
message: Schema.String,
|
|
429
|
+
filePath: Schema.String
|
|
430
|
+
}) {
|
|
431
|
+
};
|
|
432
|
+
var ManifestParseError = class extends Schema.TaggedError()("ManifestParseError", {
|
|
433
|
+
message: Schema.String,
|
|
434
|
+
filePath: Schema.String
|
|
435
|
+
}) {
|
|
436
|
+
};
|
|
437
|
+
var FrameworkNotDetectedError = class extends Schema.TaggedError()(
|
|
438
|
+
"FrameworkNotDetectedError",
|
|
439
|
+
{
|
|
440
|
+
message: Schema.String,
|
|
441
|
+
directory: Schema.String
|
|
442
|
+
}
|
|
443
|
+
) {
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
// src/detection/read-dependencies.ts
|
|
447
|
+
var MANIFEST_CONFIG = {
|
|
448
|
+
node: { file: "package.json", depKeys: ["dependencies", "devDependencies"] },
|
|
449
|
+
php: { file: "composer.json", depKeys: ["require", "require-dev"] }
|
|
450
|
+
};
|
|
451
|
+
var readManifest = Effect3.fn("readManifest")(function* (filePath) {
|
|
452
|
+
const fs = yield* FileSystem2.FileSystem;
|
|
453
|
+
const exists = yield* fs.exists(filePath).pipe(Effect3.catchAll(() => Effect3.succeed(false)));
|
|
454
|
+
if (!exists) {
|
|
455
|
+
return yield* Effect3.fail(new ManifestNotFoundError({ message: "Manifest not found", filePath }));
|
|
456
|
+
}
|
|
457
|
+
const content = yield* fs.readFileString(filePath).pipe(Effect3.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
|
|
458
|
+
const parsed = yield* Effect3.try({
|
|
459
|
+
try: () => JSON.parse(content),
|
|
460
|
+
catch: () => new ManifestParseError({ message: "Failed to parse manifest JSON", filePath })
|
|
461
|
+
});
|
|
462
|
+
return parsed;
|
|
463
|
+
});
|
|
464
|
+
var readDependencies = Effect3.fn("readDependencies")(function* (projectFolder, language) {
|
|
465
|
+
const pathService = yield* Path2.Path;
|
|
466
|
+
const config = MANIFEST_CONFIG[language];
|
|
467
|
+
const filePath = pathService.join(projectFolder, config.file);
|
|
468
|
+
const manifest = yield* readManifest(filePath).pipe(
|
|
469
|
+
Effect3.catchTag("ManifestNotFoundError", () => Effect3.succeed(null))
|
|
470
|
+
);
|
|
471
|
+
if (!manifest) {
|
|
472
|
+
return /* @__PURE__ */ new Set();
|
|
473
|
+
}
|
|
474
|
+
const deps = /* @__PURE__ */ new Set();
|
|
475
|
+
for (const key of config.depKeys) {
|
|
476
|
+
const section = manifest[key];
|
|
477
|
+
if (section && typeof section === "object" && !Array.isArray(section)) {
|
|
478
|
+
for (const name of Object.keys(section)) {
|
|
479
|
+
deps.add(name);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return deps;
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
// src/detection/detect-framework.ts
|
|
487
|
+
var matchesDetectionItem = Effect4.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
|
|
488
|
+
const fs = yield* FileSystem3.FileSystem;
|
|
489
|
+
const pathService = yield* Path3.Path;
|
|
490
|
+
if (item.matchPackage != null) {
|
|
491
|
+
const deps = yield* cachedReadDeps(`${projectFolder}\0${framework.language}`);
|
|
492
|
+
if (!deps.has(item.matchPackage)) {
|
|
493
|
+
return false;
|
|
10
494
|
}
|
|
11
495
|
}
|
|
12
|
-
|
|
496
|
+
if (item.path != null) {
|
|
497
|
+
const filePath = pathService.join(projectFolder, item.path);
|
|
498
|
+
const exists = yield* fs.exists(filePath).pipe(Effect4.catchAll(() => Effect4.succeed(false)));
|
|
499
|
+
if (!exists) {
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
if (item.matchContent != null) {
|
|
503
|
+
const content = yield* fs.readFileString(filePath).pipe(Effect4.catchAll(() => Effect4.succeed("")));
|
|
504
|
+
let regexMatch = false;
|
|
505
|
+
try {
|
|
506
|
+
regexMatch = new RegExp(item.matchContent).test(content);
|
|
507
|
+
} catch {
|
|
508
|
+
}
|
|
509
|
+
if (!regexMatch) {
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return true;
|
|
515
|
+
});
|
|
516
|
+
var matchesFramework = Effect4.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
|
|
517
|
+
for (const detector of framework.detectors) {
|
|
518
|
+
const matches = yield* matchesDetectionItem(detector, projectFolder, framework, cachedReadDeps);
|
|
519
|
+
if (!matches) {
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return true;
|
|
524
|
+
});
|
|
525
|
+
var detectFramework = Effect4.fn("detectFramework")(function* (projectFolder) {
|
|
526
|
+
yield* Effect4.logDebug(`Detecting framework in ${projectFolder}`);
|
|
527
|
+
const cachedReadDeps = yield* Effect4.cachedFunction((key) => {
|
|
528
|
+
const sepIndex = key.lastIndexOf("\0");
|
|
529
|
+
const folder = key.slice(0, sepIndex);
|
|
530
|
+
const language = key.slice(sepIndex + 1);
|
|
531
|
+
return readDependencies(folder, language);
|
|
532
|
+
});
|
|
533
|
+
for (const framework of FRAMEWORK_DEFINITIONS) {
|
|
534
|
+
const matches = yield* matchesFramework(framework, projectFolder, cachedReadDeps);
|
|
535
|
+
if (matches) {
|
|
536
|
+
yield* Effect4.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
|
|
537
|
+
const packageManager = yield* detectPackageManager(projectFolder);
|
|
538
|
+
const config = yield* generateConfig(framework, packageManager);
|
|
539
|
+
return { framework, packageManager, config };
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return yield* Effect4.fail(
|
|
543
|
+
new FrameworkNotDetectedError({
|
|
544
|
+
message: `No framework detected in project directory`,
|
|
545
|
+
directory: projectFolder
|
|
546
|
+
})
|
|
547
|
+
);
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
// src/detection/merge-config.ts
|
|
551
|
+
import { Effect as Effect5 } from "effect";
|
|
552
|
+
var mergeWithFrameworkDefaults = Effect5.fn("mergeWithFrameworkDefaults")(function* (userConfig, frameworkConfig) {
|
|
553
|
+
yield* Effect5.logDebug("Merging user config with framework defaults");
|
|
554
|
+
const merged = {
|
|
555
|
+
regions: userConfig.regions,
|
|
556
|
+
commands: userConfig.commands.length > 0 ? userConfig.commands : frameworkConfig.commands,
|
|
557
|
+
entrypoints: userConfig.entrypoints.length > 0 ? userConfig.entrypoints : frameworkConfig.entrypoints,
|
|
558
|
+
routes: userConfig.routes.length > 0 ? userConfig.routes : frameworkConfig.routes,
|
|
559
|
+
assets: userConfig.assets?.paths && userConfig.assets.paths.length > 0 ? userConfig.assets : frameworkConfig.assets,
|
|
560
|
+
environmentVariables: {
|
|
561
|
+
...frameworkConfig.environmentVariables,
|
|
562
|
+
...userConfig.environmentVariables
|
|
563
|
+
},
|
|
564
|
+
excludeFiles: userConfig.excludeFiles && userConfig.excludeFiles.length > 0 ? userConfig.excludeFiles : frameworkConfig.excludeFiles,
|
|
565
|
+
services: userConfig.services,
|
|
566
|
+
userArchive: userConfig.userArchive,
|
|
567
|
+
warnings: [...frameworkConfig.warnings, ...userConfig.warnings],
|
|
568
|
+
errors: [...frameworkConfig.errors, ...userConfig.errors]
|
|
569
|
+
};
|
|
570
|
+
return merged;
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// src/errors.ts
|
|
574
|
+
import { Schema as Schema2 } from "effect";
|
|
575
|
+
var ConfigFileNotFoundError = class extends Schema2.TaggedError()("ConfigFileNotFoundError", {
|
|
576
|
+
message: Schema2.String,
|
|
577
|
+
filePath: Schema2.String
|
|
578
|
+
}) {
|
|
579
|
+
};
|
|
580
|
+
var ConfigFileEmptyError = class extends Schema2.TaggedError()("ConfigFileEmptyError", {
|
|
581
|
+
message: Schema2.String,
|
|
582
|
+
filePath: Schema2.String
|
|
583
|
+
}) {
|
|
584
|
+
};
|
|
585
|
+
var ConfigFileParseError = class extends Schema2.TaggedError()("ConfigFileParseError", {
|
|
586
|
+
message: Schema2.String,
|
|
587
|
+
filePath: Schema2.String,
|
|
588
|
+
cause: Schema2.optional(Schema2.String)
|
|
589
|
+
}) {
|
|
590
|
+
};
|
|
591
|
+
var ConfigVersionError = class extends Schema2.TaggedError()("ConfigVersionError", {
|
|
592
|
+
message: Schema2.String,
|
|
593
|
+
filePath: Schema2.String,
|
|
594
|
+
version: Schema2.optional(Schema2.Number)
|
|
595
|
+
}) {
|
|
596
|
+
};
|
|
597
|
+
var ConfigSchemaValidationError = class extends Schema2.TaggedError()(
|
|
598
|
+
"ConfigSchemaValidationError",
|
|
599
|
+
{
|
|
600
|
+
message: Schema2.String,
|
|
601
|
+
filePath: Schema2.String,
|
|
602
|
+
validationErrors: Schema2.Array(Schema2.String)
|
|
603
|
+
}
|
|
604
|
+
) {
|
|
605
|
+
};
|
|
606
|
+
var FunctionConfigError = class extends Schema2.TaggedError()("FunctionConfigError", {
|
|
607
|
+
message: Schema2.String,
|
|
608
|
+
functionPath: Schema2.String
|
|
609
|
+
}) {
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
// src/filter-functions-from-assets.ts
|
|
613
|
+
var filterFunctionsFromAssets = (config) => {
|
|
614
|
+
return {
|
|
615
|
+
...config,
|
|
616
|
+
assets: {
|
|
617
|
+
...config.assets,
|
|
618
|
+
paths: config.assets?.paths?.filter((path2) => !config.entrypoints.some((entrypoint) => entrypoint.path === path2))
|
|
619
|
+
}
|
|
620
|
+
};
|
|
13
621
|
};
|
|
14
622
|
|
|
15
623
|
// src/parse-config.ts
|
|
624
|
+
import { Effect as Effect11 } from "effect";
|
|
625
|
+
|
|
626
|
+
// src/services/raw-config-reader.ts
|
|
627
|
+
import { FileSystem as FileSystem4, Path as Path4 } from "@effect/platform";
|
|
628
|
+
import { Effect as Effect6 } from "effect";
|
|
629
|
+
import { parse as parseYaml } from "yaml";
|
|
630
|
+
var ALLOWED_CONFIG_NAMES = [
|
|
631
|
+
"gigadrive.yaml",
|
|
632
|
+
"gigadrive.yml",
|
|
633
|
+
"nebula.yaml",
|
|
634
|
+
"nebula.yml",
|
|
635
|
+
"nebula.json"
|
|
636
|
+
];
|
|
637
|
+
var RawConfigReader = class extends Effect6.Service()("RawConfigReader", {
|
|
638
|
+
effect: Effect6.gen(function* () {
|
|
639
|
+
const fs = yield* FileSystem4.FileSystem;
|
|
640
|
+
const pathService = yield* Path4.Path;
|
|
641
|
+
const findConfig = Effect6.fn("RawConfigReader.findConfig")(function* (projectFolder) {
|
|
642
|
+
for (const name of ALLOWED_CONFIG_NAMES) {
|
|
643
|
+
const filePath = pathService.join(projectFolder, name);
|
|
644
|
+
const exists = yield* fs.exists(filePath).pipe(Effect6.catchAll(() => Effect6.succeed(false)));
|
|
645
|
+
if (exists) {
|
|
646
|
+
return filePath;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return null;
|
|
650
|
+
});
|
|
651
|
+
const readRawConfig = Effect6.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
|
|
652
|
+
const exists = yield* fs.exists(filePath).pipe(Effect6.catchAll(() => Effect6.succeed(false)));
|
|
653
|
+
if (!exists) {
|
|
654
|
+
return yield* Effect6.fail(
|
|
655
|
+
new ConfigFileNotFoundError({ message: `Config file not found at ${filePath}`, filePath })
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
const fileContents = yield* fs.readFileString(filePath).pipe(
|
|
659
|
+
Effect6.mapError(
|
|
660
|
+
() => new ConfigFileParseError({ message: `Failed to read config file at ${filePath}`, filePath })
|
|
661
|
+
)
|
|
662
|
+
);
|
|
663
|
+
if (fileContents.length === 0) {
|
|
664
|
+
return yield* Effect6.fail(
|
|
665
|
+
new ConfigFileEmptyError({ message: `Config file is empty at ${filePath}`, filePath })
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
const fileExtension = pathService.extname(filePath).toLowerCase();
|
|
669
|
+
let parsed;
|
|
670
|
+
try {
|
|
671
|
+
if (fileExtension === ".json") {
|
|
672
|
+
parsed = JSON.parse(fileContents);
|
|
673
|
+
} else if ([".yml", ".yaml"].includes(fileExtension)) {
|
|
674
|
+
parsed = parseYaml(fileContents);
|
|
675
|
+
} else {
|
|
676
|
+
parsed = parseYaml(fileContents);
|
|
677
|
+
}
|
|
678
|
+
} catch (error) {
|
|
679
|
+
return yield* Effect6.fail(
|
|
680
|
+
new ConfigFileParseError({
|
|
681
|
+
message: `Failed to parse config file at ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
682
|
+
filePath,
|
|
683
|
+
cause: error instanceof Error ? error.message : void 0
|
|
684
|
+
})
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
if (parsed == null) {
|
|
688
|
+
return yield* Effect6.fail(
|
|
689
|
+
new ConfigFileParseError({ message: `Config file could not be parsed at ${filePath}`, filePath })
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
if (!options?.disableVersionCheck && typeof parsed.version !== "number") {
|
|
693
|
+
return yield* Effect6.fail(
|
|
694
|
+
new ConfigVersionError({ message: `Config file is missing version at ${filePath}`, filePath })
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
return parsed;
|
|
698
|
+
});
|
|
699
|
+
const readConfigFile = (configFilePath) => readRawConfig(configFilePath, { disableVersionCheck: true }).pipe(
|
|
700
|
+
Effect6.map((parsed) => parsed),
|
|
701
|
+
Effect6.catchTag("ConfigFileNotFoundError", () => Effect6.succeed(null)),
|
|
702
|
+
Effect6.withSpan("RawConfigReader.readConfigFile")
|
|
703
|
+
);
|
|
704
|
+
return { findConfig, readRawConfig, readConfigFile };
|
|
705
|
+
})
|
|
706
|
+
}) {
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
// src/services/schema-validator.ts
|
|
16
710
|
import Ajv from "ajv";
|
|
17
711
|
import addFormats from "ajv-formats";
|
|
712
|
+
import { Effect as Effect7 } from "effect";
|
|
713
|
+
var SchemaValidator = class extends Effect7.Service()("SchemaValidator", {
|
|
714
|
+
effect: Effect7.gen(function* () {
|
|
715
|
+
const ajv = new Ajv();
|
|
716
|
+
addFormats(ajv);
|
|
717
|
+
const validate = Effect7.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
|
|
718
|
+
const compiledValidate = ajv.compile(schema);
|
|
719
|
+
const valid = compiledValidate(config);
|
|
720
|
+
if (!valid) {
|
|
721
|
+
const errors = compiledValidate.errors?.map((e) => `${e.instancePath || "/"} ${e.message ?? ""}`.trim()) ?? [];
|
|
722
|
+
return yield* Effect7.fail(
|
|
723
|
+
new ConfigSchemaValidationError({
|
|
724
|
+
message: `Config file at ${filePath} is invalid: ${ajv.errorsText(compiledValidate.errors)}`,
|
|
725
|
+
filePath,
|
|
726
|
+
validationErrors: errors
|
|
727
|
+
})
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
return { validate };
|
|
732
|
+
})
|
|
733
|
+
}) {
|
|
734
|
+
};
|
|
18
735
|
|
|
19
|
-
// src/
|
|
736
|
+
// src/services/v4-config-parser.ts
|
|
737
|
+
import { FileSystem as FileSystem5, Path as Path5 } from "@effect/platform";
|
|
20
738
|
import { getFilesForPattern } from "@gigadrive/build-utils";
|
|
739
|
+
import { Effect as Effect8 } from "effect";
|
|
740
|
+
import { minimatch } from "minimatch";
|
|
741
|
+
import safeRegex from "safe-regex2";
|
|
742
|
+
var MAX_ASSET_DEPTH = 100;
|
|
743
|
+
var DISALLOWED_ASSET_EXTENSIONS = [".htaccess", ".htpasswd"];
|
|
744
|
+
var DEFAULT_FUNCTION_SETTINGS = {
|
|
745
|
+
memory: 128,
|
|
746
|
+
max_duration: 30,
|
|
747
|
+
schedule: void 0,
|
|
748
|
+
symlinks: void 0,
|
|
749
|
+
excludeFiles: void 0,
|
|
750
|
+
includeFiles: void 0
|
|
751
|
+
};
|
|
752
|
+
var matchesPattern = (path2, pattern) => {
|
|
753
|
+
if (minimatch(path2, pattern)) return true;
|
|
754
|
+
try {
|
|
755
|
+
if (safeRegex(pattern)) {
|
|
756
|
+
return new RegExp(pattern).test(path2);
|
|
757
|
+
}
|
|
758
|
+
} catch {
|
|
759
|
+
}
|
|
760
|
+
return false;
|
|
761
|
+
};
|
|
762
|
+
var getFunctionSettings = (path2, config) => {
|
|
763
|
+
let settings;
|
|
764
|
+
for (const [pattern, value] of Object.entries(config.functions ?? {})) {
|
|
765
|
+
if (!matchesPattern(path2, pattern)) continue;
|
|
766
|
+
settings = { ...DEFAULT_FUNCTION_SETTINGS, ...settings, ...value };
|
|
767
|
+
}
|
|
768
|
+
return settings;
|
|
769
|
+
};
|
|
770
|
+
var resolveRouteHandler = (destination, redirect) => {
|
|
771
|
+
const isExternal = destination.toLowerCase().startsWith("http://") || destination.toLowerCase().startsWith("https://");
|
|
772
|
+
if (redirect === true) return "HTTP_REDIRECT";
|
|
773
|
+
return isExternal ? "HTTP_PROXY" : "SERVERLESS_FUNCTION";
|
|
774
|
+
};
|
|
775
|
+
var isRegion = (r) => AVAILABLE_REGIONS.includes(r);
|
|
776
|
+
var resolveRegions = (configRegions) => {
|
|
777
|
+
if (configRegions?.includes("global") === true) return AVAILABLE_REGIONS;
|
|
778
|
+
const valid = configRegions?.filter(isRegion);
|
|
779
|
+
return valid && valid.length > 0 ? valid : AVAILABLE_REGIONS;
|
|
780
|
+
};
|
|
781
|
+
var mapRoute = (route) => ({
|
|
782
|
+
path: route.source,
|
|
783
|
+
destination: route.destination,
|
|
784
|
+
handler: resolveRouteHandler(route.destination, route.redirect),
|
|
785
|
+
headers: route.headers ?? {},
|
|
786
|
+
methods: route.methods ?? ["ANY"],
|
|
787
|
+
positiveRequirements: route.has,
|
|
788
|
+
negativeRequirements: route.missing,
|
|
789
|
+
status: route.statusCode
|
|
790
|
+
});
|
|
791
|
+
var parseEntrypoints = Effect8.fn("parseEntrypoints")(function* (config, projectFolder) {
|
|
792
|
+
const entrypoints = [];
|
|
793
|
+
if (config.functions == null) return entrypoints;
|
|
794
|
+
for (const [fnPath, func] of Object.entries(config.functions)) {
|
|
795
|
+
const settings = getFunctionSettings(fnPath, config);
|
|
796
|
+
if (settings == null) {
|
|
797
|
+
yield* new FunctionConfigError({
|
|
798
|
+
message: `Settings invalid for function at path '${fnPath}'`,
|
|
799
|
+
functionPath: fnPath
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
const matchedFiles = yield* Effect8.tryPromise({
|
|
803
|
+
try: () => getFilesForPattern(fnPath, projectFolder, func.excludeFiles),
|
|
804
|
+
catch: (error) => new FunctionConfigError({
|
|
805
|
+
message: `Failed to resolve files for function pattern '${fnPath}': ${error instanceof Error ? error.message : String(error)}`,
|
|
806
|
+
functionPath: fnPath
|
|
807
|
+
})
|
|
808
|
+
});
|
|
809
|
+
for (const file of matchedFiles) {
|
|
810
|
+
if (entrypoints.some((ep) => ep.path === file)) continue;
|
|
811
|
+
if (Object.keys(config.functions).some((f) => f === file && f !== fnPath)) continue;
|
|
812
|
+
entrypoints.push({
|
|
813
|
+
path: file,
|
|
814
|
+
runtime: settings.runtime ?? "node-20",
|
|
815
|
+
memory: settings.memory ?? 128,
|
|
816
|
+
maxDuration: settings.max_duration ?? 30,
|
|
817
|
+
schedule: func.schedule,
|
|
818
|
+
symlinks: func.symlinks,
|
|
819
|
+
streaming: settings.runtime == null || settings.runtime.startsWith("node-") || settings.runtime.startsWith("bun-")
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return entrypoints;
|
|
824
|
+
});
|
|
825
|
+
var collectAssets = Effect8.fn("collectAssets")(function* (config, projectFolder) {
|
|
826
|
+
if (config.assets == null) return [];
|
|
827
|
+
const fs = yield* FileSystem5.FileSystem;
|
|
828
|
+
const pathService = yield* Path5.Path;
|
|
829
|
+
const assetsPath = pathService.join(projectFolder, config.assets);
|
|
830
|
+
const assetsExist = yield* fs.exists(assetsPath).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
|
|
831
|
+
if (!assetsExist) return [];
|
|
832
|
+
const stat = yield* fs.stat(assetsPath).pipe(Effect8.catchAll(() => Effect8.succeed(null)));
|
|
833
|
+
if (!stat || stat.type !== "Directory") return [];
|
|
834
|
+
const allFiles = yield* collectFilesRecursively(assetsPath);
|
|
835
|
+
const assets = [];
|
|
836
|
+
for (const assetName of allFiles) {
|
|
837
|
+
if (DISALLOWED_ASSET_EXTENSIONS.some((ext) => assetName.toLowerCase().endsWith(ext.toLowerCase()))) continue;
|
|
838
|
+
if (getFunctionSettings(`${config.assets}/${assetName}`, config) != null) continue;
|
|
839
|
+
assets.push(`${config.assets}/${assetName}`);
|
|
840
|
+
}
|
|
841
|
+
return assets;
|
|
842
|
+
});
|
|
843
|
+
var collectFilesRecursively = Effect8.fn("collectFilesRecursively")(
|
|
844
|
+
function* (basePath, relativePath = "", depth = 0) {
|
|
845
|
+
if (depth > MAX_ASSET_DEPTH) return [];
|
|
846
|
+
const fs = yield* FileSystem5.FileSystem;
|
|
847
|
+
const pathSvc = yield* Path5.Path;
|
|
848
|
+
const currentPath = relativePath ? pathSvc.join(basePath, relativePath) : basePath;
|
|
849
|
+
const entries = yield* fs.readDirectory(currentPath).pipe(Effect8.catchAll(() => Effect8.succeed([])));
|
|
850
|
+
const result = [];
|
|
851
|
+
for (const name of entries) {
|
|
852
|
+
const fullPath = pathSvc.join(currentPath, name);
|
|
853
|
+
const entryRelative = relativePath ? pathSvc.join(relativePath, name) : name;
|
|
854
|
+
const stat = yield* fs.stat(fullPath).pipe(Effect8.catchAll(() => Effect8.succeed(null)));
|
|
855
|
+
if (!stat) continue;
|
|
856
|
+
if (stat.type === "Directory") {
|
|
857
|
+
const nested = yield* collectFilesRecursively(basePath, entryRelative, depth + 1);
|
|
858
|
+
result.push(...nested);
|
|
859
|
+
} else {
|
|
860
|
+
result.push(entryRelative);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
return result;
|
|
864
|
+
}
|
|
865
|
+
);
|
|
866
|
+
var V4ConfigParser = class extends Effect8.Service()("V4ConfigParser", {
|
|
867
|
+
accessors: true,
|
|
868
|
+
effect: Effect8.succeed({
|
|
869
|
+
/**
|
|
870
|
+
* Parses a ConfigV4 into a NormalizedConfig.
|
|
871
|
+
*
|
|
872
|
+
* @param config - The raw V4 config object
|
|
873
|
+
* @param projectFolder - Absolute path to the project root
|
|
874
|
+
*/
|
|
875
|
+
parse: Effect8.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
|
|
876
|
+
const entrypoints = yield* parseEntrypoints(config, projectFolder);
|
|
877
|
+
const assets = yield* collectAssets(config, projectFolder);
|
|
878
|
+
return {
|
|
879
|
+
regions: resolveRegions(config.regions),
|
|
880
|
+
assets: {
|
|
881
|
+
paths: assets.sort(),
|
|
882
|
+
prefixToStrip: (config.assets ?? "") + "/",
|
|
883
|
+
dynamicRoutes: true,
|
|
884
|
+
populateCache: config.populateAssetCache ?? false
|
|
885
|
+
},
|
|
886
|
+
environmentVariables: config.env ?? {},
|
|
887
|
+
commands: config.build_commands ?? [],
|
|
888
|
+
entrypoints,
|
|
889
|
+
errors: [],
|
|
890
|
+
warnings: [],
|
|
891
|
+
routes: (config.routes ?? []).map(mapRoute)
|
|
892
|
+
};
|
|
893
|
+
})
|
|
894
|
+
})
|
|
895
|
+
}) {
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
// src/services/vercel-build-output-parser.ts
|
|
899
|
+
import { Path as Path7 } from "@effect/platform";
|
|
900
|
+
import { getFilesForPattern as getFilesForPattern2 } from "@gigadrive/build-utils";
|
|
21
901
|
import { deepMerge } from "@gigadrive/commons";
|
|
22
|
-
import
|
|
902
|
+
import { Effect as Effect10 } from "effect";
|
|
23
903
|
|
|
24
904
|
// src/build-output-v3/determine-repo-root.ts
|
|
25
|
-
import
|
|
905
|
+
import path from "path";
|
|
26
906
|
var determineRepoRoot = (projectFolder, config) => {
|
|
27
907
|
if (!config.entrypoints?.length) {
|
|
28
908
|
return projectFolder;
|
|
@@ -36,9 +916,9 @@ var determineRepoRoot = (projectFolder, config) => {
|
|
|
36
916
|
if (filePaths.length === 0) {
|
|
37
917
|
return projectFolder;
|
|
38
918
|
}
|
|
39
|
-
const pathParts = filePaths.map((p) => p.split(
|
|
919
|
+
const pathParts = filePaths.map((p) => p.split(path.sep));
|
|
40
920
|
const firstPath = pathParts[0];
|
|
41
|
-
|
|
921
|
+
const commonParts = [];
|
|
42
922
|
for (let i = 0; i < firstPath.length; i++) {
|
|
43
923
|
const part = firstPath[i];
|
|
44
924
|
if (pathParts.every((parts) => parts[i] === part)) {
|
|
@@ -47,7 +927,7 @@ var determineRepoRoot = (projectFolder, config) => {
|
|
|
47
927
|
break;
|
|
48
928
|
}
|
|
49
929
|
}
|
|
50
|
-
const commonRoot = commonParts.join(
|
|
930
|
+
const commonRoot = commonParts.join(path.sep);
|
|
51
931
|
if (commonRoot && projectFolder.startsWith(commonRoot) && commonRoot !== projectFolder) {
|
|
52
932
|
return commonRoot;
|
|
53
933
|
}
|
|
@@ -55,28 +935,35 @@ var determineRepoRoot = (projectFolder, config) => {
|
|
|
55
935
|
};
|
|
56
936
|
|
|
57
937
|
// src/build-output-v3/get-default-path-map.ts
|
|
58
|
-
import
|
|
59
|
-
import
|
|
60
|
-
var getDefaultPathMap = (directory)
|
|
938
|
+
import { FileSystem as FileSystem6, Path as Path6 } from "@effect/platform";
|
|
939
|
+
import { Effect as Effect9 } from "effect";
|
|
940
|
+
var getDefaultPathMap = Effect9.fn("getDefaultPathMap")(function* (directory) {
|
|
941
|
+
const fs = yield* FileSystem6.FileSystem;
|
|
942
|
+
const pathService = yield* Path6.Path;
|
|
61
943
|
const result = {};
|
|
62
|
-
|
|
944
|
+
const exists = yield* fs.exists(directory).pipe(Effect9.catchAll(() => Effect9.succeed(false)));
|
|
945
|
+
if (!exists) {
|
|
63
946
|
return result;
|
|
64
947
|
}
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
948
|
+
const MAX_DEPTH = 100;
|
|
949
|
+
const processDirectory = (currentPath, basePath = "", depth = 0) => Effect9.gen(function* () {
|
|
950
|
+
if (depth > MAX_DEPTH) return;
|
|
951
|
+
const entries = yield* fs.readDirectory(currentPath).pipe(Effect9.catchAll(() => Effect9.succeed([])));
|
|
952
|
+
for (const name of entries) {
|
|
953
|
+
const fullPath = pathService.join(currentPath, name);
|
|
954
|
+
const relativePath = basePath ? pathService.join(basePath, name) : name;
|
|
955
|
+
const stat = yield* fs.stat(fullPath).pipe(Effect9.catchAll(() => Effect9.succeed(null)));
|
|
956
|
+
if (!stat) continue;
|
|
957
|
+
if (stat.type === "Directory") {
|
|
958
|
+
yield* processDirectory(fullPath, relativePath, depth + 1);
|
|
72
959
|
} else {
|
|
73
960
|
result[fullPath] = relativePath;
|
|
74
961
|
}
|
|
75
962
|
}
|
|
76
|
-
};
|
|
77
|
-
processDirectory(directory);
|
|
963
|
+
});
|
|
964
|
+
yield* processDirectory(directory);
|
|
78
965
|
return result;
|
|
79
|
-
};
|
|
966
|
+
});
|
|
80
967
|
|
|
81
968
|
// src/build-output-v3/get-monorepo-files.ts
|
|
82
969
|
function getMonorepoFiles(directory, filePathMaps) {
|
|
@@ -94,54 +981,6 @@ function getMonorepoFiles(directory, filePathMaps) {
|
|
|
94
981
|
return result;
|
|
95
982
|
}
|
|
96
983
|
|
|
97
|
-
// src/build-output-v3/read-config-file.ts
|
|
98
|
-
import fs4 from "fs";
|
|
99
|
-
|
|
100
|
-
// src/parse-raw-config.ts
|
|
101
|
-
import fs3 from "fs";
|
|
102
|
-
import path4 from "path";
|
|
103
|
-
import { parse as parseYaml } from "yaml";
|
|
104
|
-
var parseRawConfig = async (filePath, { disableVersionCheck = false } = {}) => {
|
|
105
|
-
if (!fs3.existsSync(filePath)) {
|
|
106
|
-
throw new Error(`Config file not found at ${filePath}`);
|
|
107
|
-
}
|
|
108
|
-
const fileContents = fs3.readFileSync(filePath, "utf8");
|
|
109
|
-
if (fileContents.length === 0) {
|
|
110
|
-
throw new Error(`Config file is empty at ${filePath}`);
|
|
111
|
-
}
|
|
112
|
-
const fileExtension = path4.extname(filePath).toLowerCase();
|
|
113
|
-
let parsed;
|
|
114
|
-
try {
|
|
115
|
-
if (fileExtension === ".json") {
|
|
116
|
-
parsed = JSON.parse(fileContents);
|
|
117
|
-
} else if ([".yml", ".yaml"].includes(fileExtension)) {
|
|
118
|
-
parsed = parseYaml(fileContents);
|
|
119
|
-
} else {
|
|
120
|
-
parsed = parseYaml(fileContents);
|
|
121
|
-
}
|
|
122
|
-
} catch (error) {
|
|
123
|
-
throw new Error(
|
|
124
|
-
`Failed to parse config file at ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
if (parsed === void 0) {
|
|
128
|
-
throw new Error(`Config file could not be parsed at ${filePath}`);
|
|
129
|
-
}
|
|
130
|
-
if (!disableVersionCheck && typeof parsed.version !== "number") {
|
|
131
|
-
throw new Error(`Config file is missing version at ${filePath}`);
|
|
132
|
-
}
|
|
133
|
-
return parsed;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
// src/build-output-v3/read-config-file.ts
|
|
137
|
-
var readConfigFile = async (configFilePath) => {
|
|
138
|
-
if (!fs4.existsSync(configFilePath)) {
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
const parsed = await parseRawConfig(configFilePath, { disableVersionCheck: true });
|
|
142
|
-
return parsed;
|
|
143
|
-
};
|
|
144
|
-
|
|
145
984
|
// src/build-output-v3/translate-vercel-region.ts
|
|
146
985
|
var translateVercelRegion = (region) => {
|
|
147
986
|
const regionMap = {
|
|
@@ -183,284 +1022,141 @@ var translateVercelRuntime = (runtime) => {
|
|
|
183
1022
|
}
|
|
184
1023
|
};
|
|
185
1024
|
|
|
186
|
-
// src/build-output-
|
|
187
|
-
var
|
|
188
|
-
var
|
|
189
|
-
var
|
|
190
|
-
var
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
};
|
|
199
|
-
var loadAssetOverrides = async (config, parseResult) => {
|
|
200
|
-
return {
|
|
201
|
-
assets: {
|
|
202
|
-
overrides: {
|
|
203
|
-
...parseResult.assets?.overrides ?? {},
|
|
204
|
-
...config.overrides
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
};
|
|
209
|
-
var loadFunctions = async (config, parseResult, projectFolder) => {
|
|
210
|
-
const functionConfigs = await getFilesForPattern(functionConfigsPattern, projectFolder);
|
|
211
|
-
const result = {
|
|
212
|
-
entrypoints: [],
|
|
213
|
-
routes: [],
|
|
214
|
-
regions: []
|
|
215
|
-
};
|
|
216
|
-
for (const functionConfigPath of functionConfigs) {
|
|
217
|
-
const functionConfig = await readConfigFile(path5.join(projectFolder, functionConfigPath));
|
|
218
|
-
if (!functionConfig) {
|
|
219
|
-
parseResult.errors.push(`Failed to read function config at ${functionConfigPath}`);
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
const functionPathRelative = path5.dirname(functionConfigPath).replace(functionsFolder, "");
|
|
223
|
-
const functionName = functionPathRelative.replace(/^\/|\.func$/g, "");
|
|
224
|
-
const runtime = translateVercelRuntime(functionConfig.runtime);
|
|
225
|
-
if (!runtime) {
|
|
226
|
-
parseResult.errors.push(`Unsupported runtime for function ${functionName}: ${functionConfig.runtime}`);
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
const functionDirectory = `.vercel/output/functions/${functionName}.func`;
|
|
230
|
-
const {
|
|
231
|
-
handler,
|
|
232
|
-
maxDuration,
|
|
233
|
-
memory,
|
|
234
|
-
regions = [],
|
|
235
|
-
environment,
|
|
236
|
-
filePathMap: configFilePathMap = {}
|
|
237
|
-
} = functionConfig;
|
|
238
|
-
const translatedRegions = regions.length > 0 ? regions.map(translateVercelRegion) : ["us-east-1"];
|
|
239
|
-
result.regions = Array.from(/* @__PURE__ */ new Set([...parseResult.regions, ...translatedRegions]));
|
|
240
|
-
const environmentVariables = {};
|
|
241
|
-
if (environment && typeof environment === "object") {
|
|
242
|
-
for (const env of Object.values(environment)) {
|
|
243
|
-
Object.assign(environmentVariables, env);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
const streaming = runtime.startsWith("node-") || runtime.startsWith("bun-");
|
|
247
|
-
let filePathMap = {};
|
|
248
|
-
for (const [key, value] of Object.entries(configFilePathMap)) {
|
|
249
|
-
filePathMap[path5.join(projectFolder, key)] = value;
|
|
250
|
-
}
|
|
251
|
-
if (Object.keys(filePathMap).length === 0) {
|
|
252
|
-
filePathMap = getDefaultPathMap(path5.join(projectFolder, functionDirectory));
|
|
253
|
-
}
|
|
254
|
-
if (!result.entrypoints) {
|
|
255
|
-
result.entrypoints = [];
|
|
256
|
-
}
|
|
257
|
-
result.entrypoints.push({
|
|
258
|
-
displayName: functionName,
|
|
259
|
-
runtime,
|
|
260
|
-
path: path5.join(functionDirectory, handler),
|
|
261
|
-
memory: memory ?? 1024,
|
|
262
|
-
maxDuration: maxDuration ?? 15,
|
|
263
|
-
environmentVariables,
|
|
264
|
-
streaming,
|
|
265
|
-
package: {
|
|
266
|
-
filePathMap
|
|
1025
|
+
// src/services/vercel-build-output-parser.ts
|
|
1026
|
+
var CONFIG_PATH = ".vercel/output/config.json";
|
|
1027
|
+
var FUNCTIONS_FOLDER = ".vercel/output/functions";
|
|
1028
|
+
var FUNCTION_CONFIGS_PATTERN = `${FUNCTIONS_FOLDER}/**/*.func/.vc-config.json`;
|
|
1029
|
+
var VercelBuildOutputParser = class extends Effect10.Service()("VercelBuildOutputParser", {
|
|
1030
|
+
effect: Effect10.gen(function* () {
|
|
1031
|
+
const rawConfigReader = yield* RawConfigReader;
|
|
1032
|
+
const pathService = yield* Path7.Path;
|
|
1033
|
+
const parse = Effect10.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
|
|
1034
|
+
const config = yield* rawConfigReader.readConfigFile(pathService.join(projectFolder, CONFIG_PATH));
|
|
1035
|
+
if (!config || typeof config.version !== "number" || config.version < 3) {
|
|
1036
|
+
return parseResult;
|
|
267
1037
|
}
|
|
1038
|
+
const functionData = yield* loadFunctions(config, parseResult, projectFolder);
|
|
1039
|
+
const assetOverrides = loadAssetOverrides(config, parseResult);
|
|
1040
|
+
const merged = deepMerge(parseResult, functionData, assetOverrides);
|
|
1041
|
+
merged.regions = [...new Set(merged.regions)];
|
|
1042
|
+
return merged;
|
|
268
1043
|
});
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
};
|
|
277
|
-
const configRoutes = config.routes?.filter((r) => r.dest === `/${functionName}`).map(
|
|
278
|
-
(r) => ({
|
|
279
|
-
path: r.src ?? `/${functionName}`,
|
|
280
|
-
methods: ["ANY"],
|
|
281
|
-
headers: {},
|
|
282
|
-
destination: handler,
|
|
283
|
-
handler: handlerType
|
|
284
|
-
})
|
|
285
|
-
) ?? [];
|
|
286
|
-
if (!result.routes) {
|
|
287
|
-
result.routes = [];
|
|
288
|
-
}
|
|
289
|
-
result.routes.push(defaultRoute, ...configRoutes);
|
|
290
|
-
}
|
|
291
|
-
return {
|
|
292
|
-
...result,
|
|
293
|
-
userArchive: {
|
|
294
|
-
rootOverwrite: determineRepoRoot(projectFolder, result),
|
|
295
|
-
fileWhitelist: [
|
|
296
|
-
`${projectFolder}/*`,
|
|
297
|
-
...getMonorepoFiles(projectFolder, result.entrypoints?.map((e) => e.package?.filePathMap ?? {}) ?? [])
|
|
298
|
-
]
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
// src/filter-functions-from-assets.ts
|
|
304
|
-
var filterFunctionsFromAssets = async (config) => {
|
|
305
|
-
return {
|
|
306
|
-
...config,
|
|
307
|
-
assets: {
|
|
308
|
-
...config.assets,
|
|
309
|
-
paths: config.assets?.paths?.filter((path6) => !config.entrypoints.some((entrypoint) => entrypoint.path === path6))
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
// src/v4/parse.ts
|
|
315
|
-
import { getFilesForPattern as getFilesForPattern2 } from "@gigadrive/build-utils";
|
|
316
|
-
import fs5 from "fs";
|
|
317
|
-
import { minimatch } from "minimatch";
|
|
318
|
-
|
|
319
|
-
// src/regions.ts
|
|
320
|
-
var REGION_DEFINITIONS = [
|
|
321
|
-
"us-east-1",
|
|
322
|
-
"us-east-2",
|
|
323
|
-
"us-west-1",
|
|
324
|
-
"us-west-2",
|
|
325
|
-
"ap-south-1",
|
|
326
|
-
"ap-northeast-3",
|
|
327
|
-
"ap-northeast-2",
|
|
328
|
-
"ap-southeast-1",
|
|
329
|
-
"ap-southeast-2",
|
|
330
|
-
"ap-northeast-1",
|
|
331
|
-
"ca-central-1",
|
|
332
|
-
"eu-central-1",
|
|
333
|
-
"eu-west-1",
|
|
334
|
-
"eu-west-2",
|
|
335
|
-
"eu-west-3",
|
|
336
|
-
"eu-north-1",
|
|
337
|
-
"sa-east-1"
|
|
338
|
-
];
|
|
339
|
-
var AVAILABLE_REGIONS = [...REGION_DEFINITIONS];
|
|
340
|
-
|
|
341
|
-
// src/v4/parse.ts
|
|
342
|
-
var parseConfigV4 = async (config, projectFolder) => {
|
|
343
|
-
const regions = config.regions?.includes("global") === true ? AVAILABLE_REGIONS : config.regions?.filter((region) => region !== "global") ?? ["global"];
|
|
344
|
-
const populateAssetCache = config.populateAssetCache ?? false;
|
|
345
|
-
const environmentVariables = config.env ?? {};
|
|
346
|
-
const commands = config.build_commands ?? [];
|
|
347
|
-
const entrypoints = [];
|
|
348
|
-
const errors = [];
|
|
349
|
-
const warnings = [];
|
|
350
|
-
if (config.functions != null) {
|
|
351
|
-
for (const [path6, func] of Object.entries(config.functions)) {
|
|
352
|
-
const settings = getFunctionSettings(path6, config);
|
|
353
|
-
if (settings == null) {
|
|
354
|
-
throw new Error(`Settings invalid for function at path '${path6}'`);
|
|
355
|
-
}
|
|
356
|
-
(await getFilesForPattern2(path6, projectFolder, func.excludeFiles)).forEach((file) => {
|
|
357
|
-
if (entrypoints.find((entrypoint) => entrypoint.path === file)) {
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
if (config.functions != null && Object.keys(config.functions).find((func2) => func2 === file && func2 !== path6)) {
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
entrypoints.push({
|
|
364
|
-
path: file,
|
|
365
|
-
runtime: settings.runtime ?? "node-20",
|
|
366
|
-
memory: settings.memory ?? 128,
|
|
367
|
-
maxDuration: settings.max_duration ?? 30,
|
|
368
|
-
schedule: func.schedule,
|
|
369
|
-
symlinks: func.symlinks,
|
|
370
|
-
streaming: settings.runtime == null || settings.runtime.startsWith("node-") || settings.runtime.startsWith("bun-")
|
|
371
|
-
});
|
|
1044
|
+
const loadFunctions = Effect10.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
|
|
1045
|
+
const functionConfigs = yield* Effect10.tryPromise({
|
|
1046
|
+
try: () => getFilesForPattern2(FUNCTION_CONFIGS_PATTERN, projectFolder),
|
|
1047
|
+
catch: (error) => new ConfigFileParseError({
|
|
1048
|
+
message: `Failed to scan for function configs: ${error instanceof Error ? error.message : String(error)}`,
|
|
1049
|
+
filePath: projectFolder
|
|
1050
|
+
})
|
|
372
1051
|
});
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
for (const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
1052
|
+
const result = {
|
|
1053
|
+
entrypoints: [],
|
|
1054
|
+
routes: [],
|
|
1055
|
+
regions: [],
|
|
1056
|
+
errors: []
|
|
1057
|
+
};
|
|
1058
|
+
for (const functionConfigPath of functionConfigs) {
|
|
1059
|
+
const functionConfig = yield* rawConfigReader.readConfigFile(
|
|
1060
|
+
pathService.join(projectFolder, functionConfigPath)
|
|
1061
|
+
);
|
|
1062
|
+
if (!functionConfig) {
|
|
1063
|
+
result.errors.push(`Failed to read function config at ${functionConfigPath}`);
|
|
383
1064
|
continue;
|
|
384
1065
|
}
|
|
385
|
-
const
|
|
386
|
-
const
|
|
387
|
-
|
|
1066
|
+
const functionPathRelative = pathService.dirname(functionConfigPath).replace(FUNCTIONS_FOLDER, "");
|
|
1067
|
+
const functionName = functionPathRelative.replace(/^\/|\.func$/g, "");
|
|
1068
|
+
const runtime = translateVercelRuntime(functionConfig.runtime);
|
|
1069
|
+
if (!runtime) {
|
|
1070
|
+
result.errors.push(`Unsupported runtime for function ${functionName}: ${functionConfig.runtime}`);
|
|
388
1071
|
continue;
|
|
389
1072
|
}
|
|
390
|
-
|
|
391
|
-
|
|
1073
|
+
const functionDirectory = `.vercel/output/functions/${functionName}.func`;
|
|
1074
|
+
const {
|
|
1075
|
+
handler,
|
|
1076
|
+
maxDuration,
|
|
1077
|
+
memory,
|
|
1078
|
+
regions = [],
|
|
1079
|
+
environment,
|
|
1080
|
+
filePathMap: configFilePathMap = {}
|
|
1081
|
+
} = functionConfig;
|
|
1082
|
+
const functionEntrypointPath = pathService.join(functionDirectory, handler);
|
|
1083
|
+
const translatedRegions = regions.length > 0 ? regions.map(translateVercelRegion) : ["us-east-1"];
|
|
1084
|
+
result.regions = Array.from(/* @__PURE__ */ new Set([...result.regions ?? [], ...translatedRegions]));
|
|
1085
|
+
const environmentVariables = {};
|
|
1086
|
+
if (environment && typeof environment === "object") {
|
|
1087
|
+
for (const env of Object.values(environment)) {
|
|
1088
|
+
Object.assign(environmentVariables, env);
|
|
1089
|
+
}
|
|
392
1090
|
}
|
|
393
|
-
|
|
1091
|
+
const streaming = runtime.startsWith("node-") || runtime.startsWith("bun-");
|
|
1092
|
+
let filePathMap = {};
|
|
1093
|
+
for (const [key, value] of Object.entries(configFilePathMap)) {
|
|
1094
|
+
filePathMap[pathService.join(projectFolder, key)] = value;
|
|
1095
|
+
}
|
|
1096
|
+
if (Object.keys(filePathMap).length === 0) {
|
|
1097
|
+
filePathMap = yield* getDefaultPathMap(pathService.join(projectFolder, functionDirectory));
|
|
1098
|
+
}
|
|
1099
|
+
if (!result.entrypoints) {
|
|
1100
|
+
result.entrypoints = [];
|
|
1101
|
+
}
|
|
1102
|
+
result.entrypoints.push({
|
|
1103
|
+
displayName: functionName,
|
|
1104
|
+
runtime,
|
|
1105
|
+
path: functionEntrypointPath,
|
|
1106
|
+
memory: memory ?? 1024,
|
|
1107
|
+
maxDuration: maxDuration ?? 15,
|
|
1108
|
+
environmentVariables,
|
|
1109
|
+
streaming,
|
|
1110
|
+
package: {
|
|
1111
|
+
filePathMap
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
const handlerType = streaming ? "SERVERLESS_FUNCTION_STREAMING" : "SERVERLESS_FUNCTION";
|
|
1115
|
+
const defaultRoute = {
|
|
1116
|
+
path: `/${functionName}`,
|
|
1117
|
+
methods: ["ANY"],
|
|
1118
|
+
headers: {},
|
|
1119
|
+
destination: functionEntrypointPath,
|
|
1120
|
+
handler: handlerType
|
|
1121
|
+
};
|
|
1122
|
+
const configRoutes = config.routes?.filter((r) => "dest" in r && r.dest === `/${functionName}`).map(
|
|
1123
|
+
(r) => ({
|
|
1124
|
+
path: ("src" in r ? r.src : void 0) ?? `/${functionName}`,
|
|
1125
|
+
methods: ["ANY"],
|
|
1126
|
+
headers: {},
|
|
1127
|
+
destination: functionEntrypointPath,
|
|
1128
|
+
handler: handlerType
|
|
1129
|
+
})
|
|
1130
|
+
) ?? [];
|
|
1131
|
+
if (!result.routes) {
|
|
1132
|
+
result.routes = [];
|
|
1133
|
+
}
|
|
1134
|
+
result.routes.push(defaultRoute, ...configRoutes);
|
|
394
1135
|
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
const routes = config.routes ?? [];
|
|
398
|
-
return {
|
|
399
|
-
regions,
|
|
400
|
-
assets: {
|
|
401
|
-
paths: assets.sort(),
|
|
402
|
-
prefixToStrip: (config.assets ?? "") + "/",
|
|
403
|
-
dynamicRoutes: true,
|
|
404
|
-
populateCache: populateAssetCache
|
|
405
|
-
},
|
|
406
|
-
environmentVariables,
|
|
407
|
-
commands,
|
|
408
|
-
entrypoints,
|
|
409
|
-
errors,
|
|
410
|
-
warnings,
|
|
411
|
-
routes: routes.map((route) => {
|
|
412
|
-
const handler = route.destination.toLowerCase().startsWith("http://") || route.destination.toLowerCase().startsWith("https://") ? route.redirect === true ? "HTTP_REDIRECT" : "HTTP_PROXY" : route.redirect === true ? "HTTP_REDIRECT" : "SERVERLESS_FUNCTION";
|
|
413
1136
|
return {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
1137
|
+
...result,
|
|
1138
|
+
userArchive: {
|
|
1139
|
+
rootOverwrite: determineRepoRoot(projectFolder, result),
|
|
1140
|
+
fileWhitelist: [
|
|
1141
|
+
`${projectFolder}/*`,
|
|
1142
|
+
...getMonorepoFiles(projectFolder, result.entrypoints?.map((e) => e.package?.filePathMap ?? {}) ?? [])
|
|
1143
|
+
]
|
|
1144
|
+
}
|
|
422
1145
|
};
|
|
423
|
-
})
|
|
424
|
-
|
|
1146
|
+
});
|
|
1147
|
+
return { parse };
|
|
1148
|
+
})
|
|
1149
|
+
}) {
|
|
425
1150
|
};
|
|
426
|
-
var
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
memory: 128,
|
|
433
|
-
max_duration: 30,
|
|
434
|
-
schedule: void 0,
|
|
435
|
-
symlinks: void 0,
|
|
436
|
-
excludeFiles: void 0,
|
|
437
|
-
includeFiles: void 0
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
if (value.runtime != null) {
|
|
441
|
-
functionSettings.runtime = value.runtime;
|
|
442
|
-
}
|
|
443
|
-
if (value.memory != null) {
|
|
444
|
-
functionSettings.memory = value.memory;
|
|
445
|
-
}
|
|
446
|
-
if (value.max_duration != null) {
|
|
447
|
-
functionSettings.max_duration = value.max_duration;
|
|
448
|
-
}
|
|
449
|
-
if (value.schedule != null) {
|
|
450
|
-
functionSettings.schedule = value.schedule;
|
|
451
|
-
}
|
|
452
|
-
if (value.symlinks != null) {
|
|
453
|
-
functionSettings.symlinks = value.symlinks;
|
|
454
|
-
}
|
|
455
|
-
if (value.excludeFiles != null) {
|
|
456
|
-
functionSettings.excludeFiles = value.excludeFiles;
|
|
457
|
-
}
|
|
458
|
-
if (value.includeFiles != null) {
|
|
459
|
-
functionSettings.includeFiles = value.includeFiles;
|
|
1151
|
+
var loadAssetOverrides = (config, parseResult) => {
|
|
1152
|
+
return {
|
|
1153
|
+
assets: {
|
|
1154
|
+
overrides: {
|
|
1155
|
+
...parseResult.assets?.overrides ?? {},
|
|
1156
|
+
...config.overrides
|
|
460
1157
|
}
|
|
461
1158
|
}
|
|
462
|
-
}
|
|
463
|
-
return functionSettings;
|
|
1159
|
+
};
|
|
464
1160
|
};
|
|
465
1161
|
|
|
466
1162
|
// src/v4/schema.json
|
|
@@ -746,7 +1442,7 @@ var schema_default = {
|
|
|
746
1442
|
$defs: {
|
|
747
1443
|
runtimes: {
|
|
748
1444
|
type: "string",
|
|
749
|
-
enum: ["php-
|
|
1445
|
+
enum: ["php-84", "php-83", "php-81", "node-22", "node-20", "node-18", "node-16", "bun-1"]
|
|
750
1446
|
},
|
|
751
1447
|
matchRequirements: {
|
|
752
1448
|
description: "An array of requirements that are needed to match",
|
|
@@ -800,45 +1496,45 @@ var schema_default = {
|
|
|
800
1496
|
};
|
|
801
1497
|
|
|
802
1498
|
// src/parse-config.ts
|
|
803
|
-
var
|
|
804
|
-
const
|
|
1499
|
+
var parseConfigRaw = Effect11.fn("parseConfigRaw")(function* (filePath, projectFolder) {
|
|
1500
|
+
const rawReader = yield* RawConfigReader;
|
|
1501
|
+
const validator = yield* SchemaValidator;
|
|
1502
|
+
const v4Parser = yield* V4ConfigParser;
|
|
1503
|
+
const parsed = yield* rawReader.readRawConfig(filePath);
|
|
805
1504
|
const version = parsed.version;
|
|
806
1505
|
const schemaMap = {
|
|
807
|
-
/*1: schemaV1,
|
|
808
|
-
2: schemaV2,
|
|
809
|
-
3: schemaV3,*/
|
|
810
1506
|
4: schema_default
|
|
811
1507
|
};
|
|
812
|
-
const relativePath = filePath.replace("/tmp/unzipped/", "");
|
|
813
1508
|
const schema = schemaMap[version];
|
|
814
1509
|
if (!schema) {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
throw new Error(`Config file at ${relativePath} is invalid: ${ajv.errorsText(validate.errors)}`);
|
|
1510
|
+
return yield* Effect11.fail(
|
|
1511
|
+
new ConfigVersionError({
|
|
1512
|
+
message: `Config file at ${filePath} has an unsupported version: ${version}`,
|
|
1513
|
+
filePath,
|
|
1514
|
+
version
|
|
1515
|
+
})
|
|
1516
|
+
);
|
|
823
1517
|
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
1518
|
+
yield* validator.validate(parsed, schema, filePath);
|
|
1519
|
+
return yield* v4Parser.parse(parsed, projectFolder);
|
|
1520
|
+
});
|
|
1521
|
+
var parseConfig = Effect11.fn("parseConfig")(function* (filePath, projectFolder) {
|
|
1522
|
+
const parseResult = yield* parseConfigRaw(filePath, projectFolder);
|
|
1523
|
+
return yield* postProcessConfig(parseResult, projectFolder);
|
|
1524
|
+
});
|
|
1525
|
+
var postProcessConfig = Effect11.fn("postProcessConfig")(function* (config, projectFolder) {
|
|
1526
|
+
const vercelParser = yield* VercelBuildOutputParser;
|
|
1527
|
+
let result = yield* vercelParser.parse(config, projectFolder);
|
|
1528
|
+
if (result.entrypoints.length === 0 && (result.assets?.paths?.length || 0) === 0 && result.routes.length === 0) {
|
|
1529
|
+
result.errors.push(
|
|
836
1530
|
"The current project config does not resolve to any functions, assets or routes and can not be deployed."
|
|
837
1531
|
);
|
|
1532
|
+
} else if (result.entrypoints.length === 0 && (result.assets?.paths?.length || 0) === 0) {
|
|
1533
|
+
result.warnings.push("The current project does not have any functions or assets to deploy.");
|
|
838
1534
|
}
|
|
839
|
-
|
|
840
|
-
return
|
|
841
|
-
};
|
|
1535
|
+
result = filterFunctionsFromAssets(result);
|
|
1536
|
+
return result;
|
|
1537
|
+
});
|
|
842
1538
|
|
|
843
1539
|
// src/runtime.ts
|
|
844
1540
|
var RUNTIME_DEFINITIONS = [
|
|
@@ -852,12 +1548,40 @@ var RUNTIME_DEFINITIONS = [
|
|
|
852
1548
|
"bun-1"
|
|
853
1549
|
];
|
|
854
1550
|
var AVAILABLE_RUNTIMES = [...RUNTIME_DEFINITIONS];
|
|
1551
|
+
|
|
1552
|
+
// src/services/index.ts
|
|
1553
|
+
import { Layer } from "effect";
|
|
1554
|
+
var BaseLayers = Layer.mergeAll(RawConfigReader.Default, SchemaValidator.Default, V4ConfigParser.Default);
|
|
1555
|
+
var NetworkConfigLive = VercelBuildOutputParser.Default.pipe(Layer.provideMerge(BaseLayers));
|
|
855
1556
|
export {
|
|
856
1557
|
ALLOWED_CONFIG_NAMES,
|
|
857
1558
|
AVAILABLE_REGIONS,
|
|
858
1559
|
AVAILABLE_RUNTIMES,
|
|
859
|
-
|
|
1560
|
+
ConfigFileEmptyError,
|
|
1561
|
+
ConfigFileNotFoundError,
|
|
1562
|
+
ConfigFileParseError,
|
|
1563
|
+
ConfigSchemaValidationError,
|
|
1564
|
+
ConfigVersionError,
|
|
1565
|
+
FRAMEWORK_DEFINITIONS,
|
|
1566
|
+
FrameworkNotDetectedError,
|
|
1567
|
+
FunctionConfigError,
|
|
1568
|
+
ManifestNotFoundError,
|
|
1569
|
+
ManifestParseError,
|
|
1570
|
+
ManifestReadError,
|
|
1571
|
+
NetworkConfigLive,
|
|
1572
|
+
RawConfigReader,
|
|
1573
|
+
SchemaValidator,
|
|
1574
|
+
V4ConfigParser,
|
|
1575
|
+
VercelBuildOutputParser,
|
|
1576
|
+
detectFramework,
|
|
1577
|
+
detectPackageManager,
|
|
1578
|
+
filterFunctionsFromAssets,
|
|
1579
|
+
generateConfig,
|
|
1580
|
+
getFunctionSettings,
|
|
1581
|
+
mergeWithFrameworkDefaults,
|
|
860
1582
|
parseConfig,
|
|
861
|
-
|
|
1583
|
+
parseConfigRaw,
|
|
1584
|
+
postProcessConfig,
|
|
1585
|
+
readDependencies
|
|
862
1586
|
};
|
|
863
1587
|
//# sourceMappingURL=index.mjs.map
|