@ubean/preset 0.1.13 → 0.2.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.js CHANGED
@@ -64,8 +64,10 @@ function diagnoseCapabilities(presetName, presetCapabilities, requirements) {
64
64
  required: req.required,
65
65
  message: supported ? `${req.capability} is supported` : message
66
66
  });
67
- if (!supported) if (req.required) errors.push(`[${presetName}] ${message}`);
68
- else warnings.push(`[${presetName}] ${message}`);
67
+ if (!supported) {
68
+ if (req.required) errors.push(`[${presetName}] ${message}`);
69
+ else warnings.push(`[${presetName}] ${message}`);
70
+ }
69
71
  }
70
72
  return {
71
73
  valid: errors.length === 0,
@@ -243,6 +245,443 @@ function getPresetNames() {
243
245
  function getPresetAliases() {
244
246
  return new Map(presetNames);
245
247
  }
248
+ /**
249
+ * AWS Lambda preset —— AWS Lambda + API Gateway / Function URL 模式
250
+ *
251
+ * 构建输出:`dist/aws/lambda/index.mjs`(Lambda handler)
252
+ * 预览命令:`sam local start-api`(通过 AWS SAM 本地模拟)
253
+ * 部署命令:`sam deploy --guided`(交互式部署)
254
+ *
255
+ * Lambda handler 签名:
256
+ * ```typescript
257
+ * export const handler = async (event, context) => { ... };
258
+ * ```
259
+ */
260
+ const awsPreset = definePreset({
261
+ extends: "node",
262
+ capabilities: createCapabilitySet({
263
+ staticServe: true,
264
+ websocket: false,
265
+ sse: true,
266
+ cronTriggers: true,
267
+ queues: true,
268
+ kv: true,
269
+ storage: true,
270
+ database: true,
271
+ envVars: true,
272
+ secrets: true,
273
+ nodeCompat: true,
274
+ streaming: true,
275
+ compression: true,
276
+ https: true,
277
+ http2: true,
278
+ middleware: false,
279
+ bodyLimit: true,
280
+ multipart: true,
281
+ rpc: false
282
+ }),
283
+ entry: "server",
284
+ exportConditions: ["aws", "aws-lambda"],
285
+ build: {
286
+ outputDir: "dist/aws",
287
+ format: "esm",
288
+ externals: [
289
+ "hono",
290
+ "c12",
291
+ "citty",
292
+ "tslog",
293
+ "defu",
294
+ "hookable",
295
+ "pathe",
296
+ "ufo",
297
+ "zod",
298
+ "@aws-sdk/*"
299
+ ]
300
+ },
301
+ output: {
302
+ dir: "dist/aws",
303
+ serverDir: "dist/aws/lambda",
304
+ publicDir: "dist/aws/public"
305
+ },
306
+ runtime: {
307
+ entry: "lambda/index.mjs",
308
+ handler: "handler",
309
+ compatibilityDate: "2024-09-01"
310
+ },
311
+ serve: {
312
+ host: "localhost",
313
+ port: 3001
314
+ },
315
+ commands: {
316
+ preview: "sam local start-api",
317
+ deploy: "sam deploy --guided"
318
+ },
319
+ hooks: {
320
+ "build:before": async () => {},
321
+ "build:after": async () => {}
322
+ }
323
+ }, {
324
+ name: "aws",
325
+ aliases: [
326
+ "aws-lambda",
327
+ "lambda",
328
+ "amazon",
329
+ "sam"
330
+ ],
331
+ stdName: "aws_lambda",
332
+ dev: true,
333
+ compatibilityDate: "2024-09-01",
334
+ url: "https://docs.aws.amazon.com/lambda/latest/dg/welcome.html"
335
+ });
336
+ /**
337
+ * 生成 AWS SAM template.yaml 配置对象
338
+ */
339
+ function generateAwsSamConfig(options) {
340
+ const handler = options.handler || "dist/aws/lambda/index.handler";
341
+ const runtime = options.runtime || "nodejs20.x";
342
+ const codeUri = options.codeUri || "dist/aws/lambda";
343
+ const events = { ApiEvent: {
344
+ Type: "Api",
345
+ Properties: {
346
+ Path: "/{proxy+}",
347
+ Method: "ANY",
348
+ RestApiId: { Ref: "ApiGateway" }
349
+ }
350
+ } };
351
+ if (options.cronSchedules) for (const cron of options.cronSchedules) events[`Cron${cron.name}`] = {
352
+ Type: "Schedule",
353
+ Properties: {
354
+ Schedule: cron.schedule,
355
+ Enabled: cron.enabled ?? true,
356
+ Name: cron.name
357
+ }
358
+ };
359
+ const template = {
360
+ AWSTemplateFormatVersion: "2010-09-09",
361
+ Transform: "AWS::Serverless-2016-10-31",
362
+ Description: "ubean application deployed to AWS Lambda",
363
+ Globals: { Function: {
364
+ Runtime: runtime,
365
+ MemorySize: options.memorySize ?? 256,
366
+ Timeout: options.timeout ?? 30,
367
+ Handler: handler
368
+ } },
369
+ Resources: {
370
+ ApiGateway: {
371
+ Type: "AWS::Serverless::Api",
372
+ Properties: {
373
+ StageName: options.apiStage || "prod",
374
+ EndpointConfiguration: { Type: "REGIONAL" }
375
+ }
376
+ },
377
+ UbeanFunction: {
378
+ Type: "AWS::Serverless::Function",
379
+ Properties: {
380
+ FunctionName: options.functionName || "ubean-app",
381
+ Handler: handler,
382
+ Runtime: runtime,
383
+ CodeUri: codeUri,
384
+ MemorySize: options.memorySize ?? 256,
385
+ Timeout: options.timeout ?? 30,
386
+ Events: events,
387
+ Policies: ["AmazonDynamoDBReadOnlyAccess", "AmazonS3ReadOnlyAccess"]
388
+ }
389
+ }
390
+ },
391
+ Outputs: {
392
+ ApiUrl: {
393
+ Description: "URL of the API endpoint",
394
+ Value: { "Fn::Sub": `https://\${ApiGateway}.execute-api.\${AWS::Region}.amazonaws.com/${options.apiStage || "prod"}` }
395
+ },
396
+ FunctionArn: {
397
+ Description: "ARN of the Lambda function",
398
+ Value: { "Fn::GetAtt": ["UbeanFunction", "Arn"] }
399
+ }
400
+ }
401
+ };
402
+ if (options.environment && Object.keys(options.environment).length > 0) template.Resources.UbeanFunction.Properties.Environment = { Variables: options.environment };
403
+ return template;
404
+ }
405
+ /**
406
+ * 序列化 AWS SAM template 为 YAML 字符串
407
+ */
408
+ function serializeAwsSamConfig(template) {
409
+ return serializeYaml(template, 0);
410
+ }
411
+ function serializeYaml(value, indent) {
412
+ const pad = " ".repeat(indent);
413
+ if (value === null || value === void 0) return "null";
414
+ if (typeof value === "string") {
415
+ if (value.startsWith("Fn::") || value.startsWith("AWS::")) return value;
416
+ if (/^[\w./-]+$/.test(value) && !value.includes(" ")) return value;
417
+ return `"${escapeYamlString(value)}"`;
418
+ }
419
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
420
+ if (Array.isArray(value)) {
421
+ if (value.length === 0) return "[]";
422
+ return value.map((item) => `${pad}- ${serializeYaml(item, indent + 1).trimStart()}`).join("\n");
423
+ }
424
+ if (typeof value === "object") {
425
+ const entries = Object.entries(value).filter(([, v]) => v !== void 0 && v !== null);
426
+ if (entries.length === 0) return "{}";
427
+ return entries.map(([key, val]) => {
428
+ if (val !== null && typeof val === "object" && !Array.isArray(val)) {
429
+ const nested = serializeYaml(val, indent + 1);
430
+ if (nested === "{}") return `${pad}${key}: {}`;
431
+ return `${pad}${key}:\n${nested}`;
432
+ }
433
+ if (Array.isArray(val) && val.length > 0) {
434
+ const items = val.map((item) => {
435
+ if (item !== null && typeof item === "object") {
436
+ const nested = serializeYaml(item, indent + 2).trimStart();
437
+ return `${pad} - ${nested}`;
438
+ }
439
+ return `${pad} - ${serializeYaml(item, 0)}`;
440
+ }).join("\n");
441
+ return `${pad}${key}:\n${items}`;
442
+ }
443
+ return `${pad}${key}: ${serializeYaml(val, 0)}`;
444
+ }).join("\n");
445
+ }
446
+ return String(value);
447
+ }
448
+ function escapeYamlString(str) {
449
+ return str.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
450
+ }
451
+ /**
452
+ * Azure Static Web Apps preset
453
+ *
454
+ * 构建输出:`dist/azure/functions/index.mjs`(Azure Functions handler)
455
+ * 预览命令:`swa start`(Azure SWA CLI 本地模拟)
456
+ * 部署命令:`swa deploy`
457
+ *
458
+ * Azure Functions handler 签名:
459
+ * ```typescript
460
+ * export default async function handler(context, req) { ... };
461
+ * ```
462
+ */
463
+ const azurePreset = definePreset({
464
+ extends: "node",
465
+ capabilities: createCapabilitySet({
466
+ staticServe: true,
467
+ websocket: false,
468
+ sse: true,
469
+ cronTriggers: true,
470
+ queues: true,
471
+ kv: true,
472
+ storage: true,
473
+ database: true,
474
+ envVars: true,
475
+ secrets: true,
476
+ nodeCompat: true,
477
+ streaming: true,
478
+ compression: true,
479
+ https: true,
480
+ http2: true,
481
+ middleware: true,
482
+ bodyLimit: true,
483
+ multipart: true,
484
+ rpc: false
485
+ }),
486
+ entry: "server",
487
+ exportConditions: ["azure", "azure-functions"],
488
+ build: {
489
+ outputDir: "dist/azure",
490
+ format: "esm",
491
+ externals: [
492
+ "hono",
493
+ "c12",
494
+ "citty",
495
+ "tslog",
496
+ "defu",
497
+ "hookable",
498
+ "pathe",
499
+ "ufo",
500
+ "zod",
501
+ "@azure/*"
502
+ ]
503
+ },
504
+ output: {
505
+ dir: "dist/azure",
506
+ serverDir: "dist/azure/functions",
507
+ publicDir: "dist/azure/public"
508
+ },
509
+ runtime: {
510
+ entry: "functions/index.mjs",
511
+ handler: "handler",
512
+ compatibilityDate: "2024-09-01"
513
+ },
514
+ serve: {
515
+ host: "localhost",
516
+ port: 4280
517
+ },
518
+ commands: {
519
+ preview: "swa start",
520
+ deploy: "swa deploy"
521
+ },
522
+ hooks: {
523
+ "build:before": async () => {},
524
+ "build:after": async () => {}
525
+ }
526
+ }, {
527
+ name: "azure",
528
+ aliases: [
529
+ "azure-swa",
530
+ "azure-static-web-apps",
531
+ "swa",
532
+ "azure-functions"
533
+ ],
534
+ stdName: "azure_static_web_apps",
535
+ dev: true,
536
+ compatibilityDate: "2024-09-01",
537
+ url: "https://learn.microsoft.com/en-us/azure/static-web-apps/"
538
+ });
539
+ /**
540
+ * 生成 Azure Static Web Apps 配置对象
541
+ */
542
+ function generateStaticWebAppConfig(options) {
543
+ const config = {
544
+ platform: { apiRuntime: options.apiRuntime || "node:20" },
545
+ routes: options.routes || [{
546
+ route: "/api/*",
547
+ rewrite: options.apiEntry || "/api/functions"
548
+ }],
549
+ navigationFallback: { rewrite: options.navigationFallback || "/index.html" }
550
+ };
551
+ if (options.globalHeaders && Object.keys(options.globalHeaders).length > 0) config.globalHeaders = options.globalHeaders;
552
+ return config;
553
+ }
554
+ /**
555
+ * 序列化 staticwebapp.config.json 为 JSON 字符串
556
+ */
557
+ function serializeStaticWebAppConfig(config) {
558
+ return `${JSON.stringify(config, null, 2)}\n`;
559
+ }
560
+ /**
561
+ * Bun preset —— Bun 运行时模式
562
+ *
563
+ * 继承 Node preset 的全部能力,使用 Bun 运行时特性:
564
+ * - 原生 TypeScript 支持(无需编译)
565
+ * - 内置 SQLite (bun:sqlite)
566
+ * - 原生 WebSocket (Bun.serve)
567
+ * - 更快的启动和运行速度
568
+ *
569
+ * 构建输出:`dist/bun/server/index.mjs`
570
+ * 预览命令:`bun run dist/bun/server/index.mjs`
571
+ * 部署命令:`bun run dist/bun/server/index.mjs`
572
+ */
573
+ const bunPreset = definePreset({
574
+ extends: "node",
575
+ capabilities: createCapabilitySet({
576
+ staticServe: true,
577
+ websocket: true,
578
+ sse: true,
579
+ cronTriggers: true,
580
+ queues: false,
581
+ kv: false,
582
+ storage: true,
583
+ database: true,
584
+ envVars: true,
585
+ secrets: true,
586
+ nodeCompat: true,
587
+ streaming: true,
588
+ compression: true,
589
+ https: true,
590
+ http2: true,
591
+ middleware: true,
592
+ bodyLimit: true,
593
+ multipart: true,
594
+ rpc: false
595
+ }),
596
+ entry: "server",
597
+ exportConditions: ["bun"],
598
+ build: {
599
+ outputDir: "dist/bun",
600
+ format: "esm",
601
+ externals: [
602
+ "hono",
603
+ "c12",
604
+ "citty",
605
+ "tslog",
606
+ "defu",
607
+ "hookable",
608
+ "pathe",
609
+ "ufo",
610
+ "zod",
611
+ "bun:sqlite"
612
+ ]
613
+ },
614
+ output: {
615
+ dir: "dist/bun",
616
+ serverDir: "dist/bun/server",
617
+ publicDir: "dist/bun/public"
618
+ },
619
+ runtime: {
620
+ entry: "server/index.mjs",
621
+ handler: "handler",
622
+ compatibilityDate: "2024-09-01"
623
+ },
624
+ serve: {
625
+ host: "localhost",
626
+ port: 3e3
627
+ },
628
+ commands: {
629
+ preview: "bun run dist/bun/server/index.mjs",
630
+ deploy: "bun run dist/bun/server/index.mjs"
631
+ },
632
+ hooks: {
633
+ "build:before": async () => {},
634
+ "build:after": async () => {}
635
+ }
636
+ }, {
637
+ name: "bun",
638
+ aliases: ["bun-runtime"],
639
+ stdName: "bun",
640
+ dev: true,
641
+ compatibilityDate: "2024-09-01",
642
+ url: "https://bun.sh/docs/api/http"
643
+ });
644
+ /**
645
+ * 生成 Bunfig 配置对象
646
+ */
647
+ function generateBunfigConfig(options) {
648
+ const config = {};
649
+ if (options.registry !== void 0 || options.lockfile !== void 0 || options.production !== void 0) {
650
+ config.install = {};
651
+ if (options.registry) config.install.registry = options.registry;
652
+ if (options.lockfile !== void 0) config.install.lockfile = options.lockfile;
653
+ if (options.production !== void 0) config.install.production = options.production;
654
+ }
655
+ if (options.preload && options.preload.length > 0) config.test = { preload: options.preload };
656
+ return config;
657
+ }
658
+ /**
659
+ * 序列化 Bunfig 配置为 TOML 字符串
660
+ */
661
+ function serializeBunfigConfig(config) {
662
+ const lines = [];
663
+ if (config.install) {
664
+ lines.push("[install]");
665
+ if (config.install.registry) lines.push(`registry = "${escapeToml$2(config.install.registry)}"`);
666
+ if (config.install.lockfile !== void 0) lines.push(`lockfile = ${config.install.lockfile}`);
667
+ if (config.install.production !== void 0) lines.push(`production = ${config.install.production}`);
668
+ lines.push("");
669
+ }
670
+ if (config.test) {
671
+ lines.push("[test]");
672
+ if (config.test.coverage !== void 0) lines.push(`coverage = ${config.test.coverage}`);
673
+ if (config.test.coverageThreshold !== void 0) lines.push(`coverageThreshold = ${config.test.coverageThreshold}`);
674
+ if (config.test.preload && config.test.preload.length > 0) {
675
+ const preloads = config.test.preload.map((p) => `"${escapeToml$2(p)}"`).join(", ");
676
+ lines.push(`preload = [${preloads}]`);
677
+ }
678
+ lines.push("");
679
+ }
680
+ return `${lines.join("\n")}\n`;
681
+ }
682
+ function escapeToml$2(str) {
683
+ return str.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
684
+ }
246
685
  const cloudflarePreset = definePreset({
247
686
  capabilities: createCapabilitySet({
248
687
  staticServe: true,
@@ -275,7 +714,7 @@ const cloudflarePreset = definePreset({
275
714
  "hono",
276
715
  "c12",
277
716
  "citty",
278
- "consola",
717
+ "tslog",
279
718
  "defu",
280
719
  "hookable",
281
720
  "pathe",
@@ -374,18 +813,18 @@ function serializeWranglerToml(config) {
374
813
  const indent = "";
375
814
  function push(key, value, prefix = "") {
376
815
  if (value === void 0 || value === null) return;
377
- if (typeof value === "string") lines.push(`${prefix}${key} = "${escapeToml(value)}"`);
816
+ if (typeof value === "string") lines.push(`${prefix}${key} = "${escapeToml$1(value)}"`);
378
817
  else if (typeof value === "boolean") lines.push(`${prefix}${key} = ${value}`);
379
818
  else if (typeof value === "number") lines.push(`${prefix}${key} = ${value}`);
380
819
  else if (Array.isArray(value)) {
381
820
  if (value.length === 0) return;
382
821
  if (typeof value[0] === "string") {
383
- const items = value.map((v) => `"${escapeToml(String(v))}"`).join(", ");
822
+ const items = value.map((v) => `"${escapeToml$1(String(v))}"`).join(", ");
384
823
  lines.push(`${prefix}${key} = [${items}]`);
385
824
  } else {
386
825
  lines.push(`${prefix}[[${key}]]`);
387
826
  for (const item of value) lines.push(`${prefix} { ${Object.entries(item).filter(([, v]) => v !== void 0 && v !== null).map(([k, v]) => {
388
- if (typeof v === "string") return `${k} = "${escapeToml(v)}"`;
827
+ if (typeof v === "string") return `${k} = "${escapeToml$1(v)}"`;
389
828
  if (typeof v === "boolean") return `${k} = ${v}`;
390
829
  return `${k} = ${v}`;
391
830
  }).join(", ")} }`);
@@ -399,11 +838,11 @@ function serializeWranglerToml(config) {
399
838
  for (const item of v) {
400
839
  const itemEntries = Object.entries(item).filter(([, iv]) => iv !== void 0 && iv !== null);
401
840
  lines.push(itemEntries.map(([ik, iv]) => {
402
- if (typeof iv === "string") return `${prefix} ${ik} = "${escapeToml(iv)}"`;
841
+ if (typeof iv === "string") return `${prefix} ${ik} = "${escapeToml$1(iv)}"`;
403
842
  return `${prefix} ${ik} = ${iv}`;
404
843
  }).join("\n"));
405
844
  }
406
- } else if (typeof v === "string") lines.push(`${prefix}${k} = "${escapeToml(v)}"`);
845
+ } else if (typeof v === "string") lines.push(`${prefix}${k} = "${escapeToml$1(v)}"`);
407
846
  else if (typeof v === "boolean") lines.push(`${prefix}${k} = ${v}`);
408
847
  else if (typeof v === "number") lines.push(`${prefix}${k} = ${v}`);
409
848
  }
@@ -418,44 +857,291 @@ function serializeWranglerToml(config) {
418
857
  if (config.observability) push("observability", config.observability);
419
858
  if (config.kv_namespaces && config.kv_namespaces.length > 0) for (const ns of config.kv_namespaces) {
420
859
  const nsLines = [`${indent}[[kv_namespaces]]`];
421
- if (ns.binding) nsLines.push(`${indent}binding = "${escapeToml(ns.binding)}"`);
422
- if (ns.id) nsLines.push(`${indent}id = "${escapeToml(ns.id)}"`);
423
- if (ns.preview_id) nsLines.push(`${indent}preview_id = "${escapeToml(ns.preview_id)}"`);
860
+ if (ns.binding) nsLines.push(`${indent}binding = "${escapeToml$1(ns.binding)}"`);
861
+ if (ns.id) nsLines.push(`${indent}id = "${escapeToml$1(ns.id)}"`);
862
+ if (ns.preview_id) nsLines.push(`${indent}preview_id = "${escapeToml$1(ns.preview_id)}"`);
424
863
  lines.push(nsLines.join("\n"));
425
864
  }
426
865
  if (config.vars && Object.keys(config.vars).length > 0) {
427
866
  lines.push(`${indent}[vars]`);
428
- for (const [k, v] of Object.entries(config.vars)) lines.push(`${indent}${k} = "${escapeToml(v)}"`);
867
+ for (const [k, v] of Object.entries(config.vars)) lines.push(`${indent}${k} = "${escapeToml$1(v)}"`);
429
868
  }
430
869
  if (config.d1_databases && config.d1_databases.length > 0) for (const db of config.d1_databases) {
431
870
  const dbLines = [`${indent}[[d1_databases]]`];
432
- if (db.binding) dbLines.push(`${indent}binding = "${escapeToml(db.binding)}"`);
433
- if (db.database_id) dbLines.push(`${indent}database_id = "${escapeToml(db.database_id)}"`);
434
- if (db.preview_database_id) dbLines.push(`${indent}preview_database_id = "${escapeToml(db.preview_database_id)}"`);
871
+ if (db.binding) dbLines.push(`${indent}binding = "${escapeToml$1(db.binding)}"`);
872
+ if (db.database_id) dbLines.push(`${indent}database_id = "${escapeToml$1(db.database_id)}"`);
873
+ if (db.preview_database_id) dbLines.push(`${indent}preview_database_id = "${escapeToml$1(db.preview_database_id)}"`);
435
874
  lines.push(dbLines.join("\n"));
436
875
  }
437
876
  if (config.r2_buckets && config.r2_buckets.length > 0) for (const b of config.r2_buckets) {
438
877
  const bLines = [`${indent}[[r2_buckets]]`];
439
- if (b.binding) bLines.push(`${indent}binding = "${escapeToml(b.binding)}"`);
440
- if (b.bucket_name) bLines.push(`${indent}bucket_name = "${escapeToml(b.bucket_name)}"`);
441
- if (b.preview_bucket_name) bLines.push(`${indent}preview_bucket_name = "${escapeToml(b.preview_bucket_name)}"`);
878
+ if (b.binding) bLines.push(`${indent}binding = "${escapeToml$1(b.binding)}"`);
879
+ if (b.bucket_name) bLines.push(`${indent}bucket_name = "${escapeToml$1(b.bucket_name)}"`);
880
+ if (b.preview_bucket_name) bLines.push(`${indent}preview_bucket_name = "${escapeToml$1(b.preview_bucket_name)}"`);
442
881
  lines.push(bLines.join("\n"));
443
882
  }
444
883
  if (config.queues) {
445
884
  if (config.queues.producers && config.queues.producers.length > 0) for (const p of config.queues.producers) {
446
885
  const pLines = [`${indent}[[queues.producers]]`];
447
- if (p.binding) pLines.push(`${indent}binding = "${escapeToml(p.binding)}"`);
448
- if (p.queue) pLines.push(`${indent}queue = "${escapeToml(p.queue)}"`);
886
+ if (p.binding) pLines.push(`${indent}binding = "${escapeToml$1(p.binding)}"`);
887
+ if (p.queue) pLines.push(`${indent}queue = "${escapeToml$1(p.queue)}"`);
449
888
  lines.push(pLines.join("\n"));
450
889
  }
451
890
  if (config.queues.consumers && config.queues.consumers.length > 0) for (const c of config.queues.consumers) {
452
891
  const cLines = [`${indent}[[queues.consumers]]`];
453
- if (c.queue) cLines.push(`${indent}queue = "${escapeToml(c.queue)}"`);
892
+ if (c.queue) cLines.push(`${indent}queue = "${escapeToml$1(c.queue)}"`);
454
893
  lines.push(cLines.join("\n"));
455
894
  }
456
895
  }
457
896
  return `${lines.join("\n")}\n`;
458
897
  }
898
+ function escapeToml$1(str) {
899
+ return str.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
900
+ }
901
+ /**
902
+ * Deno preset —— Deno 运行时模式
903
+ *
904
+ * 继承 Node preset 的配置,使用 Deno 运行时特性:
905
+ * - 原生 TypeScript 支持(无需编译)
906
+ * - 内置 Deno KV / Deno.cron / Deno.Queue
907
+ * - 原生 WebSocket (Deno.serve)
908
+ * - 安全沙箱(默认无文件系统/网络访问,需显式授权)
909
+ *
910
+ * 构建输出:`dist/deno/server/index.mjs`
911
+ * 预览命令:`deno run --allow-net dist/deno/server/index.mjs`
912
+ * 部署命令:`deno run --allow-net dist/deno/server/index.mjs`
913
+ */
914
+ const denoPreset = definePreset({
915
+ extends: "node",
916
+ capabilities: createCapabilitySet({
917
+ staticServe: true,
918
+ websocket: true,
919
+ sse: true,
920
+ cronTriggers: true,
921
+ queues: true,
922
+ kv: true,
923
+ storage: true,
924
+ database: true,
925
+ envVars: true,
926
+ secrets: true,
927
+ nodeCompat: true,
928
+ streaming: true,
929
+ compression: true,
930
+ https: true,
931
+ http2: true,
932
+ middleware: true,
933
+ bodyLimit: true,
934
+ multipart: true,
935
+ rpc: false
936
+ }),
937
+ entry: "server",
938
+ exportConditions: ["deno"],
939
+ build: {
940
+ outputDir: "dist/deno",
941
+ format: "esm",
942
+ externals: [
943
+ "hono",
944
+ "c12",
945
+ "citty",
946
+ "tslog",
947
+ "defu",
948
+ "hookable",
949
+ "pathe",
950
+ "ufo",
951
+ "zod",
952
+ "node:*"
953
+ ]
954
+ },
955
+ output: {
956
+ dir: "dist/deno",
957
+ serverDir: "dist/deno/server",
958
+ publicDir: "dist/deno/public"
959
+ },
960
+ runtime: {
961
+ entry: "server/index.mjs",
962
+ handler: "handler",
963
+ compatibilityDate: "2024-09-01"
964
+ },
965
+ serve: {
966
+ host: "localhost",
967
+ port: 8e3
968
+ },
969
+ commands: {
970
+ preview: "deno run --allow-net --allow-env --allow-read dist/deno/server/index.mjs",
971
+ deploy: "deno run --allow-net --allow-env --allow-read dist/deno/server/index.mjs"
972
+ },
973
+ hooks: {
974
+ "build:before": async () => {},
975
+ "build:after": async () => {}
976
+ }
977
+ }, {
978
+ name: "deno",
979
+ aliases: ["deno-deploy", "deno-runtime"],
980
+ stdName: "deno",
981
+ dev: true,
982
+ compatibilityDate: "2024-09-01",
983
+ url: "https://docs.deno.com/runtime/manual"
984
+ });
985
+ /**
986
+ * 生成 Deno 配置对象
987
+ *
988
+ * @param options.lock - 传 `false` 禁用 lockfile,传字符串指定 lockfile 路径
989
+ */
990
+ function generateDenoConfig(options) {
991
+ const config = {};
992
+ if (options.tasks) config.tasks = options.tasks;
993
+ if (options.importMap) config.importMap = options.importMap;
994
+ if (options.lock !== void 0) config.lock = options.lock;
995
+ if (options.nodeModulesDir !== void 0) config.nodeModulesDir = options.nodeModulesDir;
996
+ if (options.unstable && options.unstable.length > 0) config.unstable = options.unstable;
997
+ return config;
998
+ }
999
+ /**
1000
+ * 序列化 Deno 配置为 JSON 字符串
1001
+ */
1002
+ function serializeDenoConfig(config) {
1003
+ return `${JSON.stringify(config, null, 2)}\n`;
1004
+ }
1005
+ /**
1006
+ * Netlify preset —— Netlify Functions 模式
1007
+ *
1008
+ * 构建输出:`dist/netlify/functions/index.mjs`(Netlify 自动检测 `functions/` 目录)
1009
+ * 预览命令:`netlify dev`
1010
+ * 部署命令:`netlify deploy --prod`
1011
+ */
1012
+ const netlifyPreset = definePreset({
1013
+ extends: "node",
1014
+ capabilities: createCapabilitySet({
1015
+ staticServe: true,
1016
+ websocket: false,
1017
+ sse: true,
1018
+ cronTriggers: true,
1019
+ queues: false,
1020
+ kv: true,
1021
+ storage: true,
1022
+ database: true,
1023
+ envVars: true,
1024
+ secrets: true,
1025
+ nodeCompat: true,
1026
+ streaming: true,
1027
+ compression: true,
1028
+ https: true,
1029
+ http2: true,
1030
+ middleware: true,
1031
+ bodyLimit: true,
1032
+ multipart: true,
1033
+ rpc: false
1034
+ }),
1035
+ entry: "server",
1036
+ exportConditions: ["netlify"],
1037
+ build: {
1038
+ outputDir: "dist/netlify",
1039
+ format: "esm",
1040
+ externals: [
1041
+ "hono",
1042
+ "c12",
1043
+ "citty",
1044
+ "tslog",
1045
+ "defu",
1046
+ "hookable",
1047
+ "pathe",
1048
+ "ufo",
1049
+ "zod"
1050
+ ]
1051
+ },
1052
+ output: {
1053
+ dir: "dist/netlify",
1054
+ serverDir: "dist/netlify/functions",
1055
+ publicDir: "dist/netlify/public"
1056
+ },
1057
+ runtime: {
1058
+ entry: "functions/index.mjs",
1059
+ handler: "handler"
1060
+ },
1061
+ serve: {
1062
+ host: "localhost",
1063
+ port: 8888
1064
+ },
1065
+ commands: {
1066
+ preview: "netlify dev",
1067
+ deploy: "netlify deploy --prod"
1068
+ },
1069
+ hooks: {
1070
+ "build:before": async () => {},
1071
+ "build:after": async () => {}
1072
+ }
1073
+ }, {
1074
+ name: "netlify",
1075
+ aliases: ["netlify-functions", "netlify-node"],
1076
+ stdName: "netlify",
1077
+ dev: true,
1078
+ compatibilityDate: "2024-09-01",
1079
+ url: "https://docs.netlify.com/functions/overview/"
1080
+ });
1081
+ /**
1082
+ * 生成 Netlify 配置对象
1083
+ */
1084
+ function generateNetlifyConfig(options) {
1085
+ const config = {
1086
+ build: {
1087
+ command: options.buildCommand || "pnpm build",
1088
+ publish: options.publishDir || "dist/netlify/public",
1089
+ functions: options.functionsDir || "dist/netlify/functions"
1090
+ },
1091
+ functions: {
1092
+ directory: options.functionsDir || "dist/netlify/functions",
1093
+ node_bundler: "esbuild"
1094
+ }
1095
+ };
1096
+ if (options.redirects && options.redirects.length > 0) config.redirects = options.redirects;
1097
+ if (options.headers && options.headers.length > 0) config.headers = options.headers;
1098
+ if (options.environment && Object.keys(options.environment).length > 0) config.build.environment = options.environment;
1099
+ return config;
1100
+ }
1101
+ /**
1102
+ * 序列化 Netlify 配置为 TOML 字符串
1103
+ */
1104
+ function serializeNetlifyConfig(config) {
1105
+ const lines = [];
1106
+ if (config.build) {
1107
+ lines.push("[build]");
1108
+ if (config.build.command) lines.push(`command = "${escapeToml(config.build.command)}"`);
1109
+ if (config.build.publish) lines.push(`publish = "${escapeToml(config.build.publish)}"`);
1110
+ if (config.build.functions) lines.push(`functions = "${escapeToml(config.build.functions)}"`);
1111
+ if (config.build.environment) {
1112
+ lines.push("");
1113
+ lines.push("[build.environment]");
1114
+ for (const [k, v] of Object.entries(config.build.environment)) lines.push(`${k} = "${escapeToml(v)}"`);
1115
+ }
1116
+ lines.push("");
1117
+ }
1118
+ if (config.functions) {
1119
+ lines.push("[functions]");
1120
+ if (config.functions.directory) lines.push(`directory = "${escapeToml(config.functions.directory)}"`);
1121
+ if (config.functions.node_bundler) lines.push(`node_bundler = "${config.functions.node_bundler}"`);
1122
+ if (config.functions.external_node_modules && config.functions.external_node_modules.length > 0) {
1123
+ const mods = config.functions.external_node_modules.map((m) => `"${escapeToml(m)}"`).join(", ");
1124
+ lines.push(`external_node_modules = [${mods}]`);
1125
+ }
1126
+ lines.push("");
1127
+ }
1128
+ if (config.redirects) for (const r of config.redirects) {
1129
+ lines.push("[[redirects]]");
1130
+ lines.push(`from = "${escapeToml(r.from)}"`);
1131
+ lines.push(`to = "${escapeToml(r.to)}"`);
1132
+ if (r.status) lines.push(`status = ${r.status}`);
1133
+ if (r.force) lines.push(`force = ${r.force}`);
1134
+ lines.push("");
1135
+ }
1136
+ if (config.headers) for (const h of config.headers) {
1137
+ lines.push("[[headers]]");
1138
+ lines.push(`for = "${escapeToml(h.for)}"`);
1139
+ lines.push("[headers.values]");
1140
+ for (const [k, v] of Object.entries(h.values)) lines.push(`"${k}" = "${escapeToml(v)}"`);
1141
+ lines.push("");
1142
+ }
1143
+ return `${lines.join("\n")}\n`;
1144
+ }
459
1145
  function escapeToml(str) {
460
1146
  return str.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
461
1147
  }
@@ -471,7 +1157,7 @@ const nodePreset = definePreset({
471
1157
  "hono",
472
1158
  "c12",
473
1159
  "citty",
474
- "consola",
1160
+ "tslog",
475
1161
  "defu",
476
1162
  "hookable",
477
1163
  "pathe",
@@ -512,7 +1198,7 @@ const standardPreset = definePreset({
512
1198
  "hono",
513
1199
  "c12",
514
1200
  "citty",
515
- "consola",
1201
+ "tslog",
516
1202
  "defu",
517
1203
  "hookable",
518
1204
  "pathe",
@@ -532,12 +1218,225 @@ const standardPreset = definePreset({
532
1218
  dev: true
533
1219
  });
534
1220
  //#endregion
1221
+ //#region src/vercel.ts
1222
+ /**
1223
+ * Vercel 能力矩阵
1224
+ *
1225
+ * Vercel 支持两种部署模式:
1226
+ * - **Serverless Functions**(`api/` 目录):Node.js 运行时,有冷启动,
1227
+ * 不支持 WebSocket / cron(无持久连接),支持大多数 Node.js API
1228
+ * - **Edge Functions**(基于 V8 isolates):无 Node.js 兼容,无 fs,
1229
+ * 支持流式响应,全球低延迟
1230
+ *
1231
+ * 默认按 Serverless Functions 配置(更通用);用户可通过 `extends: 'vercel-edge'`
1232
+ * 切换到 Edge 模式。
1233
+ */
1234
+ const VERCEL_CAPABILITIES = createCapabilitySet({
1235
+ staticServe: true,
1236
+ websocket: false,
1237
+ sse: true,
1238
+ cronTriggers: true,
1239
+ queues: false,
1240
+ kv: true,
1241
+ storage: true,
1242
+ database: true,
1243
+ envVars: true,
1244
+ secrets: true,
1245
+ nodeCompat: true,
1246
+ streaming: true,
1247
+ compression: true,
1248
+ https: true,
1249
+ http2: true,
1250
+ middleware: true,
1251
+ bodyLimit: true,
1252
+ multipart: true,
1253
+ rpc: false
1254
+ });
1255
+ /**
1256
+ * Vercel Edge 能力矩阵
1257
+ *
1258
+ * Edge Functions 基于 V8 isolates,无 Node.js 兼容层,
1259
+ * 但支持流式响应和全球低延迟。
1260
+ */
1261
+ const VERCEL_EDGE_CAPABILITIES = createCapabilitySet({
1262
+ staticServe: true,
1263
+ websocket: false,
1264
+ sse: true,
1265
+ cronTriggers: false,
1266
+ queues: false,
1267
+ kv: true,
1268
+ storage: true,
1269
+ database: false,
1270
+ envVars: true,
1271
+ secrets: true,
1272
+ nodeCompat: false,
1273
+ streaming: true,
1274
+ compression: false,
1275
+ https: true,
1276
+ http2: true,
1277
+ middleware: true,
1278
+ bodyLimit: true,
1279
+ multipart: false,
1280
+ rpc: false
1281
+ });
1282
+ /**
1283
+ * Vercel preset —— Serverless Functions 模式
1284
+ *
1285
+ * 构建输出:`dist/vercel/server/index.mjs`(供 Vercel 自动检测为 Serverless Function)
1286
+ * 预览命令:`vercel dev`
1287
+ * 部署命令:`vercel --prod`
1288
+ */
1289
+ const vercelPreset = definePreset({
1290
+ extends: "node",
1291
+ capabilities: VERCEL_CAPABILITIES,
1292
+ entry: "server",
1293
+ exportConditions: ["vercel"],
1294
+ build: {
1295
+ outputDir: "dist/vercel",
1296
+ format: "esm",
1297
+ externals: [
1298
+ "hono",
1299
+ "c12",
1300
+ "citty",
1301
+ "tslog",
1302
+ "defu",
1303
+ "hookable",
1304
+ "pathe",
1305
+ "ufo",
1306
+ "zod"
1307
+ ]
1308
+ },
1309
+ output: {
1310
+ dir: "dist/vercel",
1311
+ serverDir: "dist/vercel/server",
1312
+ publicDir: "dist/vercel/public"
1313
+ },
1314
+ runtime: {
1315
+ entry: "server/index.mjs",
1316
+ handler: "handler"
1317
+ },
1318
+ serve: {
1319
+ host: "localhost",
1320
+ port: 3e3
1321
+ },
1322
+ commands: {
1323
+ preview: "vercel dev",
1324
+ deploy: "vercel --prod"
1325
+ },
1326
+ hooks: {
1327
+ "build:before": async () => {},
1328
+ "build:after": async () => {}
1329
+ }
1330
+ }, {
1331
+ name: "vercel",
1332
+ aliases: ["vercel-serverless", "vercel-node"],
1333
+ stdName: "vercel",
1334
+ dev: true,
1335
+ compatibilityDate: "2024-09-01",
1336
+ url: "https://vercel.com/docs/functions/serverless-functions"
1337
+ });
1338
+ /**
1339
+ * Vercel Edge preset —— Edge Functions 模式
1340
+ *
1341
+ * 基于 V8 isolates,无 Node.js 兼容,全球低延迟。
1342
+ * 构建输出:`dist/vercel-edge/edge/index.mjs`
1343
+ */
1344
+ const vercelEdgePreset = definePreset({
1345
+ extends: "standard",
1346
+ capabilities: VERCEL_EDGE_CAPABILITIES,
1347
+ entry: "worker",
1348
+ exportConditions: ["edge-light", "vercel-edge"],
1349
+ build: {
1350
+ outputDir: "dist/vercel-edge",
1351
+ format: "esm",
1352
+ minify: true,
1353
+ externals: [
1354
+ "hono",
1355
+ "c12",
1356
+ "citty",
1357
+ "tslog",
1358
+ "defu",
1359
+ "hookable",
1360
+ "pathe",
1361
+ "ufo",
1362
+ "zod"
1363
+ ],
1364
+ rollupConfig: { external: ["node:*"] }
1365
+ },
1366
+ output: {
1367
+ dir: "dist/vercel-edge",
1368
+ serverDir: "dist/vercel-edge/edge",
1369
+ publicDir: "dist/vercel-edge/public"
1370
+ },
1371
+ runtime: {
1372
+ entry: "edge/index.mjs",
1373
+ handler: "fetch",
1374
+ compatibilityDate: "2024-09-01"
1375
+ },
1376
+ serve: {
1377
+ host: "localhost",
1378
+ port: 3e3
1379
+ },
1380
+ commands: {
1381
+ preview: "vercel dev",
1382
+ deploy: "vercel --prod"
1383
+ }
1384
+ }, {
1385
+ name: "vercel-edge",
1386
+ aliases: ["vercel-edge-function"],
1387
+ stdName: "vercel_edge",
1388
+ dev: true,
1389
+ compatibilityDate: "2024-09-01",
1390
+ url: "https://vercel.com/docs/functions/edge-functions"
1391
+ });
1392
+ /**
1393
+ * 生成 Vercel 配置对象
1394
+ */
1395
+ function generateVercelConfig(options) {
1396
+ const entry = options.entry || "dist/vercel/server/index.mjs";
1397
+ const config = {
1398
+ version: 2,
1399
+ functions: {}
1400
+ };
1401
+ config.functions[entry] = {
1402
+ memory: 1024,
1403
+ maxDuration: 10
1404
+ };
1405
+ if (options.functions) for (const [path, opts] of Object.entries(options.functions)) config.functions[path] = {
1406
+ memory: opts.memory ?? 1024,
1407
+ maxDuration: opts.maxDuration ?? 10
1408
+ };
1409
+ if (options.rewrites && options.rewrites.length > 0) config.rewrites = options.rewrites;
1410
+ if (options.redirects && options.redirects.length > 0) config.redirects = options.redirects;
1411
+ if (options.headers && options.headers.length > 0) config.headers = options.headers.map((h) => ({
1412
+ source: h.source,
1413
+ headers: Object.entries(h.headers).map(([key, value]) => ({
1414
+ key,
1415
+ value
1416
+ }))
1417
+ }));
1418
+ if (options.cron && options.cron.length > 0) config.cron = options.cron;
1419
+ if (options.env && Object.keys(options.env).length > 0) config.env = options.env;
1420
+ return config;
1421
+ }
1422
+ /**
1423
+ * 序列化 Vercel 配置为 JSON 字符串
1424
+ */
1425
+ function serializeVercelConfig(config) {
1426
+ return `${JSON.stringify(config, null, 2)}\n`;
1427
+ }
1428
+ //#endregion
535
1429
  //#region src/detect.ts
536
1430
  function getPresetDef(preset) {
537
1431
  return typeof preset === "function" ? preset() : preset;
538
1432
  }
539
1433
  function detectByConfigFiles(cwd) {
540
1434
  if (existsSync(join(cwd, "wrangler.toml")) || existsSync(join(cwd, "wrangler.json"))) return "cloudflare";
1435
+ if (existsSync(join(cwd, "vercel.json"))) return "vercel";
1436
+ if (existsSync(join(cwd, "netlify.toml"))) return "netlify";
1437
+ if (existsSync(join(cwd, "deno.json")) || existsSync(join(cwd, "deno.jsonc"))) return "deno";
1438
+ if (existsSync(join(cwd, "template.yaml")) || existsSync(join(cwd, "samconfig.toml"))) return "aws";
1439
+ if (existsSync(join(cwd, "staticwebapp.config.json"))) return "azure";
541
1440
  if (existsSync(join(cwd, "package.json"))) try {
542
1441
  const pkg = JSON.parse(readFileSync(join(cwd, "package.json"), "utf-8"));
543
1442
  const deps = {
@@ -545,14 +1444,27 @@ function detectByConfigFiles(cwd) {
545
1444
  ...pkg.devDependencies
546
1445
  };
547
1446
  if ("wrangler" in deps || "@cloudflare/workers-types" in deps) return "cloudflare";
1447
+ if ("vercel" in deps || "@vercel/node" in deps || "@vercel/edge" in deps) return "vercel";
1448
+ if ("netlify-cli" in deps || "netlify-lambda" in deps) return "netlify";
1449
+ if ("aws-sam-cli" in deps || "aws-cdk" in deps || "@aws-sdk/client-lambda" in deps) return "aws";
1450
+ if ("@azure/static-web-apps-cli" in deps || "@azure/functions" in deps) return "azure";
548
1451
  } catch {}
549
1452
  return null;
550
1453
  }
551
1454
  function detectByEnvironment(env, g) {
552
- if (env.CF_WORKERS || env.WRANGLER || env.CLOUDFLARE_WORKER) return "cloudflare";
553
- if (env.NODE_ENV === void 0 && "process" in g) return "node";
554
1455
  const gRecord = g;
1456
+ if (env.CF_WORKERS || env.WRANGLER || env.CLOUDFLARE_WORKER) return "cloudflare";
1457
+ if (env.VERCEL || env.VERCEL_ENV || env.NOW_ID) return "vercel";
1458
+ if (env.NETLIFY || env.NETLIFY_DEV || env.NETLIFY_IMAGES_CDN_DOMAIN !== void 0) return "netlify";
1459
+ if (env.AWS_LAMBDA_FUNCTION_NAME || env.AWS_EXECUTION_ENV || env.AWS_LAMBDA_RUNTIME_API) return "aws";
1460
+ if (env.AZURE_FUNCTIONS_ENVIRONMENT || env.WEBSITE_SITE_NAME || env.AZURE_HTTP_FUNCTION) return "azure";
1461
+ if (gRecord.Deno !== void 0) return "deno";
1462
+ if (gRecord.Bun !== void 0) return "bun";
1463
+ if (gRecord.process !== void 0) {
1464
+ if (gRecord.process.versions?.bun) return "bun";
1465
+ }
555
1466
  if (gRecord.CacheStorage !== void 0 && gRecord.Deno === void 0 && gRecord.process === void 0) return "cloudflare";
1467
+ if (env.NODE_ENV === void 0 && "process" in g) return "node";
556
1468
  if (gRecord.process !== void 0) {
557
1469
  if (gRecord.process.versions?.node) return "node";
558
1470
  }
@@ -579,7 +1491,14 @@ function detectPreset(hints = {}) {
579
1491
  if (preset) return {
580
1492
  preset,
581
1493
  source: "config-file",
582
- reason: configDetected === "cloudflare" ? "detected wrangler.toml or Cloudflare dependencies" : `detected ${configDetected} configuration`
1494
+ reason: {
1495
+ cloudflare: "detected wrangler.toml or Cloudflare dependencies",
1496
+ vercel: "detected vercel.json or Vercel dependencies",
1497
+ netlify: "detected netlify.toml or Netlify dependencies",
1498
+ deno: "detected deno.json",
1499
+ aws: "detected template.yaml (AWS SAM) or AWS dependencies",
1500
+ azure: "detected staticwebapp.config.json or Azure dependencies"
1501
+ }[configDetected] || `detected ${configDetected} configuration`
583
1502
  };
584
1503
  }
585
1504
  const envDetected = detectByEnvironment(env, g);
@@ -608,7 +1527,14 @@ function listDetectablePresets() {
608
1527
  getPresetDef(standardPreset),
609
1528
  getPresetDef(nodePreset),
610
1529
  getPresetDef(cloudflarePreset),
611
- getPresetDef(cloudflareDevPreset)
1530
+ getPresetDef(cloudflareDevPreset),
1531
+ getPresetDef(vercelPreset),
1532
+ getPresetDef(vercelEdgePreset),
1533
+ getPresetDef(netlifyPreset),
1534
+ getPresetDef(bunPreset),
1535
+ getPresetDef(denoPreset),
1536
+ getPresetDef(awsPreset),
1537
+ getPresetDef(azurePreset)
612
1538
  ];
613
1539
  }
614
1540
  //#endregion
@@ -617,7 +1543,14 @@ const builtinPresets = [
617
1543
  standardPreset,
618
1544
  nodePreset,
619
1545
  cloudflarePreset,
620
- cloudflareDevPreset
1546
+ cloudflareDevPreset,
1547
+ vercelPreset,
1548
+ vercelEdgePreset,
1549
+ netlifyPreset,
1550
+ bunPreset,
1551
+ denoPreset,
1552
+ awsPreset,
1553
+ azurePreset
621
1554
  ];
622
1555
  function registerBuiltinPresets() {
623
1556
  for (const preset of builtinPresets) registerPreset(preset);
@@ -647,4 +1580,4 @@ function resolvePresetByName(name) {
647
1580
  };
648
1581
  }
649
1582
  //#endregion
650
- export { DEV_REQUIREMENTS, NODE_CAPABILITIES, NODE_REQUIREMENTS, STANDARD_CAPABILITIES, WORKER_CAPABILITIES, cloudflareDevPreset, cloudflarePreset, createCapabilitySet, definePreset, detectPreset, diagnoseCapabilities, generateWranglerConfig, getPresetAliases, getPresetNames, getRegisteredPresets, listDetectablePresets, nodePreset, registerBuiltinPresets, registerPreset, requireCapability, resolvePreset, resolvePresetByName, resolvePresetWithDetection, serializeWranglerToml, standardPreset };
1583
+ export { DEV_REQUIREMENTS, NODE_CAPABILITIES, NODE_REQUIREMENTS, STANDARD_CAPABILITIES, WORKER_CAPABILITIES, awsPreset, azurePreset, bunPreset, cloudflareDevPreset, cloudflarePreset, createCapabilitySet, definePreset, denoPreset, detectPreset, diagnoseCapabilities, generateAwsSamConfig, generateBunfigConfig, generateDenoConfig, generateNetlifyConfig, generateStaticWebAppConfig, generateVercelConfig, generateWranglerConfig, getPresetAliases, getPresetNames, getRegisteredPresets, listDetectablePresets, netlifyPreset, nodePreset, registerBuiltinPresets, registerPreset, requireCapability, resolvePreset, resolvePresetByName, resolvePresetWithDetection, serializeAwsSamConfig, serializeBunfigConfig, serializeDenoConfig, serializeNetlifyConfig, serializeStaticWebAppConfig, serializeVercelConfig, serializeWranglerToml, standardPreset, vercelEdgePreset, vercelPreset };