create-sailor 1.3.3 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +33 -36
  2. package/dist/aws-kms-ZX6CTY62.js +1 -0
  3. package/dist/chunk-4NVBWJ2Q.js +1 -0
  4. package/dist/chunk-7DCGNQSQ.js +5 -0
  5. package/dist/chunk-7HOF72FC.js +1 -0
  6. package/dist/chunk-7VJYOZUP.js +2 -0
  7. package/dist/chunk-A2KGYHAM.js +1 -0
  8. package/dist/chunk-A75AMTOI.js +1 -0
  9. package/dist/chunk-B5RLHF2U.js +40 -0
  10. package/dist/chunk-DIXI4M5O.js +1 -0
  11. package/dist/chunk-EXLRPVEX.js +1 -0
  12. package/dist/chunk-FGJ5K4WM.js +1 -0
  13. package/dist/chunk-FSRPMVAS.js +1 -0
  14. package/dist/chunk-J7NVVT5I.js +20 -0
  15. package/dist/chunk-LDOHSEAR.js +9 -0
  16. package/dist/chunk-NK255JZN.js +1 -0
  17. package/dist/chunk-OJM5Y4UT.js +1 -0
  18. package/dist/chunk-PXU2OOBT.js +1 -0
  19. package/dist/chunk-QEIMNOY2.js +1 -0
  20. package/dist/chunk-QMKVUKS6.js +1 -0
  21. package/dist/chunk-RR5R4AKJ.js +1 -0
  22. package/dist/chunk-SDX64WW4.js +23 -0
  23. package/dist/chunk-XSSPJU77.js +1 -0
  24. package/dist/chunk-YR32FZAX.js +1 -0
  25. package/dist/credits-6AUSU6X6.js +1787 -0
  26. package/dist/dist-B4YTE2SQ.js +5 -0
  27. package/dist/dist-es-4EORLV5B.js +1 -0
  28. package/dist/dist-es-7IMKW7US.js +1 -0
  29. package/dist/dist-es-FJUQ4DBK.js +2 -0
  30. package/dist/dist-es-GP7DK3S3.js +5 -0
  31. package/dist/dist-es-JXNWCJHW.js +1 -0
  32. package/dist/dist-es-YKXA2GQ2.js +1 -0
  33. package/dist/dist-es-ZA2NRM7G.js +2 -0
  34. package/dist/event-streams-T5RU6C4N.js +1 -0
  35. package/dist/index.js +164 -157
  36. package/dist/loadSso-YQ73JVR6.js +1 -0
  37. package/dist/local-WW37QOXE.js +1 -0
  38. package/dist/query_compiler_fast_bg.postgresql-PN2AWLCP.js +2 -0
  39. package/dist/query_compiler_fast_bg.postgresql.wasm-base64-CASS54LO.js +1 -0
  40. package/dist/signin-LD4OP44K.js +1 -0
  41. package/dist/src-MVDQLN5F.js +1 -0
  42. package/dist/sso-oidc-4BAF7BYK.js +1 -0
  43. package/dist/sts-3V5Q4UTA.js +6 -0
  44. package/package.json +25 -26
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import{execSync as Ot}from"child_process";import ue from"fs";import dt from"path";import*as C from"@clack/prompts";import{Command as Mi}from"commander";import R from"picocolors";import Di from"update-notifier";import Go from"cfonts";import Ho from"picocolors";import Zt from"fs";import Lt from"path";import{fileURLToPath as $o}from"url";function qo(){try{let t=Lt.dirname($o(import.meta.url));for(let o=0;o<4;o++){let n=Lt.join(t,"package.json");if(Zt.existsSync(n)){let r=Zt.readFileSync(n,"utf-8"),s=JSON.parse(r);if(s.name==="create-sailor"&&typeof s.version=="string")return s.version}t=Lt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ne=qo();function en(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ne}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
3
- `));return}Go.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(Ho.dim(` AI-Native SaaS Template \xB7 v${ne} \xB7 nebutra.com
2
+ import"./chunk-FSRPMVAS.js";import{execSync as kt}from"child_process";import le from"fs";import dt from"path";import*as C from"@clack/prompts";import{Command as Ks}from"commander";import w from"picocolors";import Bs from"update-notifier";import Xo from"cfonts";import zo from"picocolors";import nn from"fs";import Lt from"path";import{fileURLToPath as Ho}from"url";function Wo(){try{let t=Lt.dirname(Ho(import.meta.url));for(let o=0;o<4;o++){let n=Lt.join(t,"package.json");if(nn.existsSync(n)){let r=nn.readFileSync(n,"utf-8"),i=JSON.parse(r);if(i.name==="create-sailor"&&typeof i.version=="string")return i.version}t=Lt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ee=Wo();function on(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ee}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
3
+ `));return}Xo.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(zo.dim(` AI-Native SaaS Template \xB7 v${ee} \xB7 nebutra.com
4
4
 
5
- `))}import E from"picocolors";var Wo={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 Xo(e){return e?Wo[e]??"stable":"stable"}function St(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function qe(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 tn(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=Xo(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function zo(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function nn(e){let t=zo(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",s=t?"\u{1F4E7}":"*",c=["",` ${t?E.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?E.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?E.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?E.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?E.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?E.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?E.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?E.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?E.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?E.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?E.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?E.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?E.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?E.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`);let i=e.previewSelections??[];if(i.length>0){let d=t?E.bold(E.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${d}`);for(let u of i){let S=St(u.status),U=` ${n} ${u.flag} (${u.provider}) ${S}`;c.push(t?E.yellow(U):U)}c.push("",` ${t?E.dim(qe("foundation")):qe("foundation")}`,` ${t?E.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?E.dim("See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"):"See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"}`)}c.push("",` ${t?E.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 _ from"picocolors";var Qo={qstash:"foundation",bullmq:"foundation",upstash:"foundation",sqs:"foundation",meilisearch:"foundation",typesense:"foundation",algolia:"foundation",pgvector:"foundation",novu:"foundation",knock:"foundation",svix:"foundation","vercel-flags":"wip",growthbook:"wip",configcat:"wip",turnstile:"wip",hcaptcha:"wip","aliyun-slide":"wip"};function Jo(e){return e?Qo[e]??"stable":"stable"}function St(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function Ye(e){switch(e){case"stable":return"Production-ready.";case"foundation":return"Foundation status \u2014 types + factory are complete, but provider adapters are stub-level and require external credentials.";case"wip":return"WIP \u2014 actively being built, should not be used in production.";case"deprecated":return"Deprecated \u2014 scheduled for removal, do not use."}}function rn(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=Jo(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function Zo(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function sn(e){let t=Zo(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",i=t?"\u{1F4E7}":"*",c=["",` ${t?_.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?_.bold("Next:"):"Next:"}`,` ${n} cd ${e.targetDir}`];e.skippedInstall&&c.push(` ${n} pnpm install (if --no-install was set)`),c.push(` ${n} fill in .env.local ${t?_.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?_.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?_.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?_.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?_.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?_.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?_.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?_.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?_.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?_.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?_.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?_.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`);let s=e.previewSelections??[];if(s.length>0){let d=t?_.bold(_.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${d}`);for(let u of s){let h=St(u.status),O=` ${n} ${u.flag} (${u.provider}) ${h}`;c.push(t?_.yellow(O):O)}c.push("",` ${t?_.dim(Ye("foundation")):Ye("foundation")}`,` ${t?_.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?_.dim("See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"):"See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"}`)}c.push("",` ${t?_.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${i} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
6
6
  `)+`
7
- `)}var Qo=`Usage: create-sailor [name] [options]
7
+ `)}var er=`Usage: create-sailor [name] [options]
8
8
 
9
9
  Arguments:
10
10
  name project directory (default: ./my-saas-app)
@@ -13,7 +13,14 @@ Core options:
13
13
  -p, --pm <id> npm | pnpm | yarn | bun (auto-detected)
14
14
  --region <id> global | cn | hybrid (default: global)
15
15
  --auth <id> clerk | betterauth | none
16
- --ai <ids> comma-separated provider ids (e.g. openai,anthropic)
16
+ --ai <ids> expert/non-interactive provider seed (e.g. openai,anthropic)
17
+
18
+ Interactive AI topology:
19
+ Default first-run asks for topology, not individual provider enablement:
20
+ gateway Multi-provider AI Gateway / router (recommended)
21
+ direct Direct SDK/provider adapters
22
+ custom OpenAI-compatible endpoint
23
+ none Skip AI
17
24
 
18
25
  Stack flags (region-based smart defaults):
19
26
  --orm <id> prisma | drizzle | none (default: prisma)
@@ -24,7 +31,7 @@ Stack flags (region-based smart defaults):
24
31
 
25
32
  Feature flags (region-based smart defaults):
26
33
  --email <id> resend | postmark | ses | aliyun-dm | tencent-ses | netease | none
27
- --storage <id> r2 | s3 | supabase | aliyun-oss | tencent-cos | qiniu | none
34
+ --storage <id> r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none
28
35
  --monitoring <id> sentry | datadog | aliyun-arms | tingyun | none
29
36
  --analytics <id> posthog | plausible | umami | baidu | sensors | none
30
37
  --sms <id> twilio | aliyun-sms | tencent-sms | yunpian | none
@@ -66,9 +73,9 @@ Examples:
66
73
  $ npx create-sailor@latest my-app --region=cn --auth=clerk
67
74
  $ npx create-sailor@latest my-app --region=hybrid --ai=openai,deepseek
68
75
  $ npm create sailor@latest --dry-run --region=cn
69
- `;function on(){process.stdout.write(Qo)}import ht from"picocolors";function rn(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Jo(e){let t=rn()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return rn()?`${ht.dim(o)} ${ht.bold(n)} ${ht.dim(t)} ${ht.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function sn(e){process.stdout.write(Jo(e)+`
70
- `)}var Et=[{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:[]}],na=Et.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var Zo="https://analytics.nebutra.com";function er(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function an(e,t={}){er(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??Zo},onError:()=>{}});if(typeof n?.track!="function")return;let r=n.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import Ge from"fs";import T from"path";var cn=[{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:""}],sa=cn.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function pn(e){return cn.find(t=>t.id===e)}function tr(e){Ge.mkdirSync(e,{recursive:!0})}function q(e,t){tr(T.dirname(e)),Ge.writeFileSync(e,t)}function me(e,t){let o=T.join(e,".env.example");Ge.existsSync(o)?Ge.appendFileSync(o,`
71
- `+t):Ge.writeFileSync(o,t)}function nr(e){let t=`"use client";
76
+ `;function an(){process.stdout.write(er)}import Et from"picocolors";function cn(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function tr(e){let t=cn()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return cn()?`${Et.dim(o)} ${Et.bold(n)} ${Et.dim(t)} ${Et.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function pn(e){process.stdout.write(tr(e)+`
77
+ `)}var Mt=[{id:"anthropic",name:"Anthropic",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.anthropic.com",envVarPrefix:"ANTHROPIC",requiredEnvVars:["ANTHROPIC_API_KEY"]},{id:"openai",name:"OpenAI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.openai.com/docs",envVarPrefix:"OPENAI",requiredEnvVars:["OPENAI_API_KEY"]},{id:"deepseek",name:"DeepSeek",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.deepseek.com/api-docs",envVarPrefix:"DEEPSEEK",requiredEnvVars:["DEEPSEEK_API_KEY"]},{id:"xai",name:"xAI (Grok)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.x.ai/api",envVarPrefix:"XAI",requiredEnvVars:["XAI_API_KEY"]},{id:"moonshot",name:"Moonshot (Kimi)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.moonshot.cn/docs",envVarPrefix:"MOONSHOT",requiredEnvVars:["MOONSHOT_API_KEY","MOONSHOT_BASE_URL"]},{id:"google",name:"Google Gemini",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://ai.google.dev/gemini-api/docs",envVarPrefix:"GOOGLE_GENERATIVE_AI",requiredEnvVars:["GOOGLE_GENERATIVE_AI_API_KEY"]},{id:"mistral",name:"Mistral AI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.mistral.ai",envVarPrefix:"MISTRAL",requiredEnvVars:["MISTRAL_API_KEY"]},{id:"cohere",name:"Cohere",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.cohere.com",envVarPrefix:"COHERE",requiredEnvVars:["COHERE_API_KEY"]},{id:"perplexity",name:"Perplexity",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.perplexity.ai",baseURL:"https://api.perplexity.ai",envVarPrefix:"PERPLEXITY",requiredEnvVars:["PERPLEXITY_API_KEY"]},{id:"ai21",name:"AI21 Labs",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.ai21.com",baseURL:"https://api.ai21.com/studio/v1",envVarPrefix:"AI21",requiredEnvVars:["AI21_API_KEY"]},{id:"upstage",name:"Upstage (Solar)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://developers.upstage.ai/docs",baseURL:"https://api.upstage.ai/v1/solar",envVarPrefix:"UPSTAGE",requiredEnvVars:["UPSTAGE_API_KEY"]},{id:"siliconflow",name:"\u7845\u57FA\u6D41\u52A8 SiliconFlow",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://docs.siliconflow.cn",baseURL:"https://api.siliconflow.cn/v1",envVarPrefix:"SILICONFLOW",requiredEnvVars:["SILICONFLOW_API_KEY"]},{id:"volcengine-ark",name:"\u706B\u5C71\u5F15\u64CE ARK (\u8C46\u5305)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://www.volcengine.com/docs/82379",baseURL:"https://ark.cn-beijing.volces.com/api/v3",envVarPrefix:"ARK",requiredEnvVars:["ARK_API_KEY"]},{id:"bailian",name:"\u767E\u70BC Bailian (\u901A\u4E49)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://help.aliyun.com/zh/model-studio",baseURL:"https://dashscope.aliyuncs.com/compatible-mode/v1",envVarPrefix:"DASHSCOPE",requiredEnvVars:["DASHSCOPE_API_KEY"]},{id:"zhipu",name:"\u667A\u8C31 AI Zhipu",category:"\u56FD\u5185\u5E73\u53F0",status:"ai-sdk",docs:"https://docs.bigmodel.cn",baseURL:"https://open.bigmodel.cn/api/paas/v4",envVarPrefix:"ZHIPU",requiredEnvVars:["ZHIPU_API_KEY"]},{id:"baichuan",name:"\u767E\u5DDD\u667A\u80FD Baichuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.baichuan-ai.com/docs",baseURL:"https://api.baichuan-ai.com/v1",envVarPrefix:"BAICHUAN",requiredEnvVars:["BAICHUAN_API_KEY"]},{id:"minimax",name:"MiniMax (ABAB)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.minimaxi.com/document/guides",baseURL:"https://api.minimax.chat/v1",envVarPrefix:"MINIMAX",requiredEnvVars:["MINIMAX_API_KEY","MINIMAX_GROUP_ID"]},{id:"stepfun",name:"\u9636\u8DC3\u661F\u8FB0 StepFun",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.stepfun.com/docs",baseURL:"https://api.stepfun.com/v1",envVarPrefix:"STEPFUN",requiredEnvVars:["STEPFUN_API_KEY"]},{id:"sensetime",name:"\u5546\u6C64 SenseNova",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.sensetime.com",baseURL:"https://api.sensenova.cn/v1",envVarPrefix:"SENSENOVA",requiredEnvVars:["SENSENOVA_API_KEY"]},{id:"tencent",name:"\u817E\u8BAF\u6DF7\u5143 Hunyuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://cloud.tencent.com/document/product/1729",baseURL:"https://api.hunyuan.cloud.tencent.com/v1",envVarPrefix:"HUNYUAN",requiredEnvVars:["HUNYUAN_API_KEY"]},{id:"lingyi",name:"\u96F6\u4E00\u4E07\u7269 Yi",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.lingyiwanwu.com/docs",baseURL:"https://api.lingyiwanwu.com/v1",envVarPrefix:"YI",requiredEnvVars:["YI_API_KEY"]},{id:"openrouter",name:"OpenRouter",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://openrouter.ai/docs",envVarPrefix:"OPENROUTER",requiredEnvVars:["OPENROUTER_API_KEY"]},{id:"vercel-gateway",name:"Vercel AI Gateway",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://vercel.com/docs/ai-gateway",envVarPrefix:"AI_GATEWAY",requiredEnvVars:["AI_GATEWAY_API_KEY"]},{id:"litellm",name:"LiteLLM Proxy",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://docs.litellm.ai",baseURL:"http://localhost:4000/v1",envVarPrefix:"LITELLM",requiredEnvVars:["LITELLM_API_KEY"]},{id:"portkey",name:"Portkey",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://portkey.ai/docs",baseURL:"https://api.portkey.ai/v1",envVarPrefix:"PORTKEY",requiredEnvVars:["PORTKEY_API_KEY"]},{id:"aws-bedrock",name:"AWS Bedrock",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://aws.amazon.com/bedrock/",envVarPrefix:"AWS_BEDROCK",requiredEnvVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"]},{id:"azure-openai",name:"Azure OpenAI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://azure.microsoft.com/en-us/products/cognitive-services/openai-service/",envVarPrefix:"AZURE_OPENAI",requiredEnvVars:["AZURE_OPENAI_API_KEY","AZURE_OPENAI_ENDPOINT"]},{id:"gcp-vertex",name:"GCP Vertex AI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://cloud.google.com/vertex-ai",envVarPrefix:"GOOGLE_VERTEX",requiredEnvVars:["GOOGLE_APPLICATION_CREDENTIALS"]},{id:"groq",name:"Groq",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://console.groq.com/docs",envVarPrefix:"GROQ",requiredEnvVars:["GROQ_API_KEY"]},{id:"fireworks",name:"Fireworks AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.fireworks.ai",envVarPrefix:"FIREWORKS",requiredEnvVars:["FIREWORKS_API_KEY"]},{id:"together",name:"Together AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.together.ai",envVarPrefix:"TOGETHER",requiredEnvVars:["TOGETHER_API_KEY"]},{id:"huggingface",name:"Hugging Face",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://huggingface.co/docs/inference-providers",envVarPrefix:"HF",requiredEnvVars:["HF_API_KEY"]},{id:"replicate",name:"Replicate",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://replicate.com/docs",envVarPrefix:"REPLICATE",requiredEnvVars:["REPLICATE_API_TOKEN"]},{id:"lepton",name:"Lepton AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://www.lepton.ai/docs",baseURL:"https://api.lepton.ai/v1",envVarPrefix:"LEPTON",requiredEnvVars:["LEPTON_API_KEY"]},{id:"anyscale",name:"Anyscale Endpoints",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://docs.endpoints.anyscale.com/",baseURL:"https://api.endpoints.anyscale.com/v1",envVarPrefix:"ANYSCALE",requiredEnvVars:["ANYSCALE_API_KEY"]},{id:"octoai",name:"OctoAI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://octoai.cloud/docs",baseURL:"https://text.octoai.run/v1",envVarPrefix:"OCTOAI",requiredEnvVars:["OCTOAI_TOKEN"]},{id:"deepinfra",name:"DeepInfra",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://deepinfra.com/docs",baseURL:"https://api.deepinfra.com/v1/openai",envVarPrefix:"DEEPINFRA",requiredEnvVars:["DEEPINFRA_API_KEY"]},{id:"novita",name:"Novita AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://novita.ai/docs",baseURL:"https://api.novita.ai/v3/openai",envVarPrefix:"NOVITA",requiredEnvVars:["NOVITA_API_KEY"]},{id:"black-forest-labs",name:"Black Forest Labs (FLUX)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://docs.bfl.ml",envVarPrefix:"BFL",requiredEnvVars:["BFL_API_KEY"]},{id:"elevenlabs",name:"ElevenLabs (TTS)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://elevenlabs.io/docs",envVarPrefix:"ELEVENLABS",requiredEnvVars:["ELEVENLABS_API_KEY"]},{id:"runway",name:"Runway (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://runwayml.com",envVarPrefix:"RUNWAY",requiredEnvVars:["RUNWAY_API_KEY"]},{id:"luma",name:"Luma (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://lumalabs.ai",envVarPrefix:"LUMA",requiredEnvVars:["LUMA_API_KEY"]},{id:"midjourney",name:"Midjourney",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://docs.midjourney.com",envVarPrefix:"MIDJOURNEY",requiredEnvVars:[]},{id:"ollama",name:"Ollama (\u672C\u5730)",category:"\u672C\u5730\u90E8\u7F72",status:"opencode",docs:"https://github.com/ollama/ollama",baseURL:"http://localhost:11434/v1",envVarPrefix:"OLLAMA",requiredEnvVars:["OLLAMA_BASE_URL"]},{id:"lmstudio",name:"LM Studio",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://lmstudio.ai/docs",baseURL:"http://localhost:1234/v1",envVarPrefix:"LMSTUDIO",requiredEnvVars:[]},{id:"vllm",name:"vLLM",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://docs.vllm.ai",baseURL:"http://localhost:8000/v1",envVarPrefix:"VLLM",requiredEnvVars:[]},{id:"tgi",name:"HF TGI",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://huggingface.co/docs/text-generation-inference",baseURL:"http://localhost:8080/v1",envVarPrefix:"TGI",requiredEnvVars:[]}],ca=Mt.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var nr=["openai","anthropic","google"],or=["openai"];function Dt(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...nr];return{mode:"gateway",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:o,runtimeGovernance:!0}}}case"direct":{let o=t.length>0?t:[...or];return{mode:"direct",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:o,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}import $e from"fs";import k from"path";var ln=[{id:"posthog",name:"PostHog",region:"both",envVars:["POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_HOST"],docs:"https://posthog.com/docs",pkgs:["posthog-js","posthog-node"],providerFile:"apps/web/src/lib/analytics/posthog.client.ts"},{id:"plausible",name:"Plausible",region:"global",envVars:["NEXT_PUBLIC_PLAUSIBLE_DOMAIN","NEXT_PUBLIC_PLAUSIBLE_SRC"],docs:"https://plausible.io/docs",providerFile:"apps/web/src/components/analytics/PlausibleScript.tsx"},{id:"umami",name:"Umami",region:"both",envVars:["NEXT_PUBLIC_UMAMI_WEBSITE_ID","NEXT_PUBLIC_UMAMI_SRC"],docs:"https://umami.is/docs",providerFile:"apps/web/src/components/analytics/UmamiScript.tsx"},{id:"mixpanel",name:"Mixpanel",region:"global",envVars:["MIXPANEL_TOKEN","NEXT_PUBLIC_MIXPANEL_TOKEN"],docs:"https://docs.mixpanel.com",pkgs:["mixpanel-browser","mixpanel"],providerFile:"apps/web/src/lib/analytics/mixpanel.client.ts"},{id:"baidu",name:"\u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji",region:"cn",envVars:["NEXT_PUBLIC_BAIDU_STATS_ID"],docs:"https://tongji.baidu.com",providerFile:"apps/web/src/components/analytics/BaiduStatsScript.tsx"},{id:"sensors",name:"\u795E\u7B56 Sensors Analytics",region:"cn",envVars:["NEXT_PUBLIC_SENSORS_SERVER_URL","NEXT_PUBLIC_SENSORS_APP_JS_URL"],docs:"https://manual.sensorsdata.cn",pkgs:["sa-sdk-javascript"],providerFile:"apps/web/src/lib/analytics/sensors.client.ts"},{id:"growingio",name:"GrowingIO",region:"cn",envVars:["NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID"],docs:"https://growingio.com/docs",providerFile:"apps/web/src/components/analytics/GrowingIoScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],da=ln.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function dn(e){return ln.find(t=>t.id===e)}function rr(e){$e.mkdirSync(e,{recursive:!0})}function $(e,t){rr(k.dirname(e)),$e.writeFileSync(e,t)}function me(e,t){let o=k.join(e,".env.example");$e.existsSync(o)?$e.appendFileSync(o,`
78
+ `+t):$e.writeFileSync(o,t)}function ir(e){let t=`"use client";
72
79
  /**
73
80
  * PostHog browser SDK \u2014 lazy-initialized on first access.
74
81
  */
@@ -151,11 +158,11 @@ export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
151
158
 
152
159
  return <>{children}</>;
153
160
  }
154
- `;q(T.join(e,"src","lib","analytics","posthog.client.ts"),t),q(T.join(e,"src","lib","analytics","posthog.server.ts"),o),q(T.join(e,"src","components","analytics","AnalyticsProvider.tsx"),n)}function or(){return`# PostHog \u2014 product analytics
161
+ `;$(k.join(e,"src","lib","analytics","posthog.client.ts"),t),$(k.join(e,"src","lib","analytics","posthog.server.ts"),o),$(k.join(e,"src","components","analytics","AnalyticsProvider.tsx"),n)}function sr(){return`# PostHog \u2014 product analytics
155
162
  POSTHOG_KEY=
156
163
  NEXT_PUBLIC_POSTHOG_KEY=
157
164
  NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
158
- `}function rr(e){q(T.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
165
+ `}function ar(e){$(k.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
159
166
  /**
160
167
  * Plausible script tag \u2014 lightweight, privacy-friendly analytics.
161
168
  */
@@ -175,10 +182,10 @@ export function PlausibleScript() {
175
182
  />
176
183
  );
177
184
  }
178
- `)}function sr(){return`# Plausible \u2014 privacy-friendly analytics
185
+ `)}function cr(){return`# Plausible \u2014 privacy-friendly analytics
179
186
  NEXT_PUBLIC_PLAUSIBLE_DOMAIN=
180
187
  NEXT_PUBLIC_PLAUSIBLE_SRC=https://plausible.io/js/script.js
181
- `}function ir(e){q(T.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
188
+ `}function pr(e){$(k.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
182
189
  /**
183
190
  * Umami analytics \u2014 self-hosted OR umami.is cloud.
184
191
  */
@@ -198,10 +205,10 @@ export function UmamiScript() {
198
205
  />
199
206
  );
200
207
  }
201
- `)}function ar(){return`# Umami \u2014 self-hostable analytics
208
+ `)}function lr(){return`# Umami \u2014 self-hostable analytics
202
209
  NEXT_PUBLIC_UMAMI_WEBSITE_ID=
203
210
  NEXT_PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
204
- `}function cr(e){let t=`"use client";
211
+ `}function dr(e){let t=`"use client";
205
212
  import mixpanel from "mixpanel-browser";
206
213
 
207
214
  let initialized = false;
@@ -240,10 +247,10 @@ export function trackServer(
240
247
  if (!c) return;
241
248
  c.track(event, { distinct_id: distinctId, ...properties });
242
249
  }
243
- `;q(T.join(e,"src","lib","analytics","mixpanel.client.ts"),t),q(T.join(e,"src","lib","analytics","mixpanel.server.ts"),o)}function pr(){return`# Mixpanel \u2014 product analytics
250
+ `;$(k.join(e,"src","lib","analytics","mixpanel.client.ts"),t),$(k.join(e,"src","lib","analytics","mixpanel.server.ts"),o)}function ur(){return`# Mixpanel \u2014 product analytics
244
251
  MIXPANEL_TOKEN=
245
252
  NEXT_PUBLIC_MIXPANEL_TOKEN=
246
- `}function lr(e){q(T.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
253
+ `}function mr(e){$(k.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
247
254
  /**
248
255
  * \u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji \u2014 hm.js \u57CB\u70B9\u811A\u672C.
249
256
  */
@@ -269,9 +276,9 @@ var _hmt = _hmt || [];
269
276
  />
270
277
  );
271
278
  }
272
- `)}function dr(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
279
+ `)}function gr(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
273
280
  NEXT_PUBLIC_BAIDU_STATS_ID=
274
- `}function ur(e){q(T.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
281
+ `}function fr(e){$(k.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
275
282
  /**
276
283
  * \u795E\u7B56\u5206\u6790 (Sensors Analytics) \u2014 sa-sdk-javascript \u5C01\u88C5.
277
284
  */
@@ -299,10 +306,10 @@ export function initSensors(): void {
299
306
  }
300
307
 
301
308
  export { sensors };
302
- `)}function mr(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
309
+ `)}function yr(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
303
310
  NEXT_PUBLIC_SENSORS_SERVER_URL=
304
311
  NEXT_PUBLIC_SENSORS_APP_JS_URL=
305
- `}function gr(e){q(T.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
312
+ `}function Sr(e){$(k.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
306
313
  /**
307
314
  * GrowingIO CDP \u2014 inline snippet installer.
308
315
  */
@@ -327,21 +334,21 @@ gdp("send");
327
334
  />
328
335
  );
329
336
  }
330
- `)}function fr(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
337
+ `)}function Er(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
331
338
  NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
332
- `}async function ln(e,t,o="global"){let n=pn(t);if(!n||n.id==="none")return;let r=T.join(e,"apps","web");if(!Ge.existsSync(r))return;let s=n.id;try{switch(s){case"posthog":nr(r),me(e,or());return;case"plausible":rr(r),me(e,sr());return;case"umami":ir(r),me(e,ar());return;case"mixpanel":cr(r),me(e,pr());return;case"baidu":lr(r),me(e,dr());return;case"sensors":ur(r),me(e,mr());return;case"growingio":gr(r),me(e,fr());return;default:return}}catch(a){throw console.error(`Failed to apply analytics selection "${t}":`,a),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}import M from"fs";import ge from"path";function Mt(e){M.existsSync(e)&&M.rmSync(e,{recursive:!0,force:!0})}function dn(e,t){let o=ge.join(e,".env.example");M.existsSync(o)?M.appendFileSync(o,`
333
- `+t):M.writeFileSync(o,t)}function un(e,t){if(!M.existsSync(e))return;let o=M.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*"[^"]+"\s*\|\s*"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&M.writeFileSync(e,n)}function yr(e,t){let o=ge.join(e,"README.md");if(!M.existsSync(o)){M.writeFileSync(o,t);return}M.appendFileSync(o,`
334
- `+t)}async function mn(e,t){let o=ge.join(e,"packages","auth");if(!M.existsSync(o))return;if(t==="none"){Mt(o),yr(e,`
339
+ `}async function un(e,t,o="global"){let n=dn(t);if(!n||n.id==="none")return;let r=k.join(e,"apps","web");if(!$e.existsSync(r))return;let i=n.id;try{switch(i){case"posthog":ir(r),me(e,sr());return;case"plausible":ar(r),me(e,cr());return;case"umami":pr(r),me(e,lr());return;case"mixpanel":dr(r),me(e,ur());return;case"baidu":mr(r),me(e,gr());return;case"sensors":fr(r),me(e,yr());return;case"growingio":Sr(r),me(e,Er());return;default:return}}catch(a){throw console.error(`Failed to apply analytics selection "${t}":`,a),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var hr="https://analytics.nebutra.com";function vr(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function mn(e,t={}){vr(t)||(async()=>{try{let o=await import("./dist-B4YTE2SQ.js");if(typeof o.createAnalyticsClient!="function")return;let n=o.createAnalyticsClient({posthog:{apiKey:process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.NEBUTRA_POSTHOG_HOST??hr},onError:()=>{}});if(typeof n?.track!="function")return;let r=n.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import U from"fs";import ge from"path";function Ft(e){U.existsSync(e)&&U.rmSync(e,{recursive:!0,force:!0})}function gn(e,t){let o=ge.join(e,".env.example");U.existsSync(o)?U.appendFileSync(o,`
340
+ `+t):U.writeFileSync(o,t)}function fn(e,t){if(!U.existsSync(e))return;let o=U.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*"[^"]+"\s*\|\s*"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&U.writeFileSync(e,n)}function _r(e,t){let o=ge.join(e,"README.md");if(!U.existsSync(o)){U.writeFileSync(o,t);return}U.appendFileSync(o,`
341
+ `+t)}async function yn(e,t){let o=ge.join(e,"packages","auth");if(!U.existsSync(o))return;if(t==="none"){Ft(o),_r(e,`
335
342
  ## Auth
336
343
 
337
344
  Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth).
338
- `);return}let n=ge.join(o,"src","providers"),r=ge.join(o,"src","types.ts");if(t==="clerk"){Mt(ge.join(n,"better-auth.ts")),un(r,"clerk"),dn(e,`# Clerk auth
345
+ `);return}let n=ge.join(o,"src","providers"),r=ge.join(o,"src","types.ts");if(t==="clerk"){Ft(ge.join(n,"better-auth.ts")),fn(r,"clerk"),gn(e,`# Clerk auth
339
346
  CLERK_PUBLISHABLE_KEY=
340
347
  CLERK_SECRET_KEY=
341
- `);return}if(t==="betterauth"){Mt(ge.join(n,"clerk.ts")),un(r,"better-auth"),dn(e,`# Better Auth
348
+ `);return}if(t==="betterauth"){Ft(ge.join(n,"clerk.ts")),fn(r,"better-auth"),gn(e,`# Better Auth
342
349
  BETTER_AUTH_SECRET=
343
350
  BETTER_AUTH_URL=http://localhost:3000
344
- `);return}}var nt=[{id:"wechat",name:"\u5FAE\u4FE1\u5F00\u653E\u5E73\u53F0",region:"cn",envVars:["WECHAT_APP_ID","WECHAT_APP_SECRET"],docs:"https://open.weixin.qq.com/cgi-bin/showdocument",callbackUrl:"/api/auth/callback/wechat",tokenEndpoint:"https://api.weixin.qq.com/sns/oauth2/access_token"},{id:"qq",name:"QQ \u767B\u5F55",region:"cn",envVars:["QQ_APP_ID","QQ_APP_KEY"],docs:"https://wiki.connect.qq.com",callbackUrl:"/api/auth/callback/qq",tokenEndpoint:"https://graph.qq.com/oauth2.0/token"},{id:"dingtalk",name:"\u9489\u9489",region:"cn",envVars:["DINGTALK_APP_ID","DINGTALK_APP_SECRET"],docs:"https://open.dingtalk.com/document/",callbackUrl:"/api/auth/callback/dingtalk",tokenEndpoint:"https://api.dingtalk.com/v1.0/oauth2/userAccessToken"},{id:"workweixin",name:"\u4F01\u4E1A\u5FAE\u4FE1",region:"cn",envVars:["WORKWEIXIN_CORP_ID","WORKWEIXIN_AGENT_ID","WORKWEIXIN_SECRET"],docs:"https://developer.work.weixin.qq.com",callbackUrl:"/api/auth/callback/workweixin",tokenEndpoint:"https://qyapi.weixin.qq.com/cgi-bin/gettoken"},{id:"feishu",name:"\u98DE\u4E66 / Lark",region:"cn",envVars:["FEISHU_APP_ID","FEISHU_APP_SECRET"],docs:"https://open.feishu.cn/document/",callbackUrl:"/api/auth/callback/feishu",tokenEndpoint:"https://open.feishu.cn/open-apis/authen/v1/access_token"},{id:"weibo",name:"\u5FAE\u535A",region:"cn",envVars:["WEIBO_APP_KEY","WEIBO_APP_SECRET"],docs:"https://open.weibo.com/wiki/",callbackUrl:"/api/auth/callback/weibo",tokenEndpoint:"https://api.weibo.com/oauth2/access_token"}],Sr=new Set(nt.map(e=>e.id));function gn(e){return nt.find(t=>t.id===e)}function fn(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)Sr.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import ye from"fs";import fe from"path";function hr(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
351
+ `);return}}var tt=[{id:"wechat",name:"\u5FAE\u4FE1\u5F00\u653E\u5E73\u53F0",region:"cn",envVars:["WECHAT_APP_ID","WECHAT_APP_SECRET"],docs:"https://open.weixin.qq.com/cgi-bin/showdocument",callbackUrl:"/api/auth/callback/wechat",tokenEndpoint:"https://api.weixin.qq.com/sns/oauth2/access_token"},{id:"qq",name:"QQ \u767B\u5F55",region:"cn",envVars:["QQ_APP_ID","QQ_APP_KEY"],docs:"https://wiki.connect.qq.com",callbackUrl:"/api/auth/callback/qq",tokenEndpoint:"https://graph.qq.com/oauth2.0/token"},{id:"dingtalk",name:"\u9489\u9489",region:"cn",envVars:["DINGTALK_APP_ID","DINGTALK_APP_SECRET"],docs:"https://open.dingtalk.com/document/",callbackUrl:"/api/auth/callback/dingtalk",tokenEndpoint:"https://api.dingtalk.com/v1.0/oauth2/userAccessToken"},{id:"workweixin",name:"\u4F01\u4E1A\u5FAE\u4FE1",region:"cn",envVars:["WORKWEIXIN_CORP_ID","WORKWEIXIN_AGENT_ID","WORKWEIXIN_SECRET"],docs:"https://developer.work.weixin.qq.com",callbackUrl:"/api/auth/callback/workweixin",tokenEndpoint:"https://qyapi.weixin.qq.com/cgi-bin/gettoken"},{id:"feishu",name:"\u98DE\u4E66 / Lark",region:"cn",envVars:["FEISHU_APP_ID","FEISHU_APP_SECRET"],docs:"https://open.feishu.cn/document/",callbackUrl:"/api/auth/callback/feishu",tokenEndpoint:"https://open.feishu.cn/open-apis/authen/v1/access_token"},{id:"weibo",name:"\u5FAE\u535A",region:"cn",envVars:["WEIBO_APP_KEY","WEIBO_APP_SECRET"],docs:"https://open.weibo.com/wiki/",callbackUrl:"/api/auth/callback/weibo",tokenEndpoint:"https://api.weibo.com/oauth2/access_token"}],Pr=new Set(tt.map(e=>e.id));function Sn(e){return tt.find(t=>t.id===e)}function En(e){if(!e)return[];let t=e.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean);if(t.includes("none"))return[];let o=[],n=new Set;for(let r of t)Pr.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import ye from"fs";import fe from"path";function br(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
345
352
  // Generated by create-sailor \u2014 OAuth callback for ${e.name}
346
353
  // Primary auth provider: ${t}
347
354
  // Docs: ${e.docs}`,n={wechat:` const tokenRes = await fetch(
@@ -466,7 +473,7 @@ ${n[e.id]}
466
473
  void state;
467
474
  return NextResponse.redirect(new URL("/dashboard", req.url));
468
475
  }
469
- `}function Er(e){return`"use client";
476
+ `}function Ir(e){return`"use client";
470
477
 
471
478
  /**
472
479
  * SocialLoginButtons \u2014 generated by create-sailor.
@@ -509,23 +516,23 @@ export function SocialLoginButtons() {
509
516
  </div>
510
517
  );
511
518
  }
512
- `}function yn(e){ye.mkdirSync(e,{recursive:!0})}function vr(e,t){let o=fe.join(e,".env.example");ye.existsSync(o)?ye.appendFileSync(o,`
513
- `+t):ye.writeFileSync(o,t)}function _r(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
519
+ `}function hn(e){ye.mkdirSync(e,{recursive:!0})}function Ar(e,t){let o=fe.join(e,".env.example");ye.existsSync(o)?ye.appendFileSync(o,`
520
+ `+t):ye.writeFileSync(o,t)}function Cr(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
514
521
  `);return`${t}
515
522
  ${o}
516
- `}async function Sn(e,t,o){if(!t||t.length===0)return;let n=fe.join(e,"apps","web");if(!ye.existsSync(n))return;let r=new Set,s=[];for(let d of t){if(r.has(d))continue;r.add(d);let u=gn(d);u&&s.push(u)}if(s.length===0)return;for(let d of s)vr(e,_r(d));let a=fe.join(n,"src","app","api","auth","callback");for(let d of s){let u=fe.join(a,d.id);yn(u);let S=fe.join(u,"route.ts");ye.writeFileSync(S,hr(d,o))}let c=fe.join(n,"src","components","auth");yn(c);let i=fe.join(c,"SocialLoginButtons.tsx");ye.writeFileSync(i,Er(s))}import oe from"fs";import Dt from"path";var vt=[{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 hn(e){return vt.find(t=>t.id===e)}var Ea=vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function En(e){return oe.existsSync(e)?oe.readFileSync(e,"utf-8"):null}function Pr(e,t){let o=Dt.join(e,".env.example"),n=En(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
517
- `);oe.appendFileSync(o,s)}function br(e,t,o){let n=Dt.join(e,".env.example"),r=En(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?oe.writeFileSync(n,r.replace(s,`${t}="${o}"`)):oe.appendFileSync(n,`${t}="${o}"
518
- `)}async function vn(e,t,o){let n=Dt.join(e,"packages","cache");if(t==="none"){oe.existsSync(n)&&oe.rmSync(n,{recursive:!0,force:!0});return}let r=hn(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${vt.map(s=>s.id).join(", ")}`);oe.existsSync(n)&&(Pr(e,r),br(e,"CACHE_PROVIDER",t))}var _t=[{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 _n(e){return _t.find(t=>t.id===e)}var Ca=_t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import J from"fs";import Ft from"path";function G(e,t){let o=Ft.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(i=>`${i}=""`),""].filter(i=>i!==null).join(`
519
- `);J.appendFileSync(o,c)}function H(e,t,o){let n=Ft.join(e,".env.example");if(!J.existsSync(n))return;let r=J.readFileSync(n,"utf-8"),s=`${t}="${o}"`,a=new RegExp(`^${t}=.*$`,"m");if(a.test(r)){J.writeFileSync(n,r.replace(a,s));return}let c=r.endsWith(`
523
+ `}async function vn(e,t,o){if(!t||t.length===0)return;let n=fe.join(e,"apps","web");if(!ye.existsSync(n))return;let r=new Set,i=[];for(let d of t){if(r.has(d))continue;r.add(d);let u=Sn(d);u&&i.push(u)}if(i.length===0)return;for(let d of i)Ar(e,Cr(d));let a=fe.join(n,"src","app","api","auth","callback");for(let d of i){let u=fe.join(a,d.id);hn(u);let h=fe.join(u,"route.ts");ye.writeFileSync(h,br(d,o))}let c=fe.join(n,"src","components","auth");hn(c);let s=fe.join(c,"SocialLoginButtons.tsx");ye.writeFileSync(s,Ir(i))}import te from"fs";import jt from"path";var ht=[{id:"upstash-redis",name:"Upstash Redis",region:"both",envVars:["UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"],docs:"https://upstash.com/docs/redis",description:"Serverless Redis"},{id:"vercel-kv",name:"Vercel KV",region:"global",envVars:["KV_URL","KV_REST_API_URL","KV_REST_API_TOKEN","KV_REST_API_READ_ONLY_TOKEN"],docs:"https://vercel.com/docs/storage/vercel-kv",description:"Vercel native KV"},{id:"redis",name:"Redis (self-hosted)",region:"both",envVars:["REDIS_URL"],docs:"https://redis.io/docs/",description:"Self-hosted Redis"},{id:"dragonfly",name:"Dragonfly",region:"global",envVars:["DRAGONFLY_URL"],docs:"https://www.dragonflydb.io/docs",description:"Drop-in Redis replacement, faster"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip cache package"}];function _n(e){return ht.find(t=>t.id===e)}var Ca=ht.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Pn(e){return te.existsSync(e)?te.readFileSync(e,"utf-8"):null}function wr(e,t){let o=jt.join(e,".env.example"),n=Pn(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
524
+ `);te.appendFileSync(o,i)}function Rr(e,t,o){let n=jt.join(e,".env.example"),r=Pn(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?te.writeFileSync(n,r.replace(i,`${t}="${o}"`)):te.appendFileSync(n,`${t}="${o}"
525
+ `)}async function bn(e,t,o){let n=jt.join(e,"packages","cache");if(t==="none"){te.existsSync(n)&&te.rmSync(n,{recursive:!0,force:!0});return}let r=_n(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${ht.map(i=>i.id).join(", ")}`);te.existsSync(n)&&(wr(e,r),Rr(e,"CACHE_PROVIDER",t))}var vt=[{id:"turnstile",name:"Cloudflare Turnstile",region:"global",envVars:["NEXT_PUBLIC_TURNSTILE_SITE_KEY","TURNSTILE_SECRET_KEY"],docs:"https://developers.cloudflare.com/turnstile/",description:"Free, privacy-focused captcha alternative"},{id:"hcaptcha",name:"hCaptcha",region:"global",envVars:["NEXT_PUBLIC_HCAPTCHA_SITE_KEY","HCAPTCHA_SECRET_KEY"],docs:"https://docs.hcaptcha.com/",description:"Privacy-respecting captcha"},{id:"aliyun-slide",name:"\u963F\u91CC\u4E91\u9A8C\u8BC1\u7801 2.0",region:"cn",envVars:["ALIYUN_CAPTCHA_ACCESS_KEY_ID","ALIYUN_CAPTCHA_ACCESS_KEY_SECRET","ALIYUN_CAPTCHA_APP_KEY","NEXT_PUBLIC_ALIYUN_CAPTCHA_APP_KEY"],docs:"https://help.aliyun.com/product/28308.html",description:"\u963F\u91CC\u4E91\u667A\u80FD\u9A8C\u8BC1 (\u6ED1\u5757/\u65E0\u75D5)"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function In(e){return vt.find(t=>t.id===e)}var Ta=vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import J from"fs";import Vt from"path";function q(e,t){let o=Vt.join(e,".env.example");if(!J.existsSync(o)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(J.readFileSync(o,"utf-8").includes(r))return;let c=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].filter(s=>s!==null).join(`
526
+ `);J.appendFileSync(o,c)}function G(e,t,o){let n=Vt.join(e,".env.example");if(!J.existsSync(n))return;let r=J.readFileSync(n,"utf-8"),i=`${t}="${o}"`,a=new RegExp(`^${t}=.*$`,"m");if(a.test(r)){J.writeFileSync(n,r.replace(a,i));return}let c=r.endsWith(`
520
527
  `)?"":`
521
- `;J.appendFileSync(n,`${c}${s}
522
- `)}function B(e,t){let o=Ft.join(e,"packages",t);J.existsSync(o)&&J.rmSync(o,{recursive:!0,force:!0})}async function Pn(e,t,o="global"){let n=_n(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${_t.map(r=>r.id).join(", ")}`);if(n.id==="none"){B(e,"captcha");return}n.envVars.length>0&&G(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),H(e,"CAPTCHA_PROVIDER",n.id)}import bt from"fs";import Ir from"path";var Pt=[{id:"sanity",name:"Sanity",region:"global",envVars:["SANITY_PROJECT_ID","SANITY_DATASET","SANITY_API_TOKEN","SANITY_API_VERSION"],docs:"https://www.sanity.io/docs",description:"Structured content platform with Studio"},{id:"contentful",name:"Contentful",region:"global",envVars:["CONTENTFUL_SPACE_ID","CONTENTFUL_ACCESS_TOKEN","CONTENTFUL_PREVIEW_ACCESS_TOKEN"],docs:"https://www.contentful.com/developers/docs/",description:"Headless CMS"},{id:"strapi",name:"Strapi",region:"both",envVars:["STRAPI_URL","STRAPI_API_TOKEN"],docs:"https://docs.strapi.io",description:"Open-source self-hosted CMS"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function bn(e){return Pt.find(t=>t.id===e)}var Oa=Pt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function In(e,t,o="global"){let n=bn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${Pt.map(s=>s.id).join(", ")}`);let r=Ir.join(e,"apps","studio");if(n.id==="none"){B(e,"sanity"),bt.existsSync(r)&&bt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(B(e,"sanity"),bt.existsSync(r)&&bt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&G(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),H(e,"CMS_PROVIDER",n.id)}import A from"fs";import I from"path";var Cr=I.join("apps","web"),jt=I.join("src","components","compliance"),ot=I.join("src","app","[locale]");function W(e){return I.join(e,Cr)}function Ar(e){A.mkdirSync(e,{recursive:!0})}function Y(e,t){Ar(I.dirname(e)),A.writeFileSync(e,t,"utf8")}function Vt(e,t){let o=I.join(e,".env.example");if(A.existsSync(o)){if(A.readFileSync(o,"utf8").includes(t.split(`
528
+ `;J.appendFileSync(n,`${c}${i}
529
+ `)}function K(e,t){let o=Vt.join(e,"packages",t);J.existsSync(o)&&J.rmSync(o,{recursive:!0,force:!0})}async function An(e,t,o="global"){let n=In(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${vt.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"captcha");return}n.envVars.length>0&&q(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"CAPTCHA_PROVIDER",n.id)}import Pt from"fs";import xr from"path";var _t=[{id:"sanity",name:"Sanity",region:"global",envVars:["SANITY_PROJECT_ID","SANITY_DATASET","SANITY_API_TOKEN","SANITY_API_VERSION"],docs:"https://www.sanity.io/docs",description:"Structured content platform with Studio"},{id:"contentful",name:"Contentful",region:"global",envVars:["CONTENTFUL_SPACE_ID","CONTENTFUL_ACCESS_TOKEN","CONTENTFUL_PREVIEW_ACCESS_TOKEN"],docs:"https://www.contentful.com/developers/docs/",description:"Headless CMS"},{id:"strapi",name:"Strapi",region:"both",envVars:["STRAPI_URL","STRAPI_API_TOKEN"],docs:"https://docs.strapi.io",description:"Open-source self-hosted CMS"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Cn(e){return _t.find(t=>t.id===e)}var Va=_t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function wn(e,t,o="global"){let n=Cn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${_t.map(i=>i.id).join(", ")}`);let r=xr.join(e,"apps","studio");if(n.id==="none"){K(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(K(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&q(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"CMS_PROVIDER",n.id)}import A from"fs";import I from"path";var Nr=I.join("apps","web"),Kt=I.join("src","components","compliance"),nt=I.join("src","app","[locale]");function H(e){return I.join(e,Nr)}function kr(e){A.mkdirSync(e,{recursive:!0})}function B(e,t){kr(I.dirname(e)),A.writeFileSync(e,t,"utf8")}function Bt(e,t){let o=I.join(e,".env.example");if(A.existsSync(o)){if(A.readFileSync(o,"utf8").includes(t.split(`
523
530
  `)[0]??""))return;A.appendFileSync(o,`
524
531
  `+t+`
525
532
  `)}else A.writeFileSync(o,t+`
526
- `)}var rt=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
533
+ `)}var ot=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
527
534
  > Consult a qualified lawyer in every jurisdiction you operate in before publishing.
528
- > \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`,wr=`import Link from "next/link";
535
+ > \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,Tr=`import Link from "next/link";
529
536
  import { IcpFooter } from "@/components/compliance/IcpFooter";
530
537
  import { PublicSecurityFooter } from "@/components/compliance/PublicSecurityFooter";
531
538
 
@@ -576,7 +583,7 @@ export function Footer({ region = "global" }: FooterProps) {
576
583
  </footer>
577
584
  );
578
585
  }
579
- `,Rr=`export function IcpFooter() {
586
+ `,Or=`export function IcpFooter() {
580
587
  const icp = process.env.NEXT_PUBLIC_ICP_BEIAN;
581
588
  if (!icp) return null;
582
589
  return (
@@ -590,7 +597,7 @@ export function Footer({ region = "global" }: FooterProps) {
590
597
  </a>
591
598
  );
592
599
  }
593
- `,Nr=`export function PublicSecurityFooter() {
600
+ `,Ur=`export function PublicSecurityFooter() {
594
601
  const psb = process.env.NEXT_PUBLIC_PSB_BEIAN;
595
602
  const psbCode = process.env.NEXT_PUBLIC_PSB_CODE;
596
603
  if (!psb) return null;
@@ -607,7 +614,7 @@ export function Footer({ region = "global" }: FooterProps) {
607
614
  </a>
608
615
  );
609
616
  }
610
- `,xr=`"use client";
617
+ `,Lr=`"use client";
611
618
 
612
619
  import { useCallback, useEffect, useState } from "react";
613
620
 
@@ -834,7 +841,7 @@ function CategoryRow({ id, title, description, checked, disabled, onChange }: Ca
834
841
  </label>
835
842
  );
836
843
  }
837
- `,kr=`interface AigcDisclaimerProps {
844
+ `,Mr=`interface AigcDisclaimerProps {
838
845
  className?: string;
839
846
  }
840
847
 
@@ -854,13 +861,13 @@ export function AigcDisclaimer({ className }: AigcDisclaimerProps) {
854
861
  </div>
855
862
  );
856
863
  }
857
- `,Tr=`---
864
+ `,Dr=`---
858
865
  title: Privacy Policy / \u9690\u79C1\u653F\u7B56
859
866
  description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal information.
860
867
  lastUpdated: 2026-01-01
861
868
  ---
862
869
 
863
- ${rt}
870
+ ${ot}
864
871
 
865
872
  # Privacy Policy / \u9690\u79C1\u653F\u7B56
866
873
 
@@ -999,13 +1006,13 @@ or in-app notification before the change takes effect.
999
1006
  **Data Controller / \u6570\u636E\u63A7\u5236\u8005:** {{COMPANY_NAME}}
1000
1007
  **Address / \u5730\u5740:** {{COMPANY_ADDRESS}}
1001
1008
  **Email / \u90AE\u7BB1:** {{COMPANY_CONTACT_EMAIL}}
1002
- `,Or=`---
1009
+ `,Fr=`---
1003
1010
  title: Terms of Service / \u670D\u52A1\u6761\u6B3E
1004
1011
  description: Terms governing your use of {{COMPANY_NAME}}.
1005
1012
  lastUpdated: 2026-01-01
1006
1013
  ---
1007
1014
 
1008
- ${rt}
1015
+ ${ot}
1009
1016
 
1010
1017
  # Terms of Service / \u670D\u52A1\u6761\u6B3E
1011
1018
 
@@ -1118,13 +1125,13 @@ conflict-of-laws principles. Disputes shall be resolved in the competent courts
1118
1125
  ## 11. Contact / \u8054\u7CFB\u65B9\u5F0F
1119
1126
 
1120
1127
  {{COMPANY_NAME}} \xB7 {{COMPANY_ADDRESS}} \xB7 {{COMPANY_CONTACT_EMAIL}}
1121
- `,Ur=`---
1128
+ `,jr=`---
1122
1129
  title: AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
1123
1130
  description: Disclosure required by \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300B
1124
1131
  lastUpdated: 2026-01-01
1125
1132
  ---
1126
1133
 
1127
- ${rt}
1134
+ ${ot}
1128
1135
 
1129
1136
  # AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
1130
1137
 
@@ -1200,13 +1207,13 @@ human professional.
1200
1207
 
1201
1208
  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
1202
1209
  \u7528\u4E8E\u533B\u7597\u3001\u6CD5\u5F8B\u3001\u91D1\u878D\u6216\u5B89\u5168\u6538\u5173\u7684\u51B3\u7B56\u3002
1203
- `,Lr=`---
1210
+ `,Vr=`---
1204
1211
  title: Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
1205
1212
  description: Notice of cross-border transfer of personal information, per PIPL.
1206
1213
  lastUpdated: 2026-01-01
1207
1214
  ---
1208
1215
 
1209
- ${rt}
1216
+ ${ot}
1210
1217
 
1211
1218
  # Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
1212
1219
 
@@ -1265,13 +1272,13 @@ Refusal may limit your ability to use features that rely on overseas services.
1265
1272
  - \u4F20\u8F93\u4E2D\u52A0\u5BC6 (TLS 1.2+) \u53CA\u9759\u6001\u52A0\u5BC6 (AES-256)\u3002
1266
1273
  - \u5408\u540C\u6761\u6B3E\u8981\u6C42\u5883\u5916\u63A5\u6536\u65B9\u63D0\u4F9B\u7B49\u540C\u4E8E PIPL \u7684\u4FDD\u62A4\u3002
1267
1274
  - \u8BBF\u95EE\u63A7\u5236\u3001\u5BA1\u8BA1\u65E5\u5FD7\u548C\u8FDD\u89C4\u901A\u77E5\u7A0B\u5E8F\u3002
1268
- `,Mr=`---
1275
+ `,Kr=`---
1269
1276
  title: Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
1270
1277
  description: Itemized list of personal information collected, per PIPL Article 17.
1271
1278
  lastUpdated: 2026-01-01
1272
1279
  ---
1273
1280
 
1274
- ${rt}
1281
+ ${ot}
1275
1282
 
1276
1283
  # Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
1277
1284
 
@@ -1307,19 +1314,19 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
1307
1314
  **{{COMPANY_CONTACT_EMAIL}}**.
1308
1315
 
1309
1316
  \u5982\u9700\u884C\u4F7F\u60A8\u7684\u6743\u5229\uFF08\u8BBF\u95EE\u3001\u66F4\u6B63\u3001\u5220\u9664\u3001\u5BFC\u51FA\u3001\u64A4\u56DE\u540C\u610F\uFF09\uFF0C\u8BF7\u8054\u7CFB **{{COMPANY_CONTACT_EMAIL}}**\u3002
1310
- `;async function Dr(e,t){let o=W(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","Footer.tsx");Y(n,wr);let r=I.join(o,"src","components","compliance","README.md");Y(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(`
1311
- `))}async function Fr(e,t){let o=W(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","CookieBanner.tsx");Y(n,xr)}async function jr(e,t){let o=W(e);if(!A.existsSync(o))return;let n=I.join(o,ot,"privacy","page.mdx");Y(n,Tr)}async function Vr(e,t){let o=W(e);if(!A.existsSync(o))return;let n=I.join(o,ot,"terms","page.mdx");Y(n,Or)}async function Kr(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,jt,"IcpFooter.tsx");Y(o,Rr),Vt(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(`
1312
- `))}async function Br(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,jt,"PublicSecurityFooter.tsx");Y(o,Nr),Vt(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(`
1313
- `))}async function Yr(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,jt,"AigcDisclaimer.tsx");Y(o,kr),Vt(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(`
1314
- `))}async function $r(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"aigc-disclosure","page.mdx");Y(o,Ur)}async function qr(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"cross-border-data","page.mdx");Y(o,Lr)}async function Gr(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"pii-collection","page.mdx");Y(o,Mr)}async function Cn(e,t){try{await Dr(e,t),await Fr(e,t),await jr(e,t),await Vr(e,t),(t==="cn"||t==="hybrid")&&(await Kr(e),await Br(e),await Yr(e),await $r(e),await qr(e),await Gr(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 Hr from"fs";import Wr from"path";async function An(e,t){let o=Wr.join(e,"nebutra.config.json");Hr.writeFileSync(o,JSON.stringify(t,null,2)+`
1315
- `)}import re from"fs";import Kt from"path";function Xr(e){re.existsSync(e)&&re.rmSync(e,{recursive:!0,force:!0})}function wn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function zr(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function Rn(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 Qr(e,t){let o=Kt.join(e,".env.example");re.existsSync(o)?re.appendFileSync(o,`
1316
- `+t):re.writeFileSync(o,t)}async function Nn(e,t,o){let n=Kt.join(e,"packages","db");if(t==="none"){Xr(n);return}let r=Kt.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",Qr(e,`# Database (${t})
1317
- DATABASE_URL="${s}"
1318
- `),!re.existsSync(r))return;let a=re.readFileSync(r,"utf8"),c=a;t==="mysql"?(c=wn(c,"mysql"),c=Rn(c)):t==="sqlite"&&(c=wn(c,"sqlite"),c=zr(c),c=Rn(c)),c!==a&&re.writeFileSync(r,c)}import st from"fs";import D from"path";import{fileURLToPath as Jr}from"url";var Zr=Jr(import.meta.url),es=D.dirname(Zr);async function xn(e,t){if(t==="none")return;let o=D.join(es,"../../templates/deploy");t==="vercel"?await st.promises.copyFile(D.join(o,"vercel.json"),D.join(e,"vercel.json")):t==="railway"?await st.promises.copyFile(D.join(o,"railway.toml"),D.join(e,"railway.toml")):t==="cloudflare"?await st.promises.copyFile(D.join(o,"wrangler.toml"),D.join(e,"wrangler.toml")):t==="selfhost"&&(await st.promises.copyFile(D.join(o,"docker-compose.yml"),D.join(e,"docker-compose.yml")),await st.promises.copyFile(D.join(o,"Dockerfile.web"),D.join(e,"Dockerfile.web")))}import se from"fs";import Se from"path";import{fileURLToPath as ts}from"url";var ns=ts(import.meta.url),kn=Se.dirname(ns),os=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml)$/;function rs(e){let t=[Se.join(kn,"..","templates","docs",e),Se.join(kn,"..","..","templates","docs",e)];for(let o of t)if(se.existsSync(o))return o;return t[0]}async function Tn(e,t){if(t.framework==="none")return;let o=(t.framework==="fumadocs","fumadocs"),n=rs(o),r=Se.join(e,"apps","docs");if(!se.existsSync(n))throw new Error(`Docs template not found: ${n}`);On(n,r),Un(r,{"{PRODUCT_NAME}":t.projectName})}function On(e,t){se.mkdirSync(t,{recursive:!0});for(let o of se.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name),r=Se.join(t,o.name);o.isDirectory()?On(n,r):se.copyFileSync(n,r)}}function Un(e,t){for(let o of se.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name);if(o.isDirectory())Un(n,t);else if(os.test(o.name)){let r=se.readFileSync(n,"utf-8");for(let[s,a]of Object.entries(t))r=r.split(s).join(a);se.writeFileSync(n,r)}}}import Ee from"fs";import he from"path";var It=[{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 Ln(e){return It.find(t=>t.id===e)}var oc=It.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var ve="@nebutra/email";function Bt(e,t){Ee.mkdirSync(he.dirname(e),{recursive:!0}),Ee.writeFileSync(e,t)}function ss(e,t){let o=he.join(e,".env.example");Ee.existsSync(o)?Ee.appendFileSync(o,`
1319
- `+t):Ee.writeFileSync(o,t)}function is(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
1317
+ `;async function Br(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","Footer.tsx");B(n,Tr);let r=I.join(o,"src","components","compliance","README.md");B(r,["# Compliance Components","",`Auto-generated by \`create-sailor\` for region: \`${t}\`.`,"","## Mounting the Footer","","```tsx",'import { Footer } from "@/components/compliance/Footer";','import { CookieBanner } from "@/components/compliance/CookieBanner";',"","export default function RootLayout({ children }) {"," return ("," <html>"," <body>"," {children}",` <Footer region="${t}" />`," <CookieBanner />"," </body>"," </html>"," );","}","```","","## Placeholders","","Policy MDX files contain `{{COMPANY_NAME}}`, `{{COMPANY_ADDRESS}}`,","`{{COMPANY_CONTACT_EMAIL}}`, `{{GOVERNING_JURISDICTION}}`, and","`{{AIGC_ALGORITHM_FILING_NUMBER}}`. These are filled by the `brand-apply` step.",""].join(`
1318
+ `))}async function Yr(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","CookieBanner.tsx");B(n,Lr)}async function $r(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,nt,"privacy","page.mdx");B(n,Dr)}async function qr(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,nt,"terms","page.mdx");B(n,Fr)}async function Gr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"IcpFooter.tsx");B(o,Or),Bt(e,["# Chinese ICP filing (\u5DE5\u4FE1\u90E8 ICP \u5907\u6848) \u2014 required to legally host a","# public-facing site from mainland China. Apply at https://beian.miit.gov.cn/",'NEXT_PUBLIC_ICP_BEIAN="" # \u5982 \u82CFICP\u59072024XXXXXX\u53F7'].join(`
1319
+ `))}async function Hr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"PublicSecurityFooter.tsx");B(o,Ur),Bt(e,["# Chinese Public Security Bureau filing (\u516C\u5B89\u8054\u7F51\u5907\u6848)","# Required in addition to ICP. Apply at http://www.beian.gov.cn/",'NEXT_PUBLIC_PSB_BEIAN="" # \u5982 \u82CF\u516C\u7F51\u5B89\u5907 32011402XXXXXX\u53F7','NEXT_PUBLIC_PSB_CODE="" # 14-digit record code'].join(`
1320
+ `))}async function Wr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"AigcDisclaimer.tsx");B(o,Mr),Bt(e,["# Generative AI algorithm filing (\u7B97\u6CD5\u5907\u6848\u53F7) \u2014 required by","# \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300Bfor services offered in China.",'NEXT_PUBLIC_AIGC_FILING_NUMBER="" # e.g. \u7F51\u4FE1\u7B97\u5907XXXXXXXX\u53F7'].join(`
1321
+ `))}async function Xr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,nt,"aigc-disclosure","page.mdx");B(o,jr)}async function zr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,nt,"cross-border-data","page.mdx");B(o,Vr)}async function Qr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,nt,"pii-collection","page.mdx");B(o,Kr)}async function Rn(e,t){try{await Br(e,t),await Yr(e,t),await $r(e,t),await qr(e,t),(t==="cn"||t==="hybrid")&&(await Gr(e),await Hr(e),await Wr(e),await Xr(e),await zr(e),await Qr(e))}catch(o){throw console.error("applyComplianceTemplates failed:",o),new Error(`Failed to apply compliance templates for region "${t}". Check that ${e} is writable.`)}}import Jr from"fs";import Zr from"path";async function xn(e,t){let o=Zr.join(e,"nebutra.config.json");Jr.writeFileSync(o,JSON.stringify(t,null,2)+`
1322
+ `)}import ne from"fs";import Yt from"path";function ei(e){ne.existsSync(e)&&ne.rmSync(e,{recursive:!0,force:!0})}function Nn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function ti(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function kn(e){let t=e.replace(/^\s*extensions\s*=\s*\[[^\]]*\]\s*\n/gm,"");return t=t.replace(/previewFeatures\s*=\s*\[\s*"postgresqlExtensions"\s*\]\s*\n/g,""),t}function ni(e,t){let o=Yt.join(e,".env.example");ne.existsSync(o)?ne.appendFileSync(o,`
1323
+ `+t):ne.writeFileSync(o,t)}async function Tn(e,t,o){let n=Yt.join(e,"packages","db");if(t==="none"){ei(n);return}let r=Yt.join(n,"prisma","schema.prisma"),i;if(t==="postgresql"?i=`postgresql://postgres:postgres@localhost:5432/${o}`:t==="mysql"?i=`mysql://root:root@localhost:3306/${o}`:i="file:./dev.db",ni(e,`# Database (${t})
1324
+ DATABASE_URL="${i}"
1325
+ `),!ne.existsSync(r))return;let a=ne.readFileSync(r,"utf8"),c=a;t==="mysql"?(c=Nn(c,"mysql"),c=kn(c)):t==="sqlite"&&(c=Nn(c,"sqlite"),c=ti(c),c=kn(c)),c!==a&&ne.writeFileSync(r,c)}import rt from"fs";import L from"path";import{fileURLToPath as oi}from"url";var ri=oi(import.meta.url),ii=L.dirname(ri);async function On(e,t){if(t==="none")return;let o=L.join(ii,"../../templates/deploy");t==="vercel"?await rt.promises.copyFile(L.join(o,"vercel.json"),L.join(e,"vercel.json")):t==="railway"?await rt.promises.copyFile(L.join(o,"railway.toml"),L.join(e,"railway.toml")):t==="cloudflare"?await rt.promises.copyFile(L.join(o,"wrangler.toml"),L.join(e,"wrangler.toml")):t==="selfhost"&&(await rt.promises.copyFile(L.join(o,"docker-compose.yml"),L.join(e,"docker-compose.yml")),await rt.promises.copyFile(L.join(o,"Dockerfile.web"),L.join(e,"Dockerfile.web")))}import oe from"fs";import Se from"path";import{fileURLToPath as si}from"url";var ai=si(import.meta.url),Un=Se.dirname(ai),ci=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml)$/;function pi(e){let t=[Se.join(Un,"..","templates","docs",e),Se.join(Un,"..","..","templates","docs",e)];for(let o of t)if(oe.existsSync(o))return o;return t[0]}async function Ln(e,t){if(t.framework==="none")return;let o=(t.framework==="fumadocs","fumadocs"),n=pi(o),r=Se.join(e,"apps","docs");if(!oe.existsSync(n))throw new Error(`Docs template not found: ${n}`);Mn(n,r),Dn(r,{"{PRODUCT_NAME}":t.projectName})}function Mn(e,t){oe.mkdirSync(t,{recursive:!0});for(let o of oe.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name),r=Se.join(t,o.name);o.isDirectory()?Mn(n,r):oe.copyFileSync(n,r)}}function Dn(e,t){for(let o of oe.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name);if(o.isDirectory())Dn(n,t);else if(ci.test(o.name)){let r=oe.readFileSync(n,"utf-8");for(let[i,a]of Object.entries(t))r=r.split(i).join(a);oe.writeFileSync(n,r)}}}import he from"fs";import Ee from"path";var bt=[{id:"resend",name:"Resend",region:"global",envVars:["RESEND_API_KEY","RESEND_FROM"],docs:"https://resend.com/docs",pkg:"resend",pkgVersion:"^4.0.1"},{id:"postmark",name:"Postmark",region:"global",envVars:["POSTMARK_API_KEY","POSTMARK_FROM"],docs:"https://postmarkapp.com/developer",pkg:"postmark",pkgVersion:"^4.0.5"},{id:"ses",name:"AWS SES",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_SES_REGION","SES_FROM"],docs:"https://docs.aws.amazon.com/ses",pkg:"@aws-sdk/client-sesv2",pkgVersion:"^3.658.0"},{id:"aliyun-dm",name:"\u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001",region:"cn",envVars:["ALIYUN_DM_ACCESS_KEY","ALIYUN_DM_ACCESS_SECRET","ALIYUN_DM_ACCOUNT_NAME","ALIYUN_DM_FROM_ALIAS"],docs:"https://help.aliyun.com/product/29412.html",pkg:"@alicloud/dm20151123",pkgVersion:"^3.0.0"},{id:"tencent-ses",name:"\u817E\u8BAF\u4E91 SES",region:"cn",envVars:["TENCENT_SECRET_ID","TENCENT_SECRET_KEY","TENCENT_SES_FROM_EMAIL"],docs:"https://cloud.tencent.com/document/product/1288",pkg:"tencentcloud-sdk-nodejs-ses",pkgVersion:"^4.0.900"},{id:"netease",name:"\u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1",region:"cn",envVars:["NETEASE_USER","NETEASE_PASS","NETEASE_FROM"],docs:"https://qiye.163.com/help",pkg:"nodemailer",pkgVersion:"^6.9.15"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function Fn(e){return bt.find(t=>t.id===e)}var lc=bt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var ve="@nebutra/email";function $t(e,t){he.mkdirSync(Ee.dirname(e),{recursive:!0}),he.writeFileSync(e,t)}function li(e,t){let o=Ee.join(e,".env.example");he.existsSync(o)?he.appendFileSync(o,`
1326
+ `+t):he.writeFileSync(o,t)}function di(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
1320
1327
  `);return`${t}
1321
1328
  ${o}
1322
- `}var as=`/**
1329
+ `}var ui=`/**
1323
1330
  * Public inputs accepted by the \`sendEmail\` wrapper.
1324
1331
  * Keep the surface minimal \u2014 individual providers may accept more, but
1325
1332
  * consumers should code against this shape for portability.
@@ -1339,7 +1346,7 @@ export interface SendEmailResult {
1339
1346
  /** Raw provider response \u2014 useful for debugging, not a stable contract. */
1340
1347
  raw?: unknown;
1341
1348
  }
1342
- `;function cs(){return`/**
1349
+ `;function mi(){return`/**
1343
1350
  * @${ve.slice(1)} \u2014 Resend transactional email wrapper.
1344
1351
  *
1345
1352
  * Docs: https://resend.com/docs
@@ -1378,7 +1385,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1378
1385
  }
1379
1386
 
1380
1387
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1381
- `}function ps(){return`/**
1388
+ `}function gi(){return`/**
1382
1389
  * @${ve.slice(1)} \u2014 Postmark transactional email wrapper.
1383
1390
  *
1384
1391
  * Docs: https://postmarkapp.com/developer
@@ -1416,7 +1423,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1416
1423
  }
1417
1424
 
1418
1425
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1419
- `}function ls(){return`/**
1426
+ `}function fi(){return`/**
1420
1427
  * @${ve.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
1421
1428
  *
1422
1429
  * Docs: https://docs.aws.amazon.com/ses
@@ -1472,7 +1479,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1472
1479
  }
1473
1480
 
1474
1481
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1475
- `}function ds(){return`/**
1482
+ `}function yi(){return`/**
1476
1483
  * @${ve.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
1477
1484
  *
1478
1485
  * Docs: https://help.aliyun.com/product/29412.html
@@ -1522,7 +1529,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1522
1529
  }
1523
1530
 
1524
1531
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1525
- `}function us(){return`/**
1532
+ `}function Si(){return`/**
1526
1533
  * @${ve.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
1527
1534
  *
1528
1535
  * Docs: https://cloud.tencent.com/document/product/1288
@@ -1570,7 +1577,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1570
1577
  }
1571
1578
 
1572
1579
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1573
- `}function ms(){return`/**
1580
+ `}function Ei(){return`/**
1574
1581
  * @${ve.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
1575
1582
  *
1576
1583
  * Docs: https://qiye.163.com/help
@@ -1608,23 +1615,23 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1608
1615
  }
1609
1616
 
1610
1617
  export type { SendEmailInput, SendEmailResult } from "./types.js";
1611
- `}function gs(e){switch(e){case"resend":return cs();case"postmark":return ps();case"ses":return ls();case"aliyun-dm":return ds();case"tencent-ses":return us();case"netease":return ms();case"none":return`export {};
1612
- `}}function fs(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),e.id==="aliyun-dm"&&(t["@alicloud/openapi-client"]="^0.4.12");let o={name:ve,version:"0.1.0",private:!0,description:`Transactional email via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
1613
- `}async function Mn(e,t,o){if(t==="none")return;let n=Ln(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${It.map(a=>a.id).join(", ")}`);let r=he.join(e,"packages","email"),s=he.join(r,"src");Ee.existsSync(s)&&Ee.rmSync(s,{recursive:!0,force:!0}),Bt(he.join(r,"package.json"),fs(n)),Bt(he.join(s,"types.ts"),as),Bt(he.join(s,"index.ts"),gs(n.id)),ss(e,is(n))}import Ct from"fs";import Dn from"path";async function Fn(e,t){let o=`# Automatically injected by create-sailor
1618
+ `}function hi(e){switch(e){case"resend":return mi();case"postmark":return gi();case"ses":return fi();case"aliyun-dm":return yi();case"tencent-ses":return Si();case"netease":return Ei();case"none":return`export {};
1619
+ `}}function vi(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),e.id==="aliyun-dm"&&(t["@alicloud/openapi-client"]="^0.4.12");let o={name:ve,version:"0.1.0",private:!0,description:`Transactional email via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
1620
+ `}async function jn(e,t,o){if(t==="none")return;let n=Fn(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${bt.map(a=>a.id).join(", ")}`);let r=Ee.join(e,"packages","email"),i=Ee.join(r,"src");he.existsSync(i)&&he.rmSync(i,{recursive:!0,force:!0}),$t(Ee.join(r,"package.json"),vi(n)),$t(Ee.join(i,"types.ts"),ui),$t(Ee.join(i,"index.ts"),hi(n.id)),li(e,di(n))}import It from"fs";import Vn from"path";async function Kn(e,t){let o=`# Automatically injected by create-sailor
1614
1621
  DATABASE_URL="${String(t.databaseUrl)}"
1615
1622
 
1616
1623
  NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
1617
1624
  CLERK_SECRET_KEY="${String(t.clerkSecret)}"
1618
1625
 
1619
1626
  NEXT_PUBLIC_SITE_URL="http://localhost:3000"
1620
- `,n=Dn.join(e,".env"),r=Dn.join(e,".env.local");!Ct.existsSync(n)&&!Ct.existsSync(r)?Ct.writeFileSync(r,o):Ct.appendFileSync(r,`
1621
- `+o)}import Vn from"crypto";import it from"fs";import jn from"path";function _e(e){return Vn.randomBytes(e).toString("base64").replace(/=+$/,"")}function ys(e){return Vn.randomBytes(e).toString("hex")}function Ss(){return{AUTH_SECRET:_e(32),NEXTAUTH_SECRET:_e(32),BETTER_AUTH_SECRET:_e(32),JWT_SECRET:_e(32),WEBHOOK_SECRET:ys(16),ENCRYPTION_KEY:_e(32),API_SECRET_KEY:_e(32),SESSION_SECRET:_e(32)}}function hs(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Es(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=hs(o);return e.replace(n,`${t}="${r}"`)}async function Kn(e){let t=jn.join(e,".env.example"),o=jn.join(e,".env.local");if(!it.existsSync(t))return null;try{let n=it.readFileSync(t,"utf8"),r=Ss(),a=it.existsSync(o)?it.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))a=Es(a,c,r[c]);return it.writeFileSync(o,a),r}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate env secrets: ${r}`),new Error(`Unable to write .env.local: ${r}`)}}var At=[{id:"vercel-flags",name:"Vercel Flags SDK",region:"global",envVars:["FLAGS_SECRET"],docs:"https://vercel.com/docs/workflow-collaboration/feature-flags",description:"Native Vercel feature flags"},{id:"growthbook",name:"GrowthBook",region:"both",envVars:["GROWTHBOOK_API_HOST","GROWTHBOOK_CLIENT_KEY","GROWTHBOOK_DECRYPTION_KEY"],docs:"https://docs.growthbook.io",description:"Open-source A/B testing + flags"},{id:"configcat",name:"ConfigCat",region:"global",envVars:["CONFIGCAT_SDK_KEY"],docs:"https://configcat.com/docs/",description:"Feature flag & config management"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Bn(e){return At.find(t=>t.id===e)}var yc=At.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Yn(e,t,o="global"){let n=Bn(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${At.map(r=>r.id).join(", ")}`);if(n.id==="none"){B(e,"feature-flags");return}n.envVars.length>0&&G(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),H(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{execFileSync as Gn}from"child_process";import x from"fs";import vs from"os";import ie from"path";import _s from"ignore";var Ps={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 bs(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function Is(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function Hn(e){return/^[0-9a-f]{7,40}$/i.test(e)}function Cs(e,t){let o=`https://github.com/${e}.git`,n=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of n)try{let s=Gn("git",["ls-remote",o,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!s)continue;let[a]=s.split(/\s+/);if(Hn(a))return a}catch{}return null}async function As(e,t){if(Hn(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=Cs(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 Wn(e,t,o){let n=x.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let s=ie.join(t,r.name),a=ie.relative(e,s).split(ie.sep).join("/");r.isDirectory()?(o.push(a+"/"),Wn(e,s,o)):o.push(a)}}function ws(e){let t=ie.join(e,".templateignore");if(!x.existsSync(t))return;let o=x.readFileSync(t,"utf8"),n=_s().add(o),r=[];Wn(e,e,r);let s=r.map(i=>i.endsWith("/")?i.slice(0,-1):i),a=new Set(n.filter(s)),c=s.filter(i=>!a.has(i)).sort((i,d)=>d.split("/").length-i.split("/").length);for(let i of c){let d=ie.join(e,i);try{x.existsSync(d)&&x.rmSync(d,{recursive:!0,force:!0})}catch{}}try{x.existsSync(t)&&x.rmSync(t,{force:!0})}catch{}}async function $n(e,t){let o=await fetch(e,{headers:{Accept:"application/octet-stream","User-Agent":"create-sailor"}});if(!o.ok)throw new Error(`Failed to download archive (${o.status})`);let n=Buffer.from(await o.arrayBuffer());if(n.byteLength<1024)throw new Error(`Downloaded archive is unexpectedly small (${n.byteLength} bytes)`);x.writeFileSync(t,n);let r=x.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function qn(e,t){Gn("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function Xn(e){try{let t=x.readdirSync(e);for(let o of t)x.rmSync(ie.join(e,o),{recursive:!0,force:!0})}catch{}}async function Rs(e,t){let o=x.mkdtempSync(ie.join(vs.tmpdir(),"create-sailor-")),n=ie.join(o,"template.tar.gz");try{let r=await As(e.repo,e.ref);await $n(Is(e.repo,r),n),qn(n,t)}catch(r){if(!e.allowMutableFallback)throw r;Xn(t),await $n(bs(e.repo,e.ref),n),qn(n,t)}finally{x.rmSync(o,{recursive:!0,force:!0})}}async function zn(e){x.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let s=Ps[r];try{if(await Rs(s,e),s.applyIgnore)try{ws(e)}catch(a){throw new Error(`Template cloned, but .templateignore processing failed: ${a instanceof Error?a.message:String(a)}`)}return}catch(a){n=a instanceof Error?a:new Error(String(a)),Xn(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
1627
+ `,n=Vn.join(e,".env"),r=Vn.join(e,".env.local");!It.existsSync(n)&&!It.existsSync(r)?It.writeFileSync(r,o):It.appendFileSync(r,`
1628
+ `+o)}import Yn from"crypto";import it from"fs";import Bn from"path";function _e(e){return Yn.randomBytes(e).toString("base64").replace(/=+$/,"")}function _i(e){return Yn.randomBytes(e).toString("hex")}function Pi(){return{AUTH_SECRET:_e(32),NEXTAUTH_SECRET:_e(32),BETTER_AUTH_SECRET:_e(32),JWT_SECRET:_e(32),WEBHOOK_SECRET:_i(16),ENCRYPTION_KEY:_e(32),API_SECRET_KEY:_e(32),SESSION_SECRET:_e(32)}}function bi(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Ii(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=bi(o);return e.replace(n,`${t}="${r}"`)}async function $n(e){let t=Bn.join(e,".env.example"),o=Bn.join(e,".env.local");if(!it.existsSync(t))return null;try{let n=it.readFileSync(t,"utf8"),r=Pi(),a=it.existsSync(o)?it.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))a=Ii(a,c,r[c]);return it.writeFileSync(o,a),r}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate env secrets: ${r}`),new Error(`Unable to write .env.local: ${r}`)}}var At=[{id:"vercel-flags",name:"Vercel Flags SDK",region:"global",envVars:["FLAGS_SECRET"],docs:"https://vercel.com/docs/workflow-collaboration/feature-flags",description:"Native Vercel feature flags"},{id:"growthbook",name:"GrowthBook",region:"both",envVars:["GROWTHBOOK_API_HOST","GROWTHBOOK_CLIENT_KEY","GROWTHBOOK_DECRYPTION_KEY"],docs:"https://docs.growthbook.io",description:"Open-source A/B testing + flags"},{id:"configcat",name:"ConfigCat",region:"global",envVars:["CONFIGCAT_SDK_KEY"],docs:"https://configcat.com/docs/",description:"Feature flag & config management"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function qn(e){return At.find(t=>t.id===e)}var bc=At.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Gn(e,t,o="global"){let n=qn(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${At.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"feature-flags");return}n.envVars.length>0&&q(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{execFileSync as Xn}from"child_process";import x from"fs";import Ai from"os";import re from"path";import Ci from"ignore";var wi={mirror:{repo:process.env.SAILOR_TEMPLATE_REPO||"Nebutra/Sailor-Template",ref:process.env.SAILOR_TEMPLATE_REF||"main",applyIgnore:!1,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"},main:{repo:"Nebutra/Nebutra-Sailor",ref:"main",applyIgnore:!0,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"}};function Ri(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function xi(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function zn(e){return/^[0-9a-f]{7,40}$/i.test(e)}function Ni(e,t){let o=`https://github.com/${e}.git`,n=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of n)try{let i=Xn("git",["ls-remote",o,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!i)continue;let[a]=i.split(/\s+/);if(zn(a))return a}catch{}return null}async function ki(e,t){if(zn(t))return t;let o=await fetch(`https://api.github.com/repos/${e}/commits/${encodeURIComponent(t)}`,{headers:{Accept:"application/vnd.github+json","User-Agent":"create-sailor"}});if(!o.ok){let r=Ni(e,t);if(r)return r;throw new Error(`Failed to resolve ${e}@${t} (GitHub API ${o.status})`)}let n=await o.json();if(typeof n.sha!="string"||n.sha.length===0)throw new Error(`GitHub API did not return a commit SHA for ${e}@${t}`);return n.sha}function Qn(e,t,o){let n=x.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let i=re.join(t,r.name),a=re.relative(e,i).split(re.sep).join("/");r.isDirectory()?(o.push(a+"/"),Qn(e,i,o)):o.push(a)}}function Ti(e){let t=re.join(e,".templateignore");if(!x.existsSync(t))return;let o=x.readFileSync(t,"utf8"),n=Ci().add(o),r=[];Qn(e,e,r);let i=r.map(s=>s.endsWith("/")?s.slice(0,-1):s),a=new Set(n.filter(i)),c=i.filter(s=>!a.has(s)).sort((s,d)=>d.split("/").length-s.split("/").length);for(let s of c){let d=re.join(e,s);try{x.existsSync(d)&&x.rmSync(d,{recursive:!0,force:!0})}catch{}}try{x.existsSync(t)&&x.rmSync(t,{force:!0})}catch{}}async function Hn(e,t){let o=await fetch(e,{headers:{Accept:"application/octet-stream","User-Agent":"create-sailor"}});if(!o.ok)throw new Error(`Failed to download archive (${o.status})`);let n=Buffer.from(await o.arrayBuffer());if(n.byteLength<1024)throw new Error(`Downloaded archive is unexpectedly small (${n.byteLength} bytes)`);x.writeFileSync(t,n);let r=x.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function Wn(e,t){Xn("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function Jn(e){try{let t=x.readdirSync(e);for(let o of t)x.rmSync(re.join(e,o),{recursive:!0,force:!0})}catch{}}async function Oi(e,t){let o=x.mkdtempSync(re.join(Ai.tmpdir(),"create-sailor-")),n=re.join(o,"template.tar.gz");try{let r=await ki(e.repo,e.ref);await Hn(xi(e.repo,r),n),Wn(n,t)}catch(r){if(!e.allowMutableFallback)throw r;Jn(t),await Hn(Ri(e.repo,e.ref),n),Wn(n,t)}finally{x.rmSync(o,{recursive:!0,force:!0})}}async function Zn(e){x.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let i=wi[r];try{if(await Oi(i,e),i.applyIgnore)try{Ti(e)}catch(a){throw new Error(`Template cloned, but .templateignore processing failed: ${a instanceof Error?a.message:String(a)}`)}return}catch(a){n=a instanceof Error?a:new Error(String(a)),Jn(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
1622
1629
 
1623
1630
  Ensure you have internet access and 'tar' installed.
1624
- You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import Pe from"fs";import Yt from"path";async function Qn(e,t){let o=Yt.join(e,"packages","mcp");if(t==="off"){Pe.existsSync(o)&&Pe.rmSync(o,{recursive:!0,force:!0});let r=Yt.join(e,"packages","cli","src","commands","mcp-server.ts");Pe.existsSync(r)&&Pe.rmSync(r,{force:!0});return}let n=Yt.join(e,".env.example");if(Pe.existsSync(n)){let r=Pe.readFileSync(n,"utf-8"),s="# MCP Server (Agent-friendly API)";if(!r.includes(s)){let a=["","# =============================================",s,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
1625
- `);Pe.appendFileSync(n,a)}}}import at from"fs";import Jn from"path";async function Zn(e,t,o){let n=Jn.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){at.existsSync(n)&&at.rmSync(n,{recursive:!0,force:!0});return}let s=Jn.join(e,".env.example");if(!at.existsSync(s))return;let a=at.readFileSync(s,"utf-8"),c="# Metering (usage-based billing)";if(!a.includes(c)){let i=["","# =============================================",c,"# Docs: see packages/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
1626
- `);at.appendFileSync(s,i)}}import He from"fs";import O 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:""}],Oc=eo.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function to(e){return eo.find(t=>t.id===e)}function Ns(e){He.mkdirSync(e,{recursive:!0})}function X(e,t){Ns(O.dirname(e)),He.writeFileSync(e,t)}function ct(e,t){let o=O.join(e,".env.example");He.existsSync(o)?He.appendFileSync(o,`
1627
- `+t):He.writeFileSync(o,t)}function xs(e){let t=`import * as Sentry from "@sentry/nextjs";
1631
+ You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import Pe from"fs";import qt from"path";async function eo(e,t){let o=qt.join(e,"packages","mcp");if(t==="off"){Pe.existsSync(o)&&Pe.rmSync(o,{recursive:!0,force:!0});let r=qt.join(e,"packages","cli","src","commands","mcp-server.ts");Pe.existsSync(r)&&Pe.rmSync(r,{force:!0});return}let n=qt.join(e,".env.example");if(Pe.existsSync(n)){let r=Pe.readFileSync(n,"utf-8"),i="# MCP Server (Agent-friendly API)";if(!r.includes(i)){let a=["","# =============================================",i,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
1632
+ `);Pe.appendFileSync(n,a)}}}import st from"fs";import to from"path";async function no(e,t,o){let n=to.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){st.existsSync(n)&&st.rmSync(n,{recursive:!0,force:!0});return}let i=to.join(e,".env.example");if(!st.existsSync(i))return;let a=st.readFileSync(i,"utf-8"),c="# Metering (usage-based billing)";if(!a.includes(c)){let s=["","# =============================================",c,"# Docs: see packages/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
1633
+ `);st.appendFileSync(i,s)}}import qe from"fs";import T from"path";var oo=[{id:"sentry",name:"Sentry",region:"both",envVars:["SENTRY_DSN","NEXT_PUBLIC_SENTRY_DSN"],docs:"https://docs.sentry.io",pkg:"@sentry/nextjs",instrumentationFile:"apps/web/instrumentation.ts"},{id:"datadog",name:"Datadog",region:"global",envVars:["DD_API_KEY","DD_APP_KEY","DD_SITE"],docs:"https://docs.datadoghq.com",pkg:"dd-trace",instrumentationFile:"apps/web/instrumentation.ts"},{id:"bugsnag",name:"Bugsnag",region:"global",envVars:["BUGSNAG_API_KEY","NEXT_PUBLIC_BUGSNAG_API_KEY"],docs:"https://docs.bugsnag.com",pkg:"@bugsnag/js",instrumentationFile:"apps/web/src/lib/monitoring/bugsnag.ts"},{id:"aliyun-arms",name:"\u963F\u91CC\u4E91 ARMS",region:"cn",envVars:["ALIYUN_ARMS_LICENSE_KEY","ALIYUN_ARMS_APP_NAME","NEXT_PUBLIC_ARMS_PID"],docs:"https://help.aliyun.com/product/34364.html",instrumentationFile:"apps/web/src/components/monitoring/ArmsScript.tsx"},{id:"tingyun",name:"\u542C\u4E91 TingYun",region:"cn",envVars:["TINGYUN_LICENSE_KEY","NEXT_PUBLIC_TINGYUN_APP_KEY"],docs:"https://www.tingyun.com/docs",instrumentationFile:"apps/web/src/components/monitoring/TingYunScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],Vc=oo.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function ro(e){return oo.find(t=>t.id===e)}function Ui(e){qe.mkdirSync(e,{recursive:!0})}function W(e,t){Ui(T.dirname(e)),qe.writeFileSync(e,t)}function at(e,t){let o=T.join(e,".env.example");qe.existsSync(o)?qe.appendFileSync(o,`
1634
+ `+t):qe.writeFileSync(o,t)}function Li(e){let t=`import * as Sentry from "@sentry/nextjs";
1628
1635
 
1629
1636
  Sentry.init({
1630
1637
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
@@ -1667,14 +1674,14 @@ export async function register() {
1667
1674
  }
1668
1675
 
1669
1676
  export { captureRequestError as onRequestError } from "@sentry/nextjs";
1670
- `;X(O.join(e,"sentry.client.config.ts"),t),X(O.join(e,"sentry.server.config.ts"),o),X(O.join(e,"sentry.edge.config.ts"),n),X(O.join(e,"instrumentation.ts"),r)}function ks(){return`# Sentry \u2014 error tracking + performance monitoring
1677
+ `;W(T.join(e,"sentry.client.config.ts"),t),W(T.join(e,"sentry.server.config.ts"),o),W(T.join(e,"sentry.edge.config.ts"),n),W(T.join(e,"instrumentation.ts"),r)}function Mi(){return`# Sentry \u2014 error tracking + performance monitoring
1671
1678
  # Get your DSN from https://sentry.io/settings/projects/<project>/keys/
1672
1679
  SENTRY_DSN=
1673
1680
  NEXT_PUBLIC_SENTRY_DSN=
1674
1681
  SENTRY_ORG=
1675
1682
  SENTRY_PROJECT=
1676
1683
  SENTRY_AUTH_TOKEN=
1677
- `}function Ts(e){let t=`/**
1684
+ `}function Di(e){let t=`/**
1678
1685
  * Next.js instrumentation hook \u2014 wires Datadog APM (dd-trace) into Node runtime.
1679
1686
  * Edge runtime is not supported by dd-trace; only nodejs is initialized.
1680
1687
  */
@@ -1722,7 +1729,7 @@ export function initDatadogRum(): void {
1722
1729
  });
1723
1730
  initialized = true;
1724
1731
  }
1725
- `;X(O.join(e,"instrumentation.ts"),t),X(O.join(e,"src","lib","monitoring","datadog-rum.ts"),o)}function Os(){return`# Datadog \u2014 APM + RUM
1732
+ `;W(T.join(e,"instrumentation.ts"),t),W(T.join(e,"src","lib","monitoring","datadog-rum.ts"),o)}function Fi(){return`# Datadog \u2014 APM + RUM
1726
1733
  # Server APM (dd-trace)
1727
1734
  DD_API_KEY=
1728
1735
  DD_APP_KEY=
@@ -1737,7 +1744,7 @@ NEXT_PUBLIC_DD_SITE=datadoghq.com
1737
1744
  NEXT_PUBLIC_DD_SERVICE=sailor-web
1738
1745
  NEXT_PUBLIC_DD_ENV=production
1739
1746
  NEXT_PUBLIC_DD_VERSION=
1740
- `}function Us(e){let t=`/**
1747
+ `}function ji(e){let t=`/**
1741
1748
  * Bugsnag server-side initialization.
1742
1749
  * Import this once at the top of your server entrypoint or a shared init module.
1743
1750
  */
@@ -1786,11 +1793,11 @@ export function getBugsnagErrorBoundary() {
1786
1793
  errorBoundary = plugin.createErrorBoundary(React) as typeof errorBoundary;
1787
1794
  return errorBoundary;
1788
1795
  }
1789
- `;X(O.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),X(O.join(e,"src","lib","monitoring","bugsnag.client.tsx"),o)}function Ls(){return`# Bugsnag \u2014 error tracking
1796
+ `;W(T.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),W(T.join(e,"src","lib","monitoring","bugsnag.client.tsx"),o)}function Vi(){return`# Bugsnag \u2014 error tracking
1790
1797
  BUGSNAG_API_KEY=
1791
1798
  NEXT_PUBLIC_BUGSNAG_API_KEY=
1792
1799
  APP_VERSION=
1793
- `}function Ms(e){X(O.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
1800
+ `}function Ki(e){W(T.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
1794
1801
  /**
1795
1802
  * \u963F\u91CC\u4E91 ARMS (Application Real-time Monitoring Service) browser agent.
1796
1803
  * Injects the official JS agent via next/script.
@@ -1811,11 +1818,11 @@ export function ArmsScript() {
1811
1818
  />
1812
1819
  );
1813
1820
  }
1814
- `)}function Ds(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
1821
+ `)}function Bi(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
1815
1822
  ALIYUN_ARMS_LICENSE_KEY=
1816
1823
  ALIYUN_ARMS_APP_NAME=
1817
1824
  NEXT_PUBLIC_ARMS_PID=
1818
- `}function Fs(e){X(O.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
1825
+ `}function Yi(e){W(T.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
1819
1826
  /**
1820
1827
  * \u542C\u4E91 Browser Agent (\u524D\u7AEF\u6027\u80FD\u76D1\u63A7).
1821
1828
  * Docs: https://www.tingyun.com/docs
@@ -1833,12 +1840,12 @@ export function TingYunScript() {
1833
1840
  />
1834
1841
  );
1835
1842
  }
1836
- `)}function js(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
1843
+ `)}function $i(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
1837
1844
  TINGYUN_LICENSE_KEY=
1838
1845
  NEXT_PUBLIC_TINGYUN_APP_KEY=
1839
- `}async function no(e,t,o="global"){let n=to(t);if(!n||n.id==="none")return;let r=O.join(e,"apps","web");if(!He.existsSync(r))return;let s=n.id;try{switch(s){case"sentry":xs(r),ct(e,ks());return;case"datadog":Ts(r),ct(e,Os());return;case"bugsnag":Us(r),ct(e,Ls());return;case"aliyun-arms":Ms(r),ct(e,Ds());return;case"tingyun":Fs(r),ct(e,js());return;default:return}}catch(a){throw console.error(`Failed to apply monitoring selection "${t}":`,a),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var wt=[{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 oo(e){return wt.find(t=>t.id===e)}var jc=wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ro(e,t,o="global"){let n=oo(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${wt.map(r=>r.id).join(", ")}`);if(n.id==="none"){B(e,"notifications");return}n.envVars.length>0&&G(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),H(e,"NOTIFICATIONS_PROVIDER",n.id)}import $t from"fs";import Vs from"path";async function so(e,t){let o=Vs.join(e,"package.json");if($t.existsSync(o)){let n=$t.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",$t.writeFileSync(o,JSON.stringify(r,null,2)+`
1840
- `)}}import Z from"fs";import pt from"path";var Ks=["stripe","lemonsqueezy","chinapay","polar"];function io(e){Z.existsSync(e)&&Z.rmSync(e,{recursive:!0,force:!0})}function Bs(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Ys(e,t){let o=pt.join(e,".env.example");Z.existsSync(o)?Z.appendFileSync(o,`
1841
- `+t):Z.writeFileSync(o,t)}function $s(e){switch(e){case"stripe":return`# Stripe
1846
+ `}async function io(e,t,o="global"){let n=ro(t);if(!n||n.id==="none")return;let r=T.join(e,"apps","web");if(!qe.existsSync(r))return;let i=n.id;try{switch(i){case"sentry":Li(r),at(e,Mi());return;case"datadog":Di(r),at(e,Fi());return;case"bugsnag":ji(r),at(e,Vi());return;case"aliyun-arms":Ki(r),at(e,Bi());return;case"tingyun":Yi(r),at(e,$i());return;default:return}}catch(a){throw console.error(`Failed to apply monitoring selection "${t}":`,a),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Ct=[{id:"novu",name:"Novu",region:"both",envVars:["NOVU_API_KEY","NOVU_APPLICATION_IDENTIFIER"],docs:"https://docs.novu.co",description:"Multi-channel notification infrastructure"},{id:"knock",name:"Knock",region:"global",envVars:["KNOCK_API_KEY","KNOCK_SIGNING_KEY","KNOCK_PUBLIC_API_KEY"],docs:"https://docs.knock.app",description:"Product notifications platform"},{id:"custom",name:"Custom (direct dispatchers)",region:"both",envVars:[],docs:"",description:"Use email + sms + push directly"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function so(e){return Ct.find(t=>t.id===e)}var Gc=Ct.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ao(e,t,o="global"){let n=so(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Ct.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"notifications");return}n.envVars.length>0&&q(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"NOTIFICATIONS_PROVIDER",n.id)}import Gt from"fs";import qi from"path";async function co(e,t){let o=qi.join(e,"package.json");if(Gt.existsSync(o)){let n=Gt.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",Gt.writeFileSync(o,JSON.stringify(r,null,2)+`
1847
+ `)}}import Z from"fs";import ct from"path";var Gi=["stripe","lemonsqueezy","chinapay","polar"];function po(e){Z.existsSync(e)&&Z.rmSync(e,{recursive:!0,force:!0})}function Hi(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Wi(e,t){let o=ct.join(e,".env.example");Z.existsSync(o)?Z.appendFileSync(o,`
1848
+ `+t):Z.writeFileSync(o,t)}function Xi(e){switch(e){case"stripe":return`# Stripe
1842
1849
  STRIPE_SECRET_KEY=
1843
1850
  STRIPE_WEBHOOK_SECRET=
1844
1851
  `;case"lemon":return`# Lemon Squeezy
@@ -1853,14 +1860,14 @@ CHINAPAY_WECHAT_ENABLED=true
1853
1860
  CHINAPAY_APP_ID=
1854
1861
  CHINAPAY_APP_SECRET=
1855
1862
  CHINAPAY_ALIPAY_ENABLED=true
1856
- `}}async function ao(e,t){let o=pt.join(e,"packages","billing");if(!Z.existsSync(o))return;if(t==="none"){io(o);return}let n=pt.join(o,"src"),r=new Set(Bs(t));for(let a of Ks)r.has(a)||io(pt.join(n,a));let s=pt.join(n,"checkout","types.ts");if(Z.existsSync(s)){let a=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=Z.readFileSync(s,"utf8"),i=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${a}";`);i!==c&&Z.writeFileSync(s,i)}Ys(e,$s(t))}import ae from"fs";import We from"path";var lo=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),qt=/@sailor:([^\s*]+)/;function qs(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=>lo.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 co(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function po(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function uo(e,t){let o=e.split(`
1857
- `),n=[],r=e.includes("#"),s=0;for(;s<o.length;){let a=o[s],c=a.match(qt);if(!c){n.push(a),s++;continue}let{marker:i,keep:d}=qs(c[1],t);if(i==="registry-entries"){n.push(r?po(a):co(a)),s++;continue}if(d){let u=r?po(a):co(a);u.trim().length>0&&n.push(u);let S=s+1;for(;S<o.length&&o[S].trim()!==""&&!qt.test(o[S]);)n.push(o[S]),S++;S<o.length&&o[S].trim()===""&&(n.push(o[S]),S++),s=S}else{let u=s+1;for(;u<o.length&&o[u].trim()!==""&&!qt.test(o[u]);)u++;u<o.length&&o[u].trim()===""&&u++,s=u}}return Gs(n.join(`
1858
- `),t)}function Gs(e,t){let{providerIds:o,customEndpoint:n}=t,r=new Set;for(let d of o)["openai","anthropic","google","mistral","xai"].includes(d)&&r.add(d),r.add(d.replace(/-/g,"_")),r.add(d);n&&r.add("custom");let s=/createProviderRegistry\(\{([\s\S]*?)\}\)/,a=e.match(s);if(!a)return e;let i=a[1].split(`
1859
- `).filter(d=>{let u=d.trim();if(u===""||u.startsWith("//"))return!0;let S=u.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return S?r.has(S[1]):!0}).join(`
1860
- `);return e.replace(s,`createProviderRegistry({${i}})`)}function Hs(e,t){let o=We.join(t,"registry.ts.template"),n=ae.readFileSync(o,"utf-8");return uo(n,e)}function Ws(e,t){let o=We.join(t,".env.example.template"),n=ae.readFileSync(o,"utf-8");return uo(n,e)}async function mo(e,t,o){let n=Hs(t,o),r=Ws(t,o),s=We.join(e,"packages/agents/src");await ae.promises.mkdir(s,{recursive:!0}),await ae.promises.writeFile(We.join(s,"registry.ts"),n),await ae.promises.appendFile(We.join(e,".env.example"),`
1861
- `+r);let a={ai:"latest"},{providerIds:c,customEndpoint:i}=t;(c.includes("openai")||i||c.some(u=>lo.has(u)))&&(a["@ai-sdk/openai"]="latest",a["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(a["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(a["@ai-sdk/google"]="latest"),c.includes("mistral")&&(a["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(a["@ai-sdk/openai"]="latest");let d=We.join(e,"package.json");if(ae.existsSync(d)){let u=JSON.parse(await ae.promises.readFile(d,"utf-8"));u.dependencies||(u.dependencies={});for(let[S,U]of Object.entries(a))u.dependencies[S]=U;await ae.promises.writeFile(d,JSON.stringify(u,null,2)+`
1862
- `)}}import g from"fs";import v from"path";function go(e,t){if(!g.existsSync(e))return;let o=g.readdirSync(e);for(let n of o){let r=v.join(e,n);g.statSync(r).isDirectory()?go(r,t):t(r)}}async function fo(e,t){let o=v.join(e,"package.json");if(!g.existsSync(o))return;let n=JSON.parse(g.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=v.join(e,"packages","db");if(g.existsSync(r)){let s=v.join(r,"prisma");g.existsSync(s)&&g.rmSync(s,{recursive:!0,force:!0});let a=v.join(r,"package.json");if(g.existsSync(a)){let i=JSON.parse(g.readFileSync(a,"utf8"));i.dependencies&&delete i.dependencies["@prisma/client"],i.devDependencies&&delete i.devDependencies.prisma,g.writeFileSync(a,JSON.stringify(i,null,2)+`
1863
- `)}let c=v.join(r,"src","index.ts");g.existsSync(c)&&g.writeFileSync(c,`
1863
+ `}}async function lo(e,t){let o=ct.join(e,"packages","billing");if(!Z.existsSync(o))return;if(t==="none"){po(o);return}let n=ct.join(o,"src"),r=new Set(Hi(t));for(let a of Gi)r.has(a)||po(ct.join(n,a));let i=ct.join(n,"checkout","types.ts");if(Z.existsSync(i)){let a=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=Z.readFileSync(i,"utf8"),s=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${a}";`);s!==c&&Z.writeFileSync(i,s)}Wi(e,Xi(t))}import ie from"fs";import Ge from"path";var go=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),Ht=/@sailor:([^\s*]+)/;function zi(e,t){let{providerIds:o,customEndpoint:n}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:o.includes(r)}}if(e==="cn-compatible"){let r=o.some(i=>go.has(i));return{marker:e,keep:r||!!n}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:o.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!n}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function uo(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function mo(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function fo(e,t){let o=e.split(`
1864
+ `),n=[],r=e.includes("#"),i=0;for(;i<o.length;){let a=o[i],c=a.match(Ht);if(!c){n.push(a),i++;continue}let{marker:s,keep:d}=zi(c[1],t);if(s==="registry-entries"){n.push(r?mo(a):uo(a)),i++;continue}if(d){let u=r?mo(a):uo(a);u.trim().length>0&&n.push(u);let h=i+1;for(;h<o.length&&o[h].trim()!==""&&!Ht.test(o[h]);)n.push(o[h]),h++;h<o.length&&o[h].trim()===""&&(n.push(o[h]),h++),i=h}else{let u=i+1;for(;u<o.length&&o[u].trim()!==""&&!Ht.test(o[u]);)u++;u<o.length&&o[u].trim()===""&&u++,i=u}}return Qi(n.join(`
1865
+ `),t)}function Qi(e,t){let{providerIds:o,customEndpoint:n}=t,r=new Set;for(let d of o)["openai","anthropic","google","mistral","xai"].includes(d)&&r.add(d),r.add(d.replace(/-/g,"_")),r.add(d);n&&r.add("custom");let i=/createProviderRegistry\(\{([\s\S]*?)\}\)/,a=e.match(i);if(!a)return e;let s=a[1].split(`
1866
+ `).filter(d=>{let u=d.trim();if(u===""||u.startsWith("//"))return!0;let h=u.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return h?r.has(h[1]):!0}).join(`
1867
+ `);return e.replace(i,`createProviderRegistry({${s}})`)}function Ji(e,t){let o=Ge.join(t,"registry.ts.template"),n=ie.readFileSync(o,"utf-8");return fo(n,e)}function Zi(e,t){let o=Ge.join(t,".env.example.template"),n=ie.readFileSync(o,"utf-8");return fo(n,e)}async function yo(e,t,o){let n=Ji(t,o),r=Zi(t,o),i=Ge.join(e,"packages/agents/src");await ie.promises.mkdir(i,{recursive:!0}),await ie.promises.writeFile(Ge.join(i,"registry.ts"),n),await ie.promises.appendFile(Ge.join(e,".env.example"),`
1868
+ `+r);let a={ai:"latest"},{providerIds:c,customEndpoint:s}=t;(c.includes("openai")||s||c.some(u=>go.has(u)))&&(a["@ai-sdk/openai"]="latest",a["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(a["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(a["@ai-sdk/google"]="latest"),c.includes("mistral")&&(a["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(a["@ai-sdk/openai"]="latest");let d=Ge.join(e,"package.json");if(ie.existsSync(d)){let u=JSON.parse(await ie.promises.readFile(d,"utf-8"));u.dependencies||(u.dependencies={});for(let[h,O]of Object.entries(a))u.dependencies[h]=O;await ie.promises.writeFile(d,JSON.stringify(u,null,2)+`
1869
+ `)}}import g from"fs";import P from"path";function So(e,t){if(!g.existsSync(e))return;let o=g.readdirSync(e);for(let n of o){let r=P.join(e,n);g.statSync(r).isDirectory()?So(r,t):t(r)}}async function Eo(e,t){let o=P.join(e,"package.json");if(!g.existsSync(o))return;let n=JSON.parse(g.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=P.join(e,"packages","db");if(g.existsSync(r)){let i=P.join(r,"prisma");g.existsSync(i)&&g.rmSync(i,{recursive:!0,force:!0});let a=P.join(r,"package.json");if(g.existsSync(a)){let s=JSON.parse(g.readFileSync(a,"utf8"));s.dependencies&&delete s.dependencies["@prisma/client"],s.devDependencies&&delete s.devDependencies.prisma,g.writeFileSync(a,JSON.stringify(s,null,2)+`
1870
+ `)}let c=P.join(r,"src","index.ts");g.existsSync(c)&&g.writeFileSync(c,`
1864
1871
  export const prisma = {} as any;
1865
1872
  export const db = {} as any;
1866
1873
  export type PrismaClient = any;
@@ -1906,7 +1913,7 @@ export type UsageAggregate = any;
1906
1913
  export type UsageLedgerEntry = any;
1907
1914
  export type UsageType = any;
1908
1915
  export type UsageLedgerSource = any;
1909
- `)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=v.join(e,"apps");if(g.existsSync(r)){let s=g.readdirSync(r);for(let a of s){let c=v.join(r,a);if(!g.statSync(c).isDirectory())continue;let i=v.join(c,"src","app");if(!g.existsSync(i))continue;["[lang]","[locale]"].forEach(h=>{let l=v.join(i,h);if(g.existsSync(l)){let N=g.readdirSync(l);for(let ut of N)g.renameSync(v.join(l,ut),v.join(i,ut));g.rmdirSync(l)}}),["src/middleware.ts","middleware.ts"].forEach(h=>{let l=v.join(c,h);g.existsSync(l)&&g.rmSync(l)});let d=v.join(c,"src","lib");g.existsSync(d)||g.mkdirSync(d,{recursive:!0});let u=v.join(d,"mock-i18n.ts");g.writeFileSync(u,`
1916
+ `)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=P.join(e,"apps");if(g.existsSync(r)){let i=g.readdirSync(r);for(let a of i){let c=P.join(r,a);if(!g.statSync(c).isDirectory())continue;let s=P.join(c,"src","app");if(!g.existsSync(s))continue;["[lang]","[locale]"].forEach(v=>{let l=P.join(s,v);if(g.existsSync(l)){let R=g.readdirSync(l);for(let ut of R)g.renameSync(P.join(l,ut),P.join(s,ut));g.rmdirSync(l)}}),["src/middleware.ts","middleware.ts"].forEach(v=>{let l=P.join(c,v);g.existsSync(l)&&g.rmSync(l)});let d=P.join(c,"src","lib");g.existsSync(d)||g.mkdirSync(d,{recursive:!0});let u=P.join(d,"mock-i18n.ts");g.writeFileSync(u,`
1910
1917
  import React from 'react';
1911
1918
  export function useTranslations(namespace?: string): any { return (key: string) => key; }
1912
1919
  export function useLocale() { return 'en'; }
@@ -1924,7 +1931,7 @@ export const useRouter = () => ({ push: (...args: any[]) => {}, replace: (...arg
1924
1931
  export default function createMiddleware(...args: any[]) { return (req: any) => req; }
1925
1932
  export function createNavigation(...args: any[]) { return { Link, redirect, usePathname, useRouter, getPathname: () => '/' }; }
1926
1933
  export function defineRouting<T>(config: T): T { return config; }
1927
- `);let U=v.join(d,"mock-i18n.d.ts");g.writeFileSync(U,`declare module '@/lib/mock-i18n' {
1934
+ `);let O=P.join(d,"mock-i18n.d.ts");g.writeFileSync(O,`declare module '@/lib/mock-i18n' {
1928
1935
  export function useTranslations(namespace?: string): any;
1929
1936
  export function useLocale(): string;
1930
1937
  export const NextIntlClientProvider: React.FC<any>;
@@ -1942,18 +1949,18 @@ export function defineRouting<T>(config: T): T { return config; }
1942
1949
  export function createNavigation(...args: any[]): any;
1943
1950
  export function defineRouting<T>(config: T): T;
1944
1951
  }
1945
- `),g.writeFileSync(v.join(d,"mock-i18n-index.ts"),`
1952
+ `),g.writeFileSync(P.join(d,"mock-i18n-index.ts"),`
1946
1953
  export * from './mock-i18n';
1947
1954
  export { default } from './mock-i18n';
1948
- `);let F=v.join(c,"tsconfig.json");if(g.existsSync(F))try{let h=g.readFileSync(F,"utf8");if(h.includes('"paths": {')){let l=h.replace(/"paths":\s*\{/,`"paths": {
1955
+ `);let M=P.join(c,"tsconfig.json");if(g.existsSync(M))try{let v=g.readFileSync(M,"utf8");if(v.includes('"paths": {')){let l=v.replace(/"paths":\s*\{/,`"paths": {
1949
1956
  "next-intl": ["./src/lib/mock-i18n"],
1950
- "next-intl/*": ["./src/lib/mock-i18n"],`);g.writeFileSync(F,l)}}catch{}let ee=v.join(c,"src");g.existsSync(ee)&&go(ee,h=>{if(!h.endsWith(".ts")&&!h.endsWith(".tsx"))return;let l=g.readFileSync(h,"utf8"),N=!1;h.endsWith("src/app/layout.tsx")&&l.includes("../providers")&&(l=l.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),N=!0),l=l.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),l=l.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),l.match(/locale\s*:\s*any/)&&(l=l.replace(/locale\s*:\s*any/g,"locale: string"),N=!0),l.match(/lang\s*:\s*any/)&&(l=l.replace(/lang\s*:\s*any/g,"lang: string"),N=!0),l.match(/requestLocale\s*:\s*any/)&&(l=l.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),N=!0),l.match(/\(locale\s*=\s*(.*)\)/)&&(l=l.replace(/\(locale\s*=\s*(.*)\)/g,"() "),N=!0),l.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(l=l.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),N=!0),(h.endsWith("src/app/layout.tsx")||h.endsWith("src/app/sitemap.ts")||h.endsWith("src/app/robots.ts")||h.endsWith("src/components/ui/locale-switcher.tsx")||h.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(l=l.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),l=l.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),l=l.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),l=l.replace(/\(l\)\s*=>/g,"(l: any) =>"),N=!0),h.endsWith("src/i18n/request.ts")&&(l=l.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),N=!0),(l.match(/locale\s*:/)||l.match(/lang\s*:/))&&(N=!0),N&&g.writeFileSync(h,l)});let Xe=v.join(c,"package.json");if(g.existsSync(Xe)){let h=JSON.parse(g.readFileSync(Xe,"utf8"));h.dependencies&&delete h.dependencies["next-intl"],g.writeFileSync(Xe,JSON.stringify(h,null,2)+`
1957
+ "next-intl/*": ["./src/lib/mock-i18n"],`);g.writeFileSync(M,l)}}catch{}let D=P.join(c,"src");g.existsSync(D)&&So(D,v=>{if(!v.endsWith(".ts")&&!v.endsWith(".tsx"))return;let l=g.readFileSync(v,"utf8"),R=!1;v.endsWith("src/app/layout.tsx")&&l.includes("../providers")&&(l=l.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),R=!0),l=l.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),l=l.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),l.match(/locale\s*:\s*any/)&&(l=l.replace(/locale\s*:\s*any/g,"locale: string"),R=!0),l.match(/lang\s*:\s*any/)&&(l=l.replace(/lang\s*:\s*any/g,"lang: string"),R=!0),l.match(/requestLocale\s*:\s*any/)&&(l=l.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),R=!0),l.match(/\(locale\s*=\s*(.*)\)/)&&(l=l.replace(/\(locale\s*=\s*(.*)\)/g,"() "),R=!0),l.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(l=l.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),R=!0),(v.endsWith("src/app/layout.tsx")||v.endsWith("src/app/sitemap.ts")||v.endsWith("src/app/robots.ts")||v.endsWith("src/components/ui/locale-switcher.tsx")||v.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(l=l.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),l=l.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),l=l.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),l=l.replace(/\(l\)\s*=>/g,"(l: any) =>"),R=!0),v.endsWith("src/i18n/request.ts")&&(l=l.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),R=!0),(l.match(/locale\s*:/)||l.match(/lang\s*:/))&&(R=!0),R&&g.writeFileSync(v,l)});let He=P.join(c,"package.json");if(g.existsSync(He)){let v=JSON.parse(g.readFileSync(He,"utf8"));v.dependencies&&delete v.dependencies["next-intl"],g.writeFileSync(He,JSON.stringify(v,null,2)+`
1951
1958
  `)}}}}g.writeFileSync(o,JSON.stringify(n,null,2)+`
1952
- `)}import{getSchema as Xs,printSchema as zs}from"@mrleebo/prisma-ast";var Qs=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function Js(e){return e.type==="comment"&&e.text.trim().startsWith("///")}function Zs(e){let t=Qs.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 ei(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=Zs(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function Gt(e,t){let o=Xs(e),n=new Set;for(let c=0;c<o.list.length;c++){if(o.list[c].type!=="model")continue;let d=ei(o.list,c);if(!d)continue;let u=t[d.parsed.flag];if(u!==void 0&&d.parsed.values.includes(u))n.add(d.annIndex);else{n.add(c);for(let F=c-1;F>=0;F--){let ee=o.list[F];if(ee.type==="comment"&&Js(ee)){n.add(F);continue}break}let U=o.list[c+1];U&&U.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,i)=>!n.has(i)),s=[];for(let c of r){let i=s[s.length-1];c.type==="break"&&i&&i.type==="break"||s.push(c)}return zs({type:"schema",list:s})}import ce from"fs";import Ht from"path";var Rt=[{id:"qstash",name:"Upstash QStash",region:"both",envVars:["QSTASH_TOKEN","QSTASH_CURRENT_SIGNING_KEY","QSTASH_NEXT_SIGNING_KEY"],docs:"https://upstash.com/docs/qstash",description:"Serverless HTTP-based queue"},{id:"bullmq",name:"BullMQ",region:"both",envVars:["REDIS_URL"],docs:"https://docs.bullmq.io",description:"Redis-backed job queue"},{id:"upstash",name:"Upstash Kafka",region:"both",envVars:["UPSTASH_KAFKA_REST_URL","UPSTASH_KAFKA_REST_USERNAME","UPSTASH_KAFKA_REST_PASSWORD"],docs:"https://upstash.com/docs/kafka",description:"Serverless Kafka"},{id:"sqs",name:"AWS SQS",region:"global",envVars:["AWS_SQS_QUEUE_URL","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"],docs:"https://docs.aws.amazon.com/AWSSimpleQueueService/",description:"AWS managed queue"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip queue package"}];function yo(e){return Rt.find(t=>t.id===e)}var rp=Rt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function So(e){return ce.existsSync(e)?ce.readFileSync(e,"utf-8"):null}function ti(e,t){let o=Ht.join(e,".env.example"),n=So(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
1953
- `);ce.appendFileSync(o,s)}function ni(e,t,o){let n=Ht.join(e,".env.example"),r=So(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?ce.writeFileSync(n,r.replace(s,`${t}="${o}"`)):ce.appendFileSync(n,`${t}="${o}"
1954
- `)}async function ho(e,t,o){let n=Ht.join(e,"packages","queue");if(t==="none"){ce.existsSync(n)&&ce.rmSync(n,{recursive:!0,force:!0});return}let r=yo(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${Rt.map(s=>s.id).join(", ")}`);ce.existsSync(n)&&(ti(e,r),ni(e,"QUEUE_PROVIDER",t))}import pe from"fs";import Wt from"path";var Nt=[{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 Eo(e){return Nt.find(t=>t.id===e)}var lp=Nt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function vo(e){return pe.existsSync(e)?pe.readFileSync(e,"utf-8"):null}function oi(e,t){let o=Wt.join(e,".env.example"),n=vo(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
1955
- `);pe.appendFileSync(o,s)}function ri(e,t,o){let n=Wt.join(e,".env.example"),r=vo(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?pe.writeFileSync(n,r.replace(s,`${t}="${o}"`)):pe.appendFileSync(n,`${t}="${o}"
1956
- `)}async function _o(e,t,o){let n=Wt.join(e,"packages","search");if(t==="none"){pe.existsSync(n)&&pe.rmSync(n,{recursive:!0,force:!0});return}let r=Eo(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Nt.map(s=>s.id).join(", ")}`);pe.existsSync(n)&&(oi(e,r),ri(e,"SEARCH_PROVIDER",t))}import le from"fs";import be from"path";function si(e){let t=[be.join(e,"packages","db"),be.join(e,"apps","web")];for(let o of t){let n=be.join(o,"prisma","schema.prisma");if(le.existsSync(n))return{packageDir:o,seedPath:be.join(o,"prisma","seed.ts"),packageJsonPath:be.join(o,"package.json")}}return null}function ii(e){try{let t=le.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 ai(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1959
+ `)}import{getSchema as es,printSchema as ts}from"@mrleebo/prisma-ast";var ns=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function os(e){return e.type==="comment"&&e.text.trim().startsWith("///")}function rs(e){let t=ns.exec(e.trim());if(!t)return null;let[,o,n]=t,r=n.split("|").map(i=>i.trim()).filter(i=>i.length>0);return{flag:o,values:r}}function is(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=rs(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function Wt(e,t){let o=es(e),n=new Set;for(let c=0;c<o.list.length;c++){if(o.list[c].type!=="model")continue;let d=is(o.list,c);if(!d)continue;let u=t[d.parsed.flag];if(u!==void 0&&d.parsed.values.includes(u))n.add(d.annIndex);else{n.add(c);for(let M=c-1;M>=0;M--){let D=o.list[M];if(D.type==="comment"&&os(D)){n.add(M);continue}break}let O=o.list[c+1];O&&O.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,s)=>!n.has(s)),i=[];for(let c of r){let s=i[i.length-1];c.type==="break"&&s&&s.type==="break"||i.push(c)}return ts({type:"schema",list:i})}import se from"fs";import Xt from"path";var wt=[{id:"qstash",name:"Upstash QStash",region:"both",envVars:["QSTASH_TOKEN","QSTASH_CURRENT_SIGNING_KEY","QSTASH_NEXT_SIGNING_KEY"],docs:"https://upstash.com/docs/qstash",description:"Serverless HTTP-based queue"},{id:"bullmq",name:"BullMQ",region:"both",envVars:["REDIS_URL"],docs:"https://docs.bullmq.io",description:"Redis-backed job queue"},{id:"upstash",name:"Upstash Kafka",region:"both",envVars:["UPSTASH_KAFKA_REST_URL","UPSTASH_KAFKA_REST_USERNAME","UPSTASH_KAFKA_REST_PASSWORD"],docs:"https://upstash.com/docs/kafka",description:"Serverless Kafka"},{id:"sqs",name:"AWS SQS",region:"global",envVars:["AWS_SQS_QUEUE_URL","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"],docs:"https://docs.aws.amazon.com/AWSSimpleQueueService/",description:"AWS managed queue"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip queue package"}];function ho(e){return wt.find(t=>t.id===e)}var dp=wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function vo(e){return se.existsSync(e)?se.readFileSync(e,"utf-8"):null}function ss(e,t){let o=Xt.join(e,".env.example"),n=vo(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
1960
+ `);se.appendFileSync(o,i)}function as(e,t,o){let n=Xt.join(e,".env.example"),r=vo(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?se.writeFileSync(n,r.replace(i,`${t}="${o}"`)):se.appendFileSync(n,`${t}="${o}"
1961
+ `)}async function _o(e,t,o){let n=Xt.join(e,"packages","queue");if(t==="none"){se.existsSync(n)&&se.rmSync(n,{recursive:!0,force:!0});return}let r=ho(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${wt.map(i=>i.id).join(", ")}`);se.existsSync(n)&&(ss(e,r),as(e,"QUEUE_PROVIDER",t))}import ae from"fs";import zt from"path";var Rt=[{id:"meilisearch",name:"Meilisearch",region:"both",envVars:["MEILISEARCH_HOST","MEILISEARCH_MASTER_KEY"],docs:"https://docs.meilisearch.com",description:"Self-hostable search"},{id:"typesense",name:"Typesense",region:"both",envVars:["TYPESENSE_HOST","TYPESENSE_PORT","TYPESENSE_PROTOCOL","TYPESENSE_API_KEY"],docs:"https://typesense.org/docs",description:"Open-source search"},{id:"algolia",name:"Algolia",region:"global",envVars:["ALGOLIA_APP_ID","ALGOLIA_ADMIN_API_KEY","ALGOLIA_SEARCH_API_KEY"],docs:"https://www.algolia.com/doc/",description:"Managed search as a service"},{id:"pgvector",name:"pgvector (Postgres)",region:"both",envVars:["DATABASE_URL"],docs:"https://github.com/pgvector/pgvector",description:"Postgres vector + full-text"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip search package"}];function Po(e){return Rt.find(t=>t.id===e)}var Sp=Rt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function bo(e){return ae.existsSync(e)?ae.readFileSync(e,"utf-8"):null}function cs(e,t){let o=zt.join(e,".env.example"),n=bo(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
1962
+ `);ae.appendFileSync(o,i)}function ps(e,t,o){let n=zt.join(e,".env.example"),r=bo(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ae.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ae.appendFileSync(n,`${t}="${o}"
1963
+ `)}async function Io(e,t,o){let n=zt.join(e,"packages","search");if(t==="none"){ae.existsSync(n)&&ae.rmSync(n,{recursive:!0,force:!0});return}let r=Po(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Rt.map(i=>i.id).join(", ")}`);ae.existsSync(n)&&(cs(e,r),ps(e,"SEARCH_PROVIDER",t))}import ce from"fs";import be from"path";function ls(e){let t=[be.join(e,"packages","db"),be.join(e,"apps","web")];for(let o of t){let n=be.join(o,"prisma","schema.prisma");if(ce.existsSync(n))return{packageDir:o,seedPath:be.join(o,"prisma","seed.ts"),packageJsonPath:be.join(o,"package.json")}}return null}function ds(e){try{let t=ce.readFileSync(e,"utf8"),o=new Set,n=/^\s*model\s+(\w+)\s*\{/gm,r=n.exec(t);for(;r;)o.add(r[1]),r=n.exec(t);return o}catch{return new Set}}function us(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1957
1964
  const admin = await prisma.user.create({
1958
1965
  data: {
1959
1966
  clerkId: "user_mock_admin",
@@ -1984,7 +1991,7 @@ export { default } from './mock-i18n';
1984
1991
  console.log("\\u2713 Created admin user:", admin.email);
1985
1992
  } catch (err) {
1986
1993
  console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
1987
- }`}function ci(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),s=ai(e,n),a=o?` let tenants: Array<{ id: string; name: string }> = [];
1994
+ }`}function ms(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),i=us(e,n),a=o?` let tenants: Array<{ id: string; name: string }> = [];
1988
1995
  try {
1989
1996
  tenants = await Promise.all([
1990
1997
  prisma.tenant.create({
@@ -2037,7 +2044,7 @@ async function main(): Promise<void> {
2037
2044
  ${a}
2038
2045
 
2039
2046
  // --- Admin user ------------------------------------------------------
2040
- ${s}
2047
+ ${i}
2041
2048
 
2042
2049
  // --- Sample projects per tenant --------------------------------------
2043
2050
  ${c}
@@ -2053,12 +2060,12 @@ main()
2053
2060
  .finally(async () => {
2054
2061
  await prisma.$disconnect();
2055
2062
  });
2056
- `}function pi(e){if(le.existsSync(e))try{let t=le.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let s=o.prisma??{};if(s.seed||(s.seed="tsx prisma/seed.ts",r=!0),!r)return;let a={...o,scripts:n,prisma:s};le.writeFileSync(e,JSON.stringify(a,null,2)+`
2057
- `)}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 Po(e,t){let o=si(e);if(o)try{let n=be.join(o.packageDir,"prisma","schema.prisma"),r=ii(n),s=ci(t,r),a=be.dirname(o.seedPath);le.existsSync(a)||le.mkdirSync(a,{recursive:!0}),le.writeFileSync(o.seedPath,s),pi(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 de from"fs";import Ie from"path";var xt=[{id:"twilio",name:"Twilio",region:"global",envVars:["TWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN","TWILIO_FROM_NUMBER"],docs:"https://www.twilio.com/docs/sms",pkgs:["twilio"]},{id:"messagebird",name:"MessageBird (Bird)",region:"global",envVars:["MESSAGEBIRD_ACCESS_KEY","MESSAGEBIRD_ORIGINATOR"],docs:"https://developers.messagebird.com/api/sms-messaging/",pkgs:["messagebird"]},{id:"plivo",name:"Plivo",region:"global",envVars:["PLIVO_AUTH_ID","PLIVO_AUTH_TOKEN","PLIVO_FROM_NUMBER"],docs:"https://www.plivo.com/docs/sms/",pkgs:["plivo"]},{id:"aliyun-sms",name:"\u963F\u91CC\u4E91\u77ED\u4FE1 Aliyun SMS",region:"cn",envVars:["ALIYUN_SMS_ACCESS_KEY","ALIYUN_SMS_ACCESS_SECRET","ALIYUN_SMS_SIGN_NAME","ALIYUN_SMS_TEMPLATE_CODE","ALIYUN_SMS_ENDPOINT"],docs:"https://help.aliyun.com/product/44282.html",pkgs:["@alicloud/dysmsapi20170525","@alicloud/openapi-client"]},{id:"tencent-sms",name:"\u817E\u8BAF\u4E91\u77ED\u4FE1 Tencent SMS",region:"cn",envVars:["TENCENT_SMS_SECRET_ID","TENCENT_SMS_SECRET_KEY","TENCENT_SMS_SDK_APP_ID","TENCENT_SMS_SIGN_NAME","TENCENT_SMS_TEMPLATE_ID","TENCENT_SMS_REGION"],docs:"https://cloud.tencent.com/document/product/382",pkgs:["tencentcloud-sdk-nodejs-sms"]},{id:"yunpian",name:"\u4E91\u7247 Yunpian",region:"cn",envVars:["YUNPIAN_API_KEY","YUNPIAN_SIGN"],docs:"https://www.yunpian.com/official/document/sms/zh_CN/introduction_product_intro",pkgs:["yunpian-nodejs-sdk"]},{id:"none",name:"None",region:"both",envVars:[],docs:""}],Ep=xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function bo(e){return xt.find(t=>t.id===e)}var li="@nebutra/sms",di={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 Xt(e,t){de.mkdirSync(Ie.dirname(e),{recursive:!0}),de.writeFileSync(e,t)}function ui(e,t){let o=Ie.join(e,".env.example");de.existsSync(o)?de.appendFileSync(o,`
2058
- `+t):de.writeFileSync(o,t)}function mi(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2063
+ `}function gs(e){if(ce.existsSync(e))try{let t=ce.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let i=o.prisma??{};if(i.seed||(i.seed="tsx prisma/seed.ts",r=!0),!r)return;let a={...o,scripts:n,prisma:i};ce.writeFileSync(e,JSON.stringify(a,null,2)+`
2064
+ `)}catch(t){let o=t instanceof Error?t.message:String(t);console.warn(`[create-sailor] Failed to patch seed scripts in ${e}: ${o}`)}}async function Ao(e,t){let o=ls(e);if(o)try{let n=be.join(o.packageDir,"prisma","schema.prisma"),r=ds(n),i=ms(t,r),a=be.dirname(o.seedPath);ce.existsSync(a)||ce.mkdirSync(a,{recursive:!0}),ce.writeFileSync(o.seedPath,i),gs(o.packageJsonPath)}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate seed data: ${r}`),new Error(`Unable to write prisma/seed.ts: ${r}`)}}import pe from"fs";import Ie from"path";var xt=[{id:"twilio",name:"Twilio",region:"global",envVars:["TWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN","TWILIO_FROM_NUMBER"],docs:"https://www.twilio.com/docs/sms",pkgs:["twilio"]},{id:"messagebird",name:"MessageBird (Bird)",region:"global",envVars:["MESSAGEBIRD_ACCESS_KEY","MESSAGEBIRD_ORIGINATOR"],docs:"https://developers.messagebird.com/api/sms-messaging/",pkgs:["messagebird"]},{id:"plivo",name:"Plivo",region:"global",envVars:["PLIVO_AUTH_ID","PLIVO_AUTH_TOKEN","PLIVO_FROM_NUMBER"],docs:"https://www.plivo.com/docs/sms/",pkgs:["plivo"]},{id:"aliyun-sms",name:"\u963F\u91CC\u4E91\u77ED\u4FE1 Aliyun SMS",region:"cn",envVars:["ALIYUN_SMS_ACCESS_KEY","ALIYUN_SMS_ACCESS_SECRET","ALIYUN_SMS_SIGN_NAME","ALIYUN_SMS_TEMPLATE_CODE","ALIYUN_SMS_ENDPOINT"],docs:"https://help.aliyun.com/product/44282.html",pkgs:["@alicloud/dysmsapi20170525","@alicloud/openapi-client"]},{id:"tencent-sms",name:"\u817E\u8BAF\u4E91\u77ED\u4FE1 Tencent SMS",region:"cn",envVars:["TENCENT_SMS_SECRET_ID","TENCENT_SMS_SECRET_KEY","TENCENT_SMS_SDK_APP_ID","TENCENT_SMS_SIGN_NAME","TENCENT_SMS_TEMPLATE_ID","TENCENT_SMS_REGION"],docs:"https://cloud.tencent.com/document/product/382",pkgs:["tencentcloud-sdk-nodejs-sms"]},{id:"yunpian",name:"\u4E91\u7247 Yunpian",region:"cn",envVars:["YUNPIAN_API_KEY","YUNPIAN_SIGN"],docs:"https://www.yunpian.com/official/document/sms/zh_CN/introduction_product_intro",pkgs:["yunpian-nodejs-sdk"]},{id:"none",name:"None",region:"both",envVars:[],docs:""}],Cp=xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Co(e){return xt.find(t=>t.id===e)}var fs="@nebutra/sms",ys={twilio:"^5.3.6",messagebird:"^4.0.1",plivo:"^4.73.0","@alicloud/dysmsapi20170525":"^2.0.24","@alicloud/openapi-client":"^0.4.12","tencentcloud-sdk-nodejs-sms":"^4.0.970","yunpian-nodejs-sdk":"^0.0.2"};function Qt(e,t){pe.mkdirSync(Ie.dirname(e),{recursive:!0}),pe.writeFileSync(e,t)}function Ss(e,t){let o=Ie.join(e,".env.example");pe.existsSync(o)?pe.appendFileSync(o,`
2065
+ `+t):pe.writeFileSync(o,t)}function Es(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2059
2066
  `);return`${t}
2060
2067
  ${o}
2061
- `}var gi=`/**
2068
+ `}var hs=`/**
2062
2069
  * Inputs for the \`sendSms\` wrapper. Keep this surface portable across
2063
2070
  * providers \u2014 provider-specific options belong in the wrapper itself.
2064
2071
  */
@@ -2078,7 +2085,7 @@ export interface SendSmsResult {
2078
2085
  provider: string;
2079
2086
  raw?: unknown;
2080
2087
  }
2081
- `;function fi(){return`import twilio from "twilio";
2088
+ `;function vs(){return`import twilio from "twilio";
2082
2089
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2083
2090
 
2084
2091
  let client: ReturnType<typeof twilio> | null = null;
@@ -2113,7 +2120,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2113
2120
  }
2114
2121
 
2115
2122
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2116
- `}function yi(){return`import messagebird from "messagebird";
2123
+ `}function _s(){return`import messagebird from "messagebird";
2117
2124
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2118
2125
 
2119
2126
  let client: ReturnType<typeof messagebird> | null = null;
@@ -2151,7 +2158,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2151
2158
  }
2152
2159
 
2153
2160
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2154
- `}function Si(){return`import plivo from "plivo";
2161
+ `}function Ps(){return`import plivo from "plivo";
2155
2162
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2156
2163
 
2157
2164
  let client: InstanceType<typeof plivo.Client> | null = null;
@@ -2190,7 +2197,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2190
2197
  }
2191
2198
 
2192
2199
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2193
- `}function hi(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
2200
+ `}function bs(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
2194
2201
  import * as $OpenApi from "@alicloud/openapi-client";
2195
2202
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2196
2203
 
@@ -2239,7 +2246,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2239
2246
  }
2240
2247
 
2241
2248
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2242
- `}function Ei(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
2249
+ `}function Is(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
2243
2250
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2244
2251
 
2245
2252
  const SmsClient = tencentcloud.sms.v20210111.Client;
@@ -2304,7 +2311,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2304
2311
  }
2305
2312
 
2306
2313
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2307
- `}function vi(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
2314
+ `}function As(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
2308
2315
  import Yunpian from "yunpian-nodejs-sdk";
2309
2316
  import type { SendSmsInput, SendSmsResult } from "./types.js";
2310
2317
 
@@ -2356,13 +2363,13 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2356
2363
  }
2357
2364
 
2358
2365
  export type { SendSmsInput, SendSmsResult } from "./types.js";
2359
- `}function _i(e){switch(e){case"twilio":return fi();case"messagebird":return yi();case"plivo":return Si();case"aliyun-sms":return hi();case"tencent-sms":return Ei();case"yunpian":return vi();case"none":return`export {};
2360
- `}}function Pi(e){let t={};for(let n of e.pkgs??[]){let r=di[n];r&&(t[n]=r)}let o={name:li,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)+`
2361
- `}async function Io(e,t,o="global"){if(t==="none")return;let n=bo(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${xt.map(a=>a.id).join(", ")}`);let r=Ie.join(e,"packages","sms");if(!de.existsSync(r))return;let s=Ie.join(r,"src");de.existsSync(s)&&de.rmSync(s,{recursive:!0,force:!0});try{Xt(Ie.join(r,"package.json"),Pi(n)),Xt(Ie.join(s,"types.ts"),gi),Xt(Ie.join(s,"index.ts"),_i(n.id)),ui(e,mi(n))}catch(a){throw console.error(`Failed to apply SMS selection "${t}":`,a),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import Ae from"fs";import Ce from"path";var kt=[{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 Co(e){return kt.find(t=>t.id===e)}var Cp=kt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var we="@nebutra/storage";function zt(e,t){Ae.mkdirSync(Ce.dirname(e),{recursive:!0}),Ae.writeFileSync(e,t)}function bi(e,t){let o=Ce.join(e,".env.example");Ae.existsSync(o)?Ae.appendFileSync(o,`
2362
- `+t):Ae.writeFileSync(o,t)}function Ii(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2366
+ `}function Cs(e){switch(e){case"twilio":return vs();case"messagebird":return _s();case"plivo":return Ps();case"aliyun-sms":return bs();case"tencent-sms":return Is();case"yunpian":return As();case"none":return`export {};
2367
+ `}}function ws(e){let t={};for(let n of e.pkgs??[]){let r=ys[n];r&&(t[n]=r)}let o={name:fs,version:"0.1.0",private:!0,description:`Transactional SMS via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
2368
+ `}async function wo(e,t,o="global"){if(t==="none")return;let n=Co(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${xt.map(a=>a.id).join(", ")}`);let r=Ie.join(e,"packages","sms");if(!pe.existsSync(r))return;let i=Ie.join(r,"src");pe.existsSync(i)&&pe.rmSync(i,{recursive:!0,force:!0});try{Qt(Ie.join(r,"package.json"),ws(n)),Qt(Ie.join(i,"types.ts"),hs),Qt(Ie.join(i,"index.ts"),Cs(n.id)),Ss(e,Es(n))}catch(a){throw console.error(`Failed to apply SMS selection "${t}":`,a),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import Ce from"fs";import Ae from"path";var pt=[{id:"r2",name:"Cloudflare R2",region:"global",envVars:["R2_ACCOUNT_ID","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY","R2_BUCKET"],docs:"https://developers.cloudflare.com/r2/api/s3/api/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"s3",name:"AWS S3",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_S3_REGION","S3_BUCKET"],docs:"https://docs.aws.amazon.com/s3/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"supabase-storage",name:"Supabase Storage",region:"global",envVars:["SUPABASE_URL","SUPABASE_SERVICE_ROLE_KEY","SUPABASE_BUCKET"],docs:"https://supabase.com/docs/guides/storage",pkg:"@supabase/supabase-js",pkgVersion:"^2.45.4"},{id:"aliyun-oss",name:"\u963F\u91CC\u4E91 OSS",region:"cn",envVars:["ALIYUN_OSS_ACCESS_KEY","ALIYUN_OSS_ACCESS_SECRET","ALIYUN_OSS_REGION","ALIYUN_OSS_BUCKET"],docs:"https://help.aliyun.com/product/31815.html",pkg:"ali-oss",pkgVersion:"^6.21.0"},{id:"tencent-cos",name:"\u817E\u8BAF\u4E91 COS",region:"cn",envVars:["TENCENT_COS_SECRET_ID","TENCENT_COS_SECRET_KEY","TENCENT_COS_BUCKET","TENCENT_COS_REGION"],docs:"https://cloud.tencent.com/document/product/436",pkg:"cos-nodejs-sdk-v5",pkgVersion:"^2.13.7"},{id:"qiniu",name:"\u4E03\u725B\u4E91 Kodo",region:"cn",envVars:["QINIU_ACCESS_KEY","QINIU_SECRET_KEY","QINIU_BUCKET","QINIU_DOMAIN"],docs:"https://developer.qiniu.com/kodo",pkg:"qiniu",pkgVersion:"^7.14.0"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function Jt(e){let t=e==="supabase"?"supabase-storage":e;return pt.some(o=>o.id===t)?t:void 0}function Ro(e){let t=Jt(e);return t?pt.find(o=>o.id===t):void 0}var Tp=pt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var we="@nebutra/storage";function Zt(e,t){Ce.mkdirSync(Ae.dirname(e),{recursive:!0}),Ce.writeFileSync(e,t)}function Rs(e,t){let o=Ae.join(e,".env.example");Ce.existsSync(o)?Ce.appendFileSync(o,`
2369
+ `+t):Ce.writeFileSync(o,t)}function xs(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2363
2370
  `);return`${t}
2364
2371
  ${o}
2365
- `}var Ci=`/**
2372
+ `}var Ns=`/**
2366
2373
  * Inputs for the \`uploadFile\` wrapper. Keep this surface portable across
2367
2374
  * providers \u2014 provider-specific options belong in the wrapper itself.
2368
2375
  */
@@ -2388,7 +2395,7 @@ export interface SignedUrlOptions {
2388
2395
  operation?: "get" | "put";
2389
2396
  contentType?: string;
2390
2397
  }
2391
- `;function Ai(){return`/**
2398
+ `;function ks(){return`/**
2392
2399
  * @${we.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
2393
2400
  *
2394
2401
  * Docs: https://developers.cloudflare.com/r2/api/s3/api/
@@ -2452,7 +2459,7 @@ export async function getSignedUrl(
2452
2459
  }
2453
2460
 
2454
2461
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2455
- `}function wi(){return`/**
2462
+ `}function Ts(){return`/**
2456
2463
  * @${we.slice(1)} \u2014 AWS S3 wrapper.
2457
2464
  *
2458
2465
  * Docs: https://docs.aws.amazon.com/s3/
@@ -2517,7 +2524,7 @@ export async function getSignedUrl(
2517
2524
  }
2518
2525
 
2519
2526
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2520
- `}function Ri(){return`/**
2527
+ `}function Os(){return`/**
2521
2528
  * @${we.slice(1)} \u2014 Supabase Storage wrapper.
2522
2529
  *
2523
2530
  * Docs: https://supabase.com/docs/guides/storage
@@ -2580,7 +2587,7 @@ export async function getSignedUrl(
2580
2587
  }
2581
2588
 
2582
2589
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2583
- `}function Ni(){return`/**
2590
+ `}function Us(){return`/**
2584
2591
  * @${we.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
2585
2592
  *
2586
2593
  * Docs: https://help.aliyun.com/product/31815.html
@@ -2627,7 +2634,7 @@ export async function getSignedUrl(
2627
2634
  }
2628
2635
 
2629
2636
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2630
- `}function xi(){return`/**
2637
+ `}function Ls(){return`/**
2631
2638
  * @${we.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
2632
2639
  *
2633
2640
  * Docs: https://cloud.tencent.com/document/product/436
@@ -2682,7 +2689,7 @@ export async function getSignedUrl(
2682
2689
  }
2683
2690
 
2684
2691
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2685
- `}function ki(){return`/**
2692
+ `}function Ms(){return`/**
2686
2693
  * @${we.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
2687
2694
  *
2688
2695
  * Docs: https://developer.qiniu.com/kodo
@@ -2750,9 +2757,9 @@ export async function getSignedUrl(
2750
2757
  }
2751
2758
 
2752
2759
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
2753
- `}function Ti(e){switch(e){case"r2":return Ai();case"s3":return wi();case"supabase-storage":return Ri();case"aliyun-oss":return Ni();case"tencent-cos":return xi();case"qiniu":return ki();case"none":return`export {};
2754
- `}}function Oi(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),(e.id==="r2"||e.id==="s3")&&(t["@aws-sdk/s3-request-presigner"]="^3.658.0");let o={name:we,version:"0.1.0",private:!0,description:`Object storage via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
2755
- `}async function Ao(e,t,o){if(t==="none")return;let n=Co(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${kt.map(a=>a.id).join(", ")}`);let r=Ce.join(e,"packages","storage"),s=Ce.join(r,"src");Ae.existsSync(s)&&Ae.rmSync(s,{recursive:!0,force:!0}),zt(Ce.join(r,"package.json"),Oi(n)),zt(Ce.join(s,"types.ts"),Ci),zt(Ce.join(s,"index.ts"),Ti(n.id)),bi(e,Ii(n))}var Tt=[{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 wo(e){return Tt.find(t=>t.id===e)}var kp=Tt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Ro(e,t,o="global"){let n=wo(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Tt.map(r=>r.id).join(", ")}`);if(n.id==="none"){B(e,"webhooks");return}n.envVars.length>0&&G(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),H(e,"WEBHOOKS_PROVIDER",n.id)}import Re from"fs";import lt from"path";function Ui(e){return`import Link from "next/link";
2760
+ `}function Ds(e){switch(e){case"r2":return ks();case"s3":return Ts();case"supabase-storage":return Os();case"aliyun-oss":return Us();case"tencent-cos":return Ls();case"qiniu":return Ms();case"none":return`export {};
2761
+ `}}function Fs(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),(e.id==="r2"||e.id==="s3")&&(t["@aws-sdk/s3-request-presigner"]="^3.658.0");let o={name:we,version:"0.1.0",private:!0,description:`Object storage via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
2762
+ `}async function xo(e,t,o){if(t==="none")return;let n=Ro(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${pt.map(a=>a.id).join(", ")}`);let r=Ae.join(e,"packages","storage"),i=Ae.join(r,"src");Ce.existsSync(i)&&Ce.rmSync(i,{recursive:!0,force:!0}),Zt(Ae.join(r,"package.json"),Fs(n)),Zt(Ae.join(i,"types.ts"),Ns),Zt(Ae.join(i,"index.ts"),Ds(n.id)),Rs(e,xs(n))}var Nt=[{id:"svix",name:"Svix",region:"global",envVars:["SVIX_API_TOKEN"],docs:"https://docs.svix.com",description:"Managed webhooks platform"},{id:"custom",name:"Custom (self-hosted)",region:"both",envVars:["WEBHOOK_SIGNING_SECRET"],docs:"",description:"Custom implementation with built-in package"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function No(e){return Nt.find(t=>t.id===e)}var Fp=Nt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ko(e,t,o="global"){let n=No(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Nt.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"webhooks");return}n.envVars.length>0&&q(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"WEBHOOKS_PROVIDER",n.id)}import Re from"fs";import lt from"path";function js(e){return`import Link from "next/link";
2756
2763
 
2757
2764
  export default function WelcomePage() {
2758
2765
  const projectName = ${JSON.stringify(e)};
@@ -2861,7 +2868,7 @@ function Step({
2861
2868
  </li>
2862
2869
  );
2863
2870
  }
2864
- `}function Li(e,t){return`# Next steps \u2014 ${e}
2871
+ `}function Vs(e,t){return`# Next steps \u2014 ${e}
2865
2872
 
2866
2873
  Region: ${t}
2867
2874
 
@@ -2893,26 +2900,26 @@ After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
2893
2900
  - [Documentation](/docs)
2894
2901
  - [GitHub](https://github.com/nebutra/nebutra-sailor)
2895
2902
  - [Get free license (Individual/OPC)](https://nebutra.com/get-license)
2896
- `}async function No(e,t){let{projectName:o,region:n}=t;try{let r=lt.join(e,".sailor");Re.existsSync(r)||Re.mkdirSync(r,{recursive:!0}),Re.writeFileSync(lt.join(r,"next-steps.md"),Li(o,n))}catch(r){let s=r instanceof Error?r.message:String(r);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${s}`)}try{let r=lt.join(e,"apps","web");if(!Re.existsSync(r))return;let s=lt.join(r,"src","app","[locale]","welcome");Re.existsSync(s)||Re.mkdirSync(s,{recursive:!0}),Re.writeFileSync(lt.join(s,"page.tsx"),Ui(o))}catch(r){let s=r instanceof Error?r.message:String(r);console.warn(`[create-sailor] Failed to write welcome page: ${s}`)}}var xo="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2897
- `)}function Fi(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function ko(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 To(e){return e==="drizzle"?"drizzle":e==="none"?"none":"prisma"}function Oo(e){return e==="lemon"||e==="lemonsqueezy"?"lemonsqueezy":e==="none"?"none":"stripe"}function Uo(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 Lo(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="none"?"none":"clerk"}function Mo(e){if(!e)return["openai"];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}var Do={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Fo(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in Do){let n=Do[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(R.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
2898
- `)+R.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
2899
- `)),"fumadocs"}return"fumadocs"}function jo(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 Vo(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function ji(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 Ko(e){return e==="cn"?"wechat":"stripe"}async function Vi(){let e=new Mi;e.name(xo).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ne,"-v, --version").helpOption(!1).argument("[name]","project directory",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--region <id>","global | cn | hybrid").option("--orm <id>","prisma | drizzle | none").option("--db <id>","postgres | mysql | sqlite | none").option("--auth <id>","clerk | betterauth | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <ids>","comma-separated provider ids").option("--deploy <target>","vercel | railway | cloudflare | selfhost").option("--docs <id>","fumadocs | mintlify | docusaurus | nextra | vitepress | none").option("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | none").option("--queue <id>","qstash | bullmq | upstash | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").option("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--no-install","skip package install").option("--no-git","skip git init").option("-y, --yes","accept all defaults (non-interactive)").option("--dry-run","preview actions without writing files").option("--json","machine-readable output").option("--no-color","disable color output").option("-h, --help","show help"),e.parse(process.argv);let t=e.opts(),[o]=e.args;t.help&&(on(),process.exit(0));let n=!!t.json,r=!!t.dryRun,s=!!t.yes,a=s||!process.stdin.isTTY;n||en(),p(n,{event:"start",version:ne});let c=o??(s?"./my-saas-app":void 0),i;if(c)i=c;else if(a)i="./my-saas-app";else{let m=await C.group({name:()=>C.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:y=>{if(y.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(R.red(`\u2718 Cancelled
2900
- `)),process.exit(130)}});i=String(m.name)}let d=dt.basename(dt.resolve(i)),u=t.pm??Fi(),S=!!t.region,U=!!t.auth,F=!!t.payment,ee=!!t.ai,Xe=!!t.email,h=!!t.storage,l=!!t.monitoring,N=!!t.analytics,ut=!!t.sms,Qt=t.i18n!==void 0,f,ze,z,Qe,j,k,$=fn(t.socialLogin),te,Ne,Q,V,mt;if(a){f=Vo(t.region),ze=To(t.orm),z=ko(t.db);let m=F?t.payment:Ko(f);Qe=Oo(m),j=Uo(m),k=Lo(t.auth),te=Mo(t.ai),Q=jo(t.deploy),V=Fo(t.docs,n),mt=Qt?!!t.i18n:!0}else{let m={};if(S||(m.region=()=>C.select({message:"Target region?",options:[{value:"global",label:"global \u2014 \u6D77\u5916\u4F18\u5148"},{value:"cn",label:"cn \u2014 \u56FD\u5185\u4F18\u5148"},{value:"hybrid",label:"hybrid \u2014 \u53CC\u8F68\uFF08\u56FD\u5185+\u51FA\u6D77\uFF09"}],initialValue:"global"})),U||(m.auth=()=>C.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk"},{value:"betterauth",label:"Better Auth"},{value:"none",label:"None"}],initialValue:"clerk"})),!ee){let yt=Array.from(new Set(Et.map(w=>w.category)));m.aiCategories=()=>C.multiselect({message:"Which AI Provider categories do you want to explore? (Select multiple)",options:yt.map(w=>({value:w,label:w})),initialValues:["\u76F4\u63A5\u5B9E\u9A8C\u5BA4","\u7EDF\u4E00\u7F51\u5173"]}),m.aiProviders=({results:w})=>{let $e=w.aiCategories||[],_=Et.filter(K=>$e.includes(K.category)).map(K=>({value:K.id,label:`[${K.category}] ${K.name}`}));return _.push({value:"custom",label:"[\u81EA\u5B9A\u4E49] Custom OpenAI-compatible endpoint"}),C.multiselect({message:"Select AI Providers (Space to select, Enter to submit)",options:_,initialValues:["openai","anthropic"],required:!1})},m.enableCustom=({results:w})=>w.aiProviders?.includes("custom")?C.confirm({message:"Configure custom OpenAI-compatible endpoint?",initialValue:!0}):Promise.resolve(!1),m.customAiName=({results:w})=>w.enableCustom?C.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),m.customAiBaseUrl=({results:w})=>w.enableCustom?C.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:$e=>{if($e.length===0)return"Base URL is required."}}):Promise.resolve(void 0),m.customAiApiKeyEnv=({results:w})=>w.enableCustom?C.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0)}let y=Object.keys(m).length>0?await C.group(m,{onCancel:()=>{process.stdout.write(R.red(`\u2718 Cancelled
2901
- `)),process.exit(130)}}):{};f=Vo(S?t.region:y.region),ze=To(t.orm),z=ko(t.db);let L=F?t.payment:Ko(f);Qe=Oo(L),j=Uo(L),k=Lo(U?t.auth:y.auth),te=ee?Mo(t.ai):y.aiProviders?.filter(yt=>yt!=="custom")??[],y.enableCustom&&(Ne={name:y.customAiName,baseURL:y.customAiBaseUrl,apiKeyEnvName:y.customAiApiKeyEnv}),Q=jo(t.deploy),V=Fo(t.docs,n),mt=Qt?!!t.i18n:!0}let P=ji(f),xe=Xe?t.email:P.email,ke=h?t.storage:P.storage,Te=l?t.monitoring:P.monitoring,Oe=N?t.analytics:P.analytics,Ue=ut?t.sms:P.sms,Le=t.queue??P.queue,Me=t.search??P.search,Je=t.cache??P.cache,De=t.notifications??P.notifications,Fe=t.webhooks??P.webhooks,Ze=t.cms??P.cms,je=t.featureFlags??P.featureFlags,Ve=t.captcha??P.captcha,gt=t.mcp??P.mcp,et=t.metering??P.metering,Ke=t.billingMode??P.billingMode,Be=t.idp??P.idp,tt=tn([{flag:"queue",provider:Le},{flag:"search",provider:Me},{flag:"notifications",provider:De},{flag:"webhooks",provider:Fe},{flag:"feature-flags",provider:je},{flag:"captcha",provider:Ve}]);function Ut(){for(let m of tt)if(n)p(!0,{event:"warn",step:m.flag,provider:m.provider,packageStatus:m.status,message:qe(m.status)});else{let y=St(m.status);process.stdout.write(R.yellow(`\u26A0 ${m.flag}=${m.provider} ${y} \u2014 ${qe(m.status)}
2902
- `))}}let Ye={region:f,orm:ze,database:z,payment:Qe,aiProviders:te,customAiEndpoint:Ne,deployTarget:Q,docs:V,i18n:mt,email:xe,storage:ke,monitoring:Te,analytics:Oe,sms:Ue,queue:Le,search:Me,cache:Je,notifications:De,webhooks:Fe,cms:Ze,featureFlags:je,captcha:Ve,mcp:gt,metering:et,billingMode:Ke,idp:Be},ft=[["Project name",d],["Region",f],["Auth",k],["Social login",$.length>0?$.map(m=>nt.find(y=>y.id===m)?.name??m).join(", "):"none"],["ORM",ze],["Database",z],["Payment",j],["AI",Array.isArray(te)?te.join(", ")+(Ne?", custom":""):String(te)],["Email",xe],["Storage",ke],["Monitoring",Te],["Analytics",Oe],["SMS",Ue],["Deploy Target",Q],["Docs Framework",V]];n?ft.forEach(([m,y],L)=>{p(!0,{event:"step",step:m,value:y,index:L+1,total:ft.length})}):ft.forEach(([m,y],L)=>{sn({index:L+1,total:ft.length,label:m,value:y})});let Bo={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},Jt=Date.now();if(r){let m=te.length,y=[`clone template \u2192 ${i}`,"write nebutra.config.json",`prune template (orm=${ze}, i18n=${mt})`,`region \u2192 ${f}`,`auth \u2192 ${k==="none"?"skip (remove packages/auth)":`configure ${k}`}`,...$.length>0?[`social-login \u2192 generate ${$.length} callback route${$.length===1?"":"s"} + SocialLoginButtons.tsx (${$.join(", ")})`]:[],`db \u2192 ${z==="none"?"skip (remove packages/db)":`configure Prisma for ${z}`}`,`payment \u2192 ${j==="none"?"skip (remove packages/billing)":`configure ${j}`}`,...V!=="none"?[`docs \u2192 scaffold apps/docs (${V==="fumadocs"?"fumadocs":`${V} \u2192 fumadocs fallback`})`]:[],...m>0||Ne?[`ai-providers \u2192 generate registry.ts + env (${m}${Ne?" + custom":""} provider${m===1&&!Ne?"":"s"})`]:[],...xe!=="none"?[`email \u2192 configure ${xe}`]:[],...ke!=="none"?[`storage \u2192 configure ${ke}`]:[],...Te!=="none"?[`monitoring \u2192 configure ${Te}`]:[],...Oe!=="none"?[`analytics \u2192 configure ${Oe}`]:[],...Ue!=="none"?[`sms \u2192 configure ${Ue}`]:[],...Le!=="none"?[`queue \u2192 configure ${Le}`]:[],...Me!=="none"?[`search \u2192 configure ${Me}`]:[],...Je!=="none"?[`cache \u2192 configure ${Je}`]:[],...De!=="none"?[`notifications \u2192 configure ${De}`]:[],...Fe!=="none"?[`webhooks \u2192 configure ${Fe}`]:[],...Ze!=="none"?[`cms \u2192 configure ${Ze}`]:[],...je!=="none"?[`feature-flags \u2192 configure ${je}`]:[],...Ve!=="none"?[`captcha \u2192 configure ${Ve}`]:[],`mcp \u2192 ${gt==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${et==="off"?"disabled":et==="auto"?Qe!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...Ke!=="usage"?[`billing-mode \u2192 ${Ke}`]:[],...Be!=="clerk"?[`idp \u2192 ${Be}`]:[],`compliance \u2192 inject ${f} boilerplate (ICP/Cookie/AIGC/Privacy)`,"welcome \u2192 generate dev welcome page","env \u2192 generate random secrets (AUTH_SECRET, JWT_SECRET)","seed \u2192 generate prisma/seed.ts (1 admin + 3 tenants)",...Q!=="none"?[`deploy \u2192 inject ${Q} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${u} install`,t.git===!1?"skip git init":"run git init"];if(n)y.forEach(L=>p(!0,{event:"plan",action:L})),Ut(),p(!0,{event:"done",dryRun:!0});else{process.stdout.write(`
2903
- `+R.bold(`Dry run \u2014 planned actions:
2904
- `));for(let L of y)process.stdout.write(` \u2022 ${L}
2905
- `);tt.length>0&&(process.stdout.write(`
2906
- `+R.bold(R.yellow(`Preview-status providers selected:
2907
- `))),Ut()),process.stdout.write(R.dim(`
2903
+ `}async function To(e,t){let{projectName:o,region:n}=t;try{let r=lt.join(e,".sailor");Re.existsSync(r)||Re.mkdirSync(r,{recursive:!0}),Re.writeFileSync(lt.join(r,"next-steps.md"),Vs(o,n))}catch(r){let i=r instanceof Error?r.message:String(r);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${i}`)}try{let r=lt.join(e,"apps","web");if(!Re.existsSync(r))return;let i=lt.join(r,"src","app","[locale]","welcome");Re.existsSync(i)||Re.mkdirSync(i,{recursive:!0}),Re.writeFileSync(lt.join(i,"page.tsx"),js(o))}catch(r){let i=r instanceof Error?r.message:String(r);console.warn(`[create-sailor] Failed to write welcome page: ${i}`)}}var Oo="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2904
+ `)}function Ys(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function Uo(e){switch(e){case"postgres":case"postgresql":return"postgresql";case"mysql":return"mysql";case"sqlite":return"sqlite";case"none":return"none";default:return"postgresql"}}function Lo(e){return e==="drizzle"?"drizzle":e==="none"?"none":"prisma"}function Mo(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function Do(e){if(!e)return"stripe";let t=e.toLowerCase();return t==="lemon"||t==="lemonsqueezy"?"lemon":t==="wechat"?"wechat":t==="alipay"?"alipay":t==="none"?"none":"stripe"}function Fo(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="none"?"none":"clerk"}function jo(e){if(!e)return["openai"];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}function $s(e,t){let o=e??t;return Jt(o)??o}var Vo={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Ko(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in Vo){let n=Vo[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(w.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
2905
+ `)+w.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
2906
+ `)),"fumadocs"}return"fumadocs"}function Bo(e){switch(e){case"vercel":return"vercel";case"railway":return"railway";case"cloudflare":return"cloudflare";case"selfhost":return"selfhost";case"none":return"none";default:return"vercel"}}function Yo(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function qs(e){return{...e==="cn"?{email:"aliyun-dm",storage:"aliyun-oss",monitoring:"sentry",analytics:"baidu",sms:"aliyun-sms"}:e==="hybrid"?{email:"resend",storage:"aliyun-oss",monitoring:"sentry",analytics:"posthog",sms:"aliyun-sms"}:{email:"resend",storage:"r2",monitoring:"sentry",analytics:"posthog",sms:"twilio"},queue:"none",search:"none",cache:e==="global"?"upstash-redis":e==="cn"?"redis":"upstash-redis",notifications:"none",webhooks:"none",cms:"none",featureFlags:"none",captcha:e==="cn"?"aliyun-slide":"turnstile",mcp:"on",metering:"auto",billingMode:"usage",idp:"clerk"}}function $o(e){return e==="cn"?"wechat":"stripe"}async function Gs(){let e=new Ks;e.name(Oo).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ee,"-v, --version").helpOption(!1).argument("[name]","project directory",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--region <id>","global | cn | hybrid").option("--orm <id>","prisma | drizzle | none").option("--db <id>","postgres | mysql | sqlite | none").option("--auth <id>","clerk | betterauth | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <ids>","expert: comma-separated provider ids used as an AI provider seed").option("--deploy <target>","vercel | railway | cloudflare | selfhost").option("--docs <id>","fumadocs | mintlify | docusaurus | nextra | vitepress | none").option("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | none").option("--queue <id>","qstash | bullmq | upstash | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").option("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--no-install","skip package install").option("--no-git","skip git init").option("-y, --yes","accept all defaults (non-interactive)").option("--dry-run","preview actions without writing files").option("--json","machine-readable output").option("--no-color","disable color output").option("-h, --help","show help"),e.parse(process.argv);let t=e.opts(),[o]=e.args;t.help&&(an(),process.exit(0));let n=!!t.json,r=!!t.dryRun,i=!!t.yes,a=i||!process.stdin.isTTY;n||on(),p(n,{event:"start",version:ee});let c=o??(i?"./my-saas-app":void 0),s;if(c)s=c;else if(a)s="./my-saas-app";else{let m=await C.group({name:()=>C.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:f=>{if(f.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(w.red(`\u2718 Cancelled
2907
+ `)),process.exit(130)}});s=String(m.name)}let d=dt.basename(dt.resolve(s)),u=t.pm??Ys(),h=!!t.region,O=!!t.auth,M=!!t.payment,D=!!t.ai,He=!!t.email,v=!!t.storage,l=!!t.monitoring,R=!!t.analytics,ut=!!t.sms,en=t.i18n!==void 0,y,We,X,Xe,F,N,Y=En(t.socialLogin),ze,Tt,de,xe,z,j,mt;if(a){y=Yo(t.region),We=Lo(t.orm),X=Uo(t.db);let m=M?t.payment:$o(y);Xe=Mo(m),F=Do(m),N=Fo(t.auth);let f=Dt({mode:D?t.ai?.trim().toLowerCase()==="none"?"none":"direct":"gateway",providerIds:D?jo(t.ai):void 0});ze=f.mode,Tt=f.routing,de=f.providerIds,z=Bo(t.deploy),j=Ko(t.docs,n),mt=en?!!t.i18n:!0}else{let m={};h||(m.region=()=>C.select({message:"Target region?",options:[{value:"global",label:"global \u2014 \u6D77\u5916\u4F18\u5148"},{value:"cn",label:"cn \u2014 \u56FD\u5185\u4F18\u5148"},{value:"hybrid",label:"hybrid \u2014 \u53CC\u8F68\uFF08\u56FD\u5185+\u51FA\u6D77\uFF09"}],initialValue:"global"})),O||(m.auth=()=>C.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk"},{value:"betterauth",label:"Better Auth"},{value:"none",label:"None"}],initialValue:"clerk"})),D||(m.aiMode=()=>C.select({message:"AI topology?",options:[{value:"gateway",label:"Multi-provider AI Gateway / router",hint:"recommended"},{value:"direct",label:"Direct SDK/provider adapters"},{value:"custom",label:"OpenAI-compatible endpoint"},{value:"none",label:"Skip AI"}],initialValue:"gateway"}),m.aiProviders=({results:E})=>{if(E.aiMode!=="direct")return Promise.resolve([]);let Q=Mt.map(Ut=>({value:Ut.id,label:`[${Ut.category}] ${Ut.name}`}));return C.multiselect({message:"Select direct AI provider adapters (expert path)",options:Q,initialValues:["openai"],required:!1})},m.customAiName=({results:E})=>E.aiMode==="custom"?C.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),m.customAiBaseUrl=({results:E})=>E.aiMode==="custom"?C.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:Q=>{if(Q.length===0)return"Base URL is required."}}):Promise.resolve(void 0),m.customAiApiKeyEnv=({results:E})=>E.aiMode==="custom"?C.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0));let f=Object.keys(m).length>0?await C.group(m,{onCancel:()=>{process.stdout.write(w.red(`\u2718 Cancelled
2908
+ `)),process.exit(130)}}):{};y=Yo(h?t.region:f.region),We=Lo(t.orm),X=Uo(t.db);let V=M?t.payment:$o(y);Xe=Mo(V),F=Do(V),N=Fo(O?t.auth:f.auth);let yt=f.aiMode==="custom"?{name:f.customAiName??"custom",baseURL:f.customAiBaseUrl??"",apiKeyEnvName:f.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,S=Dt({mode:D?t.ai?.trim().toLowerCase()==="none"?"none":"direct":f.aiMode??"gateway",providerIds:D?jo(t.ai):f.aiProviders,customEndpoint:yt});ze=S.mode,Tt=S.routing,de=S.providerIds,S.customEndpoint&&(xe={name:S.customEndpoint.name,baseURL:S.customEndpoint.baseURL,apiKeyEnvName:S.customEndpoint.apiKeyEnvName}),z=Bo(t.deploy),j=Ko(t.docs,n),mt=en?!!t.i18n:!0}let b=qs(y),Ne=He?t.email:b.email,ke=$s(v?t.storage:void 0,b.storage),Te=l?t.monitoring:b.monitoring,Oe=R?t.analytics:b.analytics,Ue=ut?t.sms:b.sms,Le=t.queue??b.queue,Me=t.search??b.search,Qe=t.cache??b.cache,De=t.notifications??b.notifications,Fe=t.webhooks??b.webhooks,Je=t.cms??b.cms,je=t.featureFlags??b.featureFlags,Ve=t.captcha??b.captcha,gt=t.mcp??b.mcp,Ze=t.metering??b.metering,Ke=t.billingMode??b.billingMode,Be=t.idp??b.idp,et=rn([{flag:"queue",provider:Le},{flag:"search",provider:Me},{flag:"notifications",provider:De},{flag:"webhooks",provider:Fe},{flag:"feature-flags",provider:je},{flag:"captcha",provider:Ve}]);function Ot(){for(let m of et)if(n)p(!0,{event:"warn",step:m.flag,provider:m.provider,packageStatus:m.status,message:Ye(m.status)});else{let f=St(m.status);process.stdout.write(w.yellow(`\u26A0 ${m.flag}=${m.provider} ${f} \u2014 ${Ye(m.status)}
2909
+ `))}}let ue={region:y,orm:We,database:X,payment:Xe,aiMode:ze,aiRouting:Tt,aiProviders:de,customAiEndpoint:xe,deployTarget:z,docs:j,i18n:mt,email:Ne,storage:ke,monitoring:Te,analytics:Oe,sms:Ue,queue:Le,search:Me,cache:Qe,notifications:De,webhooks:Fe,cms:Je,featureFlags:je,captcha:Ve,mcp:gt,metering:Ze,billingMode:Ke,idp:Be},ft=[["Project name",d],["Region",y],["Auth",N],["Social login",Y.length>0?Y.map(m=>tt.find(f=>f.id===m)?.name??m).join(", "):"none"],["ORM",We],["Database",X],["Payment",F],["AI topology",`${ze}${de.length>0?` (${de.join(", ")} seed)`:""}${xe?" + custom endpoint":""}`],["Email",Ne],["Storage",ke],["Monitoring",Te],["Analytics",Oe],["SMS",Ue],["Deploy Target",z],["Docs Framework",j]];n?ft.forEach(([m,f],V)=>{p(!0,{event:"step",step:m,value:f,index:V+1,total:ft.length})}):ft.forEach(([m,f],V)=>{pn({index:V+1,total:ft.length,label:m,value:f})});let qo={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},tn=Date.now();if(r){let m=de.length,f=[`clone template \u2192 ${s}`,"write nebutra.config.json",`prune template (orm=${We}, i18n=${mt})`,`region \u2192 ${y}`,`auth \u2192 ${N==="none"?"skip (remove packages/auth)":`configure ${N}`}`,...Y.length>0?[`social-login \u2192 generate ${Y.length} callback route${Y.length===1?"":"s"} + SocialLoginButtons.tsx (${Y.join(", ")})`]:[],`db \u2192 ${X==="none"?"skip (remove packages/db)":`configure Prisma for ${X}`}`,`payment \u2192 ${F==="none"?"skip (remove packages/billing)":`configure ${F}`}`,...j!=="none"?[`docs \u2192 scaffold apps/docs (${j==="fumadocs"?"fumadocs":`${j} \u2192 fumadocs fallback`})`]:[],...m>0||xe?[`ai-providers \u2192 generate ${ze} registry seed + env (${m}${xe?" + custom":""} provider${m===1&&!xe?"":"s"})`]:[],...Ne!=="none"?[`email \u2192 configure ${Ne}`]:[],...ke!=="none"?[`storage \u2192 configure ${ke}`]:[],...Te!=="none"?[`monitoring \u2192 configure ${Te}`]:[],...Oe!=="none"?[`analytics \u2192 configure ${Oe}`]:[],...Ue!=="none"?[`sms \u2192 configure ${Ue}`]:[],...Le!=="none"?[`queue \u2192 configure ${Le}`]:[],...Me!=="none"?[`search \u2192 configure ${Me}`]:[],...Qe!=="none"?[`cache \u2192 configure ${Qe}`]:[],...De!=="none"?[`notifications \u2192 configure ${De}`]:[],...Fe!=="none"?[`webhooks \u2192 configure ${Fe}`]:[],...Je!=="none"?[`cms \u2192 configure ${Je}`]:[],...je!=="none"?[`feature-flags \u2192 configure ${je}`]:[],...Ve!=="none"?[`captcha \u2192 configure ${Ve}`]:[],`mcp \u2192 ${gt==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${Ze==="off"?"disabled":Ze==="auto"?Xe!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...Ke!=="usage"?[`billing-mode \u2192 ${Ke}`]:[],...Be!=="clerk"?[`idp \u2192 ${Be}`]:[],`compliance \u2192 inject ${y} boilerplate (ICP/Cookie/AIGC/Privacy)`,"welcome \u2192 generate dev welcome page","env \u2192 generate random secrets (AUTH_SECRET, JWT_SECRET)","seed \u2192 generate prisma/seed.ts (1 admin + 3 tenants)",...z!=="none"?[`deploy \u2192 inject ${z} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${u} install`,t.git===!1?"skip git init":"run git init"];if(n){for(let V of f)p(!0,{event:"plan",action:V});Ot(),p(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
2910
+ `+w.bold(`Dry run \u2014 planned actions:
2911
+ `));for(let V of f)process.stdout.write(` \u2022 ${V}
2912
+ `);et.length>0&&(process.stdout.write(`
2913
+ `+w.bold(w.yellow(`Preview-status providers selected:
2914
+ `))),Ot()),process.stdout.write(w.dim(`
2908
2915
  No files were written.
2909
- `))}process.exit(0)}let Yo=async()=>{process.stdout.write(`
2910
- `+R.red(`\u2718 Cancelled
2911
- `)),ue.existsSync(i)&&await C.confirm({message:`Cleanup partial install at ${i}?`,initialValue:!0})===!0&&(ue.rmSync(i,{recursive:!0,force:!0}),process.stdout.write(R.dim(` \u2713 Removed ${i}
2912
- `))),process.exit(130)};process.on("SIGINT",Yo);try{p(n,{event:"step",step:"clone",status:"start"}),await zn(i),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await so(i,d),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await An(i,Ye),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await fo(i,Ye),p(n,{event:"step",step:"prune",status:"ok"});let m=dt.join(i,"packages/db/prisma/schema.prisma");if(ue.existsSync(m)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let b=ue.readFileSync(m,"utf-8"),_=Gt(b,{auth:k,payment:j,"billing-mode":Ke,idp:Be,template:"saas"});ue.writeFileSync(m,_),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(b){let _=b instanceof Error?b.message:String(b);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:k,status:"start"}),await mn(i,k),p(n,{event:"step",step:"auth",choice:k,status:"ok"}),$.length>0?(p(n,{event:"step",step:"social-login",providers:$,status:"start"}),await Sn(i,$,k),p(n,{event:"step",step:"social-login",providers:$,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:z,status:"start"}),await Nn(i,z,d),p(n,{event:"step",step:"db",choice:z,status:"ok"}),p(n,{event:"step",step:"payment",choice:j,status:"start"}),await ao(i,j),p(n,{event:"step",step:"payment",choice:j,status:"ok"}),await Mn(i,xe,f),n&&p(!0,{event:"step",step:"email",choice:xe,status:"ok"}),await Ao(i,ke,f),n&&p(!0,{event:"step",step:"storage",choice:ke,status:"ok"}),await no(i,Te,f),n&&p(!0,{event:"step",step:"monitoring",choice:Te,status:"ok"}),await ln(i,Oe,f),n&&p(!0,{event:"step",step:"analytics",choice:Oe,status:"ok"}),await Io(i,Ue,f),n&&p(!0,{event:"step",step:"sms",choice:Ue,status:"ok"}),await ho(i,Le,f),n&&p(!0,{event:"step",step:"queue",choice:Le,status:"ok"}),await _o(i,Me,f),n&&p(!0,{event:"step",step:"search",choice:Me,status:"ok"}),await vn(i,Je,f),n&&p(!0,{event:"step",step:"cache",choice:Je,status:"ok"}),await ro(i,De,f),n&&p(!0,{event:"step",step:"notifications",choice:De,status:"ok"}),await Ro(i,Fe,f),n&&p(!0,{event:"step",step:"webhooks",choice:Fe,status:"ok"}),await In(i,Ze,f),n&&p(!0,{event:"step",step:"cms",choice:Ze,status:"ok"}),await Yn(i,je,f),n&&p(!0,{event:"step",step:"feature-flags",choice:je,status:"ok"}),await Pn(i,Ve,f),n&&p(!0,{event:"step",step:"captcha",choice:Ve,status:"ok"}),await Qn(i,gt),n&&p(!0,{event:"step",step:"mcp",mode:gt,status:"ok"}),await Zn(i,et,Qe),n&&p(!0,{event:"step",step:"metering",mode:et,status:"ok"}),Ye.orm==="prisma"&&Ye.database!=="none"){let b=dt.join(i,"packages/db/prisma/schema.prisma");if(ue.existsSync(b)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let _=ue.readFileSync(b,"utf8"),K=Gt(_,{auth:k,payment:j,"billing-mode":Ke,idp:Be,template:"saas"});ue.writeFileSync(b,K),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(_){let K=_ instanceof Error?_.message:String(_);p(n,{event:"step",step:"schema-prune",status:"error",error:K})}}else p(n,{event:"step",step:"schema-prune",status:"skip"})}else p(n,{event:"step",step:"schema-prune",status:"skip"});p(n,{event:"step",step:"billing-mode",choice:Ke,status:"ok"}),p(n,{event:"step",step:"idp",choice:Be,status:"ok"}),await Cn(i,f),n&&p(!0,{event:"step",step:"compliance",region:f,status:"ok"}),await Kn(i),await Po(i,k),await No(i,{projectName:d,region:f}),p(n,{event:"step",step:"ai-providers",status:"start"});let y={providerIds:Ye.aiProviders,customEndpoint:Ye.customAiEndpoint},L=dt.join(i,"packages/ai-providers/templates");if(await mo(i,y,L),p(n,{event:"step",step:"ai-providers",status:"ok"}),p(n,{event:"step",step:"docs",status:"start"}),V!=="none"?(await Tn(i,{framework:V,projectName:d}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:V,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),Q!=="none"&&await xn(i,Q),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await Fn(i,Bo),p(n,{event:"step",step:"env",status:"ok"}),t.install!==!1){let b=u==="bun"?"bun install":`${u} install`;n?p(!0,{event:"step",step:"install",pm:u,status:"start"}):process.stdout.write(R.dim(` Installing dependencies with ${u}\u2026
2913
- `));try{Ot(b,{cwd:i,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(_){let K=_ instanceof Error?_.message:String(_);n?p(!0,{event:"step",step:"install",status:"error",error:K}):process.stdout.write(R.yellow(` \u26A0 install failed \u2014 run '${b}' manually.
2914
- `))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{Ot("git init -q",{cwd:i,stdio:"ignore"}),Ot("git add -A",{cwd:i,stdio:"ignore"}),Ot('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:i,stdio:"ignore"}),p(n,{event:"step",step:"git-init",status:"ok"})}catch(b){let _=b instanceof Error?b.message:String(b);n?p(!0,{event:"step",step:"git-init",status:"error",error:_}):process.stdout.write(R.yellow(` \u26A0 git init skipped \u2014 not fatal.
2915
- `))}}else p(n,{event:"step",step:"git-init",status:"skip"});let $e=Math.max(1,Math.round((Date.now()-Jt)/1e3));an({template_version:ne,package_manager:u,region:f,auth:k,payment:j,ai_providers:te,deploy_target:Q,duration_ms:Date.now()-Jt}),tt.length>0&&Ut(),n?p(!0,{event:"done",status:"ok",elapsedSec:$e,targetDir:i,previewSelections:tt}):nn({elapsedSec:$e,targetDir:i,skippedInstall:t.install===!1,previewSelections:tt});try{Di({pkg:{name:xo,version:ne},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(m){let y=m instanceof Error?m.message:String(m);n?p(!0,{event:"error",message:y}):process.stdout.write(R.red(`
2916
- \u2718 Failed: ${y}
2917
- `)),process.exit(1)}}Vi().catch(e=>{process.stderr.write(String(e)+`
2916
+ `))}process.exit(0)}let Go=async()=>{process.stdout.write(`
2917
+ `+w.red(`\u2718 Cancelled
2918
+ `)),le.existsSync(s)&&await C.confirm({message:`Cleanup partial install at ${s}?`,initialValue:!0})===!0&&(le.rmSync(s,{recursive:!0,force:!0}),process.stdout.write(w.dim(` \u2713 Removed ${s}
2919
+ `))),process.exit(130)};process.on("SIGINT",Go);try{p(n,{event:"step",step:"clone",status:"start"}),await Zn(s),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await co(s,d),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await xn(s,ue),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await Eo(s,ue),p(n,{event:"step",step:"prune",status:"ok"});let m=dt.join(s,"packages/db/prisma/schema.prisma");if(le.existsSync(m)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let S=le.readFileSync(m,"utf-8"),E=Wt(S,{auth:N,payment:F,"billing-mode":Ke,idp:Be,template:"saas"});le.writeFileSync(m,E),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(S){let E=S instanceof Error?S.message:String(S);p(n,{event:"step",step:"schema-prune",status:"error",error:E})}}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"auth",choice:N,status:"start"}),await yn(s,N),p(n,{event:"step",step:"auth",choice:N,status:"ok"}),Y.length>0?(p(n,{event:"step",step:"social-login",providers:Y,status:"start"}),await vn(s,Y,N),p(n,{event:"step",step:"social-login",providers:Y,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:X,status:"start"}),await Tn(s,X,d),p(n,{event:"step",step:"db",choice:X,status:"ok"}),p(n,{event:"step",step:"payment",choice:F,status:"start"}),await lo(s,F),p(n,{event:"step",step:"payment",choice:F,status:"ok"}),await jn(s,Ne,y),n&&p(!0,{event:"step",step:"email",choice:Ne,status:"ok"}),await xo(s,ke,y),n&&p(!0,{event:"step",step:"storage",choice:ke,status:"ok"}),await io(s,Te,y),n&&p(!0,{event:"step",step:"monitoring",choice:Te,status:"ok"}),await un(s,Oe,y),n&&p(!0,{event:"step",step:"analytics",choice:Oe,status:"ok"}),await wo(s,Ue,y),n&&p(!0,{event:"step",step:"sms",choice:Ue,status:"ok"}),await _o(s,Le,y),n&&p(!0,{event:"step",step:"queue",choice:Le,status:"ok"}),await Io(s,Me,y),n&&p(!0,{event:"step",step:"search",choice:Me,status:"ok"}),await bn(s,Qe,y),n&&p(!0,{event:"step",step:"cache",choice:Qe,status:"ok"}),await ao(s,De,y),n&&p(!0,{event:"step",step:"notifications",choice:De,status:"ok"}),await ko(s,Fe,y),n&&p(!0,{event:"step",step:"webhooks",choice:Fe,status:"ok"}),await wn(s,Je,y),n&&p(!0,{event:"step",step:"cms",choice:Je,status:"ok"}),await Gn(s,je,y),n&&p(!0,{event:"step",step:"feature-flags",choice:je,status:"ok"}),await An(s,Ve,y),n&&p(!0,{event:"step",step:"captcha",choice:Ve,status:"ok"}),await eo(s,gt),n&&p(!0,{event:"step",step:"mcp",mode:gt,status:"ok"}),await no(s,Ze,Xe),n&&p(!0,{event:"step",step:"metering",mode:Ze,status:"ok"}),ue.orm==="prisma"&&ue.database!=="none"){let S=dt.join(s,"packages/db/prisma/schema.prisma");if(le.existsSync(S)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let E=le.readFileSync(S,"utf8"),Q=Wt(E,{auth:N,payment:F,"billing-mode":Ke,idp:Be,template:"saas"});le.writeFileSync(S,Q),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(E){let Q=E instanceof Error?E.message:String(E);p(n,{event:"step",step:"schema-prune",status:"error",error:Q})}}else p(n,{event:"step",step:"schema-prune",status:"skip"})}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"billing-mode",choice:Ke,status:"ok"}),p(n,{event:"step",step:"idp",choice:Be,status:"ok"}),await Rn(s,y),n&&p(!0,{event:"step",step:"compliance",region:y,status:"ok"}),await $n(s),await Ao(s,N),await To(s,{projectName:d,region:y}),ue.aiMode!=="none"){p(n,{event:"step",step:"ai-providers",status:"start"});let S={providerIds:ue.aiProviders,customEndpoint:ue.customAiEndpoint},E=dt.join(s,"packages/ai-providers/templates");await yo(s,S,E),p(n,{event:"step",step:"ai-providers",status:"ok"})}else p(n,{event:"step",step:"ai-providers",status:"skip"});if(p(n,{event:"step",step:"docs",status:"start"}),j!=="none"?(await Ln(s,{framework:j,projectName:d}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:j,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),z!=="none"&&await On(s,z),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await Kn(s,qo),p(n,{event:"step",step:"env",status:"ok"}),t.install!==!1){let S=u==="bun"?"bun install":`${u} install`;n?p(!0,{event:"step",step:"install",pm:u,status:"start"}):process.stdout.write(w.dim(` Installing dependencies with ${u}\u2026
2920
+ `));try{kt(S,{cwd:s,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(E){let Q=E instanceof Error?E.message:String(E);n?p(!0,{event:"step",step:"install",status:"error",error:Q}):process.stdout.write(w.yellow(` \u26A0 install failed \u2014 run '${S}' manually.
2921
+ `))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{kt("git init -q",{cwd:s,stdio:"ignore"}),kt("git add -A",{cwd:s,stdio:"ignore"}),kt('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:s,stdio:"ignore"}),p(n,{event:"step",step:"git-init",status:"ok"})}catch(S){let E=S instanceof Error?S.message:String(S);n?p(!0,{event:"step",step:"git-init",status:"error",error:E}):process.stdout.write(w.yellow(` \u26A0 git init skipped \u2014 not fatal.
2922
+ `))}}else p(n,{event:"step",step:"git-init",status:"skip"});let yt=Math.max(1,Math.round((Date.now()-tn)/1e3));mn({template_version:ee,package_manager:u,region:y,auth:N,payment:F,ai_providers:de,deploy_target:z,duration_ms:Date.now()-tn}),et.length>0&&Ot(),n?p(!0,{event:"done",status:"ok",elapsedSec:yt,targetDir:s,previewSelections:et}):sn({elapsedSec:yt,targetDir:s,skippedInstall:t.install===!1,previewSelections:et});try{Bs({pkg:{name:Oo,version:ee},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(m){let f=m instanceof Error?m.message:String(m);n?p(!0,{event:"error",message:f}):process.stdout.write(w.red(`
2923
+ \u2718 Failed: ${f}
2924
+ `)),process.exit(1)}}Gs().catch(e=>{process.stderr.write(String(e)+`
2918
2925
  `),process.exit(1)});