create-sailor 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import{execSync as Pt}from"child_process";import Se from"fs";import Ct from"path";import*as x from"@clack/prompts";import{Command as Ta}from"commander";import C from"picocolors";import Na from"update-notifier";import Pr from"cfonts";import Cr from"picocolors";import fn from"fs";import Wt from"path";import{fileURLToPath as _r}from"url";function br(){try{let t=Wt.dirname(_r(import.meta.url));for(let o=0;o<4;o++){let n=Wt.join(t,"package.json");if(fn.existsSync(n)){let r=fn.readFileSync(n,"utf-8"),s=JSON.parse(r);if(s.name==="create-sailor"&&typeof s.version=="string")return s.version}t=Wt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ce=br();function yn(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ce}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
3
- `));return}Pr.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(Cr.dim(` AI-Native SaaS Template \xB7 v${ce} \xB7 nebutra.com
2
+ import{execSync as Rt}from"child_process";import _e from"fs";import de from"path";import*as O from"@clack/prompts";import{Command as Za}from"commander";import A from"picocolors";import ec from"update-notifier";import Ur from"cfonts";import Mr from"picocolors";import vn from"fs";import en from"path";import{fileURLToPath as Or}from"url";function Lr(){try{let t=en.dirname(Or(import.meta.url));for(let o=0;o<4;o++){let n=en.join(t,"package.json");if(vn.existsSync(n)){let r=vn.readFileSync(n,"utf-8"),s=JSON.parse(r);if(s.name==="create-sailor"&&typeof s.version=="string")return s.version}t=en.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ae=Lr();function _n(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ae}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
3
+ `));return}Ur.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(Mr.dim(` AI-Native SaaS Template \xB7 v${ae} \xB7 nebutra.com
4
4
 
5
- `))}import P from"picocolors";var Ar={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 wr(e){return e?Ar[e]??"stable":"stable"}function tt(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function pe(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 Sn(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=wr(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function Ir(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function hn(e){let t=Ir(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",s=t?"\u{1F4E7}":"*",c=["",` ${t?P.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?P.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?P.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?P.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?P.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?P.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?P.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?P.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?P.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?P.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?P.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?P.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?P.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?P.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`,` ${n} pnpm audit ${t?P.dim("\u2192 scan deps for known CVEs"):"-> scan deps for known CVEs"}`);let a=e.previewSelections??[];if(a.length>0){let T=t?P.bold(P.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${T}`);for(let N of a){let D=tt(N.status),ae=` ${n} ${N.flag} (${N.provider}) ${D}`;c.push(t?P.yellow(ae):ae)}c.push("",` ${t?P.dim(pe("foundation")):pe("foundation")}`,` ${t?P.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?P.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"}`)}let l=e.waveFeatures??{},m=T=>T!==!1,S=[];m(l.apiKeys)&&S.push("Manage API keys at /settings/api-keys"),m(l.auditLog)&&S.push("View audit log at /settings/audit-log"),S.push("Configure webhooks at /settings/webhooks"),m(l.commandPalette)&&S.push("Press Cmd/Ctrl+K to open the command palette"),S.push("Edit notification preferences at /settings/notifications"),S.push("Export your data at /settings/account/export"),l.chinaCompliance&&S.push("China deployments \u2014 see packages/ops/china-compliance/README.md"),c.push("",` ${t?P.bold("What you can do next:"):"What you can do next:"}`);for(let T of S)c.push(` ${n} ${T}`);c.push("",` ${t?P.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${s} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
5
+ `))}import P from"picocolors";var Dr={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",invite:"foundation"};function Fr(e){return e?Dr[e]??"stable":"stable"}function rt(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function me(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 bn(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=Fr(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function jr(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Pn(e){let t=jr(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",s=t?"\u{1F4E7}":"*",c=["",` ${t?P.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?P.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?P.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?P.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?P.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?P.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?P.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?P.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?P.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?P.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?P.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?P.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?P.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?P.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`,` ${n} pnpm audit ${t?P.dim("\u2192 scan deps for known CVEs"):"-> scan deps for known CVEs"}`);let a=e.previewSelections??[];if(a.length>0){let C=t?P.bold(P.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${C}`);for(let k of a){let $=rt(k.status),ue=` ${n} ${k.flag} (${k.provider}) ${$}`;c.push(t?P.yellow(ue):ue)}c.push("",` ${t?P.dim(me("foundation")):me("foundation")}`,` ${t?P.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?P.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"}`)}let l=e.waveFeatures??{},d=C=>C!==!1,S=[];d(l.apiKeys)&&S.push("Manage API keys at /settings/api-keys"),d(l.auditLog)&&S.push("View audit log at /settings/audit-log"),S.push("Configure webhooks at /settings/webhooks"),d(l.commandPalette)&&S.push("Press Cmd/Ctrl+K to open the command palette"),S.push("Edit notification preferences at /settings/notifications"),S.push("Export your data at /settings/account/export"),l.chinaCompliance&&S.push("China deployments \u2014 see packages/ops/china-compliance/README.md"),c.push("",` ${t?P.bold("What you can do next:"):"What you can do next:"}`);for(let C of S)c.push(` ${n} ${C}`);c.push("",` ${t?P.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${s} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
6
6
  `)+`
7
- `)}var Rr=`Usage: create-sailor [name] [options]
7
+ `)}var Vr=`Usage: create-sailor [name] [options]
8
8
 
9
9
  Arguments:
10
10
  name project directory (default: ./my-saas-app)
@@ -12,7 +12,7 @@ Arguments:
12
12
  Core options:
13
13
  -p, --pm <id> npm | pnpm | yarn | bun (auto-detected)
14
14
  --region <id> global | cn | hybrid (default: global)
15
- --auth <id> clerk | betterauth | none
15
+ --auth <id> clerk | betterauth | nextauth | supabase | none
16
16
  --ai <ids> expert/non-interactive provider seed (e.g. openai,anthropic)
17
17
 
18
18
  Interactive AI topology:
@@ -45,6 +45,7 @@ Feature flags (region-based smart defaults):
45
45
  --captcha <id> turnstile | hcaptcha | aliyun-slide | none [WIP]
46
46
  --billing-mode <mode> usage | seat | credits (default: usage)
47
47
  --idp <id> clerk | oauth-server (default: clerk)
48
+ --access-gate <mode> none | invite (default: none)
48
49
 
49
50
  Preview statuses:
50
51
  [Foundation] \u2014 types + factory complete; adapters need external credentials & may not work out-of-the-box
@@ -73,9 +74,9 @@ Examples:
73
74
  $ npx create-sailor@latest my-app --region=cn --auth=clerk
74
75
  $ npx create-sailor@latest my-app --region=hybrid --ai=openai,deepseek
75
76
  $ npm create sailor@latest --dry-run --region=cn
76
- `;function En(){process.stdout.write(Rr)}import xt from"picocolors";function vn(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function kr(e){let t=vn()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return vn()?`${xt.dim(o)} ${xt.bold(n)} ${xt.dim(t)} ${xt.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function _n(e){process.stdout.write(kr(e)+`
77
- `)}var Xt=[{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:[]}],Za=Xt.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var xr=["openai","anthropic","google"],Tr=["openai"];function zt(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...xr];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:[...Tr];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 nt from"fs";import V from"path";var bn=[{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:""}],nc=bn.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Pn(e){return bn.find(t=>t.id===e)}function Nr(e){nt.mkdirSync(e,{recursive:!0})}function z(e,t){Nr(V.dirname(e)),nt.writeFileSync(e,t)}function _e(e,t){let o=V.join(e,".env.example");nt.existsSync(o)?nt.appendFileSync(o,`
78
- `+t):nt.writeFileSync(o,t)}function Or(e){let t=`"use client";
77
+ `;function An(){process.stdout.write(Vr)}import Lt from"picocolors";function Cn(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Br(e){let t=Cn()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return Cn()?`${Lt.dim(o)} ${Lt.bold(n)} ${Lt.dim(t)} ${Lt.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function In(e){process.stdout.write(Br(e)+`
78
+ `)}var tn=[{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:[]}],_c=tn.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var Kr=["openai","anthropic","google"],$r=["openai"];function nn(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...Kr];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:[...$r];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 st from"fs";import V from"path";var wn=[{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:""}],Ac=wn.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Rn(e){return wn.find(t=>t.id===e)}function Yr(e){st.mkdirSync(e,{recursive:!0})}function Z(e,t){Yr(V.dirname(e)),st.writeFileSync(e,t)}function Ce(e,t){let o=V.join(e,".env.example");st.existsSync(o)?st.appendFileSync(o,`
79
+ `+t):st.writeFileSync(o,t)}function qr(e){let t=`"use client";
79
80
  /**
80
81
  * PostHog browser SDK \u2014 lazy-initialized on first access.
81
82
  */
@@ -158,11 +159,11 @@ export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
158
159
 
159
160
  return <>{children}</>;
160
161
  }
161
- `;z(V.join(e,"src","lib","analytics","posthog.client.ts"),t),z(V.join(e,"src","lib","analytics","posthog.server.ts"),o),z(V.join(e,"src","components","analytics","AnalyticsProvider.tsx"),n)}function Ur(){return`# PostHog \u2014 product analytics
162
+ `;Z(V.join(e,"src","lib","analytics","posthog.client.ts"),t),Z(V.join(e,"src","lib","analytics","posthog.server.ts"),o),Z(V.join(e,"src","components","analytics","AnalyticsProvider.tsx"),n)}function Gr(){return`# PostHog \u2014 product analytics
162
163
  POSTHOG_KEY=
163
164
  NEXT_PUBLIC_POSTHOG_KEY=
164
165
  NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
165
- `}function Lr(e){z(V.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
166
+ `}function Hr(e){Z(V.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
166
167
  /**
167
168
  * Plausible script tag \u2014 lightweight, privacy-friendly analytics.
168
169
  */
@@ -182,10 +183,10 @@ export function PlausibleScript() {
182
183
  />
183
184
  );
184
185
  }
185
- `)}function Mr(){return`# Plausible \u2014 privacy-friendly analytics
186
+ `)}function Wr(){return`# Plausible \u2014 privacy-friendly analytics
186
187
  NEXT_PUBLIC_PLAUSIBLE_DOMAIN=
187
188
  NEXT_PUBLIC_PLAUSIBLE_SRC=https://plausible.io/js/script.js
188
- `}function Dr(e){z(V.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
189
+ `}function Xr(e){Z(V.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
189
190
  /**
190
191
  * Umami analytics \u2014 self-hosted OR umami.is cloud.
191
192
  */
@@ -205,10 +206,10 @@ export function UmamiScript() {
205
206
  />
206
207
  );
207
208
  }
208
- `)}function Fr(){return`# Umami \u2014 self-hostable analytics
209
+ `)}function zr(){return`# Umami \u2014 self-hostable analytics
209
210
  NEXT_PUBLIC_UMAMI_WEBSITE_ID=
210
211
  NEXT_PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
211
- `}function jr(e){let t=`"use client";
212
+ `}function Jr(e){let t=`"use client";
212
213
  import mixpanel from "mixpanel-browser";
213
214
 
214
215
  let initialized = false;
@@ -247,10 +248,10 @@ export function trackServer(
247
248
  if (!c) return;
248
249
  c.track(event, { distinct_id: distinctId, ...properties });
249
250
  }
250
- `;z(V.join(e,"src","lib","analytics","mixpanel.client.ts"),t),z(V.join(e,"src","lib","analytics","mixpanel.server.ts"),o)}function Vr(){return`# Mixpanel \u2014 product analytics
251
+ `;Z(V.join(e,"src","lib","analytics","mixpanel.client.ts"),t),Z(V.join(e,"src","lib","analytics","mixpanel.server.ts"),o)}function Qr(){return`# Mixpanel \u2014 product analytics
251
252
  MIXPANEL_TOKEN=
252
253
  NEXT_PUBLIC_MIXPANEL_TOKEN=
253
- `}function Br(e){z(V.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
254
+ `}function Zr(e){Z(V.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
254
255
  /**
255
256
  * \u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji \u2014 hm.js \u57CB\u70B9\u811A\u672C.
256
257
  */
@@ -276,9 +277,9 @@ var _hmt = _hmt || [];
276
277
  />
277
278
  );
278
279
  }
279
- `)}function Kr(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
280
+ `)}function es(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
280
281
  NEXT_PUBLIC_BAIDU_STATS_ID=
281
- `}function $r(e){z(V.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
282
+ `}function ts(e){Z(V.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
282
283
  /**
283
284
  * \u795E\u7B56\u5206\u6790 (Sensors Analytics) \u2014 sa-sdk-javascript \u5C01\u88C5.
284
285
  */
@@ -306,10 +307,10 @@ export function initSensors(): void {
306
307
  }
307
308
 
308
309
  export { sensors };
309
- `)}function Yr(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
310
+ `)}function ns(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
310
311
  NEXT_PUBLIC_SENSORS_SERVER_URL=
311
312
  NEXT_PUBLIC_SENSORS_APP_JS_URL=
312
- `}function qr(e){z(V.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
313
+ `}function os(e){Z(V.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
313
314
  /**
314
315
  * GrowingIO CDP \u2014 inline snippet installer.
315
316
  */
@@ -334,21 +335,21 @@ gdp("send");
334
335
  />
335
336
  );
336
337
  }
337
- `)}function Gr(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
338
+ `)}function rs(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
338
339
  NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
339
- `}async function Cn(e,t,o="global"){let n=Pn(t);if(!n||n.id==="none")return;let r=V.join(e,"apps","web");if(!nt.existsSync(r))return;let s=n.id;try{switch(s){case"posthog":Or(r),_e(e,Ur());return;case"plausible":Lr(r),_e(e,Mr());return;case"umami":Dr(r),_e(e,Fr());return;case"mixpanel":jr(r),_e(e,Vr());return;case"baidu":Br(r),_e(e,Kr());return;case"sensors":$r(r),_e(e,Yr());return;case"growingio":qr(r),_e(e,Gr());return;default:return}}catch(i){throw console.error(`Failed to apply analytics selection "${t}":`,i),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Hr="https://analytics.nebutra.com";function Wr(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function An(e,t={}){Wr(t)||(async()=>{try{let o=await import("@nebutra/analytics");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 K from"fs";import G from"path";function be(e){K.existsSync(e)&&K.rmSync(e,{recursive:!0,force:!0})}function Jt(e,t){let o=G.join(e,".env.example");K.existsSync(o)?K.appendFileSync(o,`
340
- `+t):K.writeFileSync(o,t)}function Qt(e,t){if(!K.existsSync(e))return;let o=K.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*(?:"[^"]+"\s*\|\s*)+"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&K.writeFileSync(e,n)}function Xr(e,t){let o=G.join(e,"README.md");if(!K.existsSync(o)){K.writeFileSync(o,t);return}K.appendFileSync(o,`
341
- `+t)}async function wn(e,t){let o=G.join(e,"packages","iam","auth");if(!K.existsSync(o))return;if(t==="none"){be(o),Xr(e,`
340
+ `}async function kn(e,t,o="global"){let n=Rn(t);if(!n||n.id==="none")return;let r=V.join(e,"apps","web");if(!st.existsSync(r))return;let s=n.id;try{switch(s){case"posthog":qr(r),Ce(e,Gr());return;case"plausible":Hr(r),Ce(e,Wr());return;case"umami":Xr(r),Ce(e,zr());return;case"mixpanel":Jr(r),Ce(e,Qr());return;case"baidu":Zr(r),Ce(e,es());return;case"sensors":ts(r),Ce(e,ns());return;case"growingio":os(r),Ce(e,rs());return;default:return}}catch(i){throw console.error(`Failed to apply analytics selection "${t}":`,i),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var ss="https://analytics.nebutra.com";function is(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function xn(e,t={}){is(t)||(async()=>{try{let o=await import("@nebutra/analytics");if(typeof o.createAnalyticsClient!="function")return;let n=o.createAnalyticsClient({posthog:{apiKey:process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.NEBUTRA_POSTHOG_HOST??ss},onError:()=>{}});if(typeof n?.track!="function")return;let r=n.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import q from"fs";import x from"path";function B(e){q.existsSync(e)&&q.rmSync(e,{recursive:!0,force:!0})}function Ut(e,t){let o=x.join(e,".env.example");q.existsSync(o)?q.appendFileSync(o,`
341
+ `+t):q.writeFileSync(o,t)}function Mt(e,t){if(!q.existsSync(e))return;let o=q.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*(?:"[^"]+"\s*\|\s*)+"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&q.writeFileSync(e,n)}function as(e,t){let o=x.join(e,"README.md");if(!q.existsSync(o)){q.writeFileSync(o,t);return}q.appendFileSync(o,`
342
+ `+t)}async function Nn(e,t){let o=x.join(e,"packages","iam","auth");if(!q.existsSync(o))return;if(t==="none"){B(o),as(e,`
342
343
  ## Auth
343
344
 
344
- Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth).
345
- `);return}let n=G.join(o,"src","providers"),r=G.join(o,"src","types.ts");if(t==="clerk"){be(G.join(n,"better-auth.ts")),be(G.join(n,"nextauth.ts")),Qt(r,"clerk"),Jt(e,`# Clerk auth
345
+ Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth, Supabase).
346
+ `);return}let n=x.join(o,"src","providers"),r=x.join(o,"src","types.ts");if(t==="clerk"){B(x.join(n,"better-auth.ts")),B(x.join(n,"nextauth.ts")),B(x.join(n,"supabase.ts")),Mt(r,"clerk"),Ut(e,`# Clerk auth
346
347
  CLERK_PUBLISHABLE_KEY=
347
348
  CLERK_SECRET_KEY=
348
- `);return}if(t==="betterauth"){be(G.join(n,"clerk.ts")),be(G.join(n,"nextauth.ts")),Qt(r,"better-auth"),Jt(e,`# Better Auth
349
+ `);return}if(t==="betterauth"){B(x.join(n,"clerk.ts")),B(x.join(n,"nextauth.ts")),B(x.join(n,"supabase.ts")),Mt(r,"better-auth"),Ut(e,`# Better Auth
349
350
  BETTER_AUTH_SECRET=
350
351
  BETTER_AUTH_URL=http://localhost:3000
351
- `);return}if(t==="nextauth"){be(G.join(n,"clerk.ts")),be(G.join(n,"better-auth.ts")),Qt(r,"nextauth"),Jt(e,`# NextAuth (Auth.js v5)
352
+ `);return}if(t==="nextauth"){B(x.join(n,"clerk.ts")),B(x.join(n,"better-auth.ts")),B(x.join(n,"supabase.ts")),Mt(r,"nextauth"),Ut(e,`# NextAuth (Auth.js v5)
352
353
  AUTH_SECRET=
353
354
  NEXTAUTH_URL=http://localhost:3000
354
355
  # OAuth (optional \u2014 leave blank to disable that provider)
@@ -356,7 +357,13 @@ GOOGLE_CLIENT_ID=
356
357
  GOOGLE_CLIENT_SECRET=
357
358
  GITHUB_CLIENT_ID=
358
359
  GITHUB_CLIENT_SECRET=
359
- `);return}}var gt=[{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"}],zr=new Set(gt.map(e=>e.id));function In(e){return gt.find(t=>t.id===e)}function Rn(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)zr.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import Ce from"fs";import Pe from"path";function Jr(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
360
+ `);return}if(t==="supabase"){B(x.join(n,"clerk.ts")),B(x.join(n,"better-auth.ts")),B(x.join(n,"nextauth.ts")),Mt(r,"supabase"),Ut(e,`# Supabase Auth
361
+ NEXT_PUBLIC_SUPABASE_URL=
362
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=
363
+ SUPABASE_URL=
364
+ SUPABASE_ANON_KEY=
365
+ SUPABASE_SERVICE_ROLE_KEY=
366
+ `);return}}var Et=[{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"}],cs=new Set(Et.map(e=>e.id));function Tn(e){return Et.find(t=>t.id===e)}function On(e){if(!e)return[];let t=e.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean);if(t.includes("none"))return[];let o=[],n=new Set;for(let r of t)cs.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import we from"fs";import Ie from"path";function ps(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
360
367
  // Generated by create-sailor \u2014 OAuth callback for ${e.name}
361
368
  // Primary auth provider: ${t}
362
369
  // Docs: ${e.docs}`,n={wechat:` const tokenRes = await fetch(
@@ -481,7 +488,7 @@ ${n[e.id]}
481
488
  void state;
482
489
  return NextResponse.redirect(new URL("/dashboard", req.url));
483
490
  }
484
- `}function Qr(e){return`"use client";
491
+ `}function ls(e){return`"use client";
485
492
 
486
493
  /**
487
494
  * SocialLoginButtons \u2014 generated by create-sailor.
@@ -524,23 +531,23 @@ export function SocialLoginButtons() {
524
531
  </div>
525
532
  );
526
533
  }
527
- `}function kn(e){Ce.mkdirSync(e,{recursive:!0})}function Zr(e,t){let o=Pe.join(e,".env.example");Ce.existsSync(o)?Ce.appendFileSync(o,`
528
- `+t):Ce.writeFileSync(o,t)}function es(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
534
+ `}function Ln(e){we.mkdirSync(e,{recursive:!0})}function ds(e,t){let o=Ie.join(e,".env.example");we.existsSync(o)?we.appendFileSync(o,`
535
+ `+t):we.writeFileSync(o,t)}function us(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
529
536
  `);return`${t}
530
537
  ${o}
531
- `}async function xn(e,t,o){if(!t||t.length===0)return;let n=Pe.join(e,"apps","web");if(!Ce.existsSync(n))return;let r=new Set,s=[];for(let l of t){if(r.has(l))continue;r.add(l);let m=In(l);m&&s.push(m)}if(s.length===0)return;for(let l of s)Zr(e,es(l));let i=Pe.join(n,"src","app","api","auth","callback");for(let l of s){let m=Pe.join(i,l.id);kn(m);let S=Pe.join(m,"route.ts");Ce.writeFileSync(S,Jr(l,o))}let c=Pe.join(n,"src","components","auth");kn(c);let a=Pe.join(c,"SocialLoginButtons.tsx");Ce.writeFileSync(a,Qr(s))}import ot from"fs";import Nn from"path";var Tt=[{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 Tn(e){return Tt.find(t=>t.id===e)}var Sc=Tt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import J from"fs";import Nt from"path";function Q(e,t){let o=Nt.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(`
532
- `);J.appendFileSync(o,c)}function Z(e,t,o){let n=Nt.join(e,".env.example");if(!J.existsSync(n))return;let r=J.readFileSync(n,"utf-8"),s=`${t}="${o}"`,i=new RegExp(`^${t}=.*$`,"m");if(i.test(r)){J.writeFileSync(n,r.replace(i,s));return}let c=r.endsWith(`
538
+ `}async function Un(e,t,o){if(!t||t.length===0)return;let n=Ie.join(e,"apps","web");if(!we.existsSync(n))return;let r=new Set,s=[];for(let l of t){if(r.has(l))continue;r.add(l);let d=Tn(l);d&&s.push(d)}if(s.length===0)return;for(let l of s)ds(e,us(l));let i=Ie.join(n,"src","app","api","auth","callback");for(let l of s){let d=Ie.join(i,l.id);Ln(d);let S=Ie.join(d,"route.ts");we.writeFileSync(S,ps(l,o))}let c=Ie.join(n,"src","components","auth");Ln(c);let a=Ie.join(c,"SocialLoginButtons.tsx");we.writeFileSync(a,ls(s))}import it from"fs";import Dn from"path";var Dt=[{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 Mn(e){return Dt.find(t=>t.id===e)}var jc=Dt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import ee from"fs";import Ft from"path";function te(e,t){let o=Ft.join(e,".env.example");if(!ee.existsSync(o)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(ee.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(`
539
+ `);ee.appendFileSync(o,c)}function ne(e,t,o){let n=Ft.join(e,".env.example");if(!ee.existsSync(n))return;let r=ee.readFileSync(n,"utf-8"),s=`${t}="${o}"`,i=new RegExp(`^${t}=.*$`,"m");if(i.test(r)){ee.writeFileSync(n,r.replace(i,s));return}let c=r.endsWith(`
533
540
  `)?"":`
534
- `;J.appendFileSync(n,`${c}${s}
535
- `)}var ts=["design","iam","commerce","integrations","platform","ops","ai"];function Ae(e,t){for(let n of ts){let r=Nt.join(e,"packages",n,t);if(J.existsSync(r))return r}let o=Nt.join(e,"packages",t);return J.existsSync(o)?o:null}function H(e,t){let o=Ae(e,t);o&&J.rmSync(o,{recursive:!0,force:!0})}function On(e){return ot.existsSync(e)?ot.readFileSync(e,"utf-8"):null}function ns(e,t){let o=Nn.join(e,".env.example"),n=On(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
536
- `);ot.appendFileSync(o,s)}function os(e,t,o){let n=Nn.join(e,".env.example"),r=On(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?ot.writeFileSync(n,r.replace(s,`${t}="${o}"`)):ot.appendFileSync(n,`${t}="${o}"
537
- `)}async function Un(e,t,o){let n=Ae(e,"cache");if(t==="none"){n&&ot.rmSync(n,{recursive:!0,force:!0});return}let r=Tn(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${Tt.map(s=>s.id).join(", ")}`);n&&(ns(e,r),os(e,"CACHE_PROVIDER",t))}var Ot=[{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 Ln(e){return Ot.find(t=>t.id===e)}var Ic=Ot.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Mn(e,t,o="global"){let n=Ln(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${Ot.map(r=>r.id).join(", ")}`);if(n.id==="none"){H(e,"captcha");return}n.envVars.length>0&&Q(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),Z(e,"CAPTCHA_PROVIDER",n.id)}import Lt from"fs";import rs from"path";var Ut=[{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 Dn(e){return Ut.find(t=>t.id===e)}var Nc=Ut.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Fn(e,t,o="global"){let n=Dn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${Ut.map(s=>s.id).join(", ")}`);let r=rs.join(e,"apps","studio");if(n.id==="none"){H(e,"sanity"),Lt.existsSync(r)&&Lt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(H(e,"sanity"),Lt.existsSync(r)&&Lt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&Q(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),Z(e,"CMS_PROVIDER",n.id)}import k from"fs";import R from"path";var ss=R.join("apps","web"),Zt=R.join("src","components","compliance"),ft=R.join("src","app","[locale]");function ee(e){return R.join(e,ss)}function is(e){k.mkdirSync(e,{recursive:!0})}function W(e,t){is(R.dirname(e)),k.writeFileSync(e,t,"utf8")}function en(e,t){let o=R.join(e,".env.example");if(k.existsSync(o)){if(k.readFileSync(o,"utf8").includes(t.split(`
538
- `)[0]??""))return;k.appendFileSync(o,`
541
+ `;ee.appendFileSync(n,`${c}${s}
542
+ `)}var ms=["design","iam","commerce","integrations","platform","ops","ai"];function Re(e,t){for(let n of ms){let r=Ft.join(e,"packages",n,t);if(ee.existsSync(r))return r}let o=Ft.join(e,"packages",t);return ee.existsSync(o)?o:null}function X(e,t){let o=Re(e,t);o&&ee.rmSync(o,{recursive:!0,force:!0})}function Fn(e){return it.existsSync(e)?it.readFileSync(e,"utf-8"):null}function gs(e,t){let o=Dn.join(e,".env.example"),n=Fn(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
543
+ `);it.appendFileSync(o,s)}function fs(e,t,o){let n=Dn.join(e,".env.example"),r=Fn(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?it.writeFileSync(n,r.replace(s,`${t}="${o}"`)):it.appendFileSync(n,`${t}="${o}"
544
+ `)}async function jn(e,t,o){let n=Re(e,"cache");if(t==="none"){n&&it.rmSync(n,{recursive:!0,force:!0});return}let r=Mn(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${Dt.map(s=>s.id).join(", ")}`);n&&(gs(e,r),fs(e,"CACHE_PROVIDER",t))}var jt=[{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 Vn(e){return jt.find(t=>t.id===e)}var Xc=jt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Bn(e,t,o="global"){let n=Vn(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${jt.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"captcha");return}n.envVars.length>0&&te(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"CAPTCHA_PROVIDER",n.id)}import Bt from"fs";import ys from"path";var Vt=[{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 Kn(e){return Vt.find(t=>t.id===e)}var ep=Vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function $n(e,t,o="global"){let n=Kn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${Vt.map(s=>s.id).join(", ")}`);let r=ys.join(e,"apps","studio");if(n.id==="none"){X(e,"sanity"),Bt.existsSync(r)&&Bt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(X(e,"sanity"),Bt.existsSync(r)&&Bt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&te(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"CMS_PROVIDER",n.id)}import T from"fs";import N from"path";var Ss=N.join("apps","web"),on=N.join("src","components","compliance"),vt=N.join("src","app","[locale]");function oe(e){return N.join(e,Ss)}function hs(e){T.mkdirSync(e,{recursive:!0})}function z(e,t){hs(N.dirname(e)),T.writeFileSync(e,t,"utf8")}function rn(e,t){let o=N.join(e,".env.example");if(T.existsSync(o)){if(T.readFileSync(o,"utf8").includes(t.split(`
545
+ `)[0]??""))return;T.appendFileSync(o,`
539
546
  `+t+`
540
- `)}else k.writeFileSync(o,t+`
541
- `)}var yt=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
547
+ `)}else T.writeFileSync(o,t+`
548
+ `)}var _t=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
542
549
  > Consult a qualified lawyer in every jurisdiction you operate in before publishing.
543
- > \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`,as=`import Link from "next/link";
550
+ > \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`,Es=`import Link from "next/link";
544
551
  import { IcpFooter } from "@/components/compliance/IcpFooter";
545
552
  import { PublicSecurityFooter } from "@/components/compliance/PublicSecurityFooter";
546
553
 
@@ -591,7 +598,7 @@ export function Footer({ region = "global" }: FooterProps) {
591
598
  </footer>
592
599
  );
593
600
  }
594
- `,cs=`export function IcpFooter() {
601
+ `,vs=`export function IcpFooter() {
595
602
  const icp = process.env.NEXT_PUBLIC_ICP_BEIAN;
596
603
  if (!icp) return null;
597
604
  return (
@@ -605,7 +612,7 @@ export function Footer({ region = "global" }: FooterProps) {
605
612
  </a>
606
613
  );
607
614
  }
608
- `,ps=`export function PublicSecurityFooter() {
615
+ `,_s=`export function PublicSecurityFooter() {
609
616
  const psb = process.env.NEXT_PUBLIC_PSB_BEIAN;
610
617
  const psbCode = process.env.NEXT_PUBLIC_PSB_CODE;
611
618
  if (!psb) return null;
@@ -622,7 +629,7 @@ export function Footer({ region = "global" }: FooterProps) {
622
629
  </a>
623
630
  );
624
631
  }
625
- `,ls=`"use client";
632
+ `,bs=`"use client";
626
633
 
627
634
  import { useCallback, useEffect, useState } from "react";
628
635
 
@@ -786,7 +793,7 @@ export function CookieBanner() {
786
793
  <button
787
794
  type="button"
788
795
  onClick={saveCustom}
789
- className="rounded-md bg-[var(--blue-9)] px-4 py-2 text-sm font-medium text-white hover:opacity-90"
796
+ className="rounded-md border border-[var(--neutral-12)] bg-[var(--neutral-12)] px-4 py-2 text-sm font-medium text-[var(--neutral-1)] shadow-sm hover:bg-[var(--neutral-11)]"
790
797
  >
791
798
  Save Preferences / \u4FDD\u5B58\u504F\u597D
792
799
  </button>
@@ -809,7 +816,7 @@ export function CookieBanner() {
809
816
  <button
810
817
  type="button"
811
818
  onClick={acceptAll}
812
- className="rounded-md bg-[var(--blue-9)] px-4 py-2 text-sm font-medium text-white hover:opacity-90"
819
+ className="rounded-md border border-[var(--neutral-12)] bg-[var(--neutral-12)] px-4 py-2 text-sm font-medium text-[var(--neutral-1)] shadow-sm hover:bg-[var(--neutral-11)]"
813
820
  >
814
821
  Accept All / \u5168\u90E8\u63A5\u53D7
815
822
  </button>
@@ -849,7 +856,7 @@ function CategoryRow({ id, title, description, checked, disabled, onChange }: Ca
849
856
  </label>
850
857
  );
851
858
  }
852
- `,ds=`interface AigcDisclaimerProps {
859
+ `,Ps=`interface AigcDisclaimerProps {
853
860
  className?: string;
854
861
  }
855
862
 
@@ -869,13 +876,13 @@ export function AigcDisclaimer({ className }: AigcDisclaimerProps) {
869
876
  </div>
870
877
  );
871
878
  }
872
- `,us=`---
879
+ `,As=`---
873
880
  title: Privacy Policy / \u9690\u79C1\u653F\u7B56
874
881
  description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal information.
875
882
  lastUpdated: 2026-01-01
876
883
  ---
877
884
 
878
- ${yt}
885
+ ${_t}
879
886
 
880
887
  # Privacy Policy / \u9690\u79C1\u653F\u7B56
881
888
 
@@ -1014,13 +1021,13 @@ or in-app notification before the change takes effect.
1014
1021
  **Data Controller / \u6570\u636E\u63A7\u5236\u8005:** {{COMPANY_NAME}}
1015
1022
  **Address / \u5730\u5740:** {{COMPANY_ADDRESS}}
1016
1023
  **Email / \u90AE\u7BB1:** {{COMPANY_CONTACT_EMAIL}}
1017
- `,ms=`---
1024
+ `,Cs=`---
1018
1025
  title: Terms of Service / \u670D\u52A1\u6761\u6B3E
1019
1026
  description: Terms governing your use of {{COMPANY_NAME}}.
1020
1027
  lastUpdated: 2026-01-01
1021
1028
  ---
1022
1029
 
1023
- ${yt}
1030
+ ${_t}
1024
1031
 
1025
1032
  # Terms of Service / \u670D\u52A1\u6761\u6B3E
1026
1033
 
@@ -1133,13 +1140,13 @@ conflict-of-laws principles. Disputes shall be resolved in the competent courts
1133
1140
  ## 11. Contact / \u8054\u7CFB\u65B9\u5F0F
1134
1141
 
1135
1142
  {{COMPANY_NAME}} \xB7 {{COMPANY_ADDRESS}} \xB7 {{COMPANY_CONTACT_EMAIL}}
1136
- `,gs=`---
1143
+ `,Is=`---
1137
1144
  title: AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
1138
1145
  description: Disclosure required by \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300B
1139
1146
  lastUpdated: 2026-01-01
1140
1147
  ---
1141
1148
 
1142
- ${yt}
1149
+ ${_t}
1143
1150
 
1144
1151
  # AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
1145
1152
 
@@ -1215,13 +1222,13 @@ human professional.
1215
1222
 
1216
1223
  AI \u8F93\u51FA\u53EF\u80FD\u4E0D\u51C6\u786E\u3001\u5B58\u5728\u504F\u89C1\u6216\u8FC7\u65F6\u3002**\u8BF7\u52FF**\u5728\u672A\u7ECF\u5408\u683C\u4E13\u4E1A\u4EBA\u58EB\u72EC\u7ACB\u6838\u5B9E\u7684\u60C5\u51B5\u4E0B\uFF0C\u5C06 AI \u8F93\u51FA
1217
1224
  \u7528\u4E8E\u533B\u7597\u3001\u6CD5\u5F8B\u3001\u91D1\u878D\u6216\u5B89\u5168\u6538\u5173\u7684\u51B3\u7B56\u3002
1218
- `,fs=`---
1225
+ `,ws=`---
1219
1226
  title: Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
1220
1227
  description: Notice of cross-border transfer of personal information, per PIPL.
1221
1228
  lastUpdated: 2026-01-01
1222
1229
  ---
1223
1230
 
1224
- ${yt}
1231
+ ${_t}
1225
1232
 
1226
1233
  # Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
1227
1234
 
@@ -1280,13 +1287,13 @@ Refusal may limit your ability to use features that rely on overseas services.
1280
1287
  - \u4F20\u8F93\u4E2D\u52A0\u5BC6 (TLS 1.2+) \u53CA\u9759\u6001\u52A0\u5BC6 (AES-256)\u3002
1281
1288
  - \u5408\u540C\u6761\u6B3E\u8981\u6C42\u5883\u5916\u63A5\u6536\u65B9\u63D0\u4F9B\u7B49\u540C\u4E8E PIPL \u7684\u4FDD\u62A4\u3002
1282
1289
  - \u8BBF\u95EE\u63A7\u5236\u3001\u5BA1\u8BA1\u65E5\u5FD7\u548C\u8FDD\u89C4\u901A\u77E5\u7A0B\u5E8F\u3002
1283
- `,ys=`---
1290
+ `,Rs=`---
1284
1291
  title: Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
1285
1292
  description: Itemized list of personal information collected, per PIPL Article 17.
1286
1293
  lastUpdated: 2026-01-01
1287
1294
  ---
1288
1295
 
1289
- ${yt}
1296
+ ${_t}
1290
1297
 
1291
1298
  # Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
1292
1299
 
@@ -1322,26 +1329,26 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
1322
1329
  **{{COMPANY_CONTACT_EMAIL}}**.
1323
1330
 
1324
1331
  \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
1325
- `;async function Ss(e,t){let o=ee(e);if(!k.existsSync(o))return;let n=R.join(o,"src","components","compliance","Footer.tsx");W(n,as);let r=R.join(o,"src","components","compliance","README.md");W(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(`
1326
- `))}async function hs(e,t){let o=ee(e);if(!k.existsSync(o))return;let n=R.join(o,"src","components","compliance","CookieBanner.tsx");W(n,ls)}async function Es(e,t){let o=ee(e);if(!k.existsSync(o))return;let n=R.join(o,ft,"privacy","page.mdx");W(n,us)}async function vs(e,t){let o=ee(e);if(!k.existsSync(o))return;let n=R.join(o,ft,"terms","page.mdx");W(n,ms)}async function _s(e){let t=ee(e);if(!k.existsSync(t))return;let o=R.join(t,Zt,"IcpFooter.tsx");W(o,cs),en(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(`
1327
- `))}async function bs(e){let t=ee(e);if(!k.existsSync(t))return;let o=R.join(t,Zt,"PublicSecurityFooter.tsx");W(o,ps),en(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(`
1328
- `))}async function Ps(e){let t=ee(e);if(!k.existsSync(t))return;let o=R.join(t,Zt,"AigcDisclaimer.tsx");W(o,ds),en(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(`
1329
- `))}async function Cs(e){let t=ee(e);if(!k.existsSync(t))return;let o=R.join(t,ft,"aigc-disclosure","page.mdx");W(o,gs)}async function As(e){let t=ee(e);if(!k.existsSync(t))return;let o=R.join(t,ft,"cross-border-data","page.mdx");W(o,fs)}async function ws(e){let t=ee(e);if(!k.existsSync(t))return;let o=R.join(t,ft,"pii-collection","page.mdx");W(o,ys)}async function jn(e,t){try{await Ss(e,t),await hs(e,t),await Es(e,t),await vs(e,t),(t==="cn"||t==="hybrid")&&(await _s(e),await bs(e),await Ps(e),await Cs(e),await As(e),await ws(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 Is from"fs";import Rs from"path";async function Vn(e,t){let o=Rs.join(e,"nebutra.config.json");Is.writeFileSync(o,JSON.stringify(t,null,2)+`
1330
- `)}import w from"fs";import we from"path";var tn=[{id:"local",name:"Local / Self-hosted Docker",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres:postgres@localhost:5432/$PROJECT",comment:"Local Postgres via docker-compose (pnpm infra:up)"}],docs:"https://www.postgresql.org/docs/",description:"Docker on localhost. You operate it.",tier:"self-hosted"},{id:"supabase",name:"Supabase",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:6543/postgres?pgbouncer=true",comment:"Supabase pooler \u2014 use for runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres",comment:"Supabase direct \u2014 use for Prisma migrations"},{name:"NEXT_PUBLIC_SUPABASE_URL",placeholder:"https://<project>.supabase.co"},{name:"NEXT_PUBLIC_SUPABASE_ANON_KEY",placeholder:""},{name:"SUPABASE_SERVICE_ROLE_KEY",placeholder:""}],docs:"https://supabase.com/docs",description:"Managed Postgres + auth/storage/realtime/edge-functions.",tier:"managed"},{id:"neon",name:"Neon",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>-pooler.<region>.neon.tech/<db>?sslmode=require",comment:"Neon pooled \u2014 runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>.<region>.neon.tech/<db>?sslmode=require",comment:"Neon direct (no -pooler) \u2014 migrations"}],docs:"https://neon.tech/docs",description:"Serverless Postgres with branching and scale-to-zero.",tier:"managed"},{id:"vercel-postgres",name:"Vercel Postgres",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"$POSTGRES_PRISMA_URL",comment:"Vercel Marketplace injects POSTGRES_PRISMA_URL automatically"},{name:"DIRECT_URL",placeholder:"$POSTGRES_URL_NON_POOLING",comment:"Vercel Marketplace injects POSTGRES_URL_NON_POOLING automatically"}],docs:"https://vercel.com/docs/storage/vercel-postgres",description:"Neon-backed, auto-provisioned via Vercel Marketplace.",tier:"managed"},{id:"planetscale",name:"PlanetScale",region:"global",supportedEngines:["mysql"],forcedEngine:"mysql",prismaDatasourceExtras:['relationMode = "prisma"'],envVars:[{name:"DATABASE_URL",placeholder:"mysql://<user>:<pass>@<host>.psdb.cloud/<db>?sslaccept=strict",comment:'PlanetScale: relationMode = "prisma" (no FK support server-side)'}],docs:"https://planetscale.com/docs",description:"Managed MySQL with branching. No foreign keys.",tier:"managed"},{id:"railway",name:"Railway",region:"global",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"$DATABASE_URL",comment:"Railway service env var; injected when you link a Postgres service"}],docs:"https://docs.railway.app/databases/postgresql",description:"Generalist managed infra; standard TCP Postgres/MySQL.",tier:"managed"},{id:"aliyun-rds",name:"Aliyun RDS",region:"cn",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@<rds-instance>.rds.aliyuncs.com:5432/<db>",comment:"Aliyun RDS Postgres \u2014 internal VPC endpoint recommended"}],docs:"https://www.alibabacloud.com/help/en/rds",description:"Aliyun RDS \u2014 China compliance + intranet routing.",tier:"managed"},{id:"tencent-cdb",name:"Tencent CloudDB (CDB)",region:"cn",supportedEngines:["mysql","postgresql"],envVars:[{name:"DATABASE_URL",placeholder:"mysql://<user>:<pwd>@<cdb-instance>.tencentcdb.com:3306/<db>",comment:"Tencent CloudDB \u2014 VPC endpoint recommended"}],docs:"https://intl.cloud.tencent.com/document/product/236",description:"Tencent CloudDB \u2014 China compliance.",tier:"managed"},{id:"none",name:"None",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[],docs:"",description:"Skip database scaffolding.",tier:"self-hosted"}];function Mt(e){return tn.find(t=>t.id===e)}function Bn(e){return e==="cn"||e==="hybrid"?"local":"supabase"}function ks(e){w.existsSync(e)&&w.rmSync(e,{recursive:!0,force:!0})}function Kn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function xs(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function $n(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 Ts(e,t){let o=we.join(e,".env.example");w.existsSync(o)?w.appendFileSync(o,`
1331
- `+t):w.writeFileSync(o,t)}async function Yn(e,t,o){let n=we.join(e,"packages","platform","db");if(t==="none"){ks(n);return}let r=we.join(n,"prisma","schema.prisma"),s;if(t==="postgresql"?s=`postgresql://postgres:postgres@localhost:5432/${o}`:t==="mysql"?s=`mysql://root:root@localhost:3306/${o}`:s="file:./dev.db",Ts(e,`# Database (${t})
1332
+ `;async function ks(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,"src","components","compliance","Footer.tsx");z(n,Es);let r=N.join(o,"src","components","compliance","README.md");z(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(`
1333
+ `))}async function xs(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,"src","components","compliance","CookieBanner.tsx");z(n,bs)}async function Ns(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,vt,"privacy","page.mdx");z(n,As)}async function Ts(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,vt,"terms","page.mdx");z(n,Cs)}async function Os(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,on,"IcpFooter.tsx");z(o,vs),rn(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(`
1334
+ `))}async function Ls(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,on,"PublicSecurityFooter.tsx");z(o,_s),rn(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(`
1335
+ `))}async function Us(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,on,"AigcDisclaimer.tsx");z(o,Ps),rn(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(`
1336
+ `))}async function Ms(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"aigc-disclosure","page.mdx");z(o,Is)}async function Ds(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"cross-border-data","page.mdx");z(o,ws)}async function Fs(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"pii-collection","page.mdx");z(o,Rs)}async function Yn(e,t){try{await ks(e,t),await xs(e,t),await Ns(e,t),await Ts(e,t),(t==="cn"||t==="hybrid")&&(await Os(e),await Ls(e),await Us(e),await Ms(e),await Ds(e),await Fs(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 js from"fs";import Vs from"path";async function qn(e,t){let o=Vs.join(e,"nebutra.config.json");js.writeFileSync(o,JSON.stringify(t,null,2)+`
1337
+ `)}import w from"fs";import ke from"path";var sn=[{id:"local",name:"Local / Self-hosted Docker",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres:postgres@localhost:5432/$PROJECT",comment:"Local Postgres via docker-compose (pnpm infra:up)"}],docs:"https://www.postgresql.org/docs/",description:"Docker on localhost. You operate it.",tier:"self-hosted"},{id:"supabase",name:"Supabase",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:6543/postgres?pgbouncer=true",comment:"Supabase pooler \u2014 use for runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres",comment:"Supabase direct \u2014 use for Prisma migrations"},{name:"NEXT_PUBLIC_SUPABASE_URL",placeholder:"https://<project>.supabase.co"},{name:"NEXT_PUBLIC_SUPABASE_ANON_KEY",placeholder:""},{name:"SUPABASE_SERVICE_ROLE_KEY",placeholder:""}],docs:"https://supabase.com/docs",description:"Managed Postgres + auth/storage/realtime/edge-functions.",tier:"managed"},{id:"neon",name:"Neon",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>-pooler.<region>.neon.tech/<db>?sslmode=require",comment:"Neon pooled \u2014 runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>.<region>.neon.tech/<db>?sslmode=require",comment:"Neon direct (no -pooler) \u2014 migrations"}],docs:"https://neon.tech/docs",description:"Serverless Postgres with branching and scale-to-zero.",tier:"managed"},{id:"vercel-postgres",name:"Vercel Postgres",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"$POSTGRES_PRISMA_URL",comment:"Vercel Marketplace injects POSTGRES_PRISMA_URL automatically"},{name:"DIRECT_URL",placeholder:"$POSTGRES_URL_NON_POOLING",comment:"Vercel Marketplace injects POSTGRES_URL_NON_POOLING automatically"}],docs:"https://vercel.com/docs/storage/vercel-postgres",description:"Neon-backed, auto-provisioned via Vercel Marketplace.",tier:"managed"},{id:"planetscale",name:"PlanetScale",region:"global",supportedEngines:["mysql"],forcedEngine:"mysql",prismaDatasourceExtras:['relationMode = "prisma"'],envVars:[{name:"DATABASE_URL",placeholder:"mysql://<user>:<pass>@<host>.psdb.cloud/<db>?sslaccept=strict",comment:'PlanetScale: relationMode = "prisma" (no FK support server-side)'}],docs:"https://planetscale.com/docs",description:"Managed MySQL with branching. No foreign keys.",tier:"managed"},{id:"railway",name:"Railway",region:"global",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"$DATABASE_URL",comment:"Railway service env var; injected when you link a Postgres service"}],docs:"https://docs.railway.app/databases/postgresql",description:"Generalist managed infra; standard TCP Postgres/MySQL.",tier:"managed"},{id:"aliyun-rds",name:"Aliyun RDS",region:"cn",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@<rds-instance>.rds.aliyuncs.com:5432/<db>",comment:"Aliyun RDS Postgres \u2014 internal VPC endpoint recommended"}],docs:"https://www.alibabacloud.com/help/en/rds",description:"Aliyun RDS \u2014 China compliance + intranet routing.",tier:"managed"},{id:"tencent-cdb",name:"Tencent CloudDB (CDB)",region:"cn",supportedEngines:["mysql","postgresql"],envVars:[{name:"DATABASE_URL",placeholder:"mysql://<user>:<pwd>@<cdb-instance>.tencentcdb.com:3306/<db>",comment:"Tencent CloudDB \u2014 VPC endpoint recommended"}],docs:"https://intl.cloud.tencent.com/document/product/236",description:"Tencent CloudDB \u2014 China compliance.",tier:"managed"},{id:"none",name:"None",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[],docs:"",description:"Skip database scaffolding.",tier:"self-hosted"}];function Kt(e){return sn.find(t=>t.id===e)}function Gn(e){return e==="cn"||e==="hybrid"?"local":"supabase"}function Bs(e){w.existsSync(e)&&w.rmSync(e,{recursive:!0,force:!0})}function Hn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function Ks(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function Wn(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 $s(e,t){let o=ke.join(e,".env.example");w.existsSync(o)?w.appendFileSync(o,`
1338
+ `+t):w.writeFileSync(o,t)}async function Xn(e,t,o){let n=ke.join(e,"packages","platform","db");if(t==="none"){Bs(n);return}let r=ke.join(n,"prisma","schema.prisma"),s;if(t==="postgresql"?s=`postgresql://postgres:postgres@localhost:5432/${o}`:t==="mysql"?s=`mysql://root:root@localhost:3306/${o}`:s="file:./dev.db",$s(e,`# Database (${t})
1332
1339
  DATABASE_URL="${s}"
1333
- `),!w.existsSync(r))return;let i=w.readFileSync(r,"utf8"),c=i;t==="mysql"?(c=Kn(c,"mysql"),c=$n(c)):t==="sqlite"&&(c=Kn(c,"sqlite"),c=xs(c),c=$n(c)),c!==i&&w.writeFileSync(r,c)}function Ns(e){let t=we.join(e,".env.example");return w.existsSync(t)?w.readFileSync(t,"utf8"):""}function Os(e,t,o,n){let r=we.join(e,".env.example"),s=Ns(e),i=n?`# ${n}
1340
+ `),!w.existsSync(r))return;let i=w.readFileSync(r,"utf8"),c=i;t==="mysql"?(c=Hn(c,"mysql"),c=Wn(c)):t==="sqlite"&&(c=Hn(c,"sqlite"),c=Ks(c),c=Wn(c)),c!==i&&w.writeFileSync(r,c)}function Ys(e){let t=ke.join(e,".env.example");return w.existsSync(t)?w.readFileSync(t,"utf8"):""}function qs(e,t,o,n){let r=ke.join(e,".env.example"),s=Ys(e),i=n?`# ${n}
1334
1341
  ${t}="${o}"
1335
1342
  `:`${t}="${o}"
1336
1343
  `,c=new RegExp(`^\\s*${t}\\s*=.*$`,"m");if(c.test(s)){w.writeFileSync(r,s.replace(c,`${t}="${o}"`));return}s?w.appendFileSync(r,`
1337
- ${i}`):w.writeFileSync(r,i)}function Us(e,t){let o=we.join(e,"packages","platform","db","prisma","schema.prisma");if(!w.existsSync(o))return;let n=w.readFileSync(o,"utf8"),r=/(datasource\s+db\s*\{[^}]*?)(\n})/;if(!n.match(r))return;let i=t.filter(l=>!n.includes(l.trim()));if(i.length===0)return;let c=i.map(l=>` ${l}`).join(`
1344
+ ${i}`):w.writeFileSync(r,i)}function Gs(e,t){let o=ke.join(e,"packages","platform","db","prisma","schema.prisma");if(!w.existsSync(o))return;let n=w.readFileSync(o,"utf8"),r=/(datasource\s+db\s*\{[^}]*?)(\n})/;if(!n.match(r))return;let i=t.filter(l=>!n.includes(l.trim()));if(i.length===0)return;let c=i.map(l=>` ${l}`).join(`
1338
1345
  `),a=n.replace(r,`$1
1339
- ${c}$2`);w.writeFileSync(o,a)}function Ls(e){let t=we.join(e,"packages","platform","db","prisma","schema.prisma");if(!w.existsSync(t))return;let o=w.readFileSync(t,"utf8");if(/directUrl\s*=\s*env\(/.test(o))return;let n=/(datasource\s+db\s*\{[\s\S]*?url\s*=\s*env\(\s*"DATABASE_URL"\s*\)[^\n]*\n)/;n.test(o)&&w.writeFileSync(t,o.replace(n,`$1 directUrl = env("DIRECT_URL")
1340
- `))}async function qn(e,t,o){if(!(t.id==="none"||t.id==="local")){for(let n of t.envVars){let r=n.placeholder.replace(/\$PROJECT/g,o);Os(e,n.name,r,n.comment)}t.prismaDatasourceExtras&&t.prismaDatasourceExtras.length>0&&Us(e,t.prismaDatasourceExtras),t.keepDirectUrl&&Ls(e)}}import rt from"fs";import B from"path";import{fileURLToPath as Ms}from"url";var Ds=Ms(import.meta.url),Gn=B.dirname(Ds);function Fs(){let e=[B.join(Gn,"..","templates","deploy"),B.join(Gn,"..","..","templates","deploy")];for(let t of e)if(rt.existsSync(t))return t;return e[0]}async function Hn(e,t){if(t==="none")return;let o=Fs();t==="vercel"?await rt.promises.copyFile(B.join(o,"vercel.json"),B.join(e,"vercel.json")):t==="railway"?await rt.promises.copyFile(B.join(o,"railway.toml"),B.join(e,"railway.toml")):t==="cloudflare"?await rt.promises.copyFile(B.join(o,"wrangler.toml"),B.join(e,"wrangler.toml")):t==="selfhost"&&(await rt.promises.copyFile(B.join(o,"docker-compose.yml"),B.join(e,"docker-compose.yml")),await rt.promises.copyFile(B.join(o,"Dockerfile.web"),B.join(e,"Dockerfile.web")))}import le from"fs";import Ie from"path";import{fileURLToPath as js}from"url";var Vs=js(import.meta.url),Wn=Ie.dirname(Vs),Bs=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|vue)$/,Xn=["fumadocs","nextra","mintlify","docusaurus","vitepress"];function Ks(e){let t=[Ie.join(Wn,"..","templates","docs",e),Ie.join(Wn,"..","..","templates","docs",e)];for(let o of t)if(le.existsSync(o))return o;return t[0]}async function zn(e,t){if(t.framework==="none")return;if(!Xn.includes(t.framework))throw new Error(`Unsupported docs framework: "${t.framework}". Supported: ${Xn.join(", ")}, none.`);let o=Ks(t.framework),n=Ie.join(e,"apps","docs");if(!le.existsSync(o))throw new Error(`Docs template not found: ${o}`);Jn(o,n),Qn(n,{"{PRODUCT_NAME}":t.projectName})}function Jn(e,t){le.mkdirSync(t,{recursive:!0});for(let o of le.readdirSync(e,{withFileTypes:!0})){let n=Ie.join(e,o.name),r=Ie.join(t,o.name);o.isDirectory()?Jn(n,r):le.copyFileSync(n,r)}}function Qn(e,t){for(let o of le.readdirSync(e,{withFileTypes:!0})){let n=Ie.join(e,o.name);if(o.isDirectory())Qn(n,t);else if(Bs.test(o.name)){let r=le.readFileSync(n,"utf-8");for(let[s,i]of Object.entries(t))r=r.split(s).join(i);le.writeFileSync(n,r)}}}import ke from"fs";import Re from"path";var Dt=[{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 Zn(e){return Dt.find(t=>t.id===e)}var rp=Dt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var xe="@nebutra/email";function nn(e,t){ke.mkdirSync(Re.dirname(e),{recursive:!0}),ke.writeFileSync(e,t)}function $s(e,t){let o=Re.join(e,".env.example");ke.existsSync(o)?ke.appendFileSync(o,`
1341
- `+t):ke.writeFileSync(o,t)}function Ys(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
1346
+ ${c}$2`);w.writeFileSync(o,a)}function Hs(e){let t=ke.join(e,"packages","platform","db","prisma","schema.prisma");if(!w.existsSync(t))return;let o=w.readFileSync(t,"utf8");if(/directUrl\s*=\s*env\(/.test(o))return;let n=/(datasource\s+db\s*\{[\s\S]*?url\s*=\s*env\(\s*"DATABASE_URL"\s*\)[^\n]*\n)/;n.test(o)&&w.writeFileSync(t,o.replace(n,`$1 directUrl = env("DIRECT_URL")
1347
+ `))}async function zn(e,t,o){if(!(t.id==="none"||t.id==="local")){for(let n of t.envVars){let r=n.placeholder.replace(/\$PROJECT/g,o);qs(e,n.name,r,n.comment)}t.prismaDatasourceExtras&&t.prismaDatasourceExtras.length>0&&Gs(e,t.prismaDatasourceExtras),t.keepDirectUrl&&Hs(e)}}import at from"fs";import K from"path";import{fileURLToPath as Ws}from"url";var Xs=Ws(import.meta.url),Jn=K.dirname(Xs);function zs(){let e=[K.join(Jn,"..","templates","deploy"),K.join(Jn,"..","..","templates","deploy")];for(let t of e)if(at.existsSync(t))return t;return e[0]}async function Qn(e,t){if(t==="none")return;let o=zs();t==="vercel"?await at.promises.copyFile(K.join(o,"vercel.json"),K.join(e,"vercel.json")):t==="railway"?await at.promises.copyFile(K.join(o,"railway.toml"),K.join(e,"railway.toml")):t==="cloudflare"?await at.promises.copyFile(K.join(o,"wrangler.toml"),K.join(e,"wrangler.toml")):t==="selfhost"&&(await at.promises.copyFile(K.join(o,"docker-compose.yml"),K.join(e,"docker-compose.yml")),await at.promises.copyFile(K.join(o,"Dockerfile.web"),K.join(e,"Dockerfile.web")))}import ge from"fs";import xe from"path";import{fileURLToPath as Js}from"url";var Qs=Js(import.meta.url),Zn=xe.dirname(Qs),Zs=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|vue)$/,eo=["fumadocs","nextra","mintlify","docusaurus","vitepress"];function ei(e){let t=[xe.join(Zn,"..","templates","docs",e),xe.join(Zn,"..","..","templates","docs",e)];for(let o of t)if(ge.existsSync(o))return o;return t[0]}async function to(e,t){if(t.framework==="none")return;if(!eo.includes(t.framework))throw new Error(`Unsupported docs framework: "${t.framework}". Supported: ${eo.join(", ")}, none.`);let o=ei(t.framework),n=xe.join(e,"apps","docs");if(!ge.existsSync(o))throw new Error(`Docs template not found: ${o}`);no(o,n),oo(n,{"{PRODUCT_NAME}":t.projectName})}function no(e,t){ge.mkdirSync(t,{recursive:!0});for(let o of ge.readdirSync(e,{withFileTypes:!0})){let n=xe.join(e,o.name),r=xe.join(t,o.name);o.isDirectory()?no(n,r):ge.copyFileSync(n,r)}}function oo(e,t){for(let o of ge.readdirSync(e,{withFileTypes:!0})){let n=xe.join(e,o.name);if(o.isDirectory())oo(n,t);else if(Zs.test(o.name)){let r=ge.readFileSync(n,"utf-8");for(let[s,i]of Object.entries(t))r=r.split(s).join(i);ge.writeFileSync(n,r)}}}import Te from"fs";import Ne from"path";var $t=[{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 ro(e){return $t.find(t=>t.id===e)}var Ip=$t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Oe="@nebutra/email";function an(e,t){Te.mkdirSync(Ne.dirname(e),{recursive:!0}),Te.writeFileSync(e,t)}function ti(e,t){let o=Ne.join(e,".env.example");Te.existsSync(o)?Te.appendFileSync(o,`
1348
+ `+t):Te.writeFileSync(o,t)}function ni(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
1342
1349
  `);return`${t}
1343
1350
  ${o}
1344
- `}var qs=`/**
1351
+ `}var oi=`/**
1345
1352
  * Public inputs accepted by the \`sendEmail\` wrapper.
1346
1353
  * Keep the surface minimal \u2014 individual providers may accept more, but
1347
1354
  * consumers should code against this shape for portability.
@@ -1361,8 +1368,8 @@ export interface SendEmailResult {
1361
1368
  /** Raw provider response \u2014 useful for debugging, not a stable contract. */
1362
1369
  raw?: unknown;
1363
1370
  }
1364
- `;function Gs(){return`/**
1365
- * @${xe.slice(1)} \u2014 Resend transactional email wrapper.
1371
+ `;function ri(){return`/**
1372
+ * @${Oe.slice(1)} \u2014 Resend transactional email wrapper.
1366
1373
  *
1367
1374
  * Docs: https://resend.com/docs
1368
1375
  */
@@ -1400,8 +1407,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1400
1407
  }
1401
1408
 
1402
1409
  export type { SendEmailInput, SendEmailResult } from "./types";
1403
- `}function Hs(){return`/**
1404
- * @${xe.slice(1)} \u2014 Postmark transactional email wrapper.
1410
+ `}function si(){return`/**
1411
+ * @${Oe.slice(1)} \u2014 Postmark transactional email wrapper.
1405
1412
  *
1406
1413
  * Docs: https://postmarkapp.com/developer
1407
1414
  */
@@ -1438,8 +1445,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1438
1445
  }
1439
1446
 
1440
1447
  export type { SendEmailInput, SendEmailResult } from "./types";
1441
- `}function Ws(){return`/**
1442
- * @${xe.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
1448
+ `}function ii(){return`/**
1449
+ * @${Oe.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
1443
1450
  *
1444
1451
  * Docs: https://docs.aws.amazon.com/ses
1445
1452
  */
@@ -1494,8 +1501,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1494
1501
  }
1495
1502
 
1496
1503
  export type { SendEmailInput, SendEmailResult } from "./types";
1497
- `}function Xs(){return`/**
1498
- * @${xe.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
1504
+ `}function ai(){return`/**
1505
+ * @${Oe.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
1499
1506
  *
1500
1507
  * Docs: https://help.aliyun.com/product/29412.html
1501
1508
  */
@@ -1544,8 +1551,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1544
1551
  }
1545
1552
 
1546
1553
  export type { SendEmailInput, SendEmailResult } from "./types";
1547
- `}function zs(){return`/**
1548
- * @${xe.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
1554
+ `}function ci(){return`/**
1555
+ * @${Oe.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
1549
1556
  *
1550
1557
  * Docs: https://cloud.tencent.com/document/product/1288
1551
1558
  */
@@ -1592,8 +1599,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1592
1599
  }
1593
1600
 
1594
1601
  export type { SendEmailInput, SendEmailResult } from "./types";
1595
- `}function Js(){return`/**
1596
- * @${xe.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
1602
+ `}function pi(){return`/**
1603
+ * @${Oe.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
1597
1604
  *
1598
1605
  * Docs: https://qiye.163.com/help
1599
1606
  */
@@ -1630,24 +1637,31 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1630
1637
  }
1631
1638
 
1632
1639
  export type { SendEmailInput, SendEmailResult } from "./types";
1633
- `}function Qs(e){switch(e){case"resend":return Gs();case"postmark":return Hs();case"ses":return Ws();case"aliyun-dm":return Xs();case"tencent-ses":return zs();case"netease":return Js();case"none":return`export {};
1634
- `}}function Zs(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:xe,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)+`
1635
- `}async function eo(e,t,o){if(t==="none")return;let n=Zn(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${Dt.map(i=>i.id).join(", ")}`);let r=Re.join(e,"packages","email"),s=Re.join(r,"src");ke.existsSync(s)&&ke.rmSync(s,{recursive:!0,force:!0}),nn(Re.join(r,"package.json"),Zs(n)),nn(Re.join(s,"types.ts"),qs),nn(Re.join(s,"index.ts"),Qs(n.id)),$s(e,Ys(n))}import Ft from"fs";import to from"path";async function no(e,t){let o=`# Automatically injected by create-sailor
1640
+ `}function li(e){switch(e){case"resend":return ri();case"postmark":return si();case"ses":return ii();case"aliyun-dm":return ai();case"tencent-ses":return ci();case"netease":return pi();case"none":return`export {};
1641
+ `}}function di(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:Oe,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)+`
1642
+ `}async function so(e,t,o){if(t==="none")return;let n=ro(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${$t.map(i=>i.id).join(", ")}`);let r=Ne.join(e,"packages","email"),s=Ne.join(r,"src");Te.existsSync(s)&&Te.rmSync(s,{recursive:!0,force:!0}),an(Ne.join(r,"package.json"),di(n)),an(Ne.join(s,"types.ts"),oi),an(Ne.join(s,"index.ts"),li(n.id)),ti(e,ni(n))}import Yt from"fs";import io from"path";async function ao(e,t){let o=`# Automatically injected by create-sailor
1636
1643
  DATABASE_URL="${String(t.databaseUrl)}"
1637
1644
 
1638
1645
  NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
1639
1646
  CLERK_SECRET_KEY="${String(t.clerkSecret)}"
1640
1647
 
1641
1648
  NEXT_PUBLIC_SITE_URL="http://localhost:3000"
1642
- `,n=to.join(e,".env"),r=to.join(e,".env.local");!Ft.existsSync(n)&&!Ft.existsSync(r)?Ft.writeFileSync(r,o):Ft.appendFileSync(r,`
1643
- `+o)}import ro from"crypto";import St from"fs";import oo from"path";function Te(e){return ro.randomBytes(e).toString("base64").replace(/=+$/,"")}function ei(e){return ro.randomBytes(e).toString("hex")}function ti(){return{AUTH_SECRET:Te(32),NEXTAUTH_SECRET:Te(32),BETTER_AUTH_SECRET:Te(32),JWT_SECRET:Te(32),WEBHOOK_SECRET:ei(16),ENCRYPTION_KEY:Te(32),API_SECRET_KEY:Te(32),SESSION_SECRET:Te(32)}}function ni(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function oi(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=ni(o);return e.replace(n,`${t}="${r}"`)}async function so(e){let t=oo.join(e,".env.example"),o=oo.join(e,".env.local");if(!St.existsSync(t))return null;try{let n=St.readFileSync(t,"utf8"),r=ti(),i=St.existsSync(o)?St.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))i=oi(i,c,r[c]);return St.writeFileSync(o,i),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 jt=[{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 io(e){return jt.find(t=>t.id===e)}var Sp=jt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ao(e,t,o="global"){let n=io(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${jt.map(r=>r.id).join(", ")}`);if(n.id==="none"){H(e,"feature-flags");return}n.envVars.length>0&&Q(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),Z(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{execFileSync as lo}from"child_process";import L from"fs";import ri from"os";import de from"path";import si from"ignore";var ii={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 ai(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function ci(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function uo(e){return/^[0-9a-f]{7,40}$/i.test(e)}function pi(e,t){let o=`https://github.com/${e}.git`,n=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of n)try{let s=lo("git",["ls-remote",o,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!s)continue;let[i]=s.split(/\s+/);if(uo(i))return i}catch{}return null}async function li(e,t){if(uo(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=pi(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 mo(e,t,o){let n=L.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let s=de.join(t,r.name),i=de.relative(e,s).split(de.sep).join("/");r.isDirectory()?(o.push(i+"/"),mo(e,s,o)):o.push(i)}}function di(e){let t=de.join(e,".templateignore");if(!L.existsSync(t))return;let o=L.readFileSync(t,"utf8"),n=si().add(o),r=[];mo(e,e,r);let s=r.map(a=>a.endsWith("/")?a.slice(0,-1):a),i=new Set(n.filter(s)),c=s.filter(a=>!i.has(a)).sort((a,l)=>l.split("/").length-a.split("/").length);for(let a of c){let l=de.join(e,a);try{L.existsSync(l)&&L.rmSync(l,{recursive:!0,force:!0})}catch{}}try{L.existsSync(t)&&L.rmSync(t,{force:!0})}catch{}}async function co(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)`);L.writeFileSync(t,n);let r=L.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function po(e,t){lo("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function go(e){try{let t=L.readdirSync(e);for(let o of t)L.rmSync(de.join(e,o),{recursive:!0,force:!0})}catch{}}async function ui(e,t){let o=L.mkdtempSync(de.join(ri.tmpdir(),"create-sailor-")),n=de.join(o,"template.tar.gz");try{let r=await li(e.repo,e.ref);await co(ci(e.repo,r),n),po(n,t)}catch(r){if(!e.allowMutableFallback)throw r;go(t),await co(ai(e.repo,e.ref),n),po(n,t)}finally{L.rmSync(o,{recursive:!0,force:!0})}}async function fo(e){L.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let s=ii[r];try{if(await ui(s,e),s.applyIgnore)try{di(e)}catch(i){throw new Error(`Template cloned, but .templateignore processing failed: ${i instanceof Error?i.message:String(i)}`)}return}catch(i){n=i instanceof Error?i:new Error(String(i)),go(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
1649
+ `,n=io.join(e,".env"),r=io.join(e,".env.local");!Yt.existsSync(n)&&!Yt.existsSync(r)?Yt.writeFileSync(r,o):Yt.appendFileSync(r,`
1650
+ `+o)}import po from"crypto";import bt from"fs";import co from"path";function Le(e){return po.randomBytes(e).toString("base64").replace(/=+$/,"")}function ui(e){return po.randomBytes(e).toString("hex")}function mi(){return{AUTH_SECRET:Le(32),NEXTAUTH_SECRET:Le(32),BETTER_AUTH_SECRET:Le(32),JWT_SECRET:Le(32),WEBHOOK_SECRET:ui(16),ENCRYPTION_KEY:Le(32),API_SECRET_KEY:Le(32),SESSION_SECRET:Le(32)}}function gi(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function fi(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=gi(o);return e.replace(n,`${t}="${r}"`)}async function lo(e){let t=co.join(e,".env.example"),o=co.join(e,".env.local");if(!bt.existsSync(t))return null;try{let n=bt.readFileSync(t,"utf8"),r=mi(),i=bt.existsSync(o)?bt.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))i=fi(i,c,r[c]);return bt.writeFileSync(o,i),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 qt=[{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 uo(e){return qt.find(t=>t.id===e)}var jp=qt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function mo(e,t,o="global"){let n=uo(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${qt.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"feature-flags");return}n.envVars.length>0&&te(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{execFileSync as yo}from"child_process";import M from"fs";import yi from"os";import fe from"path";import Si from"ignore";var hi={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 Ei(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function vi(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function So(e){return/^[0-9a-f]{7,40}$/i.test(e)}function _i(e,t){let o=`https://github.com/${e}.git`,n=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of n)try{let s=yo("git",["ls-remote",o,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!s)continue;let[i]=s.split(/\s+/);if(So(i))return i}catch{}return null}async function bi(e,t){if(So(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=_i(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 ho(e,t,o){let n=M.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let s=fe.join(t,r.name),i=fe.relative(e,s).split(fe.sep).join("/");r.isDirectory()?(o.push(i+"/"),ho(e,s,o)):o.push(i)}}function Pi(e){let t=fe.join(e,".templateignore");if(!M.existsSync(t))return;let o=M.readFileSync(t,"utf8"),n=Si().add(o),r=[];ho(e,e,r);let s=r.map(a=>a.endsWith("/")?a.slice(0,-1):a),i=new Set(n.filter(s)),c=s.filter(a=>!i.has(a)).sort((a,l)=>l.split("/").length-a.split("/").length);for(let a of c){let l=fe.join(e,a);try{M.existsSync(l)&&M.rmSync(l,{recursive:!0,force:!0})}catch{}}try{M.existsSync(t)&&M.rmSync(t,{force:!0})}catch{}}async function go(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)`);M.writeFileSync(t,n);let r=M.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function fo(e,t){yo("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function Eo(e){try{let t=M.readdirSync(e);for(let o of t)M.rmSync(fe.join(e,o),{recursive:!0,force:!0})}catch{}}async function Ai(e,t){let o=M.mkdtempSync(fe.join(yi.tmpdir(),"create-sailor-")),n=fe.join(o,"template.tar.gz");try{let r=await bi(e.repo,e.ref);await go(vi(e.repo,r),n),fo(n,t)}catch(r){if(!e.allowMutableFallback)throw r;Eo(t),await go(Ei(e.repo,e.ref),n),fo(n,t)}finally{M.rmSync(o,{recursive:!0,force:!0})}}async function vo(e){M.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let s=hi[r];try{if(await Ai(s,e),s.applyIgnore)try{Pi(e)}catch(i){throw new Error(`Template cloned, but .templateignore processing failed: ${i instanceof Error?i.message:String(i)}`)}return}catch(i){n=i instanceof Error?i:new Error(String(i)),Eo(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
1644
1651
 
1645
1652
  Ensure you have internet access and 'tar' installed.
1646
- You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import Ne from"fs";import on from"path";async function yo(e,t){let o=on.join(e,"packages","mcp");if(t==="off"){Ne.existsSync(o)&&Ne.rmSync(o,{recursive:!0,force:!0});let r=on.join(e,"packages","cli","src","commands","mcp-server.ts");Ne.existsSync(r)&&Ne.rmSync(r,{force:!0});return}let n=on.join(e,".env.example");if(Ne.existsSync(n)){let r=Ne.readFileSync(n,"utf-8"),s="# MCP Server (Agent-friendly API)";if(!r.includes(s)){let i=["","# =============================================",s,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
1647
- `);Ne.appendFileSync(n,i)}}}import ht from"fs";import So from"path";async function ho(e,t,o){let n=So.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){ht.existsSync(n)&&ht.rmSync(n,{recursive:!0,force:!0});return}let s=So.join(e,".env.example");if(!ht.existsSync(s))return;let i=ht.readFileSync(s,"utf-8"),c="# Metering (usage-based billing)";if(!i.includes(c)){let a=["","# =============================================",c,"# Docs: see packages/commerce/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
1648
- `);ht.appendFileSync(s,a)}}import re from"fs";import M from"path";var Eo=[{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:""}],Up=Eo.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function vo(e){return Eo.find(t=>t.id===e)}var rn={sentry:{"@sentry/nextjs":"^8.45.0"},datadog:{"dd-trace":"^5.32.0","@datadog/browser-rum":"^5.30.0"},bugsnag:{"@bugsnag/js":"^8.2.0","@bugsnag/plugin-react":"^8.2.0"}};function mi(e){re.mkdirSync(e,{recursive:!0})}function sn(e,t){let o=M.join(e,"package.json");if(!re.existsSync(o))return;let n;try{n=JSON.parse(re.readFileSync(o,"utf-8"))}catch(c){console.error(`Failed to parse ${o}:`,c);return}let s={...n.dependencies??{}};for(let[c,a]of Object.entries(t))s[c]||(s[c]=a);let i={...n,dependencies:s};re.writeFileSync(o,JSON.stringify(i,null,2)+`
1649
- `)}function te(e,t){mi(M.dirname(e)),re.writeFileSync(e,t)}function Et(e,t){let o=M.join(e,".env.example");re.existsSync(o)?re.appendFileSync(o,`
1650
- `+t):re.writeFileSync(o,t)}function gi(e){let t=`import * as Sentry from "@sentry/nextjs";
1653
+ You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import{createHmac as Ci,randomBytes as Ii}from"crypto";import J from"fs";import re from"path";import{fileURLToPath as wi}from"url";var Ri=wi(import.meta.url),_o=re.dirname(Ri),bo="scaffold-meta.json",Po=".nebutra",ki="nebutra-sailor:scaffold-marker:v1";function xi(e){if(e)return e;let t=[re.join(_o,"..","templates"),re.join(_o,"..","..","templates")];for(let o of t)if(J.existsSync(o))return o;return t[0]}function Ni(e){let t=`${e.cliVersion}|${e.scaffoldedAt}|${e.projectName}|${e.nonce}`;return Ci("sha256",ki).update(t).digest("hex")}function Ao(e,t){let o=[],n=xi(t.templatesRoot),r=re.join(e,"LICENSE");if(J.existsSync(r)){let C=J.readFileSync(r,"utf-8").slice(0,256);/GNU AFFERO GENERAL PUBLIC LICENSE/i.test(C)&&(J.renameSync(r,re.join(e,"LICENSE-AGPL-REFERENCE.md")),o.push("LICENSE-AGPL-REFERENCE.md (preserved upstream AGPL)"))}let s=re.join(n,"LICENSE-INDEPENDENT.md");if(!J.existsSync(s))throw new Error(`LICENSE-INDEPENDENT.md template missing at ${s}; cannot emit license.`);J.copyFileSync(s,re.join(e,"LICENSE")),o.push("LICENSE");let i=new Date().toISOString(),c=Ii(12).toString("hex"),a=Ni({cliVersion:t.cliVersion,scaffoldedAt:i,projectName:t.projectName,nonce:c}),l={schemaVersion:1,cliVersion:t.cliVersion,scaffoldedAt:i,projectName:t.projectName,nonce:c,signature:a,purpose:"Marks this project as scaffolded by the official `create-sailor` CLI. The Independent Developer License in LICENSE applies as long as this file is present and the signature verifies.",license:{tier:"independent",file:"LICENSE",upgradeUrl:"https://nebutra.com/get-license"}},d=re.join(e,Po);J.mkdirSync(d,{recursive:!0}),J.writeFileSync(re.join(d,bo),`${JSON.stringify(l,null,2)}
1654
+ `),o.push(`${Po}/${bo}`);let S=re.join(e,"README.md");if(J.existsSync(S)){let C=J.readFileSync(S,"utf-8");C.includes("Nebutra-Sailor Independent Developer License")||(J.writeFileSync(S,`> **License notice:** scaffolded by \`create-sailor\` under the
1655
+ > [Nebutra-Sailor Independent Developer License](./LICENSE). Free for
1656
+ > individuals/OPC with \u2264 1 FTE and < $1M ARR; upgrade for larger teams at
1657
+ > https://nebutra.com/get-license. The upstream repository remains
1658
+ > AGPL-3.0 \u2014 see \`LICENSE-AGPL-REFERENCE.md\`.
1659
+
1660
+ `+C),o.push("README.md (prepended license notice)"))}return{wrote:o}}import Ue from"fs";import cn from"path";async function Co(e,t){let o=cn.join(e,"packages","mcp");if(t==="off"){Ue.existsSync(o)&&Ue.rmSync(o,{recursive:!0,force:!0});let r=cn.join(e,"packages","cli","src","commands","mcp-server.ts");Ue.existsSync(r)&&Ue.rmSync(r,{force:!0});return}let n=cn.join(e,".env.example");if(Ue.existsSync(n)){let r=Ue.readFileSync(n,"utf-8"),s="# MCP Server (Agent-friendly API)";if(!r.includes(s)){let i=["","# =============================================",s,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
1661
+ `);Ue.appendFileSync(n,i)}}}import Pt from"fs";import Io from"path";async function wo(e,t,o){let n=Io.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){Pt.existsSync(n)&&Pt.rmSync(n,{recursive:!0,force:!0});return}let s=Io.join(e,".env.example");if(!Pt.existsSync(s))return;let i=Pt.readFileSync(s,"utf-8"),c="# Metering (usage-based billing)";if(!i.includes(c)){let a=["","# =============================================",c,"# Docs: see packages/commerce/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
1662
+ `);Pt.appendFileSync(s,a)}}import ce from"fs";import D from"path";var Ro=[{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:""}],al=Ro.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function ko(e){return Ro.find(t=>t.id===e)}var pn={sentry:{"@sentry/nextjs":"^8.45.0"},datadog:{"dd-trace":"^5.32.0","@datadog/browser-rum":"^5.30.0"},bugsnag:{"@bugsnag/js":"^8.2.0","@bugsnag/plugin-react":"^8.2.0"}};function Ti(e){ce.mkdirSync(e,{recursive:!0})}function ln(e,t){let o=D.join(e,"package.json");if(!ce.existsSync(o))return;let n;try{n=JSON.parse(ce.readFileSync(o,"utf-8"))}catch(c){console.error(`Failed to parse ${o}:`,c);return}let s={...n.dependencies??{}};for(let[c,a]of Object.entries(t))s[c]||(s[c]=a);let i={...n,dependencies:s};ce.writeFileSync(o,JSON.stringify(i,null,2)+`
1663
+ `)}function se(e,t){Ti(D.dirname(e)),ce.writeFileSync(e,t)}function At(e,t){let o=D.join(e,".env.example");ce.existsSync(o)?ce.appendFileSync(o,`
1664
+ `+t):ce.writeFileSync(o,t)}function Oi(e){let t=`import * as Sentry from "@sentry/nextjs";
1651
1665
 
1652
1666
  Sentry.init({
1653
1667
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
@@ -1690,14 +1704,14 @@ export async function register() {
1690
1704
  }
1691
1705
 
1692
1706
  export { captureRequestError as onRequestError } from "@sentry/nextjs";
1693
- `;te(M.join(e,"sentry.client.config.ts"),t),te(M.join(e,"sentry.server.config.ts"),o),te(M.join(e,"sentry.edge.config.ts"),n),te(M.join(e,"instrumentation.ts"),r)}function fi(){return`# Sentry \u2014 error tracking + performance monitoring
1707
+ `;se(D.join(e,"sentry.client.config.ts"),t),se(D.join(e,"sentry.server.config.ts"),o),se(D.join(e,"sentry.edge.config.ts"),n),se(D.join(e,"instrumentation.ts"),r)}function Li(){return`# Sentry \u2014 error tracking + performance monitoring
1694
1708
  # Get your DSN from https://sentry.io/settings/projects/<project>/keys/
1695
1709
  SENTRY_DSN=
1696
1710
  NEXT_PUBLIC_SENTRY_DSN=
1697
1711
  SENTRY_ORG=
1698
1712
  SENTRY_PROJECT=
1699
1713
  SENTRY_AUTH_TOKEN=
1700
- `}function yi(e){let t=`/**
1714
+ `}function Ui(e){let t=`/**
1701
1715
  * Next.js instrumentation hook \u2014 wires Datadog APM (dd-trace) into Node runtime.
1702
1716
  * Edge runtime is not supported by dd-trace; only nodejs is initialized.
1703
1717
  */
@@ -1745,7 +1759,7 @@ export function initDatadogRum(): void {
1745
1759
  });
1746
1760
  initialized = true;
1747
1761
  }
1748
- `;te(M.join(e,"instrumentation.ts"),t),te(M.join(e,"src","lib","monitoring","datadog-rum.ts"),o)}function Si(){return`# Datadog \u2014 APM + RUM
1762
+ `;se(D.join(e,"instrumentation.ts"),t),se(D.join(e,"src","lib","monitoring","datadog-rum.ts"),o)}function Mi(){return`# Datadog \u2014 APM + RUM
1749
1763
  # Server APM (dd-trace)
1750
1764
  DD_API_KEY=
1751
1765
  DD_APP_KEY=
@@ -1760,7 +1774,7 @@ NEXT_PUBLIC_DD_SITE=datadoghq.com
1760
1774
  NEXT_PUBLIC_DD_SERVICE=sailor-web
1761
1775
  NEXT_PUBLIC_DD_ENV=production
1762
1776
  NEXT_PUBLIC_DD_VERSION=
1763
- `}function hi(e){let t=`/**
1777
+ `}function Di(e){let t=`/**
1764
1778
  * Bugsnag server-side initialization.
1765
1779
  * Import this once at the top of your server entrypoint or a shared init module.
1766
1780
  */
@@ -1809,11 +1823,11 @@ export function getBugsnagErrorBoundary() {
1809
1823
  errorBoundary = plugin.createErrorBoundary(React) as typeof errorBoundary;
1810
1824
  return errorBoundary;
1811
1825
  }
1812
- `;te(M.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),te(M.join(e,"src","lib","monitoring","bugsnag.client.tsx"),o)}function Ei(){return`# Bugsnag \u2014 error tracking
1826
+ `;se(D.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),se(D.join(e,"src","lib","monitoring","bugsnag.client.tsx"),o)}function Fi(){return`# Bugsnag \u2014 error tracking
1813
1827
  BUGSNAG_API_KEY=
1814
1828
  NEXT_PUBLIC_BUGSNAG_API_KEY=
1815
1829
  APP_VERSION=
1816
- `}function vi(e){te(M.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
1830
+ `}function ji(e){se(D.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
1817
1831
  /**
1818
1832
  * \u963F\u91CC\u4E91 ARMS (Application Real-time Monitoring Service) browser agent.
1819
1833
  * Injects the official JS agent via next/script.
@@ -1834,11 +1848,11 @@ export function ArmsScript() {
1834
1848
  />
1835
1849
  );
1836
1850
  }
1837
- `)}function _i(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
1851
+ `)}function Vi(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
1838
1852
  ALIYUN_ARMS_LICENSE_KEY=
1839
1853
  ALIYUN_ARMS_APP_NAME=
1840
1854
  NEXT_PUBLIC_ARMS_PID=
1841
- `}function bi(e){te(M.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
1855
+ `}function Bi(e){se(D.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
1842
1856
  /**
1843
1857
  * \u542C\u4E91 Browser Agent (\u524D\u7AEF\u6027\u80FD\u76D1\u63A7).
1844
1858
  * Docs: https://www.tingyun.com/docs
@@ -1856,12 +1870,12 @@ export function TingYunScript() {
1856
1870
  />
1857
1871
  );
1858
1872
  }
1859
- `)}function Pi(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
1873
+ `)}function Ki(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
1860
1874
  TINGYUN_LICENSE_KEY=
1861
1875
  NEXT_PUBLIC_TINGYUN_APP_KEY=
1862
- `}async function _o(e,t,o="global"){let n=vo(t);if(!n||n.id==="none")return;let r=M.join(e,"apps","web");if(!re.existsSync(r))return;let s=n.id;try{switch(s){case"sentry":gi(r),sn(r,rn.sentry),Et(e,fi());return;case"datadog":yi(r),sn(r,rn.datadog),Et(e,Si());return;case"bugsnag":hi(r),sn(r,rn.bugsnag),Et(e,Ei());return;case"aliyun-arms":vi(r),Et(e,_i());return;case"tingyun":bi(r),Et(e,Pi());return;default:return}}catch(i){throw console.error(`Failed to apply monitoring selection "${t}":`,i),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Vt=[{id:"novu",name:"Novu",region:"both",envVars:["NOVU_API_KEY","NOVU_APPLICATION_IDENTIFIER"],docs:"https://docs.novu.co",description:"Multi-channel notification infrastructure"},{id:"knock",name:"Knock",region:"global",envVars:["KNOCK_API_KEY","KNOCK_SIGNING_KEY","KNOCK_PUBLIC_API_KEY"],docs:"https://docs.knock.app",description:"Product notifications platform"},{id:"custom",name:"Custom (direct dispatchers)",region:"both",envVars:[],docs:"",description:"Use email + sms + push directly"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function bo(e){return Vt.find(t=>t.id===e)}var Vp=Vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Po(e,t,o="global"){let n=bo(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Vt.map(r=>r.id).join(", ")}`);if(n.id==="none"){H(e,"notifications");return}n.envVars.length>0&&Q(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),Z(e,"NOTIFICATIONS_PROVIDER",n.id)}import an from"fs";import Ci from"path";async function Co(e,t){let o=Ci.join(e,"package.json");if(an.existsSync(o)){let n=an.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",an.writeFileSync(o,JSON.stringify(r,null,2)+`
1863
- `)}}import Bt from"fs";import st from"path";import{fileURLToPath as Ai}from"url";var wi=Ai(import.meta.url),Ao=st.dirname(wi);function Ii(){let e=[st.join(Ao,"..","templates","orm","drizzle"),st.join(Ao,"..","..","templates","orm","drizzle")];for(let t of e)if(Bt.existsSync(t))return t;return null}function wo(e,t){Bt.mkdirSync(t,{recursive:!0});for(let o of Bt.readdirSync(e,{withFileTypes:!0})){let n=st.join(e,o.name),r=st.join(t,o.name);o.isDirectory()?wo(n,r):Bt.copyFileSync(n,r)}}async function Io(e,t,o){if(t!=="drizzle")return{applied:!1};if(o!=="postgresql")return{applied:!1,reason:`Drizzle template currently targets Postgres only; --db=${o} keeps Prisma as sole ORM`};let n=Ii();if(!n)return{applied:!1,reason:"Drizzle template directory not found in package \u2014 bundling error"};let r=st.join(e,"packages","platform","db-drizzle");return wo(n,r),{applied:!0}}import se from"fs";import vt from"path";var Ri=["stripe","lemonsqueezy","chinapay","polar"];function Ro(e){se.existsSync(e)&&se.rmSync(e,{recursive:!0,force:!0})}function ki(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function xi(e,t){let o=vt.join(e,".env.example");se.existsSync(o)?se.appendFileSync(o,`
1864
- `+t):se.writeFileSync(o,t)}function Ti(e){switch(e){case"stripe":return`# Stripe
1876
+ `}async function xo(e,t,o="global"){let n=ko(t);if(!n||n.id==="none")return;let r=D.join(e,"apps","web");if(!ce.existsSync(r))return;let s=n.id;try{switch(s){case"sentry":Oi(r),ln(r,pn.sentry),At(e,Li());return;case"datadog":Ui(r),ln(r,pn.datadog),At(e,Mi());return;case"bugsnag":Di(r),ln(r,pn.bugsnag),At(e,Fi());return;case"aliyun-arms":ji(r),At(e,Vi());return;case"tingyun":Bi(r),At(e,Ki());return;default:return}}catch(i){throw console.error(`Failed to apply monitoring selection "${t}":`,i),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Gt=[{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 No(e){return Gt.find(t=>t.id===e)}var ml=Gt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function To(e,t,o="global"){let n=No(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Gt.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"notifications");return}n.envVars.length>0&&te(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"NOTIFICATIONS_PROVIDER",n.id)}import dn from"fs";import $i from"path";async function Oo(e,t){let o=$i.join(e,"package.json");if(dn.existsSync(o)){let n=dn.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",dn.writeFileSync(o,JSON.stringify(r,null,2)+`
1877
+ `)}}import Ht from"fs";import ct from"path";import{fileURLToPath as Yi}from"url";var qi=Yi(import.meta.url),Lo=ct.dirname(qi);function Gi(){let e=[ct.join(Lo,"..","templates","orm","drizzle"),ct.join(Lo,"..","..","templates","orm","drizzle")];for(let t of e)if(Ht.existsSync(t))return t;return null}function Uo(e,t){Ht.mkdirSync(t,{recursive:!0});for(let o of Ht.readdirSync(e,{withFileTypes:!0})){let n=ct.join(e,o.name),r=ct.join(t,o.name);o.isDirectory()?Uo(n,r):Ht.copyFileSync(n,r)}}async function Mo(e,t,o){if(t!=="drizzle")return{applied:!1};if(o!=="postgresql")return{applied:!1,reason:`Drizzle template currently targets Postgres only; --db=${o} keeps Prisma as sole ORM`};let n=Gi();if(!n)return{applied:!1,reason:"Drizzle template directory not found in package \u2014 bundling error"};let r=ct.join(e,"packages","platform","db-drizzle");return Uo(n,r),{applied:!0}}import pe from"fs";import Ct from"path";var Hi=["stripe","lemonsqueezy","chinapay","polar"];function Do(e){pe.existsSync(e)&&pe.rmSync(e,{recursive:!0,force:!0})}function Wi(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Xi(e,t){let o=Ct.join(e,".env.example");pe.existsSync(o)?pe.appendFileSync(o,`
1878
+ `+t):pe.writeFileSync(o,t)}function zi(e){switch(e){case"stripe":return`# Stripe
1865
1879
  STRIPE_SECRET_KEY=
1866
1880
  STRIPE_WEBHOOK_SECRET=
1867
1881
  `;case"lemon":return`# Lemon Squeezy
@@ -1876,14 +1890,14 @@ CHINAPAY_WECHAT_ENABLED=true
1876
1890
  CHINAPAY_APP_ID=
1877
1891
  CHINAPAY_APP_SECRET=
1878
1892
  CHINAPAY_ALIPAY_ENABLED=true
1879
- `}}async function ko(e,t){let o=vt.join(e,"packages","commerce","billing");if(!se.existsSync(o))return;if(t==="none"){Ro(o);return}let n=vt.join(o,"src"),r=new Set(ki(t));for(let i of Ri)r.has(i)||Ro(vt.join(n,i));let s=vt.join(n,"checkout","types.ts");if(se.existsSync(s)){let i=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=se.readFileSync(s,"utf8"),a=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${i}";`);a!==c&&se.writeFileSync(s,a)}xi(e,Ti(t))}import ue from"fs";import it from"path";var No=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),cn=/@sailor:([^\s*]+)/;function Ni(e,t){let{providerIds:o,customEndpoint:n}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:o.includes(r)}}if(e==="cn-compatible"){let r=o.some(s=>No.has(s));return{marker:e,keep:r||!!n}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:o.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!n}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function xo(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function To(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function Oo(e,t){let o=e.split(`
1880
- `),n=[],r=e.includes("#"),s=0;for(;s<o.length;){let i=o[s],c=i.match(cn);if(!c){n.push(i),s++;continue}let{marker:a,keep:l}=Ni(c[1],t);if(a==="registry-entries"){n.push(r?To(i):xo(i)),s++;continue}if(l){let m=r?To(i):xo(i);m.trim().length>0&&n.push(m);let S=s+1;for(;S<o.length&&o[S].trim()!==""&&!cn.test(o[S]);)n.push(o[S]),S++;S<o.length&&o[S].trim()===""&&(n.push(o[S]),S++),s=S}else{let m=s+1;for(;m<o.length&&o[m].trim()!==""&&!cn.test(o[m]);)m++;m<o.length&&o[m].trim()===""&&m++,s=m}}return Oi(n.join(`
1881
- `),t)}function Oi(e,t){let{providerIds:o,customEndpoint:n}=t,r=new Set;for(let l of o)["openai","anthropic","google","mistral","xai"].includes(l)&&r.add(l),r.add(l.replace(/-/g,"_")),r.add(l);n&&r.add("custom");let s=/createProviderRegistry\(\{([\s\S]*?)\}\)/,i=e.match(s);if(!i)return e;let a=i[1].split(`
1882
- `).filter(l=>{let m=l.trim();if(m===""||m.startsWith("//"))return!0;let S=m.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return S?r.has(S[1]):!0}).join(`
1883
- `);return e.replace(s,`createProviderRegistry({${a}})`)}function Ui(e,t){let o=it.join(t,"registry.ts.template"),n=ue.readFileSync(o,"utf-8");return Oo(n,e)}function Li(e,t){let o=it.join(t,".env.example.template"),n=ue.readFileSync(o,"utf-8");return Oo(n,e)}async function Uo(e,t,o){let n=Ui(t,o),r=Li(t,o),s=it.join(e,"packages/ai/agents/src");await ue.promises.mkdir(s,{recursive:!0}),await ue.promises.writeFile(it.join(s,"registry.ts"),n),await ue.promises.appendFile(it.join(e,".env.example"),`
1884
- `+r);let i={ai:"latest"},{providerIds:c,customEndpoint:a}=t;(c.includes("openai")||a||c.some(m=>No.has(m)))&&(i["@ai-sdk/openai"]="latest",i["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(i["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(i["@ai-sdk/google"]="latest"),c.includes("mistral")&&(i["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(i["@ai-sdk/openai"]="latest");let l=it.join(e,"package.json");if(ue.existsSync(l)){let m=JSON.parse(await ue.promises.readFile(l,"utf-8"));m.dependencies||(m.dependencies={});for(let[S,T]of Object.entries(i))m.dependencies[S]=T;await ue.promises.writeFile(l,JSON.stringify(m,null,2)+`
1885
- `)}}import f from"fs";import d from"path";function Lo(e,t){if(!f.existsSync(e))return;let o=f.readdirSync(e);for(let n of o){let r=d.join(e,n);f.statSync(r).isDirectory()?Lo(r,t):t(r)}}async function Mo(e,t){let o=d.join(e,"package.json");if(!f.existsSync(o))return;let n=JSON.parse(f.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=d.join(e,"packages","db");if(f.existsSync(r)){let s=d.join(r,"prisma");f.existsSync(s)&&f.rmSync(s,{recursive:!0,force:!0});let i=d.join(r,"package.json");if(f.existsSync(i)){let a=JSON.parse(f.readFileSync(i,"utf8"));a.dependencies&&delete a.dependencies["@prisma/client"],a.devDependencies&&delete a.devDependencies.prisma,f.writeFileSync(i,JSON.stringify(a,null,2)+`
1886
- `)}let c=d.join(r,"src","index.ts");f.existsSync(c)&&f.writeFileSync(c,`
1893
+ `}}async function Fo(e,t){let o=Ct.join(e,"packages","commerce","billing");if(!pe.existsSync(o))return;if(t==="none"){Do(o);return}let n=Ct.join(o,"src"),r=new Set(Wi(t));for(let i of Hi)r.has(i)||Do(Ct.join(n,i));let s=Ct.join(n,"checkout","types.ts");if(pe.existsSync(s)){let i=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=pe.readFileSync(s,"utf8"),a=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${i}";`);a!==c&&pe.writeFileSync(s,a)}Xi(e,zi(t))}import ye from"fs";import pt from"path";var Bo=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),un=/@sailor:([^\s*]+)/;function Ji(e,t){let{providerIds:o,customEndpoint:n}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:o.includes(r)}}if(e==="cn-compatible"){let r=o.some(s=>Bo.has(s));return{marker:e,keep:r||!!n}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:o.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!n}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function jo(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function Vo(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function Ko(e,t){let o=e.split(`
1894
+ `),n=[],r=e.includes("#"),s=0;for(;s<o.length;){let i=o[s],c=i.match(un);if(!c){n.push(i),s++;continue}let{marker:a,keep:l}=Ji(c[1],t);if(a==="registry-entries"){n.push(r?Vo(i):jo(i)),s++;continue}if(l){let d=r?Vo(i):jo(i);d.trim().length>0&&n.push(d);let S=s+1;for(;S<o.length&&o[S].trim()!==""&&!un.test(o[S]);)n.push(o[S]),S++;S<o.length&&o[S].trim()===""&&(n.push(o[S]),S++),s=S}else{let d=s+1;for(;d<o.length&&o[d].trim()!==""&&!un.test(o[d]);)d++;d<o.length&&o[d].trim()===""&&d++,s=d}}return Qi(n.join(`
1895
+ `),t)}function Qi(e,t){let{providerIds:o,customEndpoint:n}=t,r=new Set;for(let l of o)["openai","anthropic","google","mistral","xai"].includes(l)&&r.add(l),r.add(l.replace(/-/g,"_")),r.add(l);n&&r.add("custom");let s=/createProviderRegistry\(\{([\s\S]*?)\}\)/,i=e.match(s);if(!i)return e;let a=i[1].split(`
1896
+ `).filter(l=>{let d=l.trim();if(d===""||d.startsWith("//"))return!0;let S=d.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return S?r.has(S[1]):!0}).join(`
1897
+ `);return e.replace(s,`createProviderRegistry({${a}})`)}function Zi(e,t){let o=pt.join(t,"registry.ts.template"),n=ye.readFileSync(o,"utf-8");return Ko(n,e)}function ea(e,t){let o=pt.join(t,".env.example.template"),n=ye.readFileSync(o,"utf-8");return Ko(n,e)}async function $o(e,t,o){let n=Zi(t,o),r=ea(t,o),s=pt.join(e,"packages/ai/agents/src");await ye.promises.mkdir(s,{recursive:!0}),await ye.promises.writeFile(pt.join(s,"registry.ts"),n),await ye.promises.appendFile(pt.join(e,".env.example"),`
1898
+ `+r);let i={ai:"latest"},{providerIds:c,customEndpoint:a}=t;(c.includes("openai")||a||c.some(d=>Bo.has(d)))&&(i["@ai-sdk/openai"]="latest",i["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(i["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(i["@ai-sdk/google"]="latest"),c.includes("mistral")&&(i["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(i["@ai-sdk/openai"]="latest");let l=pt.join(e,"package.json");if(ye.existsSync(l)){let d=JSON.parse(await ye.promises.readFile(l,"utf-8"));d.dependencies||(d.dependencies={});for(let[S,C]of Object.entries(i))d.dependencies[S]=C;await ye.promises.writeFile(l,JSON.stringify(d,null,2)+`
1899
+ `)}}import y from"fs";import u from"path";function Yo(e,t){if(!y.existsSync(e))return;let o=y.readdirSync(e);for(let n of o){let r=u.join(e,n);y.statSync(r).isDirectory()?Yo(r,t):t(r)}}async function qo(e,t){let o=u.join(e,"package.json");if(!y.existsSync(o))return;let n=JSON.parse(y.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=u.join(e,"packages","db");if(y.existsSync(r)){let s=u.join(r,"prisma");y.existsSync(s)&&y.rmSync(s,{recursive:!0,force:!0});let i=u.join(r,"package.json");if(y.existsSync(i)){let a=JSON.parse(y.readFileSync(i,"utf8"));a.dependencies&&delete a.dependencies["@prisma/client"],a.devDependencies&&delete a.devDependencies.prisma,y.writeFileSync(i,JSON.stringify(a,null,2)+`
1900
+ `)}let c=u.join(r,"src","index.ts");y.existsSync(c)&&y.writeFileSync(c,`
1887
1901
  export const prisma = {} as any;
1888
1902
  export const db = {} as any;
1889
1903
  export type PrismaClient = any;
@@ -1929,7 +1943,7 @@ export type UsageAggregate = any;
1929
1943
  export type UsageLedgerEntry = any;
1930
1944
  export type UsageType = any;
1931
1945
  export type UsageLedgerSource = any;
1932
- `)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=d.join(e,"apps");if(f.existsSync(r)){let s=f.readdirSync(r);for(let i of s){let c=d.join(r,i);if(!f.statSync(c).isDirectory())continue;let a=d.join(c,"src","app");if(!f.existsSync(a))continue;["[lang]","[locale]"].forEach(_=>{let u=d.join(a,_);if(f.existsSync(u)){let U=f.readdirSync(u);for(let At of U)f.renameSync(d.join(u,At),d.join(a,At));f.rmdirSync(u)}}),["src/middleware.ts","middleware.ts"].forEach(_=>{let u=d.join(c,_);f.existsSync(u)&&f.rmSync(u)});let l=d.join(c,"src","lib");f.existsSync(l)||f.mkdirSync(l,{recursive:!0});let m=d.join(l,"mock-i18n.ts");f.writeFileSync(m,`
1946
+ `)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=u.join(e,"apps");if(y.existsSync(r)){let s=y.readdirSync(r);for(let i of s){let c=u.join(r,i);if(!y.statSync(c).isDirectory())continue;let a=u.join(c,"src","app");if(!y.existsSync(a))continue;["[lang]","[locale]"].forEach(b=>{let m=u.join(a,b);if(y.existsSync(m)){let U=y.readdirSync(m);for(let kt of U)y.renameSync(u.join(m,kt),u.join(a,kt));y.rmdirSync(m)}}),["src/middleware.ts","middleware.ts"].forEach(b=>{let m=u.join(c,b);y.existsSync(m)&&y.rmSync(m)});let l=u.join(c,"src","lib");y.existsSync(l)||y.mkdirSync(l,{recursive:!0});let d=u.join(l,"mock-i18n.ts");y.writeFileSync(d,`
1933
1947
  import React from 'react';
1934
1948
  export function useTranslations(namespace?: string): any { return (key: string) => key; }
1935
1949
  export function useLocale() { return 'en'; }
@@ -1947,7 +1961,7 @@ export const useRouter = () => ({ push: (...args: any[]) => {}, replace: (...arg
1947
1961
  export default function createMiddleware(...args: any[]) { return (req: any) => req; }
1948
1962
  export function createNavigation(...args: any[]) { return { Link, redirect, usePathname, useRouter, getPathname: () => '/' }; }
1949
1963
  export function defineRouting<T>(config: T): T { return config; }
1950
- `);let T=d.join(l,"mock-i18n.d.ts");f.writeFileSync(T,`declare module '@/lib/mock-i18n' {
1964
+ `);let C=u.join(l,"mock-i18n.d.ts");y.writeFileSync(C,`declare module '@/lib/mock-i18n' {
1951
1965
  export function useTranslations(namespace?: string): any;
1952
1966
  export function useLocale(): string;
1953
1967
  export const NextIntlClientProvider: React.FC<any>;
@@ -1965,19 +1979,19 @@ export function defineRouting<T>(config: T): T { return config; }
1965
1979
  export function createNavigation(...args: any[]): any;
1966
1980
  export function defineRouting<T>(config: T): T;
1967
1981
  }
1968
- `),f.writeFileSync(d.join(l,"mock-i18n-index.ts"),`
1982
+ `),y.writeFileSync(u.join(l,"mock-i18n-index.ts"),`
1969
1983
  export * from './mock-i18n';
1970
1984
  export { default } from './mock-i18n';
1971
- `);let N=d.join(c,"tsconfig.json");if(f.existsSync(N))try{let _=f.readFileSync(N,"utf8");if(_.includes('"paths": {')){let u=_.replace(/"paths":\s*\{/,`"paths": {
1985
+ `);let k=u.join(c,"tsconfig.json");if(y.existsSync(k))try{let b=y.readFileSync(k,"utf8");if(b.includes('"paths": {')){let m=b.replace(/"paths":\s*\{/,`"paths": {
1972
1986
  "next-intl": ["./src/lib/mock-i18n"],
1973
- "next-intl/*": ["./src/lib/mock-i18n"],`);f.writeFileSync(N,u)}}catch{}let D=d.join(c,"src");f.existsSync(D)&&Lo(D,_=>{if(!_.endsWith(".ts")&&!_.endsWith(".tsx"))return;let u=f.readFileSync(_,"utf8"),U=!1;_.endsWith("src/app/layout.tsx")&&u.includes("../providers")&&(u=u.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),U=!0),u=u.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),u=u.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),u.match(/locale\s*:\s*any/)&&(u=u.replace(/locale\s*:\s*any/g,"locale: string"),U=!0),u.match(/lang\s*:\s*any/)&&(u=u.replace(/lang\s*:\s*any/g,"lang: string"),U=!0),u.match(/requestLocale\s*:\s*any/)&&(u=u.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),U=!0),u.match(/\(locale\s*=\s*(.*)\)/)&&(u=u.replace(/\(locale\s*=\s*(.*)\)/g,"() "),U=!0),u.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(u=u.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 })"),U=!0),(_.endsWith("src/app/layout.tsx")||_.endsWith("src/app/sitemap.ts")||_.endsWith("src/app/robots.ts")||_.endsWith("src/components/ui/locale-switcher.tsx")||_.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(u=u.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),u=u.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),u=u.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),u=u.replace(/\(l\)\s*=>/g,"(l: any) =>"),U=!0),_.endsWith("src/i18n/request.ts")&&(u=u.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),U=!0),(u.match(/locale\s*:/)||u.match(/lang\s*:/))&&(U=!0),U&&f.writeFileSync(_,u)});let ae=d.join(c,"package.json");if(f.existsSync(ae)){let _=JSON.parse(f.readFileSync(ae,"utf8"));_.dependencies&&delete _.dependencies["next-intl"],f.writeFileSync(ae,JSON.stringify(_,null,2)+`
1974
- `)}}}}f.writeFileSync(o,JSON.stringify(n,null,2)+`
1975
- `)}function v(e){try{f.rmSync(e,{recursive:!0,force:!0})}catch{}}function Mi(e,t){if(!f.existsSync(e))return;let o;try{o=JSON.parse(f.readFileSync(e,"utf8"))}catch{return}let n=!1;if(o.dependencies&&t in o.dependencies){let{[t]:r,...s}=o.dependencies;o={...o,dependencies:s},n=!0}if(o.devDependencies&&t in o.devDependencies){let{[t]:r,...s}=o.devDependencies;o={...o,devDependencies:s},n=!0}n&&f.writeFileSync(e,JSON.stringify(o,null,2)+`
1976
- `)}function Do(e,t){t.cronJobs||(v(d.join(e,"apps/web/src/app/api/cron")),v(d.join(e,"packages/integrations/queue/src/scheduled"))),t.auditLog||(v(d.join(e,"apps/web/src/app/[locale]/(app)/settings/audit-log")),v(d.join(e,"apps/web/src/app/api/audit-logs")),v(d.join(e,"apps/web/src/components/audit"))),t.apiKeys||(v(d.join(e,"apps/web/src/app/[locale]/(app)/settings/api-keys")),v(d.join(e,"apps/web/src/app/api/api-keys")),v(d.join(e,"apps/web/src/components/api-keys"))),t.webhooks||(v(d.join(e,"apps/web/src/app/[locale]/(app)/settings/webhooks")),v(d.join(e,"apps/web/src/app/api/webhooks")),v(d.join(e,"apps/web/src/components/webhooks")),v(d.join(e,"packages/integrations/webhooks"))),t.commandPalette||(v(d.join(e,"apps/web/src/components/command-palette")),v(d.join(e,"apps/web/src/app/[locale]/providers/command-palette-mount.tsx"))),t.cookieConsent||(v(d.join(e,"apps/landing-page/src/components/cookie-consent-banner.tsx")),v(d.join(e,"apps/landing-page/src/components/__tests__/cookie-consent-banner.test.tsx")),v(d.join(e,"apps/landing-page/src/lib/cookie-consent.ts")),v(d.join(e,"apps/landing-page/src/lib/__tests__/cookie-consent.test.ts")),v(d.join(e,"apps/web/src/app/api/cookie-consent"))),t.legalPages||(v(d.join(e,"apps/landing-page/src/app/[lang]/(legal)/legal")),v(d.join(e,"apps/landing-page/src/lib/legal-documents.ts")),v(d.join(e,"apps/landing-page/src/lib/__tests__/legal-documents.test.ts"))),t.chinaCompliance||(v(d.join(e,"packages/ops/china-compliance")),v(d.join(e,"apps/landing-page/src/components/icp-footer.tsx")),v(d.join(e,"apps/landing-page/src/components/__tests__/icp-footer.test.tsx")),v(d.join(e,"apps/web/src/components/auth/wechat-login-button.tsx")),v(d.join(e,"apps/web/src/components/auth/__tests__/wechat-login-button.test.tsx")),Mi(d.join(e,"apps/web/package.json"),"@nebutra/china-compliance"))}import{getSchema as Di,printSchema as Fi}from"@mrleebo/prisma-ast";var ji=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function Vi(e){return e.type==="comment"&&e.text.trim().startsWith("///")}function Bi(e){let t=ji.exec(e.trim());if(!t)return null;let[,o,n]=t,r=n.split("|").map(s=>s.trim()).filter(s=>s.length>0);return{flag:o,values:r}}function Ki(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=Bi(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function pn(e,t){let o=Di(e),n=new Set;for(let c=0;c<o.list.length;c++){if(o.list[c].type!=="model")continue;let l=Ki(o.list,c);if(!l)continue;let m=t[l.parsed.flag];if(m!==void 0&&l.parsed.values.includes(m))n.add(l.annIndex);else{n.add(c);for(let N=c-1;N>=0;N--){let D=o.list[N];if(D.type==="comment"&&Vi(D)){n.add(N);continue}break}let T=o.list[c+1];T&&T.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,a)=>!n.has(a)),s=[];for(let c of r){let a=s[s.length-1];c.type==="break"&&a&&a.type==="break"||s.push(c)}return Fi({type:"schema",list:s})}import at from"fs";import jo from"path";var Kt=[{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:"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 Fo(e){return Kt.find(t=>t.id===e)}var pl=Kt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Vo(e){return at.existsSync(e)?at.readFileSync(e,"utf-8"):null}function $i(e,t){let o=jo.join(e,".env.example"),n=Vo(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1977
- `);at.appendFileSync(o,s)}function Yi(e,t,o){let n=jo.join(e,".env.example"),r=Vo(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?at.writeFileSync(n,r.replace(s,`${t}="${o}"`)):at.appendFileSync(n,`${t}="${o}"
1978
- `)}async function Bo(e,t,o){let n=Ae(e,"queue");if(t==="none"){n&&at.rmSync(n,{recursive:!0,force:!0});return}let r=Fo(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${Kt.map(s=>s.id).join(", ")}`);n&&($i(e,r),Yi(e,"QUEUE_PROVIDER",t))}import ie from"fs";import me from"path";import{fileURLToPath as qi}from"url";var Gi=qi(import.meta.url),Ko=me.dirname(Gi),Hi=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|toml|py)$/,Wi=["backends/gateway","infra","e2e","tests"];function Xi(){let e=[me.join(Ko,"..","templates"),me.join(Ko,"..","..","templates")];for(let t of e)if(ie.existsSync(t))return t;return e[0]}async function $o(e,t){let o=Xi(),n=[],r=[],s=[...Wi,...t.withWorkflows?["workflows"]:[],...t.withPythonBackend?["backends/python"]:[]];for(let i of s){let c=me.join(o,i);if(!ie.existsSync(c)){r.push(i);continue}let a=me.join(e,i);Yo(c,a),qo(a,{"{PRODUCT_NAME}":t.projectName}),n.push(i)}return{applied:n,skipped:r}}function Yo(e,t){ie.mkdirSync(t,{recursive:!0});for(let o of ie.readdirSync(e,{withFileTypes:!0})){let n=me.join(e,o.name),r=me.join(t,o.name);o.isDirectory()?Yo(n,r):ie.existsSync(r)||ie.copyFileSync(n,r)}}function qo(e,t){for(let o of ie.readdirSync(e,{withFileTypes:!0})){let n=me.join(e,o.name);if(o.isDirectory()){qo(n,t);continue}if(!Hi.test(o.name))continue;let r=ie.readFileSync(n,"utf-8"),s=!1;for(let[i,c]of Object.entries(t))r.includes(i)&&(r=r.split(i).join(c),s=!0);s&&ie.writeFileSync(n,r)}}import ct from"fs";import Ho from"path";var $t=[{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 Go(e){return $t.find(t=>t.id===e)}var vl=$t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Wo(e){return ct.existsSync(e)?ct.readFileSync(e,"utf-8"):null}function zi(e,t){let o=Ho.join(e,".env.example"),n=Wo(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1979
- `);ct.appendFileSync(o,s)}function Ji(e,t,o){let n=Ho.join(e,".env.example"),r=Wo(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?ct.writeFileSync(n,r.replace(s,`${t}="${o}"`)):ct.appendFileSync(n,`${t}="${o}"
1980
- `)}async function Xo(e,t,o){let n=Ae(e,"search");if(t==="none"){n&&ct.rmSync(n,{recursive:!0,force:!0});return}let r=Go(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${$t.map(s=>s.id).join(", ")}`);n&&(zi(e,r),Ji(e,"SEARCH_PROVIDER",t))}import ge from"fs";import Oe from"path";function Qi(e){let t=[Oe.join(e,"packages","db"),Oe.join(e,"apps","web")];for(let o of t){let n=Oe.join(o,"prisma","schema.prisma");if(ge.existsSync(n))return{packageDir:o,seedPath:Oe.join(o,"prisma","seed.ts"),packageJsonPath:Oe.join(o,"package.json")}}return null}function Zi(e){try{let t=ge.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 ea(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1987
+ "next-intl/*": ["./src/lib/mock-i18n"],`);y.writeFileSync(k,m)}}catch{}let $=u.join(c,"src");y.existsSync($)&&Yo($,b=>{if(!b.endsWith(".ts")&&!b.endsWith(".tsx"))return;let m=y.readFileSync(b,"utf8"),U=!1;b.endsWith("src/app/layout.tsx")&&m.includes("../providers")&&(m=m.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),U=!0),m=m.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),m=m.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),m.match(/locale\s*:\s*any/)&&(m=m.replace(/locale\s*:\s*any/g,"locale: string"),U=!0),m.match(/lang\s*:\s*any/)&&(m=m.replace(/lang\s*:\s*any/g,"lang: string"),U=!0),m.match(/requestLocale\s*:\s*any/)&&(m=m.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),U=!0),m.match(/\(locale\s*=\s*(.*)\)/)&&(m=m.replace(/\(locale\s*=\s*(.*)\)/g,"() "),U=!0),m.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(m=m.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 })"),U=!0),(b.endsWith("src/app/layout.tsx")||b.endsWith("src/app/sitemap.ts")||b.endsWith("src/app/robots.ts")||b.endsWith("src/components/ui/locale-switcher.tsx")||b.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(m=m.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),m=m.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),m=m.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),m=m.replace(/\(l\)\s*=>/g,"(l: any) =>"),U=!0),b.endsWith("src/i18n/request.ts")&&(m=m.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),U=!0),(m.match(/locale\s*:/)||m.match(/lang\s*:/))&&(U=!0),U&&y.writeFileSync(b,m)});let ue=u.join(c,"package.json");if(y.existsSync(ue)){let b=JSON.parse(y.readFileSync(ue,"utf8"));b.dependencies&&delete b.dependencies["next-intl"],y.writeFileSync(ue,JSON.stringify(b,null,2)+`
1988
+ `)}}}}y.writeFileSync(o,JSON.stringify(n,null,2)+`
1989
+ `)}function v(e){try{y.rmSync(e,{recursive:!0,force:!0})}catch{}}function ta(e,t){if(!y.existsSync(e))return;let o;try{o=JSON.parse(y.readFileSync(e,"utf8"))}catch{return}let n=!1;if(o.dependencies&&t in o.dependencies){let{[t]:r,...s}=o.dependencies;o={...o,dependencies:s},n=!0}if(o.devDependencies&&t in o.devDependencies){let{[t]:r,...s}=o.devDependencies;o={...o,devDependencies:s},n=!0}n&&y.writeFileSync(e,JSON.stringify(o,null,2)+`
1990
+ `)}function Go(e,t){t.cronJobs||(v(u.join(e,"apps/web/src/app/api/cron")),v(u.join(e,"packages/integrations/queue/src/scheduled"))),t.auditLog||(v(u.join(e,"apps/web/src/app/[locale]/(app)/settings/audit-log")),v(u.join(e,"apps/web/src/app/api/audit-logs")),v(u.join(e,"apps/web/src/components/audit"))),t.apiKeys||(v(u.join(e,"apps/web/src/app/[locale]/(app)/settings/api-keys")),v(u.join(e,"apps/web/src/app/api/api-keys")),v(u.join(e,"apps/web/src/components/api-keys"))),t.webhooks||(v(u.join(e,"apps/web/src/app/[locale]/(app)/settings/webhooks")),v(u.join(e,"apps/web/src/app/api/webhooks")),v(u.join(e,"apps/web/src/components/webhooks")),v(u.join(e,"packages/integrations/webhooks"))),t.commandPalette||(v(u.join(e,"apps/web/src/components/command-palette")),v(u.join(e,"apps/web/src/app/[locale]/providers/command-palette-mount.tsx"))),t.cookieConsent||(v(u.join(e,"apps/landing-page/src/components/cookie-consent-banner.tsx")),v(u.join(e,"apps/landing-page/src/components/__tests__/cookie-consent-banner.test.tsx")),v(u.join(e,"apps/landing-page/src/lib/cookie-consent.ts")),v(u.join(e,"apps/landing-page/src/lib/__tests__/cookie-consent.test.ts")),v(u.join(e,"apps/web/src/app/api/cookie-consent"))),t.legalPages||(v(u.join(e,"apps/landing-page/src/app/[lang]/(legal)/legal")),v(u.join(e,"apps/landing-page/src/lib/legal-documents.ts")),v(u.join(e,"apps/landing-page/src/lib/__tests__/legal-documents.test.ts"))),t.chinaCompliance||(v(u.join(e,"packages/ops/china-compliance")),v(u.join(e,"apps/landing-page/src/components/icp-footer.tsx")),v(u.join(e,"apps/landing-page/src/components/__tests__/icp-footer.test.tsx")),v(u.join(e,"apps/web/src/components/auth/wechat-login-button.tsx")),v(u.join(e,"apps/web/src/components/auth/__tests__/wechat-login-button.test.tsx")),ta(u.join(e,"apps/web/package.json"),"@nebutra/china-compliance"))}import lt from"fs";import Ho from"path";var Wo=/^--\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/m;function na(e){let t=Wo.exec(e);if(!t)return null;let[,o,n]=t,r=n.split("|").map(s=>s.trim()).filter(Boolean);return{flag:o,values:r}}function oa(e){return e.replace(Wo,"").replace(/^\n/,"")}function mn(e,t){let o={kept:[],removed:[],skipped:[]};if(!lt.existsSync(e))return o;let n=lt.readdirSync(e,{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,s)=>r.name.localeCompare(s.name));for(let r of n){let s=Ho.join(e,r.name),i=Ho.join(s,"migration.sql");if(!lt.existsSync(i)){o.skipped.push(r.name);continue}let c=lt.readFileSync(i,"utf8"),a=na(c);if(!a){o.skipped.push(r.name);continue}let l=t[a.flag];if(l!==void 0&&a.values.includes(l)){lt.writeFileSync(i,oa(c)),o.kept.push(r.name);continue}lt.rmSync(s,{recursive:!0,force:!0}),o.removed.push(r.name)}return o}import{getSchema as ra,printSchema as sa}from"@mrleebo/prisma-ast";var ia=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function aa(e){return e.type==="comment"&&e.text.trim().startsWith("//")}function ca(e){let t=ia.exec(e.trim());if(!t)return null;let[,o,n]=t,r=n.split("|").map(s=>s.trim()).filter(s=>s.length>0);return{flag:o,values:r}}function pa(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=ca(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function la(e){return e.type==="model"||e.type==="enum"}function gn(e,t){let o=ra(e),n=new Set;for(let c=0;c<o.list.length;c++){let a=o.list[c];if(!la(a))continue;let l=pa(o.list,c);if(!l)continue;let d=t[l.parsed.flag];if(d!==void 0&&l.parsed.values.includes(d))n.add(l.annIndex);else{n.add(c);for(let k=c-1;k>=0;k--){let $=o.list[k];if(aa($)){n.add(k);continue}break}let C=o.list[c+1];C&&C.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,a)=>!n.has(a)),s=[];for(let c of r){let a=s[s.length-1];c.type==="break"&&a&&a.type==="break"||s.push(c)}return sa({type:"schema",list:s})}import dt from"fs";import zo 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:"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 Xo(e){return Wt.find(t=>t.id===e)}var jl=Wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Jo(e){return dt.existsSync(e)?dt.readFileSync(e,"utf-8"):null}function da(e,t){let o=zo.join(e,".env.example"),n=Jo(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1991
+ `);dt.appendFileSync(o,s)}function ua(e,t,o){let n=zo.join(e,".env.example"),r=Jo(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?dt.writeFileSync(n,r.replace(s,`${t}="${o}"`)):dt.appendFileSync(n,`${t}="${o}"
1992
+ `)}async function Qo(e,t,o){let n=Re(e,"queue");if(t==="none"){n&&dt.rmSync(n,{recursive:!0,force:!0});return}let r=Xo(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${Wt.map(s=>s.id).join(", ")}`);n&&(da(e,r),ua(e,"QUEUE_PROVIDER",t))}import le from"fs";import Se from"path";import{fileURLToPath as ma}from"url";var ga=ma(import.meta.url),Zo=Se.dirname(ga),fa=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|toml|py)$/,ya=["backends/gateway","infra","e2e","tests"];function Sa(){let e=[Se.join(Zo,"..","templates"),Se.join(Zo,"..","..","templates")];for(let t of e)if(le.existsSync(t))return t;return e[0]}async function er(e,t){let o=Sa(),n=[],r=[],s=[...ya,...t.withWorkflows?["workflows"]:[],...t.withPythonBackend?["backends/python"]:[]];for(let i of s){let c=Se.join(o,i);if(!le.existsSync(c)){r.push(i);continue}let a=Se.join(e,i);tr(c,a),nr(a,{"{PRODUCT_NAME}":t.projectName}),n.push(i)}return{applied:n,skipped:r}}function tr(e,t){le.mkdirSync(t,{recursive:!0});for(let o of le.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name),r=Se.join(t,o.name);o.isDirectory()?tr(n,r):le.existsSync(r)||le.copyFileSync(n,r)}}function nr(e,t){for(let o of le.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name);if(o.isDirectory()){nr(n,t);continue}if(!fa.test(o.name))continue;let r=le.readFileSync(n,"utf-8"),s=!1;for(let[i,c]of Object.entries(t))r.includes(i)&&(r=r.split(i).join(c),s=!0);s&&le.writeFileSync(n,r)}}import ut from"fs";import rr from"path";var Xt=[{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 or(e){return Xt.find(t=>t.id===e)}var zl=Xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function sr(e){return ut.existsSync(e)?ut.readFileSync(e,"utf-8"):null}function ha(e,t){let o=rr.join(e,".env.example"),n=sr(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1993
+ `);ut.appendFileSync(o,s)}function Ea(e,t,o){let n=rr.join(e,".env.example"),r=sr(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?ut.writeFileSync(n,r.replace(s,`${t}="${o}"`)):ut.appendFileSync(n,`${t}="${o}"
1994
+ `)}async function ir(e,t,o){let n=Re(e,"search");if(t==="none"){n&&ut.rmSync(n,{recursive:!0,force:!0});return}let r=or(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Xt.map(s=>s.id).join(", ")}`);n&&(ha(e,r),Ea(e,"SEARCH_PROVIDER",t))}import he from"fs";import Me from"path";function va(e){let t=[Me.join(e,"packages","db"),Me.join(e,"apps","web")];for(let o of t){let n=Me.join(o,"prisma","schema.prisma");if(he.existsSync(n))return{packageDir:o,seedPath:Me.join(o,"prisma","seed.ts"),packageJsonPath:Me.join(o,"package.json")}}return null}function _a(e){try{let t=he.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 ba(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1981
1995
  const admin = await prisma.user.create({
1982
1996
  data: {
1983
1997
  clerkId: "user_mock_admin",
@@ -2008,7 +2022,7 @@ export { default } from './mock-i18n';
2008
2022
  console.log("\\u2713 Created admin user:", admin.email);
2009
2023
  } catch (err) {
2010
2024
  console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
2011
- }`}function ta(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),s=ea(e,n),i=o?` let tenants: Array<{ id: string; name: string }> = [];
2025
+ }`}function Pa(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),s=ba(e,n),i=o?` let tenants: Array<{ id: string; name: string }> = [];
2012
2026
  try {
2013
2027
  tenants = await Promise.all([
2014
2028
  prisma.tenant.create({
@@ -2077,12 +2091,12 @@ main()
2077
2091
  .finally(async () => {
2078
2092
  await prisma.$disconnect();
2079
2093
  });
2080
- `}function na(e){if(ge.existsSync(e))try{let t=ge.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let s=o.prisma??{};if(s.seed||(s.seed="tsx prisma/seed.ts",r=!0),!r)return;let i={...o,scripts:n,prisma:s};ge.writeFileSync(e,JSON.stringify(i,null,2)+`
2081
- `)}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 zo(e,t){let o=Qi(e);if(o)try{let n=Oe.join(o.packageDir,"prisma","schema.prisma"),r=Zi(n),s=ta(t,r),i=Oe.dirname(o.seedPath);ge.existsSync(i)||ge.mkdirSync(i,{recursive:!0}),ge.writeFileSync(o.seedPath,s),na(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 fe from"fs";import Ue from"path";var Yt=[{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:""}],xl=Yt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Jo(e){return Yt.find(t=>t.id===e)}var oa="@nebutra/sms",ra={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 ln(e,t){fe.mkdirSync(Ue.dirname(e),{recursive:!0}),fe.writeFileSync(e,t)}function sa(e,t){let o=Ue.join(e,".env.example");fe.existsSync(o)?fe.appendFileSync(o,`
2082
- `+t):fe.writeFileSync(o,t)}function ia(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2094
+ `}function Aa(e){if(he.existsSync(e))try{let t=he.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let s=o.prisma??{};if(s.seed||(s.seed="tsx prisma/seed.ts",r=!0),!r)return;let i={...o,scripts:n,prisma:s};he.writeFileSync(e,JSON.stringify(i,null,2)+`
2095
+ `)}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 ar(e,t){let o=va(e);if(o)try{let n=Me.join(o.packageDir,"prisma","schema.prisma"),r=_a(n),s=Pa(t,r),i=Me.dirname(o.seedPath);he.existsSync(i)||he.mkdirSync(i,{recursive:!0}),he.writeFileSync(o.seedPath,s),Aa(o.packageJsonPath)}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate seed data: ${r}`),new Error(`Unable to write prisma/seed.ts: ${r}`)}}import Ee from"fs";import De from"path";var zt=[{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:""}],id=zt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function cr(e){return zt.find(t=>t.id===e)}var Ca="@nebutra/sms",Ia={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 fn(e,t){Ee.mkdirSync(De.dirname(e),{recursive:!0}),Ee.writeFileSync(e,t)}function wa(e,t){let o=De.join(e,".env.example");Ee.existsSync(o)?Ee.appendFileSync(o,`
2096
+ `+t):Ee.writeFileSync(o,t)}function Ra(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2083
2097
  `);return`${t}
2084
2098
  ${o}
2085
- `}var aa=`/**
2099
+ `}var ka=`/**
2086
2100
  * Inputs for the \`sendSms\` wrapper. Keep this surface portable across
2087
2101
  * providers \u2014 provider-specific options belong in the wrapper itself.
2088
2102
  */
@@ -2102,7 +2116,7 @@ export interface SendSmsResult {
2102
2116
  provider: string;
2103
2117
  raw?: unknown;
2104
2118
  }
2105
- `;function ca(){return`import twilio from "twilio";
2119
+ `;function xa(){return`import twilio from "twilio";
2106
2120
  import type { SendSmsInput, SendSmsResult } from "./types";
2107
2121
 
2108
2122
  let client: ReturnType<typeof twilio> | null = null;
@@ -2137,7 +2151,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2137
2151
  }
2138
2152
 
2139
2153
  export type { SendSmsInput, SendSmsResult } from "./types";
2140
- `}function pa(){return`import messagebird from "messagebird";
2154
+ `}function Na(){return`import messagebird from "messagebird";
2141
2155
  import type { SendSmsInput, SendSmsResult } from "./types";
2142
2156
 
2143
2157
  let client: ReturnType<typeof messagebird> | null = null;
@@ -2175,7 +2189,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2175
2189
  }
2176
2190
 
2177
2191
  export type { SendSmsInput, SendSmsResult } from "./types";
2178
- `}function la(){return`import plivo from "plivo";
2192
+ `}function Ta(){return`import plivo from "plivo";
2179
2193
  import type { SendSmsInput, SendSmsResult } from "./types";
2180
2194
 
2181
2195
  let client: InstanceType<typeof plivo.Client> | null = null;
@@ -2214,7 +2228,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2214
2228
  }
2215
2229
 
2216
2230
  export type { SendSmsInput, SendSmsResult } from "./types";
2217
- `}function da(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
2231
+ `}function Oa(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
2218
2232
  import * as $OpenApi from "@alicloud/openapi-client";
2219
2233
  import type { SendSmsInput, SendSmsResult } from "./types";
2220
2234
 
@@ -2263,7 +2277,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2263
2277
  }
2264
2278
 
2265
2279
  export type { SendSmsInput, SendSmsResult } from "./types";
2266
- `}function ua(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
2280
+ `}function La(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
2267
2281
  import type { SendSmsInput, SendSmsResult } from "./types";
2268
2282
 
2269
2283
  const SmsClient = tencentcloud.sms.v20210111.Client;
@@ -2328,7 +2342,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2328
2342
  }
2329
2343
 
2330
2344
  export type { SendSmsInput, SendSmsResult } from "./types";
2331
- `}function ma(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
2345
+ `}function Ua(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
2332
2346
  import Yunpian from "yunpian-nodejs-sdk";
2333
2347
  import type { SendSmsInput, SendSmsResult } from "./types";
2334
2348
 
@@ -2380,13 +2394,13 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2380
2394
  }
2381
2395
 
2382
2396
  export type { SendSmsInput, SendSmsResult } from "./types";
2383
- `}function ga(e){switch(e){case"twilio":return ca();case"messagebird":return pa();case"plivo":return la();case"aliyun-sms":return da();case"tencent-sms":return ua();case"yunpian":return ma();case"none":return`export {};
2384
- `}}function fa(e){let t={};for(let n of e.pkgs??[]){let r=ra[n];r&&(t[n]=r)}let o={name:oa,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)+`
2385
- `}async function Qo(e,t,o="global"){if(t==="none")return;let n=Jo(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${Yt.map(i=>i.id).join(", ")}`);let r=Ue.join(e,"packages","sms");if(!fe.existsSync(r))return;let s=Ue.join(r,"src");fe.existsSync(s)&&fe.rmSync(s,{recursive:!0,force:!0});try{ln(Ue.join(r,"package.json"),fa(n)),ln(Ue.join(s,"types.ts"),aa),ln(Ue.join(s,"index.ts"),ga(n.id)),sa(e,ia(n))}catch(i){throw console.error(`Failed to apply SMS selection "${t}":`,i),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import Me from"fs";import Le from"path";var _t=[{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 dn(e){let t=e==="supabase"?"supabase-storage":e;return _t.some(o=>o.id===t)?t:void 0}function Zo(e){let t=dn(e);return t?_t.find(o=>o.id===t):void 0}var Ml=_t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var De="@nebutra/storage";function un(e,t){Me.mkdirSync(Le.dirname(e),{recursive:!0}),Me.writeFileSync(e,t)}function ya(e,t){let o=Le.join(e,".env.example");Me.existsSync(o)?Me.appendFileSync(o,`
2386
- `+t):Me.writeFileSync(o,t)}function Sa(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2397
+ `}function Ma(e){switch(e){case"twilio":return xa();case"messagebird":return Na();case"plivo":return Ta();case"aliyun-sms":return Oa();case"tencent-sms":return La();case"yunpian":return Ua();case"none":return`export {};
2398
+ `}}function Da(e){let t={};for(let n of e.pkgs??[]){let r=Ia[n];r&&(t[n]=r)}let o={name:Ca,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)+`
2399
+ `}async function pr(e,t,o="global"){if(t==="none")return;let n=cr(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${zt.map(i=>i.id).join(", ")}`);let r=De.join(e,"packages","sms");if(!Ee.existsSync(r))return;let s=De.join(r,"src");Ee.existsSync(s)&&Ee.rmSync(s,{recursive:!0,force:!0});try{fn(De.join(r,"package.json"),Da(n)),fn(De.join(s,"types.ts"),ka),fn(De.join(s,"index.ts"),Ma(n.id)),wa(e,Ra(n))}catch(i){throw console.error(`Failed to apply SMS selection "${t}":`,i),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import je from"fs";import Fe from"path";var It=[{id:"r2",name:"Cloudflare R2",region:"global",envVars:["R2_ACCOUNT_ID","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY","R2_BUCKET"],docs:"https://developers.cloudflare.com/r2/api/s3/api/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"s3",name:"AWS S3",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_S3_REGION","S3_BUCKET"],docs:"https://docs.aws.amazon.com/s3/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"supabase-storage",name:"Supabase Storage",region:"global",envVars:["SUPABASE_URL","SUPABASE_SERVICE_ROLE_KEY","SUPABASE_BUCKET"],docs:"https://supabase.com/docs/guides/storage",pkg:"@supabase/supabase-js",pkgVersion:"^2.45.4"},{id:"aliyun-oss",name:"\u963F\u91CC\u4E91 OSS",region:"cn",envVars:["ALIYUN_OSS_ACCESS_KEY","ALIYUN_OSS_ACCESS_SECRET","ALIYUN_OSS_REGION","ALIYUN_OSS_BUCKET"],docs:"https://help.aliyun.com/product/31815.html",pkg:"ali-oss",pkgVersion:"^6.21.0"},{id:"tencent-cos",name:"\u817E\u8BAF\u4E91 COS",region:"cn",envVars:["TENCENT_COS_SECRET_ID","TENCENT_COS_SECRET_KEY","TENCENT_COS_BUCKET","TENCENT_COS_REGION"],docs:"https://cloud.tencent.com/document/product/436",pkg:"cos-nodejs-sdk-v5",pkgVersion:"^2.13.7"},{id:"qiniu",name:"\u4E03\u725B\u4E91 Kodo",region:"cn",envVars:["QINIU_ACCESS_KEY","QINIU_SECRET_KEY","QINIU_BUCKET","QINIU_DOMAIN"],docs:"https://developer.qiniu.com/kodo",pkg:"qiniu",pkgVersion:"^7.14.0"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function yn(e){let t=e==="supabase"?"supabase-storage":e;return It.some(o=>o.id===t)?t:void 0}function lr(e){let t=yn(e);return t?It.find(o=>o.id===t):void 0}var ud=It.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Ve="@nebutra/storage";function Sn(e,t){je.mkdirSync(Fe.dirname(e),{recursive:!0}),je.writeFileSync(e,t)}function Fa(e,t){let o=Fe.join(e,".env.example");je.existsSync(o)?je.appendFileSync(o,`
2400
+ `+t):je.writeFileSync(o,t)}function ja(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2387
2401
  `);return`${t}
2388
2402
  ${o}
2389
- `}var ha=`/**
2403
+ `}var Va=`/**
2390
2404
  * Inputs for the \`uploadFile\` wrapper. Keep this surface portable across
2391
2405
  * providers \u2014 provider-specific options belong in the wrapper itself.
2392
2406
  */
@@ -2412,8 +2426,8 @@ export interface SignedUrlOptions {
2412
2426
  operation?: "get" | "put";
2413
2427
  contentType?: string;
2414
2428
  }
2415
- `;function Ea(){return`/**
2416
- * @${De.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
2429
+ `;function Ba(){return`/**
2430
+ * @${Ve.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
2417
2431
  *
2418
2432
  * Docs: https://developers.cloudflare.com/r2/api/s3/api/
2419
2433
  */
@@ -2476,8 +2490,8 @@ export async function getSignedUrl(
2476
2490
  }
2477
2491
 
2478
2492
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2479
- `}function va(){return`/**
2480
- * @${De.slice(1)} \u2014 AWS S3 wrapper.
2493
+ `}function Ka(){return`/**
2494
+ * @${Ve.slice(1)} \u2014 AWS S3 wrapper.
2481
2495
  *
2482
2496
  * Docs: https://docs.aws.amazon.com/s3/
2483
2497
  */
@@ -2541,8 +2555,8 @@ export async function getSignedUrl(
2541
2555
  }
2542
2556
 
2543
2557
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2544
- `}function _a(){return`/**
2545
- * @${De.slice(1)} \u2014 Supabase Storage wrapper.
2558
+ `}function $a(){return`/**
2559
+ * @${Ve.slice(1)} \u2014 Supabase Storage wrapper.
2546
2560
  *
2547
2561
  * Docs: https://supabase.com/docs/guides/storage
2548
2562
  */
@@ -2604,8 +2618,8 @@ export async function getSignedUrl(
2604
2618
  }
2605
2619
 
2606
2620
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2607
- `}function ba(){return`/**
2608
- * @${De.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
2621
+ `}function Ya(){return`/**
2622
+ * @${Ve.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
2609
2623
  *
2610
2624
  * Docs: https://help.aliyun.com/product/31815.html
2611
2625
  */
@@ -2651,8 +2665,8 @@ export async function getSignedUrl(
2651
2665
  }
2652
2666
 
2653
2667
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2654
- `}function Pa(){return`/**
2655
- * @${De.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
2668
+ `}function qa(){return`/**
2669
+ * @${Ve.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
2656
2670
  *
2657
2671
  * Docs: https://cloud.tencent.com/document/product/436
2658
2672
  */
@@ -2706,8 +2720,8 @@ export async function getSignedUrl(
2706
2720
  }
2707
2721
 
2708
2722
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2709
- `}function Ca(){return`/**
2710
- * @${De.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
2723
+ `}function Ga(){return`/**
2724
+ * @${Ve.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
2711
2725
  *
2712
2726
  * Docs: https://developer.qiniu.com/kodo
2713
2727
  */
@@ -2774,9 +2788,9 @@ export async function getSignedUrl(
2774
2788
  }
2775
2789
 
2776
2790
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2777
- `}function Aa(e){switch(e){case"r2":return Ea();case"s3":return va();case"supabase-storage":return _a();case"aliyun-oss":return ba();case"tencent-cos":return Pa();case"qiniu":return Ca();case"none":return`export {};
2778
- `}}function wa(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:De,version:"0.1.0",private:!0,description:`Object storage via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
2779
- `}async function er(e,t,o){if(t==="none")return;let n=Zo(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${_t.map(i=>i.id).join(", ")}`);let r=Le.join(e,"packages","storage"),s=Le.join(r,"src");Me.existsSync(s)&&Me.rmSync(s,{recursive:!0,force:!0}),un(Le.join(r,"package.json"),wa(n)),un(Le.join(s,"types.ts"),ha),un(Le.join(s,"index.ts"),Aa(n.id)),ya(e,Sa(n))}function ye(e,t){if(e===void 0)return t;let o=String(e).trim().toLowerCase();return o==="true"||o==="1"||o==="yes"||o==="on"?!0:o==="false"||o==="0"||o==="no"||o==="off"?!1:t}function tr(e,t){let o=t==="cn";return{cronJobs:ye(e.cronJobs,!0),auditLog:ye(e.auditLog,!0),apiKeys:ye(e.apiKeys,!0),webhooks:ye(e.webhooks,!0),commandPalette:ye(e.commandPalette,!0),cookieConsent:ye(e.cookieConsent,!0),legalPages:ye(e.legalPages,!0),chinaCompliance:ye(e.chinaCompliance,o)}}var qt=[{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 nr(e){return qt.find(t=>t.id===e)}var $l=qt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function or(e,t,o="global"){let n=nr(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${qt.map(r=>r.id).join(", ")}`);if(n.id==="none"){H(e,"webhooks");return}n.envVars.length>0&&Q(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),Z(e,"WEBHOOKS_PROVIDER",n.id)}import Fe from"fs";import bt from"path";function Ia(e){return`import Link from "next/link";
2791
+ `}function Ha(e){switch(e){case"r2":return Ba();case"s3":return Ka();case"supabase-storage":return $a();case"aliyun-oss":return Ya();case"tencent-cos":return qa();case"qiniu":return Ga();case"none":return`export {};
2792
+ `}}function Wa(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:Ve,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)+`
2793
+ `}async function dr(e,t,o){if(t==="none")return;let n=lr(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${It.map(i=>i.id).join(", ")}`);let r=Fe.join(e,"packages","storage"),s=Fe.join(r,"src");je.existsSync(s)&&je.rmSync(s,{recursive:!0,force:!0}),Sn(Fe.join(r,"package.json"),Wa(n)),Sn(Fe.join(s,"types.ts"),Va),Sn(Fe.join(s,"index.ts"),Ha(n.id)),Fa(e,ja(n))}function ve(e,t){if(e===void 0)return t;let o=String(e).trim().toLowerCase();return o==="true"||o==="1"||o==="yes"||o==="on"?!0:o==="false"||o==="0"||o==="no"||o==="off"?!1:t}function ur(e,t){let o=t==="cn";return{cronJobs:ve(e.cronJobs,!0),auditLog:ve(e.auditLog,!0),apiKeys:ve(e.apiKeys,!0),webhooks:ve(e.webhooks,!0),commandPalette:ve(e.commandPalette,!0),cookieConsent:ve(e.cookieConsent,!0),legalPages:ve(e.legalPages,!0),chinaCompliance:ve(e.chinaCompliance,o)}}var Jt=[{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 mr(e){return Jt.find(t=>t.id===e)}var Ed=Jt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function gr(e,t,o="global"){let n=mr(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Jt.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"webhooks");return}n.envVars.length>0&&te(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"WEBHOOKS_PROVIDER",n.id)}import Be from"fs";import wt from"path";function Xa(e){return`import Link from "next/link";
2780
2794
 
2781
2795
  export default function WelcomePage() {
2782
2796
  const projectName = ${JSON.stringify(e)};
@@ -2885,21 +2899,21 @@ function Step({
2885
2899
  </li>
2886
2900
  );
2887
2901
  }
2888
- `}function Ra(e={}){return`
2902
+ `}function za(e={}){return`
2889
2903
  ## What you can do next
2890
2904
 
2891
2905
  ${[e.apiKeys===!1?"- Manage API keys at `/settings/api-keys` (disabled \u2014 re-enable with `--api-keys=true`)":"- Manage API keys at `/settings/api-keys`",e.auditLog===!1?"- View audit log at `/settings/audit-log` (disabled \u2014 re-enable with `--audit-log=true`)":"- View audit log at `/settings/audit-log`","- Configure webhooks at `/settings/webhooks`",e.commandPalette===!1?"- Press \u2318K to open the command palette (disabled \u2014 re-enable with `--command-palette=true`)":"- Press \u2318K to open the command palette","- Edit notification preferences at `/settings/notifications`","- Export your data at `/settings/account/export`","- For China deployments, see `packages/ops/china-compliance/README.md`"].join(`
2892
2906
  `)}
2893
- `}function ka(e=[]){return e.length===0?"":`
2907
+ `}function Ja(e=[]){return e.length===0?"":`
2894
2908
  ## Production readiness holds
2895
2909
 
2896
2910
  Do not enable these in production until you replace stubs, add provider credentials, and verify the integration contract:
2897
2911
 
2898
- ${e.map(o=>{let n=tt(o.status);return`- ${o.flag}=${o.provider} ${n} \u2014 ${pe(o.status)}`}).join(`
2912
+ ${e.map(o=>{let n=rt(o.status);return`- ${o.flag}=${o.provider} ${n} \u2014 ${me(o.status)}`}).join(`
2899
2913
  `)}
2900
2914
 
2901
2915
  Review the package readiness matrix before handoff: [docs/package-status.md](docs/package-status.md)
2902
- `}function xa(e,t,o=[],n={}){return`# Next steps \u2014 ${e}
2916
+ `}function Qa(e,t,o=[],n={}){return`# Next steps \u2014 ${e}
2903
2917
 
2904
2918
  Region: ${t}
2905
2919
 
@@ -2925,42 +2939,44 @@ Your AI-native SaaS scaffold is ready. Complete these four steps to go from temp
2925
2939
  \`\`\`
2926
2940
 
2927
2941
  After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
2928
- ${Ra(n)}${ka(o)}
2942
+ ${za(n)}${Ja(o)}
2929
2943
 
2930
2944
  ## Resources
2931
2945
 
2932
2946
  - [Documentation](/docs)
2933
2947
  - [GitHub](https://github.com/nebutra/nebutra-sailor)
2934
2948
  - [Get free license (Individual/OPC)](https://nebutra.com/get-license)
2935
- `}async function rr(e,t){let{projectName:o,region:n,previewSelections:r=[],waveFeatures:s={}}=t;try{let i=bt.join(e,".sailor");Fe.existsSync(i)||Fe.mkdirSync(i,{recursive:!0}),Fe.writeFileSync(bt.join(i,"next-steps.md"),xa(o,n,r,s))}catch(i){let c=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${c}`)}try{let i=bt.join(e,"apps","web");if(!Fe.existsSync(i))return;let c=bt.join(i,"src","app","[locale]","welcome");Fe.existsSync(c)||Fe.mkdirSync(c,{recursive:!0}),Fe.writeFileSync(bt.join(c,"page.tsx"),Ia(o))}catch(i){let c=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write welcome page: ${c}`)}}var sr="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2936
- `)}function Oa(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function ir(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 ar(e,t,o){let n=e?.trim().toLowerCase()??Bn(t),r=Mt(n);if(!r){let i=tn.map(c=>c.id).join(", ");throw new Error(`Unknown --db-host="${n}". Valid: ${i}`)}let s=o;return r.forcedEngine&&s!=="none"&&s!==r.forcedEngine&&(s=r.forcedEngine),{hostId:r.id,engine:s}}function cr(e){return e==="drizzle"?"drizzle":"prisma"}function pr(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function lr(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 dr(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="nextauth"||t==="next-auth"||t==="authjs"||t==="auth.js"?"nextauth":t==="none"?"none":"clerk"}var Ua=new Set(["gateway","direct","custom","none"]);function hr(e){if(!e)return!1;let t=e.trim().toLowerCase();return Ua.has(t)}function ur(e){if(!e)return["openai"];if(hr(e))return[];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}function La(e,t){let o=e??t;return dn(o)??o}var mr={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function gr(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in mr){let n=mr[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(C.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
2937
- `)+C.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
2938
- `)),"fumadocs"}return"fumadocs"}function fr(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 yr(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function Ma(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 Sr(e){return e==="cn"?"wechat":"stripe"}async function Da(){let e=new Ta;e.name(sr).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ce,"-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 (default, primary) | drizzle (dual-ORM: adds db-drizzle alongside Prisma \u2014 Postgres only)").option("--db <id>","postgres | mysql | sqlite | none \u2014 engine (Prisma provider)").option("--db-host <id>","local | supabase | neon | vercel-postgres | planetscale | railway | aliyun-rds | tencent-cdb | none \u2014 managed-provider (region default: supabase global, local cn)").option("--auth <id>","clerk | betterauth | nextauth | 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 <mode-or-ids>","topology shorthand (gateway | direct | custom | none) OR comma-separated provider ids (e.g. openai,anthropic)").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 | 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("--cron-jobs <bool>","true | false \u2014 scaffold scheduled cron handlers (default: true)").option("--audit-log <bool>","true | false \u2014 enable /settings/audit-log + arch test (default: true)").option("--api-keys <bool>","true | false \u2014 enable /settings/api-keys page (default: true)").option("--command-palette <bool>","true | false \u2014 enable \u2318K command palette (default: true)").option("--cookie-consent <bool>","true | false \u2014 enable GDPR/CCPA cookie banner (default: true)").option("--legal-pages <bool>","true | false \u2014 enable dynamic /legal/[slug] route (default: true)").option("--china-compliance <bool>","true | false \u2014 enable @nebutra/china-compliance + ICP footer (default: true when --region=cn, otherwise false)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--with-workflows","scaffold workflows/ (inngest + n8n + pusher stubs)").option("--with-python-backend","scaffold backends/python/ (FastAPI stub \u2014 only when TS-by-Default ADR exception applies)").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&&(En(),process.exit(0));let n=!!t.json,r=!!t.dryRun,s=!!t.yes,i=s||!process.stdin.isTTY;if(n||yn(),p(n,{event:"start",version:ce}),!t.pm)try{Pt("pnpm --version",{stdio:"ignore"})}catch{n||process.stderr.write(`
2939
- ${C.red("\u2718")} ${C.bold("pnpm is required")} but was not found on PATH.
2949
+ `}async function fr(e,t){let{projectName:o,region:n,previewSelections:r=[],waveFeatures:s={}}=t;try{let i=wt.join(e,".sailor");Be.existsSync(i)||Be.mkdirSync(i,{recursive:!0}),Be.writeFileSync(wt.join(i,"next-steps.md"),Qa(o,n,r,s))}catch(i){let c=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${c}`)}try{let i=wt.join(e,"apps","web");if(!Be.existsSync(i))return;let c=wt.join(i,"src","app","[locale]","welcome");Be.existsSync(c)||Be.mkdirSync(c,{recursive:!0}),Be.writeFileSync(wt.join(c,"page.tsx"),Xa(o))}catch(i){let c=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write welcome page: ${c}`)}}var yr="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2950
+ `)}function tc(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function Sr(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 hr(e,t,o){let n=e?.trim().toLowerCase()??Gn(t),r=Kt(n);if(!r){let i=sn.map(c=>c.id).join(", ");throw new Error(`Unknown --db-host="${n}". Valid: ${i}`)}let s=o;return r.forcedEngine&&s!=="none"&&s!==r.forcedEngine&&(s=r.forcedEngine),{hostId:r.id,engine:s}}function Er(e){return e==="drizzle"?"drizzle":"prisma"}function vr(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function _r(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 br(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="nextauth"||t==="next-auth"||t==="authjs"||t==="auth.js"?"nextauth":t==="supabase"||t==="supabase-auth"?"supabase":t==="none"?"none":"clerk"}var nc=new Set(["gateway","direct","custom","none"]);function kr(e){if(!e)return!1;let t=e.trim().toLowerCase();return nc.has(t)}function Pr(e){if(!e)return["openai"];if(kr(e))return[];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}function oc(e,t){let o=e??t;return yn(o)??o}var Ar={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Cr(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in Ar){let n=Ar[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(A.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
2951
+ `)+A.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
2952
+ `)),"fumadocs"}return"fumadocs"}function Ir(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 wr(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function rc(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",accessGate:"none"}}function Rr(e){return e==="cn"?"wechat":"stripe"}async function sc(){let e=new Za;e.name(yr).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ae,"-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 (default, primary) | drizzle (dual-ORM: adds db-drizzle alongside Prisma \u2014 Postgres only)").option("--db <id>","postgres | mysql | sqlite | none \u2014 engine (Prisma provider)").option("--db-host <id>","local | supabase | neon | vercel-postgres | planetscale | railway | aliyun-rds | tencent-cdb | none \u2014 managed-provider (region default: supabase global, local cn)").option("--auth <id>","clerk | betterauth | nextauth | supabase | 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 <mode-or-ids>","topology shorthand (gateway | direct | custom | none) OR comma-separated provider ids (e.g. openai,anthropic)").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 | 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("--access-gate <mode>","none | invite (default: none)").option("--cron-jobs <bool>","true | false \u2014 scaffold scheduled cron handlers (default: true)").option("--audit-log <bool>","true | false \u2014 enable /settings/audit-log + arch test (default: true)").option("--api-keys <bool>","true | false \u2014 enable /settings/api-keys page (default: true)").option("--command-palette <bool>","true | false \u2014 enable \u2318K command palette (default: true)").option("--cookie-consent <bool>","true | false \u2014 enable GDPR/CCPA cookie banner (default: true)").option("--legal-pages <bool>","true | false \u2014 enable dynamic /legal/[slug] route (default: true)").option("--china-compliance <bool>","true | false \u2014 enable @nebutra/china-compliance + ICP footer (default: true when --region=cn, otherwise false)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--with-workflows","scaffold workflows/ (inngest + n8n + pusher stubs)").option("--with-python-backend","scaffold backends/python/ (FastAPI stub \u2014 only when TS-by-Default ADR exception applies)").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,s=!!t.yes,i=s||!process.stdin.isTTY;if(n||_n(),p(n,{event:"start",version:ae}),!t.pm)try{Rt("pnpm --version",{stdio:"ignore"})}catch{n||process.stderr.write(`
2953
+ ${A.red("\u2718")} ${A.bold("pnpm is required")} but was not found on PATH.
2940
2954
 
2941
2955
  The scaffold uses pnpm workspaces + Turborepo. Install pnpm first:
2942
- ${C.cyan("npm i -g pnpm@10")}
2943
-
2944
- Then retry: ${C.cyan("pnpm dlx create-sailor@latest")}
2945
- (or pass ${C.dim("--pm=npm")} if you know workspace:* won't resolve in your setup)
2946
-
2947
- `),p(n,{event:"error",code:"PNPM_MISSING"}),process.exit(1)}let c=o??(s?"./my-saas-app":void 0),a;if(c)a=c;else if(i)a="./my-saas-app";else{let g=await x.group({name:()=>x.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:h=>{if(h.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(C.red(`\u2718 Cancelled
2948
- `)),process.exit(130)}});a=String(g.name)}let l=Ct.basename(Ct.resolve(a)),m=t.pm??Oa(),S=!!t.region,T=!!t.auth,N=!!t.payment,D=!!t.ai,ae=!!t.email,_=!!t.storage,u=!!t.monitoring,U=!!t.analytics,At=!!t.sms,mn=t.i18n!==void 0,E,je,$,wt="local",pt,Y,F,X=Rn(t.socialLogin),lt,Gt,he,Ve,ne,q,It;if(i){E=yr(t.region),je=cr(t.orm);{let ve=ir(t.db),j=ar(t.dbHost,E,ve);$=j.engine,wt=j.hostId}let g=N?t.payment:Sr(E);pt=pr(g),Y=lr(g),F=dr(t.auth);let h="gateway";if(D){let ve=t.ai?.trim().toLowerCase()??"";hr(ve)?h=ve:h="direct"}let O=zt({mode:h,providerIds:D?ur(t.ai):void 0});lt=O.mode,Gt=O.routing,he=O.providerIds,ne=fr(t.deploy),q=gr(t.docs,n),It=mn?!!t.i18n:!0}else{let g={};S||(g.region=()=>x.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"})),T||(g.auth=()=>x.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk",hint:"managed, fastest setup"},{value:"betterauth",label:"Better Auth",hint:"self-hosted, modern (2FA / passkeys / RBAC)"},{value:"nextauth",label:"NextAuth (Auth.js v5)",hint:"self-hosted, mature, large ecosystem"},{value:"none",label:"None"}],initialValue:"clerk"})),D||(g.aiMode=()=>x.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"}),g.aiProviders=({results:y})=>{if(y.aiMode!=="direct")return Promise.resolve([]);let b=Xt.map(oe=>({value:oe.id,label:`[${oe.category}] ${oe.name}`}));return x.multiselect({message:"Select direct AI provider adapters (expert path)",options:b,initialValues:["openai"],required:!1})},g.customAiName=({results:y})=>y.aiMode==="custom"?x.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),g.customAiBaseUrl=({results:y})=>y.aiMode==="custom"?x.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:b=>{if(b.length===0)return"Base URL is required."}}):Promise.resolve(void 0),g.customAiApiKeyEnv=({results:y})=>y.aiMode==="custom"?x.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0));let h=Object.keys(g).length>0?await x.group(g,{onCancel:()=>{process.stdout.write(C.red(`\u2718 Cancelled
2949
- `)),process.exit(130)}}):{};E=yr(S?t.region:h.region),je=cr(t.orm);{let y=ir(t.db),b=ar(t.dbHost,E,y);$=b.engine,wt=b.hostId}let O=N?t.payment:Sr(E);pt=pr(O),Y=lr(O),F=dr(T?t.auth:h.auth);let ve=h.aiMode==="custom"?{name:h.customAiName??"custom",baseURL:h.customAiBaseUrl??"",apiKeyEnvName:h.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,j=zt({mode:D?t.ai?.trim().toLowerCase()==="none"?"none":"direct":h.aiMode??"gateway",providerIds:D?ur(t.ai):h.aiProviders,customEndpoint:ve});lt=j.mode,Gt=j.routing,he=j.providerIds,j.customEndpoint&&(Ve={name:j.customEndpoint.name,baseURL:j.customEndpoint.baseURL,apiKeyEnvName:j.customEndpoint.apiKeyEnvName}),ne=fr(t.deploy),q=gr(t.docs,n),It=mn?!!t.i18n:!0}let I=Ma(E),Be=ae?t.email:I.email,Ke=La(_?t.storage:void 0,I.storage),$e=u?t.monitoring:I.monitoring,Ye=U?t.analytics:I.analytics,qe=At?t.sms:I.sms,Ge=t.queue??I.queue,He=t.search??I.search,dt=t.cache??I.cache,We=t.notifications??I.notifications,Xe=t.webhooks??I.webhooks,ut=t.cms??I.cms,ze=t.featureFlags??I.featureFlags,Je=t.captcha??I.captcha,Rt=t.mcp??I.mcp,mt=t.metering??I.metering,Qe=t.billingMode??I.billingMode,Ze=t.idp??I.idp,A=tr({cronJobs:t.cronJobs,auditLog:t.auditLog,apiKeys:t.apiKeys,commandPalette:t.commandPalette,cookieConsent:t.cookieConsent,legalPages:t.legalPages,chinaCompliance:t.chinaCompliance},E),et=Sn([{flag:"queue",provider:Ge},{flag:"search",provider:He},{flag:"notifications",provider:We},{flag:"webhooks",provider:Xe},{flag:"feature-flags",provider:ze},{flag:"captcha",provider:Je}]);function Ht(){for(let g of et)if(n)p(!0,{event:"warn",step:g.flag,provider:g.provider,packageStatus:g.status,message:pe(g.status)});else{let h=tt(g.status);process.stdout.write(C.yellow(`\u26A0 ${g.flag}=${g.provider} ${h} \u2014 ${pe(g.status)}
2950
- `))}}let Ee={region:E,orm:je,database:$,payment:pt,aiMode:lt,aiRouting:Gt,aiProviders:he,customAiEndpoint:Ve,deployTarget:ne,docs:q,i18n:It,email:Be,storage:Ke,monitoring:$e,analytics:Ye,sms:qe,queue:Ge,search:He,cache:dt,notifications:We,webhooks:Xe,cms:ut,featureFlags:ze,captcha:Je,mcp:Rt,metering:mt,billingMode:Qe,idp:Ze,cronJobs:A.cronJobs,auditLog:A.auditLog,apiKeys:A.apiKeys,commandPalette:A.commandPalette,cookieConsent:A.cookieConsent,legalPages:A.legalPages,chinaCompliance:A.chinaCompliance},kt=[["Project name",l],["Region",E],["Auth",F],["Social login",X.length>0?X.map(g=>gt.find(h=>h.id===g)?.name??g).join(", "):"none"],["ORM",je],["Database",$],["Payment",Y],["AI topology",`${lt}${he.length>0?` (${he.join(", ")} seed)`:""}${Ve?" + custom endpoint":""}`],["Email",Be],["Storage",Ke],["Monitoring",$e],["Analytics",Ye],["SMS",qe],["Deploy Target",ne],["Docs Framework",q]];n?kt.forEach(([g,h],O)=>{p(!0,{event:"step",step:g,value:h,index:O+1,total:kt.length})}):kt.forEach(([g,h],O)=>{_n({index:O+1,total:kt.length,label:g,value:h})});let Er={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},gn=Date.now();if(r){let g=he.length,h=[`clone template \u2192 ${a}`,"write nebutra.config.json",`prune template (orm=${je}, i18n=${It})`,`region \u2192 ${E}`,`auth \u2192 ${F==="none"?"skip (remove packages/auth)":`configure ${F}`}`,...X.length>0?[`social-login \u2192 generate ${X.length} callback route${X.length===1?"":"s"} + SocialLoginButtons.tsx (${X.join(", ")})`]:[],`db \u2192 ${$==="none"?"skip (remove packages/db)":`configure Prisma for ${$}`}`,`payment \u2192 ${Y==="none"?"skip (remove packages/billing)":`configure ${Y}`}`,...q!=="none"?[`docs \u2192 scaffold apps/docs (${q==="fumadocs"?"fumadocs":`${q} \u2192 fumadocs fallback`})`]:[],...g>0||Ve?[`ai-providers \u2192 generate ${lt} registry seed + env (${g}${Ve?" + custom":""} provider${g===1&&!Ve?"":"s"})`]:[],...Be!=="none"?[`email \u2192 configure ${Be}`]:[],...Ke!=="none"?[`storage \u2192 configure ${Ke}`]:[],...$e!=="none"?[`monitoring \u2192 configure ${$e}`]:[],...Ye!=="none"?[`analytics \u2192 configure ${Ye}`]:[],...qe!=="none"?[`sms \u2192 configure ${qe}`]:[],...Ge!=="none"?[`queue \u2192 configure ${Ge}`]:[],...He!=="none"?[`search \u2192 configure ${He}`]:[],...dt!=="none"?[`cache \u2192 configure ${dt}`]:[],...We!=="none"?[`notifications \u2192 configure ${We}`]:[],...Xe!=="none"?[`webhooks \u2192 configure ${Xe}`]:[],...ut!=="none"?[`cms \u2192 configure ${ut}`]:[],...ze!=="none"?[`feature-flags \u2192 configure ${ze}`]:[],...Je!=="none"?[`captcha \u2192 configure ${Je}`]:[],`mcp \u2192 ${Rt==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${mt==="off"?"disabled":mt==="auto"?pt!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...Qe!=="usage"?[`billing-mode \u2192 ${Qe}`]:[],...Ze!=="clerk"?[`idp \u2192 ${Ze}`]:[],`cron-jobs \u2192 ${A.cronJobs?"enabled":"disabled"}`,`audit-log \u2192 ${A.auditLog?"enabled":"disabled"}`,`api-keys \u2192 ${A.apiKeys?"enabled":"disabled"}`,`command-palette \u2192 ${A.commandPalette?"enabled":"disabled"}`,`cookie-consent \u2192 ${A.cookieConsent?"enabled":"disabled"}`,`legal-pages \u2192 ${A.legalPages?"enabled":"disabled"}`,`china-compliance \u2192 ${A.chinaCompliance?"enabled (@nebutra/china-compliance + ICP footer)":"disabled"}`,`compliance \u2192 inject ${E} 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)",...ne!=="none"?[`deploy \u2192 inject ${ne} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${m} install`,t.git===!1?"skip git init":"run git init"];if(n){for(let O of h)p(!0,{event:"plan",action:O});Ht(),p(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
2951
- `+C.bold(`Dry run \u2014 planned actions:
2952
- `));for(let O of h)process.stdout.write(` \u2022 ${O}
2953
- `);et.length>0&&(process.stdout.write(`
2954
- `+C.bold(C.yellow(`Preview-status providers selected:
2955
- `))),Ht()),process.stdout.write(C.dim(`
2956
+ ${A.cyan("npm i -g pnpm@10")}
2957
+
2958
+ Then retry: ${A.cyan("pnpm dlx create-sailor@latest")}
2959
+ (or pass ${A.dim("--pm=npm")} if you know workspace:* won't resolve in your setup)
2960
+
2961
+ `),p(n,{event:"error",code:"PNPM_MISSING"}),process.exit(1)}let c=o??(s?"./my-saas-app":void 0),a;if(c)a=c;else if(i)a="./my-saas-app";else{let g=await O.group({name:()=>O.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:h=>{if(h.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(A.red(`\u2718 Cancelled
2962
+ `)),process.exit(130)}});a=String(g.name)}let l=de.basename(de.resolve(a)),d=t.pm??tc(),S=!!t.region,C=!!t.auth,k=!!t.payment,$=!!t.ai,ue=!!t.email,b=!!t.storage,m=!!t.monitoring,U=!!t.analytics,kt=!!t.sms,hn=t.i18n!==void 0,E,Ke,G,xt="local",mt,H,F,Q=On(t.socialLogin),gt,Qt,be,$e,ie,W,Nt;if(i){E=wr(t.region),Ke=Er(t.orm);{let Ae=Sr(t.db),j=hr(t.dbHost,E,Ae);G=j.engine,xt=j.hostId}let g=k?t.payment:Rr(E);mt=vr(g),H=_r(g),F=br(t.auth);let h="gateway";if($){let Ae=t.ai?.trim().toLowerCase()??"";kr(Ae)?h=Ae:h="direct"}let L=nn({mode:h,providerIds:$?Pr(t.ai):void 0});gt=L.mode,Qt=L.routing,be=L.providerIds,ie=Ir(t.deploy),W=Cr(t.docs,n),Nt=hn?!!t.i18n:!0}else{let g={};S||(g.region=()=>O.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"})),C||(g.auth=()=>O.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk",hint:"managed, fastest setup"},{value:"betterauth",label:"Better Auth",hint:"self-hosted, modern (2FA / passkeys / RBAC)"},{value:"nextauth",label:"NextAuth (Auth.js v5)",hint:"self-hosted, mature, large ecosystem"},{value:"supabase",label:"Supabase Auth",hint:"managed auth with Supabase storage/realtime ecosystem"},{value:"none",label:"None"}],initialValue:"clerk"})),$||(g.aiMode=()=>O.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"}),g.aiProviders=({results:f})=>{if(f.aiMode!=="direct")return Promise.resolve([]);let _=tn.map(Y=>({value:Y.id,label:`[${Y.category}] ${Y.name}`}));return O.multiselect({message:"Select direct AI provider adapters (expert path)",options:_,initialValues:["openai"],required:!1})},g.customAiName=({results:f})=>f.aiMode==="custom"?O.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),g.customAiBaseUrl=({results:f})=>f.aiMode==="custom"?O.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:_=>{if(_.length===0)return"Base URL is required."}}):Promise.resolve(void 0),g.customAiApiKeyEnv=({results:f})=>f.aiMode==="custom"?O.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0));let h=Object.keys(g).length>0?await O.group(g,{onCancel:()=>{process.stdout.write(A.red(`\u2718 Cancelled
2963
+ `)),process.exit(130)}}):{};E=wr(S?t.region:h.region),Ke=Er(t.orm);{let f=Sr(t.db),_=hr(t.dbHost,E,f);G=_.engine,xt=_.hostId}let L=k?t.payment:Rr(E);mt=vr(L),H=_r(L),F=br(C?t.auth:h.auth);let Ae=h.aiMode==="custom"?{name:h.customAiName??"custom",baseURL:h.customAiBaseUrl??"",apiKeyEnvName:h.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,j=nn({mode:$?t.ai?.trim().toLowerCase()==="none"?"none":"direct":h.aiMode??"gateway",providerIds:$?Pr(t.ai):h.aiProviders,customEndpoint:Ae});gt=j.mode,Qt=j.routing,be=j.providerIds,j.customEndpoint&&($e={name:j.customEndpoint.name,baseURL:j.customEndpoint.baseURL,apiKeyEnvName:j.customEndpoint.apiKeyEnvName}),ie=Ir(t.deploy),W=Cr(t.docs,n),Nt=hn?!!t.i18n:!0}let R=rc(E),Ye=ue?t.email:R.email,qe=oc(b?t.storage:void 0,R.storage),Ge=m?t.monitoring:R.monitoring,He=U?t.analytics:R.analytics,We=kt?t.sms:R.sms,Xe=t.queue??R.queue,ze=t.search??R.search,ft=t.cache??R.cache,Je=t.notifications??R.notifications,Qe=t.webhooks??R.webhooks,yt=t.cms??R.cms,Ze=t.featureFlags??R.featureFlags,et=t.captcha??R.captcha,Tt=t.mcp??R.mcp,St=t.metering??R.metering,tt=t.billingMode??R.billingMode,nt=t.idp??R.idp,ht=t.accessGate==="invite"?"invite":R.accessGate,I=ur({cronJobs:t.cronJobs,auditLog:t.auditLog,apiKeys:t.apiKeys,commandPalette:t.commandPalette,cookieConsent:t.cookieConsent,legalPages:t.legalPages,chinaCompliance:t.chinaCompliance},E),ot=bn([{flag:"queue",provider:Xe},{flag:"search",provider:ze},{flag:"notifications",provider:Je},{flag:"webhooks",provider:Qe},{flag:"feature-flags",provider:Ze},{flag:"captcha",provider:et},{flag:"access-gate",provider:ht}]);function Zt(){for(let g of ot)if(n)p(!0,{event:"warn",step:g.flag,provider:g.provider,packageStatus:g.status,message:me(g.status)});else{let h=rt(g.status);process.stdout.write(A.yellow(`\u26A0 ${g.flag}=${g.provider} ${h} \u2014 ${me(g.status)}
2964
+ `))}}let Pe={region:E,orm:Ke,database:G,payment:mt,aiMode:gt,aiRouting:Qt,aiProviders:be,customAiEndpoint:$e,deployTarget:ie,docs:W,i18n:Nt,email:Ye,storage:qe,monitoring:Ge,analytics:He,sms:We,queue:Xe,search:ze,cache:ft,notifications:Je,webhooks:Qe,cms:yt,featureFlags:Ze,captcha:et,mcp:Tt,metering:St,billingMode:tt,idp:nt,accessGate:ht,cronJobs:I.cronJobs,auditLog:I.auditLog,apiKeys:I.apiKeys,commandPalette:I.commandPalette,cookieConsent:I.cookieConsent,legalPages:I.legalPages,chinaCompliance:I.chinaCompliance},Ot=[["Project name",l],["Region",E],["Auth",F],["Social login",Q.length>0?Q.map(g=>Et.find(h=>h.id===g)?.name??g).join(", "):"none"],["ORM",Ke],["Database",G],["Payment",H],["AI topology",`${gt}${be.length>0?` (${be.join(", ")} seed)`:""}${$e?" + custom endpoint":""}`],["Email",Ye],["Storage",qe],["Monitoring",Ge],["Analytics",He],["SMS",We],["Deploy Target",ie],["Docs Framework",W],["Access gate",ht]];n?Ot.forEach(([g,h],L)=>{p(!0,{event:"step",step:g,value:h,index:L+1,total:Ot.length})}):Ot.forEach(([g,h],L)=>{In({index:L+1,total:Ot.length,label:g,value:h})});let xr={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},En=Date.now();if(r){let g=be.length,h=[`clone template \u2192 ${a}`,"write nebutra.config.json",`prune template (orm=${Ke}, i18n=${Nt})`,`region \u2192 ${E}`,`auth \u2192 ${F==="none"?"skip (remove packages/auth)":`configure ${F}`}`,...Q.length>0?[`social-login \u2192 generate ${Q.length} callback route${Q.length===1?"":"s"} + SocialLoginButtons.tsx (${Q.join(", ")})`]:[],`db \u2192 ${G==="none"?"skip (remove packages/db)":`configure Prisma for ${G}`}`,`payment \u2192 ${H==="none"?"skip (remove packages/billing)":`configure ${H}`}`,...W!=="none"?[`docs \u2192 scaffold apps/docs (${W==="fumadocs"?"fumadocs":`${W} \u2192 fumadocs fallback`})`]:[],...g>0||$e?[`ai-providers \u2192 generate ${gt} registry seed + env (${g}${$e?" + custom":""} provider${g===1&&!$e?"":"s"})`]:[],...Ye!=="none"?[`email \u2192 configure ${Ye}`]:[],...qe!=="none"?[`storage \u2192 configure ${qe}`]:[],...Ge!=="none"?[`monitoring \u2192 configure ${Ge}`]:[],...He!=="none"?[`analytics \u2192 configure ${He}`]:[],...We!=="none"?[`sms \u2192 configure ${We}`]:[],...Xe!=="none"?[`queue \u2192 configure ${Xe}`]:[],...ze!=="none"?[`search \u2192 configure ${ze}`]:[],...ft!=="none"?[`cache \u2192 configure ${ft}`]:[],...Je!=="none"?[`notifications \u2192 configure ${Je}`]:[],...Qe!=="none"?[`webhooks \u2192 configure ${Qe}`]:[],...yt!=="none"?[`cms \u2192 configure ${yt}`]:[],...Ze!=="none"?[`feature-flags \u2192 configure ${Ze}`]:[],...et!=="none"?[`captcha \u2192 configure ${et}`]:[],`mcp \u2192 ${Tt==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${St==="off"?"disabled":St==="auto"?mt!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...tt!=="usage"?[`billing-mode \u2192 ${tt}`]:[],...nt!=="clerk"?[`idp \u2192 ${nt}`]:[],`cron-jobs \u2192 ${I.cronJobs?"enabled":"disabled"}`,`audit-log \u2192 ${I.auditLog?"enabled":"disabled"}`,`api-keys \u2192 ${I.apiKeys?"enabled":"disabled"}`,`command-palette \u2192 ${I.commandPalette?"enabled":"disabled"}`,`cookie-consent \u2192 ${I.cookieConsent?"enabled":"disabled"}`,`legal-pages \u2192 ${I.legalPages?"enabled":"disabled"}`,`china-compliance \u2192 ${I.chinaCompliance?"enabled (@nebutra/china-compliance + ICP footer)":"disabled"}`,`compliance \u2192 inject ${E} 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)",...ie!=="none"?[`deploy \u2192 inject ${ie} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${d} install`,t.git===!1?"skip git init":"run git init"];if(n){for(let L of h)p(!0,{event:"plan",action:L});Zt(),p(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
2965
+ `+A.bold(`Dry run \u2014 planned actions:
2966
+ `));for(let L of h)process.stdout.write(` \u2022 ${L}
2967
+ `);ot.length>0&&(process.stdout.write(`
2968
+ `+A.bold(A.yellow(`Preview-status providers selected:
2969
+ `))),Zt()),process.stdout.write(A.dim(`
2956
2970
  No files were written.
2957
- `))}process.exit(0)}let vr=async()=>{process.stdout.write(`
2958
- `+C.red(`\u2718 Cancelled
2959
- `)),Se.existsSync(a)&&await x.confirm({message:`Cleanup partial install at ${a}?`,initialValue:!0})===!0&&(Se.rmSync(a,{recursive:!0,force:!0}),process.stdout.write(C.dim(` \u2713 Removed ${a}
2960
- `))),process.exit(130)};process.on("SIGINT",vr);try{p(n,{event:"step",step:"clone",status:"start"}),await fo(a),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await Co(a,l),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await Vn(a,Ee),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await Mo(a,Ee),p(n,{event:"step",step:"prune",status:"ok"});let g=Ct.join(a,"packages/platform/db/prisma/schema.prisma");if(Se.existsSync(g)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let y=Se.readFileSync(g,"utf-8"),b=pn(y,{auth:F,payment:Y,"billing-mode":Qe,idp:Ze,template:"saas"});Se.writeFileSync(g,b),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(y){let b=y instanceof Error?y.message:String(y);p(n,{event:"step",step:"schema-prune",status:"error",error:b})}}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"auth",choice:F,status:"start"}),await wn(a,F),p(n,{event:"step",step:"auth",choice:F,status:"ok"}),X.length>0?(p(n,{event:"step",step:"social-login",providers:X,status:"start"}),await xn(a,X,F),p(n,{event:"step",step:"social-login",providers:X,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:$,status:"start"}),await Yn(a,$,l),$!=="none"){let y=Mt(wt);y&&(await qn(a,y,l),p(n,{event:"step",step:"db-host",choice:wt,status:"ok"}))}if(p(n,{event:"step",step:"db",choice:$,status:"ok"}),je==="drizzle"){p(n,{event:"step",step:"orm",choice:"drizzle",status:"start"});let y=await Io(a,"drizzle",$);p(n,{event:"step",step:"orm",choice:"drizzle",status:y.applied?"ok":"skip",...y.reason?{reason:y.reason}:{}})}if(p(n,{event:"step",step:"payment",choice:Y,status:"start"}),await ko(a,Y),p(n,{event:"step",step:"payment",choice:Y,status:"ok"}),await eo(a,Be,E),n&&p(!0,{event:"step",step:"email",choice:Be,status:"ok"}),await er(a,Ke,E),n&&p(!0,{event:"step",step:"storage",choice:Ke,status:"ok"}),await _o(a,$e,E),n&&p(!0,{event:"step",step:"monitoring",choice:$e,status:"ok"}),await Cn(a,Ye,E),n&&p(!0,{event:"step",step:"analytics",choice:Ye,status:"ok"}),await Qo(a,qe,E),n&&p(!0,{event:"step",step:"sms",choice:qe,status:"ok"}),await Bo(a,Ge,E),n&&p(!0,{event:"step",step:"queue",choice:Ge,status:"ok"}),await Xo(a,He,E),n&&p(!0,{event:"step",step:"search",choice:He,status:"ok"}),await Un(a,dt,E),n&&p(!0,{event:"step",step:"cache",choice:dt,status:"ok"}),await Po(a,We,E),n&&p(!0,{event:"step",step:"notifications",choice:We,status:"ok"}),await or(a,Xe,E),n&&p(!0,{event:"step",step:"webhooks",choice:Xe,status:"ok"}),await Fn(a,ut,E),n&&p(!0,{event:"step",step:"cms",choice:ut,status:"ok"}),await ao(a,ze,E),n&&p(!0,{event:"step",step:"feature-flags",choice:ze,status:"ok"}),await Mn(a,Je,E),n&&p(!0,{event:"step",step:"captcha",choice:Je,status:"ok"}),await yo(a,Rt),n&&p(!0,{event:"step",step:"mcp",mode:Rt,status:"ok"}),await ho(a,mt,pt),n&&p(!0,{event:"step",step:"metering",mode:mt,status:"ok"}),p(n,{event:"step",step:"prune-wave-features",status:"start"}),Do(a,A),p(n,{event:"step",step:"prune-wave-features",status:"ok",toggles:A}),Ee.orm==="prisma"&&Ee.database!=="none"){let y=Ct.join(a,"packages/platform/db/prisma/schema.prisma");if(Se.existsSync(y)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let b=Se.readFileSync(y,"utf8"),oe=pn(b,{auth:F,payment:Y,"billing-mode":Qe,idp:Ze,template:"saas"});Se.writeFileSync(y,oe),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(b){let oe=b instanceof Error?b.message:String(b);p(n,{event:"step",step:"schema-prune",status:"error",error:oe})}}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:Qe,status:"ok"}),p(n,{event:"step",step:"idp",choice:Ze,status:"ok"}),await jn(a,E),n&&p(!0,{event:"step",step:"compliance",region:E,status:"ok"}),await so(a),await zo(a,F),await rr(a,{projectName:l,region:E,previewSelections:et,waveFeatures:A}),Ee.aiMode!=="none"){p(n,{event:"step",step:"ai-providers",status:"start"});let y={providerIds:Ee.aiProviders,customEndpoint:Ee.customAiEndpoint},b=Ct.join(a,"packages/ai/ai-providers/templates");await Uo(a,y,b),p(n,{event:"step",step:"ai-providers",status:"ok"})}else p(n,{event:"step",step:"ai-providers",status:"skip"});p(n,{event:"step",step:"docs",status:"start"}),q!=="none"?(await zn(a,{framework:q,projectName:l}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:q,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),ne!=="none"&&await Hn(a,ne),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await no(a,Er),p(n,{event:"step",step:"env",status:"ok"}),p(n,{event:"step",step:"scaffold-extras",status:"start"});let h=await $o(a,{projectName:l,withWorkflows:!!t.withWorkflows,withPythonBackend:!!t.withPythonBackend});if(p(n,{event:"step",step:"scaffold-extras",status:"ok",applied:h.applied,skipped:h.skipped}),t.install!==!1){let y=m==="bun"?"bun install":`${m} install`;n?p(!0,{event:"step",step:"install",pm:m,status:"start"}):process.stdout.write(C.dim(` Installing dependencies with ${m}\u2026
2961
- `));try{Pt(y,{cwd:a,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(b){let oe=b instanceof Error?b.message:String(b);n?p(!0,{event:"step",step:"install",status:"error",error:oe}):process.stdout.write(C.yellow(` \u26A0 install failed \u2014 run '${y}' manually.
2962
- `))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{Pt("git init -q",{cwd:a,stdio:"ignore"}),Pt("git add -A",{cwd:a,stdio:"ignore"}),Pt('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(y){let b=y instanceof Error?y.message:String(y);n?p(!0,{event:"step",step:"git-init",status:"error",error:b}):process.stdout.write(C.yellow(` \u26A0 git init skipped \u2014 not fatal.
2963
- `))}}else p(n,{event:"step",step:"git-init",status:"skip"});let j=Math.max(1,Math.round((Date.now()-gn)/1e3));An({template_version:ce,package_manager:m,region:E,auth:F,payment:Y,ai_providers:he,deploy_target:ne,duration_ms:Date.now()-gn}),et.length>0&&Ht(),n?p(!0,{event:"done",status:"ok",elapsedSec:j,targetDir:a,previewSelections:et,waveFeatures:A}):hn({elapsedSec:j,targetDir:a,skippedInstall:t.install===!1,previewSelections:et,waveFeatures:A});try{Na({pkg:{name:sr,version:ce},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(g){let h=g instanceof Error?g.message:String(g);n?p(!0,{event:"error",message:h}):process.stdout.write(C.red(`
2971
+ `))}process.exit(0)}let Nr=async()=>{process.stdout.write(`
2972
+ `+A.red(`\u2718 Cancelled
2973
+ `)),_e.existsSync(a)&&await O.confirm({message:`Cleanup partial install at ${a}?`,initialValue:!0})===!0&&(_e.rmSync(a,{recursive:!0,force:!0}),process.stdout.write(A.dim(` \u2713 Removed ${a}
2974
+ `))),process.exit(130)};process.on("SIGINT",Nr);try{p(n,{event:"step",step:"clone",status:"start"}),await vo(a),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await Oo(a,l),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await qn(a,Pe),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await qo(a,Pe),p(n,{event:"step",step:"prune",status:"ok"});let g=de.join(a,"packages/platform/db/prisma/schema.prisma");if(_e.existsSync(g)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let f=_e.readFileSync(g,"utf-8"),_={auth:F,payment:H,"billing-mode":tt,idp:nt,template:"saas","access-gate":ht},Y=gn(f,_);_e.writeFileSync(g,Y),mn(de.join(de.dirname(g),"migrations"),_),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(f){let _=f instanceof Error?f.message:String(f);p(n,{event:"step",step:"schema-prune",status:"error",error:_})}}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"auth",choice:F,status:"start"}),await Nn(a,F),p(n,{event:"step",step:"auth",choice:F,status:"ok"}),Q.length>0?(p(n,{event:"step",step:"social-login",providers:Q,status:"start"}),await Un(a,Q,F),p(n,{event:"step",step:"social-login",providers:Q,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:G,status:"start"}),await Xn(a,G,l),G!=="none"){let f=Kt(xt);f&&(await zn(a,f,l),p(n,{event:"step",step:"db-host",choice:xt,status:"ok"}))}if(p(n,{event:"step",step:"db",choice:G,status:"ok"}),Ke==="drizzle"){p(n,{event:"step",step:"orm",choice:"drizzle",status:"start"});let f=await Mo(a,"drizzle",G);p(n,{event:"step",step:"orm",choice:"drizzle",status:f.applied?"ok":"skip",...f.reason?{reason:f.reason}:{}})}if(p(n,{event:"step",step:"payment",choice:H,status:"start"}),await Fo(a,H),p(n,{event:"step",step:"payment",choice:H,status:"ok"}),await so(a,Ye,E),n&&p(!0,{event:"step",step:"email",choice:Ye,status:"ok"}),await dr(a,qe,E),n&&p(!0,{event:"step",step:"storage",choice:qe,status:"ok"}),await xo(a,Ge,E),n&&p(!0,{event:"step",step:"monitoring",choice:Ge,status:"ok"}),await kn(a,He,E),n&&p(!0,{event:"step",step:"analytics",choice:He,status:"ok"}),await pr(a,We,E),n&&p(!0,{event:"step",step:"sms",choice:We,status:"ok"}),await Qo(a,Xe,E),n&&p(!0,{event:"step",step:"queue",choice:Xe,status:"ok"}),await ir(a,ze,E),n&&p(!0,{event:"step",step:"search",choice:ze,status:"ok"}),await jn(a,ft,E),n&&p(!0,{event:"step",step:"cache",choice:ft,status:"ok"}),await To(a,Je,E),n&&p(!0,{event:"step",step:"notifications",choice:Je,status:"ok"}),await gr(a,Qe,E),n&&p(!0,{event:"step",step:"webhooks",choice:Qe,status:"ok"}),await $n(a,yt,E),n&&p(!0,{event:"step",step:"cms",choice:yt,status:"ok"}),await mo(a,Ze,E),n&&p(!0,{event:"step",step:"feature-flags",choice:Ze,status:"ok"}),await Bn(a,et,E),n&&p(!0,{event:"step",step:"captcha",choice:et,status:"ok"}),await Co(a,Tt),n&&p(!0,{event:"step",step:"mcp",mode:Tt,status:"ok"}),await wo(a,St,mt),n&&p(!0,{event:"step",step:"metering",mode:St,status:"ok"}),p(n,{event:"step",step:"prune-wave-features",status:"start"}),Go(a,I),p(n,{event:"step",step:"prune-wave-features",status:"ok",toggles:I}),Pe.orm==="prisma"&&Pe.database!=="none"){let f=de.join(a,"packages/platform/db/prisma/schema.prisma");if(_e.existsSync(f)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let _=_e.readFileSync(f,"utf8"),Y={auth:F,payment:H,"billing-mode":tt,idp:nt,template:"saas","access-gate":ht},Tr=gn(_,Y);_e.writeFileSync(f,Tr),mn(de.join(de.dirname(f),"migrations"),Y),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(_){let Y=_ instanceof Error?_.message:String(_);p(n,{event:"step",step:"schema-prune",status:"error",error:Y})}}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:tt,status:"ok"}),p(n,{event:"step",step:"idp",choice:nt,status:"ok"}),await Yn(a,E),n&&p(!0,{event:"step",step:"compliance",region:E,status:"ok"}),await lo(a),await ar(a,F),await fr(a,{projectName:l,region:E,previewSelections:ot,waveFeatures:I}),Pe.aiMode!=="none"){p(n,{event:"step",step:"ai-providers",status:"start"});let f={providerIds:Pe.aiProviders,customEndpoint:Pe.customAiEndpoint},_=de.join(a,"packages/ai/ai-providers/templates");await $o(a,f,_),p(n,{event:"step",step:"ai-providers",status:"ok"})}else p(n,{event:"step",step:"ai-providers",status:"skip"});p(n,{event:"step",step:"docs",status:"start"}),W!=="none"?(await to(a,{framework:W,projectName:l}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:W,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),ie!=="none"&&await Qn(a,ie),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await ao(a,xr),p(n,{event:"step",step:"env",status:"ok"}),p(n,{event:"step",step:"scaffold-extras",status:"start"});let h=await er(a,{projectName:l,withWorkflows:!!t.withWorkflows,withPythonBackend:!!t.withPythonBackend});p(n,{event:"step",step:"scaffold-extras",status:"ok",applied:h.applied,skipped:h.skipped}),p(n,{event:"step",step:"license",status:"start"});try{let f=Ao(a,{projectName:l,cliVersion:ae});p(n,{event:"step",step:"license",status:"ok",tier:"independent",wrote:f.wrote}),n||process.stdout.write(A.dim(` License: Nebutra-Sailor Independent Developer License (free for \u2264 1 FTE, < $1M ARR).
2975
+ Upstream AGPL preserved as LICENSE-AGPL-REFERENCE.md.
2976
+ `))}catch(f){p(n,{event:"step",step:"license",status:"warn",message:f instanceof Error?f.message:String(f)})}if(t.install!==!1){let f=d==="bun"?"bun install":`${d} install`;n?p(!0,{event:"step",step:"install",pm:d,status:"start"}):process.stdout.write(A.dim(` Installing dependencies with ${d}\u2026
2977
+ `));try{Rt(f,{cwd:a,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(_){let Y=_ instanceof Error?_.message:String(_);n?p(!0,{event:"step",step:"install",status:"error",error:Y}):process.stdout.write(A.yellow(` \u26A0 install failed \u2014 run '${f}' manually.
2978
+ `))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{Rt("git init -q",{cwd:a,stdio:"ignore"}),Rt("git add -A",{cwd:a,stdio:"ignore"}),Rt('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(f){let _=f instanceof Error?f.message:String(f);n?p(!0,{event:"step",step:"git-init",status:"error",error:_}):process.stdout.write(A.yellow(` \u26A0 git init skipped \u2014 not fatal.
2979
+ `))}}else p(n,{event:"step",step:"git-init",status:"skip"});let j=Math.max(1,Math.round((Date.now()-En)/1e3));xn({template_version:ae,package_manager:d,region:E,auth:F,payment:H,ai_providers:be,deploy_target:ie,duration_ms:Date.now()-En}),ot.length>0&&Zt(),n?p(!0,{event:"done",status:"ok",elapsedSec:j,targetDir:a,previewSelections:ot,waveFeatures:I}):Pn({elapsedSec:j,targetDir:a,skippedInstall:t.install===!1,previewSelections:ot,waveFeatures:I});try{ec({pkg:{name:yr,version:ae},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(g){let h=g instanceof Error?g.message:String(g);n?p(!0,{event:"error",message:h}):process.stdout.write(A.red(`
2964
2980
  \u2718 Failed: ${h}
2965
- `)),process.exit(1)}}Da().catch(e=>{process.stderr.write(String(e)+`
2981
+ `)),process.exit(1)}}sc().catch(e=>{process.stderr.write(String(e)+`
2966
2982
  `),process.exit(1)});