create-sailor 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +73 -39
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
`));return}
|
|
2
|
+
import{execSync as ce}from"child_process";import Yt from"fs";import ye from"path";import*as v from"@clack/prompts";import{Command as Kt}from"commander";import A from"picocolors";import Mt from"update-notifier";import pt from"cfonts";import lt from"picocolors";import ge from"fs";import le from"path";import{fileURLToPath as at}from"url";function ct(){try{let t=le.dirname(at(import.meta.url));for(let n=0;n<4;n++){let s=le.join(t,"package.json");if(ge.existsSync(s)){let r=ge.readFileSync(s,"utf-8"),a=JSON.parse(r);if(a.name==="create-sailor"&&typeof a.version=="string")return a.version}t=le.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var U=ct();function ve(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${U}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
|
|
3
|
+
`));return}pt.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(lt.dim(` AI-Native SaaS Template \xB7 v${U} \xB7 nebutra.com
|
|
4
4
|
|
|
5
|
-
`))}import
|
|
5
|
+
`))}import V from"picocolors";function ut(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function he(e){let t=ut(),n=t?"\u2693":"-",s=t?"\u25B8":"->",r=t?"\u2605":"*",a=t?"\u{1F4E7}":"*",i=["",` ${t?V.bold(`${n} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${n} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?V.bold("Next:"):"Next:"}`,` ${s} cd ${e.targetDir}`];e.skippedInstall&&i.push(` ${s} pnpm install (if --no-install was set)`),i.push(` ${s} pnpm dev ${t?V.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?V.bold("Customize:"):"Customize:"}`,` ${s} pnpm sailor brand init ${t?V.dim("\u2192 your colors, logo, domain"):"-> your colors, logo, domain"}`,` ${s} pnpm sailor preset apply ${t?V.dim("\u2192 toggle features"):"-> toggle features"}`,` ${s} pnpm sailor add <feat> ${t?V.dim("\u2192 add queue/search/cache/..."):"-> add queue/search/cache/..."}`,"",` ${t?V.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${a} Free license https://nebutra.com/get-license`,""),process.stdout.write(i.join(`
|
|
6
6
|
`)+`
|
|
7
|
-
`)}var
|
|
7
|
+
`)}var dt=`Usage: create-sailor [name] [options]
|
|
8
8
|
|
|
9
9
|
Arguments:
|
|
10
10
|
name project directory (default: ./my-saas-app)
|
|
@@ -34,28 +34,59 @@ Examples:
|
|
|
34
34
|
$ npm create sailor@latest my-app -y
|
|
35
35
|
$ npm create sailor@latest my-app --auth=clerk --ai=openai,deepseek
|
|
36
36
|
$ npm create sailor@latest --dry-run
|
|
37
|
-
`;function
|
|
38
|
-
`)}var G=[{id:"anthropic",name:"Anthropic",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.anthropic.com",envVarPrefix:"ANTHROPIC",requiredEnvVars:["ANTHROPIC_API_KEY"]},{id:"openai",name:"OpenAI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.openai.com/docs",envVarPrefix:"OPENAI",requiredEnvVars:["OPENAI_API_KEY"]},{id:"deepseek",name:"DeepSeek",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.deepseek.com/api-docs",envVarPrefix:"DEEPSEEK",requiredEnvVars:["DEEPSEEK_API_KEY"]},{id:"xai",name:"xAI (Grok)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.x.ai/api",envVarPrefix:"XAI",requiredEnvVars:["XAI_API_KEY"]},{id:"moonshot",name:"Moonshot (Kimi)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.moonshot.cn/docs",envVarPrefix:"MOONSHOT",requiredEnvVars:["MOONSHOT_API_KEY","MOONSHOT_BASE_URL"]},{id:"google",name:"Google Gemini",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://ai.google.dev/gemini-api/docs",envVarPrefix:"GOOGLE_GENERATIVE_AI",requiredEnvVars:["GOOGLE_GENERATIVE_AI_API_KEY"]},{id:"mistral",name:"Mistral AI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.mistral.ai",envVarPrefix:"MISTRAL",requiredEnvVars:["MISTRAL_API_KEY"]},{id:"cohere",name:"Cohere",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.cohere.com",envVarPrefix:"COHERE",requiredEnvVars:["COHERE_API_KEY"]},{id:"perplexity",name:"Perplexity",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.perplexity.ai",baseURL:"https://api.perplexity.ai",envVarPrefix:"PERPLEXITY",requiredEnvVars:["PERPLEXITY_API_KEY"]},{id:"ai21",name:"AI21 Labs",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.ai21.com",baseURL:"https://api.ai21.com/studio/v1",envVarPrefix:"AI21",requiredEnvVars:["AI21_API_KEY"]},{id:"upstage",name:"Upstage (Solar)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://developers.upstage.ai/docs",baseURL:"https://api.upstage.ai/v1/solar",envVarPrefix:"UPSTAGE",requiredEnvVars:["UPSTAGE_API_KEY"]},{id:"siliconflow",name:"\u7845\u57FA\u6D41\u52A8 SiliconFlow",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://docs.siliconflow.cn",baseURL:"https://api.siliconflow.cn/v1",envVarPrefix:"SILICONFLOW",requiredEnvVars:["SILICONFLOW_API_KEY"]},{id:"volcengine-ark",name:"\u706B\u5C71\u5F15\u64CE ARK (\u8C46\u5305)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://www.volcengine.com/docs/82379",baseURL:"https://ark.cn-beijing.volces.com/api/v3",envVarPrefix:"ARK",requiredEnvVars:["ARK_API_KEY"]},{id:"bailian",name:"\u767E\u70BC Bailian (\u901A\u4E49)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://help.aliyun.com/zh/model-studio",baseURL:"https://dashscope.aliyuncs.com/compatible-mode/v1",envVarPrefix:"DASHSCOPE",requiredEnvVars:["DASHSCOPE_API_KEY"]},{id:"zhipu",name:"\u667A\u8C31 AI Zhipu",category:"\u56FD\u5185\u5E73\u53F0",status:"ai-sdk",docs:"https://docs.bigmodel.cn",baseURL:"https://open.bigmodel.cn/api/paas/v4",envVarPrefix:"ZHIPU",requiredEnvVars:["ZHIPU_API_KEY"]},{id:"baichuan",name:"\u767E\u5DDD\u667A\u80FD Baichuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.baichuan-ai.com/docs",baseURL:"https://api.baichuan-ai.com/v1",envVarPrefix:"BAICHUAN",requiredEnvVars:["BAICHUAN_API_KEY"]},{id:"minimax",name:"MiniMax (ABAB)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.minimaxi.com/document/guides",baseURL:"https://api.minimax.chat/v1",envVarPrefix:"MINIMAX",requiredEnvVars:["MINIMAX_API_KEY","MINIMAX_GROUP_ID"]},{id:"stepfun",name:"\u9636\u8DC3\u661F\u8FB0 StepFun",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.stepfun.com/docs",baseURL:"https://api.stepfun.com/v1",envVarPrefix:"STEPFUN",requiredEnvVars:["STEPFUN_API_KEY"]},{id:"sensetime",name:"\u5546\u6C64 SenseNova",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.sensetime.com",baseURL:"https://api.sensenova.cn/v1",envVarPrefix:"SENSENOVA",requiredEnvVars:["SENSENOVA_API_KEY"]},{id:"tencent",name:"\u817E\u8BAF\u6DF7\u5143 Hunyuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://cloud.tencent.com/document/product/1729",baseURL:"https://api.hunyuan.cloud.tencent.com/v1",envVarPrefix:"HUNYUAN",requiredEnvVars:["HUNYUAN_API_KEY"]},{id:"lingyi",name:"\u96F6\u4E00\u4E07\u7269 Yi",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.lingyiwanwu.com/docs",baseURL:"https://api.lingyiwanwu.com/v1",envVarPrefix:"YI",requiredEnvVars:["YI_API_KEY"]},{id:"openrouter",name:"OpenRouter",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://openrouter.ai/docs",envVarPrefix:"OPENROUTER",requiredEnvVars:["OPENROUTER_API_KEY"]},{id:"vercel-gateway",name:"Vercel AI Gateway",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://vercel.com/docs/ai-gateway",envVarPrefix:"AI_GATEWAY",requiredEnvVars:["AI_GATEWAY_API_KEY"]},{id:"litellm",name:"LiteLLM Proxy",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://docs.litellm.ai",baseURL:"http://localhost:4000/v1",envVarPrefix:"LITELLM",requiredEnvVars:["LITELLM_API_KEY"]},{id:"portkey",name:"Portkey",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://portkey.ai/docs",baseURL:"https://api.portkey.ai/v1",envVarPrefix:"PORTKEY",requiredEnvVars:["PORTKEY_API_KEY"]},{id:"aws-bedrock",name:"AWS Bedrock",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://aws.amazon.com/bedrock/",envVarPrefix:"AWS_BEDROCK",requiredEnvVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"]},{id:"azure-openai",name:"Azure OpenAI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://azure.microsoft.com/en-us/products/cognitive-services/openai-service/",envVarPrefix:"AZURE_OPENAI",requiredEnvVars:["AZURE_OPENAI_API_KEY","AZURE_OPENAI_ENDPOINT"]},{id:"gcp-vertex",name:"GCP Vertex AI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://cloud.google.com/vertex-ai",envVarPrefix:"GOOGLE_VERTEX",requiredEnvVars:["GOOGLE_APPLICATION_CREDENTIALS"]},{id:"groq",name:"Groq",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://console.groq.com/docs",envVarPrefix:"GROQ",requiredEnvVars:["GROQ_API_KEY"]},{id:"fireworks",name:"Fireworks AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.fireworks.ai",envVarPrefix:"FIREWORKS",requiredEnvVars:["FIREWORKS_API_KEY"]},{id:"together",name:"Together AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.together.ai",envVarPrefix:"TOGETHER",requiredEnvVars:["TOGETHER_API_KEY"]},{id:"huggingface",name:"Hugging Face",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://huggingface.co/docs/inference-providers",envVarPrefix:"HF",requiredEnvVars:["HF_API_KEY"]},{id:"replicate",name:"Replicate",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://replicate.com/docs",envVarPrefix:"REPLICATE",requiredEnvVars:["REPLICATE_API_TOKEN"]},{id:"lepton",name:"Lepton AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://www.lepton.ai/docs",baseURL:"https://api.lepton.ai/v1",envVarPrefix:"LEPTON",requiredEnvVars:["LEPTON_API_KEY"]},{id:"anyscale",name:"Anyscale Endpoints",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://docs.endpoints.anyscale.com/",baseURL:"https://api.endpoints.anyscale.com/v1",envVarPrefix:"ANYSCALE",requiredEnvVars:["ANYSCALE_API_KEY"]},{id:"octoai",name:"OctoAI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://octoai.cloud/docs",baseURL:"https://text.octoai.run/v1",envVarPrefix:"OCTOAI",requiredEnvVars:["OCTOAI_TOKEN"]},{id:"deepinfra",name:"DeepInfra",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://deepinfra.com/docs",baseURL:"https://api.deepinfra.com/v1/openai",envVarPrefix:"DEEPINFRA",requiredEnvVars:["DEEPINFRA_API_KEY"]},{id:"novita",name:"Novita AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://novita.ai/docs",baseURL:"https://api.novita.ai/v3/openai",envVarPrefix:"NOVITA",requiredEnvVars:["NOVITA_API_KEY"]},{id:"black-forest-labs",name:"Black Forest Labs (FLUX)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://docs.bfl.ml",envVarPrefix:"BFL",requiredEnvVars:["BFL_API_KEY"]},{id:"elevenlabs",name:"ElevenLabs (TTS)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://elevenlabs.io/docs",envVarPrefix:"ELEVENLABS",requiredEnvVars:["ELEVENLABS_API_KEY"]},{id:"runway",name:"Runway (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://runwayml.com",envVarPrefix:"RUNWAY",requiredEnvVars:["RUNWAY_API_KEY"]},{id:"luma",name:"Luma (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://lumalabs.ai",envVarPrefix:"LUMA",requiredEnvVars:["LUMA_API_KEY"]},{id:"midjourney",name:"Midjourney",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://docs.midjourney.com",envVarPrefix:"MIDJOURNEY",requiredEnvVars:[]},{id:"ollama",name:"Ollama (\u672C\u5730)",category:"\u672C\u5730\u90E8\u7F72",status:"opencode",docs:"https://github.com/ollama/ollama",baseURL:"http://localhost:11434/v1",envVarPrefix:"OLLAMA",requiredEnvVars:["OLLAMA_BASE_URL"]},{id:"lmstudio",name:"LM Studio",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://lmstudio.ai/docs",baseURL:"http://localhost:1234/v1",envVarPrefix:"LMSTUDIO",requiredEnvVars:[]},{id:"vllm",name:"vLLM",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://docs.vllm.ai",baseURL:"http://localhost:8000/v1",envVarPrefix:"VLLM",requiredEnvVars:[]},{id:"tgi",name:"HF TGI",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://huggingface.co/docs/text-generation-inference",baseURL:"http://localhost:8080/v1",envVarPrefix:"TGI",requiredEnvVars:[]}],xt=G.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});import Me from"fs";import Ke from"path";async function ce(e,t){let n=Ke.join(e,"nebutra.config.json");Me.writeFileSync(n,JSON.stringify(t,null,2)+`
|
|
39
|
-
|
|
37
|
+
`;function Ee(){process.stdout.write(dt)}import oe from"picocolors";function Pe(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function mt(e){let t=Pe()?"\u25B8":"->",n=`[${e.index}/${e.total}]`,s=e.label.padEnd(18," ");return Pe()?`${oe.dim(n)} ${oe.bold(s)} ${oe.dim(t)} ${oe.cyan(e.value)}`:`${n} ${s} ${t} ${e.value}`}function be(e){process.stdout.write(mt(e)+`
|
|
38
|
+
`)}var ie=[{id:"anthropic",name:"Anthropic",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.anthropic.com",envVarPrefix:"ANTHROPIC",requiredEnvVars:["ANTHROPIC_API_KEY"]},{id:"openai",name:"OpenAI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.openai.com/docs",envVarPrefix:"OPENAI",requiredEnvVars:["OPENAI_API_KEY"]},{id:"deepseek",name:"DeepSeek",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.deepseek.com/api-docs",envVarPrefix:"DEEPSEEK",requiredEnvVars:["DEEPSEEK_API_KEY"]},{id:"xai",name:"xAI (Grok)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.x.ai/api",envVarPrefix:"XAI",requiredEnvVars:["XAI_API_KEY"]},{id:"moonshot",name:"Moonshot (Kimi)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.moonshot.cn/docs",envVarPrefix:"MOONSHOT",requiredEnvVars:["MOONSHOT_API_KEY","MOONSHOT_BASE_URL"]},{id:"google",name:"Google Gemini",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://ai.google.dev/gemini-api/docs",envVarPrefix:"GOOGLE_GENERATIVE_AI",requiredEnvVars:["GOOGLE_GENERATIVE_AI_API_KEY"]},{id:"mistral",name:"Mistral AI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.mistral.ai",envVarPrefix:"MISTRAL",requiredEnvVars:["MISTRAL_API_KEY"]},{id:"cohere",name:"Cohere",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.cohere.com",envVarPrefix:"COHERE",requiredEnvVars:["COHERE_API_KEY"]},{id:"perplexity",name:"Perplexity",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.perplexity.ai",baseURL:"https://api.perplexity.ai",envVarPrefix:"PERPLEXITY",requiredEnvVars:["PERPLEXITY_API_KEY"]},{id:"ai21",name:"AI21 Labs",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.ai21.com",baseURL:"https://api.ai21.com/studio/v1",envVarPrefix:"AI21",requiredEnvVars:["AI21_API_KEY"]},{id:"upstage",name:"Upstage (Solar)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://developers.upstage.ai/docs",baseURL:"https://api.upstage.ai/v1/solar",envVarPrefix:"UPSTAGE",requiredEnvVars:["UPSTAGE_API_KEY"]},{id:"siliconflow",name:"\u7845\u57FA\u6D41\u52A8 SiliconFlow",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://docs.siliconflow.cn",baseURL:"https://api.siliconflow.cn/v1",envVarPrefix:"SILICONFLOW",requiredEnvVars:["SILICONFLOW_API_KEY"]},{id:"volcengine-ark",name:"\u706B\u5C71\u5F15\u64CE ARK (\u8C46\u5305)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://www.volcengine.com/docs/82379",baseURL:"https://ark.cn-beijing.volces.com/api/v3",envVarPrefix:"ARK",requiredEnvVars:["ARK_API_KEY"]},{id:"bailian",name:"\u767E\u70BC Bailian (\u901A\u4E49)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://help.aliyun.com/zh/model-studio",baseURL:"https://dashscope.aliyuncs.com/compatible-mode/v1",envVarPrefix:"DASHSCOPE",requiredEnvVars:["DASHSCOPE_API_KEY"]},{id:"zhipu",name:"\u667A\u8C31 AI Zhipu",category:"\u56FD\u5185\u5E73\u53F0",status:"ai-sdk",docs:"https://docs.bigmodel.cn",baseURL:"https://open.bigmodel.cn/api/paas/v4",envVarPrefix:"ZHIPU",requiredEnvVars:["ZHIPU_API_KEY"]},{id:"baichuan",name:"\u767E\u5DDD\u667A\u80FD Baichuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.baichuan-ai.com/docs",baseURL:"https://api.baichuan-ai.com/v1",envVarPrefix:"BAICHUAN",requiredEnvVars:["BAICHUAN_API_KEY"]},{id:"minimax",name:"MiniMax (ABAB)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.minimaxi.com/document/guides",baseURL:"https://api.minimax.chat/v1",envVarPrefix:"MINIMAX",requiredEnvVars:["MINIMAX_API_KEY","MINIMAX_GROUP_ID"]},{id:"stepfun",name:"\u9636\u8DC3\u661F\u8FB0 StepFun",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.stepfun.com/docs",baseURL:"https://api.stepfun.com/v1",envVarPrefix:"STEPFUN",requiredEnvVars:["STEPFUN_API_KEY"]},{id:"sensetime",name:"\u5546\u6C64 SenseNova",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.sensetime.com",baseURL:"https://api.sensenova.cn/v1",envVarPrefix:"SENSENOVA",requiredEnvVars:["SENSENOVA_API_KEY"]},{id:"tencent",name:"\u817E\u8BAF\u6DF7\u5143 Hunyuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://cloud.tencent.com/document/product/1729",baseURL:"https://api.hunyuan.cloud.tencent.com/v1",envVarPrefix:"HUNYUAN",requiredEnvVars:["HUNYUAN_API_KEY"]},{id:"lingyi",name:"\u96F6\u4E00\u4E07\u7269 Yi",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.lingyiwanwu.com/docs",baseURL:"https://api.lingyiwanwu.com/v1",envVarPrefix:"YI",requiredEnvVars:["YI_API_KEY"]},{id:"openrouter",name:"OpenRouter",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://openrouter.ai/docs",envVarPrefix:"OPENROUTER",requiredEnvVars:["OPENROUTER_API_KEY"]},{id:"vercel-gateway",name:"Vercel AI Gateway",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://vercel.com/docs/ai-gateway",envVarPrefix:"AI_GATEWAY",requiredEnvVars:["AI_GATEWAY_API_KEY"]},{id:"litellm",name:"LiteLLM Proxy",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://docs.litellm.ai",baseURL:"http://localhost:4000/v1",envVarPrefix:"LITELLM",requiredEnvVars:["LITELLM_API_KEY"]},{id:"portkey",name:"Portkey",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://portkey.ai/docs",baseURL:"https://api.portkey.ai/v1",envVarPrefix:"PORTKEY",requiredEnvVars:["PORTKEY_API_KEY"]},{id:"aws-bedrock",name:"AWS Bedrock",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://aws.amazon.com/bedrock/",envVarPrefix:"AWS_BEDROCK",requiredEnvVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"]},{id:"azure-openai",name:"Azure OpenAI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://azure.microsoft.com/en-us/products/cognitive-services/openai-service/",envVarPrefix:"AZURE_OPENAI",requiredEnvVars:["AZURE_OPENAI_API_KEY","AZURE_OPENAI_ENDPOINT"]},{id:"gcp-vertex",name:"GCP Vertex AI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://cloud.google.com/vertex-ai",envVarPrefix:"GOOGLE_VERTEX",requiredEnvVars:["GOOGLE_APPLICATION_CREDENTIALS"]},{id:"groq",name:"Groq",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://console.groq.com/docs",envVarPrefix:"GROQ",requiredEnvVars:["GROQ_API_KEY"]},{id:"fireworks",name:"Fireworks AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.fireworks.ai",envVarPrefix:"FIREWORKS",requiredEnvVars:["FIREWORKS_API_KEY"]},{id:"together",name:"Together AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.together.ai",envVarPrefix:"TOGETHER",requiredEnvVars:["TOGETHER_API_KEY"]},{id:"huggingface",name:"Hugging Face",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://huggingface.co/docs/inference-providers",envVarPrefix:"HF",requiredEnvVars:["HF_API_KEY"]},{id:"replicate",name:"Replicate",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://replicate.com/docs",envVarPrefix:"REPLICATE",requiredEnvVars:["REPLICATE_API_TOKEN"]},{id:"lepton",name:"Lepton AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://www.lepton.ai/docs",baseURL:"https://api.lepton.ai/v1",envVarPrefix:"LEPTON",requiredEnvVars:["LEPTON_API_KEY"]},{id:"anyscale",name:"Anyscale Endpoints",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://docs.endpoints.anyscale.com/",baseURL:"https://api.endpoints.anyscale.com/v1",envVarPrefix:"ANYSCALE",requiredEnvVars:["ANYSCALE_API_KEY"]},{id:"octoai",name:"OctoAI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://octoai.cloud/docs",baseURL:"https://text.octoai.run/v1",envVarPrefix:"OCTOAI",requiredEnvVars:["OCTOAI_TOKEN"]},{id:"deepinfra",name:"DeepInfra",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://deepinfra.com/docs",baseURL:"https://api.deepinfra.com/v1/openai",envVarPrefix:"DEEPINFRA",requiredEnvVars:["DEEPINFRA_API_KEY"]},{id:"novita",name:"Novita AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://novita.ai/docs",baseURL:"https://api.novita.ai/v3/openai",envVarPrefix:"NOVITA",requiredEnvVars:["NOVITA_API_KEY"]},{id:"black-forest-labs",name:"Black Forest Labs (FLUX)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://docs.bfl.ml",envVarPrefix:"BFL",requiredEnvVars:["BFL_API_KEY"]},{id:"elevenlabs",name:"ElevenLabs (TTS)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://elevenlabs.io/docs",envVarPrefix:"ELEVENLABS",requiredEnvVars:["ELEVENLABS_API_KEY"]},{id:"runway",name:"Runway (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://runwayml.com",envVarPrefix:"RUNWAY",requiredEnvVars:["RUNWAY_API_KEY"]},{id:"luma",name:"Luma (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://lumalabs.ai",envVarPrefix:"LUMA",requiredEnvVars:["LUMA_API_KEY"]},{id:"midjourney",name:"Midjourney",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://docs.midjourney.com",envVarPrefix:"MIDJOURNEY",requiredEnvVars:[]},{id:"ollama",name:"Ollama (\u672C\u5730)",category:"\u672C\u5730\u90E8\u7F72",status:"opencode",docs:"https://github.com/ollama/ollama",baseURL:"http://localhost:11434/v1",envVarPrefix:"OLLAMA",requiredEnvVars:["OLLAMA_BASE_URL"]},{id:"lmstudio",name:"LM Studio",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://lmstudio.ai/docs",baseURL:"http://localhost:1234/v1",envVarPrefix:"LMSTUDIO",requiredEnvVars:[]},{id:"vllm",name:"vLLM",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://docs.vllm.ai",baseURL:"http://localhost:8000/v1",envVarPrefix:"VLLM",requiredEnvVars:[]},{id:"tgi",name:"HF TGI",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://huggingface.co/docs/text-generation-inference",baseURL:"http://localhost:8080/v1",envVarPrefix:"TGI",requiredEnvVars:[]}],an=ie.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});import x from"fs";import $ from"path";function ue(e){x.existsSync(e)&&x.rmSync(e,{recursive:!0,force:!0})}function xe(e,t){let n=$.join(e,".env.example");x.existsSync(n)?x.appendFileSync(n,`
|
|
39
|
+
`+t):x.writeFileSync(n,t)}function Se(e,t){if(!x.existsSync(e))return;let n=x.readFileSync(e,"utf8"),s=n.replace(/export type AuthProviderId\s*=\s*"[^"]+"\s*\|\s*"[^"]+";/,`export type AuthProviderId = "${t}";`);s!==n&&x.writeFileSync(e,s)}function ft(e,t){let n=$.join(e,"README.md");if(!x.existsSync(n)){x.writeFileSync(n,t);return}x.appendFileSync(n,`
|
|
40
|
+
`+t)}async function Ae(e,t){let n=$.join(e,"packages","auth");if(!x.existsSync(n))return;if(t==="none"){ue(n),ft(e,`
|
|
41
|
+
## Auth
|
|
42
|
+
|
|
43
|
+
Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth).
|
|
44
|
+
`);return}let s=$.join(n,"src","providers"),r=$.join(n,"src","types.ts");if(t==="clerk"){ue($.join(s,"better-auth.ts")),Se(r,"clerk"),xe(e,`# Clerk auth
|
|
45
|
+
CLERK_PUBLISHABLE_KEY=
|
|
46
|
+
CLERK_SECRET_KEY=
|
|
47
|
+
`);return}if(t==="betterauth"){ue($.join(s,"clerk.ts")),Se(r,"better-auth"),xe(e,`# Better Auth
|
|
48
|
+
BETTER_AUTH_SECRET=
|
|
49
|
+
BETTER_AUTH_URL=http://localhost:3000
|
|
50
|
+
`);return}}import yt from"fs";import gt from"path";async function we(e,t){let n=gt.join(e,"nebutra.config.json");yt.writeFileSync(n,JSON.stringify(t,null,2)+`
|
|
51
|
+
`)}import j from"fs";import de from"path";function vt(e){j.existsSync(e)&&j.rmSync(e,{recursive:!0,force:!0})}function ke(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function ht(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function Ie(e){let t=e.replace(/^\s*extensions\s*=\s*\[[^\]]*\]\s*\n/gm,"");return t=t.replace(/previewFeatures\s*=\s*\[\s*"postgresqlExtensions"\s*\]\s*\n/g,""),t}function Et(e,t){let n=de.join(e,".env.example");j.existsSync(n)?j.appendFileSync(n,`
|
|
52
|
+
`+t):j.writeFileSync(n,t)}async function _e(e,t,n){let s=de.join(e,"packages","db");if(t==="none"){vt(s);return}let r=de.join(s,"prisma","schema.prisma"),a;if(t==="postgresql"?a=`postgresql://postgres:postgres@localhost:5432/${n}`:t==="mysql"?a=`mysql://root:root@localhost:3306/${n}`:a="file:./dev.db",Et(e,`# Database (${t})
|
|
53
|
+
DATABASE_URL="${a}"
|
|
54
|
+
`),!j.existsSync(r))return;let p=j.readFileSync(r,"utf8"),i=p;t==="mysql"?(i=ke(i,"mysql"),i=Ie(i)):t==="sqlite"&&(i=ke(i,"sqlite"),i=ht(i),i=Ie(i)),i!==p&&j.writeFileSync(r,i)}import Z from"fs";import S from"path";import{fileURLToPath as Pt}from"url";var bt=Pt(import.meta.url),xt=S.dirname(bt);async function Re(e,t){if(t==="none")return;let n=S.join(xt,"../../templates/deploy");t==="vercel"?await Z.promises.copyFile(S.join(n,"vercel.json"),S.join(e,"vercel.json")):t==="railway"?await Z.promises.copyFile(S.join(n,"railway.toml"),S.join(e,"railway.toml")):t==="cloudflare"?await Z.promises.copyFile(S.join(n,"wrangler.toml"),S.join(e,"wrangler.toml")):t==="selfhost"&&(await Z.promises.copyFile(S.join(n,"docker-compose.yml"),S.join(e,"docker-compose.yml")),await Z.promises.copyFile(S.join(n,"Dockerfile.web"),S.join(e,"Dockerfile.web")))}import q from"fs";import Y from"path";import{fileURLToPath as St}from"url";var At=St(import.meta.url),Ce=Y.dirname(At),wt=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml)$/;function kt(e){let t=[Y.join(Ce,"..","templates","docs",e),Y.join(Ce,"..","..","templates","docs",e)];for(let n of t)if(q.existsSync(n))return n;return t[0]}async function Le(e,t){if(t.framework==="none")return;let n=(t.framework==="fumadocs","fumadocs"),s=kt(n),r=Y.join(e,"apps","docs");if(!q.existsSync(s))throw new Error(`Docs template not found: ${s}`);Te(s,r),Ne(r,{"{PRODUCT_NAME}":t.projectName})}function Te(e,t){q.mkdirSync(t,{recursive:!0});for(let n of q.readdirSync(e,{withFileTypes:!0})){let s=Y.join(e,n.name),r=Y.join(t,n.name);n.isDirectory()?Te(s,r):q.copyFileSync(s,r)}}function Ne(e,t){for(let n of q.readdirSync(e,{withFileTypes:!0})){let s=Y.join(e,n.name);if(n.isDirectory())Ne(s,t);else if(wt.test(n.name)){let r=q.readFileSync(s,"utf-8");for(let[a,p]of Object.entries(t))r=r.split(a).join(p);q.writeFileSync(s,r)}}}import ae from"fs";import Oe from"path";async function Ve(e,t){let n=`# Automatically injected by create-sailor
|
|
40
55
|
DATABASE_URL="${String(t.databaseUrl)}"
|
|
41
56
|
|
|
42
57
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
|
|
43
58
|
CLERK_SECRET_KEY="${String(t.clerkSecret)}"
|
|
44
59
|
|
|
45
60
|
NEXT_PUBLIC_SITE_URL="http://localhost:3000"
|
|
46
|
-
`,s=
|
|
47
|
-
`+n)}import{execSync as
|
|
61
|
+
`,s=Oe.join(e,".env"),r=Oe.join(e,".env.local");!ae.existsSync(s)&&!ae.existsSync(r)?ae.writeFileSync(r,n):ae.appendFileSync(r,`
|
|
62
|
+
`+n)}import{execSync as It}from"child_process";import _ from"fs";import z from"path";import _t from"ignore";var Rt={mirror:{repo:process.env.SAILOR_TEMPLATE_REPO||"Nebutra/Sailor-Template",ref:process.env.SAILOR_TEMPLATE_REF||"main",applyIgnore:!1},main:{repo:"Nebutra/Nebutra-Sailor",ref:"main",applyIgnore:!0}};function Ct(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function je(e,t,n){let s=_.readdirSync(t,{withFileTypes:!0});for(let r of s){if(r.name==="node_modules"||r.name===".git")continue;let a=z.join(t,r.name),p=z.relative(e,a).split(z.sep).join("/");r.isDirectory()?(n.push(p+"/"),je(e,a,n)):n.push(p)}}function Lt(e){let t=z.join(e,".templateignore");if(!_.existsSync(t))return;let n=_.readFileSync(t,"utf8"),s=_t().add(n),r=[];je(e,e,r);let a=r.map(o=>o.endsWith("/")?o.slice(0,-1):o),p=new Set(s.filter(a)),i=a.filter(o=>!p.has(o)).sort((o,m)=>m.split("/").length-o.split("/").length);for(let o of i){let m=z.join(e,o);try{_.existsSync(m)&&_.rmSync(m,{recursive:!0,force:!0})}catch{}}try{_.existsSync(t)&&_.rmSync(t,{force:!0})}catch{}}function Tt(e,t){It(`set -o pipefail; curl -sSfL ${e} | tar -xz -C "${t}" --strip-components=1`,{stdio:"ignore",shell:"bash"})}async function qe(e){_.mkdirSync(e,{recursive:!0});let n=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],s;for(let r of n){let a=Rt[r],p=Ct(a.repo,a.ref);try{if(Tt(p,e),a.applyIgnore)try{Lt(e)}catch(i){throw new Error(`Template cloned, but .templateignore processing failed: ${i instanceof Error?i.message:String(i)}`)}return}catch(i){s=i instanceof Error?i:new Error(String(i));try{let o=_.readdirSync(e);for(let m of o)_.rmSync(z.join(e,m),{recursive:!0,force:!0})}catch{}}}throw new Error(`Failed to download the template from any source. Last error: ${s?.message??"unknown"}
|
|
48
63
|
|
|
49
64
|
Ensure you have internet access and curl/tar installed.
|
|
50
|
-
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import
|
|
51
|
-
`)}}import
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
65
|
+
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import me from"fs";import Nt from"path";async function Fe(e,t){let n=Nt.join(e,"package.json");if(me.existsSync(n)){let s=me.readFileSync(n,"utf8"),r=JSON.parse(s);r.name=t,r.version="0.1.0",me.writeFileSync(n,JSON.stringify(r,null,2)+`
|
|
66
|
+
`)}}import C from"fs";import Q from"path";var Ot=["stripe","lemonsqueezy","chinapay","polar"];function De(e){C.existsSync(e)&&C.rmSync(e,{recursive:!0,force:!0})}function Vt(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function jt(e,t){let n=Q.join(e,".env.example");C.existsSync(n)?C.appendFileSync(n,`
|
|
67
|
+
`+t):C.writeFileSync(n,t)}function qt(e){switch(e){case"stripe":return`# Stripe
|
|
68
|
+
STRIPE_SECRET_KEY=
|
|
69
|
+
STRIPE_WEBHOOK_SECRET=
|
|
70
|
+
`;case"lemon":return`# Lemon Squeezy
|
|
71
|
+
LEMONSQUEEZY_API_KEY=
|
|
72
|
+
LEMONSQUEEZY_STORE_ID=
|
|
73
|
+
LEMONSQUEEZY_WEBHOOK_SECRET=
|
|
74
|
+
`;case"wechat":return`# WeChat Pay (via ChinaPay aggregator)
|
|
75
|
+
CHINAPAY_APP_ID=
|
|
76
|
+
CHINAPAY_APP_SECRET=
|
|
77
|
+
CHINAPAY_WECHAT_ENABLED=true
|
|
78
|
+
`;case"alipay":return`# Alipay (via ChinaPay aggregator)
|
|
79
|
+
CHINAPAY_APP_ID=
|
|
80
|
+
CHINAPAY_APP_SECRET=
|
|
81
|
+
CHINAPAY_ALIPAY_ENABLED=true
|
|
82
|
+
`}}async function Ue(e,t){let n=Q.join(e,"packages","billing");if(!C.existsSync(n))return;if(t==="none"){De(n);return}let s=Q.join(n,"src"),r=new Set(Vt(t));for(let p of Ot)r.has(p)||De(Q.join(s,p));let a=Q.join(s,"checkout","types.ts");if(C.existsSync(a)){let p=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",i=C.readFileSync(a,"utf8"),o=i.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${p}";`);o!==i&&C.writeFileSync(a,o)}jt(e,qt(t))}import F from"fs";import G from"path";var Ke=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),fe=/@sailor:([^\s*]+)/;function Ft(e,t){let{providerIds:n,customEndpoint:s}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:n.includes(r)}}if(e==="cn-compatible"){let r=n.some(a=>Ke.has(a));return{marker:e,keep:r||!!s}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:n.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!s}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function $e(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function Ye(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function Me(e,t){let n=e.split(`
|
|
83
|
+
`),s=[],r=e.includes("#"),a=0;for(;a<n.length;){let p=n[a],i=p.match(fe);if(!i){s.push(p),a++;continue}let{marker:o,keep:m}=Ft(i[1],t);if(o==="registry-entries"){s.push(r?Ye(p):$e(p)),a++;continue}if(m){let f=r?Ye(p):$e(p);f.trim().length>0&&s.push(f);let E=a+1;for(;E<n.length&&n[E].trim()!==""&&!fe.test(n[E]);)s.push(n[E]),E++;E<n.length&&n[E].trim()===""&&(s.push(n[E]),E++),a=E}else{let f=a+1;for(;f<n.length&&n[f].trim()!==""&&!fe.test(n[f]);)f++;f<n.length&&n[f].trim()===""&&f++,a=f}}return Dt(s.join(`
|
|
84
|
+
`),t)}function Dt(e,t){let{providerIds:n,customEndpoint:s}=t,r=new Set;for(let m of n)["openai","anthropic","google","mistral","xai"].includes(m)&&r.add(m),r.add(m.replace(/-/g,"_")),r.add(m);s&&r.add("custom");let a=/createProviderRegistry\(\{([\s\S]*?)\}\)/,p=e.match(a);if(!p)return e;let o=p[1].split(`
|
|
85
|
+
`).filter(m=>{let f=m.trim();if(f===""||f.startsWith("//"))return!0;let E=f.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return E?r.has(E[1]):!0}).join(`
|
|
86
|
+
`);return e.replace(a,`createProviderRegistry({${o}})`)}function Ut(e,t){let n=G.join(t,"registry.ts.template"),s=F.readFileSync(n,"utf-8");return Me(s,e)}function $t(e,t){let n=G.join(t,".env.example.template"),s=F.readFileSync(n,"utf-8");return Me(s,e)}async function Be(e,t,n){let s=Ut(t,n),r=$t(t,n),a=G.join(e,"packages/ai-sdk/src");await F.promises.mkdir(a,{recursive:!0}),await F.promises.writeFile(G.join(a,"registry.ts"),s),await F.promises.appendFile(G.join(e,".env.example"),`
|
|
87
|
+
`+r);let p={ai:"latest"},{providerIds:i,customEndpoint:o}=t;(i.includes("openai")||o||i.some(f=>Ke.has(f)))&&(p["@ai-sdk/openai"]="latest",p["@ai-sdk/openai-compatible"]="latest"),i.includes("anthropic")&&(p["@ai-sdk/anthropic"]="latest"),i.includes("google")&&(p["@ai-sdk/google"]="latest"),i.includes("mistral")&&(p["@ai-sdk/mistral"]="latest"),i.includes("xai")&&(p["@ai-sdk/openai"]="latest");let m=G.join(e,"package.json");if(F.existsSync(m)){let f=JSON.parse(await F.promises.readFile(m,"utf-8"));f.dependencies||(f.dependencies={});for(let[E,K]of Object.entries(p))f.dependencies[E]=K;await F.promises.writeFile(m,JSON.stringify(f,null,2)+`
|
|
88
|
+
`)}}import l from"fs";import h from"path";function We(e,t){if(!l.existsSync(e))return;let n=l.readdirSync(e);for(let s of n){let r=h.join(e,s);l.statSync(r).isDirectory()?We(r,t):t(r)}}async function He(e,t){let n=h.join(e,"package.json");if(!l.existsSync(n))return;let s=JSON.parse(l.readFileSync(n,"utf8"));if(t.orm!=="prisma"){let r=h.join(e,"packages","db");if(l.existsSync(r)){let a=h.join(r,"prisma");l.existsSync(a)&&l.rmSync(a,{recursive:!0,force:!0});let p=h.join(r,"package.json");if(l.existsSync(p)){let o=JSON.parse(l.readFileSync(p,"utf8"));o.dependencies&&delete o.dependencies["@prisma/client"],o.devDependencies&&delete o.devDependencies.prisma,l.writeFileSync(p,JSON.stringify(o,null,2)+`
|
|
89
|
+
`)}let i=h.join(r,"src","index.ts");l.existsSync(i)&&l.writeFileSync(i,`
|
|
59
90
|
export const prisma = {} as any;
|
|
60
91
|
export const db = {} as any;
|
|
61
92
|
export type PrismaClient = any;
|
|
@@ -101,7 +132,7 @@ export type UsageAggregate = any;
|
|
|
101
132
|
export type UsageLedgerEntry = any;
|
|
102
133
|
export type UsageType = any;
|
|
103
134
|
export type UsageLedgerSource = any;
|
|
104
|
-
`)}s.scripts?.postinstall&&(s.scripts.postinstall=s.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=
|
|
135
|
+
`)}s.scripts?.postinstall&&(s.scripts.postinstall=s.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=h.join(e,"apps");if(l.existsSync(r)){let a=l.readdirSync(r);for(let p of a){let i=h.join(r,p);if(!l.statSync(i).isDirectory())continue;let o=h.join(i,"src","app");if(!l.existsSync(o))continue;["[lang]","[locale]"].forEach(g=>{let c=h.join(o,g);if(l.existsSync(c)){let b=l.readdirSync(c);for(let L of b)l.renameSync(h.join(c,L),h.join(o,L));l.rmdirSync(c)}}),["src/middleware.ts","middleware.ts"].forEach(g=>{let c=h.join(i,g);l.existsSync(c)&&l.rmSync(c)});let m=h.join(i,"src","lib");l.existsSync(m)||l.mkdirSync(m,{recursive:!0});let f=h.join(m,"mock-i18n.ts");l.writeFileSync(f,`
|
|
105
136
|
import React from 'react';
|
|
106
137
|
export function useTranslations(namespace?: string): any { return (key: string) => key; }
|
|
107
138
|
export function useLocale() { return 'en'; }
|
|
@@ -119,7 +150,7 @@ export const useRouter = () => ({ push: (...args: any[]) => {}, replace: (...arg
|
|
|
119
150
|
export default function createMiddleware(...args: any[]) { return (req: any) => req; }
|
|
120
151
|
export function createNavigation(...args: any[]) { return { Link, redirect, usePathname, useRouter, getPathname: () => '/' }; }
|
|
121
152
|
export function defineRouting<T>(config: T): T { return config; }
|
|
122
|
-
`);let
|
|
153
|
+
`);let K=h.join(m,"mock-i18n.d.ts");l.writeFileSync(K,`declare module '@/lib/mock-i18n' {
|
|
123
154
|
export function useTranslations(namespace?: string): any;
|
|
124
155
|
export function useLocale(): string;
|
|
125
156
|
export const NextIntlClientProvider: React.FC<any>;
|
|
@@ -137,27 +168,30 @@ export function defineRouting<T>(config: T): T { return config; }
|
|
|
137
168
|
export function createNavigation(...args: any[]): any;
|
|
138
169
|
export function defineRouting<T>(config: T): T;
|
|
139
170
|
}
|
|
140
|
-
`),
|
|
171
|
+
`),l.writeFileSync(h.join(m,"mock-i18n-index.ts"),`
|
|
141
172
|
export * from './mock-i18n';
|
|
142
173
|
export { default } from './mock-i18n';
|
|
143
|
-
`);let
|
|
174
|
+
`);let M=h.join(i,"tsconfig.json");if(l.existsSync(M))try{let g=l.readFileSync(M,"utf8");if(g.includes('"paths": {')){let c=g.replace(/"paths":\s*\{/,`"paths": {
|
|
144
175
|
"next-intl": ["./src/lib/mock-i18n"],
|
|
145
|
-
"next-intl/*": ["./src/lib/mock-i18n"],`);
|
|
146
|
-
`)}}}}
|
|
147
|
-
`)}var
|
|
148
|
-
`)}function
|
|
149
|
-
`)+
|
|
150
|
-
`)),"fumadocs"}return"fumadocs"}function
|
|
151
|
-
`)),process.exit(130)}});
|
|
152
|
-
`)),process.exit(130)}}):{};
|
|
153
|
-
`+
|
|
154
|
-
`));for(let
|
|
155
|
-
`);process.stdout.write(
|
|
176
|
+
"next-intl/*": ["./src/lib/mock-i18n"],`);l.writeFileSync(M,c)}}catch{}let J=h.join(i,"src");l.existsSync(J)&&We(J,g=>{if(!g.endsWith(".ts")&&!g.endsWith(".tsx"))return;let c=l.readFileSync(g,"utf8"),b=!1;g.endsWith("src/app/layout.tsx")&&c.includes("../providers")&&(c=c.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),b=!0),c=c.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),c=c.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),c.match(/locale\s*:\s*any/)&&(c=c.replace(/locale\s*:\s*any/g,"locale: string"),b=!0),c.match(/lang\s*:\s*any/)&&(c=c.replace(/lang\s*:\s*any/g,"lang: string"),b=!0),c.match(/requestLocale\s*:\s*any/)&&(c=c.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),b=!0),c.match(/\(locale\s*=\s*(.*)\)/)&&(c=c.replace(/\(locale\s*=\s*(.*)\)/g,"() "),b=!0),c.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(c=c.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),b=!0),(g.endsWith("src/app/layout.tsx")||g.endsWith("src/app/sitemap.ts")||g.endsWith("src/app/robots.ts")||g.endsWith("src/components/ui/locale-switcher.tsx")||g.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(c=c.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),c=c.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),c=c.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),c=c.replace(/\(l\)\s*=>/g,"(l: any) =>"),b=!0),g.endsWith("src/i18n/request.ts")&&(c=c.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),b=!0),(c.match(/locale\s*:/)||c.match(/lang\s*:/))&&(b=!0),b&&l.writeFileSync(g,c)});let B=h.join(i,"package.json");if(l.existsSync(B)){let g=JSON.parse(l.readFileSync(B,"utf8"));g.dependencies&&delete g.dependencies["next-intl"],l.writeFileSync(B,JSON.stringify(g,null,2)+`
|
|
177
|
+
`)}}}}l.writeFileSync(n,JSON.stringify(s,null,2)+`
|
|
178
|
+
`)}var ze="create-sailor";function u(e,t){e&&process.stdout.write(JSON.stringify(t)+`
|
|
179
|
+
`)}function Bt(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function Ge(e){switch(e){case"postgres":case"postgresql":return"postgresql";case"mysql":return"mysql";case"sqlite":return"sqlite";case"none":return"none";default:return"postgresql"}}function Je(e){return e==="drizzle"?"drizzle":e==="none"?"none":"prisma"}function Xe(e){return e==="lemon"||e==="lemonsqueezy"?"lemonsqueezy":e==="none"?"none":"stripe"}function Ze(e){if(!e)return"stripe";let t=e.toLowerCase();return t==="lemon"||t==="lemonsqueezy"?"lemon":t==="wechat"?"wechat":t==="alipay"?"alipay":t==="none"?"none":"stripe"}function Qe(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="none"?"none":"clerk"}function et(e){if(!e)return["openai"];let t=e.split(",").map(n=>n.trim().toLowerCase());return t.includes("none")?[]:t}var tt={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function nt(e,t){if(!e)return"fumadocs";let n=e.toLowerCase();if(n==="fumadocs"||n==="none")return n;if(n in tt){let s=tt[n];return t?u(!0,{event:"notice",kind:"docs-fallback",requested:n,effective:"fumadocs"}):process.stdout.write(A.yellow(`\u26A0 ${s} support is coming in v1.2. Falling back to fumadocs.
|
|
180
|
+
`)+A.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
|
|
181
|
+
`)),"fumadocs"}return"fumadocs"}function st(e){switch(e){case"vercel":return"vercel";case"railway":return"railway";case"cloudflare":return"cloudflare";case"selfhost":return"selfhost";case"none":return"none";default:return"vercel"}}async function Wt(){let e=new Kt;e.name(ze).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(U,"-v, --version").helpOption(!1).argument("[name]","project directory",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--orm <id>","prisma | drizzle | none").option("--db <id>","postgres | mysql | sqlite | none").option("--auth <id>","clerk | betterauth | none").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <ids>","comma-separated provider ids").option("--deploy <target>","vercel | railway | cloudflare | selfhost").option("--docs <id>","fumadocs | mintlify | docusaurus | nextra | vitepress | none").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--no-install","skip package install").option("--no-git","skip git init").option("-y, --yes","accept all defaults (non-interactive)").option("--dry-run","preview actions without writing files").option("--json","machine-readable output").option("--no-color","disable color output").option("-h, --help","show help"),e.parse(process.argv);let t=e.opts(),[n]=e.args;t.help&&(Ee(),process.exit(0));let s=!!t.json,r=!!t.dryRun,a=!!t.yes,p=a||!process.stdin.isTTY;s||ve(),u(s,{event:"start",version:U});let i=n??(a?"./my-saas-app":void 0),o;if(i)o=i;else if(p)o="./my-saas-app";else{let d=await v.group({name:()=>v.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:y=>{if(y.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(A.red(`\u2718 Cancelled
|
|
182
|
+
`)),process.exit(130)}});o=String(d.name)}let m=ye.basename(ye.resolve(o)),f=t.pm??Bt(),E=!!t.orm,K=!!t.db,M=!!t.auth,J=!!t.payment,B=!!t.ai,g=!!t.deploy,c=!!t.docs,b=t.i18n!==void 0,L,R,pe,T,N,D,W,O,w,ee;if(p)L=Je(t.orm),R=Ge(t.db),pe=Xe(t.payment),T=Ze(t.payment),N=Qe(t.auth),D=et(t.ai),O=st(t.deploy),w=nt(t.docs,s),ee=b?!!t.i18n:!0;else{let d={};if(E||(d.orm=()=>v.select({message:"Which ORM?",options:[{value:"prisma",label:"Prisma"},{value:"drizzle",label:"Drizzle"},{value:"none",label:"None"}],initialValue:"prisma"})),K||(d.database=()=>v.select({message:"Database?",options:[{value:"postgresql",label:"PostgreSQL"},{value:"mysql",label:"MySQL"},{value:"sqlite",label:"SQLite"},{value:"none",label:"None"}],initialValue:"postgresql"})),M||(d.auth=()=>v.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk"},{value:"betterauth",label:"Better Auth"},{value:"none",label:"None"}],initialValue:"clerk"})),J||(d.payment=()=>v.select({message:"Payment?",options:[{value:"stripe",label:"Stripe"},{value:"lemon",label:"Lemon Squeezy"},{value:"wechat",label:"WeChat Pay"},{value:"alipay",label:"Alipay"},{value:"none",label:"None"}],initialValue:"stripe"})),!B){let se=Array.from(new Set(ie.map(P=>P.category)));d.aiCategories=()=>v.multiselect({message:"Which AI Provider categories do you want to explore? (Select multiple)",options:se.map(P=>({value:P,label:P})),initialValues:["\u76F4\u63A5\u5B9E\u9A8C\u5BA4","\u7EDF\u4E00\u7F51\u5173"]}),d.aiProviders=({results:P})=>{let I=P.aiCategories||[],re=ie.filter(X=>I.includes(X.category)).map(X=>({value:X.id,label:`[${X.category}] ${X.name}`}));return re.push({value:"custom",label:"[\u81EA\u5B9A\u4E49] Custom OpenAI-compatible endpoint"}),v.multiselect({message:"Select AI Providers (Space to select, Enter to submit)",options:re,initialValues:["openai","anthropic"],required:!1})},d.enableCustom=({results:P})=>P.aiProviders?.includes("custom")?v.confirm({message:"Configure custom OpenAI-compatible endpoint?",initialValue:!0}):Promise.resolve(!1),d.customAiName=({results:P})=>P.enableCustom?v.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),d.customAiBaseUrl=({results:P})=>P.enableCustom?v.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:I=>{if(I.length===0)return"Base URL is required."}}):Promise.resolve(void 0),d.customAiApiKeyEnv=({results:P})=>P.enableCustom?v.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0)}g||(d.deployTarget=()=>v.select({message:"Where will you deploy?",options:[{value:"vercel",label:"Vercel"},{value:"railway",label:"Railway"},{value:"cloudflare",label:"Cloudflare Workers"},{value:"selfhost",label:"Self-host / Docker"},{value:"none",label:"None for now"}],initialValue:"vercel"})),c||(d.docs=()=>v.select({message:"What documentation framework? (affects `apps/docs`)",options:[{value:"fumadocs",label:"Fumadocs \u2014 Next.js monorepo native (Recommended)"},{value:"mintlify",label:"Mintlify \u2014 managed docs SaaS (Coming in v1.2)"},{value:"docusaurus",label:"Docusaurus \u2014 Meta's framework (Coming in v1.2)"},{value:"nextra",label:"Nextra \u2014 Next.js minimal (Coming in v1.2)"},{value:"vitepress",label:"VitePress \u2014 Vue ecosystem, separate repo (Experimental)"},{value:"none",label:"None \u2014 skip docs"}],initialValue:"fumadocs"})),b||(d.i18n=()=>v.confirm({message:"Enable i18n?",initialValue:!0}));let y=Object.keys(d).length>0?await v.group(d,{onCancel:()=>{process.stdout.write(A.red(`\u2718 Cancelled
|
|
183
|
+
`)),process.exit(130)}}):{};L=E?Je(t.orm):y.orm,R=K?Ge(t.db):y.database;let k=J?t.payment:y.payment;pe=Xe(k),T=Ze(k),N=Qe(M?t.auth:y.auth),D=B?et(t.ai):y.aiProviders?.filter(se=>se!=="custom")??[],y.enableCustom&&(W={name:y.customAiName,baseURL:y.customAiBaseUrl,apiKeyEnvName:y.customAiApiKeyEnv}),O=g?st(t.deploy):y.deployTarget,w=nt(c?t.docs:y.docs,s),ee=b?!!t.i18n:!!y.i18n}let te={orm:L,database:R,payment:pe,aiProviders:D,customAiEndpoint:W,deployTarget:O,docs:w,i18n:ee},ne=[["Project name",m],["Auth",N],["ORM",L],["Database",R],["Payment",T],["AI",Array.isArray(D)?D.join(", ")+(W?", custom":""):String(D)],["Deploy Target",O],["Docs Framework",w]];s?ne.forEach(([d,y],k)=>{u(!0,{event:"step",step:d,value:y,index:k+1,total:ne.length})}):ne.forEach(([d,y],k)=>{be({index:k+1,total:ne.length,label:d,value:y})});let rt={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},ot=Date.now();if(r){let d=D.length,y=[`clone template \u2192 ${o}`,"write nebutra.config.json",`prune template (orm=${L}, i18n=${ee})`,`auth \u2192 ${N==="none"?"skip (remove packages/auth)":`configure ${N}`}`,`db \u2192 ${R==="none"?"skip (remove packages/db)":`configure Prisma for ${R}`}`,`payment \u2192 ${T==="none"?"skip (remove packages/billing)":`configure ${T}`}`,...w!=="none"?[`docs \u2192 scaffold apps/docs (${w==="fumadocs"?"fumadocs":`${w} \u2192 fumadocs fallback`})`]:[],...d>0||W?[`ai-providers \u2192 generate registry.ts + env (${d}${W?" + custom":""} provider${d===1&&!W?"":"s"})`]:[],...O!=="none"?[`deploy \u2192 inject ${O} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${f} install`,t.git===!1?"skip git init":"run git init"];if(s)y.forEach(k=>u(!0,{event:"plan",action:k})),u(!0,{event:"done",dryRun:!0});else{process.stdout.write(`
|
|
184
|
+
`+A.bold(`Dry run \u2014 planned actions:
|
|
185
|
+
`));for(let k of y)process.stdout.write(` \u2022 ${k}
|
|
186
|
+
`);process.stdout.write(A.dim(`
|
|
156
187
|
No files were written.
|
|
157
|
-
`))}process.exit(0)}let
|
|
158
|
-
`+
|
|
159
|
-
`));try{
|
|
160
|
-
`))}catch{}process.exit(130)};process.on("SIGINT",
|
|
161
|
-
|
|
162
|
-
`)),
|
|
188
|
+
`))}process.exit(0)}let it=()=>{process.stdout.write(`
|
|
189
|
+
`+A.red(`\u2718 Cancelled
|
|
190
|
+
`));try{Yt.existsSync(o)&&process.stdout.write(A.dim(` Partial directory left at ${o} \u2014 remove manually if needed.
|
|
191
|
+
`))}catch{}process.exit(130)};process.on("SIGINT",it);try{u(s,{event:"step",step:"clone",status:"start"}),await qe(o),u(s,{event:"step",step:"clone",status:"ok"}),u(s,{event:"step",step:"package",status:"start"}),await Fe(o,m),u(s,{event:"step",step:"package",status:"ok"}),u(s,{event:"step",step:"config",status:"start"}),await we(o,te),u(s,{event:"step",step:"config",status:"ok"}),u(s,{event:"step",step:"prune",status:"start"}),await He(o,te),u(s,{event:"step",step:"prune",status:"ok"}),u(s,{event:"step",step:"auth",choice:N,status:"start"}),await Ae(o,N),u(s,{event:"step",step:"auth",choice:N,status:"ok"}),u(s,{event:"step",step:"db",choice:R,status:"start"}),await _e(o,R,m),u(s,{event:"step",step:"db",choice:R,status:"ok"}),u(s,{event:"step",step:"payment",choice:T,status:"start"}),await Ue(o,T),u(s,{event:"step",step:"payment",choice:T,status:"ok"}),u(s,{event:"step",step:"ai-providers",status:"start"});let d={providerIds:te.aiProviders,customEndpoint:te.customAiEndpoint},y=ye.join(o,"packages/ai-providers/templates");if(await Be(o,d,y),u(s,{event:"step",step:"ai-providers",status:"ok"}),u(s,{event:"step",step:"docs",status:"start"}),w!=="none"?(await Le(o,{framework:w,projectName:m}),u(s,{event:"step",step:"docs",framework:"fumadocs",requested:w,status:"ok"})):u(s,{event:"step",step:"docs",status:"skip"}),u(s,{event:"step",step:"deploy-target",status:"start"}),O!=="none"&&await Re(o,O),u(s,{event:"step",step:"deploy-target",status:"ok"}),u(s,{event:"step",step:"env",status:"start"}),await Ve(o,rt),u(s,{event:"step",step:"env",status:"ok"}),t.install!==!1){let I=f==="bun"?"bun install":`${f} install`;s?u(!0,{event:"step",step:"install",pm:f,status:"start"}):process.stdout.write(A.dim(` Installing dependencies with ${f}\u2026
|
|
192
|
+
`));try{ce(I,{cwd:o,stdio:s?"ignore":"inherit"}),u(s,{event:"step",step:"install",status:"ok"})}catch(H){let re=H instanceof Error?H.message:String(H);s?u(!0,{event:"step",step:"install",status:"error",error:re}):process.stdout.write(A.yellow(` \u26A0 install failed \u2014 run '${I}' manually.
|
|
193
|
+
`))}}else u(s,{event:"step",step:"install",status:"skip"});if(t.git!==!1){s&&u(!0,{event:"step",step:"git-init",status:"start"});try{ce("git init -q",{cwd:o,stdio:"ignore"}),ce("git add -A",{cwd:o,stdio:"ignore"}),ce('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:o,stdio:"ignore"}),u(s,{event:"step",step:"git-init",status:"ok"})}catch(I){let H=I instanceof Error?I.message:String(I);s?u(!0,{event:"step",step:"git-init",status:"error",error:H}):process.stdout.write(A.yellow(` \u26A0 git init skipped \u2014 not fatal.
|
|
194
|
+
`))}}else u(s,{event:"step",step:"git-init",status:"skip"});let P=Math.max(1,Math.round((Date.now()-ot)/1e3));s?u(!0,{event:"done",status:"ok",elapsedSec:P,targetDir:o}):he({elapsedSec:P,targetDir:o,skippedInstall:t.install===!1});try{Mt({pkg:{name:ze,version:U},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(d){let y=d instanceof Error?d.message:String(d);s?u(!0,{event:"error",message:y}):process.stdout.write(A.red(`
|
|
195
|
+
\u2718 Failed: ${y}
|
|
196
|
+
`)),process.exit(1)}}Wt().catch(e=>{process.stderr.write(String(e)+`
|
|
163
197
|
`),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-sailor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "AI-Native SaaS unicorn template. Bootstrap a production-ready Next.js + Hono + Prisma monorepo with Multi-Agent, white-labeling, billing, auth, and 50+ engineering primitives in seconds.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@types/node": "^20.0.0",
|
|
32
32
|
"@types/update-notifier": "^6.0.8",
|
|
33
33
|
"tsup": "^8.0.0",
|
|
34
|
-
"typescript": "
|
|
34
|
+
"typescript": "catalog:"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=18.17.0"
|