create-routecraft 0.3.0-canary.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,9 @@
1
1
  # create-routecraft
2
2
 
3
- Scaffold a new RouteCraft project with best practices and example routes.
3
+ Scaffold a new RouteCraft project with best practices and example capabilities.
4
4
 
5
5
  ## Usage
6
6
 
7
- Create a new RouteCraft project interactively:
8
-
9
7
  ```bash
10
8
  npm create routecraft@latest
11
9
  ```
@@ -26,11 +24,11 @@ npx create-routecraft
26
24
 
27
25
  The scaffolded project includes:
28
26
 
29
- - Pre-configured TypeScript setup
30
- - Example routes demonstrating key features
31
- - Ready-to-use project structure
32
- - Development dependencies configured
33
- - ESLint and testing setup
27
+ - Pre-configured TypeScript setup
28
+ - Example capabilities demonstrating key features
29
+ - Ready-to-use project structure
30
+ - Development dependencies configured
31
+ - ESLint and testing setup
34
32
 
35
33
  ## Interactive Prompts
36
34
 
@@ -63,4 +61,3 @@ Apache-2.0
63
61
  - [Documentation](https://routecraft.dev)
64
62
  - [GitHub Repository](https://github.com/routecraftjs/routecraft)
65
63
  - [Issue Tracker](https://github.com/routecraftjs/routecraft/issues)
66
-
package/dist/index.js CHANGED
@@ -1,60 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import {mkdir,writeFile,cp,rm,readFile,readdir,stat}from'fs/promises';import {resolve,join,dirname}from'path';import {fileURLToPath}from'url';import {existsSync,readFileSync}from'fs';import {execSync}from'child_process';import {confirm,select,input}from'@inquirer/prompts';import {tmpdir}from'os';function h(){try{let e=join(dirname(fileURLToPath(import.meta.url)),"../../routecraft/package.json");if(existsSync(e))return `^${JSON.parse(readFileSync(e,"utf-8")).version}`}catch{}return "latest"}var U={"package.json":{content:e=>JSON.stringify({name:e,version:"0.2.0",private:true,type:"module",scripts:{build:"tsc",start:"craft run dist/index.js",lint:"eslint ."},dependencies:{"@routecraft/routecraft":h()},devDependencies:{"@types/node":"^20.0.0",typescript:"^5.0.0",eslint:"^9.36.0","@eslint/js":"^9.36.0","typescript-eslint":"^8.44.1","@routecraft/eslint-plugin-routecraft":h(),"@routecraft/cli":h(),"pino-pretty":"^13.1.2"}},null,2)},"tsconfig.json":{content:JSON.stringify({compilerOptions:{target:"ES2022",module:"ESNext",moduleResolution:"bundler",outDir:"./dist",rootDir:".",allowSyntheticDefaultImports:true,esModuleInterop:true,allowJs:true,strict:true,skipLibCheck:true,isolatedModules:true,resolveJsonModule:true},include:["**/*.ts","**/*.js"],exclude:["node_modules","dist"]},null,2)},"eslint.config.mjs":{content:`import pluginJs from "@eslint/js";
3
- import tseslint from "typescript-eslint";
4
- import routecraftPlugin from "@routecraft/eslint-plugin-routecraft";
5
-
6
- /** @type {import('eslint').Linter.Config[]} */
7
- export default [
8
- pluginJs.configs.recommended,
9
- ...tseslint.configs.recommended,
10
- {
11
- files: ["routes/**/*.{ts,js}", "**/*.route.{ts,js}", "**/*.{ts,js}"],
12
- plugins: { "@routecraft/routecraft": routecraftPlugin },
13
- ...routecraftPlugin.configs.recommended,
14
- },
15
- ];
16
- `},"craft.config.ts":{content:`import type { CraftConfig } from "@routecraft/routecraft";
17
-
18
- const config: CraftConfig = {
19
- };
20
-
21
- export default config;`},".gitignore":{content:`node_modules/
22
- dist/
23
- .env
24
- .env.local
25
- .env.*.local
26
- *.log
27
- .DS_Store`},"index.ts":{content:e=>e?`export { default as craftConfig } from './craft.config.js';
28
- import helloWorldRoute from './routes/hello-world.route.js';
29
-
30
- // Export all routes as default for craft run
31
- export default [helloWorldRoute];`:`export { default as craftConfig } from './craft.config.js';
32
-
33
- // Export all routes as default for craft run
34
- export default [];`}},O={"hello-world":{"routes/hello-world.route.ts":{content:`import { log, craft, simple, http, type HttpResult } from "@routecraft/routecraft";
35
-
36
- export default craft()
37
- .id("hello-world")
38
- .from(simple({ userId: 1 }))
39
- .enrich<HttpResult<{ name: string }>>(
40
- http({
41
- method: "GET",
42
- url: (ex) =>
43
- \`https://jsonplaceholder.typicode.com/users/\${ex.body.userId}\`,
44
- }),
45
- )
46
- .transform((result) => \`Hello, \${result.body.name}!\`)
47
- .to(log());`}}};function P(e){return e.startsWith("http://")||e.startsWith("https://")}async function N(e){try{let t=await readdir(e),r=t.includes("package.json"),n=t.some(a=>a.endsWith(".ts")||a.endsWith(".js")||a.endsWith(".mjs")||a.includes("route")),o=!1;for(let a of t){let s=join(e,a);if((await stat(s)).isDirectory()&&(await readdir(s)).some(p=>p.endsWith(".ts")||p.endsWith(".js")||p.endsWith(".mjs"))){o=!0;break}}if(!r&&!n&&!o)throw new Error("Downloaded content doesn't appear to be a valid RouteCraft project. Expected to find package.json or route files (.ts, .js, .mjs).");console.log("\u2705 Downloaded content validated successfully");}catch(t){throw new Error(`Content validation failed: ${t instanceof Error?t.message:t}`)}}async function D(e){let t=join(tmpdir(),`routecraft-example-${Date.now()}`);try{console.log(`\u{1F4E5} Downloading example from ${e}...`);let r=/^https?:\/\/github\.com\/([^/]+)\/([^/]+)(?:\/tree\/([^/]+)\/(.+))?$/,n=e.match(r);if(!n)throw new Error(`Invalid GitHub URL format: ${e}`);let[,o,a,s="main",i=""]=n,l=`https://github.com/${o}/${a}.git`;try{execSync(`git clone --depth 1 ${s?`--branch ${s}`:""} ${l} ${t}`,{stdio:"inherit"});}catch{throw new Error(`Failed to clone repository. Make sure the repository is public and accessible: ${l}`)}let p=i?join(t,i):t;if(!existsSync(p))throw new Error(`Path ${i} not found in repository`);return await N(p),p}catch(r){try{await rm(t,{recursive:!0,force:!0});}catch{}throw new Error(`Failed to download example from ${e}: ${r}`)}}async function F(){let e=process.argv.slice(2);(e.includes("--help")||e.includes("-h"))&&(j(),process.exit(0));let t=e[0];t||(console.error("\u274C Project name is required"),console.log("Usage: npm create routecraft@latest <project-name> [options]"),console.log("Or: npx create-routecraft <project-name> [options]"),console.log("Run with --help for more information"),process.exit(1));let r=e.slice(1),n={};for(let o=0;o<r.length;o++){let a=r[o];a==="--example"||a==="-e"?(n.example=r[o+1],o++):a==="--use-npm"?n.packageManager="npm":a==="--use-pnpm"?n.packageManager="pnpm":a==="--use-yarn"?n.packageManager="yarn":a==="--use-bun"?n.packageManager="bun":a==="--no-src-dir"?n.useSrcDir=false:a==="--skip-install"?n.skipInstall=true:a==="--no-git"?n.git=false:a==="--yes"||a==="-y"?n.yes=true:a==="--force"||a==="-f"?n.force=true:(a==="--help"||a==="-h")&&(j(),process.exit(0));}try{await J(t,n);}catch(o){console.error("\u274C Failed to create RouteCraft project:",o),process.exit(1);}}async function J(e,t={}){try{let r=await W(e,t),n=resolve(process.cwd(),r.projectName);await H(n,r.force),await L(n,r),r.git&&await G(n),r.skipInstall||await T(n,r.packageManager),console.log(`
48
- \u{1F389} Successfully created RouteCraft project: ${r.projectName}
2
+ import {mkdir,writeFile,cp,rm,readFile,readdir,stat}from'fs/promises';import {dirname,join,resolve}from'path';import {fileURLToPath}from'url';import {existsSync,readFileSync}from'fs';import {execSync}from'child_process';import {confirm,select,input}from'@inquirer/prompts';import {tmpdir}from'os';var H=dirname(fileURLToPath(import.meta.url)),h=join(H,"../templates");function J(){try{let e=join(dirname(fileURLToPath(import.meta.url)),"../../routecraft/package.json");if(existsSync(e))return `^${JSON.parse(readFileSync(e,"utf-8")).version}`}catch{}return "latest"}function _(e){return {pnpm:"pnpm@10.17.1",npm:"npm@10.0.0",yarn:"yarn@4.0.0",bun:"bun@1.0.0"}[e]}async function b(e){return await readFile(e,"utf-8")}function E(e,t){let a=e;for(let[n,s]of Object.entries(t))a=a.replaceAll(n,s);return a}function F(e){return e.startsWith("http://")||e.startsWith("https://")}async function L(e){try{let t=await readdir(e),a=t.includes("package.json"),n=t.some(r=>r.endsWith(".ts")||r.endsWith(".js")||r.endsWith(".mjs")||r.includes("route")),s=!1;for(let r of t){let u=join(e,r);if((await stat(u)).isDirectory()&&(await readdir(u)).some(c=>c.endsWith(".ts")||c.endsWith(".js")||c.endsWith(".mjs"))){s=!0;break}}if(!a&&!n&&!s)throw new Error("Downloaded content doesn't appear to be a valid RouteCraft project. Expected to find package.json or route files (.ts, .js, .mjs).");console.log("\u2705 Downloaded content validated successfully");}catch(t){throw new Error(`Content validation failed: ${t instanceof Error?t.message:t}`)}}async function z(e){let t=join(tmpdir(),`routecraft-example-${Date.now()}`);try{console.log(`\u{1F4E5} Downloading example from ${e}...`);let a=/^https?:\/\/github\.com\/([^/]+)\/([^/]+)(?:\/tree\/([^/]+)\/(.+))?$/,n=e.match(a);if(!n)throw new Error(`Invalid GitHub URL format: ${e}`);let[,s,r,u="main",l=""]=n,f=`https://github.com/${s}/${r}.git`;try{execSync(`git clone --depth 1 ${u?`--branch ${u}`:""} ${f} ${t}`,{stdio:"inherit"});}catch{throw new Error(`Failed to clone repository. Make sure the repository is public and accessible: ${f}`)}let c=l?join(t,l):t;if(!existsSync(c))throw new Error(`Path ${l} not found in repository`);return await L(c),c}catch(a){try{await rm(t,{recursive:!0,force:!0});}catch{}throw new Error(`Failed to download example from ${e}: ${a}`)}}async function q(){let e=process.argv.slice(2);(e.includes("--help")||e.includes("-h"))&&(M(),process.exit(0));let t=e[0];t||(console.error("\u274C Project name is required"),console.log("Usage: npm create routecraft@latest <project-name> [options]"),console.log("Or: npx create-routecraft <project-name> [options]"),console.log("Run with --help for more information"),process.exit(1));let a=e.slice(1),n={};for(let s=0;s<a.length;s++){let r=a[s];r==="--example"||r==="-e"?(n.example=a[s+1],s++):r==="--use-npm"?n.packageManager="npm":r==="--use-pnpm"?n.packageManager="pnpm":r==="--use-yarn"?n.packageManager="yarn":r==="--use-bun"?n.packageManager="bun":r==="--no-src-dir"?n.useSrcDir=false:r==="--skip-install"?n.skipInstall=true:r==="--no-git"?n.git=false:r==="--yes"||r==="-y"?n.yes=true:r==="--force"||r==="-f"?n.force=true:(r==="--help"||r==="-h")&&(M(),process.exit(0));}try{await V(t,n);}catch(s){console.error("\u274C Failed to create RouteCraft project:",s),process.exit(1);}}async function V(e,t={}){try{let a=await B(e,t),n=resolve(process.cwd(),a.projectName);await K(n,a.force),await Q(n,a),a.git&&await X(n),a.skipInstall||await Y(n,a.packageManager),console.log(`
3
+ \u{1F389} Successfully created RouteCraft project: ${a.projectName}
49
4
 
50
5
  Next steps:
51
- cd ${r.projectName}
52
- ${r.skipInstall?`${f(r.packageManager)} install
53
- `:""}${f(r.packageManager)} run build
54
- ${f(r.packageManager)} run start
6
+ cd ${a.projectName}
7
+ ${a.skipInstall?`${v(a.packageManager)} install
8
+ `:""}${v(a.packageManager)} run start
55
9
 
56
10
  For more information, visit: https://routecraft.dev
57
- `);}catch(r){console.error(`Failed to initialize project: ${r}`),process.exit(1);}}async function W(e,t={}){let r=t.yes===true;return {projectName:e||(r?"my-routecraft-app":await input({message:"What is your project named?",default:"my-routecraft-app",validate:o=>o.length>0||"Project name cannot be empty"})),example:t.example||(r?"none":await select({message:"Choose an example:",choices:[{name:"None - empty project",value:"none"},{name:"Hello World - basic example",value:"hello-world"},{name:"Custom URL (GitHub)",value:"custom-url"}],default:"none"}).then(async o=>o==="custom-url"?await input({message:"Enter GitHub URL:",validate:a=>P(a)?true:"Must be a valid GitHub URL"}):o)),packageManager:t.packageManager||(r?"npm":await select({message:"Package manager:",choices:[{name:"npm",value:"npm"},{name:"pnpm",value:"pnpm"},{name:"yarn",value:"yarn"},{name:"bun",value:"bun"}],default:"npm"})),useSrcDir:t.useSrcDir??(r?false:await confirm({message:"Use src directory:",default:false})),git:t.git??(r?true:await confirm({message:"Initialize git:",default:true})),skipInstall:t.skipInstall??(r?false:!await confirm({message:"Install dependencies now:",default:true})),force:t.force??false,yes:r}}async function H(e,t=false){if(existsSync(e))if(t)console.log(`\u26A0\uFE0F Overwriting existing directory: ${e}`);else throw new Error(`Directory "${e}" already exists. Use --force to overwrite.`);await mkdir(e,{recursive:true}),console.log(`Created project directory: ${e}`);}async function L(e,t){let r=t.useSrcDir?join(e,"src"):e;await mkdir(join(r,"routes"),{recursive:true}),await mkdir(join(r,"adapters"),{recursive:true}),await mkdir(join(r,"plugins"),{recursive:true});let n=U,o=t.example!=="none";for(let[a,s]of Object.entries(n)){let i=join(e,a);await mkdir(dirname(i),{recursive:true});let l;typeof s.content=="function"?a==="index.ts"?l=s.content(o):l=s.content(t.projectName):l=s.content,await writeFile(i,l),console.log(`Created file: ${a}`);}if(t.example!=="none")if(P(t.example)){let a=await D(t.example);try{await cp(a,r,{recursive:!0,force:!0,filter:s=>{let i=s.replace(a,"").replace(/^\//,"");return !i.includes("node_modules")&&!i.includes(".git")&&!i.includes("package-lock.json")&&!i.includes("yarn.lock")&&!i.includes("pnpm-lock.yaml")}}),console.log(`\u2705 Added example from ${t.example}`);}finally{try{await rm(a,{recursive:!0,force:!0});}catch{}}}else {let s=O[t.example];if(!s)throw new Error(`Unknown example: ${t.example}`);for(let[i,l]of Object.entries(s)){let p=join(r,i);await mkdir(dirname(p),{recursive:true}),await writeFile(p,l.content),console.log(`Created example file: ${i}`);}}if(t.useSrcDir){let a=join(e,"package.json"),s=JSON.parse(await readFile(a,"utf-8"));s.scripts={...s.scripts,build:"tsc",start:"craft run dist/src/index.js"},await writeFile(a,JSON.stringify(s,null,2));}console.log("Generated project structure");}async function G(e){try{execSync("git init",{cwd:e,stdio:"inherit"}),execSync("git add .",{cwd:e,stdio:"inherit"}),execSync('git commit -m "Initial commit"',{cwd:e,stdio:"inherit"}),console.log("Initialized git repository");}catch{console.warn("Failed to initialize git repository");}}async function T(e,t){let r=f(t);try{execSync(`${r} install`,{cwd:e,stdio:"inherit"}),console.log("Installed dependencies");}catch{console.warn(`Failed to install dependencies. Run "${r} install" manually.`);}}function f(e){switch(e){case "npm":return "npm";case "pnpm":return "pnpm";case "yarn":return "yarn";case "bun":return "bun";default:return "npm"}}function j(){console.log(`
11
+ `);}catch(a){console.error(`Failed to initialize project: ${a}`),process.exit(1);}}async function B(e,t={}){let a=t.yes===true;return {projectName:e||(a?"my-routecraft-app":await input({message:"What is your project named?",default:"my-routecraft-app",validate:s=>s.length>0||"Project name cannot be empty"})),example:t.example||(a?"none":await select({message:"Choose an example:",choices:[{name:"None - empty project",value:"none"},{name:"Hello World - basic example",value:"hello-world"},{name:"Custom URL (GitHub)",value:"custom-url"}],default:"none"}).then(async s=>s==="custom-url"?await input({message:"Enter GitHub URL:",validate:r=>F(r)?true:"Must be a valid GitHub URL"}):s)),packageManager:t.packageManager||(a?"npm":await select({message:"Package manager:",choices:[{name:"npm",value:"npm"},{name:"pnpm",value:"pnpm"},{name:"yarn",value:"yarn"},{name:"bun",value:"bun"}],default:"npm"})),useSrcDir:t.useSrcDir??(a?false:await confirm({message:"Use src directory:",default:false})),git:t.git??(a?true:await confirm({message:"Initialize git:",default:true})),skipInstall:t.skipInstall??(a?false:!await confirm({message:"Install dependencies now:",default:true})),force:t.force??false,yes:a}}async function K(e,t=false){if(existsSync(e))if(t)console.log(`\u26A0\uFE0F Overwriting existing directory: ${e}`);else throw new Error(`Directory "${e}" already exists. Use --force to overwrite.`);await mkdir(e,{recursive:true}),console.log(`Created project directory: ${e}`);}async function Q(e,t){let a=t.useSrcDir?join(e,"src"):e,n=t.example!=="none";await mkdir(join(a,"capabilities"),{recursive:true}),await mkdir(join(a,"adapters"),{recursive:true}),await mkdir(join(a,"plugins"),{recursive:true});let s={gitignore:".gitignore",".prettierrc":".prettierrc","craft.config.ts":"craft.config.ts","eslint.config.mjs":"eslint.config.mjs","tsconfig.json":"tsconfig.json","vitest.config.ts":"vitest.config.ts"},r=J();for(let[i,p]of Object.entries(s)){let m=join(h,"base",i),T=join(e,p),N=await b(m);await writeFile(T,N),console.log(`Created file: ${p}`);}let u=join(h,"base","package.json"),l=await b(u);l=E(l,{PROJECT_NAME:t.projectName,ROUTECRAFT_VERSION:r,PACKAGE_MANAGER:_(t.packageManager)}),await writeFile(join(e,"package.json"),l),console.log("Created file: package.json");let c=join(h,"base",n?"index-with-example.ts":"index-empty.ts"),k=await b(c),O=t.useSrcDir?"./src/capabilities":"./capabilities";if(k=E(k,{CAPABILITIES_IMPORT_PATH:O}),await writeFile(join(e,"index.ts"),k),console.log("Created file: index.ts"),t.example!=="none")if(F(t.example)){let i=await z(t.example);try{await cp(i,a,{recursive:!0,force:!0,filter:p=>{let m=p.replace(i,"").replace(/^\//,"");return !m.includes("node_modules")&&!m.includes(".git")&&!m.includes("package-lock.json")&&!m.includes("yarn.lock")&&!m.includes("pnpm-lock.yaml")}}),console.log(`\u2705 Added example from ${t.example}`);}finally{try{await rm(i,{recursive:!0,force:!0});}catch{}}}else {let i=join(h,"examples",t.example);if(existsSync(i))await cp(i,a,{recursive:true,force:false}),console.log(`\u2705 Added ${t.example} example`);else throw new Error(`Unknown example: ${t.example}`)}if(t.useSrcDir){let i=join(e,"package.json"),p=JSON.parse(await readFile(i,"utf-8"));p.scripts={...p.scripts,build:"tsc",start:"craft run src/index.ts"},await writeFile(i,JSON.stringify(p,null,2));}console.log("Generated project structure");}async function X(e){try{execSync("git init",{cwd:e,stdio:"inherit"}),execSync("git add .",{cwd:e,stdio:"inherit"}),execSync('git commit -m "Initial commit"',{cwd:e,stdio:"inherit"}),console.log("Initialized git repository");}catch{console.warn("Failed to initialize git repository");}}async function Y(e,t){let a=v(t);try{execSync(`${a} install`,{cwd:e,stdio:"inherit"}),console.log("Installed dependencies");}catch{console.warn(`Failed to install dependencies. Run "${a} install" manually.`);}}function v(e){switch(e){case "npm":return "npm";case "pnpm":return "pnpm";case "yarn":return "yarn";case "bun":return "bun";default:return "npm"}}function M(){console.log(`
58
12
  Create a new RouteCraft project
59
13
 
60
14
  Usage:
@@ -81,5 +35,5 @@ Examples:
81
35
  npx create-routecraft my-app --force
82
36
  npm create routecraft@latest my-app --example https://github.com/user/repo
83
37
  npm create routecraft@latest my-app --example https://github.com/user/repo/tree/main/examples/api
84
- `);}F().catch(e=>{console.error("Unexpected error:",e),process.exit(1);});//# sourceMappingURL=index.js.map
38
+ `);}q().catch(e=>{console.error("Unexpected error:",e),process.exit(1);});//# sourceMappingURL=index.js.map
85
39
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["getRoutecraftVersion","packagePath","join","dirname","fileURLToPath","existsSync","readFileSync","NODE_TEMPLATE","projectName","hasExample","EXAMPLES","isUrl","example","validateExampleContent","sourceDir","files","readdir","hasPackageJson","hasRouteFiles","file","hasRouteSubdirs","filePath","stat","f","error","downloadGitHubExample","url","tempDir","tmpdir","urlPattern","match","owner","repo","branch","subPath","repoUrl","execSync","rm","main","args","showHelp","remainingArgs","options","i","arg","initCommand","answers","getUserInput","projectDir","resolve","createProjectDirectory","generateProjectStructure","initializeGit","installDependencies","getPackageManagerCommand","skipPrompts","input","value","select","choice","confirm","force","mkdir","baseDir","template","fileConfig","fullPath","content","writeFile","tempExampleDir","cp","src","relativePath","packageJsonPath","packageJson","readFile","packageManager","command"],"mappings":"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","file":"index.js","sourcesContent":["#!/usr/bin/env node\n\n/* eslint-disable no-console */\n\nimport { mkdir, writeFile, readFile, readdir, stat } from \"node:fs/promises\";\nimport { join, resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { input, select, confirm } from \"@inquirer/prompts\";\nimport { tmpdir } from \"node:os\";\nimport { cp, rm } from \"node:fs/promises\";\n\n/**\n * Package manager types\n */\ntype PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\n/**\n * Example types\n */\ntype ExampleType = string;\n\n/**\n * Project initialization options\n */\ninterface InitOptions {\n projectName?: string;\n example?: ExampleType;\n packageManager?: PackageManager;\n useSrcDir?: boolean;\n skipInstall?: boolean;\n git?: boolean;\n force?: boolean;\n yes?: boolean;\n}\n\n/**\n * Get the current version of @routecraft/routecraft from package.json\n */\nfunction getRoutecraftVersion(): string {\n try {\n // Try to read the package.json of the routecraft package\n const packagePath = join(\n dirname(fileURLToPath(import.meta.url)),\n \"../../routecraft/package.json\",\n );\n if (existsSync(packagePath)) {\n const pkg = JSON.parse(readFileSync(packagePath, \"utf-8\"));\n return `^${pkg.version}`;\n }\n } catch {\n // Fallback if we can't read the package.json\n }\n\n // Default fallback - use \"latest\" to always get the newest version\n return \"latest\";\n}\n\n/**\n * Template file configuration\n */\ninterface TemplateFileConfig {\n content: string | ((arg: string) => string) | ((arg: boolean) => string);\n}\n\n/**\n * Default project structure template for Node.js package managers\n */\nconst NODE_TEMPLATE = {\n \"package.json\": {\n content: (projectName: string) =>\n JSON.stringify(\n {\n name: projectName,\n version: \"0.2.0\",\n private: true,\n type: \"module\",\n scripts: {\n build: \"tsc\",\n start: \"craft run dist/index.js\",\n lint: \"eslint .\",\n },\n dependencies: {\n \"@routecraft/routecraft\": getRoutecraftVersion(),\n },\n devDependencies: {\n \"@types/node\": \"^20.0.0\",\n typescript: \"^5.0.0\",\n eslint: \"^9.36.0\",\n \"@eslint/js\": \"^9.36.0\",\n \"typescript-eslint\": \"^8.44.1\",\n \"@routecraft/eslint-plugin-routecraft\": getRoutecraftVersion(),\n \"@routecraft/cli\": getRoutecraftVersion(),\n \"pino-pretty\": \"^13.1.2\",\n },\n },\n null,\n 2,\n ),\n },\n \"tsconfig.json\": {\n content: JSON.stringify(\n {\n compilerOptions: {\n target: \"ES2022\",\n module: \"ESNext\",\n moduleResolution: \"bundler\",\n outDir: \"./dist\",\n rootDir: \".\",\n allowSyntheticDefaultImports: true,\n esModuleInterop: true,\n allowJs: true,\n strict: true,\n skipLibCheck: true,\n isolatedModules: true,\n resolveJsonModule: true,\n },\n include: [\"**/*.ts\", \"**/*.js\"],\n exclude: [\"node_modules\", \"dist\"],\n },\n null,\n 2,\n ),\n },\n \"eslint.config.mjs\": {\n content: `import pluginJs from \"@eslint/js\";\nimport tseslint from \"typescript-eslint\";\nimport routecraftPlugin from \"@routecraft/eslint-plugin-routecraft\";\n\n/** @type {import('eslint').Linter.Config[]} */\nexport default [\n pluginJs.configs.recommended,\n ...tseslint.configs.recommended,\n {\n files: [\"routes/**/*.{ts,js}\", \"**/*.route.{ts,js}\", \"**/*.{ts,js}\"],\n plugins: { \"@routecraft/routecraft\": routecraftPlugin },\n ...routecraftPlugin.configs.recommended,\n },\n];\n`,\n },\n \"craft.config.ts\": {\n content: `import type { CraftConfig } from \"@routecraft/routecraft\";\n\nconst config: CraftConfig = {\n};\n\nexport default config;`,\n },\n \".gitignore\": {\n content: `node_modules/\ndist/\n.env\n.env.local\n.env.*.local\n*.log\n.DS_Store`,\n },\n \"index.ts\": {\n content: (hasExample: boolean) =>\n hasExample\n ? `export { default as craftConfig } from './craft.config.js';\nimport helloWorldRoute from './routes/hello-world.route.js';\n\n// Export all routes as default for craft run\nexport default [helloWorldRoute];`\n : `export { default as craftConfig } from './craft.config.js';\n\n// Export all routes as default for craft run\nexport default [];`,\n },\n};\n\n/**\n * Example route templates for Node.js\n */\nconst EXAMPLES = {\n \"hello-world\": {\n \"routes/hello-world.route.ts\": {\n content: `import { log, craft, simple, http, type HttpResult } from \"@routecraft/routecraft\";\n\nexport default craft()\n .id(\"hello-world\")\n .from(simple({ userId: 1 }))\n .enrich<HttpResult<{ name: string }>>(\n http({\n method: \"GET\",\n url: (ex) =>\n \\`https://jsonplaceholder.typicode.com/users/\\${ex.body.userId}\\`,\n }),\n )\n .transform((result) => \\`Hello, \\${result.body.name}!\\`)\n .to(log());`,\n },\n },\n};\n\n/**\n * Check if an example string is a URL\n */\nfunction isUrl(example: string): boolean {\n return example.startsWith(\"http://\") || example.startsWith(\"https://\");\n}\n\n/**\n * Validate that the downloaded content contains expected RouteCraft project files\n * @param sourceDir Path to the source directory to validate\n */\nasync function validateExampleContent(sourceDir: string): Promise<void> {\n try {\n const files = await readdir(sourceDir);\n\n // Check for basic project structure indicators\n const hasPackageJson = files.includes(\"package.json\");\n const hasRouteFiles = files.some(\n (file) =>\n file.endsWith(\".ts\") ||\n file.endsWith(\".js\") ||\n file.endsWith(\".mjs\") ||\n file.includes(\"route\"),\n );\n\n // Check if there are subdirectories that might contain routes\n let hasRouteSubdirs = false;\n for (const file of files) {\n const filePath = join(sourceDir, file);\n const fileStat = await stat(filePath);\n if (fileStat.isDirectory()) {\n const subFiles = await readdir(filePath);\n if (\n subFiles.some(\n (f) => f.endsWith(\".ts\") || f.endsWith(\".js\") || f.endsWith(\".mjs\"),\n )\n ) {\n hasRouteSubdirs = true;\n break;\n }\n }\n }\n\n if (!hasPackageJson && !hasRouteFiles && !hasRouteSubdirs) {\n throw new Error(\n \"Downloaded content doesn't appear to be a valid RouteCraft project. \" +\n \"Expected to find package.json or route files (.ts, .js, .mjs).\",\n );\n }\n\n console.log(\"✅ Downloaded content validated successfully\");\n } catch (error) {\n throw new Error(\n `Content validation failed: ${error instanceof Error ? error.message : error}`,\n );\n }\n}\n\n/**\n * Download and extract a GitHub example\n */\nasync function downloadGitHubExample(url: string): Promise<string> {\n const tempDir = join(tmpdir(), `routecraft-example-${Date.now()}`);\n\n try {\n console.log(`📥 Downloading example from ${url}...`);\n\n // For GitHub URLs, we'll use git clone for simplicity\n // Extract repo info from URL\n const urlPattern =\n /^https?:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)(?:\\/tree\\/([^/]+)\\/(.+))?$/;\n const match = url.match(urlPattern);\n\n if (!match) {\n throw new Error(`Invalid GitHub URL format: ${url}`);\n }\n\n const [, owner, repo, branch = \"main\", subPath = \"\"] = match;\n const repoUrl = `https://github.com/${owner}/${repo}.git`;\n\n // Clone the repo (try with credentials if available, fallback to public access)\n try {\n execSync(\n `git clone --depth 1 ${branch ? `--branch ${branch}` : \"\"} ${repoUrl} ${tempDir}`,\n {\n stdio: \"inherit\",\n },\n );\n } catch {\n // If git clone fails, try a different approach or provide better error\n throw new Error(\n `Failed to clone repository. Make sure the repository is public and accessible: ${repoUrl}`,\n );\n }\n\n // If there's a subPath, use that subdirectory\n const sourceDir = subPath ? join(tempDir, subPath) : tempDir;\n\n if (!existsSync(sourceDir)) {\n throw new Error(`Path ${subPath} not found in repository`);\n }\n\n // Validate downloaded content structure\n await validateExampleContent(sourceDir);\n\n return sourceDir;\n } catch (error) {\n // Cleanup on error\n try {\n await rm(tempDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n throw new Error(`Failed to download example from ${url}: ${error}`);\n }\n}\n\n/**\n * Main entry point for create-routecraft\n * This is called by npm create routecraft <project-name>\n */\nasync function main() {\n const args = process.argv.slice(2);\n\n // Check for help flag first\n if (args.includes(\"--help\") || args.includes(\"-h\")) {\n showHelp();\n process.exit(0);\n }\n\n // npm create passes the project name as the first argument\n const projectName = args[0];\n\n if (!projectName) {\n console.error(\"❌ Project name is required\");\n console.log(\"Usage: npm create routecraft@latest <project-name> [options]\");\n console.log(\"Or: npx create-routecraft <project-name> [options]\");\n console.log(\"Run with --help for more information\");\n process.exit(1);\n }\n\n // Parse additional arguments\n const remainingArgs = args.slice(1);\n const options: Record<string, unknown> = {};\n\n // Simple argument parsing for common options\n for (let i = 0; i < remainingArgs.length; i++) {\n const arg = remainingArgs[i];\n\n if (arg === \"--example\" || arg === \"-e\") {\n options[\"example\"] = remainingArgs[i + 1];\n i++; // Skip next arg\n } else if (arg === \"--use-npm\") {\n options[\"packageManager\"] = \"npm\";\n } else if (arg === \"--use-pnpm\") {\n options[\"packageManager\"] = \"pnpm\";\n } else if (arg === \"--use-yarn\") {\n options[\"packageManager\"] = \"yarn\";\n } else if (arg === \"--use-bun\") {\n options[\"packageManager\"] = \"bun\";\n } else if (arg === \"--no-src-dir\") {\n options[\"useSrcDir\"] = false;\n } else if (arg === \"--skip-install\") {\n options[\"skipInstall\"] = true;\n } else if (arg === \"--no-git\") {\n options[\"git\"] = false;\n } else if (arg === \"--yes\" || arg === \"-y\") {\n options[\"yes\"] = true;\n } else if (arg === \"--force\" || arg === \"-f\") {\n options[\"force\"] = true;\n } else if (arg === \"--help\" || arg === \"-h\") {\n showHelp();\n process.exit(0);\n }\n }\n\n try {\n await initCommand(projectName, options);\n } catch (error) {\n console.error(\"❌ Failed to create RouteCraft project:\", error);\n process.exit(1);\n }\n}\n\n/**\n * Initialize a new RouteCraft project\n */\nasync function initCommand(\n projectName?: string,\n options: Record<string, unknown> = {},\n) {\n try {\n // Interactive prompts if values not provided\n const answers = await getUserInput(projectName, options);\n\n // Create project directory\n const projectDir = resolve(process.cwd(), answers.projectName);\n await createProjectDirectory(projectDir, answers.force);\n\n // Generate project structure\n await generateProjectStructure(projectDir, answers);\n\n // Initialize git if requested\n if (answers.git) {\n await initializeGit(projectDir);\n }\n\n // Install dependencies if requested\n if (!answers.skipInstall) {\n await installDependencies(projectDir, answers.packageManager);\n }\n\n // Success message\n console.log(`\n🎉 Successfully created RouteCraft project: ${answers.projectName}\n\nNext steps:\n cd ${answers.projectName}\n ${answers.skipInstall ? `${getPackageManagerCommand(answers.packageManager)} install\\n ` : \"\"}${getPackageManagerCommand(answers.packageManager)} run build\n ${getPackageManagerCommand(answers.packageManager)} run start\n\nFor more information, visit: https://routecraft.dev\n `);\n } catch (error) {\n console.error(`Failed to initialize project: ${error}`);\n process.exit(1);\n }\n}\n\n/**\n * Get user input through prompts or use provided options\n */\nasync function getUserInput(\n projectName?: string,\n options: Record<string, unknown> = {},\n): Promise<Required<InitOptions>> {\n const skipPrompts = options[\"yes\"] === true;\n\n const answers: Required<InitOptions> = {\n projectName:\n projectName ||\n (skipPrompts\n ? \"my-routecraft-app\"\n : await input({\n message: \"What is your project named?\",\n default: \"my-routecraft-app\",\n validate: (value: string) =>\n value.length > 0 || \"Project name cannot be empty\",\n })),\n\n example:\n (options[\"example\"] as ExampleType) ||\n (skipPrompts\n ? \"none\"\n : await select<string>({\n message: \"Choose an example:\",\n choices: [\n { name: \"None - empty project\", value: \"none\" },\n { name: \"Hello World - basic example\", value: \"hello-world\" },\n { name: \"Custom URL (GitHub)\", value: \"custom-url\" },\n ],\n default: \"none\",\n }).then(async (choice) => {\n if (choice === \"custom-url\") {\n return await input({\n message: \"Enter GitHub URL:\",\n validate: (value: string) => {\n if (isUrl(value)) return true;\n return \"Must be a valid GitHub URL\";\n },\n });\n }\n return choice;\n })),\n\n packageManager:\n (options[\"packageManager\"] as PackageManager) ||\n (skipPrompts\n ? \"npm\"\n : await select<PackageManager>({\n message: \"Package manager:\",\n choices: [\n { name: \"npm\", value: \"npm\" },\n { name: \"pnpm\", value: \"pnpm\" },\n { name: \"yarn\", value: \"yarn\" },\n { name: \"bun\", value: \"bun\" },\n ],\n default: \"npm\",\n })),\n\n useSrcDir:\n (options[\"useSrcDir\"] as boolean) ??\n (skipPrompts\n ? false\n : await confirm({\n message: \"Use src directory:\",\n default: false,\n })),\n\n git:\n (options[\"git\"] as boolean) ??\n (skipPrompts\n ? true\n : await confirm({\n message: \"Initialize git:\",\n default: true,\n })),\n\n skipInstall:\n (options[\"skipInstall\"] as boolean) ??\n (skipPrompts\n ? false\n : !(await confirm({\n message: \"Install dependencies now:\",\n default: true,\n }))),\n\n force: (options[\"force\"] as boolean) ?? false,\n\n yes: skipPrompts,\n };\n\n return answers;\n}\n\n/**\n * Create project directory\n */\nasync function createProjectDirectory(\n projectDir: string,\n force: boolean = false,\n) {\n if (existsSync(projectDir)) {\n if (!force) {\n throw new Error(\n `Directory \"${projectDir}\" already exists. Use --force to overwrite.`,\n );\n } else {\n console.log(`⚠️ Overwriting existing directory: ${projectDir}`);\n }\n }\n\n await mkdir(projectDir, { recursive: true });\n console.log(`Created project directory: ${projectDir}`);\n}\n\n/**\n * Generate project structure from template\n */\nasync function generateProjectStructure(\n projectDir: string,\n options: Required<InitOptions>,\n) {\n const baseDir = options.useSrcDir ? join(projectDir, \"src\") : projectDir;\n\n // Create base directories\n await mkdir(join(baseDir, \"routes\"), { recursive: true });\n await mkdir(join(baseDir, \"adapters\"), { recursive: true });\n await mkdir(join(baseDir, \"plugins\"), { recursive: true });\n\n // Generate template files\n const template = NODE_TEMPLATE as Record<string, TemplateFileConfig>;\n const hasExample = options.example !== \"none\";\n\n for (const [filePath, fileConfig] of Object.entries(template)) {\n const fullPath = join(projectDir, filePath);\n await mkdir(dirname(fullPath), { recursive: true });\n\n let content: string;\n if (typeof fileConfig.content === \"function\") {\n // Special handling for index.ts which needs hasExample parameter\n if (filePath === \"index.ts\") {\n content = (fileConfig.content as (arg: boolean) => string)(hasExample);\n } else {\n // Other files like package.json need projectName\n content = (fileConfig.content as (arg: string) => string)(\n options.projectName,\n );\n }\n } else {\n content = fileConfig.content;\n }\n\n await writeFile(fullPath, content);\n console.log(`Created file: ${filePath}`);\n }\n\n // Add example routes if requested\n if (options.example !== \"none\") {\n if (isUrl(options.example)) {\n // Handle GitHub URL examples\n const tempExampleDir = await downloadGitHubExample(options.example);\n try {\n // Copy all files from the downloaded example to the routes directory\n await cp(tempExampleDir, baseDir, {\n recursive: true,\n force: true,\n filter: (src) => {\n // Skip node_modules, .git, and other unwanted directories\n const relativePath = src\n .replace(tempExampleDir, \"\")\n .replace(/^\\//, \"\");\n return (\n !relativePath.includes(\"node_modules\") &&\n !relativePath.includes(\".git\") &&\n !relativePath.includes(\"package-lock.json\") &&\n !relativePath.includes(\"yarn.lock\") &&\n !relativePath.includes(\"pnpm-lock.yaml\")\n );\n },\n });\n console.log(`✅ Added example from ${options.example}`);\n } finally {\n // Cleanup temp directory\n try {\n await rm(tempExampleDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n } else {\n // Handle built-in examples\n const examples = EXAMPLES;\n const example = examples[options.example as keyof typeof examples];\n if (!example) {\n throw new Error(`Unknown example: ${options.example}`);\n }\n for (const [filePath, fileConfig] of Object.entries(example)) {\n const fullPath = join(baseDir, filePath);\n await mkdir(dirname(fullPath), { recursive: true });\n await writeFile(fullPath, fileConfig.content);\n console.log(`Created example file: ${filePath}`);\n }\n }\n }\n\n // Update package.json scripts if using src directory\n if (options.useSrcDir) {\n const packageJsonPath = join(projectDir, \"package.json\");\n const packageJson = JSON.parse(await readFile(packageJsonPath, \"utf-8\"));\n packageJson.scripts = {\n ...packageJson.scripts,\n build: \"tsc\",\n start: \"craft run dist/src/index.js\",\n };\n await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n }\n\n console.log(\"Generated project structure\");\n}\n\n/**\n * Initialize git repository\n */\nasync function initializeGit(projectDir: string) {\n try {\n execSync(\"git init\", { cwd: projectDir, stdio: \"inherit\" });\n execSync(\"git add .\", { cwd: projectDir, stdio: \"inherit\" });\n execSync('git commit -m \"Initial commit\"', {\n cwd: projectDir,\n stdio: \"inherit\",\n });\n console.log(\"Initialized git repository\");\n } catch {\n console.warn(\"Failed to initialize git repository\");\n }\n}\n\n/**\n * Install project dependencies\n */\nasync function installDependencies(\n projectDir: string,\n packageManager: PackageManager,\n) {\n const command = getPackageManagerCommand(packageManager);\n try {\n execSync(`${command} install`, { cwd: projectDir, stdio: \"inherit\" });\n console.log(\"Installed dependencies\");\n } catch {\n console.warn(\n `Failed to install dependencies. Run \"${command} install\" manually.`,\n );\n }\n}\n\n/**\n * Get package manager command\n */\nfunction getPackageManagerCommand(packageManager: PackageManager): string {\n switch (packageManager) {\n case \"npm\":\n return \"npm\";\n case \"pnpm\":\n return \"pnpm\";\n case \"yarn\":\n return \"yarn\";\n case \"bun\":\n return \"bun\";\n default:\n return \"npm\";\n }\n}\n\nfunction showHelp() {\n console.log(`\nCreate a new RouteCraft project\n\nUsage:\n npm create routecraft@latest <project-name> [options]\n npx create-routecraft <project-name> [options]\n\nOptions:\n -e, --example <name|url> Example to include (none, hello-world) or GitHub URL\n --use-npm Use npm as package manager\n --use-pnpm Use pnpm as package manager\n --use-yarn Use yarn as package manager\n --use-bun Use bun as package manager\n --no-src-dir Place project files at root instead of src/\n --skip-install Skip installing dependencies\n --no-git Skip git initialization\n -y, --yes Skip interactive prompts and use defaults\n -f, --force Overwrite existing directory\n -h, --help Show this help message\n\nExamples:\n npm create routecraft@latest my-app\n npm create routecraft@latest my-app --example hello-world --use-pnpm\n npm create routecraft@latest my-app --yes --example hello-world\n npx create-routecraft my-app --force\n npm create routecraft@latest my-app --example https://github.com/user/repo\n npm create routecraft@latest my-app --example https://github.com/user/repo/tree/main/examples/api\n`);\n}\n\n// Run the CLI\nmain().catch((error) => {\n console.error(\"Unexpected error:\", error);\n process.exit(1);\n});\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["__dirname","dirname","fileURLToPath","TEMPLATES_DIR","join","getRoutecraftVersion","packagePath","existsSync","readFileSync","getPackageManagerVersion","packageManager","readTemplateFile","filePath","readFile","processTemplate","content","replacements","processed","key","value","isUrl","example","validateExampleContent","sourceDir","files","readdir","hasPackageJson","hasRouteFiles","file","hasRouteSubdirs","stat","f","error","downloadGitHubExample","url","tempDir","tmpdir","urlPattern","match","owner","repo","branch","subPath","repoUrl","execSync","rm","main","args","showHelp","projectName","remainingArgs","options","i","arg","initCommand","answers","getUserInput","projectDir","resolve","createProjectDirectory","generateProjectStructure","initializeGit","installDependencies","getPackageManagerCommand","skipPrompts","input","select","choice","confirm","force","mkdir","baseDir","hasExample","templateFiles","routecraftVersion","sourceFile","destFile","sourcePath","destPath","writeFile","packageJsonSource","packageJsonContent","indexSource","indexContent","capabilitiesPath","tempExampleDir","cp","src","relativePath","exampleDir","packageJsonPath","packageJson","command"],"mappings":"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","file":"index.js","sourcesContent":["#!/usr/bin/env node\n\n/* eslint-disable no-console */\n\nimport { mkdir, writeFile, readFile, readdir, stat } from \"node:fs/promises\";\nimport { join, resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { input, select, confirm } from \"@inquirer/prompts\";\nimport { tmpdir } from \"node:os\";\nimport { cp, rm } from \"node:fs/promises\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst TEMPLATES_DIR = join(__dirname, \"../templates\");\n\n/**\n * Package manager types\n */\ntype PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\n/**\n * Example types\n */\ntype ExampleType = string;\n\n/**\n * Project initialization options\n */\ninterface InitOptions {\n projectName?: string;\n example?: ExampleType;\n packageManager?: PackageManager;\n useSrcDir?: boolean;\n skipInstall?: boolean;\n git?: boolean;\n force?: boolean;\n yes?: boolean;\n}\n\n/**\n * Get the current version of @routecraft/routecraft from package.json\n */\nfunction getRoutecraftVersion(): string {\n try {\n // Try to read the package.json of the routecraft package\n const packagePath = join(\n dirname(fileURLToPath(import.meta.url)),\n \"../../routecraft/package.json\",\n );\n if (existsSync(packagePath)) {\n const pkg = JSON.parse(readFileSync(packagePath, \"utf-8\"));\n return `^${pkg.version}`;\n }\n } catch {\n // Fallback if we can't read the package.json\n }\n\n // Default fallback - use \"latest\" to always get the newest version\n return \"latest\";\n}\n\n/**\n * Get package manager with version\n */\nfunction getPackageManagerVersion(packageManager: PackageManager): string {\n // In a real implementation, you might want to detect installed versions\n // For now, we'll use sensible defaults\n const versions: Record<PackageManager, string> = {\n pnpm: \"pnpm@10.17.1\",\n npm: \"npm@10.0.0\",\n yarn: \"yarn@4.0.0\",\n bun: \"bun@1.0.0\",\n };\n return versions[packageManager];\n}\n\n/**\n * Read and process a template file\n */\nasync function readTemplateFile(filePath: string): Promise<string> {\n const content = await readFile(filePath, \"utf-8\");\n return content;\n}\n\n/**\n * Process template content with replacements\n */\nfunction processTemplate(\n content: string,\n replacements: Record<string, string>,\n): string {\n let processed = content;\n for (const [key, value] of Object.entries(replacements)) {\n processed = processed.replaceAll(key, value);\n }\n return processed;\n}\n\n// Template files are now stored in the templates/ directory\n\n/**\n * Check if an example string is a URL\n */\nfunction isUrl(example: string): boolean {\n return example.startsWith(\"http://\") || example.startsWith(\"https://\");\n}\n\n/**\n * Validate that the downloaded content contains expected RouteCraft project files\n * @param sourceDir Path to the source directory to validate\n */\nasync function validateExampleContent(sourceDir: string): Promise<void> {\n try {\n const files = await readdir(sourceDir);\n\n // Check for basic project structure indicators\n const hasPackageJson = files.includes(\"package.json\");\n const hasRouteFiles = files.some(\n (file) =>\n file.endsWith(\".ts\") ||\n file.endsWith(\".js\") ||\n file.endsWith(\".mjs\") ||\n file.includes(\"route\"),\n );\n\n // Check if there are subdirectories that might contain routes\n let hasRouteSubdirs = false;\n for (const file of files) {\n const filePath = join(sourceDir, file);\n const fileStat = await stat(filePath);\n if (fileStat.isDirectory()) {\n const subFiles = await readdir(filePath);\n if (\n subFiles.some(\n (f) => f.endsWith(\".ts\") || f.endsWith(\".js\") || f.endsWith(\".mjs\"),\n )\n ) {\n hasRouteSubdirs = true;\n break;\n }\n }\n }\n\n if (!hasPackageJson && !hasRouteFiles && !hasRouteSubdirs) {\n throw new Error(\n \"Downloaded content doesn't appear to be a valid RouteCraft project. \" +\n \"Expected to find package.json or route files (.ts, .js, .mjs).\",\n );\n }\n\n console.log(\"✅ Downloaded content validated successfully\");\n } catch (error) {\n throw new Error(\n `Content validation failed: ${error instanceof Error ? error.message : error}`,\n );\n }\n}\n\n/**\n * Download and extract a GitHub example\n */\nasync function downloadGitHubExample(url: string): Promise<string> {\n const tempDir = join(tmpdir(), `routecraft-example-${Date.now()}`);\n\n try {\n console.log(`📥 Downloading example from ${url}...`);\n\n // For GitHub URLs, we'll use git clone for simplicity\n // Extract repo info from URL\n const urlPattern =\n /^https?:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)(?:\\/tree\\/([^/]+)\\/(.+))?$/;\n const match = url.match(urlPattern);\n\n if (!match) {\n throw new Error(`Invalid GitHub URL format: ${url}`);\n }\n\n const [, owner, repo, branch = \"main\", subPath = \"\"] = match;\n const repoUrl = `https://github.com/${owner}/${repo}.git`;\n\n // Clone the repo (try with credentials if available, fallback to public access)\n try {\n execSync(\n `git clone --depth 1 ${branch ? `--branch ${branch}` : \"\"} ${repoUrl} ${tempDir}`,\n {\n stdio: \"inherit\",\n },\n );\n } catch {\n // If git clone fails, try a different approach or provide better error\n throw new Error(\n `Failed to clone repository. Make sure the repository is public and accessible: ${repoUrl}`,\n );\n }\n\n // If there's a subPath, use that subdirectory\n const sourceDir = subPath ? join(tempDir, subPath) : tempDir;\n\n if (!existsSync(sourceDir)) {\n throw new Error(`Path ${subPath} not found in repository`);\n }\n\n // Validate downloaded content structure\n await validateExampleContent(sourceDir);\n\n return sourceDir;\n } catch (error) {\n // Cleanup on error\n try {\n await rm(tempDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n throw new Error(`Failed to download example from ${url}: ${error}`);\n }\n}\n\n/**\n * Main entry point for create-routecraft\n * This is called by npm create routecraft <project-name>\n */\nasync function main() {\n const args = process.argv.slice(2);\n\n // Check for help flag first\n if (args.includes(\"--help\") || args.includes(\"-h\")) {\n showHelp();\n process.exit(0);\n }\n\n // npm create passes the project name as the first argument\n const projectName = args[0];\n\n if (!projectName) {\n console.error(\"❌ Project name is required\");\n console.log(\"Usage: npm create routecraft@latest <project-name> [options]\");\n console.log(\"Or: npx create-routecraft <project-name> [options]\");\n console.log(\"Run with --help for more information\");\n process.exit(1);\n }\n\n // Parse additional arguments\n const remainingArgs = args.slice(1);\n const options: Record<string, unknown> = {};\n\n // Simple argument parsing for common options\n for (let i = 0; i < remainingArgs.length; i++) {\n const arg = remainingArgs[i];\n\n if (arg === \"--example\" || arg === \"-e\") {\n options[\"example\"] = remainingArgs[i + 1];\n i++; // Skip next arg\n } else if (arg === \"--use-npm\") {\n options[\"packageManager\"] = \"npm\";\n } else if (arg === \"--use-pnpm\") {\n options[\"packageManager\"] = \"pnpm\";\n } else if (arg === \"--use-yarn\") {\n options[\"packageManager\"] = \"yarn\";\n } else if (arg === \"--use-bun\") {\n options[\"packageManager\"] = \"bun\";\n } else if (arg === \"--no-src-dir\") {\n options[\"useSrcDir\"] = false;\n } else if (arg === \"--skip-install\") {\n options[\"skipInstall\"] = true;\n } else if (arg === \"--no-git\") {\n options[\"git\"] = false;\n } else if (arg === \"--yes\" || arg === \"-y\") {\n options[\"yes\"] = true;\n } else if (arg === \"--force\" || arg === \"-f\") {\n options[\"force\"] = true;\n } else if (arg === \"--help\" || arg === \"-h\") {\n showHelp();\n process.exit(0);\n }\n }\n\n try {\n await initCommand(projectName, options);\n } catch (error) {\n console.error(\"❌ Failed to create RouteCraft project:\", error);\n process.exit(1);\n }\n}\n\n/**\n * Initialize a new RouteCraft project\n */\nasync function initCommand(\n projectName?: string,\n options: Record<string, unknown> = {},\n) {\n try {\n // Interactive prompts if values not provided\n const answers = await getUserInput(projectName, options);\n\n // Create project directory\n const projectDir = resolve(process.cwd(), answers.projectName);\n await createProjectDirectory(projectDir, answers.force);\n\n // Generate project structure\n await generateProjectStructure(projectDir, answers);\n\n // Initialize git if requested\n if (answers.git) {\n await initializeGit(projectDir);\n }\n\n // Install dependencies if requested\n if (!answers.skipInstall) {\n await installDependencies(projectDir, answers.packageManager);\n }\n\n // Success message\n console.log(`\n🎉 Successfully created RouteCraft project: ${answers.projectName}\n\nNext steps:\n cd ${answers.projectName}\n ${answers.skipInstall ? `${getPackageManagerCommand(answers.packageManager)} install\\n ` : \"\"}${getPackageManagerCommand(answers.packageManager)} run start\n\nFor more information, visit: https://routecraft.dev\n `);\n } catch (error) {\n console.error(`Failed to initialize project: ${error}`);\n process.exit(1);\n }\n}\n\n/**\n * Get user input through prompts or use provided options\n */\nasync function getUserInput(\n projectName?: string,\n options: Record<string, unknown> = {},\n): Promise<Required<InitOptions>> {\n const skipPrompts = options[\"yes\"] === true;\n\n const answers: Required<InitOptions> = {\n projectName:\n projectName ||\n (skipPrompts\n ? \"my-routecraft-app\"\n : await input({\n message: \"What is your project named?\",\n default: \"my-routecraft-app\",\n validate: (value: string) =>\n value.length > 0 || \"Project name cannot be empty\",\n })),\n\n example:\n (options[\"example\"] as ExampleType) ||\n (skipPrompts\n ? \"none\"\n : await select<string>({\n message: \"Choose an example:\",\n choices: [\n { name: \"None - empty project\", value: \"none\" },\n { name: \"Hello World - basic example\", value: \"hello-world\" },\n { name: \"Custom URL (GitHub)\", value: \"custom-url\" },\n ],\n default: \"none\",\n }).then(async (choice) => {\n if (choice === \"custom-url\") {\n return await input({\n message: \"Enter GitHub URL:\",\n validate: (value: string) => {\n if (isUrl(value)) return true;\n return \"Must be a valid GitHub URL\";\n },\n });\n }\n return choice;\n })),\n\n packageManager:\n (options[\"packageManager\"] as PackageManager) ||\n (skipPrompts\n ? \"npm\"\n : await select<PackageManager>({\n message: \"Package manager:\",\n choices: [\n { name: \"npm\", value: \"npm\" },\n { name: \"pnpm\", value: \"pnpm\" },\n { name: \"yarn\", value: \"yarn\" },\n { name: \"bun\", value: \"bun\" },\n ],\n default: \"npm\",\n })),\n\n useSrcDir:\n (options[\"useSrcDir\"] as boolean) ??\n (skipPrompts\n ? false\n : await confirm({\n message: \"Use src directory:\",\n default: false,\n })),\n\n git:\n (options[\"git\"] as boolean) ??\n (skipPrompts\n ? true\n : await confirm({\n message: \"Initialize git:\",\n default: true,\n })),\n\n skipInstall:\n (options[\"skipInstall\"] as boolean) ??\n (skipPrompts\n ? false\n : !(await confirm({\n message: \"Install dependencies now:\",\n default: true,\n }))),\n\n force: (options[\"force\"] as boolean) ?? false,\n\n yes: skipPrompts,\n };\n\n return answers;\n}\n\n/**\n * Create project directory\n */\nasync function createProjectDirectory(\n projectDir: string,\n force: boolean = false,\n) {\n if (existsSync(projectDir)) {\n if (!force) {\n throw new Error(\n `Directory \"${projectDir}\" already exists. Use --force to overwrite.`,\n );\n } else {\n console.log(`⚠️ Overwriting existing directory: ${projectDir}`);\n }\n }\n\n await mkdir(projectDir, { recursive: true });\n console.log(`Created project directory: ${projectDir}`);\n}\n\n/**\n * Generate project structure from template\n */\nasync function generateProjectStructure(\n projectDir: string,\n options: Required<InitOptions>,\n) {\n const baseDir = options.useSrcDir ? join(projectDir, \"src\") : projectDir;\n const hasExample = options.example !== \"none\";\n\n // Create base directories\n await mkdir(join(baseDir, \"capabilities\"), { recursive: true });\n await mkdir(join(baseDir, \"adapters\"), { recursive: true });\n await mkdir(join(baseDir, \"plugins\"), { recursive: true });\n\n // Template files mapping (source -> destination)\n const templateFiles: Record<string, string> = {\n gitignore: \".gitignore\",\n \".prettierrc\": \".prettierrc\",\n \"craft.config.ts\": \"craft.config.ts\",\n \"eslint.config.mjs\": \"eslint.config.mjs\",\n \"tsconfig.json\": \"tsconfig.json\",\n \"vitest.config.ts\": \"vitest.config.ts\",\n };\n\n const routecraftVersion = getRoutecraftVersion();\n\n // Copy base template files\n for (const [sourceFile, destFile] of Object.entries(templateFiles)) {\n const sourcePath = join(TEMPLATES_DIR, \"base\", sourceFile);\n const destPath = join(projectDir, destFile);\n\n const content = await readTemplateFile(sourcePath);\n await writeFile(destPath, content);\n console.log(`Created file: ${destFile}`);\n }\n\n // Handle package.json with replacements\n const packageJsonSource = join(TEMPLATES_DIR, \"base\", \"package.json\");\n let packageJsonContent = await readTemplateFile(packageJsonSource);\n packageJsonContent = processTemplate(packageJsonContent, {\n PROJECT_NAME: options.projectName,\n ROUTECRAFT_VERSION: routecraftVersion,\n PACKAGE_MANAGER: getPackageManagerVersion(options.packageManager),\n });\n await writeFile(join(projectDir, \"package.json\"), packageJsonContent);\n console.log(`Created file: package.json`);\n\n // Handle index.ts based on whether example is included\n const indexTemplate = hasExample ? \"index-with-example.ts\" : \"index-empty.ts\";\n const indexSource = join(TEMPLATES_DIR, \"base\", indexTemplate);\n let indexContent = await readTemplateFile(indexSource);\n\n // Replace import path based on useSrcDir\n const capabilitiesPath = options.useSrcDir\n ? \"./src/capabilities\"\n : \"./capabilities\";\n indexContent = processTemplate(indexContent, {\n CAPABILITIES_IMPORT_PATH: capabilitiesPath,\n });\n\n await writeFile(join(projectDir, \"index.ts\"), indexContent);\n console.log(`Created file: index.ts`);\n\n // Add example routes if requested\n if (options.example !== \"none\") {\n if (isUrl(options.example)) {\n // Handle GitHub URL examples\n const tempExampleDir = await downloadGitHubExample(options.example);\n try {\n // Copy all files from the downloaded example to the base directory\n await cp(tempExampleDir, baseDir, {\n recursive: true,\n force: true,\n filter: (src) => {\n // Skip node_modules, .git, and other unwanted directories\n const relativePath = src\n .replace(tempExampleDir, \"\")\n .replace(/^\\//, \"\");\n return (\n !relativePath.includes(\"node_modules\") &&\n !relativePath.includes(\".git\") &&\n !relativePath.includes(\"package-lock.json\") &&\n !relativePath.includes(\"yarn.lock\") &&\n !relativePath.includes(\"pnpm-lock.yaml\")\n );\n },\n });\n console.log(`✅ Added example from ${options.example}`);\n } finally {\n // Cleanup temp directory\n try {\n await rm(tempExampleDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n } else {\n // Handle built-in examples - copy from templates/examples/\n const exampleDir = join(TEMPLATES_DIR, \"examples\", options.example);\n if (existsSync(exampleDir)) {\n await cp(exampleDir, baseDir, {\n recursive: true,\n force: false,\n });\n console.log(`✅ Added ${options.example} example`);\n } else {\n throw new Error(`Unknown example: ${options.example}`);\n }\n }\n }\n\n // Update package.json scripts if using src directory\n if (options.useSrcDir) {\n const packageJsonPath = join(projectDir, \"package.json\");\n const packageJson = JSON.parse(await readFile(packageJsonPath, \"utf-8\"));\n packageJson.scripts = {\n ...packageJson.scripts,\n build: \"tsc\",\n start: \"craft run src/index.ts\",\n };\n await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n }\n\n console.log(\"Generated project structure\");\n}\n\n/**\n * Initialize git repository\n */\nasync function initializeGit(projectDir: string) {\n try {\n execSync(\"git init\", { cwd: projectDir, stdio: \"inherit\" });\n execSync(\"git add .\", { cwd: projectDir, stdio: \"inherit\" });\n execSync('git commit -m \"Initial commit\"', {\n cwd: projectDir,\n stdio: \"inherit\",\n });\n console.log(\"Initialized git repository\");\n } catch {\n console.warn(\"Failed to initialize git repository\");\n }\n}\n\n/**\n * Install project dependencies\n */\nasync function installDependencies(\n projectDir: string,\n packageManager: PackageManager,\n) {\n const command = getPackageManagerCommand(packageManager);\n try {\n execSync(`${command} install`, { cwd: projectDir, stdio: \"inherit\" });\n console.log(\"Installed dependencies\");\n } catch {\n console.warn(\n `Failed to install dependencies. Run \"${command} install\" manually.`,\n );\n }\n}\n\n/**\n * Get package manager command\n */\nfunction getPackageManagerCommand(packageManager: PackageManager): string {\n switch (packageManager) {\n case \"npm\":\n return \"npm\";\n case \"pnpm\":\n return \"pnpm\";\n case \"yarn\":\n return \"yarn\";\n case \"bun\":\n return \"bun\";\n default:\n return \"npm\";\n }\n}\n\nfunction showHelp() {\n console.log(`\nCreate a new RouteCraft project\n\nUsage:\n npm create routecraft@latest <project-name> [options]\n npx create-routecraft <project-name> [options]\n\nOptions:\n -e, --example <name|url> Example to include (none, hello-world) or GitHub URL\n --use-npm Use npm as package manager\n --use-pnpm Use pnpm as package manager\n --use-yarn Use yarn as package manager\n --use-bun Use bun as package manager\n --no-src-dir Place project files at root instead of src/\n --skip-install Skip installing dependencies\n --no-git Skip git initialization\n -y, --yes Skip interactive prompts and use defaults\n -f, --force Overwrite existing directory\n -h, --help Show this help message\n\nExamples:\n npm create routecraft@latest my-app\n npm create routecraft@latest my-app --example hello-world --use-pnpm\n npm create routecraft@latest my-app --yes --example hello-world\n npx create-routecraft my-app --force\n npm create routecraft@latest my-app --example https://github.com/user/repo\n npm create routecraft@latest my-app --example https://github.com/user/repo/tree/main/examples/api\n`);\n}\n\n// Run the CLI\nmain().catch((error) => {\n console.error(\"Unexpected error:\", error);\n process.exit(1);\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-routecraft",
3
- "version": "0.3.0-canary.8",
3
+ "version": "0.3.0",
4
4
  "description": "Create a new RouteCraft project",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -8,7 +8,8 @@
8
8
  "create-routecraft": "./dist/index.js"
9
9
  },
10
10
  "files": [
11
- "dist"
11
+ "dist",
12
+ "templates"
12
13
  ],
13
14
  "scripts": {
14
15
  "build": "tsup src/index.ts --format esm --dts",
@@ -19,6 +20,9 @@
19
20
  "dependencies": {
20
21
  "@inquirer/prompts": "^8.3.0"
21
22
  },
23
+ "devDependencies": {
24
+ "@routecraft/testing": "^0.4.0"
25
+ },
22
26
  "publishConfig": {
23
27
  "access": "public"
24
28
  },
@@ -0,0 +1,7 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": false,
4
+ "tabWidth": 2,
5
+ "trailingComma": "all",
6
+ "printWidth": 80
7
+ }
@@ -0,0 +1,5 @@
1
+ import type { CraftConfig } from "@routecraft/routecraft";
2
+
3
+ const config: CraftConfig = {};
4
+
5
+ export default config;
@@ -0,0 +1,22 @@
1
+ import pluginJs from "@eslint/js";
2
+ import tseslint from "typescript-eslint";
3
+ import routecraftPlugin from "@routecraft/eslint-plugin-routecraft";
4
+
5
+ /** @type {import('eslint').Linter.Config[]} */
6
+ export default [
7
+ {
8
+ ignores: ["dist/**", "coverage/**", "node_modules/**"],
9
+ },
10
+ pluginJs.configs.recommended,
11
+ ...tseslint.configs.recommended,
12
+ {
13
+ files: [
14
+ "capabilities/**/*.{ts,js}",
15
+ "adapters/**/*.{ts,js}",
16
+ "plugins/**/*.{ts,js}",
17
+ "index.{ts,js}",
18
+ ],
19
+ plugins: { "@routecraft/routecraft": routecraftPlugin },
20
+ ...routecraftPlugin.configs.recommended,
21
+ },
22
+ ];
@@ -0,0 +1,8 @@
1
+ node_modules/
2
+ dist/
3
+ .env
4
+ .env.local
5
+ .env.*.local
6
+ *.log
7
+ .DS_Store
8
+ .idea/
@@ -0,0 +1,4 @@
1
+ export { default as craftConfig } from "./craft.config.js";
2
+
3
+ // Export all routes as default for craft run
4
+ export default [];
@@ -0,0 +1,5 @@
1
+ export { default as craftConfig } from "./craft.config.js";
2
+ import helloWorldRoute from "CAPABILITIES_IMPORT_PATH/hello-world.js";
3
+
4
+ // Export all routes as default for craft run
5
+ export default [helloWorldRoute];
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "PROJECT_NAME",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "packageManager": "PACKAGE_MANAGER",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "start": "craft run index.ts --log-level info",
10
+ "lint": "eslint .",
11
+ "format": "prettier . --check --ignore-unknown",
12
+ "format:write": "prettier . --write --ignore-unknown",
13
+ "typecheck": "tsc --noEmit",
14
+ "test": "vitest run",
15
+ "test:watch": "vitest",
16
+ "test:coverage": "vitest run --coverage"
17
+ },
18
+ "dependencies": {
19
+ "@routecraft/routecraft": "ROUTECRAFT_VERSION"
20
+ },
21
+ "devDependencies": {
22
+ "@eslint/js": "^10.0.1",
23
+ "@routecraft/cli": "ROUTECRAFT_VERSION",
24
+ "@routecraft/testing": "ROUTECRAFT_VERSION",
25
+ "@routecraft/eslint-plugin-routecraft": "ROUTECRAFT_VERSION",
26
+ "@types/node": "^25.3.5",
27
+ "@vitest/coverage-v8": "^4.0.18",
28
+ "eslint": "^10.0.2",
29
+ "pino-pretty": "^13.1.3",
30
+ "prettier": "^3.8.1",
31
+ "typescript": "^5.9.3",
32
+ "typescript-eslint": "^8.56.1",
33
+ "vitest": "^4.0.18"
34
+ }
35
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./dist",
7
+ "rootDir": ".",
8
+ "allowSyntheticDefaultImports": true,
9
+ "esModuleInterop": true,
10
+ "allowJs": true,
11
+ "strict": true,
12
+ "skipLibCheck": true,
13
+ "isolatedModules": true,
14
+ "resolveJsonModule": true
15
+ },
16
+ "include": ["**/*.ts", "**/*.js"],
17
+ "exclude": [
18
+ "node_modules",
19
+ "dist",
20
+ "**/*.test.ts",
21
+ "**/*.spec.ts",
22
+ "**/*.config.ts",
23
+ "vitest.config.ts",
24
+ "craft.config.ts"
25
+ ]
26
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: "node",
7
+ include: ["**/*.test.ts"],
8
+ },
9
+ });
@@ -0,0 +1,73 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { testContext, type TestContext } from "@routecraft/testing";
3
+ import capabilities from "./hello-world.js";
4
+
5
+ describe("Hello World Route", () => {
6
+ let t: TestContext;
7
+ let fetchMock: ReturnType<typeof vi.fn>;
8
+
9
+ beforeEach(() => {
10
+ // Mock globalThis.fetch to prevent real API calls
11
+ fetchMock = vi.fn();
12
+ globalThis.fetch = fetchMock as unknown as typeof globalThis.fetch;
13
+ });
14
+
15
+ afterEach(async () => {
16
+ if (t) {
17
+ await t.stop();
18
+ }
19
+ vi.restoreAllMocks();
20
+ });
21
+
22
+ /**
23
+ * @case Verifies that the route fetches user data and greets the person by name
24
+ * @preconditions Route is imported and fetch is mocked
25
+ * @expectedResult Route should fetch user and output "Hello, [name]!"
26
+ */
27
+ it("should fetch user and greet by name", async () => {
28
+ // Mock user data from JSON Placeholder
29
+ const mockUser = {
30
+ id: 1,
31
+ name: "Leanne Graham",
32
+ username: "Bret",
33
+ email: "Sincere@april.biz",
34
+ };
35
+
36
+ // Mock the fetch response
37
+ fetchMock.mockResolvedValue({
38
+ ok: true,
39
+ status: 200,
40
+ headers: new Map([["content-type", "application/json"]]),
41
+ text: async () => JSON.stringify(mockUser),
42
+ url: "https://jsonplaceholder.typicode.com/users/1",
43
+ });
44
+
45
+ // Create context with imported route and run full lifecycle (t.logger is a spy)
46
+ t = await testContext().routes(capabilities).build();
47
+ await t.test();
48
+
49
+ // Verify fetch was called with the correct URL
50
+ expect(fetchMock).toHaveBeenCalledTimes(1);
51
+ expect(fetchMock).toHaveBeenCalledWith(
52
+ "https://jsonplaceholder.typicode.com/users/1",
53
+ expect.objectContaining({
54
+ method: "GET",
55
+ }),
56
+ );
57
+
58
+ // Verify the log was called (route completed)
59
+ expect(t.logger.info).toHaveBeenCalled();
60
+
61
+ // Find the LogAdapter output call (pino.info(object, message)); lifecycle also logs at info
62
+ const infoSpy = t.logger.info as ReturnType<typeof vi.fn>;
63
+ const logAdapterCall = infoSpy.mock.calls.find(
64
+ (call: unknown[]) => call[1] === "LogAdapter output",
65
+ );
66
+ expect(logAdapterCall).toBeDefined();
67
+ const result = logAdapterCall![0];
68
+
69
+ // Assert the greeting message
70
+ expect(result).toBeDefined();
71
+ expect(result.body).toBe("Hello, Leanne Graham!");
72
+ });
73
+ });
@@ -0,0 +1,14 @@
1
+ import { log, craft, simple, http } from "@routecraft/routecraft";
2
+
3
+ export default craft()
4
+ .id("hello-world")
5
+ .from(simple({ userId: 1 }))
6
+ .enrich(
7
+ http<{ userId: number }, { name: string }>({
8
+ method: "GET",
9
+ url: (ex) =>
10
+ `https://jsonplaceholder.typicode.com/users/${ex.body.userId}`,
11
+ }),
12
+ )
13
+ .transform((result) => `Hello, ${result.body.name}!`)
14
+ .to(log());