@gigadrive/network-config 2.1.2 → 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 +430 -12
- package/dist/index.d.ts +430 -12
- package/dist/index.js +44861 -13494
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1097 -375
- package/dist/index.mjs.map +1 -1
- package/dist/v4/schema.json +1 -1
- package/package.json +9 -4
- 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;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
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;
|
|
10
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)
|
|
11
603
|
}
|
|
12
|
-
|
|
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,7 +916,7 @@ 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++) {
|
|
@@ -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,56 +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/promises";
|
|
102
|
-
import path4 from "path";
|
|
103
|
-
import { parse as parseYaml } from "yaml";
|
|
104
|
-
var parseRawConfig = async (filePath, { disableVersionCheck = false } = {}) => {
|
|
105
|
-
try {
|
|
106
|
-
await fs3.access(filePath);
|
|
107
|
-
} catch {
|
|
108
|
-
throw new Error(`Config file not found at ${filePath}`);
|
|
109
|
-
}
|
|
110
|
-
const fileContents = await fs3.readFile(filePath, "utf8");
|
|
111
|
-
if (fileContents.length === 0) {
|
|
112
|
-
throw new Error(`Config file is empty at ${filePath}`);
|
|
113
|
-
}
|
|
114
|
-
const fileExtension = path4.extname(filePath).toLowerCase();
|
|
115
|
-
let parsed;
|
|
116
|
-
try {
|
|
117
|
-
if (fileExtension === ".json") {
|
|
118
|
-
parsed = JSON.parse(fileContents);
|
|
119
|
-
} else if ([".yml", ".yaml"].includes(fileExtension)) {
|
|
120
|
-
parsed = parseYaml(fileContents);
|
|
121
|
-
} else {
|
|
122
|
-
parsed = parseYaml(fileContents);
|
|
123
|
-
}
|
|
124
|
-
} catch (error) {
|
|
125
|
-
throw new Error(
|
|
126
|
-
`Failed to parse config file at ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
if (parsed === void 0) {
|
|
130
|
-
throw new Error(`Config file could not be parsed at ${filePath}`);
|
|
131
|
-
}
|
|
132
|
-
if (!disableVersionCheck && typeof parsed.version !== "number") {
|
|
133
|
-
throw new Error(`Config file is missing version at ${filePath}`);
|
|
134
|
-
}
|
|
135
|
-
return parsed;
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
// src/build-output-v3/read-config-file.ts
|
|
139
|
-
var readConfigFile = async (configFilePath) => {
|
|
140
|
-
if (!fs4.existsSync(configFilePath)) {
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
const parsed = await parseRawConfig(configFilePath, { disableVersionCheck: true });
|
|
144
|
-
return parsed;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
984
|
// src/build-output-v3/translate-vercel-region.ts
|
|
148
985
|
var translateVercelRegion = (region) => {
|
|
149
986
|
const regionMap = {
|
|
@@ -185,284 +1022,141 @@ var translateVercelRuntime = (runtime) => {
|
|
|
185
1022
|
}
|
|
186
1023
|
};
|
|
187
1024
|
|
|
188
|
-
// src/build-output-
|
|
189
|
-
var
|
|
190
|
-
var
|
|
191
|
-
var
|
|
192
|
-
var
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
};
|
|
201
|
-
var loadAssetOverrides = (config, parseResult) => {
|
|
202
|
-
return {
|
|
203
|
-
assets: {
|
|
204
|
-
overrides: {
|
|
205
|
-
...parseResult.assets?.overrides ?? {},
|
|
206
|
-
...config.overrides
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
};
|
|
211
|
-
var loadFunctions = async (config, parseResult, projectFolder) => {
|
|
212
|
-
const functionConfigs = await getFilesForPattern(functionConfigsPattern, projectFolder);
|
|
213
|
-
const result = {
|
|
214
|
-
entrypoints: [],
|
|
215
|
-
routes: [],
|
|
216
|
-
regions: []
|
|
217
|
-
};
|
|
218
|
-
for (const functionConfigPath of functionConfigs) {
|
|
219
|
-
const functionConfig = await readConfigFile(path5.join(projectFolder, functionConfigPath));
|
|
220
|
-
if (!functionConfig) {
|
|
221
|
-
parseResult.errors.push(`Failed to read function config at ${functionConfigPath}`);
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
const functionPathRelative = path5.dirname(functionConfigPath).replace(functionsFolder, "");
|
|
225
|
-
const functionName = functionPathRelative.replace(/^\/|\.func$/g, "");
|
|
226
|
-
const runtime = translateVercelRuntime(functionConfig.runtime);
|
|
227
|
-
if (!runtime) {
|
|
228
|
-
parseResult.errors.push(`Unsupported runtime for function ${functionName}: ${functionConfig.runtime}`);
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
const functionDirectory = `.vercel/output/functions/${functionName}.func`;
|
|
232
|
-
const {
|
|
233
|
-
handler,
|
|
234
|
-
maxDuration,
|
|
235
|
-
memory,
|
|
236
|
-
regions = [],
|
|
237
|
-
environment,
|
|
238
|
-
filePathMap: configFilePathMap = {}
|
|
239
|
-
} = functionConfig;
|
|
240
|
-
const translatedRegions = regions.length > 0 ? regions.map(translateVercelRegion) : ["us-east-1"];
|
|
241
|
-
result.regions = Array.from(/* @__PURE__ */ new Set([...parseResult.regions, ...translatedRegions]));
|
|
242
|
-
const environmentVariables = {};
|
|
243
|
-
if (environment && typeof environment === "object") {
|
|
244
|
-
for (const env of Object.values(environment)) {
|
|
245
|
-
Object.assign(environmentVariables, env);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
const streaming = runtime.startsWith("node-") || runtime.startsWith("bun-");
|
|
249
|
-
let filePathMap = {};
|
|
250
|
-
for (const [key, value] of Object.entries(configFilePathMap)) {
|
|
251
|
-
filePathMap[path5.join(projectFolder, key)] = value;
|
|
252
|
-
}
|
|
253
|
-
if (Object.keys(filePathMap).length === 0) {
|
|
254
|
-
filePathMap = getDefaultPathMap(path5.join(projectFolder, functionDirectory));
|
|
255
|
-
}
|
|
256
|
-
if (!result.entrypoints) {
|
|
257
|
-
result.entrypoints = [];
|
|
258
|
-
}
|
|
259
|
-
result.entrypoints.push({
|
|
260
|
-
displayName: functionName,
|
|
261
|
-
runtime,
|
|
262
|
-
path: path5.join(functionDirectory, handler),
|
|
263
|
-
memory: memory ?? 1024,
|
|
264
|
-
maxDuration: maxDuration ?? 15,
|
|
265
|
-
environmentVariables,
|
|
266
|
-
streaming,
|
|
267
|
-
package: {
|
|
268
|
-
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;
|
|
269
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;
|
|
270
1043
|
});
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
};
|
|
279
|
-
const configRoutes = config.routes?.filter((r) => r.dest === `/${functionName}`).map(
|
|
280
|
-
(r) => ({
|
|
281
|
-
path: r.src ?? `/${functionName}`,
|
|
282
|
-
methods: ["ANY"],
|
|
283
|
-
headers: {},
|
|
284
|
-
destination: handler,
|
|
285
|
-
handler: handlerType
|
|
286
|
-
})
|
|
287
|
-
) ?? [];
|
|
288
|
-
if (!result.routes) {
|
|
289
|
-
result.routes = [];
|
|
290
|
-
}
|
|
291
|
-
result.routes.push(defaultRoute, ...configRoutes);
|
|
292
|
-
}
|
|
293
|
-
return {
|
|
294
|
-
...result,
|
|
295
|
-
userArchive: {
|
|
296
|
-
rootOverwrite: determineRepoRoot(projectFolder, result),
|
|
297
|
-
fileWhitelist: [
|
|
298
|
-
`${projectFolder}/*`,
|
|
299
|
-
...getMonorepoFiles(projectFolder, result.entrypoints?.map((e) => e.package?.filePathMap ?? {}) ?? [])
|
|
300
|
-
]
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
// src/filter-functions-from-assets.ts
|
|
306
|
-
var filterFunctionsFromAssets = (config) => {
|
|
307
|
-
return {
|
|
308
|
-
...config,
|
|
309
|
-
assets: {
|
|
310
|
-
...config.assets,
|
|
311
|
-
paths: config.assets?.paths?.filter((path6) => !config.entrypoints.some((entrypoint) => entrypoint.path === path6))
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
// src/v4/parse.ts
|
|
317
|
-
import { getFilesForPattern as getFilesForPattern2 } from "@gigadrive/build-utils";
|
|
318
|
-
import fs5 from "fs";
|
|
319
|
-
import { minimatch } from "minimatch";
|
|
320
|
-
|
|
321
|
-
// src/regions.ts
|
|
322
|
-
var REGION_DEFINITIONS = [
|
|
323
|
-
"us-east-1",
|
|
324
|
-
"us-east-2",
|
|
325
|
-
"us-west-1",
|
|
326
|
-
"us-west-2",
|
|
327
|
-
"ap-south-1",
|
|
328
|
-
"ap-northeast-3",
|
|
329
|
-
"ap-northeast-2",
|
|
330
|
-
"ap-southeast-1",
|
|
331
|
-
"ap-southeast-2",
|
|
332
|
-
"ap-northeast-1",
|
|
333
|
-
"ca-central-1",
|
|
334
|
-
"eu-central-1",
|
|
335
|
-
"eu-west-1",
|
|
336
|
-
"eu-west-2",
|
|
337
|
-
"eu-west-3",
|
|
338
|
-
"eu-north-1",
|
|
339
|
-
"sa-east-1"
|
|
340
|
-
];
|
|
341
|
-
var AVAILABLE_REGIONS = [...REGION_DEFINITIONS];
|
|
342
|
-
|
|
343
|
-
// src/v4/parse.ts
|
|
344
|
-
var parseConfigV4 = async (config, projectFolder) => {
|
|
345
|
-
const regions = config.regions?.includes("global") === true ? AVAILABLE_REGIONS : config.regions?.filter((region) => region !== "global") ?? ["global"];
|
|
346
|
-
const populateAssetCache = config.populateAssetCache ?? false;
|
|
347
|
-
const environmentVariables = config.env ?? {};
|
|
348
|
-
const commands = config.build_commands ?? [];
|
|
349
|
-
const entrypoints = [];
|
|
350
|
-
const errors = [];
|
|
351
|
-
const warnings = [];
|
|
352
|
-
if (config.functions != null) {
|
|
353
|
-
for (const [path6, func] of Object.entries(config.functions)) {
|
|
354
|
-
const settings = getFunctionSettings(path6, config);
|
|
355
|
-
if (settings == null) {
|
|
356
|
-
throw new Error(`Settings invalid for function at path '${path6}'`);
|
|
357
|
-
}
|
|
358
|
-
(await getFilesForPattern2(path6, projectFolder, func.excludeFiles)).forEach((file) => {
|
|
359
|
-
if (entrypoints.find((entrypoint) => entrypoint.path === file)) {
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
if (config.functions != null && Object.keys(config.functions).find((func2) => func2 === file && func2 !== path6)) {
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
entrypoints.push({
|
|
366
|
-
path: file,
|
|
367
|
-
runtime: settings.runtime ?? "node-20",
|
|
368
|
-
memory: settings.memory ?? 128,
|
|
369
|
-
maxDuration: settings.max_duration ?? 30,
|
|
370
|
-
schedule: func.schedule,
|
|
371
|
-
symlinks: func.symlinks,
|
|
372
|
-
streaming: settings.runtime == null || settings.runtime.startsWith("node-") || settings.runtime.startsWith("bun-")
|
|
373
|
-
});
|
|
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
|
+
})
|
|
374
1051
|
});
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
for (const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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}`);
|
|
385
1064
|
continue;
|
|
386
1065
|
}
|
|
387
|
-
const
|
|
388
|
-
const
|
|
389
|
-
|
|
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}`);
|
|
390
1071
|
continue;
|
|
391
1072
|
}
|
|
392
|
-
|
|
393
|
-
|
|
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
|
+
}
|
|
1090
|
+
}
|
|
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 = [];
|
|
394
1133
|
}
|
|
395
|
-
|
|
1134
|
+
result.routes.push(defaultRoute, ...configRoutes);
|
|
396
1135
|
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
const routes = config.routes ?? [];
|
|
400
|
-
return {
|
|
401
|
-
regions,
|
|
402
|
-
assets: {
|
|
403
|
-
paths: assets.sort(),
|
|
404
|
-
prefixToStrip: (config.assets ?? "") + "/",
|
|
405
|
-
dynamicRoutes: true,
|
|
406
|
-
populateCache: populateAssetCache
|
|
407
|
-
},
|
|
408
|
-
environmentVariables,
|
|
409
|
-
commands,
|
|
410
|
-
entrypoints,
|
|
411
|
-
errors,
|
|
412
|
-
warnings,
|
|
413
|
-
routes: routes.map((route) => {
|
|
414
|
-
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";
|
|
415
1136
|
return {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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
|
+
}
|
|
424
1145
|
};
|
|
425
|
-
})
|
|
426
|
-
|
|
1146
|
+
});
|
|
1147
|
+
return { parse };
|
|
1148
|
+
})
|
|
1149
|
+
}) {
|
|
427
1150
|
};
|
|
428
|
-
var
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
memory: 128,
|
|
435
|
-
max_duration: 30,
|
|
436
|
-
schedule: void 0,
|
|
437
|
-
symlinks: void 0,
|
|
438
|
-
excludeFiles: void 0,
|
|
439
|
-
includeFiles: void 0
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
if (value.runtime != null) {
|
|
443
|
-
functionSettings.runtime = value.runtime;
|
|
444
|
-
}
|
|
445
|
-
if (value.memory != null) {
|
|
446
|
-
functionSettings.memory = value.memory;
|
|
447
|
-
}
|
|
448
|
-
if (value.max_duration != null) {
|
|
449
|
-
functionSettings.max_duration = value.max_duration;
|
|
450
|
-
}
|
|
451
|
-
if (value.schedule != null) {
|
|
452
|
-
functionSettings.schedule = value.schedule;
|
|
453
|
-
}
|
|
454
|
-
if (value.symlinks != null) {
|
|
455
|
-
functionSettings.symlinks = value.symlinks;
|
|
456
|
-
}
|
|
457
|
-
if (value.excludeFiles != null) {
|
|
458
|
-
functionSettings.excludeFiles = value.excludeFiles;
|
|
459
|
-
}
|
|
460
|
-
if (value.includeFiles != null) {
|
|
461
|
-
functionSettings.includeFiles = value.includeFiles;
|
|
1151
|
+
var loadAssetOverrides = (config, parseResult) => {
|
|
1152
|
+
return {
|
|
1153
|
+
assets: {
|
|
1154
|
+
overrides: {
|
|
1155
|
+
...parseResult.assets?.overrides ?? {},
|
|
1156
|
+
...config.overrides
|
|
462
1157
|
}
|
|
463
1158
|
}
|
|
464
|
-
}
|
|
465
|
-
return functionSettings;
|
|
1159
|
+
};
|
|
466
1160
|
};
|
|
467
1161
|
|
|
468
1162
|
// src/v4/schema.json
|
|
@@ -748,7 +1442,7 @@ var schema_default = {
|
|
|
748
1442
|
$defs: {
|
|
749
1443
|
runtimes: {
|
|
750
1444
|
type: "string",
|
|
751
|
-
enum: ["php-
|
|
1445
|
+
enum: ["php-84", "php-83", "php-81", "node-22", "node-20", "node-18", "node-16", "bun-1"]
|
|
752
1446
|
},
|
|
753
1447
|
matchRequirements: {
|
|
754
1448
|
description: "An array of requirements that are needed to match",
|
|
@@ -802,45 +1496,45 @@ var schema_default = {
|
|
|
802
1496
|
};
|
|
803
1497
|
|
|
804
1498
|
// src/parse-config.ts
|
|
805
|
-
var
|
|
806
|
-
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);
|
|
807
1504
|
const version = parsed.version;
|
|
808
1505
|
const schemaMap = {
|
|
809
|
-
/*1: schemaV1,
|
|
810
|
-
2: schemaV2,
|
|
811
|
-
3: schemaV3,*/
|
|
812
1506
|
4: schema_default
|
|
813
1507
|
};
|
|
814
|
-
const relativePath = filePath.replace("/tmp/unzipped/", "");
|
|
815
1508
|
const schema = schemaMap[version];
|
|
816
1509
|
if (!schema) {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
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
|
+
);
|
|
825
1517
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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(
|
|
838
1530
|
"The current project config does not resolve to any functions, assets or routes and can not be deployed."
|
|
839
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.");
|
|
840
1534
|
}
|
|
841
|
-
|
|
842
|
-
return
|
|
843
|
-
};
|
|
1535
|
+
result = filterFunctionsFromAssets(result);
|
|
1536
|
+
return result;
|
|
1537
|
+
});
|
|
844
1538
|
|
|
845
1539
|
// src/runtime.ts
|
|
846
1540
|
var RUNTIME_DEFINITIONS = [
|
|
@@ -854,12 +1548,40 @@ var RUNTIME_DEFINITIONS = [
|
|
|
854
1548
|
"bun-1"
|
|
855
1549
|
];
|
|
856
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));
|
|
857
1556
|
export {
|
|
858
1557
|
ALLOWED_CONFIG_NAMES,
|
|
859
1558
|
AVAILABLE_REGIONS,
|
|
860
1559
|
AVAILABLE_RUNTIMES,
|
|
861
|
-
|
|
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,
|
|
862
1582
|
parseConfig,
|
|
863
|
-
|
|
1583
|
+
parseConfigRaw,
|
|
1584
|
+
postProcessConfig,
|
|
1585
|
+
readDependencies
|
|
864
1586
|
};
|
|
865
1587
|
//# sourceMappingURL=index.mjs.map
|