create-taserjs 0.0.6 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/addons/prisma/index.cjs +12 -5
  3. package/dist/cjs/addons/prisma/index.cjs.map +1 -1
  4. package/dist/cjs/addons/registry.cjs +3 -1
  5. package/dist/cjs/addons/registry.cjs.map +1 -1
  6. package/dist/cjs/addons/validators.cjs +10 -13
  7. package/dist/cjs/addons/validators.cjs.map +1 -1
  8. package/dist/cjs/cli.cjs +7 -5
  9. package/dist/cjs/cli.cjs.map +1 -1
  10. package/dist/cjs/commands/create.cjs +72 -49
  11. package/dist/cjs/commands/create.cjs.map +1 -1
  12. package/dist/cjs/commands/create.d.cts +2 -1
  13. package/dist/cjs/core/parse-options.cjs +48 -22
  14. package/dist/cjs/core/parse-options.cjs.map +1 -1
  15. package/dist/cjs/core/parse-options.d.cts +19 -4
  16. package/dist/cjs/core/project-config.cjs +5 -1
  17. package/dist/cjs/core/project-config.cjs.map +1 -1
  18. package/dist/cjs/core/resolve-packages.cjs +35 -65
  19. package/dist/cjs/core/resolve-packages.cjs.map +1 -1
  20. package/dist/cjs/core/resolve-packages.d.cts +1 -4
  21. package/dist/cjs/core/scaffold-engine.cjs +16 -27
  22. package/dist/cjs/core/scaffold-engine.cjs.map +1 -1
  23. package/dist/cjs/core/targets.cjs +171 -0
  24. package/dist/cjs/core/targets.cjs.map +1 -0
  25. package/dist/cjs/core/targets.d.cts +49 -0
  26. package/dist/cjs/core/types.cjs +22 -11
  27. package/dist/cjs/core/types.cjs.map +1 -1
  28. package/dist/cjs/core/types.d.cts +20 -4
  29. package/dist/cjs/core/validate-project-name.cjs +0 -1
  30. package/dist/cjs/core/validate-project-name.cjs.map +1 -1
  31. package/dist/cjs/frameworks/index.cjs +79 -171
  32. package/dist/cjs/frameworks/index.cjs.map +1 -1
  33. package/dist/cjs/frameworks/index.d.cts +18 -3
  34. package/dist/cjs/scaffold.d.cts +2 -2
  35. package/dist/cjs/templates/base.cjs +15 -99
  36. package/dist/cjs/templates/base.cjs.map +1 -1
  37. package/dist/cjs/templates/base.d.cts +0 -3
  38. package/dist/cjs/types.d.cts +1 -1
  39. package/dist/esm/addons/prisma/index.js +12 -5
  40. package/dist/esm/addons/prisma/index.js.map +1 -1
  41. package/dist/esm/addons/registry.js +4 -2
  42. package/dist/esm/addons/registry.js.map +1 -1
  43. package/dist/esm/addons/validators.js +10 -13
  44. package/dist/esm/addons/validators.js.map +1 -1
  45. package/dist/esm/cli.js +7 -5
  46. package/dist/esm/cli.js.map +1 -1
  47. package/dist/esm/commands/create.d.ts +2 -1
  48. package/dist/esm/commands/create.js +74 -51
  49. package/dist/esm/commands/create.js.map +1 -1
  50. package/dist/esm/core/parse-options.d.ts +19 -4
  51. package/dist/esm/core/parse-options.js +47 -23
  52. package/dist/esm/core/parse-options.js.map +1 -1
  53. package/dist/esm/core/project-config.js +5 -1
  54. package/dist/esm/core/project-config.js.map +1 -1
  55. package/dist/esm/core/resolve-packages.d.ts +1 -4
  56. package/dist/esm/core/resolve-packages.js +35 -65
  57. package/dist/esm/core/resolve-packages.js.map +1 -1
  58. package/dist/esm/core/scaffold-engine.js +18 -29
  59. package/dist/esm/core/scaffold-engine.js.map +1 -1
  60. package/dist/esm/core/targets.d.ts +49 -0
  61. package/dist/esm/core/targets.js +166 -0
  62. package/dist/esm/core/targets.js.map +1 -0
  63. package/dist/esm/core/types.d.ts +20 -4
  64. package/dist/esm/core/types.js +20 -11
  65. package/dist/esm/core/types.js.map +1 -1
  66. package/dist/esm/core/validate-project-name.js +0 -1
  67. package/dist/esm/core/validate-project-name.js.map +1 -1
  68. package/dist/esm/frameworks/index.d.ts +18 -3
  69. package/dist/esm/frameworks/index.js +76 -171
  70. package/dist/esm/frameworks/index.js.map +1 -1
  71. package/dist/esm/scaffold.d.ts +2 -2
  72. package/dist/esm/templates/base.d.ts +0 -3
  73. package/dist/esm/templates/base.js +16 -98
  74. package/dist/esm/templates/base.js.map +1 -1
  75. package/dist/esm/types.d.ts +1 -1
  76. package/package.json +3 -2
  77. package/src/addons/prisma/index.ts +12 -5
  78. package/src/addons/registry.ts +6 -2
  79. package/src/addons/validators.ts +10 -13
  80. package/src/cli.ts +6 -4
  81. package/src/commands/create.ts +92 -26
  82. package/src/core/parse-options.ts +84 -35
  83. package/src/core/project-config.ts +6 -1
  84. package/src/core/resolve-packages.ts +37 -74
  85. package/src/core/scaffold-engine.ts +41 -65
  86. package/src/core/targets.ts +211 -0
  87. package/src/core/types.ts +40 -24
  88. package/src/core/validate-project-name.ts +0 -4
  89. package/src/frameworks/index.ts +80 -178
  90. package/src/scaffold.ts +2 -2
  91. package/src/templates/base.ts +14 -98
  92. package/src/types.ts +3 -1
@@ -1 +1 @@
1
- {"version":3,"file":"parse-options.js","names":[],"sources":["../../../src/core/parse-options.ts"],"sourcesContent":["import {\n DB_DRIVERS,\n DB_ODMS,\n DEFAULT_DB_DRIVER,\n LOGGERS,\n PROJECT_TYPES,\n VALIDATORS,\n type DbDriver,\n type DbOdm,\n type LoggerId,\n type ProjectType,\n type ScaffoldContext,\n type ValidatorId,\n} from \"./types.js\";\n\nexport type ParsedCreateArgs = {\n projectName?: string;\n type?: ProjectType;\n db?: DbOdm;\n driver?: DbDriver;\n logger?: LoggerId;\n validator?: ValidatorId;\n yes: boolean;\n noInstall: boolean;\n json: boolean;\n};\n\nfunction isProjectType(value: string): value is ProjectType {\n return (PROJECT_TYPES as readonly string[]).includes(value);\n}\n\nfunction isDbOdm(value: string): value is DbOdm {\n return (DB_ODMS as readonly string[]).includes(value);\n}\n\nfunction isDbDriver(value: string): value is DbDriver {\n return (DB_DRIVERS as readonly string[]).includes(value);\n}\n\nfunction isLoggerId(value: string): value is LoggerId {\n return (LOGGERS as readonly string[]).includes(value);\n}\n\nfunction isValidatorId(value: string): value is ValidatorId {\n return (VALIDATORS as readonly string[]).includes(value);\n}\n\nexport function parseDbFlag(value: string): { db: DbOdm; driver: DbDriver } {\n const [odm, driver] = value.split(\":\");\n if (!odm || !isDbOdm(odm)) {\n throw new Error(\n `Invalid --db value \"${value}\". Use drizzle, prisma, or kysely (optionally with :postgres, :sqlite, or :mysql).`,\n );\n }\n\n if (driver === undefined || driver === \"\") {\n return { db: odm, driver: DEFAULT_DB_DRIVER };\n }\n\n if (!isDbDriver(driver)) {\n throw new Error(`Invalid database driver \"${driver}\". Use postgres, sqlite, or mysql.`);\n }\n\n return { db: odm, driver };\n}\n\nexport function resolveScaffoldDefaults(args: ParsedCreateArgs): ScaffoldContext {\n const type = args.type ?? \"node\";\n const db = args.db;\n const logger = args.logger;\n const validator = args.validator;\n\n if (!args.projectName) {\n throw new Error(\"Project name is required\");\n }\n\n const result: ScaffoldContext = {\n projectName: args.projectName.trim(),\n targetDir: \"\",\n type,\n };\n\n if (db) {\n result.db = db;\n result.driver = args.driver ?? DEFAULT_DB_DRIVER;\n }\n\n if (logger) {\n result.logger = logger;\n }\n\n if (validator) {\n result.validator = validator;\n }\n\n return result;\n}\n\nexport function parseTypeFlag(value: string): ProjectType {\n if (!isProjectType(value)) {\n throw new Error(`Invalid --type \"${value}\". Use ${PROJECT_TYPES.join(\", \")}.`);\n }\n return value;\n}\n\nexport function parseLoggerFlag(value: string): LoggerId {\n if (!isLoggerId(value)) {\n throw new Error(`Invalid --logger \"${value}\". Use pino or winston.`);\n }\n return value;\n}\n\nexport function parseValidatorFlag(value: string): ValidatorId {\n if (!isValidatorId(value)) {\n throw new Error(`Invalid --validator \"${value}\". Use zod, arktype, or valibot.`);\n }\n return value;\n}\n"],"mappings":";;AA2BA,SAAS,cAAc,OAAqC;CAC1D,OAAQ,cAAoC,SAAS,KAAK;AAC5D;AAEA,SAAS,QAAQ,OAA+B;CAC9C,OAAQ,QAA8B,SAAS,KAAK;AACtD;AAEA,SAAS,WAAW,OAAkC;CACpD,OAAQ,WAAiC,SAAS,KAAK;AACzD;AAEA,SAAS,WAAW,OAAkC;CACpD,OAAQ,QAA8B,SAAS,KAAK;AACtD;AAEA,SAAS,cAAc,OAAqC;CAC1D,OAAQ,WAAiC,SAAS,KAAK;AACzD;AAEA,SAAgB,YAAY,OAAgD;CAC1E,MAAM,CAAC,KAAK,UAAU,MAAM,MAAM,GAAG;CACrC,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,GACtB,MAAM,IAAI,MACR,uBAAuB,MAAM,mFAC/B;CAGF,IAAI,WAAW,KAAA,KAAa,WAAW,IACrC,OAAO;EAAE,IAAI;EAAK,QAAQ;CAAkB;CAG9C,IAAI,CAAC,WAAW,MAAM,GACpB,MAAM,IAAI,MAAM,4BAA4B,OAAO,mCAAmC;CAGxF,OAAO;EAAE,IAAI;EAAK;CAAO;AAC3B;AAEA,SAAgB,wBAAwB,MAAyC;CAC/E,MAAM,OAAO,KAAK,QAAQ;CAC1B,MAAM,KAAK,KAAK;CAChB,MAAM,SAAS,KAAK;CACpB,MAAM,YAAY,KAAK;CAEvB,IAAI,CAAC,KAAK,aACR,MAAM,IAAI,MAAM,0BAA0B;CAG5C,MAAM,SAA0B;EAC9B,aAAa,KAAK,YAAY,KAAK;EACnC,WAAW;EACX;CACF;CAEA,IAAI,IAAI;EACN,OAAO,KAAK;EACZ,OAAO,SAAS,KAAK,UAAA;CACvB;CAEA,IAAI,QACF,OAAO,SAAS;CAGlB,IAAI,WACF,OAAO,YAAY;CAGrB,OAAO;AACT;AAEA,SAAgB,cAAc,OAA4B;CACxD,IAAI,CAAC,cAAc,KAAK,GACtB,MAAM,IAAI,MAAM,mBAAmB,MAAM,SAAS,cAAc,KAAK,IAAI,EAAE,EAAE;CAE/E,OAAO;AACT;AAEA,SAAgB,gBAAgB,OAAyB;CACvD,IAAI,CAAC,WAAW,KAAK,GACnB,MAAM,IAAI,MAAM,qBAAqB,MAAM,wBAAwB;CAErE,OAAO;AACT;AAEA,SAAgB,mBAAmB,OAA4B;CAC7D,IAAI,CAAC,cAAc,KAAK,GACtB,MAAM,IAAI,MAAM,wBAAwB,MAAM,iCAAiC;CAEjF,OAAO;AACT"}
1
+ {"version":3,"file":"parse-options.js","names":[],"sources":["../../../src/core/parse-options.ts"],"sourcesContent":["import {\n DB_DRIVERS,\n DB_ODMS,\n DEFAULT_DB_DRIVER,\n FRAMEWORKS,\n LOGGERS,\n RUNTIMES,\n VALIDATORS,\n type DbDriver,\n type DbOdm,\n type DeployTarget,\n type Framework,\n type LoggerId,\n type Runtime,\n type ScaffoldContext,\n type ValidatorId,\n} from \"./types.js\";\nimport {\n DEFAULT_DEPLOY,\n isCuratedDeploy,\n resolveDeployEntry,\n validateCombination,\n} from \"./targets.js\";\n\nexport type ParsedCreateArgs = {\n projectName?: string;\n framework?: Framework;\n /** Deployment target — a Nitro preset id. */\n preset?: string;\n runtime?: Runtime;\n db?: DbOdm;\n driver?: DbDriver;\n logger?: LoggerId;\n validator?: ValidatorId;\n yes: boolean;\n noInstall: boolean;\n json: boolean;\n};\n\nfunction isFramework(value: string): value is Framework {\n return (FRAMEWORKS as readonly string[]).includes(value);\n}\n\nfunction isRuntime(value: string): value is Runtime {\n return (RUNTIMES as readonly string[]).includes(value);\n}\n\nfunction isDbOdm(value: string): value is DbOdm {\n return (DB_ODMS as readonly string[]).includes(value);\n}\n\nfunction isDbDriver(value: string): value is DbDriver {\n return (DB_DRIVERS as readonly string[]).includes(value);\n}\n\nfunction isLoggerId(value: string): value is LoggerId {\n return (LOGGERS as readonly string[]).includes(value);\n}\n\nfunction isValidatorId(value: string): value is ValidatorId {\n return (VALIDATORS as readonly string[]).includes(value);\n}\n\nexport function parseDbFlag(value: string): { db: DbOdm; driver: DbDriver } {\n const [odm, driver] = value.split(\":\");\n if (!odm || !isDbOdm(odm)) {\n throw new Error(\n `Invalid --db value \"${value}\". Use drizzle, prisma, or kysely (optionally with :postgres, :sqlite, or :mysql).`,\n );\n }\n\n if (driver === undefined || driver === \"\") {\n return { db: odm, driver: DEFAULT_DB_DRIVER };\n }\n\n if (!isDbDriver(driver)) {\n throw new Error(`Invalid database driver \"${driver}\". Use postgres, sqlite, or mysql.`);\n }\n\n return { db: odm, driver };\n}\n\nexport function parseFrameworkFlag(value: string): Framework {\n if (!isFramework(value)) {\n throw new Error(`Invalid --framework \"${value}\". Use ${FRAMEWORKS.join(\", \")}.`);\n }\n return value;\n}\n\n/**\n * Accepts curated deploy targets verbatim; unknown ids pass through to Nitro.\n * Returns a warning for passthrough ids so callers can surface it.\n */\nexport function parsePresetFlag(value: string): { preset: string; warning?: string } {\n if (!isCuratedDeploy(value)) {\n if (!/^[a-z0-9][a-z0-9-_]*$/i.test(value)) {\n throw new Error(`Invalid --preset \"${value}\".`);\n }\n return {\n preset: value,\n warning: `\"${value}\" is not a curated Taser deploy target; passing it through to Nitro as-is.`,\n };\n }\n return { preset: value };\n}\n\nexport function parseRuntimeFlag(value: string): Runtime {\n if (!isRuntime(value)) {\n throw new Error(`Invalid --runtime \"${value}\". Use node, bun, or deno.`);\n }\n return value;\n}\n\nexport function parseLoggerFlag(value: string): LoggerId {\n if (!isLoggerId(value)) {\n throw new Error(`Invalid --logger \"${value}\". Use pino or winston.`);\n }\n return value;\n}\n\nexport function parseValidatorFlag(value: string): ValidatorId {\n if (!isValidatorId(value)) {\n throw new Error(`Invalid --validator \"${value}\". Use zod, arktype, or valibot.`);\n }\n return value;\n}\n\nexport function resolveScaffoldDefaults(args: ParsedCreateArgs): ScaffoldContext {\n const framework: Framework = args.framework ?? \"none\";\n const preset = args.preset ?? DEFAULT_DEPLOY;\n\n if (!args.projectName) {\n throw new Error(\"Project name is required\");\n }\n\n // Throws with a precise reason when runtime × framework × deploy clash.\n const combination = validateCombination(args.runtime, framework, preset);\n if (!combination.ok) {\n throw new Error(combination.reason);\n }\n\n const result: ScaffoldContext = {\n projectName: args.projectName.trim(),\n targetDir: \"\",\n framework,\n preset: preset as DeployTarget,\n ...(args.runtime !== undefined ? { runtime: args.runtime } : {}),\n };\n\n if (args.db) {\n result.db = args.db;\n result.driver = args.driver ?? DEFAULT_DB_DRIVER;\n }\n\n if (args.logger) {\n result.logger = args.logger;\n }\n\n if (args.validator) {\n result.validator = args.validator;\n }\n\n return result;\n}\n\n/** Re-exported for CLI layers that need to warn about passthrough presets. */\nexport { resolveDeployEntry };\n"],"mappings":";;;AAuCA,SAAS,YAAY,OAAmC;CACtD,OAAQ,WAAiC,SAAS,KAAK;AACzD;AAEA,SAAS,UAAU,OAAiC;CAClD,OAAQ,SAA+B,SAAS,KAAK;AACvD;AAEA,SAAS,QAAQ,OAA+B;CAC9C,OAAQ,QAA8B,SAAS,KAAK;AACtD;AAEA,SAAS,WAAW,OAAkC;CACpD,OAAQ,WAAiC,SAAS,KAAK;AACzD;AAEA,SAAS,WAAW,OAAkC;CACpD,OAAQ,QAA8B,SAAS,KAAK;AACtD;AAEA,SAAS,cAAc,OAAqC;CAC1D,OAAQ,WAAiC,SAAS,KAAK;AACzD;AAEA,SAAgB,YAAY,OAAgD;CAC1E,MAAM,CAAC,KAAK,UAAU,MAAM,MAAM,GAAG;CACrC,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,GACtB,MAAM,IAAI,MACR,uBAAuB,MAAM,mFAC/B;CAGF,IAAI,WAAW,KAAA,KAAa,WAAW,IACrC,OAAO;EAAE,IAAI;EAAK,QAAQ;CAAkB;CAG9C,IAAI,CAAC,WAAW,MAAM,GACpB,MAAM,IAAI,MAAM,4BAA4B,OAAO,mCAAmC;CAGxF,OAAO;EAAE,IAAI;EAAK;CAAO;AAC3B;AAEA,SAAgB,mBAAmB,OAA0B;CAC3D,IAAI,CAAC,YAAY,KAAK,GACpB,MAAM,IAAI,MAAM,wBAAwB,MAAM,SAAS,WAAW,KAAK,IAAI,EAAE,EAAE;CAEjF,OAAO;AACT;;;;;AAMA,SAAgB,gBAAgB,OAAqD;CACnF,IAAI,CAAC,gBAAgB,KAAK,GAAG;EAC3B,IAAI,CAAC,yBAAyB,KAAK,KAAK,GACtC,MAAM,IAAI,MAAM,qBAAqB,MAAM,GAAG;EAEhD,OAAO;GACL,QAAQ;GACR,SAAS,IAAI,MAAM;EACrB;CACF;CACA,OAAO,EAAE,QAAQ,MAAM;AACzB;AAEA,SAAgB,iBAAiB,OAAwB;CACvD,IAAI,CAAC,UAAU,KAAK,GAClB,MAAM,IAAI,MAAM,sBAAsB,MAAM,2BAA2B;CAEzE,OAAO;AACT;AAEA,SAAgB,gBAAgB,OAAyB;CACvD,IAAI,CAAC,WAAW,KAAK,GACnB,MAAM,IAAI,MAAM,qBAAqB,MAAM,wBAAwB;CAErE,OAAO;AACT;AAEA,SAAgB,mBAAmB,OAA4B;CAC7D,IAAI,CAAC,cAAc,KAAK,GACtB,MAAM,IAAI,MAAM,wBAAwB,MAAM,iCAAiC;CAEjF,OAAO;AACT;AAEA,SAAgB,wBAAwB,MAAyC;CAC/E,MAAM,YAAuB,KAAK,aAAa;CAC/C,MAAM,SAAS,KAAK,UAAA;CAEpB,IAAI,CAAC,KAAK,aACR,MAAM,IAAI,MAAM,0BAA0B;CAI5C,MAAM,cAAc,oBAAoB,KAAK,SAAS,WAAW,MAAM;CACvE,IAAI,CAAC,YAAY,IACf,MAAM,IAAI,MAAM,YAAY,MAAM;CAGpC,MAAM,SAA0B;EAC9B,aAAa,KAAK,YAAY,KAAK;EACnC,WAAW;EACX;EACQ;EACR,GAAI,KAAK,YAAY,KAAA,IAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;CAChE;CAEA,IAAI,KAAK,IAAI;EACX,OAAO,KAAK,KAAK;EACjB,OAAO,SAAS,KAAK,UAAA;CACvB;CAEA,IAAI,KAAK,QACP,OAAO,SAAS,KAAK;CAGvB,IAAI,KAAK,WACP,OAAO,YAAY,KAAK;CAG1B,OAAO;AACT"}
@@ -2,7 +2,11 @@ import path from "node:path";
2
2
  import { writeFile } from "node:fs/promises";
3
3
  //#region src/core/project-config.ts
4
4
  async function writeProjectConfig(root, ctx) {
5
- const config = { type: ctx.type };
5
+ const config = {
6
+ framework: ctx.framework ?? "none",
7
+ preset: ctx.preset ?? "node-server"
8
+ };
9
+ if (ctx.runtime) config.runtime = ctx.runtime;
6
10
  if (ctx.db) {
7
11
  config.db = ctx.db;
8
12
  if (ctx.driver) config.driver = ctx.driver;
@@ -1 +1 @@
1
- {"version":3,"file":"project-config.js","names":[],"sources":["../../../src/core/project-config.ts"],"sourcesContent":["import { writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { ScaffoldContext } from \"./types.js\";\n\nexport async function writeProjectConfig(root: string, ctx: ScaffoldContext): Promise<void> {\n const config: Record<string, string> = {\n type: ctx.type,\n };\n\n if (ctx.db) {\n config.db = ctx.db;\n if (ctx.driver) {\n config.driver = ctx.driver;\n }\n }\n\n if (ctx.logger) {\n config.logger = ctx.logger;\n }\n\n if (ctx.validator) {\n config.validator = ctx.validator;\n }\n\n await writeFile(path.join(root, \".taser.json\"), `${JSON.stringify(config, null, 2)}\\n`, \"utf8\");\n}\n"],"mappings":";;;AAKA,eAAsB,mBAAmB,MAAc,KAAqC;CAC1F,MAAM,SAAiC,EACrC,MAAM,IAAI,KACZ;CAEA,IAAI,IAAI,IAAI;EACV,OAAO,KAAK,IAAI;EAChB,IAAI,IAAI,QACN,OAAO,SAAS,IAAI;CAExB;CAEA,IAAI,IAAI,QACN,OAAO,SAAS,IAAI;CAGtB,IAAI,IAAI,WACN,OAAO,YAAY,IAAI;CAGzB,MAAM,UAAU,KAAK,KAAK,MAAM,aAAa,GAAG,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,KAAK,MAAM;AAChG"}
1
+ {"version":3,"file":"project-config.js","names":[],"sources":["../../../src/core/project-config.ts"],"sourcesContent":["import { writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { ScaffoldContext } from \"./types.js\";\n\nexport async function writeProjectConfig(root: string, ctx: ScaffoldContext): Promise<void> {\n const config: Record<string, string> = {\n framework: ctx.framework ?? \"none\",\n preset: ctx.preset ?? \"node-server\",\n };\n\n if (ctx.runtime) {\n config.runtime = ctx.runtime;\n }\n\n if (ctx.db) {\n config.db = ctx.db;\n if (ctx.driver) {\n config.driver = ctx.driver;\n }\n }\n\n if (ctx.logger) {\n config.logger = ctx.logger;\n }\n\n if (ctx.validator) {\n config.validator = ctx.validator;\n }\n\n await writeFile(path.join(root, \".taser.json\"), `${JSON.stringify(config, null, 2)}\\n`, \"utf8\");\n}\n"],"mappings":";;;AAKA,eAAsB,mBAAmB,MAAc,KAAqC;CAC1F,MAAM,SAAiC;EACrC,WAAW,IAAI,aAAa;EAC5B,QAAQ,IAAI,UAAU;CACxB;CAEA,IAAI,IAAI,SACN,OAAO,UAAU,IAAI;CAGvB,IAAI,IAAI,IAAI;EACV,OAAO,KAAK,IAAI;EAChB,IAAI,IAAI,QACN,OAAO,SAAS,IAAI;CAExB;CAEA,IAAI,IAAI,QACN,OAAO,SAAS,IAAI;CAGtB,IAAI,IAAI,WACN,OAAO,YAAY,IAAI;CAGzB,MAAM,UAAU,KAAK,KAAK,MAAM,aAAa,GAAG,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,KAAK,MAAM;AAChG"}
@@ -1,5 +1,2 @@
1
- import { PackageGroups, ProjectType, ScaffoldContext } from '../core/types.js';
1
+ import { PackageGroups, ScaffoldContext } from '../core/types.js';
2
2
  export declare function resolvePackages(ctx: ScaffoldContext): PackageGroups;
3
- export declare function getPackageGroups(type: ProjectType): Omit<PackageGroups, "scripts"> & {
4
- scripts?: Record<string, string>;
5
- };
@@ -1,75 +1,45 @@
1
1
  import { resolveAddons } from "../addons/registry.js";
2
+ import { resolveDeployEntry } from "./targets.js";
3
+ import { FRAMEWORK_ENTRIES } from "../frameworks/index.js";
2
4
  //#region src/core/resolve-packages.ts
3
- function typePackages(type) {
4
- const dependencies = ["@taserjs/router", "dotenv"];
5
+ var BASE_DEPENDENCIES = [
6
+ "@taserjs/router",
7
+ "dotenv",
8
+ "srvx"
9
+ ];
10
+ /** Runtime-agnostic build/dev tooling every scaffolded project needs. */
11
+ var BASE_DEV_DEPENDENCIES = [
12
+ "@taserjs/router-plugin",
13
+ "typescript@^5.9.3",
14
+ "vite@^8.1.5"
15
+ ];
16
+ function runtimeDevDeps(ctx) {
17
+ const { entry } = resolveDeployEntry(ctx.preset ?? "node-server");
18
+ switch (ctx.runtime ?? entry.impliedRuntime) {
19
+ case "bun": return ["@types/bun"];
20
+ case "deno": return [];
21
+ case "workerd": return ["@cloudflare/workers-types"];
22
+ default: return ["@types/node"];
23
+ }
24
+ }
25
+ function resolvePackages(ctx) {
26
+ const frameworkEntry = FRAMEWORK_ENTRIES[ctx.framework ?? "none"];
27
+ const { entry: deployEntry } = resolveDeployEntry(ctx.preset ?? "node-server");
28
+ const dependencies = [...BASE_DEPENDENCIES, ...frameworkEntry.deps];
29
+ const nitroDevDeps = ctx.preset === "none" ? [] : ["nitro"];
5
30
  const devDependencies = [
6
- "@taserjs/router-cli",
7
- "npm-run-all2",
8
- "tsdown",
9
- "tsx",
10
- "typescript@^5.9.3",
11
- "@types/node"
31
+ ...BASE_DEV_DEPENDENCIES,
32
+ ...nitroDevDeps,
33
+ ...runtimeDevDeps(ctx),
34
+ ...deployEntry.devDeps,
35
+ ...frameworkEntry.devDeps
12
36
  ];
13
37
  const scripts = {};
14
- switch (type) {
15
- case "express":
16
- dependencies.push("@taserjs/adapter-express", "express");
17
- devDependencies.push("@types/express");
18
- break;
19
- case "fastify":
20
- dependencies.push("@taserjs/adapter-fastify", "fastify");
21
- break;
22
- case "hono":
23
- dependencies.push("@hono/node-server", "hono");
24
- break;
25
- case "bun":
26
- devDependencies.push("@types/bun");
27
- scripts["dev:server"] = "bun --watch src/index.ts";
28
- scripts.start = "bun src/index.ts";
29
- scripts.serve = "bun dist/index.mjs";
30
- break;
31
- case "deno":
32
- scripts["dev:server"] = "deno run --watch --allow-net --allow-env --allow-read src/index.ts";
33
- scripts.start = "deno run --allow-net --allow-env --allow-read src/index.ts";
34
- scripts.serve = "deno run --allow-net --allow-env --allow-read dist/index.mjs";
35
- break;
36
- case "aws-lambda":
37
- dependencies.push("hono");
38
- devDependencies.push("@types/aws-lambda");
39
- break;
40
- case "cloudflare-workers": {
41
- const cfDevDeps = devDependencies.filter((d) => d !== "tsx");
42
- cfDevDeps.push("wrangler", "@cloudflare/workers-types");
43
- devDependencies.length = 0;
44
- devDependencies.push(...cfDevDeps);
45
- scripts["dev:server"] = "wrangler dev";
46
- scripts.deploy = "wrangler deploy";
47
- break;
48
- }
49
- case "netlify":
50
- dependencies.push("hono", "@netlify/functions");
51
- break;
52
- case "vercel":
53
- dependencies.push("hono");
54
- devDependencies.push("@vercel/node");
55
- break;
56
- case "azure-functions":
57
- dependencies.push("hono", "@azure/functions", "@marplex/hono-azurefunc-adapter");
58
- break;
59
- default: dependencies.push("@hono/node-server");
38
+ if (deployEntry.startScript) {
39
+ if (ctx.preset === "none" && ctx.runtime === "bun") scripts.start = "bun dist/serve.mjs";
40
+ else scripts.start = deployEntry.startScript;
60
41
  }
61
- return {
62
- dependencies,
63
- devDependencies,
64
- scripts
65
- };
66
- }
67
- function resolvePackages(ctx) {
68
- const base = typePackages(ctx.type);
69
42
  const addons = resolveAddons(ctx);
70
- const dependencies = [...base.dependencies];
71
- const devDependencies = [...base.devDependencies];
72
- const scripts = { ...base.scripts };
73
43
  for (const addon of addons) {
74
44
  dependencies.push(...addon.dependencies(ctx));
75
45
  devDependencies.push(...addon.devDependencies(ctx));
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-packages.js","names":[],"sources":["../../../src/core/resolve-packages.ts"],"sourcesContent":["import { resolveAddons } from \"../addons/registry.js\";\nimport type { PackageGroups, ProjectType, ScaffoldContext } from \"../core/types.js\";\n\nfunction typePackages(type: ProjectType): PackageGroups {\n const dependencies = [\"@taserjs/router\", \"dotenv\"];\n const devDependencies = [\n \"@taserjs/router-cli\",\n \"npm-run-all2\",\n \"tsdown\",\n \"tsx\",\n \"typescript@^5.9.3\",\n \"@types/node\",\n ];\n const scripts: Record<string, string> = {};\n\n switch (type) {\n case \"express\":\n dependencies.push(\"@taserjs/adapter-express\", \"express\");\n devDependencies.push(\"@types/express\");\n break;\n case \"fastify\":\n dependencies.push(\"@taserjs/adapter-fastify\", \"fastify\");\n break;\n case \"hono\":\n dependencies.push(\"@hono/node-server\", \"hono\");\n break;\n case \"bun\":\n // Bun has native TypeScript and runtime execution\n devDependencies.push(\"@types/bun\");\n scripts[\"dev:server\"] = \"bun --watch src/index.ts\";\n scripts.start = \"bun src/index.ts\";\n scripts.serve = \"bun dist/index.mjs\";\n break;\n case \"deno\":\n scripts[\"dev:server\"] = \"deno run --watch --allow-net --allow-env --allow-read src/index.ts\";\n scripts.start = \"deno run --allow-net --allow-env --allow-read src/index.ts\";\n scripts.serve = \"deno run --allow-net --allow-env --allow-read dist/index.mjs\";\n break;\n case \"aws-lambda\":\n dependencies.push(\"hono\");\n devDependencies.push(\"@types/aws-lambda\");\n break;\n case \"cloudflare-workers\": {\n // Cloudflare workers uses wrangler\n const cfDevDeps = devDependencies.filter((d) => d !== \"tsx\");\n cfDevDeps.push(\"wrangler\", \"@cloudflare/workers-types\");\n devDependencies.length = 0;\n devDependencies.push(...cfDevDeps);\n scripts[\"dev:server\"] = \"wrangler dev\";\n scripts.deploy = \"wrangler deploy\";\n break;\n }\n case \"netlify\":\n dependencies.push(\"hono\", \"@netlify/functions\");\n break;\n case \"vercel\":\n dependencies.push(\"hono\");\n devDependencies.push(\"@vercel/node\");\n break;\n case \"azure-functions\":\n dependencies.push(\"hono\", \"@azure/functions\", \"@marplex/hono-azurefunc-adapter\");\n break;\n case \"google-cloud-run\":\n case \"node\":\n default:\n dependencies.push(\"@hono/node-server\");\n break;\n }\n\n return { dependencies, devDependencies, scripts };\n}\n\nexport function resolvePackages(ctx: ScaffoldContext): PackageGroups {\n const base = typePackages(ctx.type);\n const addons = resolveAddons(ctx);\n\n const dependencies = [...base.dependencies];\n const devDependencies = [...base.devDependencies];\n const scripts = { ...base.scripts };\n\n for (const addon of addons) {\n dependencies.push(...addon.dependencies(ctx));\n devDependencies.push(...addon.devDependencies(ctx));\n if (addon.scripts) {\n Object.assign(scripts, addon.scripts(ctx));\n }\n }\n\n return {\n dependencies: [...new Set(dependencies)],\n devDependencies: [...new Set(devDependencies)],\n scripts,\n };\n}\n\nexport function getPackageGroups(\n type: ProjectType,\n): Omit<PackageGroups, \"scripts\"> & { scripts?: Record<string, string> } {\n const groups = typePackages(type);\n return groups;\n}\n"],"mappings":";;AAGA,SAAS,aAAa,MAAkC;CACtD,MAAM,eAAe,CAAC,mBAAmB,QAAQ;CACjD,MAAM,kBAAkB;EACtB;EACA;EACA;EACA;EACA;EACA;CACF;CACA,MAAM,UAAkC,CAAC;CAEzC,QAAQ,MAAR;EACE,KAAK;GACH,aAAa,KAAK,4BAA4B,SAAS;GACvD,gBAAgB,KAAK,gBAAgB;GACrC;EACF,KAAK;GACH,aAAa,KAAK,4BAA4B,SAAS;GACvD;EACF,KAAK;GACH,aAAa,KAAK,qBAAqB,MAAM;GAC7C;EACF,KAAK;GAEH,gBAAgB,KAAK,YAAY;GACjC,QAAQ,gBAAgB;GACxB,QAAQ,QAAQ;GAChB,QAAQ,QAAQ;GAChB;EACF,KAAK;GACH,QAAQ,gBAAgB;GACxB,QAAQ,QAAQ;GAChB,QAAQ,QAAQ;GAChB;EACF,KAAK;GACH,aAAa,KAAK,MAAM;GACxB,gBAAgB,KAAK,mBAAmB;GACxC;EACF,KAAK,sBAAsB;GAEzB,MAAM,YAAY,gBAAgB,QAAQ,MAAM,MAAM,KAAK;GAC3D,UAAU,KAAK,YAAY,2BAA2B;GACtD,gBAAgB,SAAS;GACzB,gBAAgB,KAAK,GAAG,SAAS;GACjC,QAAQ,gBAAgB;GACxB,QAAQ,SAAS;GACjB;EACF;EACA,KAAK;GACH,aAAa,KAAK,QAAQ,oBAAoB;GAC9C;EACF,KAAK;GACH,aAAa,KAAK,MAAM;GACxB,gBAAgB,KAAK,cAAc;GACnC;EACF,KAAK;GACH,aAAa,KAAK,QAAQ,oBAAoB,iCAAiC;GAC/E;EAGF,SACE,aAAa,KAAK,mBAAmB;CAEzC;CAEA,OAAO;EAAE;EAAc;EAAiB;CAAQ;AAClD;AAEA,SAAgB,gBAAgB,KAAqC;CACnE,MAAM,OAAO,aAAa,IAAI,IAAI;CAClC,MAAM,SAAS,cAAc,GAAG;CAEhC,MAAM,eAAe,CAAC,GAAG,KAAK,YAAY;CAC1C,MAAM,kBAAkB,CAAC,GAAG,KAAK,eAAe;CAChD,MAAM,UAAU,EAAE,GAAG,KAAK,QAAQ;CAElC,KAAK,MAAM,SAAS,QAAQ;EAC1B,aAAa,KAAK,GAAG,MAAM,aAAa,GAAG,CAAC;EAC5C,gBAAgB,KAAK,GAAG,MAAM,gBAAgB,GAAG,CAAC;EAClD,IAAI,MAAM,SACR,OAAO,OAAO,SAAS,MAAM,QAAQ,GAAG,CAAC;CAE7C;CAEA,OAAO;EACL,cAAc,CAAC,GAAG,IAAI,IAAI,YAAY,CAAC;EACvC,iBAAiB,CAAC,GAAG,IAAI,IAAI,eAAe,CAAC;EAC7C;CACF;AACF"}
1
+ {"version":3,"file":"resolve-packages.js","names":[],"sources":["../../../src/core/resolve-packages.ts"],"sourcesContent":["import { resolveAddons } from \"../addons/registry.js\";\nimport { FRAMEWORK_ENTRIES } from \"../frameworks/index.js\";\nimport type { PackageGroups, ScaffoldContext } from \"../core/types.js\";\nimport { resolveDeployEntry } from \"./targets.js\";\n\nconst BASE_DEPENDENCIES = [\"@taserjs/router\", \"dotenv\", \"srvx\"];\n\n/** Runtime-agnostic build/dev tooling every scaffolded project needs. */\nconst BASE_DEV_DEPENDENCIES = [\"@taserjs/router-plugin\", \"typescript@^5.9.3\", \"vite@^8.1.5\"];\n\nfunction runtimeDevDeps(ctx: ScaffoldContext): string[] {\n const { entry } = resolveDeployEntry(ctx.preset ?? \"node-server\");\n const effective = ctx.runtime ?? entry.impliedRuntime;\n switch (effective) {\n case \"bun\":\n return [\"@types/bun\"];\n case \"deno\":\n return []; // Deno ships its own tooling and types.\n case \"workerd\":\n return [\"@cloudflare/workers-types\"];\n case \"node\":\n default:\n return [\"@types/node\"];\n }\n}\n\nexport function resolvePackages(ctx: ScaffoldContext): PackageGroups {\n const frameworkEntry = FRAMEWORK_ENTRIES[ctx.framework ?? \"none\"];\n const { entry: deployEntry } = resolveDeployEntry(ctx.preset ?? \"node-server\");\n\n const dependencies = [...BASE_DEPENDENCIES, ...frameworkEntry.deps];\n const nitroDevDeps = ctx.preset === \"none\" ? [] : [\"nitro\"];\n const devDependencies = [\n ...BASE_DEV_DEPENDENCIES,\n ...nitroDevDeps,\n ...runtimeDevDeps(ctx),\n ...deployEntry.devDeps,\n ...frameworkEntry.devDeps,\n ];\n\n const scripts: Record<string, string> = {};\n if (deployEntry.startScript) {\n if (ctx.preset === \"none\" && ctx.runtime === \"bun\") {\n scripts.start = \"bun dist/serve.mjs\";\n } else {\n scripts.start = deployEntry.startScript;\n }\n }\n\n const addons = resolveAddons(ctx);\n for (const addon of addons) {\n dependencies.push(...addon.dependencies(ctx));\n devDependencies.push(...addon.devDependencies(ctx));\n if (addon.scripts) {\n Object.assign(scripts, addon.scripts(ctx));\n }\n }\n\n return {\n dependencies: [...new Set(dependencies)],\n devDependencies: [...new Set(devDependencies)],\n scripts,\n };\n}\n"],"mappings":";;;;AAKA,IAAM,oBAAoB;CAAC;CAAmB;CAAU;AAAM;;AAG9D,IAAM,wBAAwB;CAAC;CAA0B;CAAqB;AAAa;AAE3F,SAAS,eAAe,KAAgC;CACtD,MAAM,EAAE,UAAU,mBAAmB,IAAI,UAAU,aAAa;CAEhE,QADkB,IAAI,WAAW,MAAM,gBACvC;EACE,KAAK,OACH,OAAO,CAAC,YAAY;EACtB,KAAK,QACH,OAAO,CAAC;EACV,KAAK,WACH,OAAO,CAAC,2BAA2B;EAErC,SACE,OAAO,CAAC,aAAa;CACzB;AACF;AAEA,SAAgB,gBAAgB,KAAqC;CACnE,MAAM,iBAAiB,kBAAkB,IAAI,aAAa;CAC1D,MAAM,EAAE,OAAO,gBAAgB,mBAAmB,IAAI,UAAU,aAAa;CAE7E,MAAM,eAAe,CAAC,GAAG,mBAAmB,GAAG,eAAe,IAAI;CAClE,MAAM,eAAe,IAAI,WAAW,SAAS,CAAC,IAAI,CAAC,OAAO;CAC1D,MAAM,kBAAkB;EACtB,GAAG;EACH,GAAG;EACH,GAAG,eAAe,GAAG;EACrB,GAAG,YAAY;EACf,GAAG,eAAe;CACpB;CAEA,MAAM,UAAkC,CAAC;CACzC,IAAI,YAAY,aAAa;EAC3B,IAAI,IAAI,WAAW,UAAU,IAAI,YAAY,OAC3C,QAAQ,QAAQ;OAEhB,QAAQ,QAAQ,YAAY;CAEhC;CAEA,MAAM,SAAS,cAAc,GAAG;CAChC,KAAK,MAAM,SAAS,QAAQ;EAC1B,aAAa,KAAK,GAAG,MAAM,aAAa,GAAG,CAAC;EAC5C,gBAAgB,KAAK,GAAG,MAAM,gBAAgB,GAAG,CAAC;EAClD,IAAI,MAAM,SACR,OAAO,OAAO,SAAS,MAAM,QAAQ,GAAG,CAAC;CAE7C;CAEA,OAAO;EACL,cAAc,CAAC,GAAG,IAAI,IAAI,YAAY,CAAC;EACvC,iBAAiB,CAAC,GAAG,IAAI,IAAI,eAAe,CAAC;EAC7C;CACF;AACF"}
@@ -1,9 +1,10 @@
1
1
  import { collectBootBindings, resolveAddons } from "../addons/registry.js";
2
- import { indexTemplate, taserTsTemplate } from "../frameworks/index.js";
2
+ import { resolveDeployEntry, validateCombination } from "./targets.js";
3
+ import { FRAMEWORK_ENTRIES, nitroConfigTemplate, taserTsTemplate, viteConfigTemplate } from "../frameworks/index.js";
3
4
  import { installPackages, resolveUserAgent } from "./package-manager.js";
4
5
  import { writeProjectConfig } from "./project-config.js";
5
6
  import { resolvePackages } from "./resolve-packages.js";
6
- import { contextTemplate, gitignoreTemplate, healthRouteTemplate, indexRouteTemplate, packageJsonTemplate, rootLayoutTemplate, starterManifestTemplate, tsconfigTemplate, tsdownConfigTemplate } from "../templates/base.js";
7
+ import { contextTemplate, gitignoreTemplate, healthRouteTemplate, indexRouteTemplate, packageJsonTemplate, rootLayoutTemplate, tsconfigTemplate } from "../templates/base.js";
7
8
  import path from "node:path";
8
9
  import { copyFile, mkdir, writeFile } from "node:fs/promises";
9
10
  //#region src/core/scaffold-engine.ts
@@ -13,10 +14,16 @@ async function write(filePath, contents) {
13
14
  }
14
15
  async function scaffoldProject(options) {
15
16
  const root = options.targetDir;
17
+ const preset = options.preset ?? "node-server";
18
+ const framework = options.framework ?? "none";
19
+ const combination = validateCombination(options.runtime, framework, preset);
20
+ if (!combination.ok) throw new Error(combination.reason);
16
21
  const ctx = {
17
22
  projectName: options.projectName,
18
23
  targetDir: root,
19
- type: options.type,
24
+ framework,
25
+ preset,
26
+ ...options.runtime !== void 0 ? { runtime: options.runtime } : {},
20
27
  ...options.db ? {
21
28
  db: options.db,
22
29
  driver: options.driver
@@ -27,39 +34,21 @@ async function scaffoldProject(options) {
27
34
  const addons = resolveAddons(ctx);
28
35
  const packages = resolvePackages(ctx);
29
36
  const bootBindings = collectBootBindings(ctx);
37
+ const frameworkEntry = FRAMEWORK_ENTRIES[framework];
38
+ const { entry: deployEntry } = resolveDeployEntry(ctx.preset ?? "node-server");
30
39
  await write(path.join(root, "package.json"), packageJsonTemplate(options.projectName, packages.scripts));
31
40
  await write(path.join(root, "tsconfig.json"), tsconfigTemplate());
32
- await write(path.join(root, "tsdown.config.ts"), tsdownConfigTemplate());
41
+ await write(path.join(root, "vite.config.ts"), viteConfigTemplate(ctx.preset));
33
42
  await write(path.join(root, ".gitignore"), gitignoreTemplate());
34
43
  await write(path.join(root, "src/context.ts"), contextTemplate(bootBindings));
35
- await write(path.join(root, "src/taser.ts"), taserTsTemplate(options.type));
36
- await write(path.join(root, "src/index.ts"), indexTemplate(options.type));
44
+ await write(path.join(root, "src/taser.ts"), taserTsTemplate());
37
45
  await write(path.join(root, "src/routes/$.ts"), rootLayoutTemplate());
38
46
  await write(path.join(root, "src/routes/index.get.ts"), indexRouteTemplate());
39
47
  await write(path.join(root, "src/routes/health.get.ts"), healthRouteTemplate(ctx));
40
- await write(path.join(root, "src/routeManifest.gen.ts"), starterManifestTemplate());
41
- if (options.type === "cloudflare-workers") await write(path.join(root, "wrangler.jsonc"), JSON.stringify({
42
- $schema: "node_modules/wrangler/config-schema.json",
43
- name: options.projectName,
44
- main: "src/index.ts",
45
- compatibility_date: "2024-11-01"
46
- }, null, 2) + "\n");
47
- if (options.type === "vercel") await write(path.join(root, "vercel.json"), JSON.stringify({ rewrites: [{
48
- source: "/(.*)",
49
- destination: "/src/index.ts"
50
- }] }, null, 2) + "\n");
51
- if (options.type === "azure-functions") await write(path.join(root, "host.json"), JSON.stringify({
52
- version: "2.0",
53
- logging: { applicationInsights: { samplingSettings: {
54
- isEnabled: true,
55
- excludedTypes: "Request"
56
- } } },
57
- extensionBundle: {
58
- id: "Microsoft.Azure.Functions.ExtensionBundle",
59
- version: "[4.*, 5.0.0)"
60
- },
61
- extensions: { http: { routePrefix: "" } }
62
- }, null, 2) + "\n");
48
+ if (ctx.preset !== "node-server" && ctx.preset !== "none") await write(path.join(root, "nitro.config.ts"), nitroConfigTemplate(deployEntry.id));
49
+ await Promise.all(deployEntry.files.map((file) => write(path.join(root, file.name), typeof file.content === "function" ? file.content({ projectName: options.projectName }) : file.content)));
50
+ const serverEntry = frameworkEntry.serverEntry;
51
+ if (serverEntry) await write(path.join(root, serverEntry.fileName), serverEntry.content);
63
52
  await Promise.all(addons.map(async (addon) => {
64
53
  await addon.apply(ctx, (filePath, contents) => write(path.join(root, filePath), contents));
65
54
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold-engine.js","names":[],"sources":["../../../src/core/scaffold-engine.ts"],"sourcesContent":["import { copyFile, mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport { collectBootBindings, resolveAddons } from \"../addons/registry.js\";\nimport { indexTemplate, taserTsTemplate } from \"../frameworks/index.js\";\nimport { installPackages, resolveUserAgent } from \"./package-manager.js\";\nimport { writeProjectConfig } from \"./project-config.js\";\nimport { resolvePackages } from \"./resolve-packages.js\";\nimport type { ScaffoldOptions, ScaffoldResult } from \"./types.js\";\nimport {\n contextTemplate,\n gitignoreTemplate,\n healthRouteTemplate,\n indexRouteTemplate,\n packageJsonTemplate,\n rootLayoutTemplate,\n starterManifestTemplate,\n tsconfigTemplate,\n tsdownConfigTemplate,\n} from \"../templates/base.js\";\n\nasync function write(filePath: string, contents: string): Promise<void> {\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, contents, \"utf8\");\n}\n\nexport async function scaffoldProject(options: ScaffoldOptions): Promise<ScaffoldResult> {\n const root = options.targetDir;\n const ctx = {\n projectName: options.projectName,\n targetDir: root,\n type: options.type,\n ...(options.db ? { db: options.db, driver: options.driver } : {}),\n ...(options.logger ? { logger: options.logger } : {}),\n ...(options.validator ? { validator: options.validator } : {}),\n };\n\n const addons = resolveAddons(ctx);\n const packages = resolvePackages(ctx);\n const bootBindings = collectBootBindings(ctx);\n\n await write(\n path.join(root, \"package.json\"),\n packageJsonTemplate(options.projectName, packages.scripts),\n );\n await write(path.join(root, \"tsconfig.json\"), tsconfigTemplate());\n await write(path.join(root, \"tsdown.config.ts\"), tsdownConfigTemplate());\n await write(path.join(root, \".gitignore\"), gitignoreTemplate());\n await write(path.join(root, \"src/context.ts\"), contextTemplate(bootBindings));\n await write(path.join(root, \"src/taser.ts\"), taserTsTemplate(options.type));\n await write(path.join(root, \"src/index.ts\"), indexTemplate(options.type));\n await write(path.join(root, \"src/routes/$.ts\"), rootLayoutTemplate());\n await write(path.join(root, \"src/routes/index.get.ts\"), indexRouteTemplate());\n await write(path.join(root, \"src/routes/health.get.ts\"), healthRouteTemplate(ctx));\n await write(path.join(root, \"src/routeManifest.gen.ts\"), starterManifestTemplate());\n\n if (options.type === \"cloudflare-workers\") {\n await write(\n path.join(root, \"wrangler.jsonc\"),\n JSON.stringify(\n {\n $schema: \"node_modules/wrangler/config-schema.json\",\n name: options.projectName,\n main: \"src/index.ts\",\n compatibility_date: \"2024-11-01\",\n },\n null,\n 2,\n ) + \"\\n\",\n );\n }\n\n if (options.type === \"vercel\") {\n await write(\n path.join(root, \"vercel.json\"),\n JSON.stringify(\n {\n rewrites: [{ source: \"/(.*)\", destination: \"/src/index.ts\" }],\n },\n null,\n 2,\n ) + \"\\n\",\n );\n }\n\n if (options.type === \"azure-functions\") {\n await write(\n path.join(root, \"host.json\"),\n JSON.stringify(\n {\n version: \"2.0\",\n logging: {\n applicationInsights: {\n samplingSettings: {\n isEnabled: true,\n excludedTypes: \"Request\",\n },\n },\n },\n extensionBundle: {\n id: \"Microsoft.Azure.Functions.ExtensionBundle\",\n version: \"[4.*, 5.0.0)\",\n },\n extensions: {\n http: {\n routePrefix: \"\",\n },\n },\n },\n null,\n 2,\n ) + \"\\n\",\n );\n }\n\n await Promise.all(\n addons.map(async (addon) => {\n await addon.apply(ctx, (filePath, contents) => write(path.join(root, filePath), contents));\n }),\n );\n\n try {\n await copyFile(path.join(root, \".env.example\"), path.join(root, \".env\"));\n } catch {\n // .env.example was not created\n }\n\n await writeProjectConfig(root, ctx);\n\n if (options.skipInstall) {\n return ctx as ScaffoldResult;\n }\n\n const agent = options.agent ?? resolveUserAgent();\n await installPackages(agent, root, {\n dependencies: packages.dependencies,\n devDependencies: packages.devDependencies,\n });\n\n return ctx as ScaffoldResult;\n}\n"],"mappings":";;;;;;;;;AAqBA,eAAe,MAAM,UAAkB,UAAiC;CACtE,MAAM,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;CACvD,MAAM,UAAU,UAAU,UAAU,MAAM;AAC5C;AAEA,eAAsB,gBAAgB,SAAmD;CACvF,MAAM,OAAO,QAAQ;CACrB,MAAM,MAAM;EACV,aAAa,QAAQ;EACrB,WAAW;EACX,MAAM,QAAQ;EACd,GAAI,QAAQ,KAAK;GAAE,IAAI,QAAQ;GAAI,QAAQ,QAAQ;EAAO,IAAI,CAAC;EAC/D,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;EACnD,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;CAC9D;CAEA,MAAM,SAAS,cAAc,GAAG;CAChC,MAAM,WAAW,gBAAgB,GAAG;CACpC,MAAM,eAAe,oBAAoB,GAAG;CAE5C,MAAM,MACJ,KAAK,KAAK,MAAM,cAAc,GAC9B,oBAAoB,QAAQ,aAAa,SAAS,OAAO,CAC3D;CACA,MAAM,MAAM,KAAK,KAAK,MAAM,eAAe,GAAG,iBAAiB,CAAC;CAChE,MAAM,MAAM,KAAK,KAAK,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;CACvE,MAAM,MAAM,KAAK,KAAK,MAAM,YAAY,GAAG,kBAAkB,CAAC;CAC9D,MAAM,MAAM,KAAK,KAAK,MAAM,gBAAgB,GAAG,gBAAgB,YAAY,CAAC;CAC5E,MAAM,MAAM,KAAK,KAAK,MAAM,cAAc,GAAG,gBAAgB,QAAQ,IAAI,CAAC;CAC1E,MAAM,MAAM,KAAK,KAAK,MAAM,cAAc,GAAG,cAAc,QAAQ,IAAI,CAAC;CACxE,MAAM,MAAM,KAAK,KAAK,MAAM,iBAAiB,GAAG,mBAAmB,CAAC;CACpE,MAAM,MAAM,KAAK,KAAK,MAAM,yBAAyB,GAAG,mBAAmB,CAAC;CAC5E,MAAM,MAAM,KAAK,KAAK,MAAM,0BAA0B,GAAG,oBAAoB,GAAG,CAAC;CACjF,MAAM,MAAM,KAAK,KAAK,MAAM,0BAA0B,GAAG,wBAAwB,CAAC;CAElF,IAAI,QAAQ,SAAS,sBACnB,MAAM,MACJ,KAAK,KAAK,MAAM,gBAAgB,GAChC,KAAK,UACH;EACE,SAAS;EACT,MAAM,QAAQ;EACd,MAAM;EACN,oBAAoB;CACtB,GACA,MACA,CACF,IAAI,IACN;CAGF,IAAI,QAAQ,SAAS,UACnB,MAAM,MACJ,KAAK,KAAK,MAAM,aAAa,GAC7B,KAAK,UACH,EACE,UAAU,CAAC;EAAE,QAAQ;EAAS,aAAa;CAAgB,CAAC,EAC9D,GACA,MACA,CACF,IAAI,IACN;CAGF,IAAI,QAAQ,SAAS,mBACnB,MAAM,MACJ,KAAK,KAAK,MAAM,WAAW,GAC3B,KAAK,UACH;EACE,SAAS;EACT,SAAS,EACP,qBAAqB,EACnB,kBAAkB;GAChB,WAAW;GACX,eAAe;EACjB,EACF,EACF;EACA,iBAAiB;GACf,IAAI;GACJ,SAAS;EACX;EACA,YAAY,EACV,MAAM,EACJ,aAAa,GACf,EACF;CACF,GACA,MACA,CACF,IAAI,IACN;CAGF,MAAM,QAAQ,IACZ,OAAO,IAAI,OAAO,UAAU;EAC1B,MAAM,MAAM,MAAM,MAAM,UAAU,aAAa,MAAM,KAAK,KAAK,MAAM,QAAQ,GAAG,QAAQ,CAAC;CAC3F,CAAC,CACH;CAEA,IAAI;EACF,MAAM,SAAS,KAAK,KAAK,MAAM,cAAc,GAAG,KAAK,KAAK,MAAM,MAAM,CAAC;CACzE,QAAQ,CAER;CAEA,MAAM,mBAAmB,MAAM,GAAG;CAElC,IAAI,QAAQ,aACV,OAAO;CAGT,MAAM,QAAQ,QAAQ,SAAS,iBAAiB;CAChD,MAAM,gBAAgB,OAAO,MAAM;EACjC,cAAc,SAAS;EACvB,iBAAiB,SAAS;CAC5B,CAAC;CAED,OAAO;AACT"}
1
+ {"version":3,"file":"scaffold-engine.js","names":[],"sources":["../../../src/core/scaffold-engine.ts"],"sourcesContent":["import { copyFile, mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport { collectBootBindings, resolveAddons } from \"../addons/registry.js\";\nimport { nitroConfigTemplate, taserTsTemplate, viteConfigTemplate } from \"../frameworks/index.js\";\nimport { installPackages, resolveUserAgent } from \"./package-manager.js\";\nimport { writeProjectConfig } from \"./project-config.js\";\nimport { resolvePackages } from \"./resolve-packages.js\";\nimport { resolveDeployEntry, validateCombination } from \"./targets.js\";\nimport { FRAMEWORK_ENTRIES } from \"../frameworks/index.js\";\nimport type { ScaffoldContext, ScaffoldOptions, ScaffoldResult } from \"./types.js\";\nimport {\n contextTemplate,\n gitignoreTemplate,\n healthRouteTemplate,\n indexRouteTemplate,\n packageJsonTemplate,\n rootLayoutTemplate,\n tsconfigTemplate,\n} from \"../templates/base.js\";\n\nasync function write(filePath: string, contents: string): Promise<void> {\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, contents, \"utf8\");\n}\n\nexport async function scaffoldProject(options: ScaffoldOptions): Promise<ScaffoldResult> {\n const root = options.targetDir;\n const preset = options.preset ?? \"node-server\";\n const framework = options.framework ?? \"none\";\n\n // Guards direct/library callers; the CLI path is validated earlier in\n // resolveScaffoldDefaults. Throws with a precise reason on impossible\n // runtime × framework × deploy combinations.\n const combination = validateCombination(options.runtime, framework, preset);\n if (!combination.ok) {\n throw new Error(combination.reason);\n }\n\n const ctx: ScaffoldContext = {\n projectName: options.projectName,\n targetDir: root,\n framework,\n preset,\n ...(options.runtime !== undefined ? { runtime: options.runtime } : {}),\n ...(options.db ? { db: options.db, driver: options.driver } : {}),\n ...(options.logger ? { logger: options.logger } : {}),\n ...(options.validator ? { validator: options.validator } : {}),\n };\n\n const addons = resolveAddons(ctx);\n const packages = resolvePackages(ctx);\n const bootBindings = collectBootBindings(ctx);\n const frameworkEntry = FRAMEWORK_ENTRIES[framework];\n const { entry: deployEntry } = resolveDeployEntry(ctx.preset ?? \"node-server\");\n\n await write(\n path.join(root, \"package.json\"),\n packageJsonTemplate(options.projectName, packages.scripts),\n );\n await write(path.join(root, \"tsconfig.json\"), tsconfigTemplate());\n await write(path.join(root, \"vite.config.ts\"), viteConfigTemplate(ctx.preset));\n await write(path.join(root, \".gitignore\"), gitignoreTemplate());\n await write(path.join(root, \"src/context.ts\"), contextTemplate(bootBindings));\n await write(path.join(root, \"src/taser.ts\"), taserTsTemplate());\n await write(path.join(root, \"src/routes/$.ts\"), rootLayoutTemplate());\n await write(path.join(root, \"src/routes/index.get.ts\"), indexRouteTemplate());\n await write(path.join(root, \"src/routes/health.get.ts\"), healthRouteTemplate(ctx));\n\n // Nitro's default preset is node-server — only emit an explicit config when\n // the deployment target differs. Do not emit for preset \"none\".\n if (ctx.preset !== \"node-server\" && ctx.preset !== \"none\") {\n await write(path.join(root, \"nitro.config.ts\"), nitroConfigTemplate(deployEntry.id));\n }\n\n await Promise.all(\n deployEntry.files.map((file) =>\n write(\n path.join(root, file.name),\n typeof file.content === \"function\"\n ? file.content({ projectName: options.projectName })\n : file.content,\n ),\n ),\n );\n\n const serverEntry = frameworkEntry.serverEntry;\n if (serverEntry) {\n await write(path.join(root, serverEntry.fileName), serverEntry.content);\n }\n\n await Promise.all(\n addons.map(async (addon) => {\n await addon.apply(ctx, (filePath, contents) => write(path.join(root, filePath), contents));\n }),\n );\n\n try {\n await copyFile(path.join(root, \".env.example\"), path.join(root, \".env\"));\n } catch {\n // .env.example was not created\n }\n\n await writeProjectConfig(root, ctx);\n\n if (options.skipInstall) {\n return ctx as ScaffoldResult;\n }\n\n const agent = options.agent ?? resolveUserAgent();\n await installPackages(agent, root, {\n dependencies: packages.dependencies,\n devDependencies: packages.devDependencies,\n });\n\n return ctx as ScaffoldResult;\n}\n"],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { DeployTarget, Framework, Runtime } from './types.js';
2
+ export type PlatformFile = {
3
+ name: string;
4
+ content: string | ((ctx: {
5
+ projectName: string;
6
+ }) => string);
7
+ };
8
+ export type DeployEntry = {
9
+ id: DeployTarget;
10
+ /** Runtime this target builds for ("workerd" = Cloudflare's V8 runtime). */
11
+ impliedRuntime: Runtime | "workerd";
12
+ /** Whether the built output is a long-running server you start locally. */
13
+ selfHosted: boolean;
14
+ /** `start` script value; null for platform-deployed targets. */
15
+ startScript: string | null;
16
+ /** Runtime/platform tooling devDependencies beyond the base set. */
17
+ devDeps: string[];
18
+ files: PlatformFile[];
19
+ };
20
+ export declare const DEPLOY_ENTRIES: Record<DeployTarget, DeployEntry>;
21
+ export declare const DEFAULT_DEPLOY: DeployTarget;
22
+ export declare const DEFAULT_FRAMEWORK: Framework;
23
+ export declare function isCuratedDeploy(value: string): value is DeployTarget;
24
+ /**
25
+ * Resolves any preset id to its emission entry. Curated ids come from the
26
+ * registry; unknown strings pass through to Nitro verbatim as non-self-hosted
27
+ * node-family targets.
28
+ */
29
+ export declare function resolveDeployEntry(id: string): {
30
+ entry: DeployEntry;
31
+ curated: boolean;
32
+ };
33
+ /** Runtime overrides permitted for a deploy target; empty = no override. */
34
+ export declare function allowedRuntimeOverrides(id: DeployTarget): readonly Runtime[];
35
+ export type CombinationError = {
36
+ ok: false;
37
+ reason: string;
38
+ };
39
+ export type CombinationOk = {
40
+ ok: true;
41
+ runtime: Runtime | "workerd";
42
+ };
43
+ /**
44
+ * Validates a runtime × framework × deploy combination.
45
+ *
46
+ * @param runtimeOverride explicit `--runtime` selection, if any
47
+ * @param deploy preset id (curated or passthrough)
48
+ */
49
+ export declare function validateCombination(runtimeOverride: Runtime | undefined, framework: Framework, deploy: string): CombinationOk | CombinationError;
@@ -0,0 +1,166 @@
1
+ import { DEPLOY_TARGETS } from "./types.js";
2
+ //#region src/core/targets.ts
3
+ /**
4
+ * Registry for the three scaffold dimensions — runtime, framework, deploy —
5
+ * plus the compatibility rules between them.
6
+ *
7
+ * Dependency direction: deploy implies the runtime family; the effective
8
+ * runtime constrains which frameworks can run. `--runtime` is an override
9
+ * available only where it is meaningful (self-hosted node-family targets).
10
+ */
11
+ var NODE_START = "node .output/server/index.mjs";
12
+ var DEPLOY_ENTRIES = {
13
+ none: {
14
+ id: "none",
15
+ impliedRuntime: "node",
16
+ selfHosted: true,
17
+ startScript: "node dist/serve.mjs",
18
+ devDeps: [],
19
+ files: []
20
+ },
21
+ "node-server": {
22
+ id: "node-server",
23
+ impliedRuntime: "node",
24
+ selfHosted: true,
25
+ startScript: NODE_START,
26
+ devDeps: [],
27
+ files: []
28
+ },
29
+ "node-cluster": {
30
+ id: "node-cluster",
31
+ impliedRuntime: "node",
32
+ selfHosted: true,
33
+ startScript: NODE_START,
34
+ devDeps: [],
35
+ files: []
36
+ },
37
+ bun: {
38
+ id: "bun",
39
+ impliedRuntime: "bun",
40
+ selfHosted: true,
41
+ startScript: "bun .output/server/index.mjs",
42
+ devDeps: ["@types/bun"],
43
+ files: []
44
+ },
45
+ "deno-server": {
46
+ id: "deno-server",
47
+ impliedRuntime: "deno",
48
+ selfHosted: true,
49
+ startScript: "deno run -A .output/server/index.mjs",
50
+ devDeps: [],
51
+ files: []
52
+ },
53
+ "deno-deploy": {
54
+ id: "deno-deploy",
55
+ impliedRuntime: "deno",
56
+ selfHosted: false,
57
+ startScript: null,
58
+ devDeps: [],
59
+ files: []
60
+ },
61
+ "cloudflare-module": {
62
+ id: "cloudflare-module",
63
+ impliedRuntime: "workerd",
64
+ selfHosted: false,
65
+ startScript: null,
66
+ devDeps: ["wrangler", "@cloudflare/workers-types"],
67
+ files: [{
68
+ name: "wrangler.jsonc",
69
+ content: ({ projectName }) => `${JSON.stringify({
70
+ $schema: "node_modules/wrangler/config-schema.json",
71
+ name: projectName,
72
+ main: ".output/server/index.mjs",
73
+ compatibility_date: "2024-11-01"
74
+ }, null, 2)}\n`
75
+ }]
76
+ },
77
+ vercel: {
78
+ id: "vercel",
79
+ impliedRuntime: "node",
80
+ selfHosted: false,
81
+ startScript: null,
82
+ devDeps: ["@vercel/node"],
83
+ files: []
84
+ },
85
+ "aws-lambda": {
86
+ id: "aws-lambda",
87
+ impliedRuntime: "node",
88
+ selfHosted: false,
89
+ startScript: null,
90
+ devDeps: ["@types/aws-lambda"],
91
+ files: []
92
+ },
93
+ netlify: {
94
+ id: "netlify",
95
+ impliedRuntime: "node",
96
+ selfHosted: false,
97
+ startScript: null,
98
+ devDeps: [],
99
+ files: []
100
+ }
101
+ };
102
+ /** Runtimes a `--runtime` override may select per self-hosted deploy target. */
103
+ var RUNTIME_OVERRIDES = {
104
+ none: ["node", "bun"],
105
+ "node-server": ["node", "bun"],
106
+ "node-cluster": ["node", "bun"]
107
+ };
108
+ var DEFAULT_DEPLOY = "node-server";
109
+ function isCuratedDeploy(value) {
110
+ return DEPLOY_TARGETS.includes(value);
111
+ }
112
+ /**
113
+ * Resolves any preset id to its emission entry. Curated ids come from the
114
+ * registry; unknown strings pass through to Nitro verbatim as non-self-hosted
115
+ * node-family targets.
116
+ */
117
+ function resolveDeployEntry(id) {
118
+ if (isCuratedDeploy(id)) return {
119
+ entry: DEPLOY_ENTRIES[id],
120
+ curated: true
121
+ };
122
+ return {
123
+ entry: {
124
+ id,
125
+ impliedRuntime: "node",
126
+ selfHosted: false,
127
+ startScript: null,
128
+ devDeps: [],
129
+ files: []
130
+ },
131
+ curated: false
132
+ };
133
+ }
134
+ /** Runtime overrides permitted for a deploy target; empty = no override. */
135
+ function allowedRuntimeOverrides(id) {
136
+ return RUNTIME_OVERRIDES[id] ?? [];
137
+ }
138
+ /**
139
+ * Validates a runtime × framework × deploy combination.
140
+ *
141
+ * @param runtimeOverride explicit `--runtime` selection, if any
142
+ * @param deploy preset id (curated or passthrough)
143
+ */
144
+ function validateCombination(runtimeOverride, framework, deploy) {
145
+ const { entry } = resolveDeployEntry(deploy);
146
+ if (runtimeOverride !== void 0) {
147
+ const allowed = entry.selfHosted ? allowedRuntimeOverrides(entry.id) : [];
148
+ if (!allowed.includes(runtimeOverride)) return {
149
+ ok: false,
150
+ reason: `Runtime "${runtimeOverride}" is not valid for deploy target "${entry.id}". ` + (allowed.length > 0 ? `Allowed overrides: ${allowed.join(", ")}.` : `It implies runtime "${String(entry.impliedRuntime)}".`)
151
+ };
152
+ }
153
+ const effective = runtimeOverride ?? entry.impliedRuntime;
154
+ if ((framework === "express" || framework === "fastify") && effective !== "node") return {
155
+ ok: false,
156
+ reason: `Framework "${framework}" requires the Node runtime, but deploy target "${entry.id}" implies "${String(effective)}".`
157
+ };
158
+ return {
159
+ ok: true,
160
+ runtime: effective
161
+ };
162
+ }
163
+ //#endregion
164
+ export { DEFAULT_DEPLOY, DEPLOY_ENTRIES, allowedRuntimeOverrides, isCuratedDeploy, resolveDeployEntry, validateCombination };
165
+
166
+ //# sourceMappingURL=targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.js","names":[],"sources":["../../../src/core/targets.ts"],"sourcesContent":["/**\n * Registry for the three scaffold dimensions — runtime, framework, deploy —\n * plus the compatibility rules between them.\n *\n * Dependency direction: deploy implies the runtime family; the effective\n * runtime constrains which frameworks can run. `--runtime` is an override\n * available only where it is meaningful (self-hosted node-family targets).\n */\nimport { DEPLOY_TARGETS, type DeployTarget, type Framework, type Runtime } from \"./types.js\";\n\nexport type PlatformFile = {\n name: string;\n content: string | ((ctx: { projectName: string }) => string);\n};\n\nexport type DeployEntry = {\n id: DeployTarget;\n /** Runtime this target builds for (\"workerd\" = Cloudflare's V8 runtime). */\n impliedRuntime: Runtime | \"workerd\";\n /** Whether the built output is a long-running server you start locally. */\n selfHosted: boolean;\n /** `start` script value; null for platform-deployed targets. */\n startScript: string | null;\n /** Runtime/platform tooling devDependencies beyond the base set. */\n devDeps: string[];\n files: PlatformFile[];\n};\n\nconst NODE_START = \"node .output/server/index.mjs\";\n\nexport const DEPLOY_ENTRIES: Record<DeployTarget, DeployEntry> = {\n none: {\n id: \"none\",\n impliedRuntime: \"node\",\n selfHosted: true,\n startScript: \"node dist/serve.mjs\",\n devDeps: [],\n files: [],\n },\n \"node-server\": {\n id: \"node-server\",\n impliedRuntime: \"node\",\n selfHosted: true,\n startScript: NODE_START,\n devDeps: [],\n files: [],\n },\n \"node-cluster\": {\n id: \"node-cluster\",\n impliedRuntime: \"node\",\n selfHosted: true,\n startScript: NODE_START,\n devDeps: [],\n files: [],\n },\n bun: {\n id: \"bun\",\n impliedRuntime: \"bun\",\n selfHosted: true,\n startScript: \"bun .output/server/index.mjs\",\n devDeps: [\"@types/bun\"],\n files: [],\n },\n \"deno-server\": {\n id: \"deno-server\",\n impliedRuntime: \"deno\",\n selfHosted: true,\n startScript: \"deno run -A .output/server/index.mjs\",\n devDeps: [],\n files: [],\n },\n \"deno-deploy\": {\n id: \"deno-deploy\",\n impliedRuntime: \"deno\",\n selfHosted: false,\n startScript: null,\n devDeps: [],\n files: [],\n },\n \"cloudflare-module\": {\n id: \"cloudflare-module\",\n impliedRuntime: \"workerd\",\n selfHosted: false,\n startScript: null,\n devDeps: [\"wrangler\", \"@cloudflare/workers-types\"],\n files: [\n {\n name: \"wrangler.jsonc\",\n content: ({ projectName }) =>\n `${JSON.stringify(\n {\n $schema: \"node_modules/wrangler/config-schema.json\",\n name: projectName,\n main: \".output/server/index.mjs\",\n compatibility_date: \"2024-11-01\",\n },\n null,\n 2,\n )}\\n`,\n },\n ],\n },\n vercel: {\n id: \"vercel\",\n impliedRuntime: \"node\",\n selfHosted: false,\n startScript: null,\n devDeps: [\"@vercel/node\"],\n files: [],\n },\n \"aws-lambda\": {\n id: \"aws-lambda\",\n impliedRuntime: \"node\",\n selfHosted: false,\n startScript: null,\n devDeps: [\"@types/aws-lambda\"],\n files: [],\n },\n netlify: {\n id: \"netlify\",\n impliedRuntime: \"node\",\n selfHosted: false,\n startScript: null,\n devDeps: [],\n files: [],\n },\n};\n\n/** Runtimes a `--runtime` override may select per self-hosted deploy target. */\nconst RUNTIME_OVERRIDES: Partial<Record<DeployTarget, readonly Runtime[]>> = {\n none: [\"node\", \"bun\"],\n \"node-server\": [\"node\", \"bun\"],\n \"node-cluster\": [\"node\", \"bun\"],\n};\n\nexport const DEFAULT_DEPLOY: DeployTarget = \"node-server\";\nexport const DEFAULT_FRAMEWORK: Framework = \"none\";\n\nexport function isCuratedDeploy(value: string): value is DeployTarget {\n return (DEPLOY_TARGETS as readonly string[]).includes(value);\n}\n\n/**\n * Resolves any preset id to its emission entry. Curated ids come from the\n * registry; unknown strings pass through to Nitro verbatim as non-self-hosted\n * node-family targets.\n */\nexport function resolveDeployEntry(id: string): { entry: DeployEntry; curated: boolean } {\n if (isCuratedDeploy(id)) {\n return { entry: DEPLOY_ENTRIES[id], curated: true };\n }\n return {\n entry: {\n // Cast: passthrough ids are valid Nitro PresetNameInputs by contract.\n id: id as DeployTarget,\n impliedRuntime: \"node\",\n selfHosted: false,\n startScript: null,\n devDeps: [],\n files: [],\n },\n curated: false,\n };\n}\n\n/** Runtime overrides permitted for a deploy target; empty = no override. */\nexport function allowedRuntimeOverrides(id: DeployTarget): readonly Runtime[] {\n return RUNTIME_OVERRIDES[id] ?? [];\n}\n\nexport type CombinationError = { ok: false; reason: string };\nexport type CombinationOk = { ok: true; runtime: Runtime | \"workerd\" };\n\n/**\n * Validates a runtime × framework × deploy combination.\n *\n * @param runtimeOverride explicit `--runtime` selection, if any\n * @param deploy preset id (curated or passthrough)\n */\nexport function validateCombination(\n runtimeOverride: Runtime | undefined,\n framework: Framework,\n deploy: string,\n): CombinationOk | CombinationError {\n const { entry } = resolveDeployEntry(deploy);\n\n if (runtimeOverride !== undefined) {\n const allowed = entry.selfHosted ? allowedRuntimeOverrides(entry.id) : [];\n if (!allowed.includes(runtimeOverride)) {\n return {\n ok: false,\n reason:\n `Runtime \"${runtimeOverride}\" is not valid for deploy target \"${entry.id}\". ` +\n (allowed.length > 0\n ? `Allowed overrides: ${allowed.join(\", \")}.`\n : `It implies runtime \"${String(entry.impliedRuntime)}\".`),\n };\n }\n }\n\n const effective = runtimeOverride ?? entry.impliedRuntime;\n\n if ((framework === \"express\" || framework === \"fastify\") && effective !== \"node\") {\n return {\n ok: false,\n reason: `Framework \"${framework}\" requires the Node runtime, but deploy target \"${entry.id}\" implies \"${String(effective)}\".`,\n };\n }\n\n return { ok: true, runtime: effective };\n}\n"],"mappings":";;;;;;;;;;AA4BA,IAAM,aAAa;AAEnB,IAAa,iBAAoD;CAC/D,MAAM;EACJ,IAAI;EACJ,gBAAgB;EAChB,YAAY;EACZ,aAAa;EACb,SAAS,CAAC;EACV,OAAO,CAAC;CACV;CACA,eAAe;EACb,IAAI;EACJ,gBAAgB;EAChB,YAAY;EACZ,aAAa;EACb,SAAS,CAAC;EACV,OAAO,CAAC;CACV;CACA,gBAAgB;EACd,IAAI;EACJ,gBAAgB;EAChB,YAAY;EACZ,aAAa;EACb,SAAS,CAAC;EACV,OAAO,CAAC;CACV;CACA,KAAK;EACH,IAAI;EACJ,gBAAgB;EAChB,YAAY;EACZ,aAAa;EACb,SAAS,CAAC,YAAY;EACtB,OAAO,CAAC;CACV;CACA,eAAe;EACb,IAAI;EACJ,gBAAgB;EAChB,YAAY;EACZ,aAAa;EACb,SAAS,CAAC;EACV,OAAO,CAAC;CACV;CACA,eAAe;EACb,IAAI;EACJ,gBAAgB;EAChB,YAAY;EACZ,aAAa;EACb,SAAS,CAAC;EACV,OAAO,CAAC;CACV;CACA,qBAAqB;EACnB,IAAI;EACJ,gBAAgB;EAChB,YAAY;EACZ,aAAa;EACb,SAAS,CAAC,YAAY,2BAA2B;EACjD,OAAO,CACL;GACE,MAAM;GACN,UAAU,EAAE,kBACV,GAAG,KAAK,UACN;IACE,SAAS;IACT,MAAM;IACN,MAAM;IACN,oBAAoB;GACtB,GACA,MACA,CACF,EAAE;EACN,CACF;CACF;CACA,QAAQ;EACN,IAAI;EACJ,gBAAgB;EAChB,YAAY;EACZ,aAAa;EACb,SAAS,CAAC,cAAc;EACxB,OAAO,CAAC;CACV;CACA,cAAc;EACZ,IAAI;EACJ,gBAAgB;EAChB,YAAY;EACZ,aAAa;EACb,SAAS,CAAC,mBAAmB;EAC7B,OAAO,CAAC;CACV;CACA,SAAS;EACP,IAAI;EACJ,gBAAgB;EAChB,YAAY;EACZ,aAAa;EACb,SAAS,CAAC;EACV,OAAO,CAAC;CACV;AACF;;AAGA,IAAM,oBAAuE;CAC3E,MAAM,CAAC,QAAQ,KAAK;CACpB,eAAe,CAAC,QAAQ,KAAK;CAC7B,gBAAgB,CAAC,QAAQ,KAAK;AAChC;AAEA,IAAa,iBAA+B;AAG5C,SAAgB,gBAAgB,OAAsC;CACpE,OAAQ,eAAqC,SAAS,KAAK;AAC7D;;;;;;AAOA,SAAgB,mBAAmB,IAAsD;CACvF,IAAI,gBAAgB,EAAE,GACpB,OAAO;EAAE,OAAO,eAAe;EAAK,SAAS;CAAK;CAEpD,OAAO;EACL,OAAO;GAED;GACJ,gBAAgB;GAChB,YAAY;GACZ,aAAa;GACb,SAAS,CAAC;GACV,OAAO,CAAC;EACV;EACA,SAAS;CACX;AACF;;AAGA,SAAgB,wBAAwB,IAAsC;CAC5E,OAAO,kBAAkB,OAAO,CAAC;AACnC;;;;;;;AAWA,SAAgB,oBACd,iBACA,WACA,QACkC;CAClC,MAAM,EAAE,UAAU,mBAAmB,MAAM;CAE3C,IAAI,oBAAoB,KAAA,GAAW;EACjC,MAAM,UAAU,MAAM,aAAa,wBAAwB,MAAM,EAAE,IAAI,CAAC;EACxE,IAAI,CAAC,QAAQ,SAAS,eAAe,GACnC,OAAO;GACL,IAAI;GACJ,QACE,YAAY,gBAAgB,oCAAoC,MAAM,GAAG,QACxE,QAAQ,SAAS,IACd,sBAAsB,QAAQ,KAAK,IAAI,EAAE,KACzC,uBAAuB,OAAO,MAAM,cAAc,EAAE;EAC5D;CAEJ;CAEA,MAAM,YAAY,mBAAmB,MAAM;CAE3C,KAAK,cAAc,aAAa,cAAc,cAAc,cAAc,QACxE,OAAO;EACL,IAAI;EACJ,QAAQ,cAAc,UAAU,kDAAkD,MAAM,GAAG,aAAa,OAAO,SAAS,EAAE;CAC5H;CAGF,OAAO;EAAE,IAAI;EAAM,SAAS;CAAU;AACxC"}
@@ -1,6 +1,15 @@
1
1
  import { Agent } from 'package-manager-detector';
2
- export type ProjectType = "node" | "express" | "fastify" | "hono" | "bun" | "deno" | "aws-lambda" | "cloudflare-workers" | "netlify" | "vercel" | "azure-functions" | "google-cloud-run";
3
- export declare const PROJECT_TYPES: readonly ProjectType[];
2
+ /** Host framework layered on top of pure Taser pass-through dispatch. */
3
+ export type Framework = "none" | "hono" | "express" | "fastify";
4
+ export declare const FRAMEWORKS: readonly Framework[];
5
+ export type Runtime = "node" | "bun" | "deno";
6
+ export declare const RUNTIMES: readonly Runtime[];
7
+ /**
8
+ * Deployment target. Values are Nitro preset ids (see `nitro/config`
9
+ * PresetNameInput) so `--preset` passes straight through to Nitro.
10
+ */
11
+ export type DeployTarget = "none" | "node-server" | "node-cluster" | "bun" | "deno-server" | "deno-deploy" | "cloudflare-module" | "vercel" | "aws-lambda" | "netlify";
12
+ export declare const DEPLOY_TARGETS: readonly DeployTarget[];
4
13
  export type DbOdm = "drizzle" | "prisma" | "kysely";
5
14
  export declare const DB_ODMS: readonly DbOdm[];
6
15
  export type DbDriver = "postgres" | "sqlite" | "mysql";
@@ -18,7 +27,12 @@ export type PackageGroups = {
18
27
  export type ScaffoldContext = {
19
28
  projectName: string;
20
29
  targetDir: string;
21
- type: ProjectType;
30
+ /** Host framework; "none" is pure Taser pass-through dispatch. Defaults to "none". */
31
+ framework?: Framework;
32
+ /** Deployment target — a Nitro preset id. Defaults to "node-server". */
33
+ preset?: DeployTarget;
34
+ /** Set only when explicitly overriding the runtime implied by the preset. */
35
+ runtime?: Runtime;
22
36
  db?: DbOdm;
23
37
  driver?: DbDriver;
24
38
  logger?: LoggerId;
@@ -30,7 +44,9 @@ export type ScaffoldOptions = ScaffoldContext & {
30
44
  };
31
45
  export type ScaffoldResult = ScaffoldContext;
32
46
  export type CapabilitiesCatalog = {
33
- types: ProjectType[];
47
+ frameworks: Framework[];
48
+ deployTargets: DeployTarget[];
49
+ runtimes: Runtime[];
34
50
  db: {
35
51
  odms: DbOdm[];
36
52
  drivers: DbDriver[];