@arkenv/cli 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +27 -27
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -108,7 +108,7 @@ ${t?(0,a.styleText)(`cyan`,V):``}
|
|
|
108
108
|
outdir: "./dist",
|
|
109
109
|
${y.default.green(`plugins: [arkenv]`)}
|
|
110
110
|
});
|
|
111
|
-
`),{success:!0,instructions:a.trim()}}async function Dt(e,t){let n=t||await J();if(!n)return{status:`not_found`};let i=r.default.basename(n);try{let t=await e.readFile(n);if((0,u.parse)(t)?.compilerOptions?.strict===!0)return{status:`already_strict`,file:i};let r=(0,u.applyEdits)(t,(0,u.modify)(t,[`compilerOptions`,`strict`],!0,{formattingOptions:{insertSpaces:!0,tabSize:2}}));return await e.writeFile(n,r),{status:`updated`,file:i}}catch{return{status:`error`,file:i}}}var Ot=class{constructor(e,t){this.isQuiet=e,this.stdio=t}async exists(e){try{return await n.default.access(e),!0}catch{return!1}}async readFile(e){return n.default.readFile(e,`utf-8`)}async writeFile(e,t){await n.default.writeFile(e,t,`utf-8`)}async mkdir(e,t){await n.default.mkdir(e,{recursive:t})}async execute(e,t=[],n){return new Promise((r,i)=>{let a=(0,d.spawn)(e,t,{cwd:n,stdio:this.isQuiet?`pipe`:this.stdio,shell:!1}),o=``,s=``,c=1e4;this.isQuiet&&(a.stdout?.on(`data`,e=>{o=(o+e.toString()).slice(-c)}),a.stderr?.on(`data`,e=>{s=(s+e.toString()).slice(-c)})),a.on(`close`,(e,t)=>{if(e===0)r();else{let n=e===null?`Command terminated by signal ${t}`:`Command failed with code ${e}`;this.isQuiet&&(o&&(n+=`\n${y.default.dim(`STDOUT:`)}\n${o}`),s&&(n+=`\n${y.default.red(`STDERR:`)}\n${s}`)),i(Error(n))}}),a.on(`error`,i)})}async updateTsConfigToStrict(e){return Dt(this,e)}async findViteConfig(e){return Ct(e)}async findBunConfig(e){return wt(e)}async bootstrapViteConfig(e,t){return Tt(this,e,t)}async bootstrapBunConfig(e,t){return Et(e,t)}async safeAppend(e,t,n){let{safeAppend:r}=await Promise.resolve().then(()=>p);return r(e,t,n)}};async function kt(e){let t=e.defaultPath||`./src/env.ts`;if(e.hasEnvSchemaFile){let e=await U({message:y.default.yellow(`An existing ArkEnv configuration was found at ${Y(t)}. Do you want to overwrite it?`),initialValue:!1,active:`Yes (override my configuration)`,inactive:`No (abort)`});return I(e)||!e?null:e}return!0}async function At(e){let t=e.detectedKeys,n=e.keysSource||`.env.example`;if(t&&t.length>0){let e=t.length,r=e===1,i=await U({message:n===`.env.example`?`Detected ${Y(`.env.example`)} with ${e} ${r?`key`:`keys`}. Use ${r?`it`:`them`} for your schema?`:`Detected ${e} environment variable${r?``:`s`} used in your project. Use ${r?`it`:`them`} for your schema?`,active:`Yes (Recommended)`,initialValue:!0});return I(i)?null:i}return!1}async function jt(e){if(e.framework===`vite`||e.framework===`bun-fullstack`){let t=e.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`;if(e.hasTypeFile)return!0;let n=await U({message:`Establish ${Y(t)} for typesafe environment variables?`,initialValue:!0,active:`Yes (Recommended)`,inactive:`No`});return I(n)?null:n}return!0}async function Mt(e){if(!e.installTypeDefinitions||e.framework!==`vite`&&e.framework!==`bun-fullstack`)return`skip`;let t=e.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`;if(e.hasTypeFile){let e=await K({message:`Found existing ${Y(t)}. How should we handle ArkEnv types?`,options:[{value:`append`,label:`Append types safely (if needed)`,hint:`Recommended`},{value:`overwrite`,label:`Overwrite entirely`,hint:`Destructive`},{value:`skip`,label:`Skip`}]});return I(e)?null:e}return`overwrite`}async function Nt(e){let t=await K({message:`Select an example:`,options:e.examples.map(e=>({value:e.id,label:e.name,...e.description?{hint:e.description}:{}}))});return I(t)?null:t}async function Pt(e){let t=await K({message:`Select your framework or build tool:`,initialValue:e.framework,options:[{value:`vanilla`,label:`Vanilla${e.framework===`vanilla`?` (Detected)`:``}`,hint:`Node.js, Bun, server-side or runtime-only validation`},{value:`vite`,label:`Vite${e.framework===`vite`?` (Detected)`:``}`,hint:`Client-side and static inlining validation`},{value:`bun-fullstack`,label:`Bun fullstack dev server${e.framework===`bun-fullstack`?` (Detected)`:``}`,hint:`Client-side bundling and Bun.serve integration`},{value:`nextjs`,label:`Next.js${e.framework===`nextjs`?` (Detected)`:``}`,hint:`Next.js App or Pages Router with build and runtime validation`}]});return I(t)?null:t}async function Ft(e){let t=await U({message:`Optional: Would you also like to bootstrap a custom Bun.build script for programmatic bundling?`,initialValue:e.initialValue??!1});return I(t)?null:t}async function It(){let e=await K({message:`Select your preferred validator library:`,options:[{value:`arktype`,label:`ArkType (Recommended)`,hint:`TypeScript's 1:1 validator, optimized from editor to runtime`},{value:`zod`,label:`Zod`,hint:`TypeScript-first schema validation with static type inference`},{value:`valibot`,label:`Valibot`,hint:`The modular and type safe schema library`}]});return I(e)?null:e}async function Lt(){let e=await K({message:`How would you like to structure your environment variables?`,options:[{value:`strict`,label:`Strict (Recommended)`,hint:`Generates separate shared, client, and server files for maximum security`},{value:`simple`,label:`Simple`,hint:`Generates a single unified file for quick prototyping`}]});return I(e)?null:e}async function Rt(e){let t=await U({message:`Enable automated Next.js code generation for environment variables?`,initialValue:e.initialValue??!0,active:`Yes (Recommended)`,inactive:`No`});return I(t)?null:t}async function zt(e){let t=await U({message:`Use default config path (${Y(e.defaultEnvPath||`./src/env.ts`)})?`,initialValue:!0,active:`Yes (Recommended)`,inactive:`No, let me customize it`});return I(t)?null:t}async function Bt(e){let t=e.defaultEnvPath||`./src/env.ts`;if(!e.useDefaultPath){let e=await $e({message:`Where should we create the ArkEnv config?`,placeholder:t,initialValue:t,defaultValue:t});if(I(e))return null;let n=typeof e==`string`?e.trim():``;return n===``?t:n}return t}const X={example:Nt,overwriteEnvSchemaFile:kt,framework:Pt,bunBuild:Ft,layout:Lt,nextjsCodegen:Rt,useDefaultPath:zt,path:Bt,installTypeDefinitions:jt,envDtsHandling:Mt,validator:It,useEnvExample:At};async function Vt(e,t=!1){return(e?.mode||`existing`)===`new`?Ht(e,t):Ut(e,t)}async function Ht(e,t=!1){let n=e?.examples||[],i=`arkenv-project`;try{let a;if(e?.name){let t=e.name.trim();a=t===`.`||t===`./`||r.default.resolve(process.cwd(),t)===process.cwd()?`.`:t}else if(t)a=i;else{let e=(Z(await $e({message:`Project name:`,placeholder:i,defaultValue:i}))||i).trim();a=e===`.`||e===`./`||r.default.resolve(process.cwd(),e)===process.cwd()?`.`:e}let o=e?.example;!o&&!t?o=Z(await X.example({examples:n})):!o&&t&&(o=`basic`);let s=n.find(e=>e.id===o);if(!s){let e=n.map(e=>e.id).join(`, `);throw Error(`Unknown example ${o}. Available examples: ${e}`)}return{mode:`new`,example:s.id,name:a,path:`./src/env.ts`,validator:`arktype`,framework:s.framework,language:`ts`,installSkill:!1}}catch(e){if(e instanceof Gt)return null;throw e}}async function Ut(e,n=!1){let r=e?.defaultEnvPath||`./src/env.ts`,i=e?.envKeys||null,a=e?.envKeysSource||`.env.example`;if(n){let n=e?.framework||`vanilla`,a;n===`nextjs`&&(a=e?.isStrict?`strict`:e?.isSimple?`simple`:`strict`);let o=await Wt(e,n,r),s;return(n===`vite`||n===`bun-fullstack`)&&(s=o?`append`:`overwrite`),(0,t.shake)({mode:`existing`,path:r,validator:`arktype`,framework:n,layout:a,bunFeatures:n===`bun-fullstack`?e?.bunFeatures??[`serve`]:void 0,language:`ts`,overwriteEnvSchemaFile:!0,installTypeDefinitions:n===`vite`||n===`bun-fullstack`,installSkill:!1,envDtsHandling:s,envKeys:i??void 0,disableCodegen:e?.disableCodegen??!1})}try{let n=Z(await X.overwriteEnvSchemaFile({hasEnvSchemaFile:e?.hasEnvSchemaFile??!1,defaultPath:r})),o=Z(await X.framework({framework:e?.framework})),s;o===`nextjs`&&(s=e?.isStrict?`strict`:e?.isSimple?`simple`:Z(await X.layout()));let c;if(o===`bun-fullstack`){let t=!!e?.bunFeatures?.includes(`build`);c=Z(await X.bunBuild({initialValue:t}))}let l=e?.disableCodegen;o===`nextjs`&&l===void 0&&(l=!Z(await X.nextjsCodegen({initialValue:!0})));let u=Z(await X.useDefaultPath({defaultEnvPath:r})),d=Z(await X.path({useDefaultPath:u,defaultEnvPath:r})),f=await Wt(e,o,d),p=Z(await X.installTypeDefinitions({framework:o,hasTypeFile:f})),m=Z(await X.envDtsHandling({framework:o,installTypeDefinitions:p,hasTypeFile:f})),h=Z(await X.validator()),g=Z(await X.useEnvExample({detectedKeys:i,keysSource:a}));return(0,t.shake)({mode:`existing`,overwriteEnvSchemaFile:n,framework:o,layout:s,path:d,installTypeDefinitions:p,envDtsHandling:m,validator:h,bunFeatures:o===`bun-fullstack`?c?[`serve`,`build`]:[`serve`]:void 0,language:`ts`,installSkill:!1,envKeys:g?i??void 0:void 0,disableCodegen:l})}catch(e){if(e instanceof Gt)return null;throw e}}async function Wt(e,t,n){return await e?.hasTypeFileAtPath?.({framework:t,envPath:n})??e?.hasTypeFile??!1}var Gt=class extends Error{constructor(){super(`Operation cancelled`)}};function Z(e){if(e===null||I(e))throw Ge(`Operation cancelled`),new Gt;return e}var Kt=class{async confirm(e,n=!0,r,i){let a=await U((0,t.shake)({message:e,initialValue:n,active:r,inactive:i}));return I(a)?null:a}async runWizard(e,t=!1){return Vt(e,t)}};const qt={isYes:{long:`--yes`,short:`-y`,kind:`boolean`},isForce:{long:`--force`,short:`-f`,kind:`boolean`},isQuiet:{long:`--quiet`,short:`-q`,kind:`boolean`},isJson:{long:`--json`,short:`-j`,kind:`boolean`},isAgent:{long:`--agent`,short:`-a`,kind:`boolean`},helpRequested:{long:`--help`,short:`-h`,kind:`boolean`},example:{long:`--example`,short:`-e`,kind:`value`},isStrict:{long:`--strict`,short:``,kind:`boolean`},isSimple:{long:`--simple`,short:``,kind:`boolean`},noCodegen:{long:`--no-codegen`,short:`-C`,kind:`boolean`}},Jt=new Set(Object.values(qt).flatMap(e=>[e.long,e.short].filter(Boolean))),Yt=new Set(Object.values(qt).filter(e=>e.kind===`value`).flatMap(e=>[e.long,e.short].filter(Boolean)));var Xt=class{constructor(e,t={}){let n=e.slice(2),r=[],i=!1;for(let e of n){if(i){r.push(e),i=!1;continue}if(Yt.has(e)){r.push(e),i=!0;continue}if(/^-[a-zA-Z]{2,}$/.test(e)){let t=e.slice(1).split(``);for(let e of t)r.push(`-${e}`);Yt.has(`-${t[t.length-1]}`)&&(i=!0)}else r.push(e)}this.args=r,this.command=this.args[0];let a=1,o=[];for(this.validationError=void 0;a<this.args.length;){let e=this.args[a];if(e.startsWith(`-`)){if(!Jt.has(e)){this.validationError=`Unknown argument: ${e}`;break}if(Yt.has(e))if(a+1<this.args.length&&!this.args[a+1].startsWith(`-`))a+=2;else{this.validationError=`Missing value for option: ${e}`;break}else a+=1}else o.push(e),a+=1}this.validationError||(o.length>1?this.validationError=`Unknown argument: ${o[1]}`:this.name=o[0]),this.logger=t.logger||new tt({isQuiet:this.isQuiet,isJson:this.isJson,isYes:this.isYes})}get isAgent(){return this.hasFlag(`isAgent`)}get isYes(){return this.isAgent||this.hasFlag(`isYes`)}get isQuiet(){return this.isAgent||this.hasFlag(`isQuiet`)}get isJson(){return this.isAgent||this.hasFlag(`isJson`)}get isForce(){return this.hasFlag(`isForce`)}get helpRequested(){return this.hasFlag(`helpRequested`)}get example(){let e=qt.example;return this.getFlagValue(e.long,e.short)}get isStrict(){return this.hasFlag(`isStrict`)}get isSimple(){return this.hasFlag(`isSimple`)}get noCodegen(){return this.hasFlag(`noCodegen`)}hasFlag(e){let t=qt[e];return this.args.includes(t.long)||!!t.short&&this.args.includes(t.short)}get initInput(){let e={isYes:this.isYes,isForce:this.isForce,isQuiet:this.isQuiet,isAgent:this.isAgent,isStrict:this.isStrict,isSimple:this.isSimple};return this.example!==void 0&&(e.example=this.example),this.name!==void 0&&(e.name=this.name),this.noCodegen&&(e.noCodegen=!0),e}getFlagValue(e,t){let n=this.args.findIndex(n=>n===e||n===t);if(n!==-1&&this.args[n+1]&&!this.args[n+1].startsWith(`-`))return this.args[n+1]}},Zt=`0.2.7`;function Qt(e,t=2,n=4){let r=Math.max(...e.map(e=>e.left.length),0),i=` `.repeat(t);return e.map(e=>{let t=` `.repeat(r-e.left.length+n);return`${i}${e.left}${t}${e.right}`})}var $t=class{constructor(e){this.logger=e}async execute(){let e=[{left:`arkenv init [project-name]`,right:`Set up ArkEnv in your project`}],t=[{left:`--yes, -y`,right:`Skip prompts and use defaults (also passed to subprocesses)`},{left:`--force, -f`,right:`Bypass technical requirement checks and force scaffolding`},{left:`--agent, -a`,right:`Enable non-interactive, machine-readable mode for AI agents. Bypasses all prompts and outputs structured JSON. Macro for --yes --quiet --json`},{left:`--example, -e`,right:`Specify an example name when creating a new project`},{left:`--quiet, -q`,right:`Quiet mode: Suppress output, capture logs on failure`},{left:`--json, -j`,right:`Output structured JSON to stdout`},{left:`--no-codegen, -C`,right:`Disable automatic env.gen.ts code generation for Next.js`},{left:`--help, -h`,right:`Show this help message`}];this.logger.log(`ArkEnv CLI v${Zt}`),this.logger.log(`\n${y.default.bold(`Usage:`)}`);for(let t of Qt(e))this.logger.log(t);this.logger.log(`\n${y.default.bold(`Options:`)}`);for(let e of Qt(t))this.logger.log(e)}};function en(e,t,n,r){let{extraImports:i,serverField:a,clientField:o,sharedField:s,defaultServerFields:c,defaultClientFields:l,defaultSharedFields:u}=t,d=[],f=[],p=[];if(e&&e.length>0)for(let t of e)t.startsWith(`NEXT_PUBLIC_`)?f.push(o(t)):t===`NODE_ENV`||t===`PORT`?p.push(s(t,t===`PORT`)):d.push(a(t));else d.push(...c),f.push(...l),p.push(...u);let m=[];if(d.length>0&&m.push(`\tserver: {\n${d.join(`
|
|
111
|
+
`),{success:!0,instructions:a.trim()}}async function Dt(e,t){let n=t||await J();if(!n)return{status:`not_found`};let i=r.default.basename(n);try{let t=await e.readFile(n);if((0,u.parse)(t)?.compilerOptions?.strict===!0)return{status:`already_strict`,file:i};let r=(0,u.applyEdits)(t,(0,u.modify)(t,[`compilerOptions`,`strict`],!0,{formattingOptions:{insertSpaces:!0,tabSize:2}}));return await e.writeFile(n,r),{status:`updated`,file:i}}catch{return{status:`error`,file:i}}}var Ot=class{constructor(e,t){this.isQuiet=e,this.stdio=t}async exists(e){try{return await n.default.access(e),!0}catch{return!1}}async readFile(e){return n.default.readFile(e,`utf-8`)}async writeFile(e,t){await n.default.writeFile(e,t,`utf-8`)}async mkdir(e,t){await n.default.mkdir(e,{recursive:t})}async execute(e,t=[],n){return new Promise((r,i)=>{let a=(0,d.spawn)(e,t,{cwd:n,stdio:this.isQuiet?`pipe`:this.stdio,shell:!1}),o=``,s=``,c=1e4;this.isQuiet&&(a.stdout?.on(`data`,e=>{o=(o+e.toString()).slice(-c)}),a.stderr?.on(`data`,e=>{s=(s+e.toString()).slice(-c)})),a.on(`close`,(e,t)=>{if(e===0)r();else{let n=e===null?`Command terminated by signal ${t}`:`Command failed with code ${e}`;this.isQuiet&&(o&&(n+=`\n${y.default.dim(`STDOUT:`)}\n${o}`),s&&(n+=`\n${y.default.red(`STDERR:`)}\n${s}`)),i(Error(n))}}),a.on(`error`,i)})}async updateTsConfigToStrict(e){return Dt(this,e)}async findViteConfig(e){return Ct(e)}async findBunConfig(e){return wt(e)}async bootstrapViteConfig(e,t){return Tt(this,e,t)}async bootstrapBunConfig(e,t){return Et(e,t)}async safeAppend(e,t,n){let{safeAppend:r}=await Promise.resolve().then(()=>p);return r(e,t,n)}};async function kt(e){let t=e.defaultPath||`./src/env.ts`;if(e.hasEnvSchemaFile){let e=await U({message:y.default.yellow(`An existing ArkEnv configuration was found at ${Y(t)}. Do you want to overwrite it?`),initialValue:!1,active:`Yes (override my configuration)`,inactive:`No (abort)`});return I(e)||!e?null:e}return!0}async function At(e){let t=e.detectedKeys,n=e.keysSource||`.env.example`;if(t&&t.length>0){let e=t.length,r=e===1,i=await U({message:n===`.env.example`?`Detected ${Y(`.env.example`)} with ${e} ${r?`key`:`keys`}. Use ${r?`it`:`them`} for your schema?`:`Detected ${e} environment variable${r?``:`s`} used in your project. Use ${r?`it`:`them`} for your schema?`,active:`Yes (Recommended)`,initialValue:!0});return I(i)?null:i}return!1}async function jt(e){if(e.framework===`vite`||e.framework===`bun-fullstack`){let t=e.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`;if(e.hasTypeFile)return!0;let n=await U({message:`Establish ${Y(t)} for typesafe environment variables?`,initialValue:!0,active:`Yes (Recommended)`,inactive:`No`});return I(n)?null:n}return!0}async function Mt(e){if(!e.installTypeDefinitions||e.framework!==`vite`&&e.framework!==`bun-fullstack`)return`skip`;let t=e.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`;if(e.hasTypeFile){let e=await K({message:`Found existing ${Y(t)}. How should we handle ArkEnv types?`,options:[{value:`append`,label:`Append types safely (if needed)`,hint:`Recommended`},{value:`overwrite`,label:`Overwrite entirely`,hint:`Destructive`},{value:`skip`,label:`Skip`}]});return I(e)?null:e}return`overwrite`}async function Nt(e){let t=await K({message:`Select an example:`,options:e.examples.map(e=>({value:e.id,label:e.name,...e.description?{hint:e.description}:{}}))});return I(t)?null:t}async function Pt(e){let t=await K({message:`Select your framework or build tool:`,initialValue:e.framework,options:[{value:`vanilla`,label:`Vanilla${e.framework===`vanilla`?` (Detected)`:``}`,hint:`Node.js, Bun, server-side or runtime-only validation`},{value:`vite`,label:`Vite${e.framework===`vite`?` (Detected)`:``}`,hint:`Client-side and static inlining validation`},{value:`bun-fullstack`,label:`Bun fullstack dev server${e.framework===`bun-fullstack`?` (Detected)`:``}`,hint:`Client-side bundling and Bun.serve integration`},{value:`nextjs`,label:`Next.js${e.framework===`nextjs`?` (Detected)`:``}`,hint:`Next.js App or Pages Router with build and runtime validation`}]});return I(t)?null:t}async function Ft(e){let t=await U({message:`Optional: Would you also like to bootstrap a custom Bun.build script for programmatic bundling?`,initialValue:e.initialValue??!1});return I(t)?null:t}async function It(){let e=await K({message:`Select your preferred validator library:`,options:[{value:`arktype`,label:`ArkType (Recommended)`,hint:`TypeScript's 1:1 validator, optimized from editor to runtime`},{value:`zod`,label:`Zod`,hint:`TypeScript-first schema validation with static type inference`},{value:`valibot`,label:`Valibot`,hint:`The modular and type safe schema library`}]});return I(e)?null:e}async function Lt(){let e=await K({message:`How would you like to structure your environment variables?`,options:[{value:`simple`,label:`Simple`,hint:`(Recommended) A single env.ts file for the best DX`},{value:`strict`,label:`Strict`,hint:`Separate shared, client, and server files for hard bundle boundaries.`}]});return I(e)?null:e}async function Rt(e){let t=await U({message:`Enable automated Next.js code generation for environment variables?`,initialValue:e.initialValue??!0,active:`Yes (Recommended)`,inactive:`No`});return I(t)?null:t}async function zt(e){let t=await U({message:`Use default config path (${Y(e.defaultEnvPath||`./src/env.ts`)})?`,initialValue:!0,active:`Yes (Recommended)`,inactive:`No, let me customize it`});return I(t)?null:t}async function Bt(e){let t=e.defaultEnvPath||`./src/env.ts`;if(!e.useDefaultPath){let e=await $e({message:`Where should we create the ArkEnv config?`,placeholder:t,initialValue:t,defaultValue:t});if(I(e))return null;let n=typeof e==`string`?e.trim():``;return n===``?t:n}return t}const X={example:Nt,overwriteEnvSchemaFile:kt,framework:Pt,bunBuild:Ft,layout:Lt,nextjsCodegen:Rt,useDefaultPath:zt,path:Bt,installTypeDefinitions:jt,envDtsHandling:Mt,validator:It,useEnvExample:At};async function Vt(e,t=!1){return(e?.mode||`existing`)===`new`?Ht(e,t):Ut(e,t)}async function Ht(e,t=!1){let n=e?.examples||[],i=`arkenv-project`;try{let a;if(e?.name){let t=e.name.trim();a=t===`.`||t===`./`||r.default.resolve(process.cwd(),t)===process.cwd()?`.`:t}else if(t)a=i;else{let e=(Z(await $e({message:`Project name:`,placeholder:i,defaultValue:i}))||i).trim();a=e===`.`||e===`./`||r.default.resolve(process.cwd(),e)===process.cwd()?`.`:e}let o=e?.example;!o&&!t?o=Z(await X.example({examples:n})):!o&&t&&(o=`basic`);let s=n.find(e=>e.id===o);if(!s){let e=n.map(e=>e.id).join(`, `);throw Error(`Unknown example ${o}. Available examples: ${e}`)}return{mode:`new`,example:s.id,name:a,path:`./src/env.ts`,validator:`arktype`,framework:s.framework,language:`ts`,installSkill:!1}}catch(e){if(e instanceof Gt)return null;throw e}}async function Ut(e,n=!1){let r=e?.defaultEnvPath||`./src/env.ts`,i=e?.envKeys||null,a=e?.envKeysSource||`.env.example`;if(n){let n=e?.framework||`vanilla`,a;n===`nextjs`&&(a=e?.isStrict?`strict`:(e?.isSimple,`simple`));let o=await Wt(e,n,r),s;return(n===`vite`||n===`bun-fullstack`)&&(s=o?`append`:`overwrite`),(0,t.shake)({mode:`existing`,path:r,validator:`arktype`,framework:n,layout:a,bunFeatures:n===`bun-fullstack`?e?.bunFeatures??[`serve`]:void 0,language:`ts`,overwriteEnvSchemaFile:!0,installTypeDefinitions:n===`vite`||n===`bun-fullstack`,installSkill:!1,envDtsHandling:s,envKeys:i??void 0,disableCodegen:e?.disableCodegen??!1})}try{let n=Z(await X.overwriteEnvSchemaFile({hasEnvSchemaFile:e?.hasEnvSchemaFile??!1,defaultPath:r})),o=Z(await X.framework({framework:e?.framework})),s;o===`nextjs`&&(s=e?.isStrict?`strict`:e?.isSimple?`simple`:Z(await X.layout()));let c;if(o===`bun-fullstack`){let t=!!e?.bunFeatures?.includes(`build`);c=Z(await X.bunBuild({initialValue:t}))}let l=e?.disableCodegen;o===`nextjs`&&l===void 0&&(l=!Z(await X.nextjsCodegen({initialValue:!0})));let u=Z(await X.useDefaultPath({defaultEnvPath:r})),d=Z(await X.path({useDefaultPath:u,defaultEnvPath:r})),f=await Wt(e,o,d),p=Z(await X.installTypeDefinitions({framework:o,hasTypeFile:f})),m=Z(await X.envDtsHandling({framework:o,installTypeDefinitions:p,hasTypeFile:f})),h=Z(await X.validator()),g=Z(await X.useEnvExample({detectedKeys:i,keysSource:a}));return(0,t.shake)({mode:`existing`,overwriteEnvSchemaFile:n,framework:o,layout:s,path:d,installTypeDefinitions:p,envDtsHandling:m,validator:h,bunFeatures:o===`bun-fullstack`?c?[`serve`,`build`]:[`serve`]:void 0,language:`ts`,installSkill:!1,envKeys:g?i??void 0:void 0,disableCodegen:l})}catch(e){if(e instanceof Gt)return null;throw e}}async function Wt(e,t,n){return await e?.hasTypeFileAtPath?.({framework:t,envPath:n})??e?.hasTypeFile??!1}var Gt=class extends Error{constructor(){super(`Operation cancelled`)}};function Z(e){if(e===null||I(e))throw Ge(`Operation cancelled`),new Gt;return e}var Kt=class{async confirm(e,n=!0,r,i){let a=await U((0,t.shake)({message:e,initialValue:n,active:r,inactive:i}));return I(a)?null:a}async runWizard(e,t=!1){return Vt(e,t)}};const qt={isYes:{long:`--yes`,short:`-y`,kind:`boolean`},isForce:{long:`--force`,short:`-f`,kind:`boolean`},isQuiet:{long:`--quiet`,short:`-q`,kind:`boolean`},isJson:{long:`--json`,short:`-j`,kind:`boolean`},isAgent:{long:`--agent`,short:`-a`,kind:`boolean`},helpRequested:{long:`--help`,short:`-h`,kind:`boolean`},example:{long:`--example`,short:`-e`,kind:`value`},isStrict:{long:`--strict`,short:``,kind:`boolean`},isSimple:{long:`--simple`,short:``,kind:`boolean`},noCodegen:{long:`--no-codegen`,short:`-C`,kind:`boolean`}},Jt=new Set(Object.values(qt).flatMap(e=>[e.long,e.short].filter(Boolean))),Yt=new Set(Object.values(qt).filter(e=>e.kind===`value`).flatMap(e=>[e.long,e.short].filter(Boolean)));var Xt=class{constructor(e,t={}){let n=e.slice(2),r=[],i=!1;for(let e of n){if(i){r.push(e),i=!1;continue}if(Yt.has(e)){r.push(e),i=!0;continue}if(/^-[a-zA-Z]{2,}$/.test(e)){let t=e.slice(1).split(``);for(let e of t)r.push(`-${e}`);Yt.has(`-${t[t.length-1]}`)&&(i=!0)}else r.push(e)}this.args=r,this.command=this.args[0];let a=1,o=[];for(this.validationError=void 0;a<this.args.length;){let e=this.args[a];if(e.startsWith(`-`)){if(!Jt.has(e)){this.validationError=`Unknown argument: ${e}`;break}if(Yt.has(e))if(a+1<this.args.length&&!this.args[a+1].startsWith(`-`))a+=2;else{this.validationError=`Missing value for option: ${e}`;break}else a+=1}else o.push(e),a+=1}this.validationError||(o.length>1?this.validationError=`Unknown argument: ${o[1]}`:this.name=o[0]),this.logger=t.logger||new tt({isQuiet:this.isQuiet,isJson:this.isJson,isYes:this.isYes})}get isAgent(){return this.hasFlag(`isAgent`)}get isYes(){return this.isAgent||this.hasFlag(`isYes`)}get isQuiet(){return this.isAgent||this.hasFlag(`isQuiet`)}get isJson(){return this.isAgent||this.hasFlag(`isJson`)}get isForce(){return this.hasFlag(`isForce`)}get helpRequested(){return this.hasFlag(`helpRequested`)}get example(){let e=qt.example;return this.getFlagValue(e.long,e.short)}get isStrict(){return this.hasFlag(`isStrict`)}get isSimple(){return this.hasFlag(`isSimple`)}get noCodegen(){return this.hasFlag(`noCodegen`)}hasFlag(e){let t=qt[e];return this.args.includes(t.long)||!!t.short&&this.args.includes(t.short)}get initInput(){let e={isYes:this.isYes,isForce:this.isForce,isQuiet:this.isQuiet,isAgent:this.isAgent,isStrict:this.isStrict,isSimple:this.isSimple};return this.example!==void 0&&(e.example=this.example),this.name!==void 0&&(e.name=this.name),this.noCodegen&&(e.noCodegen=!0),e}getFlagValue(e,t){let n=this.args.findIndex(n=>n===e||n===t);if(n!==-1&&this.args[n+1]&&!this.args[n+1].startsWith(`-`))return this.args[n+1]}},Zt=`0.2.8`;function Qt(e,t=2,n=4){let r=Math.max(...e.map(e=>e.left.length),0),i=` `.repeat(t);return e.map(e=>{let t=` `.repeat(r-e.left.length+n);return`${i}${e.left}${t}${e.right}`})}var $t=class{constructor(e){this.logger=e}async execute(){let e=[{left:`arkenv init [project-name]`,right:`Set up ArkEnv in your project`}],t=[{left:`--yes, -y`,right:`Skip prompts and use defaults (also passed to subprocesses)`},{left:`--force, -f`,right:`Bypass technical requirement checks and force scaffolding`},{left:`--agent, -a`,right:`Enable non-interactive, machine-readable mode for AI agents. Bypasses all prompts and outputs structured JSON. Macro for --yes --quiet --json`},{left:`--example, -e`,right:`Specify an example name when creating a new project`},{left:`--quiet, -q`,right:`Quiet mode: Suppress output, capture logs on failure`},{left:`--json, -j`,right:`Output structured JSON to stdout`},{left:`--no-codegen, -C`,right:`Disable automatic env.gen.ts code generation for Next.js`},{left:`--help, -h`,right:`Show this help message`}];this.logger.log(`ArkEnv CLI v${Zt}`),this.logger.log(`\n${y.default.bold(`Usage:`)}`);for(let t of Qt(e))this.logger.log(t);this.logger.log(`\n${y.default.bold(`Options:`)}`);for(let e of Qt(t))this.logger.log(e)}};function en(e,t,n,r){let{extraImports:i,serverField:a,clientField:o,sharedField:s,defaultServerFields:c,defaultClientFields:l,defaultSharedFields:u}=t,d=[],f=[],p=[];if(e&&e.length>0)for(let t of e)t.startsWith(`NEXT_PUBLIC_`)?f.push(o(t)):t===`NODE_ENV`||t===`PORT`?p.push(s(t,t===`PORT`)):d.push(a(t));else d.push(...c),f.push(...l),p.push(...u);let m=[];if(d.length>0&&m.push(`\tserver: {\n${d.join(`
|
|
112
112
|
`)}\n\t}`),f.length>0&&m.push(`\tclient: {\n${f.join(`
|
|
113
113
|
`)}\n\t}`),p.length>0&&m.push(`\tshared: {\n${p.join(`
|
|
114
114
|
`)}\n\t}`),r){let t=[];if(e&&e.length>0)for(let n of e)(n.startsWith(`NEXT_PUBLIC_`)||n===`NODE_ENV`||n===`PORT`)&&t.push(`\t\t${n}: process.env.${n},`);else t.push(` NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,`,` NODE_ENV: process.env.NODE_ENV,`);return m.push(`\truntimeEnv: {\n${t.join(`
|
|
@@ -266,115 +266,115 @@ ${a}
|
|
|
266
266
|
export const env = arkenv({
|
|
267
267
|
${a}
|
|
268
268
|
});
|
|
269
|
-
`};function sn(e,t){let{validator:n,envKeys:r,framework:i,disableCodegen:a}=e;switch(n){case`arktype`:return`${tn(r,i,t,a)}\n`;case`zod`:return`${on(r,i,t,a)}\n`;case`valibot`:return`${an(r,i,t,a)}\n`;default:throw Error(`Unsupported validator: ${n}`)}}function Q(e,t=` `){return e.length===0?`{}`:`{\n${t}${e.map(e=>e.trim()).join(`\n${t}`)}\n${t.slice(1)}}`}function cn(e){let{validator:
|
|
269
|
+
`};function sn(e,t){let{validator:n,envKeys:r,framework:i,disableCodegen:a}=e;switch(n){case`arktype`:return`${tn(r,i,t,a)}\n`;case`zod`:return`${on(r,i,t,a)}\n`;case`valibot`:return`${an(r,i,t,a)}\n`;default:throw Error(`Unsupported validator: ${n}`)}}function Q(e,t=` `){return e.length===0?`{}`:`{\n${t}${e.map(e=>e.trim()).join(`\n${t}`)}\n${t.slice(1)}}`}function cn(e,t){let{validator:n,envKeys:r,disableCodegen:i}=e,a=[],o=[],s=[],c=[];if(r&&r.length>0)for(let e of r)e.startsWith(`NEXT_PUBLIC_`)?(n===`arktype`?o.push(`${e}: "string?",`):n===`zod`?o.push(`${e}: z.string().optional(),`):n===`valibot`&&o.push(`${e}: v.optional(v.string()),`),c.push(`${e}: process.env.${e},`)):e===`NODE_ENV`||e===`PORT`?(n===`arktype`?s.push(`${e}: "${e===`PORT`?`number.port = 3000`:`'development' | 'production' | 'test' = 'development'`}",`):n===`zod`?s.push(`${e}: ${e===`PORT`?`z.coerce.number().int().min(1).max(65535).default(3000)`:`z.enum(["development", "production", "test"]).default("development")`},`):n===`valibot`&&s.push(`${e}: ${e===`PORT`?`v.optional(v.pipe(v.string(), v.transform(Number), v.number(), v.integer(), v.minValue(1), v.maxValue(65535)), 3000)`:`v.optional(v.picklist(["development", "production", "test"]), "development")`},`),c.push(`${e}: process.env.${e},`)):n===`arktype`?a.push(`${e}: "string?",`):n===`zod`?a.push(`${e}: z.string().optional(),`):n===`valibot`&&a.push(`${e}: v.optional(v.string()),`);else n===`arktype`?(a.push(`DATABASE_URL: "string = 'postgres://localhost:5432/mydb'",`),o.push(`NEXT_PUBLIC_API_URL: "string = 'https://api.example.com'",`),s.push(`NODE_ENV: "'development' | 'production' | 'test' = 'development'",`)):n===`zod`?(a.push(`DATABASE_URL: z.string().url().default("postgres://localhost:5432/mydb"),`),o.push(`NEXT_PUBLIC_API_URL: z.string().url().default("https://api.example.com"),`),s.push(`NODE_ENV: z.enum(["development", "production", "test"]).default("development"),`)):n===`valibot`&&(a.push(`DATABASE_URL: v.optional(v.pipe(v.string(), v.url()), "postgres://localhost:5432/mydb"),`),o.push(`NEXT_PUBLIC_API_URL: v.optional(v.pipe(v.string(), v.url()), "https://api.example.com"),`),s.push(`NODE_ENV: v.optional(v.picklist(["development", "production", "test"]), "development"),`)),c.push(`NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,`,`NODE_ENV: process.env.NODE_ENV,`);let l=``,u=``,d=``;return n===`arktype`?(l=`import { type } from "@arkenv/nextjs/shared";
|
|
270
270
|
|
|
271
271
|
/**
|
|
272
272
|
* @internal 🛑 INTERNAL SCHEMA ONLY.
|
|
273
273
|
* Do not import this directly. Import \`env\` from \`./client\` or \`./server\` instead.
|
|
274
274
|
*/
|
|
275
|
-
export const SharedSchema = type(${Q(
|
|
275
|
+
export const SharedSchema = type(${Q(s,` `)});`,u=i?`import arkenv from "@arkenv/nextjs/client";
|
|
276
276
|
import { SharedSchema } from "./internal/shared";
|
|
277
277
|
|
|
278
278
|
export const env = arkenv(
|
|
279
|
-
${Q(
|
|
279
|
+
${Q(o,` `)},
|
|
280
280
|
{
|
|
281
281
|
extends: [SharedSchema],
|
|
282
282
|
runtimeEnv: {
|
|
283
|
-
${
|
|
283
|
+
${c.map(e=>e.trim()).join(`
|
|
284
284
|
`)}
|
|
285
285
|
},
|
|
286
286
|
},
|
|
287
|
-
);`:`import { createEnv } from "
|
|
287
|
+
);`:`import { createEnv } from "${t||`./generated/env.gen`}";
|
|
288
288
|
import { SharedSchema } from "./internal/shared";
|
|
289
289
|
|
|
290
290
|
export const env = createEnv(
|
|
291
|
-
${Q(
|
|
291
|
+
${Q(o,` `)},
|
|
292
292
|
{
|
|
293
293
|
extends: [SharedSchema],
|
|
294
294
|
},
|
|
295
|
-
);`,
|
|
295
|
+
);`,d=`import arkenv from "@arkenv/nextjs/server";
|
|
296
296
|
import { env as clientEnv } from "./client";
|
|
297
297
|
|
|
298
298
|
export const env = arkenv(
|
|
299
|
-
${Q(
|
|
299
|
+
${Q(a,` `)},
|
|
300
300
|
{
|
|
301
301
|
extends: [clientEnv],
|
|
302
302
|
},
|
|
303
|
-
);`):
|
|
303
|
+
);`):n===`zod`?(l=`import { z } from "zod";
|
|
304
304
|
|
|
305
305
|
/**
|
|
306
306
|
* @internal 🛑 INTERNAL SCHEMA ONLY.
|
|
307
307
|
* Do not import this directly. Import \`env\` from \`./client\` or \`./server\` instead.
|
|
308
308
|
*/
|
|
309
|
-
export const SharedSchema = z.object(${Q(
|
|
309
|
+
export const SharedSchema = z.object(${Q(s,` `)});`,u=i?`import arkenv from "@arkenv/nextjs/client";
|
|
310
310
|
import { z } from "zod";
|
|
311
311
|
import { SharedSchema } from "./internal/shared";
|
|
312
312
|
|
|
313
313
|
export const env = arkenv(
|
|
314
|
-
${Q(
|
|
314
|
+
${Q(o,` `)},
|
|
315
315
|
{
|
|
316
316
|
extends: [SharedSchema],
|
|
317
317
|
runtimeEnv: {
|
|
318
|
-
${
|
|
318
|
+
${c.map(e=>e.trim()).join(`
|
|
319
319
|
`)}
|
|
320
320
|
},
|
|
321
321
|
},
|
|
322
|
-
);`:`import { createEnv } from "
|
|
322
|
+
);`:`import { createEnv } from "${t||`./generated/env.gen`}";
|
|
323
323
|
import { z } from "zod";
|
|
324
324
|
import { SharedSchema } from "./internal/shared";
|
|
325
325
|
|
|
326
326
|
export const env = createEnv(
|
|
327
|
-
${Q(
|
|
327
|
+
${Q(o,` `)},
|
|
328
328
|
{
|
|
329
329
|
extends: [SharedSchema],
|
|
330
330
|
},
|
|
331
|
-
);`,
|
|
331
|
+
);`,d=`import arkenv from "@arkenv/nextjs/server";
|
|
332
332
|
import { z } from "zod";
|
|
333
333
|
import { env as clientEnv } from "./client";
|
|
334
334
|
|
|
335
335
|
export const env = arkenv(
|
|
336
|
-
${Q(
|
|
336
|
+
${Q(a,` `)},
|
|
337
337
|
{
|
|
338
338
|
extends: [clientEnv],
|
|
339
339
|
},
|
|
340
|
-
);`):
|
|
340
|
+
);`):n===`valibot`&&(l=`import * as v from "valibot";
|
|
341
341
|
|
|
342
342
|
/**
|
|
343
343
|
* @internal 🛑 INTERNAL SCHEMA ONLY.
|
|
344
344
|
* Do not import this directly. Import \`env\` from \`./client\` or \`./server\` instead.
|
|
345
345
|
*/
|
|
346
|
-
export const SharedSchema = v.object(${Q(
|
|
346
|
+
export const SharedSchema = v.object(${Q(s,` `)});`,u=i?`import arkenv from "@arkenv/nextjs/client";
|
|
347
347
|
import * as v from "valibot";
|
|
348
348
|
import { SharedSchema } from "./internal/shared";
|
|
349
349
|
|
|
350
350
|
export const env = arkenv(
|
|
351
|
-
${Q(
|
|
351
|
+
${Q(o,` `)},
|
|
352
352
|
{
|
|
353
353
|
extends: [SharedSchema],
|
|
354
354
|
runtimeEnv: {
|
|
355
|
-
${
|
|
355
|
+
${c.map(e=>e.trim()).join(`
|
|
356
356
|
`)}
|
|
357
357
|
},
|
|
358
358
|
},
|
|
359
|
-
);`:`import { createEnv } from "
|
|
359
|
+
);`:`import { createEnv } from "${t||`./generated/env.gen`}";
|
|
360
360
|
import * as v from "valibot";
|
|
361
361
|
import { SharedSchema } from "./internal/shared";
|
|
362
362
|
|
|
363
363
|
export const env = createEnv(
|
|
364
|
-
${Q(
|
|
364
|
+
${Q(o,` `)},
|
|
365
365
|
{
|
|
366
366
|
extends: [SharedSchema],
|
|
367
367
|
},
|
|
368
|
-
);`,
|
|
368
|
+
);`,d=`import arkenv from "@arkenv/nextjs/server";
|
|
369
369
|
import * as v from "valibot";
|
|
370
370
|
import { env as clientEnv } from "./client";
|
|
371
371
|
|
|
372
372
|
export const env = arkenv(
|
|
373
|
-
${Q(
|
|
373
|
+
${Q(a,` `)},
|
|
374
374
|
{
|
|
375
375
|
extends: [clientEnv],
|
|
376
376
|
},
|
|
377
|
-
);`),{shared:`${
|
|
377
|
+
);`),{shared:`${l}\n`,client:`${u}\n`,server:`${d}\n`}}async function ln(e,t){let i=t.targetDir??process.cwd(),a=r.default.join(process.cwd(),`.arkenv-temp`);await e.mkdir(a,!0),t.targetDir&&await e.mkdir(i,!0);try{await e.execute(`git`,[`clone`,`--filter=blob:none`,`--sparse`,t.repository,a]);let o=`examples/${t.example}`;await e.execute(`git`,[`-C`,a,`sparse-checkout`,`set`,o]);let s=r.default.join(a,o),c=await n.default.readdir(s),l=[];for(let t of c){let n=r.default.join(i,t);await e.exists(n)&&l.push(t)}if(l.length>0)throw Error(`Scaffolding into a non-empty directory failed. The following paths already exist: ${l.join(`, `)}`);await un(s,i);for(let e of[`package-lock.json`,`pnpm-lock.yaml`,`yarn.lock`,`bun.lockb`,`bun.lock`])await n.default.rm(r.default.join(i,e),{force:!0});let u=r.default.join(i,`package.json`);if(await e.exists(u)){let n=await e.readFile(u),r=JSON.parse(n);r.name=t.targetName,delete r.packageManager,await e.writeFile(u,JSON.stringify(r,null,2))}}finally{await n.default.rm(a,{recursive:!0,force:!0})}}async function un(e,t){let i=await n.default.readdir(e);await Promise.all(i.map(i=>n.default.cp(r.default.join(e,i),r.default.join(t,i),{recursive:!0,force:!1})))}function dn(e,t){let n=t.length>0;switch(e){case`pnpm`:return[`pnpm`,[n?`add`:`install`,...t]];case`yarn`:return[`yarn`,[n?`add`:`install`,...t]];case`bun`:return[`bun`,[n?`add`:`install`,...t]];default:return[`npm`,[`install`,...t]]}}function fn(e,t){if(t||e.metadata.skillDetected)return{message:i.default`
|
|
378
378
|
Inside your AI assistant (e.g. Claude Code), use:
|
|
379
379
|
${Y(`/arkenv`)} - automatically refine your schema and configure integrations.
|
|
380
|
-
`,title:`Next steps`};let n=e.skill?.dlxCommand.join(` `)||`npx`,r=e.skill?.packageName||`yamcodes/arkenv`,a=``,o=1,s=e.metadata.displayPath;if(e.metadata.layout===`strict`){let e=s.lastIndexOf(`.`),t=e===-1?s:s.slice(0,e);s=`${t}/client.ts, ${t}/server.ts, and ${t}/internal/shared.ts`}return a+=`${o++}. Check ${Y(s)} and refine your environment schema.\n`,e.metadata.framework===`vite`?a+=`${o++}. Access via ${Y(`import.meta.env.YOUR_VAR`)}\n`:e.metadata.framework===`bun-fullstack`?a+=`${o++}. Access via ${Y(`process.env.YOUR_VAR`)}\n`:e.metadata.framework===`nextjs`?e.metadata.layout===`strict`?e.metadata.disableCodegen?a+=`${o++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}/client"`)} (client) or ${Y(`import { env } from "${e.metadata.importPath}/server"`)} (server)\n`:(a+=`${o++}. Wrap your Next.js config with ${Y(`withArkEnv`)} inside ${Y(`next.config.ts`)}:\n`,a+=` ${Y(`import { withArkEnv } from "@arkenv/nextjs/config";`)}\n`,a+=` ${Y(`export default withArkEnv(nextConfig);`)}\n`,a+=`${o++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}/client"`)} (client) or ${Y(`import { env } from "${e.metadata.importPath}/server"`)} (server)\n`):e.metadata.disableCodegen?a+=`${o++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`:(a+=`${o++}. Wrap your Next.js config with ${Y(`withArkEnv`)} inside ${Y(`next.config.ts`)}:\n`,a+=` ${Y(`import { withArkEnv } from "@arkenv/nextjs/config";`)}\n`,a+=` ${Y(`export default withArkEnv(nextConfig);`)}\n`,a+=`${o++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`):a+=`${o++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`,a+=`${o++}. (Recommended) Install the AI skill: ${Y(`${n} skills add ${r}`)}\n`,a+=` Then run ${Y(`/arkenv`)} inside your AI assistant to finish.`,{message:a,title:`Next steps`}}var pn=class{constructor(e,t){this.workspace=e,this.reporter=t}async execute(e){let t=this.reporter.spinner();t.start(`Scaffolding ArkEnv configuration...`);try{e.clone&&(t.stop(`Starting new project scaffolding...`),this.reporter.step(`Cloning example ${Y(e.clone.example)}...`),await ln(this.workspace,e.clone),t.start(`Scaffolding complete, finalizing...`));for(let t of e.files){if(t.action===`append`){if(!e.bootstrap||e.bootstrap.framework!==`vite`&&e.bootstrap.framework!==`bun-fullstack`){this.reporter.warn(`Skipping safe-append for ${Y(r.default.basename(t.path))}: unsupported framework.`);continue}await this.workspace.safeAppend(t.path,t.content,e.bootstrap.framework)?this.reporter.info(`Appended ArkEnv types to ${Y(r.default.basename(t.path))}.`):this.reporter.info(`${Y(r.default.basename(t.path))} already contains ArkEnv types.`);continue}if(await this.workspace.mkdir(r.default.dirname(t.path),!0),await this.workspace.writeFile(t.path,t.content),t.label!==`environment schema`&&t.label?.includes(`types`)){let e=t.action===`overwrite`?`Updated`:`Created`;this.reporter.info(`${e} ${Y(r.default.basename(t.path))} for typesafe environment variables.`)}}if(t.stop(`Configuration scaffolded!`),e.install&&process.env.SKIP_INSTALL!==`true`){this.reporter.step(`Installing dependencies with ${Y(e.install.packageManager)}...`);let[t,n]=dn(e.install.packageManager,e.install.dependencies);await this.workspace.execute(t,n,e.install.cwd??e.cwd)}let n=!1;if(e.tsConfig){let t=await this.workspace.updateTsConfigToStrict(e.tsConfig.path);t.status===`updated`?(this.reporter.info(`Enforced strict: true in your ${Y(t.file)}`),n=!0):t.status===`error`&&this.reporter.warn(`Could not automatically update ${Y(t.file||`tsconfig.json`)}. Please ensure 'strict: true' is set manually.`)}if(e.bootstrap){if(e.bootstrap.framework===`vite`){let t=await this.workspace.findViteConfig(e.cwd);if(t){this.reporter.step(`Bootstrapping Vite plugin...`);let n=await this.workspace.bootstrapViteConfig(t,e.bootstrap.importPath||`./src/env`);n.success?n.updated&&this.reporter.info(`Updated ${Y(r.default.basename(t))}`):(this.reporter.warn(`Could not automatically update ${Y(r.default.basename(t))}: ${n.error}`),this.reporter.info(`Please add ${Y(`@arkenv/vite-plugin`)} manually.`))}else this.reporter.info(`No Vite config found — please add ${Y(`@arkenv/vite-plugin`)} to your Vite config manually.`)}else if(e.bootstrap.framework===`bun-fullstack`){let t=await this.workspace.findBunConfig(e.cwd),n=await this.workspace.bootstrapBunConfig(t,e.bootstrap.bunFeatures);n.success&&n.instructions?this.reporter.info(n.instructions):n.success||this.reporter.error(n.error||`Bun bootstrap failed`)}else if(e.bootstrap.framework===`nextjs`){this.reporter.step(`Generating Next.js environment bindings...`);let t=`import('@arkenv/nextjs/config').then(({ runCodegen }) => { const path = require('path'); const schemaPath = path.resolve(process.cwd(), '${e.metadata.displayPath}'); const outputPath = path.join(path.dirname(schemaPath), 'generated', 'env.gen.ts'); runCodegen(schemaPath, outputPath); }).catch(err => { console.error(err); process.exit(1); });`;try{await this.workspace.execute(`node`,[`-e`,t],e.cwd),this.reporter.info(`Generated ${Y(`env.gen.ts`)} for Next.js`)}catch{this.reporter.warn(`Failed to automatically generate ${Y(`env.gen.ts`)}. It will be generated when you start your dev server.`)}}}let i=!1;if(e.skill&&process.env.SKIP_INSTALL!==`true`){this.reporter.step(`Installing ArkEnv agent skill...`);try{let[t,...n]=e.skill.dlxCommand,r=[...n,`skills`,`add`,e.skill.packageName];e.skill.isYes&&r.push(`--yes`),await this.workspace.execute(t,r,e.cwd),i=!0}catch(e){let t=e instanceof Error?e.message:String(e);this.reporter.warn(`Failed to install ArkEnv AI skill: ${t}`)}}let a=fn(e,i);if(this.reporter.note(a.message,a.title),e.metadata.layout===`strict`){let t=r.default.resolve(e.cwd,e.metadata.displayPath);if(await this.workspace.exists(t)){let t=e.metadata.displayPath,n=r.default.basename(t,r.default.extname(t));this.reporter.warn(`Found existing single-file schema at ${Y(t)}. You can delete it after updating your imports to point to your new ${Y(`${n}/client`)} and ${Y(`${n}/server`)}.`)}}this.reporter.finish(`${xt} ArkEnv scaffolding complete. Happy coding!`,{path:e.metadata.displayPath,framework:e.metadata.framework,validator:e.metadata.validator,packageManager:e.metadata.packageManager,tsConfigUpdated:n,skillInstalled:i})}catch(e){throw t.stop(`Scaffolding failed.`),e}}};function mn(e){switch(e){case`pnpm`:return[`pnpm`,`dlx`];case`yarn`:return[`yarn`,`dlx`];case`bun`:return[`bunx`];default:return[`npx`]}}function hn(e){let{mode:n,options:i,packageManager:a,tsConfig:o,shouldUpdateTsConfig:s,cwd:c,existingFiles:l}=e,u=i.name&&i.name!==`.`?r.default.basename(i.name):void 0,d={files:[],cwd:c,metadata:(0,t.shake)({displayPath:``,framework:i.framework,validator:i.validator,packageManager:a,importPath:``,mode:n,example:i.example,name:u,layout:i.layout,skillDetected:i.skillDetected,disableCodegen:i.disableCodegen})};if(n===`new`){if(!i.example)throw Error(`New project scaffolding requires an example.`);let t=i.name&&i.name!==`.`?r.default.join(c,i.name):void 0,n=i.name&&i.name!==`.`?r.default.basename(i.name):r.default.basename(c);return d.clone={repository:`https://github.com/yamcodes/arkenv.git`,example:i.example,targetName:n,...t!==void 0&&{targetDir:t}},d.install={packageManager:a,dependencies:[],...t!==void 0&&{cwd:t}},i.installSkill&&(d.skill={dlxCommand:mn(a),packageName:`yamcodes/arkenv`,isYes:e.isYes}),d.metadata.displayPath=`./src/env.ts`,d.metadata.importPath=`./src/env`,d}let f=r.default.resolve(c,i.path),p=r.default.dirname(f);if(i.framework===`nextjs`&&i.layout===`strict`){let e=r.default.extname(f),t=f.slice(0,-e.length),n=r.default.join(t,`internal`,`shared${e}`),a=r.default.join(t,`client${e}`),o=r.default.join(t,`server${e}`),s=cn(i),c=l.includes(n),u=l.includes(a),p=l.includes(o);(!c||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:n,content:s.shared,action:c?`overwrite`:`create`,label:`shared environment schema`}),(!u||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:a,content:s.client,action:u?`overwrite`:`create`,label:`client environment schema`}),(!p||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:o,content:s.server,action:p?`overwrite`:`create`,label:`server environment schema`})}else{let e;if(i.framework===`nextjs`&&!i.disableCodegen&&o?.parsed){let t=o.parsed,n=(t.compilerOptions||{}).paths||{};if(n[`@/*`]){let i=t.path?r.default.dirname(t.path):c,a=r.default.join(p,`generated`),o=r.default.relative(i,a).replace(/\\/g,`/`);for(let t of n[`@/*`]){let n=t.replace(/^\.\//,``).replace(/\*$/,``);if(n===``||o.startsWith(n)){let t=o;n!==``&&o.startsWith(n)&&(t=o.substring(n.length)),t=t.replace(/^\/+/,``).replace(/\/+$/,``),e=`@/${t}/env.gen`.replace(/\/+/g,`/`);break}}}}let t=sn(i,e),n=l.includes(f);(!n||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:f,content:t,action:n?`overwrite`:`create`,label:`environment schema`})}let m=[`arkenv`,i.validator];if(i.framework===`vite`&&m.push(`@arkenv/vite-plugin`),i.framework===`bun-fullstack`&&i.bunFeatures?.length&&m.push(`@arkenv/bun-plugin`),i.framework===`nextjs`&&m.push(`@arkenv/nextjs`),(i.framework===`vite`||i.framework===`nextjs`||i.framework===`bun-fullstack`&&i.bunFeatures?.length)&&!m.includes(`arktype`)&&m.push(`arktype`),d.install={packageManager:a,dependencies:m},s&&o.file&&(d.tsConfig={path:r.default.resolve(c,o.file),action:`strict`}),(i.framework===`vite`||i.framework===`bun-fullstack`&&i.bunFeatures?.length)&&i.installTypeDefinitions!==!1){let e=i.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`,t=r.default.join(p,e),n=l.includes(t);if(i.envDtsHandling!==`skip`)if(i.envDtsHandling===`append`||!i.envDtsHandling&&n)d.files.push({path:t,content:f,action:`append`,label:`${i.framework} types`});else{let e=i.framework===`vite`?nn(i.path):rn(i.path);d.files.push({path:t,content:e,action:n?`overwrite`:`create`,label:`${i.framework} types`})}}(i.framework===`vite`||i.framework===`bun-fullstack`||i.framework===`nextjs`&&!i.disableCodegen)&&(d.bootstrap=(0,t.shake)({framework:i.framework,bunFeatures:i.framework===`bun-fullstack`?i.bunFeatures:void 0})),i.installSkill&&(d.skill={dlxCommand:mn(a),packageName:`yamcodes/arkenv`,isYes:e.isYes});let h=r.default.relative(c,f).replace(/\\/g,`/`),g=h.startsWith(`.`)?h:`./${h}`,_=g.replace(/\.(ts|js|tsx|jsx)$/,``);return d.metadata.displayPath=g,d.metadata.importPath=_,d.bootstrap&&(d.bootstrap.importPath=_),d}var gn=class{async fetchRegistry(){try{let e=await fetch(`https://raw.githubusercontent.com/yamcodes/arkenv/main/examples/registry.json`);if(!e.ok)throw Error(`Failed to fetch registry: ${e.statusText}`);return await e.json()}catch{return{examples:[{id:`basic`,name:`Basic`,description:`A minimal ArkEnv setup in Node.js`,framework:`vanilla`},{id:`with-nextjs`,name:`Next.js`,description:`Minimal Next.js project with ArkType`,framework:`nextjs`},{id:`with-vite-react`,name:`React + Vite`,framework:`vite`},{id:`with-bun`,name:`Bun (Vanilla)`,description:`Minimal Bun project with ArkType`,framework:`vanilla`},{id:`with-bun-react`,name:`React + Bun fullstack dev server`,framework:`bun-fullstack`},{id:`with-zod`,name:`Zod`,description:`ArkEnv with Zod in Node.js`,framework:`vanilla`}]}}}},_n=class{constructor(e,t,n,r,i=new gn){this.logger=e,this.workspace=t,this.prompt=n,this.scanner=r,this.registry=i}async execute(e){let t=await this.collect(e);if(!t)return!1;let n=hn(t),r=new pn(this.workspace,this.logger);try{await r.execute(n)}catch(e){this.logger.fatal(`Scaffolding failed.`,e)}return!0}async collect(e){this.logger.interactiveStdout(!0);try{let t=e.name;t&&r.default.resolve(process.cwd(),t)===process.cwd()&&(t=`.`);let n={...e,...t!==void 0&&{name:t}},i=t&&t!==`.`?r.default.resolve(process.cwd(),t):process.cwd(),a=await this.workspace.exists(i),o=a?await this.scanner.hasPackageJson(i):!1,s=a?await this.scanner.isEmptyDirectory(i):!0;return n.example===void 0?o?await this.collectExistingProject(n,i):s||n.isForce?await this.collectNewProject(n,s):(this.logger.error(`Directory is not empty and no ${Y(`package.json`)} was found.`),this.logger.info(`To scaffold a new project, run ${Y(`arkenv init`)} in an empty directory or use ${Y(`--force`)} to proceed anyway.`),null):await this.collectNewProject(n,s)}finally{this.logger.interactiveStdout(!1)}}async collectExistingProject(e,n){let{isYes:i,isForce:a,isQuiet:o,isAgent:s}=e,c=await this.scanner.checkRequirements(n),l=c.filter(e=>e.status===`fail`),u=c.filter(e=>e.status===`warn`);for(let e of u)this.logger.warn(`${e.requirement}: ${e.message}`);if(l.length>0)if(a){this.logger.warn(`Technical requirements not met, but continuing due to --force flag.`);for(let e of l)this.logger.warn(`${e.requirement}: ${e.message}`)}else{this.logger.error(`Technical requirements not met:`);for(let e of l)this.logger.error(`- ${e.requirement}: ${e.message}${e.current?` (Current: ${e.current}, Expected: ${e.expected})`:``}`);return this.logger.info(`Use --force to bypass these checks.`),null}let d=!1,f=await this.scanner.checkTsConfig(n);if(f.status===`not_strict`)if(i)d=!0;else{this.logger.warn(`TypeScript strict mode is not enabled in your ${Y(f.file)}.`);let e=await this.prompt.confirm(`ArkEnv requires ${Y(`strict`)} mode in your ${Y(f.file)}. Would you like to enable it now?`,!0,`Yes (Recommended)`);if(e===null)return null;if(!e)return this.logger.cancel(`Operation cancelled.`),null;d=!0}let p=await this.scanner.detectFramework(n,f.parsed),m=p===`bun-fullstack`?await this.scanner.detectBunFeatures(n,f.parsed):void 0,h=await this.scanner.suggestDefaultEnvPath(n,f.parsed),g=r.default.resolve(n,h),_=await this.scanner.getEnvExampleKeys(n,f.parsed,g),v=await(async()=>{if(e.isStrict){let e=r.default.extname(g),t=g.slice(0,-e.length),n=[r.default.join(t,`internal`,`shared${e}`),r.default.join(t,`client${e}`),r.default.join(t,`server${e}`)];if((await Promise.all(n.map(e=>this.workspace.exists(e)))).some(Boolean))return!0}return this.workspace.exists(g)})(),y=async({framework:e,envPath:t})=>{if(e!==`vite`&&e!==`bun-fullstack`)return!1;let i=e===`vite`?`vite-env.d.ts`:`bun-env.d.ts`,a=r.default.resolve(n,t),o=r.default.dirname(a),s=r.default.join(o,i);return this.workspace.exists(s)},b=await y({framework:p,envPath:h}),x=await this.prompt.runWizard((0,t.shake)({mode:`existing`,framework:p,bunFeatures:m,defaultEnvPath:h,tsConfig:f.parsed??null,envKeys:_?.keys,envKeysSource:_?.source,hasTypeFileAtPath:y,hasTypeFile:b,hasEnvSchemaFile:v,isStrict:e.isStrict,isSimple:e.isSimple,disableCodegen:e.noCodegen}),i);if(x===null)return null;let S=await this.scanner.hasSkill(n);if(S&&(x.skillDetected=!0,!o&&!s&&this.logger.info(`ArkEnv agent skill detected.`)),S)x.installSkill=!1;else if(s)x.installSkill=!1;else if(i)x.installSkill=!0;else{let e=await this.prompt.confirm(`Would you like to install the ArkEnv agent skill?`,!0,`Yes (Recommended)`);if(e===null)return null;x.installSkill=e}let C=r.default.resolve(n,x.path);if(x.overwriteEnvSchemaFile===void 0&&(x.layout===`strict`?await(async()=>{let e=r.default.extname(C),t=C.slice(0,-e.length);return(await Promise.all([this.workspace.exists(r.default.join(t,`internal`,`shared${e}`)),this.workspace.exists(r.default.join(t,`client${e}`)),this.workspace.exists(r.default.join(t,`server${e}`))])).some(Boolean)})():await this.workspace.exists(C))){let e=x.layout===`strict`?`Strict layout files (client, server, internal/shared)`:r.default.basename(C),t=await this.prompt.confirm(`${e} already exist. Overwrite?`,!1);if(t===null)return null;if(!t)return this.logger.cancel(`Operation cancelled.`),null;x.overwriteEnvSchemaFile=t}let ee=await this.scanner.detectPackageManager(n,f.parsed),w=r.default.extname(C),T=C.slice(0,-w.length),E=x.layout===`strict`?[r.default.join(T,`internal`,`shared${w}`),r.default.join(T,`client${w}`),r.default.join(T,`server${w}`)]:[C],D=[];for(let e of E)await this.workspace.exists(e)&&D.push(e);let O;if(x.framework===`vite`?O=`vite-env.d.ts`:x.framework===`bun-fullstack`&&(O=`bun-env.d.ts`),O){let e=r.default.dirname(C),t=r.default.join(e,O);await this.workspace.exists(t)&&D.push(t)}return(0,t.shake)({mode:`existing`,cwd:n,options:x,detectedFramework:p,detectedBunFeatures:m,packageManager:ee,tsConfig:f,shouldUpdateTsConfig:d,existingFiles:D,isYes:i})}async collectNewProject(e,n=!0){let{isYes:r,example:i,name:a,isForce:o}=e,s=await this.registry.fetchRegistry(),c=await this.prompt.runWizard((0,t.shake)({mode:`new`,examples:s.examples,example:i,name:a}),r);if(c===null)return null;if(c.name===`.`&&!n&&!o)return this.logger.error(`Cannot scaffold into ${Y(`.`)} because the current directory is not empty.`),this.logger.info(`Run ${Y(`arkenv init`)} in an empty directory or choose a sub-directory name instead.`),null;let l=this.detectPackageManager();return(0,t.shake)({mode:`new`,cwd:process.cwd(),options:c,detectedFramework:c.framework,packageManager:l,tsConfig:{status:`not_found`},shouldUpdateTsConfig:!1,existingFiles:[],isYes:r})}detectPackageManager(){let e=process.env.npm_config_user_agent||``;return e.includes(`pnpm`)?`pnpm`:e.includes(`yarn`)?`yarn`:e.includes(`bun`)?`bun`:`npm`}};function vn(e){let t=new Xt(e),n=t.logger,r=new Ot(t.isQuiet,n.stdio),i=new Kt;return{cli:t,logger:n,workspace:r,prompt:i,initUseCase:new _n(n,r,i,new bt),helpUseCase:new $t(n)}}let $,yn=!1;async function bn(){if(process.env.INIT_CWD)try{process.chdir(process.env.INIT_CWD)}catch{}let{cli:e,logger:n,initUseCase:r,helpUseCase:i}=vn(process.argv);$=n,xn(n),e.validationError&&(n.error(e.validationError),await i.execute(),await n.flush(),process.exit(1)),e.helpRequested&&(await i.execute(),await n.flush(),process.exit(0)),e.command!==`init`&&(e.command?n.error(`Unknown command: ${e.command}`):n.error(`Missing command.`),await i.execute(),await n.flush(),process.exit(1));try{await r.execute((0,t.shake)(e.initInput))||(await n.flush(),process.exit(1))}catch(e){try{n.fatal(`An unexpected error occurred`,e)}catch{}await n.flush(),process.exit(1)}}function xn(e){let t=async t=>{yn&&process.exit(t),yn=!0,setTimeout(()=>{process.exit(t)},2e3).unref(),e.interactiveStdout&&e.interactiveStdout(!1);try{e.cancel(`Operation cancelled.`),await e.flush()}catch(t){e.error&&e.error(`Logger failed during shutdown`,t)}finally{process.exit(t)}};process.on(`SIGINT`,()=>t(130)),process.on(`SIGTERM`,()=>t(143))}bn(),process.on(`unhandledRejection`,async e=>{if($){try{$.fatal(`Unhandled rejection`,e)}catch{}await $.flush()}else console.error(`Unhandled rejection`,e);process.exit(1)}),process.on(`uncaughtException`,async e=>{if($){try{$.fatal(`Uncaught exception`,e)}catch{}await $.flush()}else console.error(`Uncaught exception`,e);process.exit(1)});
|
|
380
|
+
`,title:`Next steps`};let n=e.skill?.dlxCommand.join(` `)||`npx`,r=e.skill?.packageName||`yamcodes/arkenv`,a=``,o=1,s=e.metadata.displayPath;if(e.metadata.layout===`strict`){let e=s.lastIndexOf(`.`),t=e===-1?s:s.slice(0,e);s=`${t}/client.ts, ${t}/server.ts, and ${t}/internal/shared.ts`}return a+=`${o++}. Check ${Y(s)} and refine your environment schema.\n`,e.metadata.framework===`vite`?a+=`${o++}. Access via ${Y(`import.meta.env.YOUR_VAR`)}\n`:e.metadata.framework===`bun-fullstack`?a+=`${o++}. Access via ${Y(`process.env.YOUR_VAR`)}\n`:e.metadata.framework===`nextjs`?e.metadata.layout===`strict`?e.metadata.disableCodegen?a+=`${o++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}/client"`)} (client) or ${Y(`import { env } from "${e.metadata.importPath}/server"`)} (server)\n`:(a+=`${o++}. Wrap your Next.js config with ${Y(`withArkEnv`)} inside ${Y(`next.config.ts`)}:\n`,a+=` ${Y(`import { withArkEnv } from "@arkenv/nextjs/config";`)}\n`,a+=` ${Y(`export default withArkEnv(nextConfig);`)}\n`,a+=`${o++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}/client"`)} (client) or ${Y(`import { env } from "${e.metadata.importPath}/server"`)} (server)\n`):e.metadata.disableCodegen?a+=`${o++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`:(a+=`${o++}. Wrap your Next.js config with ${Y(`withArkEnv`)} inside ${Y(`next.config.ts`)}:\n`,a+=` ${Y(`import { withArkEnv } from "@arkenv/nextjs/config";`)}\n`,a+=` ${Y(`export default withArkEnv(nextConfig);`)}\n`,a+=`${o++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`):a+=`${o++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`,a+=`${o++}. (Recommended) Install the AI skill: ${Y(`${n} skills add ${r}`)}\n`,a+=` Then run ${Y(`/arkenv`)} inside your AI assistant to finish.`,{message:a,title:`Next steps`}}var pn=class{constructor(e,t){this.workspace=e,this.reporter=t}async execute(e){let t=this.reporter.spinner();t.start(`Scaffolding ArkEnv configuration...`);try{e.clone&&(t.stop(`Starting new project scaffolding...`),this.reporter.step(`Cloning example ${Y(e.clone.example)}...`),await ln(this.workspace,e.clone),t.start(`Scaffolding complete, finalizing...`));for(let t of e.files){if(t.action===`append`){if(!e.bootstrap||e.bootstrap.framework!==`vite`&&e.bootstrap.framework!==`bun-fullstack`){this.reporter.warn(`Skipping safe-append for ${Y(r.default.basename(t.path))}: unsupported framework.`);continue}await this.workspace.safeAppend(t.path,t.content,e.bootstrap.framework)?this.reporter.info(`Appended ArkEnv types to ${Y(r.default.basename(t.path))}.`):this.reporter.info(`${Y(r.default.basename(t.path))} already contains ArkEnv types.`);continue}if(await this.workspace.mkdir(r.default.dirname(t.path),!0),await this.workspace.writeFile(t.path,t.content),t.label!==`environment schema`&&t.label?.includes(`types`)){let e=t.action===`overwrite`?`Updated`:`Created`;this.reporter.info(`${e} ${Y(r.default.basename(t.path))} for typesafe environment variables.`)}}if(t.stop(`Configuration scaffolded!`),e.install&&process.env.SKIP_INSTALL!==`true`){this.reporter.step(`Installing dependencies with ${Y(e.install.packageManager)}...`);let[t,n]=dn(e.install.packageManager,e.install.dependencies);await this.workspace.execute(t,n,e.install.cwd??e.cwd)}let n=!1;if(e.tsConfig){let t=await this.workspace.updateTsConfigToStrict(e.tsConfig.path);t.status===`updated`?(this.reporter.info(`Enforced strict: true in your ${Y(t.file)}`),n=!0):t.status===`error`&&this.reporter.warn(`Could not automatically update ${Y(t.file||`tsconfig.json`)}. Please ensure 'strict: true' is set manually.`)}if(e.bootstrap){if(e.bootstrap.framework===`vite`){let t=await this.workspace.findViteConfig(e.cwd);if(t){this.reporter.step(`Bootstrapping Vite plugin...`);let n=await this.workspace.bootstrapViteConfig(t,e.bootstrap.importPath||`./src/env`);n.success?n.updated&&this.reporter.info(`Updated ${Y(r.default.basename(t))}`):(this.reporter.warn(`Could not automatically update ${Y(r.default.basename(t))}: ${n.error}`),this.reporter.info(`Please add ${Y(`@arkenv/vite-plugin`)} manually.`))}else this.reporter.info(`No Vite config found — please add ${Y(`@arkenv/vite-plugin`)} to your Vite config manually.`)}else if(e.bootstrap.framework===`bun-fullstack`){let t=await this.workspace.findBunConfig(e.cwd),n=await this.workspace.bootstrapBunConfig(t,e.bootstrap.bunFeatures);n.success&&n.instructions?this.reporter.info(n.instructions):n.success||this.reporter.error(n.error||`Bun bootstrap failed`)}else if(e.bootstrap.framework===`nextjs`){this.reporter.step(`Generating Next.js environment bindings...`);let t=`import('@arkenv/nextjs/config').then(({ runCodegen }) => { const path = require('path'); const schemaPath = path.resolve(process.cwd(), '${e.metadata.displayPath}'); const outputPath = path.join(path.dirname(schemaPath), 'generated', 'env.gen.ts'); runCodegen(schemaPath, outputPath); }).catch(err => { console.error(err); process.exit(1); });`;try{await this.workspace.execute(`node`,[`-e`,t],e.cwd),this.reporter.info(`Generated ${Y(`env.gen.ts`)} for Next.js`)}catch{this.reporter.warn(`Failed to automatically generate ${Y(`env.gen.ts`)}. It will be generated when you start your dev server.`)}}}let i=!1;if(e.skill&&process.env.SKIP_INSTALL!==`true`){this.reporter.step(`Installing ArkEnv agent skill...`);try{let[t,...n]=e.skill.dlxCommand,r=[...n,`skills`,`add`,e.skill.packageName];e.skill.isYes&&r.push(`--yes`),await this.workspace.execute(t,r,e.cwd),i=!0}catch(e){let t=e instanceof Error?e.message:String(e);this.reporter.warn(`Failed to install ArkEnv AI skill: ${t}`)}}let a=fn(e,i);if(this.reporter.note(a.message,a.title),e.metadata.layout===`strict`){let t=r.default.resolve(e.cwd,e.metadata.displayPath);if(await this.workspace.exists(t)){let t=e.metadata.displayPath,n=r.default.basename(t,r.default.extname(t));this.reporter.warn(`Found existing single-file schema at ${Y(t)}. You can delete it after updating your imports to point to your new ${Y(`${n}/client`)} and ${Y(`${n}/server`)}.`)}}this.reporter.finish(`${xt} ArkEnv scaffolding complete. Happy coding!`,{path:e.metadata.displayPath,framework:e.metadata.framework,validator:e.metadata.validator,packageManager:e.metadata.packageManager,tsConfigUpdated:n,skillInstalled:i})}catch(e){throw t.stop(`Scaffolding failed.`),e}}};function mn(e){switch(e){case`pnpm`:return[`pnpm`,`dlx`];case`yarn`:return[`yarn`,`dlx`];case`bun`:return[`bunx`];default:return[`npx`]}}function hn(e){let{mode:n,options:i,packageManager:a,tsConfig:o,shouldUpdateTsConfig:s,cwd:c,existingFiles:l}=e,u=i.name&&i.name!==`.`?r.default.basename(i.name):void 0,d={files:[],cwd:c,metadata:(0,t.shake)({displayPath:``,framework:i.framework,validator:i.validator,packageManager:a,importPath:``,mode:n,example:i.example,name:u,layout:i.layout,skillDetected:i.skillDetected,disableCodegen:i.disableCodegen})};if(n===`new`){if(!i.example)throw Error(`New project scaffolding requires an example.`);let t=i.name&&i.name!==`.`?r.default.join(c,i.name):void 0,n=i.name&&i.name!==`.`?r.default.basename(i.name):r.default.basename(c);return d.clone={repository:`https://github.com/yamcodes/arkenv.git`,example:i.example,targetName:n,...t!==void 0&&{targetDir:t}},d.install={packageManager:a,dependencies:[],...t!==void 0&&{cwd:t}},i.installSkill&&(d.skill={dlxCommand:mn(a),packageName:`yamcodes/arkenv`,isYes:e.isYes}),d.metadata.displayPath=`./src/env.ts`,d.metadata.importPath=`./src/env`,d}let f=r.default.resolve(c,i.path),p=r.default.dirname(f);if(i.framework===`nextjs`&&i.layout===`strict`){let e=r.default.extname(f),t=f.slice(0,-e.length),n=r.default.join(t,`internal`,`shared${e}`),a=r.default.join(t,`client${e}`),s=r.default.join(t,`server${e}`),u;if(i.framework===`nextjs`&&!i.disableCodegen&&o?.parsed){let e=o.parsed,n=(e.compilerOptions||{}).paths||{};if(n[`@/*`]){let i=e.path?r.default.dirname(e.path):c,a=r.default.join(t,`generated`),o=r.default.relative(i,a).replace(/\\/g,`/`);for(let e of n[`@/*`]){let t=e.replace(/^\.\//,``).replace(/\*$/,``);if(t===``||o.startsWith(t)){let e=o;t!==``&&o.startsWith(t)&&(e=o.substring(t.length)),e=e.replace(/^\/+/,``).replace(/\/+$/,``),u=`@/${e}/env.gen`.replace(/\/+/g,`/`);break}}}}let p=cn(i,u),m=l.includes(n),h=l.includes(a),g=l.includes(s);(!m||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:n,content:p.shared,action:m?`overwrite`:`create`,label:`shared environment schema`}),(!h||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:a,content:p.client,action:h?`overwrite`:`create`,label:`client environment schema`}),(!g||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:s,content:p.server,action:g?`overwrite`:`create`,label:`server environment schema`})}else{let e;if(i.framework===`nextjs`&&!i.disableCodegen&&o?.parsed){let t=o.parsed,n=(t.compilerOptions||{}).paths||{};if(n[`@/*`]){let i=t.path?r.default.dirname(t.path):c,a=r.default.join(p,`generated`),o=r.default.relative(i,a).replace(/\\/g,`/`);for(let t of n[`@/*`]){let n=t.replace(/^\.\//,``).replace(/\*$/,``);if(n===``||o.startsWith(n)){let t=o;n!==``&&o.startsWith(n)&&(t=o.substring(n.length)),t=t.replace(/^\/+/,``).replace(/\/+$/,``),e=`@/${t}/env.gen`.replace(/\/+/g,`/`);break}}}}let t=sn(i,e),n=l.includes(f);(!n||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:f,content:t,action:n?`overwrite`:`create`,label:`environment schema`})}let m=[`arkenv`,i.validator];if(i.framework===`vite`&&m.push(`@arkenv/vite-plugin`),i.framework===`bun-fullstack`&&i.bunFeatures?.length&&m.push(`@arkenv/bun-plugin`),i.framework===`nextjs`&&m.push(`@arkenv/nextjs`),(i.framework===`vite`||i.framework===`nextjs`||i.framework===`bun-fullstack`&&i.bunFeatures?.length)&&!m.includes(`arktype`)&&m.push(`arktype`),d.install={packageManager:a,dependencies:m},s&&o.file&&(d.tsConfig={path:r.default.resolve(c,o.file),action:`strict`}),(i.framework===`vite`||i.framework===`bun-fullstack`&&i.bunFeatures?.length)&&i.installTypeDefinitions!==!1){let e=i.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`,t=r.default.join(p,e),n=l.includes(t);if(i.envDtsHandling!==`skip`)if(i.envDtsHandling===`append`||!i.envDtsHandling&&n)d.files.push({path:t,content:f,action:`append`,label:`${i.framework} types`});else{let e=i.framework===`vite`?nn(i.path):rn(i.path);d.files.push({path:t,content:e,action:n?`overwrite`:`create`,label:`${i.framework} types`})}}(i.framework===`vite`||i.framework===`bun-fullstack`||i.framework===`nextjs`&&!i.disableCodegen)&&(d.bootstrap=(0,t.shake)({framework:i.framework,bunFeatures:i.framework===`bun-fullstack`?i.bunFeatures:void 0})),i.installSkill&&(d.skill={dlxCommand:mn(a),packageName:`yamcodes/arkenv`,isYes:e.isYes});let h=r.default.relative(c,f).replace(/\\/g,`/`),g=h.startsWith(`.`)?h:`./${h}`,_=g.replace(/\.(ts|js|tsx|jsx)$/,``);return d.metadata.displayPath=g,d.metadata.importPath=_,d.bootstrap&&(d.bootstrap.importPath=_),d}var gn=class{async fetchRegistry(){try{let e=await fetch(`https://raw.githubusercontent.com/yamcodes/arkenv/main/examples/registry.json`);if(!e.ok)throw Error(`Failed to fetch registry: ${e.statusText}`);return await e.json()}catch{return{examples:[{id:`basic`,name:`Basic`,description:`A minimal ArkEnv setup in Node.js`,framework:`vanilla`},{id:`with-nextjs`,name:`Next.js`,description:`Minimal Next.js project with ArkType`,framework:`nextjs`},{id:`with-vite-react`,name:`React + Vite`,framework:`vite`},{id:`with-bun`,name:`Bun (Vanilla)`,description:`Minimal Bun project with ArkType`,framework:`vanilla`},{id:`with-bun-react`,name:`React + Bun fullstack dev server`,framework:`bun-fullstack`},{id:`with-zod`,name:`Zod`,description:`ArkEnv with Zod in Node.js`,framework:`vanilla`}]}}}},_n=class{constructor(e,t,n,r,i=new gn){this.logger=e,this.workspace=t,this.prompt=n,this.scanner=r,this.registry=i}async execute(e){let t=await this.collect(e);if(!t)return!1;let n=hn(t),r=new pn(this.workspace,this.logger);try{await r.execute(n)}catch(e){this.logger.fatal(`Scaffolding failed.`,e)}return!0}async collect(e){this.logger.interactiveStdout(!0);try{let t=e.name;t&&r.default.resolve(process.cwd(),t)===process.cwd()&&(t=`.`);let n={...e,...t!==void 0&&{name:t}},i=t&&t!==`.`?r.default.resolve(process.cwd(),t):process.cwd(),a=await this.workspace.exists(i),o=a?await this.scanner.hasPackageJson(i):!1,s=a?await this.scanner.isEmptyDirectory(i):!0;return n.example===void 0?o?await this.collectExistingProject(n,i):s||n.isForce?await this.collectNewProject(n,s):(this.logger.error(`Directory is not empty and no ${Y(`package.json`)} was found.`),this.logger.info(`To scaffold a new project, run ${Y(`arkenv init`)} in an empty directory or use ${Y(`--force`)} to proceed anyway.`),null):await this.collectNewProject(n,s)}finally{this.logger.interactiveStdout(!1)}}async collectExistingProject(e,n){let{isYes:i,isForce:a,isQuiet:o,isAgent:s}=e,c=await this.scanner.checkRequirements(n),l=c.filter(e=>e.status===`fail`),u=c.filter(e=>e.status===`warn`);for(let e of u)this.logger.warn(`${e.requirement}: ${e.message}`);if(l.length>0)if(a){this.logger.warn(`Technical requirements not met, but continuing due to --force flag.`);for(let e of l)this.logger.warn(`${e.requirement}: ${e.message}`)}else{this.logger.error(`Technical requirements not met:`);for(let e of l)this.logger.error(`- ${e.requirement}: ${e.message}${e.current?` (Current: ${e.current}, Expected: ${e.expected})`:``}`);return this.logger.info(`Use --force to bypass these checks.`),null}let d=!1,f=await this.scanner.checkTsConfig(n);if(f.status===`not_strict`)if(i)d=!0;else{this.logger.warn(`TypeScript strict mode is not enabled in your ${Y(f.file)}.`);let e=await this.prompt.confirm(`ArkEnv requires ${Y(`strict`)} mode in your ${Y(f.file)}. Would you like to enable it now?`,!0,`Yes (Recommended)`);if(e===null)return null;if(!e)return this.logger.cancel(`Operation cancelled.`),null;d=!0}let p=await this.scanner.detectFramework(n,f.parsed),m=p===`bun-fullstack`?await this.scanner.detectBunFeatures(n,f.parsed):void 0,h=await this.scanner.suggestDefaultEnvPath(n,f.parsed),g=r.default.resolve(n,h),_=await this.scanner.getEnvExampleKeys(n,f.parsed,g),v=await(async()=>{if(e.isStrict){let e=r.default.extname(g),t=g.slice(0,-e.length),n=[r.default.join(t,`internal`,`shared${e}`),r.default.join(t,`client${e}`),r.default.join(t,`server${e}`)];if((await Promise.all(n.map(e=>this.workspace.exists(e)))).some(Boolean))return!0}return this.workspace.exists(g)})(),y=async({framework:e,envPath:t})=>{if(e!==`vite`&&e!==`bun-fullstack`)return!1;let i=e===`vite`?`vite-env.d.ts`:`bun-env.d.ts`,a=r.default.resolve(n,t),o=r.default.dirname(a),s=r.default.join(o,i);return this.workspace.exists(s)},b=await y({framework:p,envPath:h}),x=await this.prompt.runWizard((0,t.shake)({mode:`existing`,framework:p,bunFeatures:m,defaultEnvPath:h,tsConfig:f.parsed??null,envKeys:_?.keys,envKeysSource:_?.source,hasTypeFileAtPath:y,hasTypeFile:b,hasEnvSchemaFile:v,isStrict:e.isStrict,isSimple:e.isSimple,disableCodegen:e.noCodegen}),i);if(x===null)return null;let S=await this.scanner.hasSkill(n);if(S&&(x.skillDetected=!0,!o&&!s&&this.logger.info(`ArkEnv agent skill detected.`)),S)x.installSkill=!1;else if(s)x.installSkill=!1;else if(i)x.installSkill=!0;else{let e=await this.prompt.confirm(`Would you like to install the ArkEnv agent skill?`,!0,`Yes (Recommended)`);if(e===null)return null;x.installSkill=e}let C=r.default.resolve(n,x.path);if(x.overwriteEnvSchemaFile===void 0&&(x.layout===`strict`?await(async()=>{let e=r.default.extname(C),t=C.slice(0,-e.length);return(await Promise.all([this.workspace.exists(r.default.join(t,`internal`,`shared${e}`)),this.workspace.exists(r.default.join(t,`client${e}`)),this.workspace.exists(r.default.join(t,`server${e}`))])).some(Boolean)})():await this.workspace.exists(C))){let e=x.layout===`strict`?`Strict layout files (client, server, internal/shared)`:r.default.basename(C),t=await this.prompt.confirm(`${e} already exist. Overwrite?`,!1);if(t===null)return null;if(!t)return this.logger.cancel(`Operation cancelled.`),null;x.overwriteEnvSchemaFile=t}let ee=await this.scanner.detectPackageManager(n,f.parsed),w=r.default.extname(C),T=C.slice(0,-w.length),E=x.layout===`strict`?[r.default.join(T,`internal`,`shared${w}`),r.default.join(T,`client${w}`),r.default.join(T,`server${w}`)]:[C],D=[];for(let e of E)await this.workspace.exists(e)&&D.push(e);let O;if(x.framework===`vite`?O=`vite-env.d.ts`:x.framework===`bun-fullstack`&&(O=`bun-env.d.ts`),O){let e=r.default.dirname(C),t=r.default.join(e,O);await this.workspace.exists(t)&&D.push(t)}return(0,t.shake)({mode:`existing`,cwd:n,options:x,detectedFramework:p,detectedBunFeatures:m,packageManager:ee,tsConfig:f,shouldUpdateTsConfig:d,existingFiles:D,isYes:i})}async collectNewProject(e,n=!0){let{isYes:r,example:i,name:a,isForce:o}=e,s=await this.registry.fetchRegistry(),c=await this.prompt.runWizard((0,t.shake)({mode:`new`,examples:s.examples,example:i,name:a}),r);if(c===null)return null;if(c.name===`.`&&!n&&!o)return this.logger.error(`Cannot scaffold into ${Y(`.`)} because the current directory is not empty.`),this.logger.info(`Run ${Y(`arkenv init`)} in an empty directory or choose a sub-directory name instead.`),null;let l=this.detectPackageManager();return(0,t.shake)({mode:`new`,cwd:process.cwd(),options:c,detectedFramework:c.framework,packageManager:l,tsConfig:{status:`not_found`},shouldUpdateTsConfig:!1,existingFiles:[],isYes:r})}detectPackageManager(){let e=process.env.npm_config_user_agent||``;return e.includes(`pnpm`)?`pnpm`:e.includes(`yarn`)?`yarn`:e.includes(`bun`)?`bun`:`npm`}};function vn(e){let t=new Xt(e),n=t.logger,r=new Ot(t.isQuiet,n.stdio),i=new Kt;return{cli:t,logger:n,workspace:r,prompt:i,initUseCase:new _n(n,r,i,new bt),helpUseCase:new $t(n)}}let $,yn=!1;async function bn(){if(process.env.INIT_CWD)try{process.chdir(process.env.INIT_CWD)}catch{}let{cli:e,logger:n,initUseCase:r,helpUseCase:i}=vn(process.argv);$=n,xn(n),e.validationError&&(n.error(e.validationError),await i.execute(),await n.flush(),process.exit(1)),e.helpRequested&&(await i.execute(),await n.flush(),process.exit(0)),e.command!==`init`&&(e.command?n.error(`Unknown command: ${e.command}`):n.error(`Missing command.`),await i.execute(),await n.flush(),process.exit(1));try{await r.execute((0,t.shake)(e.initInput))||(await n.flush(),process.exit(1))}catch(e){try{n.fatal(`An unexpected error occurred`,e)}catch{}await n.flush(),process.exit(1)}}function xn(e){let t=async t=>{yn&&process.exit(t),yn=!0,setTimeout(()=>{process.exit(t)},2e3).unref(),e.interactiveStdout&&e.interactiveStdout(!1);try{e.cancel(`Operation cancelled.`),await e.flush()}catch(t){e.error&&e.error(`Logger failed during shutdown`,t)}finally{process.exit(t)}};process.on(`SIGINT`,()=>t(130)),process.on(`SIGTERM`,()=>t(143))}bn(),process.on(`unhandledRejection`,async e=>{if($){try{$.fatal(`Unhandled rejection`,e)}catch{}await $.flush()}else console.error(`Unhandled rejection`,e);process.exit(1)}),process.on(`uncaughtException`,async e=>{if($){try{$.fatal(`Uncaught exception`,e)}catch{}await $.flush()}else console.error(`Uncaught exception`,e);process.exit(1)});
|