create-sailor 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +195 -171
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import{execSync as Je}from"child_process";import un from"fs";import pt from"path";import*as I from"@clack/prompts";import{Command as ts}from"commander";import T from"picocolors";import ns from"update-notifier";import xn from"cfonts";import Rn from"picocolors";import dt from"fs";import Ze from"path";import{fileURLToPath as Nn}from"url";function Tn(){try{let t=Ze.dirname(Nn(import.meta.url));for(let n=0;n<4;n++){let r=Ze.join(t,"package.json");if(dt.existsSync(r)){let o=dt.readFileSync(r,"utf-8"),s=JSON.parse(o);if(s.name==="create-sailor"&&typeof s.version=="string")return s.version}t=Ze.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var J=Tn();function ut(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${J}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
3
- `));return}xn.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(Rn.dim(` AI-Native SaaS Template \xB7 v${J} \xB7 nebutra.com
2
+ import{execSync as At}from"child_process";import go from"fs";import Yt from"path";import*as P from"@clack/prompts";import{Command as pi}from"commander";import x from"picocolors";import li from"update-notifier";import ko from"cfonts";import Oo from"picocolors";import $t from"fs";import Rt from"path";import{fileURLToPath as xo}from"url";function To(){try{let t=Rt.dirname(xo(import.meta.url));for(let o=0;o<4;o++){let n=Rt.join(t,"package.json");if($t.existsSync(n)){let r=$t.readFileSync(n,"utf-8"),s=JSON.parse(r);if(s.name==="create-sailor"&&typeof s.version=="string")return s.version}t=Rt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var se=To();function qt(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${se}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
3
+ `));return}ko.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(Oo.dim(` AI-Native SaaS Template \xB7 v${se} \xB7 nebutra.com
4
4
 
5
- `))}import M from"picocolors";function kn(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function mt(e){let t=kn(),n=t?"\u2693":"-",r=t?"\u25B8":"->",o=t?"\u2605":"*",s=t?"\u{1F4E7}":"*",c=["",` ${t?M.bold(`${n} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${n} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?M.bold("Next:"):"Next:"}`,` ${r} cd ${e.targetDir}`];e.skippedInstall&&c.push(` ${r} pnpm install (if --no-install was set)`),c.push(` ${r} pnpm dev ${t?M.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?M.bold("Customize:"):"Customize:"}`,` ${r} pnpm sailor brand init ${t?M.dim("\u2192 your colors, logo, domain"):"-> your colors, logo, domain"}`,` ${r} pnpm sailor preset apply ${t?M.dim("\u2192 toggle features"):"-> toggle features"}`,` ${r} pnpm sailor add <feat> ${t?M.dim("\u2192 add queue/search/cache/..."):"-> add queue/search/cache/..."}`,"",` ${t?M.bold("Add more features later:"):"Add more features later:"}`,` ${r} sailor add payment --provider=wechat`,` ${r} sailor add email --provider=postmark`,` ${r} sailor add storage --provider=supabase`,` ${t?M.dim("(more providers: `sailor add --list`)"):"(more providers: `sailor add --list`)"}`,"",` ${t?M.bold("Ship faster:"):"Ship faster:"}`,` ${o} Star us https://github.com/nebutra/nebutra-sailor`,` ${s} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
5
+ `))}import j from"picocolors";function Uo(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Gt(e){let t=Uo(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",s=t?"\u{1F4E7}":"*",c=["",` ${t?j.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?j.bold("Next:"):"Next:"}`,` ${n} cd ${e.targetDir}`];e.skippedInstall&&c.push(` ${n} pnpm install (if --no-install was set)`),c.push(` ${n} pnpm dev ${t?j.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?j.bold("Customize:"):"Customize:"}`,` ${n} pnpm sailor brand init ${t?j.dim("\u2192 your colors, logo, domain"):"-> your colors, logo, domain"}`,` ${n} pnpm sailor preset apply ${t?j.dim("\u2192 toggle features"):"-> toggle features"}`,` ${n} pnpm sailor add <feat> ${t?j.dim("\u2192 add queue/search/cache/..."):"-> add queue/search/cache/..."}`,"",` ${t?j.bold("Add more features later:"):"Add more features later:"}`,` ${n} sailor add payment --provider=wechat`,` ${n} sailor add email --provider=postmark`,` ${n} sailor add storage --provider=supabase`,` ${t?j.dim("(more providers: `sailor add --list`)"):"(more providers: `sailor add --list`)"}`,"",` ${t?j.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${s} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
6
6
  `)+`
7
- `)}var On=`Usage: create-sailor [name] [options]
7
+ `)}var Lo=`Usage: create-sailor [name] [options]
8
8
 
9
9
  Arguments:
10
10
  name project directory (default: ./my-saas-app)
@@ -28,6 +28,18 @@ Feature flags (region-based smart defaults):
28
28
  --monitoring <id> sentry | datadog | aliyun-arms | tingyun | none
29
29
  --analytics <id> posthog | plausible | umami | baidu | sensors | none
30
30
  --sms <id> twilio | aliyun-sms | tencent-sms | yunpian | none
31
+ --queue <id> qstash | bullmq | upstash | sqs | none
32
+ --search <id> meilisearch | typesense | algolia | pgvector | none
33
+ --cache <id> upstash-redis | vercel-kv | redis | dragonfly | none
34
+ --notifications <id> novu | knock | custom | none
35
+ --webhooks <id> svix | custom | none
36
+ --cms <id> sanity | contentful | strapi | none
37
+ --feature-flags <id> vercel-flags | growthbook | configcat | none
38
+ --captcha <id> turnstile | hcaptcha | aliyun-slide | none
39
+
40
+ Sailor features:
41
+ --mcp <mode> on | off (default: on \u2014 Agent-friendly MCP server)
42
+ --metering <mode> auto | on | off (default: auto)
31
43
 
32
44
  Toggles:
33
45
  --i18n enable i18n (default: true)
@@ -47,9 +59,9 @@ Examples:
47
59
  $ npm create sailor@latest my-app --region=cn --auth=clerk
48
60
  $ npm create sailor@latest my-app --region=hybrid --ai=openai,deepseek
49
61
  $ npm create sailor@latest --dry-run --region=cn
50
- `;function gt(){process.stdout.write(On)}import qe from"picocolors";function ft(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Un(e){let t=ft()?"\u25B8":"->",n=`[${e.index}/${e.total}]`,r=e.label.padEnd(18," ");return ft()?`${qe.dim(n)} ${qe.bold(r)} ${qe.dim(t)} ${qe.cyan(e.value)}`:`${n} ${r} ${t} ${e.value}`}function yt(e){process.stdout.write(Un(e)+`
51
- `)}var Ge=[{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:[]}],hs=Ge.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});import Ie from"fs";import A from"path";var St=[{id:"posthog",name:"PostHog",region:"both",envVars:["POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_HOST"],docs:"https://posthog.com/docs",pkgs:["posthog-js","posthog-node"],providerFile:"apps/web/src/lib/analytics/posthog.client.ts"},{id:"plausible",name:"Plausible",region:"global",envVars:["NEXT_PUBLIC_PLAUSIBLE_DOMAIN","NEXT_PUBLIC_PLAUSIBLE_SRC"],docs:"https://plausible.io/docs",providerFile:"apps/web/src/components/analytics/PlausibleScript.tsx"},{id:"umami",name:"Umami",region:"both",envVars:["NEXT_PUBLIC_UMAMI_WEBSITE_ID","NEXT_PUBLIC_UMAMI_SRC"],docs:"https://umami.is/docs",providerFile:"apps/web/src/components/analytics/UmamiScript.tsx"},{id:"mixpanel",name:"Mixpanel",region:"global",envVars:["MIXPANEL_TOKEN","NEXT_PUBLIC_MIXPANEL_TOKEN"],docs:"https://docs.mixpanel.com",pkgs:["mixpanel-browser","mixpanel"],providerFile:"apps/web/src/lib/analytics/mixpanel.client.ts"},{id:"baidu",name:"\u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji",region:"cn",envVars:["NEXT_PUBLIC_BAIDU_STATS_ID"],docs:"https://tongji.baidu.com",providerFile:"apps/web/src/components/analytics/BaiduStatsScript.tsx"},{id:"sensors",name:"\u795E\u7B56 Sensors Analytics",region:"cn",envVars:["NEXT_PUBLIC_SENSORS_SERVER_URL","NEXT_PUBLIC_SENSORS_APP_JS_URL"],docs:"https://manual.sensorsdata.cn",pkgs:["sa-sdk-javascript"],providerFile:"apps/web/src/lib/analytics/sensors.client.ts"},{id:"growingio",name:"GrowingIO",region:"cn",envVars:["NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID"],docs:"https://growingio.com/docs",providerFile:"apps/web/src/components/analytics/GrowingIoScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],vs=St.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Et(e){return St.find(t=>t.id===e)}function Ln(e){Ie.mkdirSync(e,{recursive:!0})}function j(e,t){Ln(A.dirname(e)),Ie.writeFileSync(e,t)}function Q(e,t){let n=A.join(e,".env.example");Ie.existsSync(n)?Ie.appendFileSync(n,`
52
- `+t):Ie.writeFileSync(n,t)}function Mn(e){let t=`"use client";
62
+ `;function Ht(){process.stdout.write(Lo)}import dt from"picocolors";function Wt(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Mo(e){let t=Wt()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return Wt()?`${dt.dim(o)} ${dt.bold(n)} ${dt.dim(t)} ${dt.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function Xt(e){process.stdout.write(Mo(e)+`
63
+ `)}var ut=[{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:[]}],Ri=ut.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});import Te from"fs";import A from"path";var zt=[{id:"posthog",name:"PostHog",region:"both",envVars:["POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_HOST"],docs:"https://posthog.com/docs",pkgs:["posthog-js","posthog-node"],providerFile:"apps/web/src/lib/analytics/posthog.client.ts"},{id:"plausible",name:"Plausible",region:"global",envVars:["NEXT_PUBLIC_PLAUSIBLE_DOMAIN","NEXT_PUBLIC_PLAUSIBLE_SRC"],docs:"https://plausible.io/docs",providerFile:"apps/web/src/components/analytics/PlausibleScript.tsx"},{id:"umami",name:"Umami",region:"both",envVars:["NEXT_PUBLIC_UMAMI_WEBSITE_ID","NEXT_PUBLIC_UMAMI_SRC"],docs:"https://umami.is/docs",providerFile:"apps/web/src/components/analytics/UmamiScript.tsx"},{id:"mixpanel",name:"Mixpanel",region:"global",envVars:["MIXPANEL_TOKEN","NEXT_PUBLIC_MIXPANEL_TOKEN"],docs:"https://docs.mixpanel.com",pkgs:["mixpanel-browser","mixpanel"],providerFile:"apps/web/src/lib/analytics/mixpanel.client.ts"},{id:"baidu",name:"\u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji",region:"cn",envVars:["NEXT_PUBLIC_BAIDU_STATS_ID"],docs:"https://tongji.baidu.com",providerFile:"apps/web/src/components/analytics/BaiduStatsScript.tsx"},{id:"sensors",name:"\u795E\u7B56 Sensors Analytics",region:"cn",envVars:["NEXT_PUBLIC_SENSORS_SERVER_URL","NEXT_PUBLIC_SENSORS_APP_JS_URL"],docs:"https://manual.sensorsdata.cn",pkgs:["sa-sdk-javascript"],providerFile:"apps/web/src/lib/analytics/sensors.client.ts"},{id:"growingio",name:"GrowingIO",region:"cn",envVars:["NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID"],docs:"https://growingio.com/docs",providerFile:"apps/web/src/components/analytics/GrowingIoScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],Ni=zt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Qt(e){return zt.find(t=>t.id===e)}function Do(e){Te.mkdirSync(e,{recursive:!0})}function F(e,t){Do(A.dirname(e)),Te.writeFileSync(e,t)}function ie(e,t){let o=A.join(e,".env.example");Te.existsSync(o)?Te.appendFileSync(o,`
64
+ `+t):Te.writeFileSync(o,t)}function jo(e){let t=`"use client";
53
65
  /**
54
66
  * PostHog browser SDK \u2014 lazy-initialized on first access.
55
67
  */
@@ -74,7 +86,7 @@ export function initPostHog(): void {
74
86
  }
75
87
 
76
88
  export { posthog };
77
- `,n=`import { PostHog } from "posthog-node";
89
+ `,o=`import { PostHog } from "posthog-node";
78
90
 
79
91
  /**
80
92
  * PostHog server-side client. Remember to await client.shutdown() at the end
@@ -105,7 +117,7 @@ export async function captureServerEvent(
105
117
  ph.capture({ distinctId, event, properties });
106
118
  await ph.shutdown();
107
119
  }
108
- `,r=`"use client";
120
+ `,n=`"use client";
109
121
  /**
110
122
  * <AnalyticsProvider /> \u2014 wrap the app root to enable PostHog + auto page views.
111
123
  */
@@ -132,11 +144,11 @@ export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
132
144
 
133
145
  return <>{children}</>;
134
146
  }
135
- `;j(A.join(e,"src","lib","analytics","posthog.client.ts"),t),j(A.join(e,"src","lib","analytics","posthog.server.ts"),n),j(A.join(e,"src","components","analytics","AnalyticsProvider.tsx"),r)}function jn(){return`# PostHog \u2014 product analytics
147
+ `;F(A.join(e,"src","lib","analytics","posthog.client.ts"),t),F(A.join(e,"src","lib","analytics","posthog.server.ts"),o),F(A.join(e,"src","components","analytics","AnalyticsProvider.tsx"),n)}function Fo(){return`# PostHog \u2014 product analytics
136
148
  POSTHOG_KEY=
137
149
  NEXT_PUBLIC_POSTHOG_KEY=
138
150
  NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
139
- `}function Dn(e){j(A.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
151
+ `}function Vo(e){F(A.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
140
152
  /**
141
153
  * Plausible script tag \u2014 lightweight, privacy-friendly analytics.
142
154
  */
@@ -156,10 +168,10 @@ export function PlausibleScript() {
156
168
  />
157
169
  );
158
170
  }
159
- `)}function Fn(){return`# Plausible \u2014 privacy-friendly analytics
171
+ `)}function Ko(){return`# Plausible \u2014 privacy-friendly analytics
160
172
  NEXT_PUBLIC_PLAUSIBLE_DOMAIN=
161
173
  NEXT_PUBLIC_PLAUSIBLE_SRC=https://plausible.io/js/script.js
162
- `}function Bn(e){j(A.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
174
+ `}function Yo(e){F(A.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
163
175
  /**
164
176
  * Umami analytics \u2014 self-hosted OR umami.is cloud.
165
177
  */
@@ -179,10 +191,10 @@ export function UmamiScript() {
179
191
  />
180
192
  );
181
193
  }
182
- `)}function Yn(){return`# Umami \u2014 self-hostable analytics
194
+ `)}function Bo(){return`# Umami \u2014 self-hostable analytics
183
195
  NEXT_PUBLIC_UMAMI_WEBSITE_ID=
184
196
  NEXT_PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
185
- `}function Kn(e){let t=`"use client";
197
+ `}function $o(e){let t=`"use client";
186
198
  import mixpanel from "mixpanel-browser";
187
199
 
188
200
  let initialized = false;
@@ -200,7 +212,7 @@ export function initMixpanel(): void {
200
212
  }
201
213
 
202
214
  export { mixpanel };
203
- `,n=`import Mixpanel from "mixpanel";
215
+ `,o=`import Mixpanel from "mixpanel";
204
216
 
205
217
  let client: Mixpanel.Mixpanel | null = null;
206
218
 
@@ -221,10 +233,10 @@ export function trackServer(
221
233
  if (!c) return;
222
234
  c.track(event, { distinct_id: distinctId, ...properties });
223
235
  }
224
- `;j(A.join(e,"src","lib","analytics","mixpanel.client.ts"),t),j(A.join(e,"src","lib","analytics","mixpanel.server.ts"),n)}function Vn(){return`# Mixpanel \u2014 product analytics
236
+ `;F(A.join(e,"src","lib","analytics","mixpanel.client.ts"),t),F(A.join(e,"src","lib","analytics","mixpanel.server.ts"),o)}function qo(){return`# Mixpanel \u2014 product analytics
225
237
  MIXPANEL_TOKEN=
226
238
  NEXT_PUBLIC_MIXPANEL_TOKEN=
227
- `}function $n(e){j(A.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
239
+ `}function Go(e){F(A.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
228
240
  /**
229
241
  * \u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji \u2014 hm.js \u57CB\u70B9\u811A\u672C.
230
242
  */
@@ -250,9 +262,9 @@ var _hmt = _hmt || [];
250
262
  />
251
263
  );
252
264
  }
253
- `)}function qn(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
265
+ `)}function Ho(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
254
266
  NEXT_PUBLIC_BAIDU_STATS_ID=
255
- `}function Gn(e){j(A.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
267
+ `}function Wo(e){F(A.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
256
268
  /**
257
269
  * \u795E\u7B56\u5206\u6790 (Sensors Analytics) \u2014 sa-sdk-javascript \u5C01\u88C5.
258
270
  */
@@ -280,10 +292,10 @@ export function initSensors(): void {
280
292
  }
281
293
 
282
294
  export { sensors };
283
- `)}function Wn(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
295
+ `)}function Xo(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
284
296
  NEXT_PUBLIC_SENSORS_SERVER_URL=
285
297
  NEXT_PUBLIC_SENSORS_APP_JS_URL=
286
- `}function Xn(e){j(A.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
298
+ `}function zo(e){F(A.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
287
299
  /**
288
300
  * GrowingIO CDP \u2014 inline snippet installer.
289
301
  */
@@ -308,24 +320,24 @@ gdp("send");
308
320
  />
309
321
  );
310
322
  }
311
- `)}function Hn(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
323
+ `)}function Qo(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
312
324
  NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
313
- `}async function ht(e,t,n="global"){let r=Et(t);if(!r||r.id==="none")return;let o=A.join(e,"apps","web");if(!Ie.existsSync(o))return;let s=r.id;try{switch(s){case"posthog":Mn(o),Q(e,jn());return;case"plausible":Dn(o),Q(e,Fn());return;case"umami":Bn(o),Q(e,Yn());return;case"mixpanel":Kn(o),Q(e,Vn());return;case"baidu":$n(o),Q(e,qn());return;case"sensors":Gn(o),Q(e,Wn());return;case"growingio":Xn(o),Q(e,Hn());return;default:return}}catch(a){throw console.error(`Failed to apply analytics selection "${t}":`,a),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}import w from"fs";import Z from"path";function et(e){w.existsSync(e)&&w.rmSync(e,{recursive:!0,force:!0})}function _t(e,t){let n=Z.join(e,".env.example");w.existsSync(n)?w.appendFileSync(n,`
314
- `+t):w.writeFileSync(n,t)}function vt(e,t){if(!w.existsSync(e))return;let n=w.readFileSync(e,"utf8"),r=n.replace(/export type AuthProviderId\s*=\s*"[^"]+"\s*\|\s*"[^"]+";/,`export type AuthProviderId = "${t}";`);r!==n&&w.writeFileSync(e,r)}function zn(e,t){let n=Z.join(e,"README.md");if(!w.existsSync(n)){w.writeFileSync(n,t);return}w.appendFileSync(n,`
315
- `+t)}async function It(e,t){let n=Z.join(e,"packages","auth");if(!w.existsSync(n))return;if(t==="none"){et(n),zn(e,`
325
+ `}async function Jt(e,t,o="global"){let n=Qt(t);if(!n||n.id==="none")return;let r=A.join(e,"apps","web");if(!Te.existsSync(r))return;let s=n.id;try{switch(s){case"posthog":jo(r),ie(e,Fo());return;case"plausible":Vo(r),ie(e,Ko());return;case"umami":Yo(r),ie(e,Bo());return;case"mixpanel":$o(r),ie(e,qo());return;case"baidu":Go(r),ie(e,Ho());return;case"sensors":Wo(r),ie(e,Xo());return;case"growingio":zo(r),ie(e,Qo());return;default:return}}catch(a){throw console.error(`Failed to apply analytics selection "${t}":`,a),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}import w from"fs";import ae from"path";function wt(e){w.existsSync(e)&&w.rmSync(e,{recursive:!0,force:!0})}function Zt(e,t){let o=ae.join(e,".env.example");w.existsSync(o)?w.appendFileSync(o,`
326
+ `+t):w.writeFileSync(o,t)}function en(e,t){if(!w.existsSync(e))return;let o=w.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*"[^"]+"\s*\|\s*"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&w.writeFileSync(e,n)}function Jo(e,t){let o=ae.join(e,"README.md");if(!w.existsSync(o)){w.writeFileSync(o,t);return}w.appendFileSync(o,`
327
+ `+t)}async function tn(e,t){let o=ae.join(e,"packages","auth");if(!w.existsSync(o))return;if(t==="none"){wt(o),Jo(e,`
316
328
  ## Auth
317
329
 
318
330
  Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth).
319
- `);return}let r=Z.join(n,"src","providers"),o=Z.join(n,"src","types.ts");if(t==="clerk"){et(Z.join(r,"better-auth.ts")),vt(o,"clerk"),_t(e,`# Clerk auth
331
+ `);return}let n=ae.join(o,"src","providers"),r=ae.join(o,"src","types.ts");if(t==="clerk"){wt(ae.join(n,"better-auth.ts")),en(r,"clerk"),Zt(e,`# Clerk auth
320
332
  CLERK_PUBLISHABLE_KEY=
321
333
  CLERK_SECRET_KEY=
322
- `);return}if(t==="betterauth"){et(Z.join(r,"clerk.ts")),vt(o,"better-auth"),_t(e,`# Better Auth
334
+ `);return}if(t==="betterauth"){wt(ae.join(n,"clerk.ts")),en(r,"better-auth"),Zt(e,`# Better Auth
323
335
  BETTER_AUTH_SECRET=
324
336
  BETTER_AUTH_URL=http://localhost:3000
325
- `);return}}var Re=[{id:"wechat",name:"\u5FAE\u4FE1\u5F00\u653E\u5E73\u53F0",region:"cn",envVars:["WECHAT_APP_ID","WECHAT_APP_SECRET"],docs:"https://open.weixin.qq.com/cgi-bin/showdocument",callbackUrl:"/api/auth/callback/wechat",tokenEndpoint:"https://api.weixin.qq.com/sns/oauth2/access_token"},{id:"qq",name:"QQ \u767B\u5F55",region:"cn",envVars:["QQ_APP_ID","QQ_APP_KEY"],docs:"https://wiki.connect.qq.com",callbackUrl:"/api/auth/callback/qq",tokenEndpoint:"https://graph.qq.com/oauth2.0/token"},{id:"dingtalk",name:"\u9489\u9489",region:"cn",envVars:["DINGTALK_APP_ID","DINGTALK_APP_SECRET"],docs:"https://open.dingtalk.com/document/",callbackUrl:"/api/auth/callback/dingtalk",tokenEndpoint:"https://api.dingtalk.com/v1.0/oauth2/userAccessToken"},{id:"workweixin",name:"\u4F01\u4E1A\u5FAE\u4FE1",region:"cn",envVars:["WORKWEIXIN_CORP_ID","WORKWEIXIN_AGENT_ID","WORKWEIXIN_SECRET"],docs:"https://developer.work.weixin.qq.com",callbackUrl:"/api/auth/callback/workweixin",tokenEndpoint:"https://qyapi.weixin.qq.com/cgi-bin/gettoken"},{id:"feishu",name:"\u98DE\u4E66 / Lark",region:"cn",envVars:["FEISHU_APP_ID","FEISHU_APP_SECRET"],docs:"https://open.feishu.cn/document/",callbackUrl:"/api/auth/callback/feishu",tokenEndpoint:"https://open.feishu.cn/open-apis/authen/v1/access_token"},{id:"weibo",name:"\u5FAE\u535A",region:"cn",envVars:["WEIBO_APP_KEY","WEIBO_APP_SECRET"],docs:"https://open.weibo.com/wiki/",callbackUrl:"/api/auth/callback/weibo",tokenEndpoint:"https://api.weibo.com/oauth2/access_token"}],Jn=new Set(Re.map(e=>e.id));function Pt(e){return Re.find(t=>t.id===e)}function bt(e){if(!e)return[];let t=e.split(",").map(o=>o.trim().toLowerCase()).filter(Boolean);if(t.includes("none"))return[];let n=[],r=new Set;for(let o of t)Jn.has(o)&&!r.has(o)&&(n.push(o),r.add(o));return n}import te from"fs";import ee from"path";function Qn(e,t){let n=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
337
+ `);return}}var Xe=[{id:"wechat",name:"\u5FAE\u4FE1\u5F00\u653E\u5E73\u53F0",region:"cn",envVars:["WECHAT_APP_ID","WECHAT_APP_SECRET"],docs:"https://open.weixin.qq.com/cgi-bin/showdocument",callbackUrl:"/api/auth/callback/wechat",tokenEndpoint:"https://api.weixin.qq.com/sns/oauth2/access_token"},{id:"qq",name:"QQ \u767B\u5F55",region:"cn",envVars:["QQ_APP_ID","QQ_APP_KEY"],docs:"https://wiki.connect.qq.com",callbackUrl:"/api/auth/callback/qq",tokenEndpoint:"https://graph.qq.com/oauth2.0/token"},{id:"dingtalk",name:"\u9489\u9489",region:"cn",envVars:["DINGTALK_APP_ID","DINGTALK_APP_SECRET"],docs:"https://open.dingtalk.com/document/",callbackUrl:"/api/auth/callback/dingtalk",tokenEndpoint:"https://api.dingtalk.com/v1.0/oauth2/userAccessToken"},{id:"workweixin",name:"\u4F01\u4E1A\u5FAE\u4FE1",region:"cn",envVars:["WORKWEIXIN_CORP_ID","WORKWEIXIN_AGENT_ID","WORKWEIXIN_SECRET"],docs:"https://developer.work.weixin.qq.com",callbackUrl:"/api/auth/callback/workweixin",tokenEndpoint:"https://qyapi.weixin.qq.com/cgi-bin/gettoken"},{id:"feishu",name:"\u98DE\u4E66 / Lark",region:"cn",envVars:["FEISHU_APP_ID","FEISHU_APP_SECRET"],docs:"https://open.feishu.cn/document/",callbackUrl:"/api/auth/callback/feishu",tokenEndpoint:"https://open.feishu.cn/open-apis/authen/v1/access_token"},{id:"weibo",name:"\u5FAE\u535A",region:"cn",envVars:["WEIBO_APP_KEY","WEIBO_APP_SECRET"],docs:"https://open.weibo.com/wiki/",callbackUrl:"/api/auth/callback/weibo",tokenEndpoint:"https://api.weibo.com/oauth2/access_token"}],Zo=new Set(Xe.map(e=>e.id));function nn(e){return Xe.find(t=>t.id===e)}function on(e){if(!e)return[];let t=e.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean);if(t.includes("none"))return[];let o=[],n=new Set;for(let r of t)Zo.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import pe from"fs";import ce from"path";function er(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
326
338
  // Generated by create-sailor \u2014 OAuth callback for ${e.name}
327
339
  // Primary auth provider: ${t}
328
- // Docs: ${e.docs}`,r={wechat:` const tokenRes = await fetch(
340
+ // Docs: ${e.docs}`,n={wechat:` const tokenRes = await fetch(
329
341
  "${e.tokenEndpoint}?" +
330
342
  new URLSearchParams({
331
343
  appid: process.env.WECHAT_APP_ID ?? "",
@@ -426,7 +438,7 @@ BETTER_AUTH_URL=http://localhost:3000
426
438
  const token = (await tokenRes.json()) as { access_token?: string; uid?: string };
427
439
  if (!token.access_token) {
428
440
  return NextResponse.redirect(new URL("/login?error=weibo_token", req.url));
429
- }`};return`${n}
441
+ }`};return`${o}
430
442
  import { type NextRequest, NextResponse } from "next/server";
431
443
 
432
444
  export async function GET(req: NextRequest) {
@@ -437,7 +449,7 @@ export async function GET(req: NextRequest) {
437
449
  return NextResponse.redirect(new URL("/login?error=no_code", req.url));
438
450
  }
439
451
 
440
- ${r[e.id]}
452
+ ${n[e.id]}
441
453
 
442
454
  // TODO: fetch user profile from ${e.name} using the access token.
443
455
  // TODO: upsert the user into your primary auth provider (${t}).
@@ -447,7 +459,7 @@ ${r[e.id]}
447
459
  void state;
448
460
  return NextResponse.redirect(new URL("/dashboard", req.url));
449
461
  }
450
- `}function Zn(e){return`"use client";
462
+ `}function tr(e){return`"use client";
451
463
 
452
464
  /**
453
465
  * SocialLoginButtons \u2014 generated by create-sailor.
@@ -467,7 +479,7 @@ interface SocialProvider {
467
479
  }
468
480
 
469
481
  const PROVIDERS: SocialProvider[] = [
470
- ${e.map(n=>` { id: ${JSON.stringify(n.id)}, name: ${JSON.stringify(n.name)}, href: ${JSON.stringify(`/api/auth/oauth/${n.id}`)} }`).join(`,
482
+ ${e.map(o=>` { id: ${JSON.stringify(o.id)}, name: ${JSON.stringify(o.name)}, href: ${JSON.stringify(`/api/auth/oauth/${o.id}`)} }`).join(`,
471
483
  `)},
472
484
  ];
473
485
 
@@ -490,17 +502,17 @@ export function SocialLoginButtons() {
490
502
  </div>
491
503
  );
492
504
  }
493
- `}function At(e){te.mkdirSync(e,{recursive:!0})}function er(e,t){let n=ee.join(e,".env.example");te.existsSync(n)?te.appendFileSync(n,`
494
- `+t):te.writeFileSync(n,t)}function tr(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,n=e.envVars.map(r=>`${r}=`).join(`
505
+ `}function rn(e){pe.mkdirSync(e,{recursive:!0})}function nr(e,t){let o=ce.join(e,".env.example");pe.existsSync(o)?pe.appendFileSync(o,`
506
+ `+t):pe.writeFileSync(o,t)}function or(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
495
507
  `);return`${t}
496
- ${n}
497
- `}async function Ct(e,t,n){if(!t||t.length===0)return;let r=ee.join(e,"apps","web");if(!te.existsSync(r))return;let o=new Set,s=[];for(let d of t){if(o.has(d))continue;o.add(d);let m=Pt(d);m&&s.push(m)}if(s.length===0)return;for(let d of s)er(e,tr(d));let a=ee.join(r,"src","app","api","auth","callback");for(let d of s){let m=ee.join(a,d.id);At(m);let S=ee.join(m,"route.ts");te.writeFileSync(S,Qn(d,n))}let c=ee.join(r,"src","components","auth");At(c);let i=ee.join(c,"SocialLoginButtons.tsx");te.writeFileSync(i,Zn(s))}import P from"fs";import v from"path";var nr=v.join("apps","web"),tt=v.join("src","components","compliance"),ke=v.join("src","app","[locale]");function D(e){return v.join(e,nr)}function rr(e){P.mkdirSync(e,{recursive:!0})}function k(e,t){rr(v.dirname(e)),P.writeFileSync(e,t,"utf8")}function nt(e,t){let n=v.join(e,".env.example");if(P.existsSync(n)){if(P.readFileSync(n,"utf8").includes(t.split(`
498
- `)[0]??""))return;P.appendFileSync(n,`
508
+ ${o}
509
+ `}async function sn(e,t,o){if(!t||t.length===0)return;let n=ce.join(e,"apps","web");if(!pe.existsSync(n))return;let r=new Set,s=[];for(let d of t){if(r.has(d))continue;r.add(d);let m=nn(d);m&&s.push(m)}if(s.length===0)return;for(let d of s)nr(e,or(d));let a=ce.join(n,"src","app","api","auth","callback");for(let d of s){let m=ce.join(a,d.id);rn(m);let E=ce.join(m,"route.ts");pe.writeFileSync(E,er(d,o))}let c=ce.join(n,"src","components","auth");rn(c);let i=ce.join(c,"SocialLoginButtons.tsx");pe.writeFileSync(i,tr(s))}import I from"fs";import _ from"path";var rr=_.join("apps","web"),Nt=_.join("src","components","compliance"),ze=_.join("src","app","[locale]");function V(e){return _.join(e,rr)}function sr(e){I.mkdirSync(e,{recursive:!0})}function O(e,t){sr(_.dirname(e)),I.writeFileSync(e,t,"utf8")}function xt(e,t){let o=_.join(e,".env.example");if(I.existsSync(o)){if(I.readFileSync(o,"utf8").includes(t.split(`
510
+ `)[0]??""))return;I.appendFileSync(o,`
499
511
  `+t+`
500
- `)}else P.writeFileSync(n,t+`
501
- `)}var Oe=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
512
+ `)}else I.writeFileSync(o,t+`
513
+ `)}var Qe=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
502
514
  > Consult a qualified lawyer in every jurisdiction you operate in before publishing.
503
- > \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,or=`import Link from "next/link";
515
+ > \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,ir=`import Link from "next/link";
504
516
  import { IcpFooter } from "@/components/compliance/IcpFooter";
505
517
  import { PublicSecurityFooter } from "@/components/compliance/PublicSecurityFooter";
506
518
 
@@ -551,7 +563,7 @@ export function Footer({ region = "global" }: FooterProps) {
551
563
  </footer>
552
564
  );
553
565
  }
554
- `,sr=`export function IcpFooter() {
566
+ `,ar=`export function IcpFooter() {
555
567
  const icp = process.env.NEXT_PUBLIC_ICP_BEIAN;
556
568
  if (!icp) return null;
557
569
  return (
@@ -565,7 +577,7 @@ export function Footer({ region = "global" }: FooterProps) {
565
577
  </a>
566
578
  );
567
579
  }
568
- `,ir=`export function PublicSecurityFooter() {
580
+ `,cr=`export function PublicSecurityFooter() {
569
581
  const psb = process.env.NEXT_PUBLIC_PSB_BEIAN;
570
582
  const psbCode = process.env.NEXT_PUBLIC_PSB_CODE;
571
583
  if (!psb) return null;
@@ -582,7 +594,7 @@ export function Footer({ region = "global" }: FooterProps) {
582
594
  </a>
583
595
  );
584
596
  }
585
- `,ar=`"use client";
597
+ `,pr=`"use client";
586
598
 
587
599
  import { useCallback, useEffect, useState } from "react";
588
600
 
@@ -809,7 +821,7 @@ function CategoryRow({ id, title, description, checked, disabled, onChange }: Ca
809
821
  </label>
810
822
  );
811
823
  }
812
- `,cr=`interface AigcDisclaimerProps {
824
+ `,lr=`interface AigcDisclaimerProps {
813
825
  className?: string;
814
826
  }
815
827
 
@@ -829,13 +841,13 @@ export function AigcDisclaimer({ className }: AigcDisclaimerProps) {
829
841
  </div>
830
842
  );
831
843
  }
832
- `,pr=`---
844
+ `,dr=`---
833
845
  title: Privacy Policy / \u9690\u79C1\u653F\u7B56
834
846
  description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal information.
835
847
  lastUpdated: 2026-01-01
836
848
  ---
837
849
 
838
- ${Oe}
850
+ ${Qe}
839
851
 
840
852
  # Privacy Policy / \u9690\u79C1\u653F\u7B56
841
853
 
@@ -974,13 +986,13 @@ or in-app notification before the change takes effect.
974
986
  **Data Controller / \u6570\u636E\u63A7\u5236\u8005:** {{COMPANY_NAME}}
975
987
  **Address / \u5730\u5740:** {{COMPANY_ADDRESS}}
976
988
  **Email / \u90AE\u7BB1:** {{COMPANY_CONTACT_EMAIL}}
977
- `,lr=`---
989
+ `,ur=`---
978
990
  title: Terms of Service / \u670D\u52A1\u6761\u6B3E
979
991
  description: Terms governing your use of {{COMPANY_NAME}}.
980
992
  lastUpdated: 2026-01-01
981
993
  ---
982
994
 
983
- ${Oe}
995
+ ${Qe}
984
996
 
985
997
  # Terms of Service / \u670D\u52A1\u6761\u6B3E
986
998
 
@@ -1093,13 +1105,13 @@ conflict-of-laws principles. Disputes shall be resolved in the competent courts
1093
1105
  ## 11. Contact / \u8054\u7CFB\u65B9\u5F0F
1094
1106
 
1095
1107
  {{COMPANY_NAME}} \xB7 {{COMPANY_ADDRESS}} \xB7 {{COMPANY_CONTACT_EMAIL}}
1096
- `,dr=`---
1108
+ `,mr=`---
1097
1109
  title: AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
1098
1110
  description: Disclosure required by \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300B
1099
1111
  lastUpdated: 2026-01-01
1100
1112
  ---
1101
1113
 
1102
- ${Oe}
1114
+ ${Qe}
1103
1115
 
1104
1116
  # AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
1105
1117
 
@@ -1175,13 +1187,13 @@ human professional.
1175
1187
 
1176
1188
  AI \u8F93\u51FA\u53EF\u80FD\u4E0D\u51C6\u786E\u3001\u5B58\u5728\u504F\u89C1\u6216\u8FC7\u65F6\u3002**\u8BF7\u52FF**\u5728\u672A\u7ECF\u5408\u683C\u4E13\u4E1A\u4EBA\u58EB\u72EC\u7ACB\u6838\u5B9E\u7684\u60C5\u51B5\u4E0B\uFF0C\u5C06 AI \u8F93\u51FA
1177
1189
  \u7528\u4E8E\u533B\u7597\u3001\u6CD5\u5F8B\u3001\u91D1\u878D\u6216\u5B89\u5168\u6538\u5173\u7684\u51B3\u7B56\u3002
1178
- `,ur=`---
1190
+ `,gr=`---
1179
1191
  title: Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
1180
1192
  description: Notice of cross-border transfer of personal information, per PIPL.
1181
1193
  lastUpdated: 2026-01-01
1182
1194
  ---
1183
1195
 
1184
- ${Oe}
1196
+ ${Qe}
1185
1197
 
1186
1198
  # Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
1187
1199
 
@@ -1240,13 +1252,13 @@ Refusal may limit your ability to use features that rely on overseas services.
1240
1252
  - \u4F20\u8F93\u4E2D\u52A0\u5BC6 (TLS 1.2+) \u53CA\u9759\u6001\u52A0\u5BC6 (AES-256)\u3002
1241
1253
  - \u5408\u540C\u6761\u6B3E\u8981\u6C42\u5883\u5916\u63A5\u6536\u65B9\u63D0\u4F9B\u7B49\u540C\u4E8E PIPL \u7684\u4FDD\u62A4\u3002
1242
1254
  - \u8BBF\u95EE\u63A7\u5236\u3001\u5BA1\u8BA1\u65E5\u5FD7\u548C\u8FDD\u89C4\u901A\u77E5\u7A0B\u5E8F\u3002
1243
- `,mr=`---
1255
+ `,fr=`---
1244
1256
  title: Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
1245
1257
  description: Itemized list of personal information collected, per PIPL Article 17.
1246
1258
  lastUpdated: 2026-01-01
1247
1259
  ---
1248
1260
 
1249
- ${Oe}
1261
+ ${Qe}
1250
1262
 
1251
1263
  # Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
1252
1264
 
@@ -1282,19 +1294,19 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
1282
1294
  **{{COMPANY_CONTACT_EMAIL}}**.
1283
1295
 
1284
1296
  \u5982\u9700\u884C\u4F7F\u60A8\u7684\u6743\u5229\uFF08\u8BBF\u95EE\u3001\u66F4\u6B63\u3001\u5220\u9664\u3001\u5BFC\u51FA\u3001\u64A4\u56DE\u540C\u610F\uFF09\uFF0C\u8BF7\u8054\u7CFB **{{COMPANY_CONTACT_EMAIL}}**\u3002
1285
- `;async function gr(e,t){let n=D(e);if(!P.existsSync(n))return;let r=v.join(n,"src","components","compliance","Footer.tsx");k(r,or);let o=v.join(n,"src","components","compliance","README.md");k(o,["# Compliance Components","",`Auto-generated by \`create-sailor\` for region: \`${t}\`.`,"","## Mounting the Footer","","```tsx",'import { Footer } from "@/components/compliance/Footer";','import { CookieBanner } from "@/components/compliance/CookieBanner";',"","export default function RootLayout({ children }) {"," return ("," <html>"," <body>"," {children}",` <Footer region="${t}" />`," <CookieBanner />"," </body>"," </html>"," );","}","```","","## Placeholders","","Policy MDX files contain `{{COMPANY_NAME}}`, `{{COMPANY_ADDRESS}}`,","`{{COMPANY_CONTACT_EMAIL}}`, `{{GOVERNING_JURISDICTION}}`, and","`{{AIGC_ALGORITHM_FILING_NUMBER}}`. These are filled by the `brand-apply` step.",""].join(`
1286
- `))}async function fr(e,t){let n=D(e);if(!P.existsSync(n))return;let r=v.join(n,"src","components","compliance","CookieBanner.tsx");k(r,ar)}async function yr(e,t){let n=D(e);if(!P.existsSync(n))return;let r=v.join(n,ke,"privacy","page.mdx");k(r,pr)}async function Sr(e,t){let n=D(e);if(!P.existsSync(n))return;let r=v.join(n,ke,"terms","page.mdx");k(r,lr)}async function Er(e){let t=D(e);if(!P.existsSync(t))return;let n=v.join(t,tt,"IcpFooter.tsx");k(n,sr),nt(e,["# Chinese ICP filing (\u5DE5\u4FE1\u90E8 ICP \u5907\u6848) \u2014 required to legally host a","# public-facing site from mainland China. Apply at https://beian.miit.gov.cn/",'NEXT_PUBLIC_ICP_BEIAN="" # \u5982 \u82CFICP\u59072024XXXXXX\u53F7'].join(`
1287
- `))}async function hr(e){let t=D(e);if(!P.existsSync(t))return;let n=v.join(t,tt,"PublicSecurityFooter.tsx");k(n,ir),nt(e,["# Chinese Public Security Bureau filing (\u516C\u5B89\u8054\u7F51\u5907\u6848)","# Required in addition to ICP. Apply at http://www.beian.gov.cn/",'NEXT_PUBLIC_PSB_BEIAN="" # \u5982 \u82CF\u516C\u7F51\u5B89\u5907 32011402XXXXXX\u53F7','NEXT_PUBLIC_PSB_CODE="" # 14-digit record code'].join(`
1288
- `))}async function _r(e){let t=D(e);if(!P.existsSync(t))return;let n=v.join(t,tt,"AigcDisclaimer.tsx");k(n,cr),nt(e,["# Generative AI algorithm filing (\u7B97\u6CD5\u5907\u6848\u53F7) \u2014 required by","# \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300Bfor services offered in China.",'NEXT_PUBLIC_AIGC_FILING_NUMBER="" # e.g. \u7F51\u4FE1\u7B97\u5907XXXXXXXX\u53F7'].join(`
1289
- `))}async function vr(e){let t=D(e);if(!P.existsSync(t))return;let n=v.join(t,ke,"aigc-disclosure","page.mdx");k(n,dr)}async function Ir(e){let t=D(e);if(!P.existsSync(t))return;let n=v.join(t,ke,"cross-border-data","page.mdx");k(n,ur)}async function Pr(e){let t=D(e);if(!P.existsSync(t))return;let n=v.join(t,ke,"pii-collection","page.mdx");k(n,mr)}async function wt(e,t){try{await gr(e,t),await fr(e,t),await yr(e,t),await Sr(e,t),(t==="cn"||t==="hybrid")&&(await Er(e),await hr(e),await _r(e),await vr(e),await Ir(e),await Pr(e))}catch(n){throw console.error("applyComplianceTemplates failed:",n),new Error(`Failed to apply compliance templates for region "${t}". Check that ${e} is writable.`)}}import br from"fs";import Ar from"path";async function Nt(e,t){let n=Ar.join(e,"nebutra.config.json");br.writeFileSync(n,JSON.stringify(t,null,2)+`
1290
- `)}import q from"fs";import rt from"path";function Cr(e){q.existsSync(e)&&q.rmSync(e,{recursive:!0,force:!0})}function Tt(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function wr(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function xt(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 Nr(e,t){let n=rt.join(e,".env.example");q.existsSync(n)?q.appendFileSync(n,`
1291
- `+t):q.writeFileSync(n,t)}async function Rt(e,t,n){let r=rt.join(e,"packages","db");if(t==="none"){Cr(r);return}let o=rt.join(r,"prisma","schema.prisma"),s;if(t==="postgresql"?s=`postgresql://postgres:postgres@localhost:5432/${n}`:t==="mysql"?s=`mysql://root:root@localhost:3306/${n}`:s="file:./dev.db",Nr(e,`# Database (${t})
1297
+ `;async function yr(e,t){let o=V(e);if(!I.existsSync(o))return;let n=_.join(o,"src","components","compliance","Footer.tsx");O(n,ir);let r=_.join(o,"src","components","compliance","README.md");O(r,["# Compliance Components","",`Auto-generated by \`create-sailor\` for region: \`${t}\`.`,"","## Mounting the Footer","","```tsx",'import { Footer } from "@/components/compliance/Footer";','import { CookieBanner } from "@/components/compliance/CookieBanner";',"","export default function RootLayout({ children }) {"," return ("," <html>"," <body>"," {children}",` <Footer region="${t}" />`," <CookieBanner />"," </body>"," </html>"," );","}","```","","## Placeholders","","Policy MDX files contain `{{COMPANY_NAME}}`, `{{COMPANY_ADDRESS}}`,","`{{COMPANY_CONTACT_EMAIL}}`, `{{GOVERNING_JURISDICTION}}`, and","`{{AIGC_ALGORITHM_FILING_NUMBER}}`. These are filled by the `brand-apply` step.",""].join(`
1298
+ `))}async function Sr(e,t){let o=V(e);if(!I.existsSync(o))return;let n=_.join(o,"src","components","compliance","CookieBanner.tsx");O(n,pr)}async function Er(e,t){let o=V(e);if(!I.existsSync(o))return;let n=_.join(o,ze,"privacy","page.mdx");O(n,dr)}async function hr(e,t){let o=V(e);if(!I.existsSync(o))return;let n=_.join(o,ze,"terms","page.mdx");O(n,ur)}async function vr(e){let t=V(e);if(!I.existsSync(t))return;let o=_.join(t,Nt,"IcpFooter.tsx");O(o,ar),xt(e,["# Chinese ICP filing (\u5DE5\u4FE1\u90E8 ICP \u5907\u6848) \u2014 required to legally host a","# public-facing site from mainland China. Apply at https://beian.miit.gov.cn/",'NEXT_PUBLIC_ICP_BEIAN="" # \u5982 \u82CFICP\u59072024XXXXXX\u53F7'].join(`
1299
+ `))}async function _r(e){let t=V(e);if(!I.existsSync(t))return;let o=_.join(t,Nt,"PublicSecurityFooter.tsx");O(o,cr),xt(e,["# Chinese Public Security Bureau filing (\u516C\u5B89\u8054\u7F51\u5907\u6848)","# Required in addition to ICP. Apply at http://www.beian.gov.cn/",'NEXT_PUBLIC_PSB_BEIAN="" # \u5982 \u82CF\u516C\u7F51\u5B89\u5907 32011402XXXXXX\u53F7','NEXT_PUBLIC_PSB_CODE="" # 14-digit record code'].join(`
1300
+ `))}async function Pr(e){let t=V(e);if(!I.existsSync(t))return;let o=_.join(t,Nt,"AigcDisclaimer.tsx");O(o,lr),xt(e,["# Generative AI algorithm filing (\u7B97\u6CD5\u5907\u6848\u53F7) \u2014 required by","# \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300Bfor services offered in China.",'NEXT_PUBLIC_AIGC_FILING_NUMBER="" # e.g. \u7F51\u4FE1\u7B97\u5907XXXXXXXX\u53F7'].join(`
1301
+ `))}async function Ir(e){let t=V(e);if(!I.existsSync(t))return;let o=_.join(t,ze,"aigc-disclosure","page.mdx");O(o,mr)}async function Cr(e){let t=V(e);if(!I.existsSync(t))return;let o=_.join(t,ze,"cross-border-data","page.mdx");O(o,gr)}async function br(e){let t=V(e);if(!I.existsSync(t))return;let o=_.join(t,ze,"pii-collection","page.mdx");O(o,fr)}async function an(e,t){try{await yr(e,t),await Sr(e,t),await Er(e,t),await hr(e,t),(t==="cn"||t==="hybrid")&&(await vr(e),await _r(e),await Pr(e),await Ir(e),await Cr(e),await br(e))}catch(o){throw console.error("applyComplianceTemplates failed:",o),new Error(`Failed to apply compliance templates for region "${t}". Check that ${e} is writable.`)}}import Ar from"fs";import Rr from"path";async function cn(e,t){let o=Rr.join(e,"nebutra.config.json");Ar.writeFileSync(o,JSON.stringify(t,null,2)+`
1302
+ `)}import z from"fs";import Tt from"path";function wr(e){z.existsSync(e)&&z.rmSync(e,{recursive:!0,force:!0})}function pn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function Nr(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function ln(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 xr(e,t){let o=Tt.join(e,".env.example");z.existsSync(o)?z.appendFileSync(o,`
1303
+ `+t):z.writeFileSync(o,t)}async function dn(e,t,o){let n=Tt.join(e,"packages","db");if(t==="none"){wr(n);return}let r=Tt.join(n,"prisma","schema.prisma"),s;if(t==="postgresql"?s=`postgresql://postgres:postgres@localhost:5432/${o}`:t==="mysql"?s=`mysql://root:root@localhost:3306/${o}`:s="file:./dev.db",xr(e,`# Database (${t})
1292
1304
  DATABASE_URL="${s}"
1293
- `),!q.existsSync(o))return;let a=q.readFileSync(o,"utf8"),c=a;t==="mysql"?(c=Tt(c,"mysql"),c=xt(c)):t==="sqlite"&&(c=Tt(c,"sqlite"),c=wr(c),c=xt(c)),c!==a&&q.writeFileSync(o,c)}import Ue from"fs";import N from"path";import{fileURLToPath as Tr}from"url";var xr=Tr(import.meta.url),Rr=N.dirname(xr);async function kt(e,t){if(t==="none")return;let n=N.join(Rr,"../../templates/deploy");t==="vercel"?await Ue.promises.copyFile(N.join(n,"vercel.json"),N.join(e,"vercel.json")):t==="railway"?await Ue.promises.copyFile(N.join(n,"railway.toml"),N.join(e,"railway.toml")):t==="cloudflare"?await Ue.promises.copyFile(N.join(n,"wrangler.toml"),N.join(e,"wrangler.toml")):t==="selfhost"&&(await Ue.promises.copyFile(N.join(n,"docker-compose.yml"),N.join(e,"docker-compose.yml")),await Ue.promises.copyFile(N.join(n,"Dockerfile.web"),N.join(e,"Dockerfile.web")))}import G from"fs";import ne from"path";import{fileURLToPath as kr}from"url";var Or=kr(import.meta.url),Ot=ne.dirname(Or),Ur=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml)$/;function Lr(e){let t=[ne.join(Ot,"..","templates","docs",e),ne.join(Ot,"..","..","templates","docs",e)];for(let n of t)if(G.existsSync(n))return n;return t[0]}async function Ut(e,t){if(t.framework==="none")return;let n=(t.framework==="fumadocs","fumadocs"),r=Lr(n),o=ne.join(e,"apps","docs");if(!G.existsSync(r))throw new Error(`Docs template not found: ${r}`);Lt(r,o),Mt(o,{"{PRODUCT_NAME}":t.projectName})}function Lt(e,t){G.mkdirSync(t,{recursive:!0});for(let n of G.readdirSync(e,{withFileTypes:!0})){let r=ne.join(e,n.name),o=ne.join(t,n.name);n.isDirectory()?Lt(r,o):G.copyFileSync(r,o)}}function Mt(e,t){for(let n of G.readdirSync(e,{withFileTypes:!0})){let r=ne.join(e,n.name);if(n.isDirectory())Mt(r,t);else if(Ur.test(n.name)){let o=G.readFileSync(r,"utf-8");for(let[s,a]of Object.entries(t))o=o.split(s).join(a);G.writeFileSync(r,o)}}}import oe from"fs";import re from"path";var We=[{id:"resend",name:"Resend",region:"global",envVars:["RESEND_API_KEY","RESEND_FROM"],docs:"https://resend.com/docs",pkg:"resend",pkgVersion:"^4.0.1"},{id:"postmark",name:"Postmark",region:"global",envVars:["POSTMARK_API_KEY","POSTMARK_FROM"],docs:"https://postmarkapp.com/developer",pkg:"postmark",pkgVersion:"^4.0.5"},{id:"ses",name:"AWS SES",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_SES_REGION","SES_FROM"],docs:"https://docs.aws.amazon.com/ses",pkg:"@aws-sdk/client-sesv2",pkgVersion:"^3.658.0"},{id:"aliyun-dm",name:"\u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001",region:"cn",envVars:["ALIYUN_DM_ACCESS_KEY","ALIYUN_DM_ACCESS_SECRET","ALIYUN_DM_ACCOUNT_NAME","ALIYUN_DM_FROM_ALIAS"],docs:"https://help.aliyun.com/product/29412.html",pkg:"@alicloud/dm20151123",pkgVersion:"^3.0.0"},{id:"tencent-ses",name:"\u817E\u8BAF\u4E91 SES",region:"cn",envVars:["TENCENT_SECRET_ID","TENCENT_SECRET_KEY","TENCENT_SES_FROM_EMAIL"],docs:"https://cloud.tencent.com/document/product/1288",pkg:"tencentcloud-sdk-nodejs-ses",pkgVersion:"^4.0.900"},{id:"netease",name:"\u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1",region:"cn",envVars:["NETEASE_USER","NETEASE_PASS","NETEASE_FROM"],docs:"https://qiye.163.com/help",pkg:"nodemailer",pkgVersion:"^6.9.15"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function jt(e){return We.find(t=>t.id===e)}var Qs=We.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var se="@nebutra/email";function ot(e,t){oe.mkdirSync(re.dirname(e),{recursive:!0}),oe.writeFileSync(e,t)}function Mr(e,t){let n=re.join(e,".env.example");oe.existsSync(n)?oe.appendFileSync(n,`
1294
- `+t):oe.writeFileSync(n,t)}function jr(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,n=e.envVars.map(r=>`${r}=`).join(`
1305
+ `),!z.existsSync(r))return;let a=z.readFileSync(r,"utf8"),c=a;t==="mysql"?(c=pn(c,"mysql"),c=ln(c)):t==="sqlite"&&(c=pn(c,"sqlite"),c=Nr(c),c=ln(c)),c!==a&&z.writeFileSync(r,c)}import Je from"fs";import N from"path";import{fileURLToPath as Tr}from"url";var kr=Tr(import.meta.url),Or=N.dirname(kr);async function un(e,t){if(t==="none")return;let o=N.join(Or,"../../templates/deploy");t==="vercel"?await Je.promises.copyFile(N.join(o,"vercel.json"),N.join(e,"vercel.json")):t==="railway"?await Je.promises.copyFile(N.join(o,"railway.toml"),N.join(e,"railway.toml")):t==="cloudflare"?await Je.promises.copyFile(N.join(o,"wrangler.toml"),N.join(e,"wrangler.toml")):t==="selfhost"&&(await Je.promises.copyFile(N.join(o,"docker-compose.yml"),N.join(e,"docker-compose.yml")),await Je.promises.copyFile(N.join(o,"Dockerfile.web"),N.join(e,"Dockerfile.web")))}import Q from"fs";import le from"path";import{fileURLToPath as Ur}from"url";var Lr=Ur(import.meta.url),mn=le.dirname(Lr),Mr=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml)$/;function Dr(e){let t=[le.join(mn,"..","templates","docs",e),le.join(mn,"..","..","templates","docs",e)];for(let o of t)if(Q.existsSync(o))return o;return t[0]}async function gn(e,t){if(t.framework==="none")return;let o=(t.framework==="fumadocs","fumadocs"),n=Dr(o),r=le.join(e,"apps","docs");if(!Q.existsSync(n))throw new Error(`Docs template not found: ${n}`);fn(n,r),yn(r,{"{PRODUCT_NAME}":t.projectName})}function fn(e,t){Q.mkdirSync(t,{recursive:!0});for(let o of Q.readdirSync(e,{withFileTypes:!0})){let n=le.join(e,o.name),r=le.join(t,o.name);o.isDirectory()?fn(n,r):Q.copyFileSync(n,r)}}function yn(e,t){for(let o of Q.readdirSync(e,{withFileTypes:!0})){let n=le.join(e,o.name);if(o.isDirectory())yn(n,t);else if(Mr.test(o.name)){let r=Q.readFileSync(n,"utf-8");for(let[s,a]of Object.entries(t))r=r.split(s).join(a);Q.writeFileSync(n,r)}}}import ue from"fs";import de from"path";var mt=[{id:"resend",name:"Resend",region:"global",envVars:["RESEND_API_KEY","RESEND_FROM"],docs:"https://resend.com/docs",pkg:"resend",pkgVersion:"^4.0.1"},{id:"postmark",name:"Postmark",region:"global",envVars:["POSTMARK_API_KEY","POSTMARK_FROM"],docs:"https://postmarkapp.com/developer",pkg:"postmark",pkgVersion:"^4.0.5"},{id:"ses",name:"AWS SES",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_SES_REGION","SES_FROM"],docs:"https://docs.aws.amazon.com/ses",pkg:"@aws-sdk/client-sesv2",pkgVersion:"^3.658.0"},{id:"aliyun-dm",name:"\u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001",region:"cn",envVars:["ALIYUN_DM_ACCESS_KEY","ALIYUN_DM_ACCESS_SECRET","ALIYUN_DM_ACCOUNT_NAME","ALIYUN_DM_FROM_ALIAS"],docs:"https://help.aliyun.com/product/29412.html",pkg:"@alicloud/dm20151123",pkgVersion:"^3.0.0"},{id:"tencent-ses",name:"\u817E\u8BAF\u4E91 SES",region:"cn",envVars:["TENCENT_SECRET_ID","TENCENT_SECRET_KEY","TENCENT_SES_FROM_EMAIL"],docs:"https://cloud.tencent.com/document/product/1288",pkg:"tencentcloud-sdk-nodejs-ses",pkgVersion:"^4.0.900"},{id:"netease",name:"\u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1",region:"cn",envVars:["NETEASE_USER","NETEASE_PASS","NETEASE_FROM"],docs:"https://qiye.163.com/help",pkg:"nodemailer",pkgVersion:"^6.9.15"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function Sn(e){return mt.find(t=>t.id===e)}var ia=mt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var me="@nebutra/email";function kt(e,t){ue.mkdirSync(de.dirname(e),{recursive:!0}),ue.writeFileSync(e,t)}function jr(e,t){let o=de.join(e,".env.example");ue.existsSync(o)?ue.appendFileSync(o,`
1306
+ `+t):ue.writeFileSync(o,t)}function Fr(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
1295
1307
  `);return`${t}
1296
- ${n}
1297
- `}var Dr=`/**
1308
+ ${o}
1309
+ `}var Vr=`/**
1298
1310
  * Public inputs accepted by the \`sendEmail\` wrapper.
1299
1311
  * Keep the surface minimal \u2014 individual providers may accept more, but
1300
1312
  * consumers should code against this shape for portability.
@@ -1314,8 +1326,8 @@ export interface SendEmailResult {
1314
1326
  /** Raw provider response \u2014 useful for debugging, not a stable contract. */
1315
1327
  raw?: unknown;
1316
1328
  }
1317
- `;function Fr(){return`/**
1318
- * @${se.slice(1)} \u2014 Resend transactional email wrapper.
1329
+ `;function Kr(){return`/**
1330
+ * @${me.slice(1)} \u2014 Resend transactional email wrapper.
1319
1331
  *
1320
1332
  * Docs: https://resend.com/docs
1321
1333
  */
@@ -1353,8 +1365,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1353
1365
  }
1354
1366
 
1355
1367
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1356
- `}function Br(){return`/**
1357
- * @${se.slice(1)} \u2014 Postmark transactional email wrapper.
1368
+ `}function Yr(){return`/**
1369
+ * @${me.slice(1)} \u2014 Postmark transactional email wrapper.
1358
1370
  *
1359
1371
  * Docs: https://postmarkapp.com/developer
1360
1372
  */
@@ -1391,8 +1403,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1391
1403
  }
1392
1404
 
1393
1405
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1394
- `}function Yr(){return`/**
1395
- * @${se.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
1406
+ `}function Br(){return`/**
1407
+ * @${me.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
1396
1408
  *
1397
1409
  * Docs: https://docs.aws.amazon.com/ses
1398
1410
  */
@@ -1447,8 +1459,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1447
1459
  }
1448
1460
 
1449
1461
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1450
- `}function Kr(){return`/**
1451
- * @${se.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
1462
+ `}function $r(){return`/**
1463
+ * @${me.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
1452
1464
  *
1453
1465
  * Docs: https://help.aliyun.com/product/29412.html
1454
1466
  */
@@ -1497,8 +1509,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1497
1509
  }
1498
1510
 
1499
1511
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1500
- `}function Vr(){return`/**
1501
- * @${se.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
1512
+ `}function qr(){return`/**
1513
+ * @${me.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
1502
1514
  *
1503
1515
  * Docs: https://cloud.tencent.com/document/product/1288
1504
1516
  */
@@ -1545,8 +1557,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1545
1557
  }
1546
1558
 
1547
1559
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1548
- `}function $r(){return`/**
1549
- * @${se.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
1560
+ `}function Gr(){return`/**
1561
+ * @${me.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
1550
1562
  *
1551
1563
  * Docs: https://qiye.163.com/help
1552
1564
  */
@@ -1583,21 +1595,21 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1583
1595
  }
1584
1596
 
1585
1597
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1586
- `}function qr(e){switch(e){case"resend":return Fr();case"postmark":return Br();case"ses":return Yr();case"aliyun-dm":return Kr();case"tencent-ses":return Vr();case"netease":return $r();case"none":return`export {};
1587
- `}}function Gr(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),e.id==="aliyun-dm"&&(t["@alicloud/openapi-client"]="^0.4.12");let n={name:se,version:"0.1.0",private:!0,description:`Transactional email via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(n,null,2)+`
1588
- `}async function Dt(e,t,n){if(t==="none")return;let r=jt(t);if(!r)throw new Error(`Unknown email provider "${t}". Valid ids: ${We.map(a=>a.id).join(", ")}`);let o=re.join(e,"packages","email"),s=re.join(o,"src");oe.existsSync(s)&&oe.rmSync(s,{recursive:!0,force:!0}),ot(re.join(o,"package.json"),Gr(r)),ot(re.join(s,"types.ts"),Dr),ot(re.join(s,"index.ts"),qr(r.id)),Mr(e,jr(r))}import Bt from"crypto";import Le from"fs";import Ft from"path";function ie(e){return Bt.randomBytes(e).toString("base64").replace(/=+$/,"")}function Wr(e){return Bt.randomBytes(e).toString("hex")}function Xr(){return{AUTH_SECRET:ie(32),NEXTAUTH_SECRET:ie(32),BETTER_AUTH_SECRET:ie(32),JWT_SECRET:ie(32),WEBHOOK_SECRET:Wr(16),ENCRYPTION_KEY:ie(32),API_SECRET_KEY:ie(32),SESSION_SECRET:ie(32)}}function Hr(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function zr(e,t,n){let r=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),o=Hr(n);return e.replace(r,`${t}="${o}"`)}async function Yt(e){let t=Ft.join(e,".env.example"),n=Ft.join(e,".env.local");if(!Le.existsSync(t))return null;try{let r=Le.readFileSync(t,"utf8"),o=Xr(),a=Le.existsSync(n)?Le.readFileSync(n,"utf8"):r;for(let c of Object.keys(o))a=zr(a,c,o[c]);return Le.writeFileSync(n,a),o}catch(r){let o=r instanceof Error?r.message:String(r);throw console.error(`[create-sailor] Failed to generate env secrets: ${o}`),new Error(`Unable to write .env.local: ${o}`)}}import Xe from"fs";import Kt from"path";async function Vt(e,t){let n=`# Automatically injected by create-sailor
1598
+ `}function Hr(e){switch(e){case"resend":return Kr();case"postmark":return Yr();case"ses":return Br();case"aliyun-dm":return $r();case"tencent-ses":return qr();case"netease":return Gr();case"none":return`export {};
1599
+ `}}function Wr(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),e.id==="aliyun-dm"&&(t["@alicloud/openapi-client"]="^0.4.12");let o={name:me,version:"0.1.0",private:!0,description:`Transactional email via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
1600
+ `}async function En(e,t,o){if(t==="none")return;let n=Sn(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${mt.map(a=>a.id).join(", ")}`);let r=de.join(e,"packages","email"),s=de.join(r,"src");ue.existsSync(s)&&ue.rmSync(s,{recursive:!0,force:!0}),kt(de.join(r,"package.json"),Wr(n)),kt(de.join(s,"types.ts"),Vr),kt(de.join(s,"index.ts"),Hr(n.id)),jr(e,Fr(n))}import vn from"crypto";import Ze from"fs";import hn from"path";function ge(e){return vn.randomBytes(e).toString("base64").replace(/=+$/,"")}function Xr(e){return vn.randomBytes(e).toString("hex")}function zr(){return{AUTH_SECRET:ge(32),NEXTAUTH_SECRET:ge(32),BETTER_AUTH_SECRET:ge(32),JWT_SECRET:ge(32),WEBHOOK_SECRET:Xr(16),ENCRYPTION_KEY:ge(32),API_SECRET_KEY:ge(32),SESSION_SECRET:ge(32)}}function Qr(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Jr(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=Qr(o);return e.replace(n,`${t}="${r}"`)}async function _n(e){let t=hn.join(e,".env.example"),o=hn.join(e,".env.local");if(!Ze.existsSync(t))return null;try{let n=Ze.readFileSync(t,"utf8"),r=zr(),a=Ze.existsSync(o)?Ze.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))a=Jr(a,c,r[c]);return Ze.writeFileSync(o,a),r}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate env secrets: ${r}`),new Error(`Unable to write .env.local: ${r}`)}}import gt from"fs";import Pn from"path";async function In(e,t){let o=`# Automatically injected by create-sailor
1589
1601
  DATABASE_URL="${String(t.databaseUrl)}"
1590
1602
 
1591
1603
  NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
1592
1604
  CLERK_SECRET_KEY="${String(t.clerkSecret)}"
1593
1605
 
1594
1606
  NEXT_PUBLIC_SITE_URL="http://localhost:3000"
1595
- `,r=Kt.join(e,".env"),o=Kt.join(e,".env.local");!Xe.existsSync(r)&&!Xe.existsSync(o)?Xe.writeFileSync(o,n):Xe.appendFileSync(o,`
1596
- `+n)}import{execSync as Jr}from"child_process";import F from"fs";import Pe from"path";import Qr from"ignore";var Zr={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 eo(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function $t(e,t,n){let r=F.readdirSync(t,{withFileTypes:!0});for(let o of r){if(o.name==="node_modules"||o.name===".git")continue;let s=Pe.join(t,o.name),a=Pe.relative(e,s).split(Pe.sep).join("/");o.isDirectory()?(n.push(a+"/"),$t(e,s,n)):n.push(a)}}function to(e){let t=Pe.join(e,".templateignore");if(!F.existsSync(t))return;let n=F.readFileSync(t,"utf8"),r=Qr().add(n),o=[];$t(e,e,o);let s=o.map(i=>i.endsWith("/")?i.slice(0,-1):i),a=new Set(r.filter(s)),c=s.filter(i=>!a.has(i)).sort((i,d)=>d.split("/").length-i.split("/").length);for(let i of c){let d=Pe.join(e,i);try{F.existsSync(d)&&F.rmSync(d,{recursive:!0,force:!0})}catch{}}try{F.existsSync(t)&&F.rmSync(t,{force:!0})}catch{}}function no(e,t){Jr(`set -o pipefail; curl -sSfL ${e} | tar -xz -C "${t}" --strip-components=1`,{stdio:"ignore",shell:"bash"})}async function qt(e){F.mkdirSync(e,{recursive:!0});let n=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],r;for(let o of n){let s=Zr[o],a=eo(s.repo,s.ref);try{if(no(a,e),s.applyIgnore)try{to(e)}catch(c){throw new Error(`Template cloned, but .templateignore processing failed: ${c instanceof Error?c.message:String(c)}`)}return}catch(c){r=c instanceof Error?c:new Error(String(c));try{let i=F.readdirSync(e);for(let d of i)F.rmSync(Pe.join(e,d),{recursive:!0,force:!0})}catch{}}}throw new Error(`Failed to download the template from any source. Last error: ${r?.message??"unknown"}
1607
+ `,n=Pn.join(e,".env"),r=Pn.join(e,".env.local");!gt.existsSync(n)&&!gt.existsSync(r)?gt.writeFileSync(r,o):gt.appendFileSync(r,`
1608
+ `+o)}import{execSync as Zr}from"child_process";import K from"fs";import ke from"path";import es from"ignore";var ts={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 ns(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function Cn(e,t,o){let n=K.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let s=ke.join(t,r.name),a=ke.relative(e,s).split(ke.sep).join("/");r.isDirectory()?(o.push(a+"/"),Cn(e,s,o)):o.push(a)}}function os(e){let t=ke.join(e,".templateignore");if(!K.existsSync(t))return;let o=K.readFileSync(t,"utf8"),n=es().add(o),r=[];Cn(e,e,r);let s=r.map(i=>i.endsWith("/")?i.slice(0,-1):i),a=new Set(n.filter(s)),c=s.filter(i=>!a.has(i)).sort((i,d)=>d.split("/").length-i.split("/").length);for(let i of c){let d=ke.join(e,i);try{K.existsSync(d)&&K.rmSync(d,{recursive:!0,force:!0})}catch{}}try{K.existsSync(t)&&K.rmSync(t,{force:!0})}catch{}}function rs(e,t){Zr(`set -o pipefail; curl -sSfL ${e} | tar -xz -C "${t}" --strip-components=1`,{stdio:"ignore",shell:"bash"})}async function bn(e){K.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let s=ts[r],a=ns(s.repo,s.ref);try{if(rs(a,e),s.applyIgnore)try{os(e)}catch(c){throw new Error(`Template cloned, but .templateignore processing failed: ${c instanceof Error?c.message:String(c)}`)}return}catch(c){n=c instanceof Error?c:new Error(String(c));try{let i=K.readdirSync(e);for(let d of i)K.rmSync(ke.join(e,d),{recursive:!0,force:!0})}catch{}}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
1597
1609
 
1598
1610
  Ensure you have internet access and curl/tar installed.
1599
- You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import be from"fs";import C from"path";var Gt=[{id:"sentry",name:"Sentry",region:"both",envVars:["SENTRY_DSN","NEXT_PUBLIC_SENTRY_DSN"],docs:"https://docs.sentry.io",pkg:"@sentry/nextjs",instrumentationFile:"apps/web/instrumentation.ts"},{id:"datadog",name:"Datadog",region:"global",envVars:["DD_API_KEY","DD_APP_KEY","DD_SITE"],docs:"https://docs.datadoghq.com",pkg:"dd-trace",instrumentationFile:"apps/web/instrumentation.ts"},{id:"bugsnag",name:"Bugsnag",region:"global",envVars:["BUGSNAG_API_KEY","NEXT_PUBLIC_BUGSNAG_API_KEY"],docs:"https://docs.bugsnag.com",pkg:"@bugsnag/js",instrumentationFile:"apps/web/src/lib/monitoring/bugsnag.ts"},{id:"aliyun-arms",name:"\u963F\u91CC\u4E91 ARMS",region:"cn",envVars:["ALIYUN_ARMS_LICENSE_KEY","ALIYUN_ARMS_APP_NAME","NEXT_PUBLIC_ARMS_PID"],docs:"https://help.aliyun.com/product/34364.html",instrumentationFile:"apps/web/src/components/monitoring/ArmsScript.tsx"},{id:"tingyun",name:"\u542C\u4E91 TingYun",region:"cn",envVars:["TINGYUN_LICENSE_KEY","NEXT_PUBLIC_TINGYUN_APP_KEY"],docs:"https://www.tingyun.com/docs",instrumentationFile:"apps/web/src/components/monitoring/TingYunScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],yi=Gt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Wt(e){return Gt.find(t=>t.id===e)}function ro(e){be.mkdirSync(e,{recursive:!0})}function B(e,t){ro(C.dirname(e)),be.writeFileSync(e,t)}function Me(e,t){let n=C.join(e,".env.example");be.existsSync(n)?be.appendFileSync(n,`
1600
- `+t):be.writeFileSync(n,t)}function oo(e){let t=`import * as Sentry from "@sentry/nextjs";
1611
+ You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import Oe from"fs";import R from"path";var An=[{id:"sentry",name:"Sentry",region:"both",envVars:["SENTRY_DSN","NEXT_PUBLIC_SENTRY_DSN"],docs:"https://docs.sentry.io",pkg:"@sentry/nextjs",instrumentationFile:"apps/web/instrumentation.ts"},{id:"datadog",name:"Datadog",region:"global",envVars:["DD_API_KEY","DD_APP_KEY","DD_SITE"],docs:"https://docs.datadoghq.com",pkg:"dd-trace",instrumentationFile:"apps/web/instrumentation.ts"},{id:"bugsnag",name:"Bugsnag",region:"global",envVars:["BUGSNAG_API_KEY","NEXT_PUBLIC_BUGSNAG_API_KEY"],docs:"https://docs.bugsnag.com",pkg:"@bugsnag/js",instrumentationFile:"apps/web/src/lib/monitoring/bugsnag.ts"},{id:"aliyun-arms",name:"\u963F\u91CC\u4E91 ARMS",region:"cn",envVars:["ALIYUN_ARMS_LICENSE_KEY","ALIYUN_ARMS_APP_NAME","NEXT_PUBLIC_ARMS_PID"],docs:"https://help.aliyun.com/product/34364.html",instrumentationFile:"apps/web/src/components/monitoring/ArmsScript.tsx"},{id:"tingyun",name:"\u542C\u4E91 TingYun",region:"cn",envVars:["TINGYUN_LICENSE_KEY","NEXT_PUBLIC_TINGYUN_APP_KEY"],docs:"https://www.tingyun.com/docs",instrumentationFile:"apps/web/src/components/monitoring/TingYunScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],Ca=An.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Rn(e){return An.find(t=>t.id===e)}function ss(e){Oe.mkdirSync(e,{recursive:!0})}function Y(e,t){ss(R.dirname(e)),Oe.writeFileSync(e,t)}function et(e,t){let o=R.join(e,".env.example");Oe.existsSync(o)?Oe.appendFileSync(o,`
1612
+ `+t):Oe.writeFileSync(o,t)}function is(e){let t=`import * as Sentry from "@sentry/nextjs";
1601
1613
 
1602
1614
  Sentry.init({
1603
1615
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
@@ -1612,21 +1624,21 @@ Sentry.init({
1612
1624
  ],
1613
1625
  environment: process.env.NODE_ENV,
1614
1626
  });
1615
- `,n=`import * as Sentry from "@sentry/nextjs";
1627
+ `,o=`import * as Sentry from "@sentry/nextjs";
1616
1628
 
1617
1629
  Sentry.init({
1618
1630
  dsn: process.env.SENTRY_DSN ?? process.env.NEXT_PUBLIC_SENTRY_DSN,
1619
1631
  tracesSampleRate: 1.0,
1620
1632
  environment: process.env.NODE_ENV,
1621
1633
  });
1622
- `,r=`import * as Sentry from "@sentry/nextjs";
1634
+ `,n=`import * as Sentry from "@sentry/nextjs";
1623
1635
 
1624
1636
  Sentry.init({
1625
1637
  dsn: process.env.SENTRY_DSN ?? process.env.NEXT_PUBLIC_SENTRY_DSN,
1626
1638
  tracesSampleRate: 1.0,
1627
1639
  environment: process.env.NODE_ENV,
1628
1640
  });
1629
- `,o=`/**
1641
+ `,r=`/**
1630
1642
  * Next.js instrumentation hook \u2014 wires Sentry into Node and Edge runtimes.
1631
1643
  * See https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation
1632
1644
  */
@@ -1640,14 +1652,14 @@ export async function register() {
1640
1652
  }
1641
1653
 
1642
1654
  export { captureRequestError as onRequestError } from "@sentry/nextjs";
1643
- `;B(C.join(e,"sentry.client.config.ts"),t),B(C.join(e,"sentry.server.config.ts"),n),B(C.join(e,"sentry.edge.config.ts"),r),B(C.join(e,"instrumentation.ts"),o)}function so(){return`# Sentry \u2014 error tracking + performance monitoring
1655
+ `;Y(R.join(e,"sentry.client.config.ts"),t),Y(R.join(e,"sentry.server.config.ts"),o),Y(R.join(e,"sentry.edge.config.ts"),n),Y(R.join(e,"instrumentation.ts"),r)}function as(){return`# Sentry \u2014 error tracking + performance monitoring
1644
1656
  # Get your DSN from https://sentry.io/settings/projects/<project>/keys/
1645
1657
  SENTRY_DSN=
1646
1658
  NEXT_PUBLIC_SENTRY_DSN=
1647
1659
  SENTRY_ORG=
1648
1660
  SENTRY_PROJECT=
1649
1661
  SENTRY_AUTH_TOKEN=
1650
- `}function io(e){let t=`/**
1662
+ `}function cs(e){let t=`/**
1651
1663
  * Next.js instrumentation hook \u2014 wires Datadog APM (dd-trace) into Node runtime.
1652
1664
  * Edge runtime is not supported by dd-trace; only nodejs is initialized.
1653
1665
  */
@@ -1664,7 +1676,7 @@ export async function register() {
1664
1676
  });
1665
1677
  }
1666
1678
  }
1667
- `,n=`"use client";
1679
+ `,o=`"use client";
1668
1680
  /**
1669
1681
  * Datadog RUM (Real User Monitoring) \u2014 browser-side tracking.
1670
1682
  * Initialize once in your root layout via <DatadogRumProvider />.
@@ -1695,7 +1707,7 @@ export function initDatadogRum(): void {
1695
1707
  });
1696
1708
  initialized = true;
1697
1709
  }
1698
- `;B(C.join(e,"instrumentation.ts"),t),B(C.join(e,"src","lib","monitoring","datadog-rum.ts"),n)}function ao(){return`# Datadog \u2014 APM + RUM
1710
+ `;Y(R.join(e,"instrumentation.ts"),t),Y(R.join(e,"src","lib","monitoring","datadog-rum.ts"),o)}function ps(){return`# Datadog \u2014 APM + RUM
1699
1711
  # Server APM (dd-trace)
1700
1712
  DD_API_KEY=
1701
1713
  DD_APP_KEY=
@@ -1710,7 +1722,7 @@ NEXT_PUBLIC_DD_SITE=datadoghq.com
1710
1722
  NEXT_PUBLIC_DD_SERVICE=sailor-web
1711
1723
  NEXT_PUBLIC_DD_ENV=production
1712
1724
  NEXT_PUBLIC_DD_VERSION=
1713
- `}function co(e){let t=`/**
1725
+ `}function ls(e){let t=`/**
1714
1726
  * Bugsnag server-side initialization.
1715
1727
  * Import this once at the top of your server entrypoint or a shared init module.
1716
1728
  */
@@ -1730,7 +1742,7 @@ export function startBugsnagServer(): void {
1730
1742
  });
1731
1743
  started = true;
1732
1744
  }
1733
- `,n=`"use client";
1745
+ `,o=`"use client";
1734
1746
  /**
1735
1747
  * Bugsnag browser initialization \u2014 wrap your app root with the returned provider.
1736
1748
  */
@@ -1759,11 +1771,11 @@ export function getBugsnagErrorBoundary() {
1759
1771
  errorBoundary = plugin.createErrorBoundary(React) as typeof errorBoundary;
1760
1772
  return errorBoundary;
1761
1773
  }
1762
- `;B(C.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),B(C.join(e,"src","lib","monitoring","bugsnag.client.tsx"),n)}function po(){return`# Bugsnag \u2014 error tracking
1774
+ `;Y(R.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),Y(R.join(e,"src","lib","monitoring","bugsnag.client.tsx"),o)}function ds(){return`# Bugsnag \u2014 error tracking
1763
1775
  BUGSNAG_API_KEY=
1764
1776
  NEXT_PUBLIC_BUGSNAG_API_KEY=
1765
1777
  APP_VERSION=
1766
- `}function lo(e){B(C.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
1778
+ `}function us(e){Y(R.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
1767
1779
  /**
1768
1780
  * \u963F\u91CC\u4E91 ARMS (Application Real-time Monitoring Service) browser agent.
1769
1781
  * Injects the official JS agent via next/script.
@@ -1784,11 +1796,11 @@ export function ArmsScript() {
1784
1796
  />
1785
1797
  );
1786
1798
  }
1787
- `)}function uo(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
1799
+ `)}function ms(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
1788
1800
  ALIYUN_ARMS_LICENSE_KEY=
1789
1801
  ALIYUN_ARMS_APP_NAME=
1790
1802
  NEXT_PUBLIC_ARMS_PID=
1791
- `}function mo(e){B(C.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
1803
+ `}function gs(e){Y(R.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
1792
1804
  /**
1793
1805
  * \u542C\u4E91 Browser Agent (\u524D\u7AEF\u6027\u80FD\u76D1\u63A7).
1794
1806
  * Docs: https://www.tingyun.com/docs
@@ -1806,12 +1818,12 @@ export function TingYunScript() {
1806
1818
  />
1807
1819
  );
1808
1820
  }
1809
- `)}function go(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
1821
+ `)}function fs(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
1810
1822
  TINGYUN_LICENSE_KEY=
1811
1823
  NEXT_PUBLIC_TINGYUN_APP_KEY=
1812
- `}async function Xt(e,t,n="global"){let r=Wt(t);if(!r||r.id==="none")return;let o=C.join(e,"apps","web");if(!be.existsSync(o))return;let s=r.id;try{switch(s){case"sentry":oo(o),Me(e,so());return;case"datadog":io(o),Me(e,ao());return;case"bugsnag":co(o),Me(e,po());return;case"aliyun-arms":lo(o),Me(e,uo());return;case"tingyun":mo(o),Me(e,go());return;default:return}}catch(a){throw console.error(`Failed to apply monitoring selection "${t}":`,a),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}import st from"fs";import fo from"path";async function Ht(e,t){let n=fo.join(e,"package.json");if(st.existsSync(n)){let r=st.readFileSync(n,"utf8"),o=JSON.parse(r);o.name=t,o.version="0.1.0",st.writeFileSync(n,JSON.stringify(o,null,2)+`
1813
- `)}}import K from"fs";import je from"path";var yo=["stripe","lemonsqueezy","chinapay","polar"];function zt(e){K.existsSync(e)&&K.rmSync(e,{recursive:!0,force:!0})}function So(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Eo(e,t){let n=je.join(e,".env.example");K.existsSync(n)?K.appendFileSync(n,`
1814
- `+t):K.writeFileSync(n,t)}function ho(e){switch(e){case"stripe":return`# Stripe
1824
+ `}async function wn(e,t,o="global"){let n=Rn(t);if(!n||n.id==="none")return;let r=R.join(e,"apps","web");if(!Oe.existsSync(r))return;let s=n.id;try{switch(s){case"sentry":is(r),et(e,as());return;case"datadog":cs(r),et(e,ps());return;case"bugsnag":ls(r),et(e,ds());return;case"aliyun-arms":us(r),et(e,ms());return;case"tingyun":gs(r),et(e,fs());return;default:return}}catch(a){throw console.error(`Failed to apply monitoring selection "${t}":`,a),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}import Ot from"fs";import ys from"path";async function Nn(e,t){let o=ys.join(e,"package.json");if(Ot.existsSync(o)){let n=Ot.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",Ot.writeFileSync(o,JSON.stringify(r,null,2)+`
1825
+ `)}}import G from"fs";import tt from"path";var Ss=["stripe","lemonsqueezy","chinapay","polar"];function xn(e){G.existsSync(e)&&G.rmSync(e,{recursive:!0,force:!0})}function Es(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function hs(e,t){let o=tt.join(e,".env.example");G.existsSync(o)?G.appendFileSync(o,`
1826
+ `+t):G.writeFileSync(o,t)}function vs(e){switch(e){case"stripe":return`# Stripe
1815
1827
  STRIPE_SECRET_KEY=
1816
1828
  STRIPE_WEBHOOK_SECRET=
1817
1829
  `;case"lemon":return`# Lemon Squeezy
@@ -1826,14 +1838,14 @@ CHINAPAY_WECHAT_ENABLED=true
1826
1838
  CHINAPAY_APP_ID=
1827
1839
  CHINAPAY_APP_SECRET=
1828
1840
  CHINAPAY_ALIPAY_ENABLED=true
1829
- `}}async function Jt(e,t){let n=je.join(e,"packages","billing");if(!K.existsSync(n))return;if(t==="none"){zt(n);return}let r=je.join(n,"src"),o=new Set(So(t));for(let a of yo)o.has(a)||zt(je.join(r,a));let s=je.join(r,"checkout","types.ts");if(K.existsSync(s)){let a=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=K.readFileSync(s,"utf8"),i=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${a}";`);i!==c&&K.writeFileSync(s,i)}Eo(e,ho(t))}import W from"fs";import Ae from"path";var en=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),it=/@sailor:([^\s*]+)/;function _o(e,t){let{providerIds:n,customEndpoint:r}=t;if(e.startsWith("provider:")){let o=e.slice(9);return{marker:e,keep:n.includes(o)}}if(e==="cn-compatible"){let o=n.some(s=>en.has(s));return{marker:e,keep:o||!!r}}if(e.startsWith("cn-instance:")){let o=e.slice(12);return{marker:e,keep:n.includes(o)}}return e==="custom-endpoint"?{marker:e,keep:!!r}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function Qt(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function Zt(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function tn(e,t){let n=e.split(`
1830
- `),r=[],o=e.includes("#"),s=0;for(;s<n.length;){let a=n[s],c=a.match(it);if(!c){r.push(a),s++;continue}let{marker:i,keep:d}=_o(c[1],t);if(i==="registry-entries"){r.push(o?Zt(a):Qt(a)),s++;continue}if(d){let m=o?Zt(a):Qt(a);m.trim().length>0&&r.push(m);let S=s+1;for(;S<n.length&&n[S].trim()!==""&&!it.test(n[S]);)r.push(n[S]),S++;S<n.length&&n[S].trim()===""&&(r.push(n[S]),S++),s=S}else{let m=s+1;for(;m<n.length&&n[m].trim()!==""&&!it.test(n[m]);)m++;m<n.length&&n[m].trim()===""&&m++,s=m}}return vo(r.join(`
1831
- `),t)}function vo(e,t){let{providerIds:n,customEndpoint:r}=t,o=new Set;for(let d of n)["openai","anthropic","google","mistral","xai"].includes(d)&&o.add(d),o.add(d.replace(/-/g,"_")),o.add(d);r&&o.add("custom");let s=/createProviderRegistry\(\{([\s\S]*?)\}\)/,a=e.match(s);if(!a)return e;let i=a[1].split(`
1832
- `).filter(d=>{let m=d.trim();if(m===""||m.startsWith("//"))return!0;let S=m.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return S?o.has(S[1]):!0}).join(`
1833
- `);return e.replace(s,`createProviderRegistry({${i}})`)}function Io(e,t){let n=Ae.join(t,"registry.ts.template"),r=W.readFileSync(n,"utf-8");return tn(r,e)}function Po(e,t){let n=Ae.join(t,".env.example.template"),r=W.readFileSync(n,"utf-8");return tn(r,e)}async function nn(e,t,n){let r=Io(t,n),o=Po(t,n),s=Ae.join(e,"packages/ai-sdk/src");await W.promises.mkdir(s,{recursive:!0}),await W.promises.writeFile(Ae.join(s,"registry.ts"),r),await W.promises.appendFile(Ae.join(e,".env.example"),`
1834
- `+o);let a={ai:"latest"},{providerIds:c,customEndpoint:i}=t;(c.includes("openai")||i||c.some(m=>en.has(m)))&&(a["@ai-sdk/openai"]="latest",a["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(a["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(a["@ai-sdk/google"]="latest"),c.includes("mistral")&&(a["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(a["@ai-sdk/openai"]="latest");let d=Ae.join(e,"package.json");if(W.existsSync(d)){let m=JSON.parse(await W.promises.readFile(d,"utf-8"));m.dependencies||(m.dependencies={});for(let[S,me]of Object.entries(a))m.dependencies[S]=me;await W.promises.writeFile(d,JSON.stringify(m,null,2)+`
1835
- `)}}import u from"fs";import E from"path";function rn(e,t){if(!u.existsSync(e))return;let n=u.readdirSync(e);for(let r of n){let o=E.join(e,r);u.statSync(o).isDirectory()?rn(o,t):t(o)}}async function on(e,t){let n=E.join(e,"package.json");if(!u.existsSync(n))return;let r=JSON.parse(u.readFileSync(n,"utf8"));if(t.orm!=="prisma"){let o=E.join(e,"packages","db");if(u.existsSync(o)){let s=E.join(o,"prisma");u.existsSync(s)&&u.rmSync(s,{recursive:!0,force:!0});let a=E.join(o,"package.json");if(u.existsSync(a)){let i=JSON.parse(u.readFileSync(a,"utf8"));i.dependencies&&delete i.dependencies["@prisma/client"],i.devDependencies&&delete i.devDependencies.prisma,u.writeFileSync(a,JSON.stringify(i,null,2)+`
1836
- `)}let c=E.join(o,"src","index.ts");u.existsSync(c)&&u.writeFileSync(c,`
1841
+ `}}async function Tn(e,t){let o=tt.join(e,"packages","billing");if(!G.existsSync(o))return;if(t==="none"){xn(o);return}let n=tt.join(o,"src"),r=new Set(Es(t));for(let a of Ss)r.has(a)||xn(tt.join(n,a));let s=tt.join(n,"checkout","types.ts");if(G.existsSync(s)){let a=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=G.readFileSync(s,"utf8"),i=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${a}";`);i!==c&&G.writeFileSync(s,i)}hs(e,vs(t))}import J from"fs";import Ue from"path";var Un=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),Ut=/@sailor:([^\s*]+)/;function _s(e,t){let{providerIds:o,customEndpoint:n}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:o.includes(r)}}if(e==="cn-compatible"){let r=o.some(s=>Un.has(s));return{marker:e,keep:r||!!n}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:o.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!n}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function kn(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function On(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function Ln(e,t){let o=e.split(`
1842
+ `),n=[],r=e.includes("#"),s=0;for(;s<o.length;){let a=o[s],c=a.match(Ut);if(!c){n.push(a),s++;continue}let{marker:i,keep:d}=_s(c[1],t);if(i==="registry-entries"){n.push(r?On(a):kn(a)),s++;continue}if(d){let m=r?On(a):kn(a);m.trim().length>0&&n.push(m);let E=s+1;for(;E<o.length&&o[E].trim()!==""&&!Ut.test(o[E]);)n.push(o[E]),E++;E<o.length&&o[E].trim()===""&&(n.push(o[E]),E++),s=E}else{let m=s+1;for(;m<o.length&&o[m].trim()!==""&&!Ut.test(o[m]);)m++;m<o.length&&o[m].trim()===""&&m++,s=m}}return Ps(n.join(`
1843
+ `),t)}function Ps(e,t){let{providerIds:o,customEndpoint:n}=t,r=new Set;for(let d of o)["openai","anthropic","google","mistral","xai"].includes(d)&&r.add(d),r.add(d.replace(/-/g,"_")),r.add(d);n&&r.add("custom");let s=/createProviderRegistry\(\{([\s\S]*?)\}\)/,a=e.match(s);if(!a)return e;let i=a[1].split(`
1844
+ `).filter(d=>{let m=d.trim();if(m===""||m.startsWith("//"))return!0;let E=m.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return E?r.has(E[1]):!0}).join(`
1845
+ `);return e.replace(s,`createProviderRegistry({${i}})`)}function Is(e,t){let o=Ue.join(t,"registry.ts.template"),n=J.readFileSync(o,"utf-8");return Ln(n,e)}function Cs(e,t){let o=Ue.join(t,".env.example.template"),n=J.readFileSync(o,"utf-8");return Ln(n,e)}async function Mn(e,t,o){let n=Is(t,o),r=Cs(t,o),s=Ue.join(e,"packages/ai-sdk/src");await J.promises.mkdir(s,{recursive:!0}),await J.promises.writeFile(Ue.join(s,"registry.ts"),n),await J.promises.appendFile(Ue.join(e,".env.example"),`
1846
+ `+r);let a={ai:"latest"},{providerIds:c,customEndpoint:i}=t;(c.includes("openai")||i||c.some(m=>Un.has(m)))&&(a["@ai-sdk/openai"]="latest",a["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(a["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(a["@ai-sdk/google"]="latest"),c.includes("mistral")&&(a["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(a["@ai-sdk/openai"]="latest");let d=Ue.join(e,"package.json");if(J.existsSync(d)){let m=JSON.parse(await J.promises.readFile(d,"utf-8"));m.dependencies||(m.dependencies={});for(let[E,Pe]of Object.entries(a))m.dependencies[E]=Pe;await J.promises.writeFile(d,JSON.stringify(m,null,2)+`
1847
+ `)}}import u from"fs";import h from"path";function Dn(e,t){if(!u.existsSync(e))return;let o=u.readdirSync(e);for(let n of o){let r=h.join(e,n);u.statSync(r).isDirectory()?Dn(r,t):t(r)}}async function jn(e,t){let o=h.join(e,"package.json");if(!u.existsSync(o))return;let n=JSON.parse(u.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=h.join(e,"packages","db");if(u.existsSync(r)){let s=h.join(r,"prisma");u.existsSync(s)&&u.rmSync(s,{recursive:!0,force:!0});let a=h.join(r,"package.json");if(u.existsSync(a)){let i=JSON.parse(u.readFileSync(a,"utf8"));i.dependencies&&delete i.dependencies["@prisma/client"],i.devDependencies&&delete i.devDependencies.prisma,u.writeFileSync(a,JSON.stringify(i,null,2)+`
1848
+ `)}let c=h.join(r,"src","index.ts");u.existsSync(c)&&u.writeFileSync(c,`
1837
1849
  export const prisma = {} as any;
1838
1850
  export const db = {} as any;
1839
1851
  export type PrismaClient = any;
@@ -1879,7 +1891,7 @@ export type UsageAggregate = any;
1879
1891
  export type UsageLedgerEntry = any;
1880
1892
  export type UsageType = any;
1881
1893
  export type UsageLedgerSource = any;
1882
- `)}r.scripts?.postinstall&&(r.scripts.postinstall=r.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let o=E.join(e,"apps");if(u.existsSync(o)){let s=u.readdirSync(o);for(let a of s){let c=E.join(o,a);if(!u.statSync(c).isDirectory())continue;let i=E.join(c,"src","app");if(!u.existsSync(i))continue;["[lang]","[locale]"].forEach(f=>{let p=E.join(i,f);if(u.existsSync(p)){let b=u.readdirSync(p);for(let Fe of b)u.renameSync(E.join(p,Fe),E.join(i,Fe));u.rmdirSync(p)}}),["src/middleware.ts","middleware.ts"].forEach(f=>{let p=E.join(c,f);u.existsSync(p)&&u.rmSync(p)});let d=E.join(c,"src","lib");u.existsSync(d)||u.mkdirSync(d,{recursive:!0});let m=E.join(d,"mock-i18n.ts");u.writeFileSync(m,`
1894
+ `)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=h.join(e,"apps");if(u.existsSync(r)){let s=u.readdirSync(r);for(let a of s){let c=h.join(r,a);if(!u.statSync(c).isDirectory())continue;let i=h.join(c,"src","app");if(!u.existsSync(i))continue;["[lang]","[locale]"].forEach(y=>{let l=h.join(i,y);if(u.existsSync(l)){let b=u.readdirSync(l);for(let rt of b)u.renameSync(h.join(l,rt),h.join(i,rt));u.rmdirSync(l)}}),["src/middleware.ts","middleware.ts"].forEach(y=>{let l=h.join(c,y);u.existsSync(l)&&u.rmSync(l)});let d=h.join(c,"src","lib");u.existsSync(d)||u.mkdirSync(d,{recursive:!0});let m=h.join(d,"mock-i18n.ts");u.writeFileSync(m,`
1883
1895
  import React from 'react';
1884
1896
  export function useTranslations(namespace?: string): any { return (key: string) => key; }
1885
1897
  export function useLocale() { return 'en'; }
@@ -1897,7 +1909,7 @@ export const useRouter = () => ({ push: (...args: any[]) => {}, replace: (...arg
1897
1909
  export default function createMiddleware(...args: any[]) { return (req: any) => req; }
1898
1910
  export function createNavigation(...args: any[]) { return { Link, redirect, usePathname, useRouter, getPathname: () => '/' }; }
1899
1911
  export function defineRouting<T>(config: T): T { return config; }
1900
- `);let me=E.join(d,"mock-i18n.d.ts");u.writeFileSync(me,`declare module '@/lib/mock-i18n' {
1912
+ `);let Pe=h.join(d,"mock-i18n.d.ts");u.writeFileSync(Pe,`declare module '@/lib/mock-i18n' {
1901
1913
  export function useTranslations(namespace?: string): any;
1902
1914
  export function useLocale(): string;
1903
1915
  export const NextIntlClientProvider: React.FC<any>;
@@ -1915,14 +1927,14 @@ export function defineRouting<T>(config: T): T { return config; }
1915
1927
  export function createNavigation(...args: any[]): any;
1916
1928
  export function defineRouting<T>(config: T): T;
1917
1929
  }
1918
- `),u.writeFileSync(E.join(d,"mock-i18n-index.ts"),`
1930
+ `),u.writeFileSync(h.join(d,"mock-i18n-index.ts"),`
1919
1931
  export * from './mock-i18n';
1920
1932
  export { default } from './mock-i18n';
1921
- `);let ge=E.join(c,"tsconfig.json");if(u.existsSync(ge))try{let f=u.readFileSync(ge,"utf8");if(f.includes('"paths": {')){let p=f.replace(/"paths":\s*\{/,`"paths": {
1933
+ `);let Ie=h.join(c,"tsconfig.json");if(u.existsSync(Ie))try{let y=u.readFileSync(Ie,"utf8");if(y.includes('"paths": {')){let l=y.replace(/"paths":\s*\{/,`"paths": {
1922
1934
  "next-intl": ["./src/lib/mock-i18n"],
1923
- "next-intl/*": ["./src/lib/mock-i18n"],`);u.writeFileSync(ge,p)}}catch{}let Ce=E.join(c,"src");u.existsSync(Ce)&&rn(Ce,f=>{if(!f.endsWith(".ts")&&!f.endsWith(".tsx"))return;let p=u.readFileSync(f,"utf8"),b=!1;f.endsWith("src/app/layout.tsx")&&p.includes("../providers")&&(p=p.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),b=!0),p=p.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),p=p.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),p.match(/locale\s*:\s*any/)&&(p=p.replace(/locale\s*:\s*any/g,"locale: string"),b=!0),p.match(/lang\s*:\s*any/)&&(p=p.replace(/lang\s*:\s*any/g,"lang: string"),b=!0),p.match(/requestLocale\s*:\s*any/)&&(p=p.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),b=!0),p.match(/\(locale\s*=\s*(.*)\)/)&&(p=p.replace(/\(locale\s*=\s*(.*)\)/g,"() "),b=!0),p.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(p=p.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),(f.endsWith("src/app/layout.tsx")||f.endsWith("src/app/sitemap.ts")||f.endsWith("src/app/robots.ts")||f.endsWith("src/components/ui/locale-switcher.tsx")||f.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(p=p.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),p=p.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),p=p.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),p=p.replace(/\(l\)\s*=>/g,"(l: any) =>"),b=!0),f.endsWith("src/i18n/request.ts")&&(p=p.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),b=!0),(p.match(/locale\s*:/)||p.match(/lang\s*:/))&&(b=!0),b&&u.writeFileSync(f,p)});let we=E.join(c,"package.json");if(u.existsSync(we)){let f=JSON.parse(u.readFileSync(we,"utf8"));f.dependencies&&delete f.dependencies["next-intl"],u.writeFileSync(we,JSON.stringify(f,null,2)+`
1924
- `)}}}}u.writeFileSync(n,JSON.stringify(r,null,2)+`
1925
- `)}import X from"fs";import ae from"path";function bo(e){let t=[ae.join(e,"packages","db"),ae.join(e,"apps","web")];for(let n of t){let r=ae.join(n,"prisma","schema.prisma");if(X.existsSync(r))return{packageDir:n,seedPath:ae.join(n,"prisma","seed.ts"),packageJsonPath:ae.join(n,"package.json")}}return null}function Ao(e){try{let t=X.readFileSync(e,"utf8"),n=new Set,r=/^\s*model\s+(\w+)\s*\{/gm,o=r.exec(t);for(;o;)n.add(o[1]),o=r.exec(t);return n}catch{return new Set}}function Co(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1935
+ "next-intl/*": ["./src/lib/mock-i18n"],`);u.writeFileSync(Ie,l)}}catch{}let Le=h.join(c,"src");u.existsSync(Le)&&Dn(Le,y=>{if(!y.endsWith(".ts")&&!y.endsWith(".tsx"))return;let l=u.readFileSync(y,"utf8"),b=!1;y.endsWith("src/app/layout.tsx")&&l.includes("../providers")&&(l=l.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),b=!0),l=l.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),l=l.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),l.match(/locale\s*:\s*any/)&&(l=l.replace(/locale\s*:\s*any/g,"locale: string"),b=!0),l.match(/lang\s*:\s*any/)&&(l=l.replace(/lang\s*:\s*any/g,"lang: string"),b=!0),l.match(/requestLocale\s*:\s*any/)&&(l=l.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),b=!0),l.match(/\(locale\s*=\s*(.*)\)/)&&(l=l.replace(/\(locale\s*=\s*(.*)\)/g,"() "),b=!0),l.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(l=l.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),(y.endsWith("src/app/layout.tsx")||y.endsWith("src/app/sitemap.ts")||y.endsWith("src/app/robots.ts")||y.endsWith("src/components/ui/locale-switcher.tsx")||y.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(l=l.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),l=l.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),l=l.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),l=l.replace(/\(l\)\s*=>/g,"(l: any) =>"),b=!0),y.endsWith("src/i18n/request.ts")&&(l=l.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),b=!0),(l.match(/locale\s*:/)||l.match(/lang\s*:/))&&(b=!0),b&&u.writeFileSync(y,l)});let Me=h.join(c,"package.json");if(u.existsSync(Me)){let y=JSON.parse(u.readFileSync(Me,"utf8"));y.dependencies&&delete y.dependencies["next-intl"],u.writeFileSync(Me,JSON.stringify(y,null,2)+`
1936
+ `)}}}}u.writeFileSync(o,JSON.stringify(n,null,2)+`
1937
+ `)}import Z from"fs";import fe from"path";function bs(e){let t=[fe.join(e,"packages","db"),fe.join(e,"apps","web")];for(let o of t){let n=fe.join(o,"prisma","schema.prisma");if(Z.existsSync(n))return{packageDir:o,seedPath:fe.join(o,"prisma","seed.ts"),packageJsonPath:fe.join(o,"package.json")}}return null}function As(e){try{let t=Z.readFileSync(e,"utf8"),o=new Set,n=/^\s*model\s+(\w+)\s*\{/gm,r=n.exec(t);for(;r;)o.add(r[1]),r=n.exec(t);return o}catch{return new Set}}function Rs(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1926
1938
  const admin = await prisma.user.create({
1927
1939
  data: {
1928
1940
  clerkId: "user_mock_admin",
@@ -1953,7 +1965,7 @@ export { default } from './mock-i18n';
1953
1965
  console.log("\\u2713 Created admin user:", admin.email);
1954
1966
  } catch (err) {
1955
1967
  console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
1956
- }`}function wo(e,t){let n=t.has("Tenant"),r=t.has("User"),o=t.has("Project"),s=Co(e,r),a=n?` let tenants: Array<{ id: string; name: string }> = [];
1968
+ }`}function ws(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),s=Rs(e,n),a=o?` let tenants: Array<{ id: string; name: string }> = [];
1957
1969
  try {
1958
1970
  tenants = await Promise.all([
1959
1971
  prisma.tenant.create({
@@ -1970,7 +1982,7 @@ export { default } from './mock-i18n';
1970
1982
  } catch (err) {
1971
1983
  console.warn("\\u26A0 Tenant creation skipped:", (err as Error).message);
1972
1984
  }`:` const tenants: Array<{ id: string; name: string }> = [];
1973
- console.log("\\u2139 No Tenant model in schema \u2014 skipping tenant seed.");`,c=o&&n?` for (const tenant of tenants) {
1985
+ console.log("\\u2139 No Tenant model in schema \u2014 skipping tenant seed.");`,c=r&&o?` for (const tenant of tenants) {
1974
1986
  try {
1975
1987
  await prisma.project.createMany({
1976
1988
  data: [
@@ -2022,12 +2034,12 @@ main()
2022
2034
  .finally(async () => {
2023
2035
  await prisma.$disconnect();
2024
2036
  });
2025
- `}function No(e){if(X.existsSync(e))try{let t=X.readFileSync(e,"utf8"),n=JSON.parse(t),r=n.scripts??{},o=!1;r["db:seed"]||(r["db:seed"]="prisma db seed",o=!0);let s=n.prisma??{};if(s.seed||(s.seed="tsx prisma/seed.ts",o=!0),!o)return;let a={...n,scripts:r,prisma:s};X.writeFileSync(e,JSON.stringify(a,null,2)+`
2026
- `)}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(`[create-sailor] Failed to patch seed scripts in ${e}: ${n}`)}}async function sn(e,t){let n=bo(e);if(n)try{let r=ae.join(n.packageDir,"prisma","schema.prisma"),o=Ao(r),s=wo(t,o),a=ae.dirname(n.seedPath);X.existsSync(a)||X.mkdirSync(a,{recursive:!0}),X.writeFileSync(n.seedPath,s),No(n.packageJsonPath)}catch(r){let o=r instanceof Error?r.message:String(r);throw console.error(`[create-sailor] Failed to generate seed data: ${o}`),new Error(`Unable to write prisma/seed.ts: ${o}`)}}import H from"fs";import ce from"path";var He=[{id:"twilio",name:"Twilio",region:"global",envVars:["TWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN","TWILIO_FROM_NUMBER"],docs:"https://www.twilio.com/docs/sms",pkgs:["twilio"]},{id:"messagebird",name:"MessageBird (Bird)",region:"global",envVars:["MESSAGEBIRD_ACCESS_KEY","MESSAGEBIRD_ORIGINATOR"],docs:"https://developers.messagebird.com/api/sms-messaging/",pkgs:["messagebird"]},{id:"plivo",name:"Plivo",region:"global",envVars:["PLIVO_AUTH_ID","PLIVO_AUTH_TOKEN","PLIVO_FROM_NUMBER"],docs:"https://www.plivo.com/docs/sms/",pkgs:["plivo"]},{id:"aliyun-sms",name:"\u963F\u91CC\u4E91\u77ED\u4FE1 Aliyun SMS",region:"cn",envVars:["ALIYUN_SMS_ACCESS_KEY","ALIYUN_SMS_ACCESS_SECRET","ALIYUN_SMS_SIGN_NAME","ALIYUN_SMS_TEMPLATE_CODE","ALIYUN_SMS_ENDPOINT"],docs:"https://help.aliyun.com/product/44282.html",pkgs:["@alicloud/dysmsapi20170525","@alicloud/openapi-client"]},{id:"tencent-sms",name:"\u817E\u8BAF\u4E91\u77ED\u4FE1 Tencent SMS",region:"cn",envVars:["TENCENT_SMS_SECRET_ID","TENCENT_SMS_SECRET_KEY","TENCENT_SMS_SDK_APP_ID","TENCENT_SMS_SIGN_NAME","TENCENT_SMS_TEMPLATE_ID","TENCENT_SMS_REGION"],docs:"https://cloud.tencent.com/document/product/382",pkgs:["tencentcloud-sdk-nodejs-sms"]},{id:"yunpian",name:"\u4E91\u7247 Yunpian",region:"cn",envVars:["YUNPIAN_API_KEY","YUNPIAN_SIGN"],docs:"https://www.yunpian.com/official/document/sms/zh_CN/introduction_product_intro",pkgs:["yunpian-nodejs-sdk"]},{id:"none",name:"None",region:"both",envVars:[],docs:""}],ji=He.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function an(e){return He.find(t=>t.id===e)}var To="@nebutra/sms",xo={twilio:"^5.3.6",messagebird:"^4.0.1",plivo:"^4.73.0","@alicloud/dysmsapi20170525":"^2.0.24","@alicloud/openapi-client":"^0.4.12","tencentcloud-sdk-nodejs-sms":"^4.0.970","yunpian-nodejs-sdk":"^0.0.2"};function at(e,t){H.mkdirSync(ce.dirname(e),{recursive:!0}),H.writeFileSync(e,t)}function Ro(e,t){let n=ce.join(e,".env.example");H.existsSync(n)?H.appendFileSync(n,`
2027
- `+t):H.writeFileSync(n,t)}function ko(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,n=e.envVars.map(r=>`${r}=`).join(`
2037
+ `}function Ns(e){if(Z.existsSync(e))try{let t=Z.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let s=o.prisma??{};if(s.seed||(s.seed="tsx prisma/seed.ts",r=!0),!r)return;let a={...o,scripts:n,prisma:s};Z.writeFileSync(e,JSON.stringify(a,null,2)+`
2038
+ `)}catch(t){let o=t instanceof Error?t.message:String(t);console.warn(`[create-sailor] Failed to patch seed scripts in ${e}: ${o}`)}}async function Fn(e,t){let o=bs(e);if(o)try{let n=fe.join(o.packageDir,"prisma","schema.prisma"),r=As(n),s=ws(t,r),a=fe.dirname(o.seedPath);Z.existsSync(a)||Z.mkdirSync(a,{recursive:!0}),Z.writeFileSync(o.seedPath,s),Ns(o.packageJsonPath)}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate seed data: ${r}`),new Error(`Unable to write prisma/seed.ts: ${r}`)}}import ee from"fs";import ye from"path";var ft=[{id:"twilio",name:"Twilio",region:"global",envVars:["TWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN","TWILIO_FROM_NUMBER"],docs:"https://www.twilio.com/docs/sms",pkgs:["twilio"]},{id:"messagebird",name:"MessageBird (Bird)",region:"global",envVars:["MESSAGEBIRD_ACCESS_KEY","MESSAGEBIRD_ORIGINATOR"],docs:"https://developers.messagebird.com/api/sms-messaging/",pkgs:["messagebird"]},{id:"plivo",name:"Plivo",region:"global",envVars:["PLIVO_AUTH_ID","PLIVO_AUTH_TOKEN","PLIVO_FROM_NUMBER"],docs:"https://www.plivo.com/docs/sms/",pkgs:["plivo"]},{id:"aliyun-sms",name:"\u963F\u91CC\u4E91\u77ED\u4FE1 Aliyun SMS",region:"cn",envVars:["ALIYUN_SMS_ACCESS_KEY","ALIYUN_SMS_ACCESS_SECRET","ALIYUN_SMS_SIGN_NAME","ALIYUN_SMS_TEMPLATE_CODE","ALIYUN_SMS_ENDPOINT"],docs:"https://help.aliyun.com/product/44282.html",pkgs:["@alicloud/dysmsapi20170525","@alicloud/openapi-client"]},{id:"tencent-sms",name:"\u817E\u8BAF\u4E91\u77ED\u4FE1 Tencent SMS",region:"cn",envVars:["TENCENT_SMS_SECRET_ID","TENCENT_SMS_SECRET_KEY","TENCENT_SMS_SDK_APP_ID","TENCENT_SMS_SIGN_NAME","TENCENT_SMS_TEMPLATE_ID","TENCENT_SMS_REGION"],docs:"https://cloud.tencent.com/document/product/382",pkgs:["tencentcloud-sdk-nodejs-sms"]},{id:"yunpian",name:"\u4E91\u7247 Yunpian",region:"cn",envVars:["YUNPIAN_API_KEY","YUNPIAN_SIGN"],docs:"https://www.yunpian.com/official/document/sms/zh_CN/introduction_product_intro",pkgs:["yunpian-nodejs-sdk"]},{id:"none",name:"None",region:"both",envVars:[],docs:""}],qa=ft.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Vn(e){return ft.find(t=>t.id===e)}var xs="@nebutra/sms",Ts={twilio:"^5.3.6",messagebird:"^4.0.1",plivo:"^4.73.0","@alicloud/dysmsapi20170525":"^2.0.24","@alicloud/openapi-client":"^0.4.12","tencentcloud-sdk-nodejs-sms":"^4.0.970","yunpian-nodejs-sdk":"^0.0.2"};function Lt(e,t){ee.mkdirSync(ye.dirname(e),{recursive:!0}),ee.writeFileSync(e,t)}function ks(e,t){let o=ye.join(e,".env.example");ee.existsSync(o)?ee.appendFileSync(o,`
2039
+ `+t):ee.writeFileSync(o,t)}function Os(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2028
2040
  `);return`${t}
2029
- ${n}
2030
- `}var Oo=`/**
2041
+ ${o}
2042
+ `}var Us=`/**
2031
2043
  * Inputs for the \`sendSms\` wrapper. Keep this surface portable across
2032
2044
  * providers \u2014 provider-specific options belong in the wrapper itself.
2033
2045
  */
@@ -2047,7 +2059,7 @@ export interface SendSmsResult {
2047
2059
  provider: string;
2048
2060
  raw?: unknown;
2049
2061
  }
2050
- `;function Uo(){return`import twilio from "twilio";
2062
+ `;function Ls(){return`import twilio from "twilio";
2051
2063
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2052
2064
 
2053
2065
  let client: ReturnType<typeof twilio> | null = null;
@@ -2082,7 +2094,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2082
2094
  }
2083
2095
 
2084
2096
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2085
- `}function Lo(){return`import messagebird from "messagebird";
2097
+ `}function Ms(){return`import messagebird from "messagebird";
2086
2098
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2087
2099
 
2088
2100
  let client: ReturnType<typeof messagebird> | null = null;
@@ -2120,7 +2132,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2120
2132
  }
2121
2133
 
2122
2134
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2123
- `}function Mo(){return`import plivo from "plivo";
2135
+ `}function Ds(){return`import plivo from "plivo";
2124
2136
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2125
2137
 
2126
2138
  let client: InstanceType<typeof plivo.Client> | null = null;
@@ -2159,7 +2171,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2159
2171
  }
2160
2172
 
2161
2173
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2162
- `}function jo(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
2174
+ `}function js(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
2163
2175
  import * as $OpenApi from "@alicloud/openapi-client";
2164
2176
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2165
2177
 
@@ -2208,7 +2220,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2208
2220
  }
2209
2221
 
2210
2222
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2211
- `}function Do(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
2223
+ `}function Fs(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
2212
2224
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2213
2225
 
2214
2226
  const SmsClient = tencentcloud.sms.v20210111.Client;
@@ -2273,7 +2285,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2273
2285
  }
2274
2286
 
2275
2287
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2276
- `}function Fo(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
2288
+ `}function Vs(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
2277
2289
  import Yunpian from "yunpian-nodejs-sdk";
2278
2290
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2279
2291
 
@@ -2325,13 +2337,13 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2325
2337
  }
2326
2338
 
2327
2339
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2328
- `}function Bo(e){switch(e){case"twilio":return Uo();case"messagebird":return Lo();case"plivo":return Mo();case"aliyun-sms":return jo();case"tencent-sms":return Do();case"yunpian":return Fo();case"none":return`export {};
2329
- `}}function Yo(e){let t={};for(let r of e.pkgs??[]){let o=xo[r];o&&(t[r]=o)}let n={name:To,version:"0.1.0",private:!0,description:`Transactional SMS via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(n,null,2)+`
2330
- `}async function cn(e,t,n="global"){if(t==="none")return;let r=an(t);if(!r)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${He.map(a=>a.id).join(", ")}`);let o=ce.join(e,"packages","sms");if(!H.existsSync(o))return;let s=ce.join(o,"src");H.existsSync(s)&&H.rmSync(s,{recursive:!0,force:!0});try{at(ce.join(o,"package.json"),Yo(r)),at(ce.join(s,"types.ts"),Oo),at(ce.join(s,"index.ts"),Bo(r.id)),Ro(e,ko(r))}catch(a){throw console.error(`Failed to apply SMS selection "${t}":`,a),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import le from"fs";import pe from"path";var ze=[{id:"r2",name:"Cloudflare R2",region:"global",envVars:["R2_ACCOUNT_ID","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY","R2_BUCKET"],docs:"https://developers.cloudflare.com/r2/api/s3/api/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"s3",name:"AWS S3",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_S3_REGION","S3_BUCKET"],docs:"https://docs.aws.amazon.com/s3/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"supabase-storage",name:"Supabase Storage",region:"global",envVars:["SUPABASE_URL","SUPABASE_SERVICE_ROLE_KEY","SUPABASE_BUCKET"],docs:"https://supabase.com/docs/guides/storage",pkg:"@supabase/supabase-js",pkgVersion:"^2.45.4"},{id:"aliyun-oss",name:"\u963F\u91CC\u4E91 OSS",region:"cn",envVars:["ALIYUN_OSS_ACCESS_KEY","ALIYUN_OSS_ACCESS_SECRET","ALIYUN_OSS_REGION","ALIYUN_OSS_BUCKET"],docs:"https://help.aliyun.com/product/31815.html",pkg:"ali-oss",pkgVersion:"^6.21.0"},{id:"tencent-cos",name:"\u817E\u8BAF\u4E91 COS",region:"cn",envVars:["TENCENT_COS_SECRET_ID","TENCENT_COS_SECRET_KEY","TENCENT_COS_BUCKET","TENCENT_COS_REGION"],docs:"https://cloud.tencent.com/document/product/436",pkg:"cos-nodejs-sdk-v5",pkgVersion:"^2.13.7"},{id:"qiniu",name:"\u4E03\u725B\u4E91 Kodo",region:"cn",envVars:["QINIU_ACCESS_KEY","QINIU_SECRET_KEY","QINIU_BUCKET","QINIU_DOMAIN"],docs:"https://developer.qiniu.com/kodo",pkg:"qiniu",pkgVersion:"^7.14.0"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function pn(e){return ze.find(t=>t.id===e)}var Vi=ze.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var de="@nebutra/storage";function ct(e,t){le.mkdirSync(pe.dirname(e),{recursive:!0}),le.writeFileSync(e,t)}function Ko(e,t){let n=pe.join(e,".env.example");le.existsSync(n)?le.appendFileSync(n,`
2331
- `+t):le.writeFileSync(n,t)}function Vo(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,n=e.envVars.map(r=>`${r}=`).join(`
2340
+ `}function Ks(e){switch(e){case"twilio":return Ls();case"messagebird":return Ms();case"plivo":return Ds();case"aliyun-sms":return js();case"tencent-sms":return Fs();case"yunpian":return Vs();case"none":return`export {};
2341
+ `}}function Ys(e){let t={};for(let n of e.pkgs??[]){let r=Ts[n];r&&(t[n]=r)}let o={name:xs,version:"0.1.0",private:!0,description:`Transactional SMS via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
2342
+ `}async function Kn(e,t,o="global"){if(t==="none")return;let n=Vn(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${ft.map(a=>a.id).join(", ")}`);let r=ye.join(e,"packages","sms");if(!ee.existsSync(r))return;let s=ye.join(r,"src");ee.existsSync(s)&&ee.rmSync(s,{recursive:!0,force:!0});try{Lt(ye.join(r,"package.json"),Ys(n)),Lt(ye.join(s,"types.ts"),Us),Lt(ye.join(s,"index.ts"),Ks(n.id)),ks(e,Os(n))}catch(a){throw console.error(`Failed to apply SMS selection "${t}":`,a),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import Ee from"fs";import Se from"path";var yt=[{id:"r2",name:"Cloudflare R2",region:"global",envVars:["R2_ACCOUNT_ID","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY","R2_BUCKET"],docs:"https://developers.cloudflare.com/r2/api/s3/api/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"s3",name:"AWS S3",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_S3_REGION","S3_BUCKET"],docs:"https://docs.aws.amazon.com/s3/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"supabase-storage",name:"Supabase Storage",region:"global",envVars:["SUPABASE_URL","SUPABASE_SERVICE_ROLE_KEY","SUPABASE_BUCKET"],docs:"https://supabase.com/docs/guides/storage",pkg:"@supabase/supabase-js",pkgVersion:"^2.45.4"},{id:"aliyun-oss",name:"\u963F\u91CC\u4E91 OSS",region:"cn",envVars:["ALIYUN_OSS_ACCESS_KEY","ALIYUN_OSS_ACCESS_SECRET","ALIYUN_OSS_REGION","ALIYUN_OSS_BUCKET"],docs:"https://help.aliyun.com/product/31815.html",pkg:"ali-oss",pkgVersion:"^6.21.0"},{id:"tencent-cos",name:"\u817E\u8BAF\u4E91 COS",region:"cn",envVars:["TENCENT_COS_SECRET_ID","TENCENT_COS_SECRET_KEY","TENCENT_COS_BUCKET","TENCENT_COS_REGION"],docs:"https://cloud.tencent.com/document/product/436",pkg:"cos-nodejs-sdk-v5",pkgVersion:"^2.13.7"},{id:"qiniu",name:"\u4E03\u725B\u4E91 Kodo",region:"cn",envVars:["QINIU_ACCESS_KEY","QINIU_SECRET_KEY","QINIU_BUCKET","QINIU_DOMAIN"],docs:"https://developer.qiniu.com/kodo",pkg:"qiniu",pkgVersion:"^7.14.0"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function Yn(e){return yt.find(t=>t.id===e)}var Qa=yt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var he="@nebutra/storage";function Mt(e,t){Ee.mkdirSync(Se.dirname(e),{recursive:!0}),Ee.writeFileSync(e,t)}function Bs(e,t){let o=Se.join(e,".env.example");Ee.existsSync(o)?Ee.appendFileSync(o,`
2343
+ `+t):Ee.writeFileSync(o,t)}function $s(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2332
2344
  `);return`${t}
2333
- ${n}
2334
- `}var $o=`/**
2345
+ ${o}
2346
+ `}var qs=`/**
2335
2347
  * Inputs for the \`uploadFile\` wrapper. Keep this surface portable across
2336
2348
  * providers \u2014 provider-specific options belong in the wrapper itself.
2337
2349
  */
@@ -2357,8 +2369,8 @@ export interface SignedUrlOptions {
2357
2369
  operation?: "get" | "put";
2358
2370
  contentType?: string;
2359
2371
  }
2360
- `;function qo(){return`/**
2361
- * @${de.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
2372
+ `;function Gs(){return`/**
2373
+ * @${he.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
2362
2374
  *
2363
2375
  * Docs: https://developers.cloudflare.com/r2/api/s3/api/
2364
2376
  */
@@ -2421,8 +2433,8 @@ export async function getSignedUrl(
2421
2433
  }
2422
2434
 
2423
2435
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2424
- `}function Go(){return`/**
2425
- * @${de.slice(1)} \u2014 AWS S3 wrapper.
2436
+ `}function Hs(){return`/**
2437
+ * @${he.slice(1)} \u2014 AWS S3 wrapper.
2426
2438
  *
2427
2439
  * Docs: https://docs.aws.amazon.com/s3/
2428
2440
  */
@@ -2486,8 +2498,8 @@ export async function getSignedUrl(
2486
2498
  }
2487
2499
 
2488
2500
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2489
- `}function Wo(){return`/**
2490
- * @${de.slice(1)} \u2014 Supabase Storage wrapper.
2501
+ `}function Ws(){return`/**
2502
+ * @${he.slice(1)} \u2014 Supabase Storage wrapper.
2491
2503
  *
2492
2504
  * Docs: https://supabase.com/docs/guides/storage
2493
2505
  */
@@ -2549,8 +2561,8 @@ export async function getSignedUrl(
2549
2561
  }
2550
2562
 
2551
2563
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2552
- `}function Xo(){return`/**
2553
- * @${de.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
2564
+ `}function Xs(){return`/**
2565
+ * @${he.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
2554
2566
  *
2555
2567
  * Docs: https://help.aliyun.com/product/31815.html
2556
2568
  */
@@ -2596,8 +2608,8 @@ export async function getSignedUrl(
2596
2608
  }
2597
2609
 
2598
2610
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2599
- `}function Ho(){return`/**
2600
- * @${de.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
2611
+ `}function zs(){return`/**
2612
+ * @${he.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
2601
2613
  *
2602
2614
  * Docs: https://cloud.tencent.com/document/product/436
2603
2615
  */
@@ -2651,8 +2663,8 @@ export async function getSignedUrl(
2651
2663
  }
2652
2664
 
2653
2665
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2654
- `}function zo(){return`/**
2655
- * @${de.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
2666
+ `}function Qs(){return`/**
2667
+ * @${he.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
2656
2668
  *
2657
2669
  * Docs: https://developer.qiniu.com/kodo
2658
2670
  */
@@ -2719,9 +2731,21 @@ export async function getSignedUrl(
2719
2731
  }
2720
2732
 
2721
2733
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2722
- `}function Jo(e){switch(e){case"r2":return qo();case"s3":return Go();case"supabase-storage":return Wo();case"aliyun-oss":return Xo();case"tencent-cos":return Ho();case"qiniu":return zo();case"none":return`export {};
2723
- `}}function Qo(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),(e.id==="r2"||e.id==="s3")&&(t["@aws-sdk/s3-request-presigner"]="^3.658.0");let n={name:de,version:"0.1.0",private:!0,description:`Object storage via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(n,null,2)+`
2724
- `}async function ln(e,t,n){if(t==="none")return;let r=pn(t);if(!r)throw new Error(`Unknown storage provider "${t}". Valid ids: ${ze.map(a=>a.id).join(", ")}`);let o=pe.join(e,"packages","storage"),s=pe.join(o,"src");le.existsSync(s)&&le.rmSync(s,{recursive:!0,force:!0}),ct(pe.join(o,"package.json"),Qo(r)),ct(pe.join(s,"types.ts"),$o),ct(pe.join(s,"index.ts"),Jo(r.id)),Ko(e,Vo(r))}import ue from"fs";import De from"path";function Zo(e){return`import Link from "next/link";
2734
+ `}function Js(e){switch(e){case"r2":return Gs();case"s3":return Hs();case"supabase-storage":return Ws();case"aliyun-oss":return Xs();case"tencent-cos":return zs();case"qiniu":return Qs();case"none":return`export {};
2735
+ `}}function Zs(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),(e.id==="r2"||e.id==="s3")&&(t["@aws-sdk/s3-request-presigner"]="^3.658.0");let o={name:he,version:"0.1.0",private:!0,description:`Object storage via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
2736
+ `}async function Bn(e,t,o){if(t==="none")return;let n=Yn(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${yt.map(a=>a.id).join(", ")}`);let r=Se.join(e,"packages","storage"),s=Se.join(r,"src");Ee.existsSync(s)&&Ee.rmSync(s,{recursive:!0,force:!0}),Mt(Se.join(r,"package.json"),Zs(n)),Mt(Se.join(s,"types.ts"),qs),Mt(Se.join(s,"index.ts"),Js(n.id)),Bs(e,$s(n))}import te from"fs";import Dt from"path";var St=[{id:"qstash",name:"Upstash QStash",region:"both",envVars:["QSTASH_TOKEN","QSTASH_CURRENT_SIGNING_KEY","QSTASH_NEXT_SIGNING_KEY"],docs:"https://upstash.com/docs/qstash",description:"Serverless HTTP-based queue"},{id:"bullmq",name:"BullMQ",region:"both",envVars:["REDIS_URL"],docs:"https://docs.bullmq.io",description:"Redis-backed job queue"},{id:"upstash",name:"Upstash Kafka",region:"both",envVars:["UPSTASH_KAFKA_REST_URL","UPSTASH_KAFKA_REST_USERNAME","UPSTASH_KAFKA_REST_PASSWORD"],docs:"https://upstash.com/docs/kafka",description:"Serverless Kafka"},{id:"sqs",name:"AWS SQS",region:"global",envVars:["AWS_SQS_QUEUE_URL","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"],docs:"https://docs.aws.amazon.com/AWSSimpleQueueService/",description:"AWS managed queue"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip queue package"}];function $n(e){return St.find(t=>t.id===e)}var oc=St.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function qn(e){return te.existsSync(e)?te.readFileSync(e,"utf-8"):null}function ei(e,t){let o=Dt.join(e,".env.example"),n=qn(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
2737
+ `);te.appendFileSync(o,s)}function ti(e,t,o){let n=Dt.join(e,".env.example"),r=qn(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?te.writeFileSync(n,r.replace(s,`${t}="${o}"`)):te.appendFileSync(n,`${t}="${o}"
2738
+ `)}async function Gn(e,t,o){let n=Dt.join(e,"packages","queue");if(t==="none"){te.existsSync(n)&&te.rmSync(n,{recursive:!0,force:!0});return}let r=$n(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${St.map(s=>s.id).join(", ")}`);te.existsSync(n)&&(ei(e,r),ti(e,"QUEUE_PROVIDER",t))}import ne from"fs";import jt from"path";var Et=[{id:"meilisearch",name:"Meilisearch",region:"both",envVars:["MEILISEARCH_HOST","MEILISEARCH_MASTER_KEY"],docs:"https://docs.meilisearch.com",description:"Self-hostable search"},{id:"typesense",name:"Typesense",region:"both",envVars:["TYPESENSE_HOST","TYPESENSE_PORT","TYPESENSE_PROTOCOL","TYPESENSE_API_KEY"],docs:"https://typesense.org/docs",description:"Open-source search"},{id:"algolia",name:"Algolia",region:"global",envVars:["ALGOLIA_APP_ID","ALGOLIA_ADMIN_API_KEY","ALGOLIA_SEARCH_API_KEY"],docs:"https://www.algolia.com/doc/",description:"Managed search as a service"},{id:"pgvector",name:"pgvector (Postgres)",region:"both",envVars:["DATABASE_URL"],docs:"https://github.com/pgvector/pgvector",description:"Postgres vector + full-text"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip search package"}];function Hn(e){return Et.find(t=>t.id===e)}var pc=Et.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Wn(e){return ne.existsSync(e)?ne.readFileSync(e,"utf-8"):null}function ni(e,t){let o=jt.join(e,".env.example"),n=Wn(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
2739
+ `);ne.appendFileSync(o,s)}function oi(e,t,o){let n=jt.join(e,".env.example"),r=Wn(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?ne.writeFileSync(n,r.replace(s,`${t}="${o}"`)):ne.appendFileSync(n,`${t}="${o}"
2740
+ `)}async function Xn(e,t,o){let n=jt.join(e,"packages","search");if(t==="none"){ne.existsSync(n)&&ne.rmSync(n,{recursive:!0,force:!0});return}let r=Hn(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Et.map(s=>s.id).join(", ")}`);ne.existsSync(n)&&(ni(e,r),oi(e,"SEARCH_PROVIDER",t))}import oe from"fs";import Ft from"path";var ht=[{id:"upstash-redis",name:"Upstash Redis",region:"both",envVars:["UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"],docs:"https://upstash.com/docs/redis",description:"Serverless Redis"},{id:"vercel-kv",name:"Vercel KV",region:"global",envVars:["KV_URL","KV_REST_API_URL","KV_REST_API_TOKEN","KV_REST_API_READ_ONLY_TOKEN"],docs:"https://vercel.com/docs/storage/vercel-kv",description:"Vercel native KV"},{id:"redis",name:"Redis (self-hosted)",region:"both",envVars:["REDIS_URL"],docs:"https://redis.io/docs/",description:"Self-hosted Redis"},{id:"dragonfly",name:"Dragonfly",region:"global",envVars:["DRAGONFLY_URL"],docs:"https://www.dragonflydb.io/docs",description:"Drop-in Redis replacement, faster"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip cache package"}];function zn(e){return ht.find(t=>t.id===e)}var fc=ht.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Qn(e){return oe.existsSync(e)?oe.readFileSync(e,"utf-8"):null}function ri(e,t){let o=Ft.join(e,".env.example"),n=Qn(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
2741
+ `);oe.appendFileSync(o,s)}function si(e,t,o){let n=Ft.join(e,".env.example"),r=Qn(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?oe.writeFileSync(n,r.replace(s,`${t}="${o}"`)):oe.appendFileSync(n,`${t}="${o}"
2742
+ `)}async function Jn(e,t,o){let n=Ft.join(e,"packages","cache");if(t==="none"){oe.existsSync(n)&&oe.rmSync(n,{recursive:!0,force:!0});return}let r=zn(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${ht.map(s=>s.id).join(", ")}`);oe.existsSync(n)&&(ri(e,r),si(e,"CACHE_PROVIDER",t))}import H from"fs";import Vt from"path";function B(e,t){let o=Vt.join(e,".env.example");if(!H.existsSync(o)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(H.readFileSync(o,"utf-8").includes(r))return;let c=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].filter(i=>i!==null).join(`
2743
+ `);H.appendFileSync(o,c)}function $(e,t,o){let n=Vt.join(e,".env.example");if(!H.existsSync(n))return;let r=H.readFileSync(n,"utf-8"),s=`${t}="${o}"`,a=new RegExp(`^${t}=.*$`,"m");if(a.test(r)){H.writeFileSync(n,r.replace(a,s));return}let c=r.endsWith(`
2744
+ `)?"":`
2745
+ `;H.appendFileSync(n,`${c}${s}
2746
+ `)}function U(e,t){let o=Vt.join(e,"packages",t);H.existsSync(o)&&H.rmSync(o,{recursive:!0,force:!0})}var vt=[{id:"novu",name:"Novu",region:"both",envVars:["NOVU_API_KEY","NOVU_APPLICATION_IDENTIFIER"],docs:"https://docs.novu.co",description:"Multi-channel notification infrastructure"},{id:"knock",name:"Knock",region:"global",envVars:["KNOCK_API_KEY","KNOCK_SIGNING_KEY","KNOCK_PUBLIC_API_KEY"],docs:"https://docs.knock.app",description:"Product notifications platform"},{id:"custom",name:"Custom (direct dispatchers)",region:"both",envVars:[],docs:"",description:"Use email + sms + push directly"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Zn(e){return vt.find(t=>t.id===e)}var Cc=vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function eo(e,t,o="global"){let n=Zn(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${vt.map(r=>r.id).join(", ")}`);if(n.id==="none"){U(e,"notifications");return}n.envVars.length>0&&B(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),$(e,"NOTIFICATIONS_PROVIDER",n.id)}var _t=[{id:"svix",name:"Svix",region:"global",envVars:["SVIX_API_TOKEN"],docs:"https://docs.svix.com",description:"Managed webhooks platform"},{id:"custom",name:"Custom (self-hosted)",region:"both",envVars:["WEBHOOK_SIGNING_SECRET"],docs:"",description:"Custom implementation with built-in package"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function to(e){return _t.find(t=>t.id===e)}var Nc=_t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function no(e,t,o="global"){let n=to(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${_t.map(r=>r.id).join(", ")}`);if(n.id==="none"){U(e,"webhooks");return}n.envVars.length>0&&B(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),$(e,"WEBHOOKS_PROVIDER",n.id)}import It from"fs";import ii from"path";var Pt=[{id:"sanity",name:"Sanity",region:"global",envVars:["SANITY_PROJECT_ID","SANITY_DATASET","SANITY_API_TOKEN","SANITY_API_VERSION"],docs:"https://www.sanity.io/docs",description:"Structured content platform with Studio"},{id:"contentful",name:"Contentful",region:"global",envVars:["CONTENTFUL_SPACE_ID","CONTENTFUL_ACCESS_TOKEN","CONTENTFUL_PREVIEW_ACCESS_TOKEN"],docs:"https://www.contentful.com/developers/docs/",description:"Headless CMS"},{id:"strapi",name:"Strapi",region:"both",envVars:["STRAPI_URL","STRAPI_API_TOKEN"],docs:"https://docs.strapi.io",description:"Open-source self-hosted CMS"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function oo(e){return Pt.find(t=>t.id===e)}var Uc=Pt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ro(e,t,o="global"){let n=oo(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${Pt.map(s=>s.id).join(", ")}`);let r=ii.join(e,"apps","studio");if(n.id==="none"){U(e,"sanity"),It.existsSync(r)&&It.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(U(e,"sanity"),It.existsSync(r)&&It.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&B(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),$(e,"CMS_PROVIDER",n.id)}var Ct=[{id:"vercel-flags",name:"Vercel Flags SDK",region:"global",envVars:["FLAGS_SECRET"],docs:"https://vercel.com/docs/workflow-collaboration/feature-flags",description:"Native Vercel feature flags"},{id:"growthbook",name:"GrowthBook",region:"both",envVars:["GROWTHBOOK_API_HOST","GROWTHBOOK_CLIENT_KEY","GROWTHBOOK_DECRYPTION_KEY"],docs:"https://docs.growthbook.io",description:"Open-source A/B testing + flags"},{id:"configcat",name:"ConfigCat",region:"global",envVars:["CONFIGCAT_SDK_KEY"],docs:"https://configcat.com/docs/",description:"Feature flag & config management"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function so(e){return Ct.find(t=>t.id===e)}var Kc=Ct.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function io(e,t,o="global"){let n=so(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${Ct.map(r=>r.id).join(", ")}`);if(n.id==="none"){U(e,"feature-flags");return}n.envVars.length>0&&B(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),$(e,"FEATURE_FLAGS_PROVIDER",n.id)}var bt=[{id:"turnstile",name:"Cloudflare Turnstile",region:"global",envVars:["NEXT_PUBLIC_TURNSTILE_SITE_KEY","TURNSTILE_SECRET_KEY"],docs:"https://developers.cloudflare.com/turnstile/",description:"Free, privacy-focused captcha alternative"},{id:"hcaptcha",name:"hCaptcha",region:"global",envVars:["NEXT_PUBLIC_HCAPTCHA_SITE_KEY","HCAPTCHA_SECRET_KEY"],docs:"https://docs.hcaptcha.com/",description:"Privacy-respecting captcha"},{id:"aliyun-slide",name:"\u963F\u91CC\u4E91\u9A8C\u8BC1\u7801 2.0",region:"cn",envVars:["ALIYUN_CAPTCHA_ACCESS_KEY_ID","ALIYUN_CAPTCHA_ACCESS_KEY_SECRET","ALIYUN_CAPTCHA_APP_KEY","NEXT_PUBLIC_ALIYUN_CAPTCHA_APP_KEY"],docs:"https://help.aliyun.com/product/28308.html",description:"\u963F\u91CC\u4E91\u667A\u80FD\u9A8C\u8BC1 (\u6ED1\u5757/\u65E0\u75D5)"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function ao(e){return bt.find(t=>t.id===e)}var Gc=bt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function co(e,t,o="global"){let n=ao(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${bt.map(r=>r.id).join(", ")}`);if(n.id==="none"){U(e,"captcha");return}n.envVars.length>0&&B(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),$(e,"CAPTCHA_PROVIDER",n.id)}import ve from"fs";import Kt from"path";async function po(e,t){let o=Kt.join(e,"packages","mcp");if(t==="off"){ve.existsSync(o)&&ve.rmSync(o,{recursive:!0,force:!0});let r=Kt.join(e,"packages","cli","src","commands","mcp-server.ts");ve.existsSync(r)&&ve.rmSync(r,{force:!0});return}let n=Kt.join(e,".env.example");if(ve.existsSync(n)){let r=ve.readFileSync(n,"utf-8"),s="# MCP Server (Agent-friendly API)";if(!r.includes(s)){let a=["","# =============================================",s,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
2747
+ `);ve.appendFileSync(n,a)}}}import nt from"fs";import lo from"path";async function uo(e,t,o){let n=lo.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){nt.existsSync(n)&&nt.rmSync(n,{recursive:!0,force:!0});return}let s=lo.join(e,".env.example");if(!nt.existsSync(s))return;let a=nt.readFileSync(s,"utf-8"),c="# Metering (usage-based billing)";if(!a.includes(c)){let i=["","# =============================================",c,"# Docs: see packages/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
2748
+ `);nt.appendFileSync(s,i)}}import _e from"fs";import ot from"path";function ai(e){return`import Link from "next/link";
2725
2749
 
2726
2750
  export default function WelcomePage() {
2727
2751
  const projectName = ${JSON.stringify(e)};
@@ -2830,7 +2854,7 @@ function Step({
2830
2854
  </li>
2831
2855
  );
2832
2856
  }
2833
- `}function es(e,t){return`# Next steps \u2014 ${e}
2857
+ `}function ci(e,t){return`# Next steps \u2014 ${e}
2834
2858
 
2835
2859
  Region: ${t}
2836
2860
 
@@ -2861,23 +2885,23 @@ After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
2861
2885
  - [Documentation](/docs)
2862
2886
  - [GitHub](https://github.com/nebutra/nebutra-sailor)
2863
2887
  - [Get free license (Individual/OPC)](https://nebutra.com/get-license)
2864
- `}async function dn(e,t){let{projectName:n,region:r}=t;try{let o=De.join(e,".sailor");ue.existsSync(o)||ue.mkdirSync(o,{recursive:!0}),ue.writeFileSync(De.join(o,"next-steps.md"),es(n,r))}catch(o){let s=o instanceof Error?o.message:String(o);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${s}`)}try{let o=De.join(e,"apps","web");if(!ue.existsSync(o))return;let s=De.join(o,"src","app","[locale]","welcome");ue.existsSync(s)||ue.mkdirSync(s,{recursive:!0}),ue.writeFileSync(De.join(s,"page.tsx"),Zo(n))}catch(o){let s=o instanceof Error?o.message:String(o);console.warn(`[create-sailor] Failed to write welcome page: ${s}`)}}var mn="create-sailor";function l(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2865
- `)}function rs(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function gn(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 fn(e){return e==="drizzle"?"drizzle":e==="none"?"none":"prisma"}function yn(e){return e==="lemon"||e==="lemonsqueezy"?"lemonsqueezy":e==="none"?"none":"stripe"}function Sn(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 En(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="none"?"none":"clerk"}function hn(e){if(!e)return["openai"];let t=e.split(",").map(n=>n.trim().toLowerCase());return t.includes("none")?[]:t}var _n={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function vn(e,t){if(!e)return"fumadocs";let n=e.toLowerCase();if(n==="fumadocs"||n==="none")return n;if(n in _n){let r=_n[n];return t?l(!0,{event:"notice",kind:"docs-fallback",requested:n,effective:"fumadocs"}):process.stdout.write(T.yellow(`\u26A0 ${r} support is coming in v1.2. Falling back to fumadocs.
2866
- `)+T.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
2867
- `)),"fumadocs"}return"fumadocs"}function In(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"}}function Pn(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function os(e){return e==="cn"?{email:"aliyun-dm",storage:"aliyun-oss",monitoring:"sentry",analytics:"baidu",sms:"aliyun-sms"}:e==="hybrid"?{email:"resend",storage:"aliyun-oss",monitoring:"sentry",analytics:"posthog",sms:"aliyun-sms"}:{email:"resend",storage:"r2",monitoring:"sentry",analytics:"posthog",sms:"twilio"}}function bn(e){return e==="cn"?"wechat":"stripe"}async function ss(){let e=new ts;e.name(mn).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(J,"-v, --version").helpOption(!1).argument("[name]","project directory",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--region <id>","global | cn | hybrid").option("--orm <id>","prisma | drizzle | none").option("--db <id>","postgres | mysql | sqlite | none").option("--auth <id>","clerk | betterauth | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").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("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | 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&&(gt(),process.exit(0));let r=!!t.json,o=!!t.dryRun,s=!!t.yes,a=s||!process.stdin.isTTY;r||ut(),l(r,{event:"start",version:J});let c=n??(s?"./my-saas-app":void 0),i;if(c)i=c;else if(a)i="./my-saas-app";else{let g=await I.group({name:()=>I.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(T.red(`\u2718 Cancelled
2868
- `)),process.exit(130)}});i=String(g.name)}let d=pt.basename(pt.resolve(i)),m=t.pm??rs(),S=!!t.region,me=!!t.auth,ge=!!t.payment,Ce=!!t.ai,we=!!t.email,f=!!t.storage,p=!!t.monitoring,b=!!t.analytics,Fe=!!t.sms,lt=t.i18n!==void 0,h,Ne,Y,Qe,V,O,U=bt(t.socialLogin),z,fe,$,x,Be;if(a){h=Pn(t.region),Ne=fn(t.orm),Y=gn(t.db);let g=ge?t.payment:bn(h);Qe=yn(g),V=Sn(g),O=En(t.auth),z=hn(t.ai),$=In(t.deploy),x=vn(t.docs,r),Be=lt?!!t.i18n:!0}else{let g={};if(S||(g.region=()=>I.select({message:"Target region?",options:[{value:"global",label:"global \u2014 \u6D77\u5916\u4F18\u5148"},{value:"cn",label:"cn \u2014 \u56FD\u5185\u4F18\u5148"},{value:"hybrid",label:"hybrid \u2014 \u53CC\u8F68\uFF08\u56FD\u5185+\u51FA\u6D77\uFF09"}],initialValue:"global"})),me||(g.auth=()=>I.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk"},{value:"betterauth",label:"Better Auth"},{value:"none",label:"None"}],initialValue:"clerk"})),!Ce){let Ve=Array.from(new Set(Ge.map(_=>_.category)));g.aiCategories=()=>I.multiselect({message:"Which AI Provider categories do you want to explore? (Select multiple)",options:Ve.map(_=>({value:_,label:_})),initialValues:["\u76F4\u63A5\u5B9E\u9A8C\u5BA4","\u7EDF\u4E00\u7F51\u5173"]}),g.aiProviders=({results:_})=>{let L=_.aiCategories||[],$e=Ge.filter(xe=>L.includes(xe.category)).map(xe=>({value:xe.id,label:`[${xe.category}] ${xe.name}`}));return $e.push({value:"custom",label:"[\u81EA\u5B9A\u4E49] Custom OpenAI-compatible endpoint"}),I.multiselect({message:"Select AI Providers (Space to select, Enter to submit)",options:$e,initialValues:["openai","anthropic"],required:!1})},g.enableCustom=({results:_})=>_.aiProviders?.includes("custom")?I.confirm({message:"Configure custom OpenAI-compatible endpoint?",initialValue:!0}):Promise.resolve(!1),g.customAiName=({results:_})=>_.enableCustom?I.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),g.customAiBaseUrl=({results:_})=>_.enableCustom?I.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:L=>{if(L.length===0)return"Base URL is required."}}):Promise.resolve(void 0),g.customAiApiKeyEnv=({results:_})=>_.enableCustom?I.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0)}let y=Object.keys(g).length>0?await I.group(g,{onCancel:()=>{process.stdout.write(T.red(`\u2718 Cancelled
2869
- `)),process.exit(130)}}):{};h=Pn(S?t.region:y.region),Ne=fn(t.orm),Y=gn(t.db);let R=ge?t.payment:bn(h);Qe=yn(R),V=Sn(R),O=En(me?t.auth:y.auth),z=Ce?hn(t.ai):y.aiProviders?.filter(Ve=>Ve!=="custom")??[],y.enableCustom&&(fe={name:y.customAiName,baseURL:y.customAiBaseUrl,apiKeyEnvName:y.customAiApiKeyEnv}),$=In(t.deploy),x=vn(t.docs,r),Be=lt?!!t.i18n:!0}let Te=os(h),ye=we?t.email:Te.email,Se=f?t.storage:Te.storage,Ee=p?t.monitoring:Te.monitoring,he=b?t.analytics:Te.analytics,_e=Fe?t.sms:Te.sms,Ye={region:h,orm:Ne,database:Y,payment:Qe,aiProviders:z,customAiEndpoint:fe,deployTarget:$,docs:x,i18n:Be,email:ye,storage:Se,monitoring:Ee,analytics:he,sms:_e},Ke=[["Project name",d],["Region",h],["Auth",O],["Social login",U.length>0?U.map(g=>Re.find(y=>y.id===g)?.name??g).join(", "):"none"],["ORM",Ne],["Database",Y],["Payment",V],["AI",Array.isArray(z)?z.join(", ")+(fe?", custom":""):String(z)],["Email",ye],["Storage",Se],["Monitoring",Ee],["Analytics",he],["SMS",_e],["Deploy Target",$],["Docs Framework",x]];r?Ke.forEach(([g,y],R)=>{l(!0,{event:"step",step:g,value:y,index:R+1,total:Ke.length})}):Ke.forEach(([g,y],R)=>{yt({index:R+1,total:Ke.length,label:g,value:y})});let An={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},Cn=Date.now();if(o){let g=z.length,y=[`clone template \u2192 ${i}`,"write nebutra.config.json",`prune template (orm=${Ne}, i18n=${Be})`,`region \u2192 ${h}`,`auth \u2192 ${O==="none"?"skip (remove packages/auth)":`configure ${O}`}`,...U.length>0?[`social-login \u2192 generate ${U.length} callback route${U.length===1?"":"s"} + SocialLoginButtons.tsx (${U.join(", ")})`]:[],`db \u2192 ${Y==="none"?"skip (remove packages/db)":`configure Prisma for ${Y}`}`,`payment \u2192 ${V==="none"?"skip (remove packages/billing)":`configure ${V}`}`,...x!=="none"?[`docs \u2192 scaffold apps/docs (${x==="fumadocs"?"fumadocs":`${x} \u2192 fumadocs fallback`})`]:[],...g>0||fe?[`ai-providers \u2192 generate registry.ts + env (${g}${fe?" + custom":""} provider${g===1&&!fe?"":"s"})`]:[],...ye!=="none"?[`email \u2192 configure ${ye}`]:[],...Se!=="none"?[`storage \u2192 configure ${Se}`]:[],...Ee!=="none"?[`monitoring \u2192 configure ${Ee}`]:[],...he!=="none"?[`analytics \u2192 configure ${he}`]:[],..._e!=="none"?[`sms \u2192 configure ${_e}`]:[],`compliance \u2192 inject ${h} boilerplate (ICP/Cookie/AIGC/Privacy)`,"welcome \u2192 generate dev welcome page","env \u2192 generate random secrets (AUTH_SECRET, JWT_SECRET)","seed \u2192 generate prisma/seed.ts (1 admin + 3 tenants)",...$!=="none"?[`deploy \u2192 inject ${$} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${m} install`,t.git===!1?"skip git init":"run git init"];if(r)y.forEach(R=>l(!0,{event:"plan",action:R})),l(!0,{event:"done",dryRun:!0});else{process.stdout.write(`
2870
- `+T.bold(`Dry run \u2014 planned actions:
2871
- `));for(let R of y)process.stdout.write(` \u2022 ${R}
2872
- `);process.stdout.write(T.dim(`
2888
+ `}async function mo(e,t){let{projectName:o,region:n}=t;try{let r=ot.join(e,".sailor");_e.existsSync(r)||_e.mkdirSync(r,{recursive:!0}),_e.writeFileSync(ot.join(r,"next-steps.md"),ci(o,n))}catch(r){let s=r instanceof Error?r.message:String(r);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${s}`)}try{let r=ot.join(e,"apps","web");if(!_e.existsSync(r))return;let s=ot.join(r,"src","app","[locale]","welcome");_e.existsSync(s)||_e.mkdirSync(s,{recursive:!0}),_e.writeFileSync(ot.join(s,"page.tsx"),ai(o))}catch(r){let s=r instanceof Error?r.message:String(r);console.warn(`[create-sailor] Failed to write welcome page: ${s}`)}}var fo="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2889
+ `)}function di(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function yo(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 So(e){return e==="drizzle"?"drizzle":e==="none"?"none":"prisma"}function Eo(e){return e==="lemon"||e==="lemonsqueezy"?"lemonsqueezy":e==="none"?"none":"stripe"}function ho(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 vo(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="none"?"none":"clerk"}function _o(e){if(!e)return["openai"];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}var Po={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Io(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in Po){let n=Po[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(x.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
2890
+ `)+x.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
2891
+ `)),"fumadocs"}return"fumadocs"}function Co(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"}}function bo(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function ui(e){return{...e==="cn"?{email:"aliyun-dm",storage:"aliyun-oss",monitoring:"sentry",analytics:"baidu",sms:"aliyun-sms"}:e==="hybrid"?{email:"resend",storage:"aliyun-oss",monitoring:"sentry",analytics:"posthog",sms:"aliyun-sms"}:{email:"resend",storage:"r2",monitoring:"sentry",analytics:"posthog",sms:"twilio"},queue:"none",search:"none",cache:e==="global"?"upstash-redis":e==="cn"?"redis":"upstash-redis",notifications:"none",webhooks:"none",cms:"none",featureFlags:"none",captcha:e==="cn"?"aliyun-slide":"turnstile",mcp:"on",metering:"auto"}}function Ao(e){return e==="cn"?"wechat":"stripe"}async function mi(){let e=new pi;e.name(fo).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(se,"-v, --version").helpOption(!1).argument("[name]","project directory",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--region <id>","global | cn | hybrid").option("--orm <id>","prisma | drizzle | none").option("--db <id>","postgres | mysql | sqlite | none").option("--auth <id>","clerk | betterauth | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").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("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | none").option("--queue <id>","qstash | bullmq | upstash | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").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(),[o]=e.args;t.help&&(Ht(),process.exit(0));let n=!!t.json,r=!!t.dryRun,s=!!t.yes,a=s||!process.stdin.isTTY;n||qt(),p(n,{event:"start",version:se});let c=o??(s?"./my-saas-app":void 0),i;if(c)i=c;else if(a)i="./my-saas-app";else{let g=await P.group({name:()=>P.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:S=>{if(S.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(x.red(`\u2718 Cancelled
2892
+ `)),process.exit(130)}});i=String(g.name)}let d=Yt.basename(Yt.resolve(i)),m=t.pm??di(),E=!!t.region,Pe=!!t.auth,Ie=!!t.payment,Le=!!t.ai,Me=!!t.email,y=!!t.storage,l=!!t.monitoring,b=!!t.analytics,rt=!!t.sms,Bt=t.i18n!==void 0,f,De,q,je,W,L,M=on(t.socialLogin),re,Ce,X,T,st;if(a){f=bo(t.region),De=So(t.orm),q=yo(t.db);let g=Ie?t.payment:Ao(f);je=Eo(g),W=ho(g),L=vo(t.auth),re=_o(t.ai),X=Co(t.deploy),T=Io(t.docs,n),st=Bt?!!t.i18n:!0}else{let g={};if(E||(g.region=()=>P.select({message:"Target region?",options:[{value:"global",label:"global \u2014 \u6D77\u5916\u4F18\u5148"},{value:"cn",label:"cn \u2014 \u56FD\u5185\u4F18\u5148"},{value:"hybrid",label:"hybrid \u2014 \u53CC\u8F68\uFF08\u56FD\u5185+\u51FA\u6D77\uFF09"}],initialValue:"global"})),Pe||(g.auth=()=>P.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk"},{value:"betterauth",label:"Better Auth"},{value:"none",label:"None"}],initialValue:"clerk"})),!Le){let pt=Array.from(new Set(ut.map(v=>v.category)));g.aiCategories=()=>P.multiselect({message:"Which AI Provider categories do you want to explore? (Select multiple)",options:pt.map(v=>({value:v,label:v})),initialValues:["\u76F4\u63A5\u5B9E\u9A8C\u5BA4","\u7EDF\u4E00\u7F51\u5173"]}),g.aiProviders=({results:v})=>{let D=v.aiCategories||[],lt=ut.filter(We=>D.includes(We.category)).map(We=>({value:We.id,label:`[${We.category}] ${We.name}`}));return lt.push({value:"custom",label:"[\u81EA\u5B9A\u4E49] Custom OpenAI-compatible endpoint"}),P.multiselect({message:"Select AI Providers (Space to select, Enter to submit)",options:lt,initialValues:["openai","anthropic"],required:!1})},g.enableCustom=({results:v})=>v.aiProviders?.includes("custom")?P.confirm({message:"Configure custom OpenAI-compatible endpoint?",initialValue:!0}):Promise.resolve(!1),g.customAiName=({results:v})=>v.enableCustom?P.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),g.customAiBaseUrl=({results:v})=>v.enableCustom?P.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:D=>{if(D.length===0)return"Base URL is required."}}):Promise.resolve(void 0),g.customAiApiKeyEnv=({results:v})=>v.enableCustom?P.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0)}let S=Object.keys(g).length>0?await P.group(g,{onCancel:()=>{process.stdout.write(x.red(`\u2718 Cancelled
2893
+ `)),process.exit(130)}}):{};f=bo(E?t.region:S.region),De=So(t.orm),q=yo(t.db);let k=Ie?t.payment:Ao(f);je=Eo(k),W=ho(k),L=vo(Pe?t.auth:S.auth),re=Le?_o(t.ai):S.aiProviders?.filter(pt=>pt!=="custom")??[],S.enableCustom&&(Ce={name:S.customAiName,baseURL:S.customAiBaseUrl,apiKeyEnvName:S.customAiApiKeyEnv}),X=Co(t.deploy),T=Io(t.docs,n),st=Bt?!!t.i18n:!0}let C=ui(f),be=Me?t.email:C.email,Ae=y?t.storage:C.storage,Re=l?t.monitoring:C.monitoring,we=b?t.analytics:C.analytics,Ne=rt?t.sms:C.sms,Fe=t.queue??C.queue,Ve=t.search??C.search,Ke=t.cache??C.cache,Ye=t.notifications??C.notifications,Be=t.webhooks??C.webhooks,$e=t.cms??C.cms,qe=t.featureFlags??C.featureFlags,Ge=t.captcha??C.captcha,it=t.mcp??C.mcp,He=t.metering??C.metering,at={region:f,orm:De,database:q,payment:je,aiProviders:re,customAiEndpoint:Ce,deployTarget:X,docs:T,i18n:st,email:be,storage:Ae,monitoring:Re,analytics:we,sms:Ne,queue:Fe,search:Ve,cache:Ke,notifications:Ye,webhooks:Be,cms:$e,featureFlags:qe,captcha:Ge,mcp:it,metering:He},ct=[["Project name",d],["Region",f],["Auth",L],["Social login",M.length>0?M.map(g=>Xe.find(S=>S.id===g)?.name??g).join(", "):"none"],["ORM",De],["Database",q],["Payment",W],["AI",Array.isArray(re)?re.join(", ")+(Ce?", custom":""):String(re)],["Email",be],["Storage",Ae],["Monitoring",Re],["Analytics",we],["SMS",Ne],["Deploy Target",X],["Docs Framework",T]];n?ct.forEach(([g,S],k)=>{p(!0,{event:"step",step:g,value:S,index:k+1,total:ct.length})}):ct.forEach(([g,S],k)=>{Xt({index:k+1,total:ct.length,label:g,value:S})});let Ro={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},wo=Date.now();if(r){let g=re.length,S=[`clone template \u2192 ${i}`,"write nebutra.config.json",`prune template (orm=${De}, i18n=${st})`,`region \u2192 ${f}`,`auth \u2192 ${L==="none"?"skip (remove packages/auth)":`configure ${L}`}`,...M.length>0?[`social-login \u2192 generate ${M.length} callback route${M.length===1?"":"s"} + SocialLoginButtons.tsx (${M.join(", ")})`]:[],`db \u2192 ${q==="none"?"skip (remove packages/db)":`configure Prisma for ${q}`}`,`payment \u2192 ${W==="none"?"skip (remove packages/billing)":`configure ${W}`}`,...T!=="none"?[`docs \u2192 scaffold apps/docs (${T==="fumadocs"?"fumadocs":`${T} \u2192 fumadocs fallback`})`]:[],...g>0||Ce?[`ai-providers \u2192 generate registry.ts + env (${g}${Ce?" + custom":""} provider${g===1&&!Ce?"":"s"})`]:[],...be!=="none"?[`email \u2192 configure ${be}`]:[],...Ae!=="none"?[`storage \u2192 configure ${Ae}`]:[],...Re!=="none"?[`monitoring \u2192 configure ${Re}`]:[],...we!=="none"?[`analytics \u2192 configure ${we}`]:[],...Ne!=="none"?[`sms \u2192 configure ${Ne}`]:[],...Fe!=="none"?[`queue \u2192 configure ${Fe}`]:[],...Ve!=="none"?[`search \u2192 configure ${Ve}`]:[],...Ke!=="none"?[`cache \u2192 configure ${Ke}`]:[],...Ye!=="none"?[`notifications \u2192 configure ${Ye}`]:[],...Be!=="none"?[`webhooks \u2192 configure ${Be}`]:[],...$e!=="none"?[`cms \u2192 configure ${$e}`]:[],...qe!=="none"?[`feature-flags \u2192 configure ${qe}`]:[],...Ge!=="none"?[`captcha \u2192 configure ${Ge}`]:[],`mcp \u2192 ${it==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${He==="off"?"disabled":He==="auto"?je!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,`compliance \u2192 inject ${f} boilerplate (ICP/Cookie/AIGC/Privacy)`,"welcome \u2192 generate dev welcome page","env \u2192 generate random secrets (AUTH_SECRET, JWT_SECRET)","seed \u2192 generate prisma/seed.ts (1 admin + 3 tenants)",...X!=="none"?[`deploy \u2192 inject ${X} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${m} install`,t.git===!1?"skip git init":"run git init"];if(n)S.forEach(k=>p(!0,{event:"plan",action:k})),p(!0,{event:"done",dryRun:!0});else{process.stdout.write(`
2894
+ `+x.bold(`Dry run \u2014 planned actions:
2895
+ `));for(let k of S)process.stdout.write(` \u2022 ${k}
2896
+ `);process.stdout.write(x.dim(`
2873
2897
  No files were written.
2874
- `))}process.exit(0)}let wn=async()=>{process.stdout.write(`
2875
- `+T.red(`\u2718 Cancelled
2876
- `)),un.existsSync(i)&&await I.confirm({message:`Cleanup partial install at ${i}?`,initialValue:!0})===!0&&(un.rmSync(i,{recursive:!0,force:!0}),process.stdout.write(T.dim(` \u2713 Removed ${i}
2877
- `))),process.exit(130)};process.on("SIGINT",wn);try{l(r,{event:"step",step:"clone",status:"start"}),await qt(i),l(r,{event:"step",step:"clone",status:"ok"}),l(r,{event:"step",step:"package",status:"start"}),await Ht(i,d),l(r,{event:"step",step:"package",status:"ok"}),l(r,{event:"step",step:"config",status:"start"}),await Nt(i,Ye),l(r,{event:"step",step:"config",status:"ok"}),l(r,{event:"step",step:"prune",status:"start"}),await on(i,Ye),l(r,{event:"step",step:"prune",status:"ok"}),l(r,{event:"step",step:"auth",choice:O,status:"start"}),await It(i,O),l(r,{event:"step",step:"auth",choice:O,status:"ok"}),U.length>0?(l(r,{event:"step",step:"social-login",providers:U,status:"start"}),await Ct(i,U,O),l(r,{event:"step",step:"social-login",providers:U,status:"ok"})):l(r,{event:"step",step:"social-login",status:"skip"}),l(r,{event:"step",step:"db",choice:Y,status:"start"}),await Rt(i,Y,d),l(r,{event:"step",step:"db",choice:Y,status:"ok"}),l(r,{event:"step",step:"payment",choice:V,status:"start"}),await Jt(i,V),l(r,{event:"step",step:"payment",choice:V,status:"ok"}),await Dt(i,ye,h),r&&l(!0,{event:"step",step:"email",choice:ye,status:"ok"}),await ln(i,Se,h),r&&l(!0,{event:"step",step:"storage",choice:Se,status:"ok"}),await Xt(i,Ee,h),r&&l(!0,{event:"step",step:"monitoring",choice:Ee,status:"ok"}),await ht(i,he,h),r&&l(!0,{event:"step",step:"analytics",choice:he,status:"ok"}),await cn(i,_e,h),r&&l(!0,{event:"step",step:"sms",choice:_e,status:"ok"}),await wt(i,h),r&&l(!0,{event:"step",step:"compliance",region:h,status:"ok"}),await Yt(i),await sn(i,O),await dn(i,{projectName:d,region:h}),l(r,{event:"step",step:"ai-providers",status:"start"});let g={providerIds:Ye.aiProviders,customEndpoint:Ye.customAiEndpoint},y=pt.join(i,"packages/ai-providers/templates");if(await nn(i,g,y),l(r,{event:"step",step:"ai-providers",status:"ok"}),l(r,{event:"step",step:"docs",status:"start"}),x!=="none"?(await Ut(i,{framework:x,projectName:d}),l(r,{event:"step",step:"docs",framework:"fumadocs",requested:x,status:"ok"})):l(r,{event:"step",step:"docs",status:"skip"}),l(r,{event:"step",step:"deploy-target",status:"start"}),$!=="none"&&await kt(i,$),l(r,{event:"step",step:"deploy-target",status:"ok"}),l(r,{event:"step",step:"env",status:"start"}),await Vt(i,An),l(r,{event:"step",step:"env",status:"ok"}),t.install!==!1){let L=m==="bun"?"bun install":`${m} install`;r?l(!0,{event:"step",step:"install",pm:m,status:"start"}):process.stdout.write(T.dim(` Installing dependencies with ${m}\u2026
2878
- `));try{Je(L,{cwd:i,stdio:r?"ignore":"inherit"}),l(r,{event:"step",step:"install",status:"ok"})}catch(ve){let $e=ve instanceof Error?ve.message:String(ve);r?l(!0,{event:"step",step:"install",status:"error",error:$e}):process.stdout.write(T.yellow(` \u26A0 install failed \u2014 run '${L}' manually.
2879
- `))}}else l(r,{event:"step",step:"install",status:"skip"});if(t.git!==!1){r&&l(!0,{event:"step",step:"git-init",status:"start"});try{Je("git init -q",{cwd:i,stdio:"ignore"}),Je("git add -A",{cwd:i,stdio:"ignore"}),Je('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:i,stdio:"ignore"}),l(r,{event:"step",step:"git-init",status:"ok"})}catch(L){let ve=L instanceof Error?L.message:String(L);r?l(!0,{event:"step",step:"git-init",status:"error",error:ve}):process.stdout.write(T.yellow(` \u26A0 git init skipped \u2014 not fatal.
2880
- `))}}else l(r,{event:"step",step:"git-init",status:"skip"});let _=Math.max(1,Math.round((Date.now()-Cn)/1e3));r?l(!0,{event:"done",status:"ok",elapsedSec:_,targetDir:i}):mt({elapsedSec:_,targetDir:i,skippedInstall:t.install===!1});try{ns({pkg:{name:mn,version:J},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(g){let y=g instanceof Error?g.message:String(g);r?l(!0,{event:"error",message:y}):process.stdout.write(T.red(`
2881
- \u2718 Failed: ${y}
2882
- `)),process.exit(1)}}ss().catch(e=>{process.stderr.write(String(e)+`
2898
+ `))}process.exit(0)}let No=async()=>{process.stdout.write(`
2899
+ `+x.red(`\u2718 Cancelled
2900
+ `)),go.existsSync(i)&&await P.confirm({message:`Cleanup partial install at ${i}?`,initialValue:!0})===!0&&(go.rmSync(i,{recursive:!0,force:!0}),process.stdout.write(x.dim(` \u2713 Removed ${i}
2901
+ `))),process.exit(130)};process.on("SIGINT",No);try{p(n,{event:"step",step:"clone",status:"start"}),await bn(i),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await Nn(i,d),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await cn(i,at),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await jn(i,at),p(n,{event:"step",step:"prune",status:"ok"}),p(n,{event:"step",step:"auth",choice:L,status:"start"}),await tn(i,L),p(n,{event:"step",step:"auth",choice:L,status:"ok"}),M.length>0?(p(n,{event:"step",step:"social-login",providers:M,status:"start"}),await sn(i,M,L),p(n,{event:"step",step:"social-login",providers:M,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:q,status:"start"}),await dn(i,q,d),p(n,{event:"step",step:"db",choice:q,status:"ok"}),p(n,{event:"step",step:"payment",choice:W,status:"start"}),await Tn(i,W),p(n,{event:"step",step:"payment",choice:W,status:"ok"}),await En(i,be,f),n&&p(!0,{event:"step",step:"email",choice:be,status:"ok"}),await Bn(i,Ae,f),n&&p(!0,{event:"step",step:"storage",choice:Ae,status:"ok"}),await wn(i,Re,f),n&&p(!0,{event:"step",step:"monitoring",choice:Re,status:"ok"}),await Jt(i,we,f),n&&p(!0,{event:"step",step:"analytics",choice:we,status:"ok"}),await Kn(i,Ne,f),n&&p(!0,{event:"step",step:"sms",choice:Ne,status:"ok"}),await Gn(i,Fe,f),n&&p(!0,{event:"step",step:"queue",choice:Fe,status:"ok"}),await Xn(i,Ve,f),n&&p(!0,{event:"step",step:"search",choice:Ve,status:"ok"}),await Jn(i,Ke,f),n&&p(!0,{event:"step",step:"cache",choice:Ke,status:"ok"}),await eo(i,Ye,f),n&&p(!0,{event:"step",step:"notifications",choice:Ye,status:"ok"}),await no(i,Be,f),n&&p(!0,{event:"step",step:"webhooks",choice:Be,status:"ok"}),await ro(i,$e,f),n&&p(!0,{event:"step",step:"cms",choice:$e,status:"ok"}),await io(i,qe,f),n&&p(!0,{event:"step",step:"feature-flags",choice:qe,status:"ok"}),await co(i,Ge,f),n&&p(!0,{event:"step",step:"captcha",choice:Ge,status:"ok"}),await po(i,it),n&&p(!0,{event:"step",step:"mcp",mode:it,status:"ok"}),await uo(i,He,je),n&&p(!0,{event:"step",step:"metering",mode:He,status:"ok"}),await an(i,f),n&&p(!0,{event:"step",step:"compliance",region:f,status:"ok"}),await _n(i),await Fn(i,L),await mo(i,{projectName:d,region:f}),p(n,{event:"step",step:"ai-providers",status:"start"});let g={providerIds:at.aiProviders,customEndpoint:at.customAiEndpoint},S=Yt.join(i,"packages/ai-providers/templates");if(await Mn(i,g,S),p(n,{event:"step",step:"ai-providers",status:"ok"}),p(n,{event:"step",step:"docs",status:"start"}),T!=="none"?(await gn(i,{framework:T,projectName:d}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:T,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),X!=="none"&&await un(i,X),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await In(i,Ro),p(n,{event:"step",step:"env",status:"ok"}),t.install!==!1){let D=m==="bun"?"bun install":`${m} install`;n?p(!0,{event:"step",step:"install",pm:m,status:"start"}):process.stdout.write(x.dim(` Installing dependencies with ${m}\u2026
2902
+ `));try{At(D,{cwd:i,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(xe){let lt=xe instanceof Error?xe.message:String(xe);n?p(!0,{event:"step",step:"install",status:"error",error:lt}):process.stdout.write(x.yellow(` \u26A0 install failed \u2014 run '${D}' manually.
2903
+ `))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{At("git init -q",{cwd:i,stdio:"ignore"}),At("git add -A",{cwd:i,stdio:"ignore"}),At('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:i,stdio:"ignore"}),p(n,{event:"step",step:"git-init",status:"ok"})}catch(D){let xe=D instanceof Error?D.message:String(D);n?p(!0,{event:"step",step:"git-init",status:"error",error:xe}):process.stdout.write(x.yellow(` \u26A0 git init skipped \u2014 not fatal.
2904
+ `))}}else p(n,{event:"step",step:"git-init",status:"skip"});let v=Math.max(1,Math.round((Date.now()-wo)/1e3));n?p(!0,{event:"done",status:"ok",elapsedSec:v,targetDir:i}):Gt({elapsedSec:v,targetDir:i,skippedInstall:t.install===!1});try{li({pkg:{name:fo,version:se},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(g){let S=g instanceof Error?g.message:String(g);n?p(!0,{event:"error",message:S}):process.stdout.write(x.red(`
2905
+ \u2718 Failed: ${S}
2906
+ `)),process.exit(1)}}mi().catch(e=>{process.stderr.write(String(e)+`
2883
2907
  `),process.exit(1)});