create-sailor 1.3.5 → 1.3.6

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 (3) hide show
  1. package/README.md +3 -3
  2. package/dist/index.js +96 -86
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -146,15 +146,15 @@ single monorepo you can extend instead of re-assembling from scratch.
146
146
 
147
147
  ## Documentation
148
148
 
149
- - **Getting Started**: [nebutra.com/docs](https://nebutra.com/docs)
150
- - **White-label Guide**: [nebutra.com/docs/whitelabel](https://nebutra.com/docs/whitelabel)
149
+ - **Getting Started**: [nebutra.com/docs/getting-started/installation](https://nebutra.com/docs/getting-started/installation)
150
+ - **Customization Guide**: [nebutra.com/docs/customization/overview](https://nebutra.com/docs/customization/overview)
151
151
  - **Licensing**: [nebutra.com/licensing](https://nebutra.com/licensing)
152
152
  - **Get Free License**: [nebutra.com/get-license](https://nebutra.com/get-license)
153
153
 
154
154
  ## License
155
155
 
156
156
  AGPL-3.0 with a commercial license exception.
157
- See [LICENSE-COMMERCIAL.md](https://github.com/nebutra/nebutra-sailor/blob/main/LICENSE-COMMERCIAL.md) for details.
157
+ See [LICENSE-COMMERCIAL.md](https://github.com/Nebutra/Nebutra-Sailor/blob/main/LICENSE-COMMERCIAL.md) for details.
158
158
  Commercial and individual licensing details: [get-license](https://nebutra.com/get-license).
159
159
 
160
160
  ---
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import"./chunk-FSRPMVAS.js";import{execSync as kt}from"child_process";import le from"fs";import dt from"path";import*as C from"@clack/prompts";import{Command as Ks}from"commander";import w from"picocolors";import Bs from"update-notifier";import Xo from"cfonts";import zo from"picocolors";import nn from"fs";import Lt from"path";import{fileURLToPath as Ho}from"url";function Wo(){try{let t=Lt.dirname(Ho(import.meta.url));for(let o=0;o<4;o++){let n=Lt.join(t,"package.json");if(nn.existsSync(n)){let r=nn.readFileSync(n,"utf-8"),i=JSON.parse(r);if(i.name==="create-sailor"&&typeof i.version=="string")return i.version}t=Lt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ee=Wo();function on(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ee}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
2
+ import"./chunk-FSRPMVAS.js";import{execSync as kt}from"child_process";import de from"fs";import ut from"path";import*as C from"@clack/prompts";import{Command as Bs}from"commander";import w from"picocolors";import Ys from"update-notifier";import Xo from"cfonts";import zo from"picocolors";import nn from"fs";import Lt from"path";import{fileURLToPath as Ho}from"url";function Wo(){try{let t=Lt.dirname(Ho(import.meta.url));for(let o=0;o<4;o++){let n=Lt.join(t,"package.json");if(nn.existsSync(n)){let r=nn.readFileSync(n,"utf-8"),i=JSON.parse(r);if(i.name==="create-sailor"&&typeof i.version=="string")return i.version}t=Lt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ee=Wo();function on(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ee}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
3
3
  `));return}Xo.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(zo.dim(` AI-Native SaaS Template \xB7 v${ee} \xB7 nebutra.com
4
4
 
5
- `))}import _ from"picocolors";var Qo={qstash:"foundation",bullmq:"foundation",upstash:"foundation",sqs:"foundation",meilisearch:"foundation",typesense:"foundation",algolia:"foundation",pgvector:"foundation",novu:"foundation",knock:"foundation",svix:"foundation","vercel-flags":"wip",growthbook:"wip",configcat:"wip",turnstile:"wip",hcaptcha:"wip","aliyun-slide":"wip"};function Jo(e){return e?Qo[e]??"stable":"stable"}function St(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function Ye(e){switch(e){case"stable":return"Production-ready.";case"foundation":return"Foundation status \u2014 types + factory are complete, but provider adapters are stub-level and require external credentials.";case"wip":return"WIP \u2014 actively being built, should not be used in production.";case"deprecated":return"Deprecated \u2014 scheduled for removal, do not use."}}function rn(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=Jo(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function Zo(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function sn(e){let t=Zo(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",i=t?"\u{1F4E7}":"*",c=["",` ${t?_.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?_.bold("Next:"):"Next:"}`,` ${n} cd ${e.targetDir}`];e.skippedInstall&&c.push(` ${n} pnpm install (if --no-install was set)`),c.push(` ${n} fill in .env.local ${t?_.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?_.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?_.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?_.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?_.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?_.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?_.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?_.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?_.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?_.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?_.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?_.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`);let s=e.previewSelections??[];if(s.length>0){let d=t?_.bold(_.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${d}`);for(let u of s){let h=St(u.status),O=` ${n} ${u.flag} (${u.provider}) ${h}`;c.push(t?_.yellow(O):O)}c.push("",` ${t?_.dim(Ye("foundation")):Ye("foundation")}`,` ${t?_.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?_.dim("See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"):"See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"}`)}c.push("",` ${t?_.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${i} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
5
+ `))}import _ from"picocolors";var Qo={qstash:"foundation",bullmq:"foundation",upstash:"foundation",sqs:"foundation",meilisearch:"foundation",typesense:"foundation",algolia:"foundation",pgvector:"foundation",novu:"foundation",knock:"foundation",svix:"foundation","vercel-flags":"wip",growthbook:"wip",configcat:"wip",turnstile:"wip",hcaptcha:"wip","aliyun-slide":"wip"};function Jo(e){return e?Qo[e]??"stable":"stable"}function qe(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function te(e){switch(e){case"stable":return"Production-ready.";case"foundation":return"Foundation status \u2014 types + factory are complete, but provider adapters are stub-level and require external credentials.";case"wip":return"WIP \u2014 actively being built, should not be used in production.";case"deprecated":return"Deprecated \u2014 scheduled for removal, do not use."}}function rn(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=Jo(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function Zo(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function sn(e){let t=Zo(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",i=t?"\u{1F4E7}":"*",c=["",` ${t?_.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?_.bold("Next:"):"Next:"}`,` ${n} cd ${e.targetDir}`];e.skippedInstall&&c.push(` ${n} pnpm install (if --no-install was set)`),c.push(` ${n} fill in .env.local ${t?_.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?_.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?_.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?_.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?_.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?_.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?_.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?_.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?_.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?_.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?_.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?_.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`);let a=e.previewSelections??[];if(a.length>0){let d=t?_.bold(_.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${d}`);for(let u of a){let h=qe(u.status),O=` ${n} ${u.flag} (${u.provider}) ${h}`;c.push(t?_.yellow(O):O)}c.push("",` ${t?_.dim(te("foundation")):te("foundation")}`,` ${t?_.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?_.dim("See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"):"See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"}`)}c.push("",` ${t?_.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${i} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
6
6
  `)+`
7
7
  `)}var er=`Usage: create-sailor [name] [options]
8
8
 
@@ -74,8 +74,8 @@ Examples:
74
74
  $ npx create-sailor@latest my-app --region=hybrid --ai=openai,deepseek
75
75
  $ npm create sailor@latest --dry-run --region=cn
76
76
  `;function an(){process.stdout.write(er)}import Et from"picocolors";function cn(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function tr(e){let t=cn()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return cn()?`${Et.dim(o)} ${Et.bold(n)} ${Et.dim(t)} ${Et.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function pn(e){process.stdout.write(tr(e)+`
77
- `)}var Mt=[{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:[]}],ca=Mt.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var nr=["openai","anthropic","google"],or=["openai"];function Dt(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...nr];return{mode:"gateway",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:o,runtimeGovernance:!0}}}case"direct":{let o=t.length>0?t:[...or];return{mode:"direct",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:o,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}import $e from"fs";import k from"path";var ln=[{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:""}],da=ln.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function dn(e){return ln.find(t=>t.id===e)}function rr(e){$e.mkdirSync(e,{recursive:!0})}function $(e,t){rr(k.dirname(e)),$e.writeFileSync(e,t)}function me(e,t){let o=k.join(e,".env.example");$e.existsSync(o)?$e.appendFileSync(o,`
78
- `+t):$e.writeFileSync(o,t)}function ir(e){let t=`"use client";
77
+ `)}var Mt=[{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:[]}],pa=Mt.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var nr=["openai","anthropic","google"],or=["openai"];function Dt(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...nr];return{mode:"gateway",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:o,runtimeGovernance:!0}}}case"direct":{let o=t.length>0?t:[...or];return{mode:"direct",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:o,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}import Ge from"fs";import k from"path";var ln=[{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:""}],ua=ln.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function dn(e){return ln.find(t=>t.id===e)}function rr(e){Ge.mkdirSync(e,{recursive:!0})}function $(e,t){rr(k.dirname(e)),Ge.writeFileSync(e,t)}function ge(e,t){let o=k.join(e,".env.example");Ge.existsSync(o)?Ge.appendFileSync(o,`
78
+ `+t):Ge.writeFileSync(o,t)}function ir(e){let t=`"use client";
79
79
  /**
80
80
  * PostHog browser SDK \u2014 lazy-initialized on first access.
81
81
  */
@@ -336,19 +336,19 @@ gdp("send");
336
336
  }
337
337
  `)}function Er(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
338
338
  NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
339
- `}async function un(e,t,o="global"){let n=dn(t);if(!n||n.id==="none")return;let r=k.join(e,"apps","web");if(!$e.existsSync(r))return;let i=n.id;try{switch(i){case"posthog":ir(r),me(e,sr());return;case"plausible":ar(r),me(e,cr());return;case"umami":pr(r),me(e,lr());return;case"mixpanel":dr(r),me(e,ur());return;case"baidu":mr(r),me(e,gr());return;case"sensors":fr(r),me(e,yr());return;case"growingio":Sr(r),me(e,Er());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.`)}}var hr="https://analytics.nebutra.com";function vr(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function mn(e,t={}){vr(t)||(async()=>{try{let o=await import("./dist-B4YTE2SQ.js");if(typeof o.createAnalyticsClient!="function")return;let n=o.createAnalyticsClient({posthog:{apiKey:process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.NEBUTRA_POSTHOG_HOST??hr},onError:()=>{}});if(typeof n?.track!="function")return;let r=n.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import U from"fs";import ge from"path";function Ft(e){U.existsSync(e)&&U.rmSync(e,{recursive:!0,force:!0})}function gn(e,t){let o=ge.join(e,".env.example");U.existsSync(o)?U.appendFileSync(o,`
340
- `+t):U.writeFileSync(o,t)}function fn(e,t){if(!U.existsSync(e))return;let o=U.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*"[^"]+"\s*\|\s*"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&U.writeFileSync(e,n)}function _r(e,t){let o=ge.join(e,"README.md");if(!U.existsSync(o)){U.writeFileSync(o,t);return}U.appendFileSync(o,`
341
- `+t)}async function yn(e,t){let o=ge.join(e,"packages","auth");if(!U.existsSync(o))return;if(t==="none"){Ft(o),_r(e,`
339
+ `}async function un(e,t,o="global"){let n=dn(t);if(!n||n.id==="none")return;let r=k.join(e,"apps","web");if(!Ge.existsSync(r))return;let i=n.id;try{switch(i){case"posthog":ir(r),ge(e,sr());return;case"plausible":ar(r),ge(e,cr());return;case"umami":pr(r),ge(e,lr());return;case"mixpanel":dr(r),ge(e,ur());return;case"baidu":mr(r),ge(e,gr());return;case"sensors":fr(r),ge(e,yr());return;case"growingio":Sr(r),ge(e,Er());return;default:return}}catch(s){throw console.error(`Failed to apply analytics selection "${t}":`,s),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var hr="https://analytics.nebutra.com";function vr(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function mn(e,t={}){vr(t)||(async()=>{try{let o=await import("./dist-B4YTE2SQ.js");if(typeof o.createAnalyticsClient!="function")return;let n=o.createAnalyticsClient({posthog:{apiKey:process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.NEBUTRA_POSTHOG_HOST??hr},onError:()=>{}});if(typeof n?.track!="function")return;let r=n.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import U from"fs";import fe from"path";function Ft(e){U.existsSync(e)&&U.rmSync(e,{recursive:!0,force:!0})}function gn(e,t){let o=fe.join(e,".env.example");U.existsSync(o)?U.appendFileSync(o,`
340
+ `+t):U.writeFileSync(o,t)}function fn(e,t){if(!U.existsSync(e))return;let o=U.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*"[^"]+"\s*\|\s*"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&U.writeFileSync(e,n)}function _r(e,t){let o=fe.join(e,"README.md");if(!U.existsSync(o)){U.writeFileSync(o,t);return}U.appendFileSync(o,`
341
+ `+t)}async function yn(e,t){let o=fe.join(e,"packages","auth");if(!U.existsSync(o))return;if(t==="none"){Ft(o),_r(e,`
342
342
  ## Auth
343
343
 
344
344
  Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth).
345
- `);return}let n=ge.join(o,"src","providers"),r=ge.join(o,"src","types.ts");if(t==="clerk"){Ft(ge.join(n,"better-auth.ts")),fn(r,"clerk"),gn(e,`# Clerk auth
345
+ `);return}let n=fe.join(o,"src","providers"),r=fe.join(o,"src","types.ts");if(t==="clerk"){Ft(fe.join(n,"better-auth.ts")),fn(r,"clerk"),gn(e,`# Clerk auth
346
346
  CLERK_PUBLISHABLE_KEY=
347
347
  CLERK_SECRET_KEY=
348
- `);return}if(t==="betterauth"){Ft(ge.join(n,"clerk.ts")),fn(r,"better-auth"),gn(e,`# Better Auth
348
+ `);return}if(t==="betterauth"){Ft(fe.join(n,"clerk.ts")),fn(r,"better-auth"),gn(e,`# Better Auth
349
349
  BETTER_AUTH_SECRET=
350
350
  BETTER_AUTH_URL=http://localhost:3000
351
- `);return}}var tt=[{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"}],Pr=new Set(tt.map(e=>e.id));function Sn(e){return tt.find(t=>t.id===e)}function En(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)Pr.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import ye from"fs";import fe from"path";function br(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
351
+ `);return}}var nt=[{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"}],Pr=new Set(nt.map(e=>e.id));function Sn(e){return nt.find(t=>t.id===e)}function En(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)Pr.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import Se from"fs";import ye from"path";function br(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
352
352
  // Generated by create-sailor \u2014 OAuth callback for ${e.name}
353
353
  // Primary auth provider: ${t}
354
354
  // Docs: ${e.docs}`,n={wechat:` const tokenRes = await fetch(
@@ -516,21 +516,21 @@ export function SocialLoginButtons() {
516
516
  </div>
517
517
  );
518
518
  }
519
- `}function hn(e){ye.mkdirSync(e,{recursive:!0})}function Ar(e,t){let o=fe.join(e,".env.example");ye.existsSync(o)?ye.appendFileSync(o,`
520
- `+t):ye.writeFileSync(o,t)}function Cr(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
519
+ `}function hn(e){Se.mkdirSync(e,{recursive:!0})}function Ar(e,t){let o=ye.join(e,".env.example");Se.existsSync(o)?Se.appendFileSync(o,`
520
+ `+t):Se.writeFileSync(o,t)}function Cr(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
521
521
  `);return`${t}
522
522
  ${o}
523
- `}async function vn(e,t,o){if(!t||t.length===0)return;let n=fe.join(e,"apps","web");if(!ye.existsSync(n))return;let r=new Set,i=[];for(let d of t){if(r.has(d))continue;r.add(d);let u=Sn(d);u&&i.push(u)}if(i.length===0)return;for(let d of i)Ar(e,Cr(d));let a=fe.join(n,"src","app","api","auth","callback");for(let d of i){let u=fe.join(a,d.id);hn(u);let h=fe.join(u,"route.ts");ye.writeFileSync(h,br(d,o))}let c=fe.join(n,"src","components","auth");hn(c);let s=fe.join(c,"SocialLoginButtons.tsx");ye.writeFileSync(s,Ir(i))}import te from"fs";import jt 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 _n(e){return ht.find(t=>t.id===e)}var Ca=ht.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Pn(e){return te.existsSync(e)?te.readFileSync(e,"utf-8"):null}function wr(e,t){let o=jt.join(e,".env.example"),n=Pn(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
524
- `);te.appendFileSync(o,i)}function Rr(e,t,o){let n=jt.join(e,".env.example"),r=Pn(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?te.writeFileSync(n,r.replace(i,`${t}="${o}"`)):te.appendFileSync(n,`${t}="${o}"
525
- `)}async function bn(e,t,o){let n=jt.join(e,"packages","cache");if(t==="none"){te.existsSync(n)&&te.rmSync(n,{recursive:!0,force:!0});return}let r=_n(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${ht.map(i=>i.id).join(", ")}`);te.existsSync(n)&&(wr(e,r),Rr(e,"CACHE_PROVIDER",t))}var vt=[{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 In(e){return vt.find(t=>t.id===e)}var Ta=vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import J from"fs";import Vt from"path";function q(e,t){let o=Vt.join(e,".env.example");if(!J.existsSync(o)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(J.readFileSync(o,"utf-8").includes(r))return;let c=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].filter(s=>s!==null).join(`
526
- `);J.appendFileSync(o,c)}function G(e,t,o){let n=Vt.join(e,".env.example");if(!J.existsSync(n))return;let r=J.readFileSync(n,"utf-8"),i=`${t}="${o}"`,a=new RegExp(`^${t}=.*$`,"m");if(a.test(r)){J.writeFileSync(n,r.replace(a,i));return}let c=r.endsWith(`
523
+ `}async function vn(e,t,o){if(!t||t.length===0)return;let n=ye.join(e,"apps","web");if(!Se.existsSync(n))return;let r=new Set,i=[];for(let d of t){if(r.has(d))continue;r.add(d);let u=Sn(d);u&&i.push(u)}if(i.length===0)return;for(let d of i)Ar(e,Cr(d));let s=ye.join(n,"src","app","api","auth","callback");for(let d of i){let u=ye.join(s,d.id);hn(u);let h=ye.join(u,"route.ts");Se.writeFileSync(h,br(d,o))}let c=ye.join(n,"src","components","auth");hn(c);let a=ye.join(c,"SocialLoginButtons.tsx");Se.writeFileSync(a,Ir(i))}import ne from"fs";import jt 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 _n(e){return ht.find(t=>t.id===e)}var wa=ht.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Pn(e){return ne.existsSync(e)?ne.readFileSync(e,"utf-8"):null}function wr(e,t){let o=jt.join(e,".env.example"),n=Pn(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
524
+ `);ne.appendFileSync(o,i)}function Rr(e,t,o){let n=jt.join(e,".env.example"),r=Pn(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ne.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ne.appendFileSync(n,`${t}="${o}"
525
+ `)}async function bn(e,t,o){let n=jt.join(e,"packages","cache");if(t==="none"){ne.existsSync(n)&&ne.rmSync(n,{recursive:!0,force:!0});return}let r=_n(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${ht.map(i=>i.id).join(", ")}`);ne.existsSync(n)&&(wr(e,r),Rr(e,"CACHE_PROVIDER",t))}var vt=[{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 In(e){return vt.find(t=>t.id===e)}var Oa=vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import J from"fs";import Vt from"path";function q(e,t){let o=Vt.join(e,".env.example");if(!J.existsSync(o)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(J.readFileSync(o,"utf-8").includes(r))return;let c=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].filter(a=>a!==null).join(`
526
+ `);J.appendFileSync(o,c)}function G(e,t,o){let n=Vt.join(e,".env.example");if(!J.existsSync(n))return;let r=J.readFileSync(n,"utf-8"),i=`${t}="${o}"`,s=new RegExp(`^${t}=.*$`,"m");if(s.test(r)){J.writeFileSync(n,r.replace(s,i));return}let c=r.endsWith(`
527
527
  `)?"":`
528
528
  `;J.appendFileSync(n,`${c}${i}
529
- `)}function K(e,t){let o=Vt.join(e,"packages",t);J.existsSync(o)&&J.rmSync(o,{recursive:!0,force:!0})}async function An(e,t,o="global"){let n=In(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${vt.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"captcha");return}n.envVars.length>0&&q(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"CAPTCHA_PROVIDER",n.id)}import Pt from"fs";import xr from"path";var _t=[{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 Cn(e){return _t.find(t=>t.id===e)}var Va=_t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function wn(e,t,o="global"){let n=Cn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${_t.map(i=>i.id).join(", ")}`);let r=xr.join(e,"apps","studio");if(n.id==="none"){K(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(K(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&q(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"CMS_PROVIDER",n.id)}import A from"fs";import I from"path";var Nr=I.join("apps","web"),Kt=I.join("src","components","compliance"),nt=I.join("src","app","[locale]");function H(e){return I.join(e,Nr)}function kr(e){A.mkdirSync(e,{recursive:!0})}function B(e,t){kr(I.dirname(e)),A.writeFileSync(e,t,"utf8")}function Bt(e,t){let o=I.join(e,".env.example");if(A.existsSync(o)){if(A.readFileSync(o,"utf8").includes(t.split(`
529
+ `)}function K(e,t){let o=Vt.join(e,"packages",t);J.existsSync(o)&&J.rmSync(o,{recursive:!0,force:!0})}async function An(e,t,o="global"){let n=In(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${vt.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"captcha");return}n.envVars.length>0&&q(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"CAPTCHA_PROVIDER",n.id)}import Pt from"fs";import xr from"path";var _t=[{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 Cn(e){return _t.find(t=>t.id===e)}var Ka=_t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function wn(e,t,o="global"){let n=Cn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${_t.map(i=>i.id).join(", ")}`);let r=xr.join(e,"apps","studio");if(n.id==="none"){K(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(K(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&q(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"CMS_PROVIDER",n.id)}import A from"fs";import I from"path";var Nr=I.join("apps","web"),Kt=I.join("src","components","compliance"),ot=I.join("src","app","[locale]");function H(e){return I.join(e,Nr)}function kr(e){A.mkdirSync(e,{recursive:!0})}function B(e,t){kr(I.dirname(e)),A.writeFileSync(e,t,"utf8")}function Bt(e,t){let o=I.join(e,".env.example");if(A.existsSync(o)){if(A.readFileSync(o,"utf8").includes(t.split(`
530
530
  `)[0]??""))return;A.appendFileSync(o,`
531
531
  `+t+`
532
532
  `)}else A.writeFileSync(o,t+`
533
- `)}var ot=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
533
+ `)}var rt=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
534
534
  > Consult a qualified lawyer in every jurisdiction you operate in before publishing.
535
535
  > \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`,Tr=`import Link from "next/link";
536
536
  import { IcpFooter } from "@/components/compliance/IcpFooter";
@@ -867,7 +867,7 @@ description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal
867
867
  lastUpdated: 2026-01-01
868
868
  ---
869
869
 
870
- ${ot}
870
+ ${rt}
871
871
 
872
872
  # Privacy Policy / \u9690\u79C1\u653F\u7B56
873
873
 
@@ -1012,7 +1012,7 @@ description: Terms governing your use of {{COMPANY_NAME}}.
1012
1012
  lastUpdated: 2026-01-01
1013
1013
  ---
1014
1014
 
1015
- ${ot}
1015
+ ${rt}
1016
1016
 
1017
1017
  # Terms of Service / \u670D\u52A1\u6761\u6B3E
1018
1018
 
@@ -1131,7 +1131,7 @@ description: Disclosure required by \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u
1131
1131
  lastUpdated: 2026-01-01
1132
1132
  ---
1133
1133
 
1134
- ${ot}
1134
+ ${rt}
1135
1135
 
1136
1136
  # AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
1137
1137
 
@@ -1213,7 +1213,7 @@ description: Notice of cross-border transfer of personal information, per PIPL.
1213
1213
  lastUpdated: 2026-01-01
1214
1214
  ---
1215
1215
 
1216
- ${ot}
1216
+ ${rt}
1217
1217
 
1218
1218
  # Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
1219
1219
 
@@ -1278,7 +1278,7 @@ description: Itemized list of personal information collected, per PIPL Article 1
1278
1278
  lastUpdated: 2026-01-01
1279
1279
  ---
1280
1280
 
1281
- ${ot}
1281
+ ${rt}
1282
1282
 
1283
1283
  # Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
1284
1284
 
@@ -1315,15 +1315,15 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
1315
1315
 
1316
1316
  \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
1317
1317
  `;async function Br(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","Footer.tsx");B(n,Tr);let r=I.join(o,"src","components","compliance","README.md");B(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(`
1318
- `))}async function Yr(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","CookieBanner.tsx");B(n,Lr)}async function $r(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,nt,"privacy","page.mdx");B(n,Dr)}async function qr(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,nt,"terms","page.mdx");B(n,Fr)}async function Gr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"IcpFooter.tsx");B(o,Or),Bt(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(`
1318
+ `))}async function Yr(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","CookieBanner.tsx");B(n,Lr)}async function $r(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,ot,"privacy","page.mdx");B(n,Dr)}async function qr(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,ot,"terms","page.mdx");B(n,Fr)}async function Gr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"IcpFooter.tsx");B(o,Or),Bt(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(`
1319
1319
  `))}async function Hr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"PublicSecurityFooter.tsx");B(o,Ur),Bt(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(`
1320
1320
  `))}async function Wr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"AigcDisclaimer.tsx");B(o,Mr),Bt(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(`
1321
- `))}async function Xr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,nt,"aigc-disclosure","page.mdx");B(o,jr)}async function zr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,nt,"cross-border-data","page.mdx");B(o,Vr)}async function Qr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,nt,"pii-collection","page.mdx");B(o,Kr)}async function Rn(e,t){try{await Br(e,t),await Yr(e,t),await $r(e,t),await qr(e,t),(t==="cn"||t==="hybrid")&&(await Gr(e),await Hr(e),await Wr(e),await Xr(e),await zr(e),await Qr(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 Jr from"fs";import Zr from"path";async function xn(e,t){let o=Zr.join(e,"nebutra.config.json");Jr.writeFileSync(o,JSON.stringify(t,null,2)+`
1322
- `)}import ne from"fs";import Yt from"path";function ei(e){ne.existsSync(e)&&ne.rmSync(e,{recursive:!0,force:!0})}function Nn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function ti(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function kn(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 ni(e,t){let o=Yt.join(e,".env.example");ne.existsSync(o)?ne.appendFileSync(o,`
1323
- `+t):ne.writeFileSync(o,t)}async function Tn(e,t,o){let n=Yt.join(e,"packages","db");if(t==="none"){ei(n);return}let r=Yt.join(n,"prisma","schema.prisma"),i;if(t==="postgresql"?i=`postgresql://postgres:postgres@localhost:5432/${o}`:t==="mysql"?i=`mysql://root:root@localhost:3306/${o}`:i="file:./dev.db",ni(e,`# Database (${t})
1321
+ `))}async function Xr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"aigc-disclosure","page.mdx");B(o,jr)}async function zr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"cross-border-data","page.mdx");B(o,Vr)}async function Qr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"pii-collection","page.mdx");B(o,Kr)}async function Rn(e,t){try{await Br(e,t),await Yr(e,t),await $r(e,t),await qr(e,t),(t==="cn"||t==="hybrid")&&(await Gr(e),await Hr(e),await Wr(e),await Xr(e),await zr(e),await Qr(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 Jr from"fs";import Zr from"path";async function xn(e,t){let o=Zr.join(e,"nebutra.config.json");Jr.writeFileSync(o,JSON.stringify(t,null,2)+`
1322
+ `)}import oe from"fs";import Yt from"path";function ei(e){oe.existsSync(e)&&oe.rmSync(e,{recursive:!0,force:!0})}function Nn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function ti(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function kn(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 ni(e,t){let o=Yt.join(e,".env.example");oe.existsSync(o)?oe.appendFileSync(o,`
1323
+ `+t):oe.writeFileSync(o,t)}async function Tn(e,t,o){let n=Yt.join(e,"packages","db");if(t==="none"){ei(n);return}let r=Yt.join(n,"prisma","schema.prisma"),i;if(t==="postgresql"?i=`postgresql://postgres:postgres@localhost:5432/${o}`:t==="mysql"?i=`mysql://root:root@localhost:3306/${o}`:i="file:./dev.db",ni(e,`# Database (${t})
1324
1324
  DATABASE_URL="${i}"
1325
- `),!ne.existsSync(r))return;let a=ne.readFileSync(r,"utf8"),c=a;t==="mysql"?(c=Nn(c,"mysql"),c=kn(c)):t==="sqlite"&&(c=Nn(c,"sqlite"),c=ti(c),c=kn(c)),c!==a&&ne.writeFileSync(r,c)}import rt from"fs";import L from"path";import{fileURLToPath as oi}from"url";var ri=oi(import.meta.url),ii=L.dirname(ri);async function On(e,t){if(t==="none")return;let o=L.join(ii,"../../templates/deploy");t==="vercel"?await rt.promises.copyFile(L.join(o,"vercel.json"),L.join(e,"vercel.json")):t==="railway"?await rt.promises.copyFile(L.join(o,"railway.toml"),L.join(e,"railway.toml")):t==="cloudflare"?await rt.promises.copyFile(L.join(o,"wrangler.toml"),L.join(e,"wrangler.toml")):t==="selfhost"&&(await rt.promises.copyFile(L.join(o,"docker-compose.yml"),L.join(e,"docker-compose.yml")),await rt.promises.copyFile(L.join(o,"Dockerfile.web"),L.join(e,"Dockerfile.web")))}import oe from"fs";import Se from"path";import{fileURLToPath as si}from"url";var ai=si(import.meta.url),Un=Se.dirname(ai),ci=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml)$/;function pi(e){let t=[Se.join(Un,"..","templates","docs",e),Se.join(Un,"..","..","templates","docs",e)];for(let o of t)if(oe.existsSync(o))return o;return t[0]}async function Ln(e,t){if(t.framework==="none")return;let o=(t.framework==="fumadocs","fumadocs"),n=pi(o),r=Se.join(e,"apps","docs");if(!oe.existsSync(n))throw new Error(`Docs template not found: ${n}`);Mn(n,r),Dn(r,{"{PRODUCT_NAME}":t.projectName})}function Mn(e,t){oe.mkdirSync(t,{recursive:!0});for(let o of oe.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name),r=Se.join(t,o.name);o.isDirectory()?Mn(n,r):oe.copyFileSync(n,r)}}function Dn(e,t){for(let o of oe.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name);if(o.isDirectory())Dn(n,t);else if(ci.test(o.name)){let r=oe.readFileSync(n,"utf-8");for(let[i,a]of Object.entries(t))r=r.split(i).join(a);oe.writeFileSync(n,r)}}}import he from"fs";import Ee from"path";var bt=[{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 Fn(e){return bt.find(t=>t.id===e)}var lc=bt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var ve="@nebutra/email";function $t(e,t){he.mkdirSync(Ee.dirname(e),{recursive:!0}),he.writeFileSync(e,t)}function li(e,t){let o=Ee.join(e,".env.example");he.existsSync(o)?he.appendFileSync(o,`
1326
- `+t):he.writeFileSync(o,t)}function di(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
1325
+ `),!oe.existsSync(r))return;let s=oe.readFileSync(r,"utf8"),c=s;t==="mysql"?(c=Nn(c,"mysql"),c=kn(c)):t==="sqlite"&&(c=Nn(c,"sqlite"),c=ti(c),c=kn(c)),c!==s&&oe.writeFileSync(r,c)}import it from"fs";import L from"path";import{fileURLToPath as oi}from"url";var ri=oi(import.meta.url),ii=L.dirname(ri);async function On(e,t){if(t==="none")return;let o=L.join(ii,"../../templates/deploy");t==="vercel"?await it.promises.copyFile(L.join(o,"vercel.json"),L.join(e,"vercel.json")):t==="railway"?await it.promises.copyFile(L.join(o,"railway.toml"),L.join(e,"railway.toml")):t==="cloudflare"?await it.promises.copyFile(L.join(o,"wrangler.toml"),L.join(e,"wrangler.toml")):t==="selfhost"&&(await it.promises.copyFile(L.join(o,"docker-compose.yml"),L.join(e,"docker-compose.yml")),await it.promises.copyFile(L.join(o,"Dockerfile.web"),L.join(e,"Dockerfile.web")))}import re from"fs";import Ee from"path";import{fileURLToPath as si}from"url";var ai=si(import.meta.url),Un=Ee.dirname(ai),ci=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml)$/;function pi(e){let t=[Ee.join(Un,"..","templates","docs",e),Ee.join(Un,"..","..","templates","docs",e)];for(let o of t)if(re.existsSync(o))return o;return t[0]}async function Ln(e,t){if(t.framework==="none")return;let o=(t.framework==="fumadocs","fumadocs"),n=pi(o),r=Ee.join(e,"apps","docs");if(!re.existsSync(n))throw new Error(`Docs template not found: ${n}`);Mn(n,r),Dn(r,{"{PRODUCT_NAME}":t.projectName})}function Mn(e,t){re.mkdirSync(t,{recursive:!0});for(let o of re.readdirSync(e,{withFileTypes:!0})){let n=Ee.join(e,o.name),r=Ee.join(t,o.name);o.isDirectory()?Mn(n,r):re.copyFileSync(n,r)}}function Dn(e,t){for(let o of re.readdirSync(e,{withFileTypes:!0})){let n=Ee.join(e,o.name);if(o.isDirectory())Dn(n,t);else if(ci.test(o.name)){let r=re.readFileSync(n,"utf-8");for(let[i,s]of Object.entries(t))r=r.split(i).join(s);re.writeFileSync(n,r)}}}import ve from"fs";import he from"path";var bt=[{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 Fn(e){return bt.find(t=>t.id===e)}var dc=bt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var _e="@nebutra/email";function $t(e,t){ve.mkdirSync(he.dirname(e),{recursive:!0}),ve.writeFileSync(e,t)}function li(e,t){let o=he.join(e,".env.example");ve.existsSync(o)?ve.appendFileSync(o,`
1326
+ `+t):ve.writeFileSync(o,t)}function di(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
1327
1327
  `);return`${t}
1328
1328
  ${o}
1329
1329
  `}var ui=`/**
@@ -1347,7 +1347,7 @@ export interface SendEmailResult {
1347
1347
  raw?: unknown;
1348
1348
  }
1349
1349
  `;function mi(){return`/**
1350
- * @${ve.slice(1)} \u2014 Resend transactional email wrapper.
1350
+ * @${_e.slice(1)} \u2014 Resend transactional email wrapper.
1351
1351
  *
1352
1352
  * Docs: https://resend.com/docs
1353
1353
  */
@@ -1386,7 +1386,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1386
1386
 
1387
1387
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1388
1388
  `}function gi(){return`/**
1389
- * @${ve.slice(1)} \u2014 Postmark transactional email wrapper.
1389
+ * @${_e.slice(1)} \u2014 Postmark transactional email wrapper.
1390
1390
  *
1391
1391
  * Docs: https://postmarkapp.com/developer
1392
1392
  */
@@ -1424,7 +1424,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1424
1424
 
1425
1425
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1426
1426
  `}function fi(){return`/**
1427
- * @${ve.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
1427
+ * @${_e.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
1428
1428
  *
1429
1429
  * Docs: https://docs.aws.amazon.com/ses
1430
1430
  */
@@ -1480,7 +1480,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1480
1480
 
1481
1481
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1482
1482
  `}function yi(){return`/**
1483
- * @${ve.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
1483
+ * @${_e.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
1484
1484
  *
1485
1485
  * Docs: https://help.aliyun.com/product/29412.html
1486
1486
  */
@@ -1530,7 +1530,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1530
1530
 
1531
1531
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1532
1532
  `}function Si(){return`/**
1533
- * @${ve.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
1533
+ * @${_e.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
1534
1534
  *
1535
1535
  * Docs: https://cloud.tencent.com/document/product/1288
1536
1536
  */
@@ -1578,7 +1578,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1578
1578
 
1579
1579
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1580
1580
  `}function Ei(){return`/**
1581
- * @${ve.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
1581
+ * @${_e.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
1582
1582
  *
1583
1583
  * Docs: https://qiye.163.com/help
1584
1584
  */
@@ -1616,8 +1616,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1616
1616
 
1617
1617
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1618
1618
  `}function hi(e){switch(e){case"resend":return mi();case"postmark":return gi();case"ses":return fi();case"aliyun-dm":return yi();case"tencent-ses":return Si();case"netease":return Ei();case"none":return`export {};
1619
- `}}function vi(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:ve,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)+`
1620
- `}async function jn(e,t,o){if(t==="none")return;let n=Fn(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${bt.map(a=>a.id).join(", ")}`);let r=Ee.join(e,"packages","email"),i=Ee.join(r,"src");he.existsSync(i)&&he.rmSync(i,{recursive:!0,force:!0}),$t(Ee.join(r,"package.json"),vi(n)),$t(Ee.join(i,"types.ts"),ui),$t(Ee.join(i,"index.ts"),hi(n.id)),li(e,di(n))}import It from"fs";import Vn from"path";async function Kn(e,t){let o=`# Automatically injected by create-sailor
1619
+ `}}function vi(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:_e,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)+`
1620
+ `}async function jn(e,t,o){if(t==="none")return;let n=Fn(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${bt.map(s=>s.id).join(", ")}`);let r=he.join(e,"packages","email"),i=he.join(r,"src");ve.existsSync(i)&&ve.rmSync(i,{recursive:!0,force:!0}),$t(he.join(r,"package.json"),vi(n)),$t(he.join(i,"types.ts"),ui),$t(he.join(i,"index.ts"),hi(n.id)),li(e,di(n))}import It from"fs";import Vn from"path";async function Kn(e,t){let o=`# Automatically injected by create-sailor
1621
1621
  DATABASE_URL="${String(t.databaseUrl)}"
1622
1622
 
1623
1623
  NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
@@ -1625,13 +1625,13 @@ CLERK_SECRET_KEY="${String(t.clerkSecret)}"
1625
1625
 
1626
1626
  NEXT_PUBLIC_SITE_URL="http://localhost:3000"
1627
1627
  `,n=Vn.join(e,".env"),r=Vn.join(e,".env.local");!It.existsSync(n)&&!It.existsSync(r)?It.writeFileSync(r,o):It.appendFileSync(r,`
1628
- `+o)}import Yn from"crypto";import it from"fs";import Bn from"path";function _e(e){return Yn.randomBytes(e).toString("base64").replace(/=+$/,"")}function _i(e){return Yn.randomBytes(e).toString("hex")}function Pi(){return{AUTH_SECRET:_e(32),NEXTAUTH_SECRET:_e(32),BETTER_AUTH_SECRET:_e(32),JWT_SECRET:_e(32),WEBHOOK_SECRET:_i(16),ENCRYPTION_KEY:_e(32),API_SECRET_KEY:_e(32),SESSION_SECRET:_e(32)}}function bi(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Ii(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=bi(o);return e.replace(n,`${t}="${r}"`)}async function $n(e){let t=Bn.join(e,".env.example"),o=Bn.join(e,".env.local");if(!it.existsSync(t))return null;try{let n=it.readFileSync(t,"utf8"),r=Pi(),a=it.existsSync(o)?it.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))a=Ii(a,c,r[c]);return it.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}`)}}var At=[{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 qn(e){return At.find(t=>t.id===e)}var bc=At.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Gn(e,t,o="global"){let n=qn(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${At.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"feature-flags");return}n.envVars.length>0&&q(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{execFileSync as Xn}from"child_process";import x from"fs";import Ai from"os";import re from"path";import Ci from"ignore";var wi={mirror:{repo:process.env.SAILOR_TEMPLATE_REPO||"Nebutra/Sailor-Template",ref:process.env.SAILOR_TEMPLATE_REF||"main",applyIgnore:!1,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"},main:{repo:"Nebutra/Nebutra-Sailor",ref:"main",applyIgnore:!0,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"}};function Ri(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function xi(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function zn(e){return/^[0-9a-f]{7,40}$/i.test(e)}function Ni(e,t){let o=`https://github.com/${e}.git`,n=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of n)try{let i=Xn("git",["ls-remote",o,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!i)continue;let[a]=i.split(/\s+/);if(zn(a))return a}catch{}return null}async function ki(e,t){if(zn(t))return t;let o=await fetch(`https://api.github.com/repos/${e}/commits/${encodeURIComponent(t)}`,{headers:{Accept:"application/vnd.github+json","User-Agent":"create-sailor"}});if(!o.ok){let r=Ni(e,t);if(r)return r;throw new Error(`Failed to resolve ${e}@${t} (GitHub API ${o.status})`)}let n=await o.json();if(typeof n.sha!="string"||n.sha.length===0)throw new Error(`GitHub API did not return a commit SHA for ${e}@${t}`);return n.sha}function Qn(e,t,o){let n=x.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let i=re.join(t,r.name),a=re.relative(e,i).split(re.sep).join("/");r.isDirectory()?(o.push(a+"/"),Qn(e,i,o)):o.push(a)}}function Ti(e){let t=re.join(e,".templateignore");if(!x.existsSync(t))return;let o=x.readFileSync(t,"utf8"),n=Ci().add(o),r=[];Qn(e,e,r);let i=r.map(s=>s.endsWith("/")?s.slice(0,-1):s),a=new Set(n.filter(i)),c=i.filter(s=>!a.has(s)).sort((s,d)=>d.split("/").length-s.split("/").length);for(let s of c){let d=re.join(e,s);try{x.existsSync(d)&&x.rmSync(d,{recursive:!0,force:!0})}catch{}}try{x.existsSync(t)&&x.rmSync(t,{force:!0})}catch{}}async function Hn(e,t){let o=await fetch(e,{headers:{Accept:"application/octet-stream","User-Agent":"create-sailor"}});if(!o.ok)throw new Error(`Failed to download archive (${o.status})`);let n=Buffer.from(await o.arrayBuffer());if(n.byteLength<1024)throw new Error(`Downloaded archive is unexpectedly small (${n.byteLength} bytes)`);x.writeFileSync(t,n);let r=x.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function Wn(e,t){Xn("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function Jn(e){try{let t=x.readdirSync(e);for(let o of t)x.rmSync(re.join(e,o),{recursive:!0,force:!0})}catch{}}async function Oi(e,t){let o=x.mkdtempSync(re.join(Ai.tmpdir(),"create-sailor-")),n=re.join(o,"template.tar.gz");try{let r=await ki(e.repo,e.ref);await Hn(xi(e.repo,r),n),Wn(n,t)}catch(r){if(!e.allowMutableFallback)throw r;Jn(t),await Hn(Ri(e.repo,e.ref),n),Wn(n,t)}finally{x.rmSync(o,{recursive:!0,force:!0})}}async function Zn(e){x.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let i=wi[r];try{if(await Oi(i,e),i.applyIgnore)try{Ti(e)}catch(a){throw new Error(`Template cloned, but .templateignore processing failed: ${a instanceof Error?a.message:String(a)}`)}return}catch(a){n=a instanceof Error?a:new Error(String(a)),Jn(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
1628
+ `+o)}import Yn from"crypto";import st from"fs";import Bn from"path";function Pe(e){return Yn.randomBytes(e).toString("base64").replace(/=+$/,"")}function _i(e){return Yn.randomBytes(e).toString("hex")}function Pi(){return{AUTH_SECRET:Pe(32),NEXTAUTH_SECRET:Pe(32),BETTER_AUTH_SECRET:Pe(32),JWT_SECRET:Pe(32),WEBHOOK_SECRET:_i(16),ENCRYPTION_KEY:Pe(32),API_SECRET_KEY:Pe(32),SESSION_SECRET:Pe(32)}}function bi(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Ii(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=bi(o);return e.replace(n,`${t}="${r}"`)}async function $n(e){let t=Bn.join(e,".env.example"),o=Bn.join(e,".env.local");if(!st.existsSync(t))return null;try{let n=st.readFileSync(t,"utf8"),r=Pi(),s=st.existsSync(o)?st.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))s=Ii(s,c,r[c]);return st.writeFileSync(o,s),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}`)}}var At=[{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 qn(e){return At.find(t=>t.id===e)}var Ic=At.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Gn(e,t,o="global"){let n=qn(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${At.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"feature-flags");return}n.envVars.length>0&&q(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{execFileSync as Xn}from"child_process";import x from"fs";import Ai from"os";import ie from"path";import Ci from"ignore";var wi={mirror:{repo:process.env.SAILOR_TEMPLATE_REPO||"Nebutra/Sailor-Template",ref:process.env.SAILOR_TEMPLATE_REF||"main",applyIgnore:!1,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"},main:{repo:"Nebutra/Nebutra-Sailor",ref:"main",applyIgnore:!0,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"}};function Ri(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function xi(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function zn(e){return/^[0-9a-f]{7,40}$/i.test(e)}function Ni(e,t){let o=`https://github.com/${e}.git`,n=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of n)try{let i=Xn("git",["ls-remote",o,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!i)continue;let[s]=i.split(/\s+/);if(zn(s))return s}catch{}return null}async function ki(e,t){if(zn(t))return t;let o=await fetch(`https://api.github.com/repos/${e}/commits/${encodeURIComponent(t)}`,{headers:{Accept:"application/vnd.github+json","User-Agent":"create-sailor"}});if(!o.ok){let r=Ni(e,t);if(r)return r;throw new Error(`Failed to resolve ${e}@${t} (GitHub API ${o.status})`)}let n=await o.json();if(typeof n.sha!="string"||n.sha.length===0)throw new Error(`GitHub API did not return a commit SHA for ${e}@${t}`);return n.sha}function Qn(e,t,o){let n=x.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let i=ie.join(t,r.name),s=ie.relative(e,i).split(ie.sep).join("/");r.isDirectory()?(o.push(s+"/"),Qn(e,i,o)):o.push(s)}}function Ti(e){let t=ie.join(e,".templateignore");if(!x.existsSync(t))return;let o=x.readFileSync(t,"utf8"),n=Ci().add(o),r=[];Qn(e,e,r);let i=r.map(a=>a.endsWith("/")?a.slice(0,-1):a),s=new Set(n.filter(i)),c=i.filter(a=>!s.has(a)).sort((a,d)=>d.split("/").length-a.split("/").length);for(let a of c){let d=ie.join(e,a);try{x.existsSync(d)&&x.rmSync(d,{recursive:!0,force:!0})}catch{}}try{x.existsSync(t)&&x.rmSync(t,{force:!0})}catch{}}async function Hn(e,t){let o=await fetch(e,{headers:{Accept:"application/octet-stream","User-Agent":"create-sailor"}});if(!o.ok)throw new Error(`Failed to download archive (${o.status})`);let n=Buffer.from(await o.arrayBuffer());if(n.byteLength<1024)throw new Error(`Downloaded archive is unexpectedly small (${n.byteLength} bytes)`);x.writeFileSync(t,n);let r=x.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function Wn(e,t){Xn("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function Jn(e){try{let t=x.readdirSync(e);for(let o of t)x.rmSync(ie.join(e,o),{recursive:!0,force:!0})}catch{}}async function Oi(e,t){let o=x.mkdtempSync(ie.join(Ai.tmpdir(),"create-sailor-")),n=ie.join(o,"template.tar.gz");try{let r=await ki(e.repo,e.ref);await Hn(xi(e.repo,r),n),Wn(n,t)}catch(r){if(!e.allowMutableFallback)throw r;Jn(t),await Hn(Ri(e.repo,e.ref),n),Wn(n,t)}finally{x.rmSync(o,{recursive:!0,force:!0})}}async function Zn(e){x.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let i=wi[r];try{if(await Oi(i,e),i.applyIgnore)try{Ti(e)}catch(s){throw new Error(`Template cloned, but .templateignore processing failed: ${s instanceof Error?s.message:String(s)}`)}return}catch(s){n=s instanceof Error?s:new Error(String(s)),Jn(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
1629
1629
 
1630
1630
  Ensure you have internet access and 'tar' installed.
1631
- You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import Pe from"fs";import qt from"path";async function eo(e,t){let o=qt.join(e,"packages","mcp");if(t==="off"){Pe.existsSync(o)&&Pe.rmSync(o,{recursive:!0,force:!0});let r=qt.join(e,"packages","cli","src","commands","mcp-server.ts");Pe.existsSync(r)&&Pe.rmSync(r,{force:!0});return}let n=qt.join(e,".env.example");if(Pe.existsSync(n)){let r=Pe.readFileSync(n,"utf-8"),i="# MCP Server (Agent-friendly API)";if(!r.includes(i)){let a=["","# =============================================",i,"# 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(`
1632
- `);Pe.appendFileSync(n,a)}}}import st from"fs";import to from"path";async function no(e,t,o){let n=to.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){st.existsSync(n)&&st.rmSync(n,{recursive:!0,force:!0});return}let i=to.join(e,".env.example");if(!st.existsSync(i))return;let a=st.readFileSync(i,"utf-8"),c="# Metering (usage-based billing)";if(!a.includes(c)){let s=["","# =============================================",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(`
1633
- `);st.appendFileSync(i,s)}}import qe from"fs";import T from"path";var oo=[{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:""}],Vc=oo.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function ro(e){return oo.find(t=>t.id===e)}function Ui(e){qe.mkdirSync(e,{recursive:!0})}function W(e,t){Ui(T.dirname(e)),qe.writeFileSync(e,t)}function at(e,t){let o=T.join(e,".env.example");qe.existsSync(o)?qe.appendFileSync(o,`
1634
- `+t):qe.writeFileSync(o,t)}function Li(e){let t=`import * as Sentry from "@sentry/nextjs";
1631
+ You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import be from"fs";import qt from"path";async function eo(e,t){let o=qt.join(e,"packages","mcp");if(t==="off"){be.existsSync(o)&&be.rmSync(o,{recursive:!0,force:!0});let r=qt.join(e,"packages","cli","src","commands","mcp-server.ts");be.existsSync(r)&&be.rmSync(r,{force:!0});return}let n=qt.join(e,".env.example");if(be.existsSync(n)){let r=be.readFileSync(n,"utf-8"),i="# MCP Server (Agent-friendly API)";if(!r.includes(i)){let s=["","# =============================================",i,"# 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(`
1632
+ `);be.appendFileSync(n,s)}}}import at from"fs";import to from"path";async function no(e,t,o){let n=to.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){at.existsSync(n)&&at.rmSync(n,{recursive:!0,force:!0});return}let i=to.join(e,".env.example");if(!at.existsSync(i))return;let s=at.readFileSync(i,"utf-8"),c="# Metering (usage-based billing)";if(!s.includes(c)){let a=["","# =============================================",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(`
1633
+ `);at.appendFileSync(i,a)}}import He from"fs";import T from"path";var oo=[{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:""}],Kc=oo.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function ro(e){return oo.find(t=>t.id===e)}function Ui(e){He.mkdirSync(e,{recursive:!0})}function W(e,t){Ui(T.dirname(e)),He.writeFileSync(e,t)}function ct(e,t){let o=T.join(e,".env.example");He.existsSync(o)?He.appendFileSync(o,`
1634
+ `+t):He.writeFileSync(o,t)}function Li(e){let t=`import * as Sentry from "@sentry/nextjs";
1635
1635
 
1636
1636
  Sentry.init({
1637
1637
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
@@ -1843,8 +1843,8 @@ export function TingYunScript() {
1843
1843
  `)}function $i(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
1844
1844
  TINGYUN_LICENSE_KEY=
1845
1845
  NEXT_PUBLIC_TINGYUN_APP_KEY=
1846
- `}async function io(e,t,o="global"){let n=ro(t);if(!n||n.id==="none")return;let r=T.join(e,"apps","web");if(!qe.existsSync(r))return;let i=n.id;try{switch(i){case"sentry":Li(r),at(e,Mi());return;case"datadog":Di(r),at(e,Fi());return;case"bugsnag":ji(r),at(e,Vi());return;case"aliyun-arms":Ki(r),at(e,Bi());return;case"tingyun":Yi(r),at(e,$i());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.`)}}var Ct=[{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 so(e){return Ct.find(t=>t.id===e)}var Gc=Ct.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ao(e,t,o="global"){let n=so(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Ct.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"notifications");return}n.envVars.length>0&&q(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"NOTIFICATIONS_PROVIDER",n.id)}import Gt from"fs";import qi from"path";async function co(e,t){let o=qi.join(e,"package.json");if(Gt.existsSync(o)){let n=Gt.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",Gt.writeFileSync(o,JSON.stringify(r,null,2)+`
1847
- `)}}import Z from"fs";import ct from"path";var Gi=["stripe","lemonsqueezy","chinapay","polar"];function po(e){Z.existsSync(e)&&Z.rmSync(e,{recursive:!0,force:!0})}function Hi(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Wi(e,t){let o=ct.join(e,".env.example");Z.existsSync(o)?Z.appendFileSync(o,`
1846
+ `}async function io(e,t,o="global"){let n=ro(t);if(!n||n.id==="none")return;let r=T.join(e,"apps","web");if(!He.existsSync(r))return;let i=n.id;try{switch(i){case"sentry":Li(r),ct(e,Mi());return;case"datadog":Di(r),ct(e,Fi());return;case"bugsnag":ji(r),ct(e,Vi());return;case"aliyun-arms":Ki(r),ct(e,Bi());return;case"tingyun":Yi(r),ct(e,$i());return;default:return}}catch(s){throw console.error(`Failed to apply monitoring selection "${t}":`,s),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Ct=[{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 so(e){return Ct.find(t=>t.id===e)}var Hc=Ct.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ao(e,t,o="global"){let n=so(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Ct.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"notifications");return}n.envVars.length>0&&q(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"NOTIFICATIONS_PROVIDER",n.id)}import Gt from"fs";import qi from"path";async function co(e,t){let o=qi.join(e,"package.json");if(Gt.existsSync(o)){let n=Gt.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",Gt.writeFileSync(o,JSON.stringify(r,null,2)+`
1847
+ `)}}import Z from"fs";import pt from"path";var Gi=["stripe","lemonsqueezy","chinapay","polar"];function po(e){Z.existsSync(e)&&Z.rmSync(e,{recursive:!0,force:!0})}function Hi(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Wi(e,t){let o=pt.join(e,".env.example");Z.existsSync(o)?Z.appendFileSync(o,`
1848
1848
  `+t):Z.writeFileSync(o,t)}function Xi(e){switch(e){case"stripe":return`# Stripe
1849
1849
  STRIPE_SECRET_KEY=
1850
1850
  STRIPE_WEBHOOK_SECRET=
@@ -1860,13 +1860,13 @@ CHINAPAY_WECHAT_ENABLED=true
1860
1860
  CHINAPAY_APP_ID=
1861
1861
  CHINAPAY_APP_SECRET=
1862
1862
  CHINAPAY_ALIPAY_ENABLED=true
1863
- `}}async function lo(e,t){let o=ct.join(e,"packages","billing");if(!Z.existsSync(o))return;if(t==="none"){po(o);return}let n=ct.join(o,"src"),r=new Set(Hi(t));for(let a of Gi)r.has(a)||po(ct.join(n,a));let i=ct.join(n,"checkout","types.ts");if(Z.existsSync(i)){let a=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=Z.readFileSync(i,"utf8"),s=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${a}";`);s!==c&&Z.writeFileSync(i,s)}Wi(e,Xi(t))}import ie from"fs";import Ge from"path";var go=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),Ht=/@sailor:([^\s*]+)/;function zi(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(i=>go.has(i));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 uo(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function mo(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function fo(e,t){let o=e.split(`
1864
- `),n=[],r=e.includes("#"),i=0;for(;i<o.length;){let a=o[i],c=a.match(Ht);if(!c){n.push(a),i++;continue}let{marker:s,keep:d}=zi(c[1],t);if(s==="registry-entries"){n.push(r?mo(a):uo(a)),i++;continue}if(d){let u=r?mo(a):uo(a);u.trim().length>0&&n.push(u);let h=i+1;for(;h<o.length&&o[h].trim()!==""&&!Ht.test(o[h]);)n.push(o[h]),h++;h<o.length&&o[h].trim()===""&&(n.push(o[h]),h++),i=h}else{let u=i+1;for(;u<o.length&&o[u].trim()!==""&&!Ht.test(o[u]);)u++;u<o.length&&o[u].trim()===""&&u++,i=u}}return Qi(n.join(`
1865
- `),t)}function Qi(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 i=/createProviderRegistry\(\{([\s\S]*?)\}\)/,a=e.match(i);if(!a)return e;let s=a[1].split(`
1863
+ `}}async function lo(e,t){let o=pt.join(e,"packages","billing");if(!Z.existsSync(o))return;if(t==="none"){po(o);return}let n=pt.join(o,"src"),r=new Set(Hi(t));for(let s of Gi)r.has(s)||po(pt.join(n,s));let i=pt.join(n,"checkout","types.ts");if(Z.existsSync(i)){let s=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=Z.readFileSync(i,"utf8"),a=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${s}";`);a!==c&&Z.writeFileSync(i,a)}Wi(e,Xi(t))}import se from"fs";import We from"path";var go=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),Ht=/@sailor:([^\s*]+)/;function zi(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(i=>go.has(i));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 uo(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function mo(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function fo(e,t){let o=e.split(`
1864
+ `),n=[],r=e.includes("#"),i=0;for(;i<o.length;){let s=o[i],c=s.match(Ht);if(!c){n.push(s),i++;continue}let{marker:a,keep:d}=zi(c[1],t);if(a==="registry-entries"){n.push(r?mo(s):uo(s)),i++;continue}if(d){let u=r?mo(s):uo(s);u.trim().length>0&&n.push(u);let h=i+1;for(;h<o.length&&o[h].trim()!==""&&!Ht.test(o[h]);)n.push(o[h]),h++;h<o.length&&o[h].trim()===""&&(n.push(o[h]),h++),i=h}else{let u=i+1;for(;u<o.length&&o[u].trim()!==""&&!Ht.test(o[u]);)u++;u<o.length&&o[u].trim()===""&&u++,i=u}}return Qi(n.join(`
1865
+ `),t)}function Qi(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 i=/createProviderRegistry\(\{([\s\S]*?)\}\)/,s=e.match(i);if(!s)return e;let a=s[1].split(`
1866
1866
  `).filter(d=>{let u=d.trim();if(u===""||u.startsWith("//"))return!0;let h=u.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return h?r.has(h[1]):!0}).join(`
1867
- `);return e.replace(i,`createProviderRegistry({${s}})`)}function Ji(e,t){let o=Ge.join(t,"registry.ts.template"),n=ie.readFileSync(o,"utf-8");return fo(n,e)}function Zi(e,t){let o=Ge.join(t,".env.example.template"),n=ie.readFileSync(o,"utf-8");return fo(n,e)}async function yo(e,t,o){let n=Ji(t,o),r=Zi(t,o),i=Ge.join(e,"packages/agents/src");await ie.promises.mkdir(i,{recursive:!0}),await ie.promises.writeFile(Ge.join(i,"registry.ts"),n),await ie.promises.appendFile(Ge.join(e,".env.example"),`
1868
- `+r);let a={ai:"latest"},{providerIds:c,customEndpoint:s}=t;(c.includes("openai")||s||c.some(u=>go.has(u)))&&(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=Ge.join(e,"package.json");if(ie.existsSync(d)){let u=JSON.parse(await ie.promises.readFile(d,"utf-8"));u.dependencies||(u.dependencies={});for(let[h,O]of Object.entries(a))u.dependencies[h]=O;await ie.promises.writeFile(d,JSON.stringify(u,null,2)+`
1869
- `)}}import g from"fs";import P from"path";function So(e,t){if(!g.existsSync(e))return;let o=g.readdirSync(e);for(let n of o){let r=P.join(e,n);g.statSync(r).isDirectory()?So(r,t):t(r)}}async function Eo(e,t){let o=P.join(e,"package.json");if(!g.existsSync(o))return;let n=JSON.parse(g.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=P.join(e,"packages","db");if(g.existsSync(r)){let i=P.join(r,"prisma");g.existsSync(i)&&g.rmSync(i,{recursive:!0,force:!0});let a=P.join(r,"package.json");if(g.existsSync(a)){let s=JSON.parse(g.readFileSync(a,"utf8"));s.dependencies&&delete s.dependencies["@prisma/client"],s.devDependencies&&delete s.devDependencies.prisma,g.writeFileSync(a,JSON.stringify(s,null,2)+`
1867
+ `);return e.replace(i,`createProviderRegistry({${a}})`)}function Ji(e,t){let o=We.join(t,"registry.ts.template"),n=se.readFileSync(o,"utf-8");return fo(n,e)}function Zi(e,t){let o=We.join(t,".env.example.template"),n=se.readFileSync(o,"utf-8");return fo(n,e)}async function yo(e,t,o){let n=Ji(t,o),r=Zi(t,o),i=We.join(e,"packages/agents/src");await se.promises.mkdir(i,{recursive:!0}),await se.promises.writeFile(We.join(i,"registry.ts"),n),await se.promises.appendFile(We.join(e,".env.example"),`
1868
+ `+r);let s={ai:"latest"},{providerIds:c,customEndpoint:a}=t;(c.includes("openai")||a||c.some(u=>go.has(u)))&&(s["@ai-sdk/openai"]="latest",s["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(s["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(s["@ai-sdk/google"]="latest"),c.includes("mistral")&&(s["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(s["@ai-sdk/openai"]="latest");let d=We.join(e,"package.json");if(se.existsSync(d)){let u=JSON.parse(await se.promises.readFile(d,"utf-8"));u.dependencies||(u.dependencies={});for(let[h,O]of Object.entries(s))u.dependencies[h]=O;await se.promises.writeFile(d,JSON.stringify(u,null,2)+`
1869
+ `)}}import g from"fs";import P from"path";function So(e,t){if(!g.existsSync(e))return;let o=g.readdirSync(e);for(let n of o){let r=P.join(e,n);g.statSync(r).isDirectory()?So(r,t):t(r)}}async function Eo(e,t){let o=P.join(e,"package.json");if(!g.existsSync(o))return;let n=JSON.parse(g.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=P.join(e,"packages","db");if(g.existsSync(r)){let i=P.join(r,"prisma");g.existsSync(i)&&g.rmSync(i,{recursive:!0,force:!0});let s=P.join(r,"package.json");if(g.existsSync(s)){let a=JSON.parse(g.readFileSync(s,"utf8"));a.dependencies&&delete a.dependencies["@prisma/client"],a.devDependencies&&delete a.devDependencies.prisma,g.writeFileSync(s,JSON.stringify(a,null,2)+`
1870
1870
  `)}let c=P.join(r,"src","index.ts");g.existsSync(c)&&g.writeFileSync(c,`
1871
1871
  export const prisma = {} as any;
1872
1872
  export const db = {} as any;
@@ -1913,7 +1913,7 @@ export type UsageAggregate = any;
1913
1913
  export type UsageLedgerEntry = any;
1914
1914
  export type UsageType = any;
1915
1915
  export type UsageLedgerSource = any;
1916
- `)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=P.join(e,"apps");if(g.existsSync(r)){let i=g.readdirSync(r);for(let a of i){let c=P.join(r,a);if(!g.statSync(c).isDirectory())continue;let s=P.join(c,"src","app");if(!g.existsSync(s))continue;["[lang]","[locale]"].forEach(v=>{let l=P.join(s,v);if(g.existsSync(l)){let R=g.readdirSync(l);for(let ut of R)g.renameSync(P.join(l,ut),P.join(s,ut));g.rmdirSync(l)}}),["src/middleware.ts","middleware.ts"].forEach(v=>{let l=P.join(c,v);g.existsSync(l)&&g.rmSync(l)});let d=P.join(c,"src","lib");g.existsSync(d)||g.mkdirSync(d,{recursive:!0});let u=P.join(d,"mock-i18n.ts");g.writeFileSync(u,`
1916
+ `)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=P.join(e,"apps");if(g.existsSync(r)){let i=g.readdirSync(r);for(let s of i){let c=P.join(r,s);if(!g.statSync(c).isDirectory())continue;let a=P.join(c,"src","app");if(!g.existsSync(a))continue;["[lang]","[locale]"].forEach(v=>{let l=P.join(a,v);if(g.existsSync(l)){let R=g.readdirSync(l);for(let mt of R)g.renameSync(P.join(l,mt),P.join(a,mt));g.rmdirSync(l)}}),["src/middleware.ts","middleware.ts"].forEach(v=>{let l=P.join(c,v);g.existsSync(l)&&g.rmSync(l)});let d=P.join(c,"src","lib");g.existsSync(d)||g.mkdirSync(d,{recursive:!0});let u=P.join(d,"mock-i18n.ts");g.writeFileSync(u,`
1917
1917
  import React from 'react';
1918
1918
  export function useTranslations(namespace?: string): any { return (key: string) => key; }
1919
1919
  export function useLocale() { return 'en'; }
@@ -1954,13 +1954,13 @@ export * from './mock-i18n';
1954
1954
  export { default } from './mock-i18n';
1955
1955
  `);let M=P.join(c,"tsconfig.json");if(g.existsSync(M))try{let v=g.readFileSync(M,"utf8");if(v.includes('"paths": {')){let l=v.replace(/"paths":\s*\{/,`"paths": {
1956
1956
  "next-intl": ["./src/lib/mock-i18n"],
1957
- "next-intl/*": ["./src/lib/mock-i18n"],`);g.writeFileSync(M,l)}}catch{}let D=P.join(c,"src");g.existsSync(D)&&So(D,v=>{if(!v.endsWith(".ts")&&!v.endsWith(".tsx"))return;let l=g.readFileSync(v,"utf8"),R=!1;v.endsWith("src/app/layout.tsx")&&l.includes("../providers")&&(l=l.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),R=!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"),R=!0),l.match(/lang\s*:\s*any/)&&(l=l.replace(/lang\s*:\s*any/g,"lang: string"),R=!0),l.match(/requestLocale\s*:\s*any/)&&(l=l.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),R=!0),l.match(/\(locale\s*=\s*(.*)\)/)&&(l=l.replace(/\(locale\s*=\s*(.*)\)/g,"() "),R=!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 })"),R=!0),(v.endsWith("src/app/layout.tsx")||v.endsWith("src/app/sitemap.ts")||v.endsWith("src/app/robots.ts")||v.endsWith("src/components/ui/locale-switcher.tsx")||v.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) =>"),R=!0),v.endsWith("src/i18n/request.ts")&&(l=l.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),R=!0),(l.match(/locale\s*:/)||l.match(/lang\s*:/))&&(R=!0),R&&g.writeFileSync(v,l)});let He=P.join(c,"package.json");if(g.existsSync(He)){let v=JSON.parse(g.readFileSync(He,"utf8"));v.dependencies&&delete v.dependencies["next-intl"],g.writeFileSync(He,JSON.stringify(v,null,2)+`
1957
+ "next-intl/*": ["./src/lib/mock-i18n"],`);g.writeFileSync(M,l)}}catch{}let D=P.join(c,"src");g.existsSync(D)&&So(D,v=>{if(!v.endsWith(".ts")&&!v.endsWith(".tsx"))return;let l=g.readFileSync(v,"utf8"),R=!1;v.endsWith("src/app/layout.tsx")&&l.includes("../providers")&&(l=l.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),R=!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"),R=!0),l.match(/lang\s*:\s*any/)&&(l=l.replace(/lang\s*:\s*any/g,"lang: string"),R=!0),l.match(/requestLocale\s*:\s*any/)&&(l=l.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),R=!0),l.match(/\(locale\s*=\s*(.*)\)/)&&(l=l.replace(/\(locale\s*=\s*(.*)\)/g,"() "),R=!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 })"),R=!0),(v.endsWith("src/app/layout.tsx")||v.endsWith("src/app/sitemap.ts")||v.endsWith("src/app/robots.ts")||v.endsWith("src/components/ui/locale-switcher.tsx")||v.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) =>"),R=!0),v.endsWith("src/i18n/request.ts")&&(l=l.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),R=!0),(l.match(/locale\s*:/)||l.match(/lang\s*:/))&&(R=!0),R&&g.writeFileSync(v,l)});let Xe=P.join(c,"package.json");if(g.existsSync(Xe)){let v=JSON.parse(g.readFileSync(Xe,"utf8"));v.dependencies&&delete v.dependencies["next-intl"],g.writeFileSync(Xe,JSON.stringify(v,null,2)+`
1958
1958
  `)}}}}g.writeFileSync(o,JSON.stringify(n,null,2)+`
1959
- `)}import{getSchema as es,printSchema as ts}from"@mrleebo/prisma-ast";var ns=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function os(e){return e.type==="comment"&&e.text.trim().startsWith("///")}function rs(e){let t=ns.exec(e.trim());if(!t)return null;let[,o,n]=t,r=n.split("|").map(i=>i.trim()).filter(i=>i.length>0);return{flag:o,values:r}}function is(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=rs(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function Wt(e,t){let o=es(e),n=new Set;for(let c=0;c<o.list.length;c++){if(o.list[c].type!=="model")continue;let d=is(o.list,c);if(!d)continue;let u=t[d.parsed.flag];if(u!==void 0&&d.parsed.values.includes(u))n.add(d.annIndex);else{n.add(c);for(let M=c-1;M>=0;M--){let D=o.list[M];if(D.type==="comment"&&os(D)){n.add(M);continue}break}let O=o.list[c+1];O&&O.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,s)=>!n.has(s)),i=[];for(let c of r){let s=i[i.length-1];c.type==="break"&&s&&s.type==="break"||i.push(c)}return ts({type:"schema",list:i})}import se from"fs";import Xt from"path";var wt=[{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 ho(e){return wt.find(t=>t.id===e)}var dp=wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function vo(e){return se.existsSync(e)?se.readFileSync(e,"utf-8"):null}function ss(e,t){let o=Xt.join(e,".env.example"),n=vo(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
1960
- `);se.appendFileSync(o,i)}function as(e,t,o){let n=Xt.join(e,".env.example"),r=vo(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?se.writeFileSync(n,r.replace(i,`${t}="${o}"`)):se.appendFileSync(n,`${t}="${o}"
1961
- `)}async function _o(e,t,o){let n=Xt.join(e,"packages","queue");if(t==="none"){se.existsSync(n)&&se.rmSync(n,{recursive:!0,force:!0});return}let r=ho(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${wt.map(i=>i.id).join(", ")}`);se.existsSync(n)&&(ss(e,r),as(e,"QUEUE_PROVIDER",t))}import ae from"fs";import zt from"path";var Rt=[{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 Po(e){return Rt.find(t=>t.id===e)}var Sp=Rt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function bo(e){return ae.existsSync(e)?ae.readFileSync(e,"utf-8"):null}function cs(e,t){let o=zt.join(e,".env.example"),n=bo(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
1962
- `);ae.appendFileSync(o,i)}function ps(e,t,o){let n=zt.join(e,".env.example"),r=bo(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ae.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ae.appendFileSync(n,`${t}="${o}"
1963
- `)}async function Io(e,t,o){let n=zt.join(e,"packages","search");if(t==="none"){ae.existsSync(n)&&ae.rmSync(n,{recursive:!0,force:!0});return}let r=Po(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Rt.map(i=>i.id).join(", ")}`);ae.existsSync(n)&&(cs(e,r),ps(e,"SEARCH_PROVIDER",t))}import ce from"fs";import be from"path";function ls(e){let t=[be.join(e,"packages","db"),be.join(e,"apps","web")];for(let o of t){let n=be.join(o,"prisma","schema.prisma");if(ce.existsSync(n))return{packageDir:o,seedPath:be.join(o,"prisma","seed.ts"),packageJsonPath:be.join(o,"package.json")}}return null}function ds(e){try{let t=ce.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 us(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1959
+ `)}import{getSchema as es,printSchema as ts}from"@mrleebo/prisma-ast";var ns=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function os(e){return e.type==="comment"&&e.text.trim().startsWith("///")}function rs(e){let t=ns.exec(e.trim());if(!t)return null;let[,o,n]=t,r=n.split("|").map(i=>i.trim()).filter(i=>i.length>0);return{flag:o,values:r}}function is(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=rs(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function Wt(e,t){let o=es(e),n=new Set;for(let c=0;c<o.list.length;c++){if(o.list[c].type!=="model")continue;let d=is(o.list,c);if(!d)continue;let u=t[d.parsed.flag];if(u!==void 0&&d.parsed.values.includes(u))n.add(d.annIndex);else{n.add(c);for(let M=c-1;M>=0;M--){let D=o.list[M];if(D.type==="comment"&&os(D)){n.add(M);continue}break}let O=o.list[c+1];O&&O.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,a)=>!n.has(a)),i=[];for(let c of r){let a=i[i.length-1];c.type==="break"&&a&&a.type==="break"||i.push(c)}return ts({type:"schema",list:i})}import ae from"fs";import Xt from"path";var wt=[{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 ho(e){return wt.find(t=>t.id===e)}var up=wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function vo(e){return ae.existsSync(e)?ae.readFileSync(e,"utf-8"):null}function ss(e,t){let o=Xt.join(e,".env.example"),n=vo(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
1960
+ `);ae.appendFileSync(o,i)}function as(e,t,o){let n=Xt.join(e,".env.example"),r=vo(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ae.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ae.appendFileSync(n,`${t}="${o}"
1961
+ `)}async function _o(e,t,o){let n=Xt.join(e,"packages","queue");if(t==="none"){ae.existsSync(n)&&ae.rmSync(n,{recursive:!0,force:!0});return}let r=ho(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${wt.map(i=>i.id).join(", ")}`);ae.existsSync(n)&&(ss(e,r),as(e,"QUEUE_PROVIDER",t))}import ce from"fs";import zt from"path";var Rt=[{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 Po(e){return Rt.find(t=>t.id===e)}var Ep=Rt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function bo(e){return ce.existsSync(e)?ce.readFileSync(e,"utf-8"):null}function cs(e,t){let o=zt.join(e,".env.example"),n=bo(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
1962
+ `);ce.appendFileSync(o,i)}function ps(e,t,o){let n=zt.join(e,".env.example"),r=bo(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ce.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ce.appendFileSync(n,`${t}="${o}"
1963
+ `)}async function Io(e,t,o){let n=zt.join(e,"packages","search");if(t==="none"){ce.existsSync(n)&&ce.rmSync(n,{recursive:!0,force:!0});return}let r=Po(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Rt.map(i=>i.id).join(", ")}`);ce.existsSync(n)&&(cs(e,r),ps(e,"SEARCH_PROVIDER",t))}import pe from"fs";import Ie from"path";function ls(e){let t=[Ie.join(e,"packages","db"),Ie.join(e,"apps","web")];for(let o of t){let n=Ie.join(o,"prisma","schema.prisma");if(pe.existsSync(n))return{packageDir:o,seedPath:Ie.join(o,"prisma","seed.ts"),packageJsonPath:Ie.join(o,"package.json")}}return null}function ds(e){try{let t=pe.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 us(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1964
1964
  const admin = await prisma.user.create({
1965
1965
  data: {
1966
1966
  clerkId: "user_mock_admin",
@@ -1991,7 +1991,7 @@ export { default } from './mock-i18n';
1991
1991
  console.log("\\u2713 Created admin user:", admin.email);
1992
1992
  } catch (err) {
1993
1993
  console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
1994
- }`}function ms(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),i=us(e,n),a=o?` let tenants: Array<{ id: string; name: string }> = [];
1994
+ }`}function ms(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),i=us(e,n),s=o?` let tenants: Array<{ id: string; name: string }> = [];
1995
1995
  try {
1996
1996
  tenants = await Promise.all([
1997
1997
  prisma.tenant.create({
@@ -2041,7 +2041,7 @@ async function main(): Promise<void> {
2041
2041
  console.log("\\uD83C\\uDF31 Seeding database...");
2042
2042
 
2043
2043
  // --- Tenants ---------------------------------------------------------
2044
- ${a}
2044
+ ${s}
2045
2045
 
2046
2046
  // --- Admin user ------------------------------------------------------
2047
2047
  ${i}
@@ -2060,9 +2060,9 @@ main()
2060
2060
  .finally(async () => {
2061
2061
  await prisma.$disconnect();
2062
2062
  });
2063
- `}function gs(e){if(ce.existsSync(e))try{let t=ce.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let i=o.prisma??{};if(i.seed||(i.seed="tsx prisma/seed.ts",r=!0),!r)return;let a={...o,scripts:n,prisma:i};ce.writeFileSync(e,JSON.stringify(a,null,2)+`
2064
- `)}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 Ao(e,t){let o=ls(e);if(o)try{let n=be.join(o.packageDir,"prisma","schema.prisma"),r=ds(n),i=ms(t,r),a=be.dirname(o.seedPath);ce.existsSync(a)||ce.mkdirSync(a,{recursive:!0}),ce.writeFileSync(o.seedPath,i),gs(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 pe from"fs";import Ie from"path";var xt=[{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:""}],Cp=xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Co(e){return xt.find(t=>t.id===e)}var fs="@nebutra/sms",ys={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 Qt(e,t){pe.mkdirSync(Ie.dirname(e),{recursive:!0}),pe.writeFileSync(e,t)}function Ss(e,t){let o=Ie.join(e,".env.example");pe.existsSync(o)?pe.appendFileSync(o,`
2065
- `+t):pe.writeFileSync(o,t)}function Es(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2063
+ `}function gs(e){if(pe.existsSync(e))try{let t=pe.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let i=o.prisma??{};if(i.seed||(i.seed="tsx prisma/seed.ts",r=!0),!r)return;let s={...o,scripts:n,prisma:i};pe.writeFileSync(e,JSON.stringify(s,null,2)+`
2064
+ `)}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 Ao(e,t){let o=ls(e);if(o)try{let n=Ie.join(o.packageDir,"prisma","schema.prisma"),r=ds(n),i=ms(t,r),s=Ie.dirname(o.seedPath);pe.existsSync(s)||pe.mkdirSync(s,{recursive:!0}),pe.writeFileSync(o.seedPath,i),gs(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 le from"fs";import Ae from"path";var xt=[{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:""}],wp=xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Co(e){return xt.find(t=>t.id===e)}var fs="@nebutra/sms",ys={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 Qt(e,t){le.mkdirSync(Ae.dirname(e),{recursive:!0}),le.writeFileSync(e,t)}function Ss(e,t){let o=Ae.join(e,".env.example");le.existsSync(o)?le.appendFileSync(o,`
2065
+ `+t):le.writeFileSync(o,t)}function Es(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2066
2066
  `);return`${t}
2067
2067
  ${o}
2068
2068
  `}var hs=`/**
@@ -2365,8 +2365,8 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2365
2365
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2366
2366
  `}function Cs(e){switch(e){case"twilio":return vs();case"messagebird":return _s();case"plivo":return Ps();case"aliyun-sms":return bs();case"tencent-sms":return Is();case"yunpian":return As();case"none":return`export {};
2367
2367
  `}}function ws(e){let t={};for(let n of e.pkgs??[]){let r=ys[n];r&&(t[n]=r)}let o={name:fs,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)+`
2368
- `}async function wo(e,t,o="global"){if(t==="none")return;let n=Co(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${xt.map(a=>a.id).join(", ")}`);let r=Ie.join(e,"packages","sms");if(!pe.existsSync(r))return;let i=Ie.join(r,"src");pe.existsSync(i)&&pe.rmSync(i,{recursive:!0,force:!0});try{Qt(Ie.join(r,"package.json"),ws(n)),Qt(Ie.join(i,"types.ts"),hs),Qt(Ie.join(i,"index.ts"),Cs(n.id)),Ss(e,Es(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 Ce from"fs";import Ae from"path";var pt=[{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 Jt(e){let t=e==="supabase"?"supabase-storage":e;return pt.some(o=>o.id===t)?t:void 0}function Ro(e){let t=Jt(e);return t?pt.find(o=>o.id===t):void 0}var Tp=pt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var we="@nebutra/storage";function Zt(e,t){Ce.mkdirSync(Ae.dirname(e),{recursive:!0}),Ce.writeFileSync(e,t)}function Rs(e,t){let o=Ae.join(e,".env.example");Ce.existsSync(o)?Ce.appendFileSync(o,`
2369
- `+t):Ce.writeFileSync(o,t)}function xs(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2368
+ `}async function wo(e,t,o="global"){if(t==="none")return;let n=Co(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${xt.map(s=>s.id).join(", ")}`);let r=Ae.join(e,"packages","sms");if(!le.existsSync(r))return;let i=Ae.join(r,"src");le.existsSync(i)&&le.rmSync(i,{recursive:!0,force:!0});try{Qt(Ae.join(r,"package.json"),ws(n)),Qt(Ae.join(i,"types.ts"),hs),Qt(Ae.join(i,"index.ts"),Cs(n.id)),Ss(e,Es(n))}catch(s){throw console.error(`Failed to apply SMS selection "${t}":`,s),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import we from"fs";import Ce from"path";var lt=[{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 Jt(e){let t=e==="supabase"?"supabase-storage":e;return lt.some(o=>o.id===t)?t:void 0}function Ro(e){let t=Jt(e);return t?lt.find(o=>o.id===t):void 0}var Op=lt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Re="@nebutra/storage";function Zt(e,t){we.mkdirSync(Ce.dirname(e),{recursive:!0}),we.writeFileSync(e,t)}function Rs(e,t){let o=Ce.join(e,".env.example");we.existsSync(o)?we.appendFileSync(o,`
2369
+ `+t):we.writeFileSync(o,t)}function xs(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2370
2370
  `);return`${t}
2371
2371
  ${o}
2372
2372
  `}var Ns=`/**
@@ -2396,7 +2396,7 @@ export interface SignedUrlOptions {
2396
2396
  contentType?: string;
2397
2397
  }
2398
2398
  `;function ks(){return`/**
2399
- * @${we.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
2399
+ * @${Re.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
2400
2400
  *
2401
2401
  * Docs: https://developers.cloudflare.com/r2/api/s3/api/
2402
2402
  */
@@ -2460,7 +2460,7 @@ export async function getSignedUrl(
2460
2460
 
2461
2461
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2462
2462
  `}function Ts(){return`/**
2463
- * @${we.slice(1)} \u2014 AWS S3 wrapper.
2463
+ * @${Re.slice(1)} \u2014 AWS S3 wrapper.
2464
2464
  *
2465
2465
  * Docs: https://docs.aws.amazon.com/s3/
2466
2466
  */
@@ -2525,7 +2525,7 @@ export async function getSignedUrl(
2525
2525
 
2526
2526
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2527
2527
  `}function Os(){return`/**
2528
- * @${we.slice(1)} \u2014 Supabase Storage wrapper.
2528
+ * @${Re.slice(1)} \u2014 Supabase Storage wrapper.
2529
2529
  *
2530
2530
  * Docs: https://supabase.com/docs/guides/storage
2531
2531
  */
@@ -2588,7 +2588,7 @@ export async function getSignedUrl(
2588
2588
 
2589
2589
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2590
2590
  `}function Us(){return`/**
2591
- * @${we.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
2591
+ * @${Re.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
2592
2592
  *
2593
2593
  * Docs: https://help.aliyun.com/product/31815.html
2594
2594
  */
@@ -2635,7 +2635,7 @@ export async function getSignedUrl(
2635
2635
 
2636
2636
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2637
2637
  `}function Ls(){return`/**
2638
- * @${we.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
2638
+ * @${Re.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
2639
2639
  *
2640
2640
  * Docs: https://cloud.tencent.com/document/product/436
2641
2641
  */
@@ -2690,7 +2690,7 @@ export async function getSignedUrl(
2690
2690
 
2691
2691
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2692
2692
  `}function Ms(){return`/**
2693
- * @${we.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
2693
+ * @${Re.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
2694
2694
  *
2695
2695
  * Docs: https://developer.qiniu.com/kodo
2696
2696
  */
@@ -2758,8 +2758,8 @@ export async function getSignedUrl(
2758
2758
 
2759
2759
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2760
2760
  `}function Ds(e){switch(e){case"r2":return ks();case"s3":return Ts();case"supabase-storage":return Os();case"aliyun-oss":return Us();case"tencent-cos":return Ls();case"qiniu":return Ms();case"none":return`export {};
2761
- `}}function Fs(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:we,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)+`
2762
- `}async function xo(e,t,o){if(t==="none")return;let n=Ro(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${pt.map(a=>a.id).join(", ")}`);let r=Ae.join(e,"packages","storage"),i=Ae.join(r,"src");Ce.existsSync(i)&&Ce.rmSync(i,{recursive:!0,force:!0}),Zt(Ae.join(r,"package.json"),Fs(n)),Zt(Ae.join(i,"types.ts"),Ns),Zt(Ae.join(i,"index.ts"),Ds(n.id)),Rs(e,xs(n))}var Nt=[{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 No(e){return Nt.find(t=>t.id===e)}var Fp=Nt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ko(e,t,o="global"){let n=No(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Nt.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"webhooks");return}n.envVars.length>0&&q(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"WEBHOOKS_PROVIDER",n.id)}import Re from"fs";import lt from"path";function js(e){return`import Link from "next/link";
2761
+ `}}function Fs(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:Re,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)+`
2762
+ `}async function xo(e,t,o){if(t==="none")return;let n=Ro(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${lt.map(s=>s.id).join(", ")}`);let r=Ce.join(e,"packages","storage"),i=Ce.join(r,"src");we.existsSync(i)&&we.rmSync(i,{recursive:!0,force:!0}),Zt(Ce.join(r,"package.json"),Fs(n)),Zt(Ce.join(i,"types.ts"),Ns),Zt(Ce.join(i,"index.ts"),Ds(n.id)),Rs(e,xs(n))}var Nt=[{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 No(e){return Nt.find(t=>t.id===e)}var jp=Nt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ko(e,t,o="global"){let n=No(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Nt.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"webhooks");return}n.envVars.length>0&&q(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"WEBHOOKS_PROVIDER",n.id)}import xe from"fs";import dt from"path";function js(e){return`import Link from "next/link";
2763
2763
 
2764
2764
  export default function WelcomePage() {
2765
2765
  const projectName = ${JSON.stringify(e)};
@@ -2868,7 +2868,16 @@ function Step({
2868
2868
  </li>
2869
2869
  );
2870
2870
  }
2871
- `}function Vs(e,t){return`# Next steps \u2014 ${e}
2871
+ `}function Vs(e=[]){return e.length===0?"":`
2872
+ ## Production readiness holds
2873
+
2874
+ Do not enable these in production until you replace stubs, add provider credentials, and verify the integration contract:
2875
+
2876
+ ${e.map(o=>{let n=qe(o.status);return`- ${o.flag}=${o.provider} ${n} \u2014 ${te(o.status)}`}).join(`
2877
+ `)}
2878
+
2879
+ Review the package readiness matrix before handoff: [docs/package-status.md](docs/package-status.md)
2880
+ `}function Ks(e,t,o=[]){return`# Next steps \u2014 ${e}
2872
2881
 
2873
2882
  Region: ${t}
2874
2883
 
@@ -2894,32 +2903,33 @@ Your AI-native SaaS scaffold is ready. Complete these four steps to go from temp
2894
2903
  \`\`\`
2895
2904
 
2896
2905
  After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
2906
+ ${Vs(o)}
2897
2907
 
2898
2908
  ## Resources
2899
2909
 
2900
2910
  - [Documentation](/docs)
2901
2911
  - [GitHub](https://github.com/nebutra/nebutra-sailor)
2902
2912
  - [Get free license (Individual/OPC)](https://nebutra.com/get-license)
2903
- `}async function To(e,t){let{projectName:o,region:n}=t;try{let r=lt.join(e,".sailor");Re.existsSync(r)||Re.mkdirSync(r,{recursive:!0}),Re.writeFileSync(lt.join(r,"next-steps.md"),Vs(o,n))}catch(r){let i=r instanceof Error?r.message:String(r);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${i}`)}try{let r=lt.join(e,"apps","web");if(!Re.existsSync(r))return;let i=lt.join(r,"src","app","[locale]","welcome");Re.existsSync(i)||Re.mkdirSync(i,{recursive:!0}),Re.writeFileSync(lt.join(i,"page.tsx"),js(o))}catch(r){let i=r instanceof Error?r.message:String(r);console.warn(`[create-sailor] Failed to write welcome page: ${i}`)}}var Oo="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2904
- `)}function Ys(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function Uo(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 Lo(e){return e==="drizzle"?"drizzle":e==="none"?"none":"prisma"}function Mo(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function Do(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 Fo(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="none"?"none":"clerk"}function jo(e){if(!e)return["openai"];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}function $s(e,t){let o=e??t;return Jt(o)??o}var Vo={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Ko(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in Vo){let n=Vo[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(w.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
2913
+ `}async function To(e,t){let{projectName:o,region:n,previewSelections:r=[]}=t;try{let i=dt.join(e,".sailor");xe.existsSync(i)||xe.mkdirSync(i,{recursive:!0}),xe.writeFileSync(dt.join(i,"next-steps.md"),Ks(o,n,r))}catch(i){let s=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${s}`)}try{let i=dt.join(e,"apps","web");if(!xe.existsSync(i))return;let s=dt.join(i,"src","app","[locale]","welcome");xe.existsSync(s)||xe.mkdirSync(s,{recursive:!0}),xe.writeFileSync(dt.join(s,"page.tsx"),js(o))}catch(i){let s=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write welcome page: ${s}`)}}var Oo="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2914
+ `)}function $s(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function Uo(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 Lo(e){return e==="drizzle"?"drizzle":e==="none"?"none":"prisma"}function Mo(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function Do(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 Fo(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="none"?"none":"clerk"}function jo(e){if(!e)return["openai"];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}function qs(e,t){let o=e??t;return Jt(o)??o}var Vo={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Ko(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in Vo){let n=Vo[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(w.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
2905
2915
  `)+w.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
2906
- `)),"fumadocs"}return"fumadocs"}function Bo(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 Yo(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function qs(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",billingMode:"usage",idp:"clerk"}}function $o(e){return e==="cn"?"wechat":"stripe"}async function Gs(){let e=new Ks;e.name(Oo).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ee,"-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>","expert: comma-separated provider ids used as an AI provider seed").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-storage | 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("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").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&&(an(),process.exit(0));let n=!!t.json,r=!!t.dryRun,i=!!t.yes,a=i||!process.stdin.isTTY;n||on(),p(n,{event:"start",version:ee});let c=o??(i?"./my-saas-app":void 0),s;if(c)s=c;else if(a)s="./my-saas-app";else{let m=await C.group({name:()=>C.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:f=>{if(f.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(w.red(`\u2718 Cancelled
2907
- `)),process.exit(130)}});s=String(m.name)}let d=dt.basename(dt.resolve(s)),u=t.pm??Ys(),h=!!t.region,O=!!t.auth,M=!!t.payment,D=!!t.ai,He=!!t.email,v=!!t.storage,l=!!t.monitoring,R=!!t.analytics,ut=!!t.sms,en=t.i18n!==void 0,y,We,X,Xe,F,N,Y=En(t.socialLogin),ze,Tt,de,xe,z,j,mt;if(a){y=Yo(t.region),We=Lo(t.orm),X=Uo(t.db);let m=M?t.payment:$o(y);Xe=Mo(m),F=Do(m),N=Fo(t.auth);let f=Dt({mode:D?t.ai?.trim().toLowerCase()==="none"?"none":"direct":"gateway",providerIds:D?jo(t.ai):void 0});ze=f.mode,Tt=f.routing,de=f.providerIds,z=Bo(t.deploy),j=Ko(t.docs,n),mt=en?!!t.i18n:!0}else{let m={};h||(m.region=()=>C.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"})),O||(m.auth=()=>C.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk"},{value:"betterauth",label:"Better Auth"},{value:"none",label:"None"}],initialValue:"clerk"})),D||(m.aiMode=()=>C.select({message:"AI topology?",options:[{value:"gateway",label:"Multi-provider AI Gateway / router",hint:"recommended"},{value:"direct",label:"Direct SDK/provider adapters"},{value:"custom",label:"OpenAI-compatible endpoint"},{value:"none",label:"Skip AI"}],initialValue:"gateway"}),m.aiProviders=({results:E})=>{if(E.aiMode!=="direct")return Promise.resolve([]);let Q=Mt.map(Ut=>({value:Ut.id,label:`[${Ut.category}] ${Ut.name}`}));return C.multiselect({message:"Select direct AI provider adapters (expert path)",options:Q,initialValues:["openai"],required:!1})},m.customAiName=({results:E})=>E.aiMode==="custom"?C.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),m.customAiBaseUrl=({results:E})=>E.aiMode==="custom"?C.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:Q=>{if(Q.length===0)return"Base URL is required."}}):Promise.resolve(void 0),m.customAiApiKeyEnv=({results:E})=>E.aiMode==="custom"?C.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0));let f=Object.keys(m).length>0?await C.group(m,{onCancel:()=>{process.stdout.write(w.red(`\u2718 Cancelled
2908
- `)),process.exit(130)}}):{};y=Yo(h?t.region:f.region),We=Lo(t.orm),X=Uo(t.db);let V=M?t.payment:$o(y);Xe=Mo(V),F=Do(V),N=Fo(O?t.auth:f.auth);let yt=f.aiMode==="custom"?{name:f.customAiName??"custom",baseURL:f.customAiBaseUrl??"",apiKeyEnvName:f.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,S=Dt({mode:D?t.ai?.trim().toLowerCase()==="none"?"none":"direct":f.aiMode??"gateway",providerIds:D?jo(t.ai):f.aiProviders,customEndpoint:yt});ze=S.mode,Tt=S.routing,de=S.providerIds,S.customEndpoint&&(xe={name:S.customEndpoint.name,baseURL:S.customEndpoint.baseURL,apiKeyEnvName:S.customEndpoint.apiKeyEnvName}),z=Bo(t.deploy),j=Ko(t.docs,n),mt=en?!!t.i18n:!0}let b=qs(y),Ne=He?t.email:b.email,ke=$s(v?t.storage:void 0,b.storage),Te=l?t.monitoring:b.monitoring,Oe=R?t.analytics:b.analytics,Ue=ut?t.sms:b.sms,Le=t.queue??b.queue,Me=t.search??b.search,Qe=t.cache??b.cache,De=t.notifications??b.notifications,Fe=t.webhooks??b.webhooks,Je=t.cms??b.cms,je=t.featureFlags??b.featureFlags,Ve=t.captcha??b.captcha,gt=t.mcp??b.mcp,Ze=t.metering??b.metering,Ke=t.billingMode??b.billingMode,Be=t.idp??b.idp,et=rn([{flag:"queue",provider:Le},{flag:"search",provider:Me},{flag:"notifications",provider:De},{flag:"webhooks",provider:Fe},{flag:"feature-flags",provider:je},{flag:"captcha",provider:Ve}]);function Ot(){for(let m of et)if(n)p(!0,{event:"warn",step:m.flag,provider:m.provider,packageStatus:m.status,message:Ye(m.status)});else{let f=St(m.status);process.stdout.write(w.yellow(`\u26A0 ${m.flag}=${m.provider} ${f} \u2014 ${Ye(m.status)}
2909
- `))}}let ue={region:y,orm:We,database:X,payment:Xe,aiMode:ze,aiRouting:Tt,aiProviders:de,customAiEndpoint:xe,deployTarget:z,docs:j,i18n:mt,email:Ne,storage:ke,monitoring:Te,analytics:Oe,sms:Ue,queue:Le,search:Me,cache:Qe,notifications:De,webhooks:Fe,cms:Je,featureFlags:je,captcha:Ve,mcp:gt,metering:Ze,billingMode:Ke,idp:Be},ft=[["Project name",d],["Region",y],["Auth",N],["Social login",Y.length>0?Y.map(m=>tt.find(f=>f.id===m)?.name??m).join(", "):"none"],["ORM",We],["Database",X],["Payment",F],["AI topology",`${ze}${de.length>0?` (${de.join(", ")} seed)`:""}${xe?" + custom endpoint":""}`],["Email",Ne],["Storage",ke],["Monitoring",Te],["Analytics",Oe],["SMS",Ue],["Deploy Target",z],["Docs Framework",j]];n?ft.forEach(([m,f],V)=>{p(!0,{event:"step",step:m,value:f,index:V+1,total:ft.length})}):ft.forEach(([m,f],V)=>{pn({index:V+1,total:ft.length,label:m,value:f})});let qo={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},tn=Date.now();if(r){let m=de.length,f=[`clone template \u2192 ${s}`,"write nebutra.config.json",`prune template (orm=${We}, i18n=${mt})`,`region \u2192 ${y}`,`auth \u2192 ${N==="none"?"skip (remove packages/auth)":`configure ${N}`}`,...Y.length>0?[`social-login \u2192 generate ${Y.length} callback route${Y.length===1?"":"s"} + SocialLoginButtons.tsx (${Y.join(", ")})`]:[],`db \u2192 ${X==="none"?"skip (remove packages/db)":`configure Prisma for ${X}`}`,`payment \u2192 ${F==="none"?"skip (remove packages/billing)":`configure ${F}`}`,...j!=="none"?[`docs \u2192 scaffold apps/docs (${j==="fumadocs"?"fumadocs":`${j} \u2192 fumadocs fallback`})`]:[],...m>0||xe?[`ai-providers \u2192 generate ${ze} registry seed + env (${m}${xe?" + custom":""} provider${m===1&&!xe?"":"s"})`]:[],...Ne!=="none"?[`email \u2192 configure ${Ne}`]:[],...ke!=="none"?[`storage \u2192 configure ${ke}`]:[],...Te!=="none"?[`monitoring \u2192 configure ${Te}`]:[],...Oe!=="none"?[`analytics \u2192 configure ${Oe}`]:[],...Ue!=="none"?[`sms \u2192 configure ${Ue}`]:[],...Le!=="none"?[`queue \u2192 configure ${Le}`]:[],...Me!=="none"?[`search \u2192 configure ${Me}`]:[],...Qe!=="none"?[`cache \u2192 configure ${Qe}`]:[],...De!=="none"?[`notifications \u2192 configure ${De}`]:[],...Fe!=="none"?[`webhooks \u2192 configure ${Fe}`]:[],...Je!=="none"?[`cms \u2192 configure ${Je}`]:[],...je!=="none"?[`feature-flags \u2192 configure ${je}`]:[],...Ve!=="none"?[`captcha \u2192 configure ${Ve}`]:[],`mcp \u2192 ${gt==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${Ze==="off"?"disabled":Ze==="auto"?Xe!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...Ke!=="usage"?[`billing-mode \u2192 ${Ke}`]:[],...Be!=="clerk"?[`idp \u2192 ${Be}`]:[],`compliance \u2192 inject ${y} 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)",...z!=="none"?[`deploy \u2192 inject ${z} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${u} install`,t.git===!1?"skip git init":"run git init"];if(n){for(let V of f)p(!0,{event:"plan",action:V});Ot(),p(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
2916
+ `)),"fumadocs"}return"fumadocs"}function Bo(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 Yo(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function Gs(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",billingMode:"usage",idp:"clerk"}}function $o(e){return e==="cn"?"wechat":"stripe"}async function Hs(){let e=new Bs;e.name(Oo).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ee,"-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>","expert: comma-separated provider ids used as an AI provider seed").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-storage | 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("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").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&&(an(),process.exit(0));let n=!!t.json,r=!!t.dryRun,i=!!t.yes,s=i||!process.stdin.isTTY;n||on(),p(n,{event:"start",version:ee});let c=o??(i?"./my-saas-app":void 0),a;if(c)a=c;else if(s)a="./my-saas-app";else{let m=await C.group({name:()=>C.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:f=>{if(f.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(w.red(`\u2718 Cancelled
2917
+ `)),process.exit(130)}});a=String(m.name)}let d=ut.basename(ut.resolve(a)),u=t.pm??$s(),h=!!t.region,O=!!t.auth,M=!!t.payment,D=!!t.ai,Xe=!!t.email,v=!!t.storage,l=!!t.monitoring,R=!!t.analytics,mt=!!t.sms,en=t.i18n!==void 0,y,ze,X,Qe,F,N,Y=En(t.socialLogin),Je,Tt,ue,Ne,z,j,gt;if(s){y=Yo(t.region),ze=Lo(t.orm),X=Uo(t.db);let m=M?t.payment:$o(y);Qe=Mo(m),F=Do(m),N=Fo(t.auth);let f=Dt({mode:D?t.ai?.trim().toLowerCase()==="none"?"none":"direct":"gateway",providerIds:D?jo(t.ai):void 0});Je=f.mode,Tt=f.routing,ue=f.providerIds,z=Bo(t.deploy),j=Ko(t.docs,n),gt=en?!!t.i18n:!0}else{let m={};h||(m.region=()=>C.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"})),O||(m.auth=()=>C.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk"},{value:"betterauth",label:"Better Auth"},{value:"none",label:"None"}],initialValue:"clerk"})),D||(m.aiMode=()=>C.select({message:"AI topology?",options:[{value:"gateway",label:"Multi-provider AI Gateway / router",hint:"recommended"},{value:"direct",label:"Direct SDK/provider adapters"},{value:"custom",label:"OpenAI-compatible endpoint"},{value:"none",label:"Skip AI"}],initialValue:"gateway"}),m.aiProviders=({results:E})=>{if(E.aiMode!=="direct")return Promise.resolve([]);let Q=Mt.map(Ut=>({value:Ut.id,label:`[${Ut.category}] ${Ut.name}`}));return C.multiselect({message:"Select direct AI provider adapters (expert path)",options:Q,initialValues:["openai"],required:!1})},m.customAiName=({results:E})=>E.aiMode==="custom"?C.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),m.customAiBaseUrl=({results:E})=>E.aiMode==="custom"?C.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:Q=>{if(Q.length===0)return"Base URL is required."}}):Promise.resolve(void 0),m.customAiApiKeyEnv=({results:E})=>E.aiMode==="custom"?C.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0));let f=Object.keys(m).length>0?await C.group(m,{onCancel:()=>{process.stdout.write(w.red(`\u2718 Cancelled
2918
+ `)),process.exit(130)}}):{};y=Yo(h?t.region:f.region),ze=Lo(t.orm),X=Uo(t.db);let V=M?t.payment:$o(y);Qe=Mo(V),F=Do(V),N=Fo(O?t.auth:f.auth);let St=f.aiMode==="custom"?{name:f.customAiName??"custom",baseURL:f.customAiBaseUrl??"",apiKeyEnvName:f.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,S=Dt({mode:D?t.ai?.trim().toLowerCase()==="none"?"none":"direct":f.aiMode??"gateway",providerIds:D?jo(t.ai):f.aiProviders,customEndpoint:St});Je=S.mode,Tt=S.routing,ue=S.providerIds,S.customEndpoint&&(Ne={name:S.customEndpoint.name,baseURL:S.customEndpoint.baseURL,apiKeyEnvName:S.customEndpoint.apiKeyEnvName}),z=Bo(t.deploy),j=Ko(t.docs,n),gt=en?!!t.i18n:!0}let b=Gs(y),ke=Xe?t.email:b.email,Te=qs(v?t.storage:void 0,b.storage),Oe=l?t.monitoring:b.monitoring,Ue=R?t.analytics:b.analytics,Le=mt?t.sms:b.sms,Me=t.queue??b.queue,De=t.search??b.search,Ze=t.cache??b.cache,Fe=t.notifications??b.notifications,je=t.webhooks??b.webhooks,et=t.cms??b.cms,Ve=t.featureFlags??b.featureFlags,Ke=t.captcha??b.captcha,ft=t.mcp??b.mcp,tt=t.metering??b.metering,Be=t.billingMode??b.billingMode,Ye=t.idp??b.idp,$e=rn([{flag:"queue",provider:Me},{flag:"search",provider:De},{flag:"notifications",provider:Fe},{flag:"webhooks",provider:je},{flag:"feature-flags",provider:Ve},{flag:"captcha",provider:Ke}]);function Ot(){for(let m of $e)if(n)p(!0,{event:"warn",step:m.flag,provider:m.provider,packageStatus:m.status,message:te(m.status)});else{let f=qe(m.status);process.stdout.write(w.yellow(`\u26A0 ${m.flag}=${m.provider} ${f} \u2014 ${te(m.status)}
2919
+ `))}}let me={region:y,orm:ze,database:X,payment:Qe,aiMode:Je,aiRouting:Tt,aiProviders:ue,customAiEndpoint:Ne,deployTarget:z,docs:j,i18n:gt,email:ke,storage:Te,monitoring:Oe,analytics:Ue,sms:Le,queue:Me,search:De,cache:Ze,notifications:Fe,webhooks:je,cms:et,featureFlags:Ve,captcha:Ke,mcp:ft,metering:tt,billingMode:Be,idp:Ye},yt=[["Project name",d],["Region",y],["Auth",N],["Social login",Y.length>0?Y.map(m=>nt.find(f=>f.id===m)?.name??m).join(", "):"none"],["ORM",ze],["Database",X],["Payment",F],["AI topology",`${Je}${ue.length>0?` (${ue.join(", ")} seed)`:""}${Ne?" + custom endpoint":""}`],["Email",ke],["Storage",Te],["Monitoring",Oe],["Analytics",Ue],["SMS",Le],["Deploy Target",z],["Docs Framework",j]];n?yt.forEach(([m,f],V)=>{p(!0,{event:"step",step:m,value:f,index:V+1,total:yt.length})}):yt.forEach(([m,f],V)=>{pn({index:V+1,total:yt.length,label:m,value:f})});let qo={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},tn=Date.now();if(r){let m=ue.length,f=[`clone template \u2192 ${a}`,"write nebutra.config.json",`prune template (orm=${ze}, i18n=${gt})`,`region \u2192 ${y}`,`auth \u2192 ${N==="none"?"skip (remove packages/auth)":`configure ${N}`}`,...Y.length>0?[`social-login \u2192 generate ${Y.length} callback route${Y.length===1?"":"s"} + SocialLoginButtons.tsx (${Y.join(", ")})`]:[],`db \u2192 ${X==="none"?"skip (remove packages/db)":`configure Prisma for ${X}`}`,`payment \u2192 ${F==="none"?"skip (remove packages/billing)":`configure ${F}`}`,...j!=="none"?[`docs \u2192 scaffold apps/docs (${j==="fumadocs"?"fumadocs":`${j} \u2192 fumadocs fallback`})`]:[],...m>0||Ne?[`ai-providers \u2192 generate ${Je} registry seed + env (${m}${Ne?" + custom":""} provider${m===1&&!Ne?"":"s"})`]:[],...ke!=="none"?[`email \u2192 configure ${ke}`]:[],...Te!=="none"?[`storage \u2192 configure ${Te}`]:[],...Oe!=="none"?[`monitoring \u2192 configure ${Oe}`]:[],...Ue!=="none"?[`analytics \u2192 configure ${Ue}`]:[],...Le!=="none"?[`sms \u2192 configure ${Le}`]:[],...Me!=="none"?[`queue \u2192 configure ${Me}`]:[],...De!=="none"?[`search \u2192 configure ${De}`]:[],...Ze!=="none"?[`cache \u2192 configure ${Ze}`]:[],...Fe!=="none"?[`notifications \u2192 configure ${Fe}`]:[],...je!=="none"?[`webhooks \u2192 configure ${je}`]:[],...et!=="none"?[`cms \u2192 configure ${et}`]:[],...Ve!=="none"?[`feature-flags \u2192 configure ${Ve}`]:[],...Ke!=="none"?[`captcha \u2192 configure ${Ke}`]:[],`mcp \u2192 ${ft==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${tt==="off"?"disabled":tt==="auto"?Qe!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...Be!=="usage"?[`billing-mode \u2192 ${Be}`]:[],...Ye!=="clerk"?[`idp \u2192 ${Ye}`]:[],`compliance \u2192 inject ${y} 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)",...z!=="none"?[`deploy \u2192 inject ${z} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${u} install`,t.git===!1?"skip git init":"run git init"];if(n){for(let V of f)p(!0,{event:"plan",action:V});Ot(),p(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
2910
2920
  `+w.bold(`Dry run \u2014 planned actions:
2911
2921
  `));for(let V of f)process.stdout.write(` \u2022 ${V}
2912
- `);et.length>0&&(process.stdout.write(`
2922
+ `);$e.length>0&&(process.stdout.write(`
2913
2923
  `+w.bold(w.yellow(`Preview-status providers selected:
2914
2924
  `))),Ot()),process.stdout.write(w.dim(`
2915
2925
  No files were written.
2916
2926
  `))}process.exit(0)}let Go=async()=>{process.stdout.write(`
2917
2927
  `+w.red(`\u2718 Cancelled
2918
- `)),le.existsSync(s)&&await C.confirm({message:`Cleanup partial install at ${s}?`,initialValue:!0})===!0&&(le.rmSync(s,{recursive:!0,force:!0}),process.stdout.write(w.dim(` \u2713 Removed ${s}
2919
- `))),process.exit(130)};process.on("SIGINT",Go);try{p(n,{event:"step",step:"clone",status:"start"}),await Zn(s),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await co(s,d),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await xn(s,ue),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await Eo(s,ue),p(n,{event:"step",step:"prune",status:"ok"});let m=dt.join(s,"packages/db/prisma/schema.prisma");if(le.existsSync(m)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let S=le.readFileSync(m,"utf-8"),E=Wt(S,{auth:N,payment:F,"billing-mode":Ke,idp:Be,template:"saas"});le.writeFileSync(m,E),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(S){let E=S instanceof Error?S.message:String(S);p(n,{event:"step",step:"schema-prune",status:"error",error:E})}}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"auth",choice:N,status:"start"}),await yn(s,N),p(n,{event:"step",step:"auth",choice:N,status:"ok"}),Y.length>0?(p(n,{event:"step",step:"social-login",providers:Y,status:"start"}),await vn(s,Y,N),p(n,{event:"step",step:"social-login",providers:Y,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:X,status:"start"}),await Tn(s,X,d),p(n,{event:"step",step:"db",choice:X,status:"ok"}),p(n,{event:"step",step:"payment",choice:F,status:"start"}),await lo(s,F),p(n,{event:"step",step:"payment",choice:F,status:"ok"}),await jn(s,Ne,y),n&&p(!0,{event:"step",step:"email",choice:Ne,status:"ok"}),await xo(s,ke,y),n&&p(!0,{event:"step",step:"storage",choice:ke,status:"ok"}),await io(s,Te,y),n&&p(!0,{event:"step",step:"monitoring",choice:Te,status:"ok"}),await un(s,Oe,y),n&&p(!0,{event:"step",step:"analytics",choice:Oe,status:"ok"}),await wo(s,Ue,y),n&&p(!0,{event:"step",step:"sms",choice:Ue,status:"ok"}),await _o(s,Le,y),n&&p(!0,{event:"step",step:"queue",choice:Le,status:"ok"}),await Io(s,Me,y),n&&p(!0,{event:"step",step:"search",choice:Me,status:"ok"}),await bn(s,Qe,y),n&&p(!0,{event:"step",step:"cache",choice:Qe,status:"ok"}),await ao(s,De,y),n&&p(!0,{event:"step",step:"notifications",choice:De,status:"ok"}),await ko(s,Fe,y),n&&p(!0,{event:"step",step:"webhooks",choice:Fe,status:"ok"}),await wn(s,Je,y),n&&p(!0,{event:"step",step:"cms",choice:Je,status:"ok"}),await Gn(s,je,y),n&&p(!0,{event:"step",step:"feature-flags",choice:je,status:"ok"}),await An(s,Ve,y),n&&p(!0,{event:"step",step:"captcha",choice:Ve,status:"ok"}),await eo(s,gt),n&&p(!0,{event:"step",step:"mcp",mode:gt,status:"ok"}),await no(s,Ze,Xe),n&&p(!0,{event:"step",step:"metering",mode:Ze,status:"ok"}),ue.orm==="prisma"&&ue.database!=="none"){let S=dt.join(s,"packages/db/prisma/schema.prisma");if(le.existsSync(S)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let E=le.readFileSync(S,"utf8"),Q=Wt(E,{auth:N,payment:F,"billing-mode":Ke,idp:Be,template:"saas"});le.writeFileSync(S,Q),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(E){let Q=E instanceof Error?E.message:String(E);p(n,{event:"step",step:"schema-prune",status:"error",error:Q})}}else p(n,{event:"step",step:"schema-prune",status:"skip"})}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"billing-mode",choice:Ke,status:"ok"}),p(n,{event:"step",step:"idp",choice:Be,status:"ok"}),await Rn(s,y),n&&p(!0,{event:"step",step:"compliance",region:y,status:"ok"}),await $n(s),await Ao(s,N),await To(s,{projectName:d,region:y}),ue.aiMode!=="none"){p(n,{event:"step",step:"ai-providers",status:"start"});let S={providerIds:ue.aiProviders,customEndpoint:ue.customAiEndpoint},E=dt.join(s,"packages/ai-providers/templates");await yo(s,S,E),p(n,{event:"step",step:"ai-providers",status:"ok"})}else p(n,{event:"step",step:"ai-providers",status:"skip"});if(p(n,{event:"step",step:"docs",status:"start"}),j!=="none"?(await Ln(s,{framework:j,projectName:d}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:j,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),z!=="none"&&await On(s,z),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await Kn(s,qo),p(n,{event:"step",step:"env",status:"ok"}),t.install!==!1){let S=u==="bun"?"bun install":`${u} install`;n?p(!0,{event:"step",step:"install",pm:u,status:"start"}):process.stdout.write(w.dim(` Installing dependencies with ${u}\u2026
2920
- `));try{kt(S,{cwd:s,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(E){let Q=E instanceof Error?E.message:String(E);n?p(!0,{event:"step",step:"install",status:"error",error:Q}):process.stdout.write(w.yellow(` \u26A0 install failed \u2014 run '${S}' manually.
2921
- `))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{kt("git init -q",{cwd:s,stdio:"ignore"}),kt("git add -A",{cwd:s,stdio:"ignore"}),kt('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:s,stdio:"ignore"}),p(n,{event:"step",step:"git-init",status:"ok"})}catch(S){let E=S instanceof Error?S.message:String(S);n?p(!0,{event:"step",step:"git-init",status:"error",error:E}):process.stdout.write(w.yellow(` \u26A0 git init skipped \u2014 not fatal.
2922
- `))}}else p(n,{event:"step",step:"git-init",status:"skip"});let yt=Math.max(1,Math.round((Date.now()-tn)/1e3));mn({template_version:ee,package_manager:u,region:y,auth:N,payment:F,ai_providers:de,deploy_target:z,duration_ms:Date.now()-tn}),et.length>0&&Ot(),n?p(!0,{event:"done",status:"ok",elapsedSec:yt,targetDir:s,previewSelections:et}):sn({elapsedSec:yt,targetDir:s,skippedInstall:t.install===!1,previewSelections:et});try{Bs({pkg:{name:Oo,version:ee},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(m){let f=m instanceof Error?m.message:String(m);n?p(!0,{event:"error",message:f}):process.stdout.write(w.red(`
2928
+ `)),de.existsSync(a)&&await C.confirm({message:`Cleanup partial install at ${a}?`,initialValue:!0})===!0&&(de.rmSync(a,{recursive:!0,force:!0}),process.stdout.write(w.dim(` \u2713 Removed ${a}
2929
+ `))),process.exit(130)};process.on("SIGINT",Go);try{p(n,{event:"step",step:"clone",status:"start"}),await Zn(a),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await co(a,d),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await xn(a,me),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await Eo(a,me),p(n,{event:"step",step:"prune",status:"ok"});let m=ut.join(a,"packages/db/prisma/schema.prisma");if(de.existsSync(m)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let S=de.readFileSync(m,"utf-8"),E=Wt(S,{auth:N,payment:F,"billing-mode":Be,idp:Ye,template:"saas"});de.writeFileSync(m,E),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(S){let E=S instanceof Error?S.message:String(S);p(n,{event:"step",step:"schema-prune",status:"error",error:E})}}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"auth",choice:N,status:"start"}),await yn(a,N),p(n,{event:"step",step:"auth",choice:N,status:"ok"}),Y.length>0?(p(n,{event:"step",step:"social-login",providers:Y,status:"start"}),await vn(a,Y,N),p(n,{event:"step",step:"social-login",providers:Y,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:X,status:"start"}),await Tn(a,X,d),p(n,{event:"step",step:"db",choice:X,status:"ok"}),p(n,{event:"step",step:"payment",choice:F,status:"start"}),await lo(a,F),p(n,{event:"step",step:"payment",choice:F,status:"ok"}),await jn(a,ke,y),n&&p(!0,{event:"step",step:"email",choice:ke,status:"ok"}),await xo(a,Te,y),n&&p(!0,{event:"step",step:"storage",choice:Te,status:"ok"}),await io(a,Oe,y),n&&p(!0,{event:"step",step:"monitoring",choice:Oe,status:"ok"}),await un(a,Ue,y),n&&p(!0,{event:"step",step:"analytics",choice:Ue,status:"ok"}),await wo(a,Le,y),n&&p(!0,{event:"step",step:"sms",choice:Le,status:"ok"}),await _o(a,Me,y),n&&p(!0,{event:"step",step:"queue",choice:Me,status:"ok"}),await Io(a,De,y),n&&p(!0,{event:"step",step:"search",choice:De,status:"ok"}),await bn(a,Ze,y),n&&p(!0,{event:"step",step:"cache",choice:Ze,status:"ok"}),await ao(a,Fe,y),n&&p(!0,{event:"step",step:"notifications",choice:Fe,status:"ok"}),await ko(a,je,y),n&&p(!0,{event:"step",step:"webhooks",choice:je,status:"ok"}),await wn(a,et,y),n&&p(!0,{event:"step",step:"cms",choice:et,status:"ok"}),await Gn(a,Ve,y),n&&p(!0,{event:"step",step:"feature-flags",choice:Ve,status:"ok"}),await An(a,Ke,y),n&&p(!0,{event:"step",step:"captcha",choice:Ke,status:"ok"}),await eo(a,ft),n&&p(!0,{event:"step",step:"mcp",mode:ft,status:"ok"}),await no(a,tt,Qe),n&&p(!0,{event:"step",step:"metering",mode:tt,status:"ok"}),me.orm==="prisma"&&me.database!=="none"){let S=ut.join(a,"packages/db/prisma/schema.prisma");if(de.existsSync(S)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let E=de.readFileSync(S,"utf8"),Q=Wt(E,{auth:N,payment:F,"billing-mode":Be,idp:Ye,template:"saas"});de.writeFileSync(S,Q),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(E){let Q=E instanceof Error?E.message:String(E);p(n,{event:"step",step:"schema-prune",status:"error",error:Q})}}else p(n,{event:"step",step:"schema-prune",status:"skip"})}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"billing-mode",choice:Be,status:"ok"}),p(n,{event:"step",step:"idp",choice:Ye,status:"ok"}),await Rn(a,y),n&&p(!0,{event:"step",step:"compliance",region:y,status:"ok"}),await $n(a),await Ao(a,N),await To(a,{projectName:d,region:y,previewSelections:$e}),me.aiMode!=="none"){p(n,{event:"step",step:"ai-providers",status:"start"});let S={providerIds:me.aiProviders,customEndpoint:me.customAiEndpoint},E=ut.join(a,"packages/ai-providers/templates");await yo(a,S,E),p(n,{event:"step",step:"ai-providers",status:"ok"})}else p(n,{event:"step",step:"ai-providers",status:"skip"});if(p(n,{event:"step",step:"docs",status:"start"}),j!=="none"?(await Ln(a,{framework:j,projectName:d}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:j,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),z!=="none"&&await On(a,z),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await Kn(a,qo),p(n,{event:"step",step:"env",status:"ok"}),t.install!==!1){let S=u==="bun"?"bun install":`${u} install`;n?p(!0,{event:"step",step:"install",pm:u,status:"start"}):process.stdout.write(w.dim(` Installing dependencies with ${u}\u2026
2930
+ `));try{kt(S,{cwd:a,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(E){let Q=E instanceof Error?E.message:String(E);n?p(!0,{event:"step",step:"install",status:"error",error:Q}):process.stdout.write(w.yellow(` \u26A0 install failed \u2014 run '${S}' manually.
2931
+ `))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{kt("git init -q",{cwd:a,stdio:"ignore"}),kt("git add -A",{cwd:a,stdio:"ignore"}),kt('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:a,stdio:"ignore"}),p(n,{event:"step",step:"git-init",status:"ok"})}catch(S){let E=S instanceof Error?S.message:String(S);n?p(!0,{event:"step",step:"git-init",status:"error",error:E}):process.stdout.write(w.yellow(` \u26A0 git init skipped \u2014 not fatal.
2932
+ `))}}else p(n,{event:"step",step:"git-init",status:"skip"});let St=Math.max(1,Math.round((Date.now()-tn)/1e3));mn({template_version:ee,package_manager:u,region:y,auth:N,payment:F,ai_providers:ue,deploy_target:z,duration_ms:Date.now()-tn}),$e.length>0&&Ot(),n?p(!0,{event:"done",status:"ok",elapsedSec:St,targetDir:a,previewSelections:$e}):sn({elapsedSec:St,targetDir:a,skippedInstall:t.install===!1,previewSelections:$e});try{Ys({pkg:{name:Oo,version:ee},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(m){let f=m instanceof Error?m.message:String(m);n?p(!0,{event:"error",message:f}):process.stdout.write(w.red(`
2923
2933
  \u2718 Failed: ${f}
2924
- `)),process.exit(1)}}Gs().catch(e=>{process.stderr.write(String(e)+`
2934
+ `)),process.exit(1)}}Hs().catch(e=>{process.stderr.write(String(e)+`
2925
2935
  `),process.exit(1)});
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "create-sailor",
3
- "version": "1.3.5",
3
+ "version": "1.3.6",
4
4
  "description": "Governed AI-native SaaS scaffolder for Nebutra Sailor. Bootstrap a production-ready Next.js + Hono + Prisma monorepo with multi-tenant foundations, region-aware defaults, and AI integrations.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
- "create-sailor": "./dist/index.js"
8
+ "create-sailor": "dist/index.js"
9
9
  },
10
10
  "files": [
11
11
  "dist",