create-sailor 1.3.5 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.js +96 -86
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -146,15 +146,15 @@ single monorepo you can extend instead of re-assembling from scratch.
|
|
|
146
146
|
|
|
147
147
|
## Documentation
|
|
148
148
|
|
|
149
|
-
- **Getting Started**: [nebutra.com/docs](https://nebutra.com/docs)
|
|
150
|
-
- **
|
|
149
|
+
- **Getting Started**: [nebutra.com/docs/getting-started/installation](https://nebutra.com/docs/getting-started/installation)
|
|
150
|
+
- **Customization Guide**: [nebutra.com/docs/customization/overview](https://nebutra.com/docs/customization/overview)
|
|
151
151
|
- **Licensing**: [nebutra.com/licensing](https://nebutra.com/licensing)
|
|
152
152
|
- **Get Free License**: [nebutra.com/get-license](https://nebutra.com/get-license)
|
|
153
153
|
|
|
154
154
|
## License
|
|
155
155
|
|
|
156
156
|
AGPL-3.0 with a commercial license exception.
|
|
157
|
-
See [LICENSE-COMMERCIAL.md](https://github.com/
|
|
157
|
+
See [LICENSE-COMMERCIAL.md](https://github.com/Nebutra/Nebutra-Sailor/blob/main/LICENSE-COMMERCIAL.md) for details.
|
|
158
158
|
Commercial and individual licensing details: [get-license](https://nebutra.com/get-license).
|
|
159
159
|
|
|
160
160
|
---
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import"./chunk-FSRPMVAS.js";import{execSync as kt}from"child_process";import
|
|
2
|
+
import"./chunk-FSRPMVAS.js";import{execSync as kt}from"child_process";import de from"fs";import ut from"path";import*as C from"@clack/prompts";import{Command as Bs}from"commander";import w from"picocolors";import Ys from"update-notifier";import Xo from"cfonts";import zo from"picocolors";import nn from"fs";import Lt from"path";import{fileURLToPath as Ho}from"url";function Wo(){try{let t=Lt.dirname(Ho(import.meta.url));for(let o=0;o<4;o++){let n=Lt.join(t,"package.json");if(nn.existsSync(n)){let r=nn.readFileSync(n,"utf-8"),i=JSON.parse(r);if(i.name==="create-sailor"&&typeof i.version=="string")return i.version}t=Lt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ee=Wo();function on(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ee}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
|
|
3
3
|
`));return}Xo.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(zo.dim(` AI-Native SaaS Template \xB7 v${ee} \xB7 nebutra.com
|
|
4
4
|
|
|
5
|
-
`))}import _ from"picocolors";var Qo={qstash:"foundation",bullmq:"foundation",upstash:"foundation",sqs:"foundation",meilisearch:"foundation",typesense:"foundation",algolia:"foundation",pgvector:"foundation",novu:"foundation",knock:"foundation",svix:"foundation","vercel-flags":"wip",growthbook:"wip",configcat:"wip",turnstile:"wip",hcaptcha:"wip","aliyun-slide":"wip"};function Jo(e){return e?Qo[e]??"stable":"stable"}function
|
|
5
|
+
`))}import _ from"picocolors";var Qo={qstash:"foundation",bullmq:"foundation",upstash:"foundation",sqs:"foundation",meilisearch:"foundation",typesense:"foundation",algolia:"foundation",pgvector:"foundation",novu:"foundation",knock:"foundation",svix:"foundation","vercel-flags":"wip",growthbook:"wip",configcat:"wip",turnstile:"wip",hcaptcha:"wip","aliyun-slide":"wip"};function Jo(e){return e?Qo[e]??"stable":"stable"}function qe(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function te(e){switch(e){case"stable":return"Production-ready.";case"foundation":return"Foundation status \u2014 types + factory are complete, but provider adapters are stub-level and require external credentials.";case"wip":return"WIP \u2014 actively being built, should not be used in production.";case"deprecated":return"Deprecated \u2014 scheduled for removal, do not use."}}function rn(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=Jo(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function Zo(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function sn(e){let t=Zo(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",i=t?"\u{1F4E7}":"*",c=["",` ${t?_.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?_.bold("Next:"):"Next:"}`,` ${n} cd ${e.targetDir}`];e.skippedInstall&&c.push(` ${n} pnpm install (if --no-install was set)`),c.push(` ${n} fill in .env.local ${t?_.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?_.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?_.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?_.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?_.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?_.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?_.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?_.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?_.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?_.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?_.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?_.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`);let a=e.previewSelections??[];if(a.length>0){let d=t?_.bold(_.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${d}`);for(let u of a){let h=qe(u.status),O=` ${n} ${u.flag} (${u.provider}) ${h}`;c.push(t?_.yellow(O):O)}c.push("",` ${t?_.dim(te("foundation")):te("foundation")}`,` ${t?_.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?_.dim("See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"):"See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"}`)}c.push("",` ${t?_.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${i} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
|
|
6
6
|
`)+`
|
|
7
7
|
`)}var er=`Usage: create-sailor [name] [options]
|
|
8
8
|
|
|
@@ -74,8 +74,8 @@ Examples:
|
|
|
74
74
|
$ npx create-sailor@latest my-app --region=hybrid --ai=openai,deepseek
|
|
75
75
|
$ npm create sailor@latest --dry-run --region=cn
|
|
76
76
|
`;function an(){process.stdout.write(er)}import Et from"picocolors";function cn(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function tr(e){let t=cn()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return cn()?`${Et.dim(o)} ${Et.bold(n)} ${Et.dim(t)} ${Et.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function pn(e){process.stdout.write(tr(e)+`
|
|
77
|
-
`)}var Mt=[{id:"anthropic",name:"Anthropic",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.anthropic.com",envVarPrefix:"ANTHROPIC",requiredEnvVars:["ANTHROPIC_API_KEY"]},{id:"openai",name:"OpenAI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.openai.com/docs",envVarPrefix:"OPENAI",requiredEnvVars:["OPENAI_API_KEY"]},{id:"deepseek",name:"DeepSeek",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.deepseek.com/api-docs",envVarPrefix:"DEEPSEEK",requiredEnvVars:["DEEPSEEK_API_KEY"]},{id:"xai",name:"xAI (Grok)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.x.ai/api",envVarPrefix:"XAI",requiredEnvVars:["XAI_API_KEY"]},{id:"moonshot",name:"Moonshot (Kimi)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.moonshot.cn/docs",envVarPrefix:"MOONSHOT",requiredEnvVars:["MOONSHOT_API_KEY","MOONSHOT_BASE_URL"]},{id:"google",name:"Google Gemini",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://ai.google.dev/gemini-api/docs",envVarPrefix:"GOOGLE_GENERATIVE_AI",requiredEnvVars:["GOOGLE_GENERATIVE_AI_API_KEY"]},{id:"mistral",name:"Mistral AI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.mistral.ai",envVarPrefix:"MISTRAL",requiredEnvVars:["MISTRAL_API_KEY"]},{id:"cohere",name:"Cohere",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.cohere.com",envVarPrefix:"COHERE",requiredEnvVars:["COHERE_API_KEY"]},{id:"perplexity",name:"Perplexity",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.perplexity.ai",baseURL:"https://api.perplexity.ai",envVarPrefix:"PERPLEXITY",requiredEnvVars:["PERPLEXITY_API_KEY"]},{id:"ai21",name:"AI21 Labs",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.ai21.com",baseURL:"https://api.ai21.com/studio/v1",envVarPrefix:"AI21",requiredEnvVars:["AI21_API_KEY"]},{id:"upstage",name:"Upstage (Solar)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://developers.upstage.ai/docs",baseURL:"https://api.upstage.ai/v1/solar",envVarPrefix:"UPSTAGE",requiredEnvVars:["UPSTAGE_API_KEY"]},{id:"siliconflow",name:"\u7845\u57FA\u6D41\u52A8 SiliconFlow",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://docs.siliconflow.cn",baseURL:"https://api.siliconflow.cn/v1",envVarPrefix:"SILICONFLOW",requiredEnvVars:["SILICONFLOW_API_KEY"]},{id:"volcengine-ark",name:"\u706B\u5C71\u5F15\u64CE ARK (\u8C46\u5305)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://www.volcengine.com/docs/82379",baseURL:"https://ark.cn-beijing.volces.com/api/v3",envVarPrefix:"ARK",requiredEnvVars:["ARK_API_KEY"]},{id:"bailian",name:"\u767E\u70BC Bailian (\u901A\u4E49)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://help.aliyun.com/zh/model-studio",baseURL:"https://dashscope.aliyuncs.com/compatible-mode/v1",envVarPrefix:"DASHSCOPE",requiredEnvVars:["DASHSCOPE_API_KEY"]},{id:"zhipu",name:"\u667A\u8C31 AI Zhipu",category:"\u56FD\u5185\u5E73\u53F0",status:"ai-sdk",docs:"https://docs.bigmodel.cn",baseURL:"https://open.bigmodel.cn/api/paas/v4",envVarPrefix:"ZHIPU",requiredEnvVars:["ZHIPU_API_KEY"]},{id:"baichuan",name:"\u767E\u5DDD\u667A\u80FD Baichuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.baichuan-ai.com/docs",baseURL:"https://api.baichuan-ai.com/v1",envVarPrefix:"BAICHUAN",requiredEnvVars:["BAICHUAN_API_KEY"]},{id:"minimax",name:"MiniMax (ABAB)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.minimaxi.com/document/guides",baseURL:"https://api.minimax.chat/v1",envVarPrefix:"MINIMAX",requiredEnvVars:["MINIMAX_API_KEY","MINIMAX_GROUP_ID"]},{id:"stepfun",name:"\u9636\u8DC3\u661F\u8FB0 StepFun",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.stepfun.com/docs",baseURL:"https://api.stepfun.com/v1",envVarPrefix:"STEPFUN",requiredEnvVars:["STEPFUN_API_KEY"]},{id:"sensetime",name:"\u5546\u6C64 SenseNova",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.sensetime.com",baseURL:"https://api.sensenova.cn/v1",envVarPrefix:"SENSENOVA",requiredEnvVars:["SENSENOVA_API_KEY"]},{id:"tencent",name:"\u817E\u8BAF\u6DF7\u5143 Hunyuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://cloud.tencent.com/document/product/1729",baseURL:"https://api.hunyuan.cloud.tencent.com/v1",envVarPrefix:"HUNYUAN",requiredEnvVars:["HUNYUAN_API_KEY"]},{id:"lingyi",name:"\u96F6\u4E00\u4E07\u7269 Yi",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.lingyiwanwu.com/docs",baseURL:"https://api.lingyiwanwu.com/v1",envVarPrefix:"YI",requiredEnvVars:["YI_API_KEY"]},{id:"openrouter",name:"OpenRouter",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://openrouter.ai/docs",envVarPrefix:"OPENROUTER",requiredEnvVars:["OPENROUTER_API_KEY"]},{id:"vercel-gateway",name:"Vercel AI Gateway",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://vercel.com/docs/ai-gateway",envVarPrefix:"AI_GATEWAY",requiredEnvVars:["AI_GATEWAY_API_KEY"]},{id:"litellm",name:"LiteLLM Proxy",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://docs.litellm.ai",baseURL:"http://localhost:4000/v1",envVarPrefix:"LITELLM",requiredEnvVars:["LITELLM_API_KEY"]},{id:"portkey",name:"Portkey",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://portkey.ai/docs",baseURL:"https://api.portkey.ai/v1",envVarPrefix:"PORTKEY",requiredEnvVars:["PORTKEY_API_KEY"]},{id:"aws-bedrock",name:"AWS Bedrock",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://aws.amazon.com/bedrock/",envVarPrefix:"AWS_BEDROCK",requiredEnvVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"]},{id:"azure-openai",name:"Azure OpenAI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://azure.microsoft.com/en-us/products/cognitive-services/openai-service/",envVarPrefix:"AZURE_OPENAI",requiredEnvVars:["AZURE_OPENAI_API_KEY","AZURE_OPENAI_ENDPOINT"]},{id:"gcp-vertex",name:"GCP Vertex AI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://cloud.google.com/vertex-ai",envVarPrefix:"GOOGLE_VERTEX",requiredEnvVars:["GOOGLE_APPLICATION_CREDENTIALS"]},{id:"groq",name:"Groq",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://console.groq.com/docs",envVarPrefix:"GROQ",requiredEnvVars:["GROQ_API_KEY"]},{id:"fireworks",name:"Fireworks AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.fireworks.ai",envVarPrefix:"FIREWORKS",requiredEnvVars:["FIREWORKS_API_KEY"]},{id:"together",name:"Together AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.together.ai",envVarPrefix:"TOGETHER",requiredEnvVars:["TOGETHER_API_KEY"]},{id:"huggingface",name:"Hugging Face",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://huggingface.co/docs/inference-providers",envVarPrefix:"HF",requiredEnvVars:["HF_API_KEY"]},{id:"replicate",name:"Replicate",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://replicate.com/docs",envVarPrefix:"REPLICATE",requiredEnvVars:["REPLICATE_API_TOKEN"]},{id:"lepton",name:"Lepton AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://www.lepton.ai/docs",baseURL:"https://api.lepton.ai/v1",envVarPrefix:"LEPTON",requiredEnvVars:["LEPTON_API_KEY"]},{id:"anyscale",name:"Anyscale Endpoints",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://docs.endpoints.anyscale.com/",baseURL:"https://api.endpoints.anyscale.com/v1",envVarPrefix:"ANYSCALE",requiredEnvVars:["ANYSCALE_API_KEY"]},{id:"octoai",name:"OctoAI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://octoai.cloud/docs",baseURL:"https://text.octoai.run/v1",envVarPrefix:"OCTOAI",requiredEnvVars:["OCTOAI_TOKEN"]},{id:"deepinfra",name:"DeepInfra",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://deepinfra.com/docs",baseURL:"https://api.deepinfra.com/v1/openai",envVarPrefix:"DEEPINFRA",requiredEnvVars:["DEEPINFRA_API_KEY"]},{id:"novita",name:"Novita AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://novita.ai/docs",baseURL:"https://api.novita.ai/v3/openai",envVarPrefix:"NOVITA",requiredEnvVars:["NOVITA_API_KEY"]},{id:"black-forest-labs",name:"Black Forest Labs (FLUX)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://docs.bfl.ml",envVarPrefix:"BFL",requiredEnvVars:["BFL_API_KEY"]},{id:"elevenlabs",name:"ElevenLabs (TTS)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://elevenlabs.io/docs",envVarPrefix:"ELEVENLABS",requiredEnvVars:["ELEVENLABS_API_KEY"]},{id:"runway",name:"Runway (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://runwayml.com",envVarPrefix:"RUNWAY",requiredEnvVars:["RUNWAY_API_KEY"]},{id:"luma",name:"Luma (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://lumalabs.ai",envVarPrefix:"LUMA",requiredEnvVars:["LUMA_API_KEY"]},{id:"midjourney",name:"Midjourney",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://docs.midjourney.com",envVarPrefix:"MIDJOURNEY",requiredEnvVars:[]},{id:"ollama",name:"Ollama (\u672C\u5730)",category:"\u672C\u5730\u90E8\u7F72",status:"opencode",docs:"https://github.com/ollama/ollama",baseURL:"http://localhost:11434/v1",envVarPrefix:"OLLAMA",requiredEnvVars:["OLLAMA_BASE_URL"]},{id:"lmstudio",name:"LM Studio",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://lmstudio.ai/docs",baseURL:"http://localhost:1234/v1",envVarPrefix:"LMSTUDIO",requiredEnvVars:[]},{id:"vllm",name:"vLLM",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://docs.vllm.ai",baseURL:"http://localhost:8000/v1",envVarPrefix:"VLLM",requiredEnvVars:[]},{id:"tgi",name:"HF TGI",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://huggingface.co/docs/text-generation-inference",baseURL:"http://localhost:8080/v1",envVarPrefix:"TGI",requiredEnvVars:[]}],ca=Mt.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var nr=["openai","anthropic","google"],or=["openai"];function Dt(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...nr];return{mode:"gateway",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:o,runtimeGovernance:!0}}}case"direct":{let o=t.length>0?t:[...or];return{mode:"direct",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:o,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}import $e from"fs";import k from"path";var ln=[{id:"posthog",name:"PostHog",region:"both",envVars:["POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_HOST"],docs:"https://posthog.com/docs",pkgs:["posthog-js","posthog-node"],providerFile:"apps/web/src/lib/analytics/posthog.client.ts"},{id:"plausible",name:"Plausible",region:"global",envVars:["NEXT_PUBLIC_PLAUSIBLE_DOMAIN","NEXT_PUBLIC_PLAUSIBLE_SRC"],docs:"https://plausible.io/docs",providerFile:"apps/web/src/components/analytics/PlausibleScript.tsx"},{id:"umami",name:"Umami",region:"both",envVars:["NEXT_PUBLIC_UMAMI_WEBSITE_ID","NEXT_PUBLIC_UMAMI_SRC"],docs:"https://umami.is/docs",providerFile:"apps/web/src/components/analytics/UmamiScript.tsx"},{id:"mixpanel",name:"Mixpanel",region:"global",envVars:["MIXPANEL_TOKEN","NEXT_PUBLIC_MIXPANEL_TOKEN"],docs:"https://docs.mixpanel.com",pkgs:["mixpanel-browser","mixpanel"],providerFile:"apps/web/src/lib/analytics/mixpanel.client.ts"},{id:"baidu",name:"\u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji",region:"cn",envVars:["NEXT_PUBLIC_BAIDU_STATS_ID"],docs:"https://tongji.baidu.com",providerFile:"apps/web/src/components/analytics/BaiduStatsScript.tsx"},{id:"sensors",name:"\u795E\u7B56 Sensors Analytics",region:"cn",envVars:["NEXT_PUBLIC_SENSORS_SERVER_URL","NEXT_PUBLIC_SENSORS_APP_JS_URL"],docs:"https://manual.sensorsdata.cn",pkgs:["sa-sdk-javascript"],providerFile:"apps/web/src/lib/analytics/sensors.client.ts"},{id:"growingio",name:"GrowingIO",region:"cn",envVars:["NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID"],docs:"https://growingio.com/docs",providerFile:"apps/web/src/components/analytics/GrowingIoScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],da=ln.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function dn(e){return ln.find(t=>t.id===e)}function rr(e){$e.mkdirSync(e,{recursive:!0})}function $(e,t){rr(k.dirname(e)),$e.writeFileSync(e,t)}function me(e,t){let o=k.join(e,".env.example");$e.existsSync(o)?$e.appendFileSync(o,`
|
|
78
|
-
`+t)
|
|
77
|
+
`)}var Mt=[{id:"anthropic",name:"Anthropic",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.anthropic.com",envVarPrefix:"ANTHROPIC",requiredEnvVars:["ANTHROPIC_API_KEY"]},{id:"openai",name:"OpenAI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.openai.com/docs",envVarPrefix:"OPENAI",requiredEnvVars:["OPENAI_API_KEY"]},{id:"deepseek",name:"DeepSeek",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.deepseek.com/api-docs",envVarPrefix:"DEEPSEEK",requiredEnvVars:["DEEPSEEK_API_KEY"]},{id:"xai",name:"xAI (Grok)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.x.ai/api",envVarPrefix:"XAI",requiredEnvVars:["XAI_API_KEY"]},{id:"moonshot",name:"Moonshot (Kimi)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.moonshot.cn/docs",envVarPrefix:"MOONSHOT",requiredEnvVars:["MOONSHOT_API_KEY","MOONSHOT_BASE_URL"]},{id:"google",name:"Google Gemini",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://ai.google.dev/gemini-api/docs",envVarPrefix:"GOOGLE_GENERATIVE_AI",requiredEnvVars:["GOOGLE_GENERATIVE_AI_API_KEY"]},{id:"mistral",name:"Mistral AI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.mistral.ai",envVarPrefix:"MISTRAL",requiredEnvVars:["MISTRAL_API_KEY"]},{id:"cohere",name:"Cohere",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.cohere.com",envVarPrefix:"COHERE",requiredEnvVars:["COHERE_API_KEY"]},{id:"perplexity",name:"Perplexity",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.perplexity.ai",baseURL:"https://api.perplexity.ai",envVarPrefix:"PERPLEXITY",requiredEnvVars:["PERPLEXITY_API_KEY"]},{id:"ai21",name:"AI21 Labs",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.ai21.com",baseURL:"https://api.ai21.com/studio/v1",envVarPrefix:"AI21",requiredEnvVars:["AI21_API_KEY"]},{id:"upstage",name:"Upstage (Solar)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://developers.upstage.ai/docs",baseURL:"https://api.upstage.ai/v1/solar",envVarPrefix:"UPSTAGE",requiredEnvVars:["UPSTAGE_API_KEY"]},{id:"siliconflow",name:"\u7845\u57FA\u6D41\u52A8 SiliconFlow",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://docs.siliconflow.cn",baseURL:"https://api.siliconflow.cn/v1",envVarPrefix:"SILICONFLOW",requiredEnvVars:["SILICONFLOW_API_KEY"]},{id:"volcengine-ark",name:"\u706B\u5C71\u5F15\u64CE ARK (\u8C46\u5305)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://www.volcengine.com/docs/82379",baseURL:"https://ark.cn-beijing.volces.com/api/v3",envVarPrefix:"ARK",requiredEnvVars:["ARK_API_KEY"]},{id:"bailian",name:"\u767E\u70BC Bailian (\u901A\u4E49)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://help.aliyun.com/zh/model-studio",baseURL:"https://dashscope.aliyuncs.com/compatible-mode/v1",envVarPrefix:"DASHSCOPE",requiredEnvVars:["DASHSCOPE_API_KEY"]},{id:"zhipu",name:"\u667A\u8C31 AI Zhipu",category:"\u56FD\u5185\u5E73\u53F0",status:"ai-sdk",docs:"https://docs.bigmodel.cn",baseURL:"https://open.bigmodel.cn/api/paas/v4",envVarPrefix:"ZHIPU",requiredEnvVars:["ZHIPU_API_KEY"]},{id:"baichuan",name:"\u767E\u5DDD\u667A\u80FD Baichuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.baichuan-ai.com/docs",baseURL:"https://api.baichuan-ai.com/v1",envVarPrefix:"BAICHUAN",requiredEnvVars:["BAICHUAN_API_KEY"]},{id:"minimax",name:"MiniMax (ABAB)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.minimaxi.com/document/guides",baseURL:"https://api.minimax.chat/v1",envVarPrefix:"MINIMAX",requiredEnvVars:["MINIMAX_API_KEY","MINIMAX_GROUP_ID"]},{id:"stepfun",name:"\u9636\u8DC3\u661F\u8FB0 StepFun",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.stepfun.com/docs",baseURL:"https://api.stepfun.com/v1",envVarPrefix:"STEPFUN",requiredEnvVars:["STEPFUN_API_KEY"]},{id:"sensetime",name:"\u5546\u6C64 SenseNova",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.sensetime.com",baseURL:"https://api.sensenova.cn/v1",envVarPrefix:"SENSENOVA",requiredEnvVars:["SENSENOVA_API_KEY"]},{id:"tencent",name:"\u817E\u8BAF\u6DF7\u5143 Hunyuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://cloud.tencent.com/document/product/1729",baseURL:"https://api.hunyuan.cloud.tencent.com/v1",envVarPrefix:"HUNYUAN",requiredEnvVars:["HUNYUAN_API_KEY"]},{id:"lingyi",name:"\u96F6\u4E00\u4E07\u7269 Yi",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.lingyiwanwu.com/docs",baseURL:"https://api.lingyiwanwu.com/v1",envVarPrefix:"YI",requiredEnvVars:["YI_API_KEY"]},{id:"openrouter",name:"OpenRouter",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://openrouter.ai/docs",envVarPrefix:"OPENROUTER",requiredEnvVars:["OPENROUTER_API_KEY"]},{id:"vercel-gateway",name:"Vercel AI Gateway",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://vercel.com/docs/ai-gateway",envVarPrefix:"AI_GATEWAY",requiredEnvVars:["AI_GATEWAY_API_KEY"]},{id:"litellm",name:"LiteLLM Proxy",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://docs.litellm.ai",baseURL:"http://localhost:4000/v1",envVarPrefix:"LITELLM",requiredEnvVars:["LITELLM_API_KEY"]},{id:"portkey",name:"Portkey",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://portkey.ai/docs",baseURL:"https://api.portkey.ai/v1",envVarPrefix:"PORTKEY",requiredEnvVars:["PORTKEY_API_KEY"]},{id:"aws-bedrock",name:"AWS Bedrock",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://aws.amazon.com/bedrock/",envVarPrefix:"AWS_BEDROCK",requiredEnvVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"]},{id:"azure-openai",name:"Azure OpenAI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://azure.microsoft.com/en-us/products/cognitive-services/openai-service/",envVarPrefix:"AZURE_OPENAI",requiredEnvVars:["AZURE_OPENAI_API_KEY","AZURE_OPENAI_ENDPOINT"]},{id:"gcp-vertex",name:"GCP Vertex AI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://cloud.google.com/vertex-ai",envVarPrefix:"GOOGLE_VERTEX",requiredEnvVars:["GOOGLE_APPLICATION_CREDENTIALS"]},{id:"groq",name:"Groq",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://console.groq.com/docs",envVarPrefix:"GROQ",requiredEnvVars:["GROQ_API_KEY"]},{id:"fireworks",name:"Fireworks AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.fireworks.ai",envVarPrefix:"FIREWORKS",requiredEnvVars:["FIREWORKS_API_KEY"]},{id:"together",name:"Together AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.together.ai",envVarPrefix:"TOGETHER",requiredEnvVars:["TOGETHER_API_KEY"]},{id:"huggingface",name:"Hugging Face",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://huggingface.co/docs/inference-providers",envVarPrefix:"HF",requiredEnvVars:["HF_API_KEY"]},{id:"replicate",name:"Replicate",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://replicate.com/docs",envVarPrefix:"REPLICATE",requiredEnvVars:["REPLICATE_API_TOKEN"]},{id:"lepton",name:"Lepton AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://www.lepton.ai/docs",baseURL:"https://api.lepton.ai/v1",envVarPrefix:"LEPTON",requiredEnvVars:["LEPTON_API_KEY"]},{id:"anyscale",name:"Anyscale Endpoints",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://docs.endpoints.anyscale.com/",baseURL:"https://api.endpoints.anyscale.com/v1",envVarPrefix:"ANYSCALE",requiredEnvVars:["ANYSCALE_API_KEY"]},{id:"octoai",name:"OctoAI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://octoai.cloud/docs",baseURL:"https://text.octoai.run/v1",envVarPrefix:"OCTOAI",requiredEnvVars:["OCTOAI_TOKEN"]},{id:"deepinfra",name:"DeepInfra",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://deepinfra.com/docs",baseURL:"https://api.deepinfra.com/v1/openai",envVarPrefix:"DEEPINFRA",requiredEnvVars:["DEEPINFRA_API_KEY"]},{id:"novita",name:"Novita AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://novita.ai/docs",baseURL:"https://api.novita.ai/v3/openai",envVarPrefix:"NOVITA",requiredEnvVars:["NOVITA_API_KEY"]},{id:"black-forest-labs",name:"Black Forest Labs (FLUX)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://docs.bfl.ml",envVarPrefix:"BFL",requiredEnvVars:["BFL_API_KEY"]},{id:"elevenlabs",name:"ElevenLabs (TTS)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://elevenlabs.io/docs",envVarPrefix:"ELEVENLABS",requiredEnvVars:["ELEVENLABS_API_KEY"]},{id:"runway",name:"Runway (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://runwayml.com",envVarPrefix:"RUNWAY",requiredEnvVars:["RUNWAY_API_KEY"]},{id:"luma",name:"Luma (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://lumalabs.ai",envVarPrefix:"LUMA",requiredEnvVars:["LUMA_API_KEY"]},{id:"midjourney",name:"Midjourney",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://docs.midjourney.com",envVarPrefix:"MIDJOURNEY",requiredEnvVars:[]},{id:"ollama",name:"Ollama (\u672C\u5730)",category:"\u672C\u5730\u90E8\u7F72",status:"opencode",docs:"https://github.com/ollama/ollama",baseURL:"http://localhost:11434/v1",envVarPrefix:"OLLAMA",requiredEnvVars:["OLLAMA_BASE_URL"]},{id:"lmstudio",name:"LM Studio",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://lmstudio.ai/docs",baseURL:"http://localhost:1234/v1",envVarPrefix:"LMSTUDIO",requiredEnvVars:[]},{id:"vllm",name:"vLLM",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://docs.vllm.ai",baseURL:"http://localhost:8000/v1",envVarPrefix:"VLLM",requiredEnvVars:[]},{id:"tgi",name:"HF TGI",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://huggingface.co/docs/text-generation-inference",baseURL:"http://localhost:8080/v1",envVarPrefix:"TGI",requiredEnvVars:[]}],pa=Mt.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var nr=["openai","anthropic","google"],or=["openai"];function Dt(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...nr];return{mode:"gateway",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:o,runtimeGovernance:!0}}}case"direct":{let o=t.length>0?t:[...or];return{mode:"direct",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:o,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}import Ge from"fs";import k from"path";var ln=[{id:"posthog",name:"PostHog",region:"both",envVars:["POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_HOST"],docs:"https://posthog.com/docs",pkgs:["posthog-js","posthog-node"],providerFile:"apps/web/src/lib/analytics/posthog.client.ts"},{id:"plausible",name:"Plausible",region:"global",envVars:["NEXT_PUBLIC_PLAUSIBLE_DOMAIN","NEXT_PUBLIC_PLAUSIBLE_SRC"],docs:"https://plausible.io/docs",providerFile:"apps/web/src/components/analytics/PlausibleScript.tsx"},{id:"umami",name:"Umami",region:"both",envVars:["NEXT_PUBLIC_UMAMI_WEBSITE_ID","NEXT_PUBLIC_UMAMI_SRC"],docs:"https://umami.is/docs",providerFile:"apps/web/src/components/analytics/UmamiScript.tsx"},{id:"mixpanel",name:"Mixpanel",region:"global",envVars:["MIXPANEL_TOKEN","NEXT_PUBLIC_MIXPANEL_TOKEN"],docs:"https://docs.mixpanel.com",pkgs:["mixpanel-browser","mixpanel"],providerFile:"apps/web/src/lib/analytics/mixpanel.client.ts"},{id:"baidu",name:"\u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji",region:"cn",envVars:["NEXT_PUBLIC_BAIDU_STATS_ID"],docs:"https://tongji.baidu.com",providerFile:"apps/web/src/components/analytics/BaiduStatsScript.tsx"},{id:"sensors",name:"\u795E\u7B56 Sensors Analytics",region:"cn",envVars:["NEXT_PUBLIC_SENSORS_SERVER_URL","NEXT_PUBLIC_SENSORS_APP_JS_URL"],docs:"https://manual.sensorsdata.cn",pkgs:["sa-sdk-javascript"],providerFile:"apps/web/src/lib/analytics/sensors.client.ts"},{id:"growingio",name:"GrowingIO",region:"cn",envVars:["NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID"],docs:"https://growingio.com/docs",providerFile:"apps/web/src/components/analytics/GrowingIoScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],ua=ln.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function dn(e){return ln.find(t=>t.id===e)}function rr(e){Ge.mkdirSync(e,{recursive:!0})}function $(e,t){rr(k.dirname(e)),Ge.writeFileSync(e,t)}function ge(e,t){let o=k.join(e,".env.example");Ge.existsSync(o)?Ge.appendFileSync(o,`
|
|
78
|
+
`+t):Ge.writeFileSync(o,t)}function ir(e){let t=`"use client";
|
|
79
79
|
/**
|
|
80
80
|
* PostHog browser SDK \u2014 lazy-initialized on first access.
|
|
81
81
|
*/
|
|
@@ -336,19 +336,19 @@ gdp("send");
|
|
|
336
336
|
}
|
|
337
337
|
`)}function Er(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
|
|
338
338
|
NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
|
|
339
|
-
`}async function un(e,t,o="global"){let n=dn(t);if(!n||n.id==="none")return;let r=k.join(e,"apps","web");if(
|
|
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=
|
|
341
|
-
`+t)}async function yn(e,t){let o=
|
|
339
|
+
`}async function un(e,t,o="global"){let n=dn(t);if(!n||n.id==="none")return;let r=k.join(e,"apps","web");if(!Ge.existsSync(r))return;let i=n.id;try{switch(i){case"posthog":ir(r),ge(e,sr());return;case"plausible":ar(r),ge(e,cr());return;case"umami":pr(r),ge(e,lr());return;case"mixpanel":dr(r),ge(e,ur());return;case"baidu":mr(r),ge(e,gr());return;case"sensors":fr(r),ge(e,yr());return;case"growingio":Sr(r),ge(e,Er());return;default:return}}catch(s){throw console.error(`Failed to apply analytics selection "${t}":`,s),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var hr="https://analytics.nebutra.com";function vr(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function mn(e,t={}){vr(t)||(async()=>{try{let o=await import("./dist-B4YTE2SQ.js");if(typeof o.createAnalyticsClient!="function")return;let n=o.createAnalyticsClient({posthog:{apiKey:process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.NEBUTRA_POSTHOG_HOST??hr},onError:()=>{}});if(typeof n?.track!="function")return;let r=n.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import U from"fs";import fe from"path";function Ft(e){U.existsSync(e)&&U.rmSync(e,{recursive:!0,force:!0})}function gn(e,t){let o=fe.join(e,".env.example");U.existsSync(o)?U.appendFileSync(o,`
|
|
340
|
+
`+t):U.writeFileSync(o,t)}function fn(e,t){if(!U.existsSync(e))return;let o=U.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*"[^"]+"\s*\|\s*"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&U.writeFileSync(e,n)}function _r(e,t){let o=fe.join(e,"README.md");if(!U.existsSync(o)){U.writeFileSync(o,t);return}U.appendFileSync(o,`
|
|
341
|
+
`+t)}async function yn(e,t){let o=fe.join(e,"packages","auth");if(!U.existsSync(o))return;if(t==="none"){Ft(o),_r(e,`
|
|
342
342
|
## Auth
|
|
343
343
|
|
|
344
344
|
Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth).
|
|
345
|
-
`);return}let n=
|
|
345
|
+
`);return}let n=fe.join(o,"src","providers"),r=fe.join(o,"src","types.ts");if(t==="clerk"){Ft(fe.join(n,"better-auth.ts")),fn(r,"clerk"),gn(e,`# Clerk auth
|
|
346
346
|
CLERK_PUBLISHABLE_KEY=
|
|
347
347
|
CLERK_SECRET_KEY=
|
|
348
|
-
`);return}if(t==="betterauth"){Ft(
|
|
348
|
+
`);return}if(t==="betterauth"){Ft(fe.join(n,"clerk.ts")),fn(r,"better-auth"),gn(e,`# Better Auth
|
|
349
349
|
BETTER_AUTH_SECRET=
|
|
350
350
|
BETTER_AUTH_URL=http://localhost:3000
|
|
351
|
-
`);return}}var
|
|
351
|
+
`);return}}var nt=[{id:"wechat",name:"\u5FAE\u4FE1\u5F00\u653E\u5E73\u53F0",region:"cn",envVars:["WECHAT_APP_ID","WECHAT_APP_SECRET"],docs:"https://open.weixin.qq.com/cgi-bin/showdocument",callbackUrl:"/api/auth/callback/wechat",tokenEndpoint:"https://api.weixin.qq.com/sns/oauth2/access_token"},{id:"qq",name:"QQ \u767B\u5F55",region:"cn",envVars:["QQ_APP_ID","QQ_APP_KEY"],docs:"https://wiki.connect.qq.com",callbackUrl:"/api/auth/callback/qq",tokenEndpoint:"https://graph.qq.com/oauth2.0/token"},{id:"dingtalk",name:"\u9489\u9489",region:"cn",envVars:["DINGTALK_APP_ID","DINGTALK_APP_SECRET"],docs:"https://open.dingtalk.com/document/",callbackUrl:"/api/auth/callback/dingtalk",tokenEndpoint:"https://api.dingtalk.com/v1.0/oauth2/userAccessToken"},{id:"workweixin",name:"\u4F01\u4E1A\u5FAE\u4FE1",region:"cn",envVars:["WORKWEIXIN_CORP_ID","WORKWEIXIN_AGENT_ID","WORKWEIXIN_SECRET"],docs:"https://developer.work.weixin.qq.com",callbackUrl:"/api/auth/callback/workweixin",tokenEndpoint:"https://qyapi.weixin.qq.com/cgi-bin/gettoken"},{id:"feishu",name:"\u98DE\u4E66 / Lark",region:"cn",envVars:["FEISHU_APP_ID","FEISHU_APP_SECRET"],docs:"https://open.feishu.cn/document/",callbackUrl:"/api/auth/callback/feishu",tokenEndpoint:"https://open.feishu.cn/open-apis/authen/v1/access_token"},{id:"weibo",name:"\u5FAE\u535A",region:"cn",envVars:["WEIBO_APP_KEY","WEIBO_APP_SECRET"],docs:"https://open.weibo.com/wiki/",callbackUrl:"/api/auth/callback/weibo",tokenEndpoint:"https://api.weibo.com/oauth2/access_token"}],Pr=new Set(nt.map(e=>e.id));function Sn(e){return nt.find(t=>t.id===e)}function En(e){if(!e)return[];let t=e.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean);if(t.includes("none"))return[];let o=[],n=new Set;for(let r of t)Pr.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import Se from"fs";import ye from"path";function br(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
|
|
352
352
|
// Generated by create-sailor \u2014 OAuth callback for ${e.name}
|
|
353
353
|
// Primary auth provider: ${t}
|
|
354
354
|
// Docs: ${e.docs}`,n={wechat:` const tokenRes = await fetch(
|
|
@@ -516,21 +516,21 @@ export function SocialLoginButtons() {
|
|
|
516
516
|
</div>
|
|
517
517
|
);
|
|
518
518
|
}
|
|
519
|
-
`}function hn(e){
|
|
520
|
-
`+t):
|
|
519
|
+
`}function hn(e){Se.mkdirSync(e,{recursive:!0})}function Ar(e,t){let o=ye.join(e,".env.example");Se.existsSync(o)?Se.appendFileSync(o,`
|
|
520
|
+
`+t):Se.writeFileSync(o,t)}function Cr(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
521
521
|
`);return`${t}
|
|
522
522
|
${o}
|
|
523
|
-
`}async function vn(e,t,o){if(!t||t.length===0)return;let n=
|
|
524
|
-
`);
|
|
525
|
-
`)}async function bn(e,t,o){let n=jt.join(e,"packages","cache");if(t==="none"){
|
|
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}"`,
|
|
523
|
+
`}async function vn(e,t,o){if(!t||t.length===0)return;let n=ye.join(e,"apps","web");if(!Se.existsSync(n))return;let r=new Set,i=[];for(let d of t){if(r.has(d))continue;r.add(d);let u=Sn(d);u&&i.push(u)}if(i.length===0)return;for(let d of i)Ar(e,Cr(d));let s=ye.join(n,"src","app","api","auth","callback");for(let d of i){let u=ye.join(s,d.id);hn(u);let h=ye.join(u,"route.ts");Se.writeFileSync(h,br(d,o))}let c=ye.join(n,"src","components","auth");hn(c);let a=ye.join(c,"SocialLoginButtons.tsx");Se.writeFileSync(a,Ir(i))}import ne from"fs";import jt from"path";var ht=[{id:"upstash-redis",name:"Upstash Redis",region:"both",envVars:["UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"],docs:"https://upstash.com/docs/redis",description:"Serverless Redis"},{id:"vercel-kv",name:"Vercel KV",region:"global",envVars:["KV_URL","KV_REST_API_URL","KV_REST_API_TOKEN","KV_REST_API_READ_ONLY_TOKEN"],docs:"https://vercel.com/docs/storage/vercel-kv",description:"Vercel native KV"},{id:"redis",name:"Redis (self-hosted)",region:"both",envVars:["REDIS_URL"],docs:"https://redis.io/docs/",description:"Self-hosted Redis"},{id:"dragonfly",name:"Dragonfly",region:"global",envVars:["DRAGONFLY_URL"],docs:"https://www.dragonflydb.io/docs",description:"Drop-in Redis replacement, faster"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip cache package"}];function _n(e){return ht.find(t=>t.id===e)}var wa=ht.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Pn(e){return ne.existsSync(e)?ne.readFileSync(e,"utf-8"):null}function wr(e,t){let o=jt.join(e,".env.example"),n=Pn(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
|
|
524
|
+
`);ne.appendFileSync(o,i)}function Rr(e,t,o){let n=jt.join(e,".env.example"),r=Pn(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ne.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ne.appendFileSync(n,`${t}="${o}"
|
|
525
|
+
`)}async function bn(e,t,o){let n=jt.join(e,"packages","cache");if(t==="none"){ne.existsSync(n)&&ne.rmSync(n,{recursive:!0,force:!0});return}let r=_n(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${ht.map(i=>i.id).join(", ")}`);ne.existsSync(n)&&(wr(e,r),Rr(e,"CACHE_PROVIDER",t))}var vt=[{id:"turnstile",name:"Cloudflare Turnstile",region:"global",envVars:["NEXT_PUBLIC_TURNSTILE_SITE_KEY","TURNSTILE_SECRET_KEY"],docs:"https://developers.cloudflare.com/turnstile/",description:"Free, privacy-focused captcha alternative"},{id:"hcaptcha",name:"hCaptcha",region:"global",envVars:["NEXT_PUBLIC_HCAPTCHA_SITE_KEY","HCAPTCHA_SECRET_KEY"],docs:"https://docs.hcaptcha.com/",description:"Privacy-respecting captcha"},{id:"aliyun-slide",name:"\u963F\u91CC\u4E91\u9A8C\u8BC1\u7801 2.0",region:"cn",envVars:["ALIYUN_CAPTCHA_ACCESS_KEY_ID","ALIYUN_CAPTCHA_ACCESS_KEY_SECRET","ALIYUN_CAPTCHA_APP_KEY","NEXT_PUBLIC_ALIYUN_CAPTCHA_APP_KEY"],docs:"https://help.aliyun.com/product/28308.html",description:"\u963F\u91CC\u4E91\u667A\u80FD\u9A8C\u8BC1 (\u6ED1\u5757/\u65E0\u75D5)"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function In(e){return vt.find(t=>t.id===e)}var Oa=vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import J from"fs";import Vt from"path";function q(e,t){let o=Vt.join(e,".env.example");if(!J.existsSync(o)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(J.readFileSync(o,"utf-8").includes(r))return;let c=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].filter(a=>a!==null).join(`
|
|
526
|
+
`);J.appendFileSync(o,c)}function G(e,t,o){let n=Vt.join(e,".env.example");if(!J.existsSync(n))return;let r=J.readFileSync(n,"utf-8"),i=`${t}="${o}"`,s=new RegExp(`^${t}=.*$`,"m");if(s.test(r)){J.writeFileSync(n,r.replace(s,i));return}let c=r.endsWith(`
|
|
527
527
|
`)?"":`
|
|
528
528
|
`;J.appendFileSync(n,`${c}${i}
|
|
529
|
-
`)}function K(e,t){let o=Vt.join(e,"packages",t);J.existsSync(o)&&J.rmSync(o,{recursive:!0,force:!0})}async function An(e,t,o="global"){let n=In(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${vt.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"captcha");return}n.envVars.length>0&&q(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"CAPTCHA_PROVIDER",n.id)}import Pt from"fs";import xr from"path";var _t=[{id:"sanity",name:"Sanity",region:"global",envVars:["SANITY_PROJECT_ID","SANITY_DATASET","SANITY_API_TOKEN","SANITY_API_VERSION"],docs:"https://www.sanity.io/docs",description:"Structured content platform with Studio"},{id:"contentful",name:"Contentful",region:"global",envVars:["CONTENTFUL_SPACE_ID","CONTENTFUL_ACCESS_TOKEN","CONTENTFUL_PREVIEW_ACCESS_TOKEN"],docs:"https://www.contentful.com/developers/docs/",description:"Headless CMS"},{id:"strapi",name:"Strapi",region:"both",envVars:["STRAPI_URL","STRAPI_API_TOKEN"],docs:"https://docs.strapi.io",description:"Open-source self-hosted CMS"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Cn(e){return _t.find(t=>t.id===e)}var
|
|
529
|
+
`)}function K(e,t){let o=Vt.join(e,"packages",t);J.existsSync(o)&&J.rmSync(o,{recursive:!0,force:!0})}async function An(e,t,o="global"){let n=In(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${vt.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"captcha");return}n.envVars.length>0&&q(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"CAPTCHA_PROVIDER",n.id)}import Pt from"fs";import xr from"path";var _t=[{id:"sanity",name:"Sanity",region:"global",envVars:["SANITY_PROJECT_ID","SANITY_DATASET","SANITY_API_TOKEN","SANITY_API_VERSION"],docs:"https://www.sanity.io/docs",description:"Structured content platform with Studio"},{id:"contentful",name:"Contentful",region:"global",envVars:["CONTENTFUL_SPACE_ID","CONTENTFUL_ACCESS_TOKEN","CONTENTFUL_PREVIEW_ACCESS_TOKEN"],docs:"https://www.contentful.com/developers/docs/",description:"Headless CMS"},{id:"strapi",name:"Strapi",region:"both",envVars:["STRAPI_URL","STRAPI_API_TOKEN"],docs:"https://docs.strapi.io",description:"Open-source self-hosted CMS"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Cn(e){return _t.find(t=>t.id===e)}var Ka=_t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function wn(e,t,o="global"){let n=Cn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${_t.map(i=>i.id).join(", ")}`);let r=xr.join(e,"apps","studio");if(n.id==="none"){K(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(K(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&q(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"CMS_PROVIDER",n.id)}import A from"fs";import I from"path";var Nr=I.join("apps","web"),Kt=I.join("src","components","compliance"),ot=I.join("src","app","[locale]");function H(e){return I.join(e,Nr)}function kr(e){A.mkdirSync(e,{recursive:!0})}function B(e,t){kr(I.dirname(e)),A.writeFileSync(e,t,"utf8")}function Bt(e,t){let o=I.join(e,".env.example");if(A.existsSync(o)){if(A.readFileSync(o,"utf8").includes(t.split(`
|
|
530
530
|
`)[0]??""))return;A.appendFileSync(o,`
|
|
531
531
|
`+t+`
|
|
532
532
|
`)}else A.writeFileSync(o,t+`
|
|
533
|
-
`)}var
|
|
533
|
+
`)}var rt=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
|
|
534
534
|
> Consult a qualified lawyer in every jurisdiction you operate in before publishing.
|
|
535
535
|
> \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,Tr=`import Link from "next/link";
|
|
536
536
|
import { IcpFooter } from "@/components/compliance/IcpFooter";
|
|
@@ -867,7 +867,7 @@ description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal
|
|
|
867
867
|
lastUpdated: 2026-01-01
|
|
868
868
|
---
|
|
869
869
|
|
|
870
|
-
${
|
|
870
|
+
${rt}
|
|
871
871
|
|
|
872
872
|
# Privacy Policy / \u9690\u79C1\u653F\u7B56
|
|
873
873
|
|
|
@@ -1012,7 +1012,7 @@ description: Terms governing your use of {{COMPANY_NAME}}.
|
|
|
1012
1012
|
lastUpdated: 2026-01-01
|
|
1013
1013
|
---
|
|
1014
1014
|
|
|
1015
|
-
${
|
|
1015
|
+
${rt}
|
|
1016
1016
|
|
|
1017
1017
|
# Terms of Service / \u670D\u52A1\u6761\u6B3E
|
|
1018
1018
|
|
|
@@ -1131,7 +1131,7 @@ description: Disclosure required by \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u
|
|
|
1131
1131
|
lastUpdated: 2026-01-01
|
|
1132
1132
|
---
|
|
1133
1133
|
|
|
1134
|
-
${
|
|
1134
|
+
${rt}
|
|
1135
1135
|
|
|
1136
1136
|
# AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
|
|
1137
1137
|
|
|
@@ -1213,7 +1213,7 @@ description: Notice of cross-border transfer of personal information, per PIPL.
|
|
|
1213
1213
|
lastUpdated: 2026-01-01
|
|
1214
1214
|
---
|
|
1215
1215
|
|
|
1216
|
-
${
|
|
1216
|
+
${rt}
|
|
1217
1217
|
|
|
1218
1218
|
# Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
|
|
1219
1219
|
|
|
@@ -1278,7 +1278,7 @@ description: Itemized list of personal information collected, per PIPL Article 1
|
|
|
1278
1278
|
lastUpdated: 2026-01-01
|
|
1279
1279
|
---
|
|
1280
1280
|
|
|
1281
|
-
${
|
|
1281
|
+
${rt}
|
|
1282
1282
|
|
|
1283
1283
|
# Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
|
|
1284
1284
|
|
|
@@ -1315,15 +1315,15 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
|
|
|
1315
1315
|
|
|
1316
1316
|
\u5982\u9700\u884C\u4F7F\u60A8\u7684\u6743\u5229\uFF08\u8BBF\u95EE\u3001\u66F4\u6B63\u3001\u5220\u9664\u3001\u5BFC\u51FA\u3001\u64A4\u56DE\u540C\u610F\uFF09\uFF0C\u8BF7\u8054\u7CFB **{{COMPANY_CONTACT_EMAIL}}**\u3002
|
|
1317
1317
|
`;async function Br(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","Footer.tsx");B(n,Tr);let r=I.join(o,"src","components","compliance","README.md");B(r,["# Compliance Components","",`Auto-generated by \`create-sailor\` for region: \`${t}\`.`,"","## Mounting the Footer","","```tsx",'import { Footer } from "@/components/compliance/Footer";','import { CookieBanner } from "@/components/compliance/CookieBanner";',"","export default function RootLayout({ children }) {"," return ("," <html>"," <body>"," {children}",` <Footer region="${t}" />`," <CookieBanner />"," </body>"," </html>"," );","}","```","","## Placeholders","","Policy MDX files contain `{{COMPANY_NAME}}`, `{{COMPANY_ADDRESS}}`,","`{{COMPANY_CONTACT_EMAIL}}`, `{{GOVERNING_JURISDICTION}}`, and","`{{AIGC_ALGORITHM_FILING_NUMBER}}`. These are filled by the `brand-apply` step.",""].join(`
|
|
1318
|
-
`))}async function Yr(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","CookieBanner.tsx");B(n,Lr)}async function $r(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,
|
|
1318
|
+
`))}async function Yr(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","CookieBanner.tsx");B(n,Lr)}async function $r(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,ot,"privacy","page.mdx");B(n,Dr)}async function qr(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,ot,"terms","page.mdx");B(n,Fr)}async function Gr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"IcpFooter.tsx");B(o,Or),Bt(e,["# Chinese ICP filing (\u5DE5\u4FE1\u90E8 ICP \u5907\u6848) \u2014 required to legally host a","# public-facing site from mainland China. Apply at https://beian.miit.gov.cn/",'NEXT_PUBLIC_ICP_BEIAN="" # \u5982 \u82CFICP\u59072024XXXXXX\u53F7'].join(`
|
|
1319
1319
|
`))}async function Hr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"PublicSecurityFooter.tsx");B(o,Ur),Bt(e,["# Chinese Public Security Bureau filing (\u516C\u5B89\u8054\u7F51\u5907\u6848)","# Required in addition to ICP. Apply at http://www.beian.gov.cn/",'NEXT_PUBLIC_PSB_BEIAN="" # \u5982 \u82CF\u516C\u7F51\u5B89\u5907 32011402XXXXXX\u53F7','NEXT_PUBLIC_PSB_CODE="" # 14-digit record code'].join(`
|
|
1320
1320
|
`))}async function Wr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"AigcDisclaimer.tsx");B(o,Mr),Bt(e,["# Generative AI algorithm filing (\u7B97\u6CD5\u5907\u6848\u53F7) \u2014 required by","# \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300Bfor services offered in China.",'NEXT_PUBLIC_AIGC_FILING_NUMBER="" # e.g. \u7F51\u4FE1\u7B97\u5907XXXXXXXX\u53F7'].join(`
|
|
1321
|
-
`))}async function Xr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,
|
|
1322
|
-
`)}import
|
|
1323
|
-
`+t):
|
|
1321
|
+
`))}async function Xr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"aigc-disclosure","page.mdx");B(o,jr)}async function zr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"cross-border-data","page.mdx");B(o,Vr)}async function Qr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"pii-collection","page.mdx");B(o,Kr)}async function Rn(e,t){try{await Br(e,t),await Yr(e,t),await $r(e,t),await qr(e,t),(t==="cn"||t==="hybrid")&&(await Gr(e),await Hr(e),await Wr(e),await Xr(e),await zr(e),await Qr(e))}catch(o){throw console.error("applyComplianceTemplates failed:",o),new Error(`Failed to apply compliance templates for region "${t}". Check that ${e} is writable.`)}}import Jr from"fs";import Zr from"path";async function xn(e,t){let o=Zr.join(e,"nebutra.config.json");Jr.writeFileSync(o,JSON.stringify(t,null,2)+`
|
|
1322
|
+
`)}import oe from"fs";import Yt from"path";function ei(e){oe.existsSync(e)&&oe.rmSync(e,{recursive:!0,force:!0})}function Nn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function ti(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function kn(e){let t=e.replace(/^\s*extensions\s*=\s*\[[^\]]*\]\s*\n/gm,"");return t=t.replace(/previewFeatures\s*=\s*\[\s*"postgresqlExtensions"\s*\]\s*\n/g,""),t}function ni(e,t){let o=Yt.join(e,".env.example");oe.existsSync(o)?oe.appendFileSync(o,`
|
|
1323
|
+
`+t):oe.writeFileSync(o,t)}async function Tn(e,t,o){let n=Yt.join(e,"packages","db");if(t==="none"){ei(n);return}let r=Yt.join(n,"prisma","schema.prisma"),i;if(t==="postgresql"?i=`postgresql://postgres:postgres@localhost:5432/${o}`:t==="mysql"?i=`mysql://root:root@localhost:3306/${o}`:i="file:./dev.db",ni(e,`# Database (${t})
|
|
1324
1324
|
DATABASE_URL="${i}"
|
|
1325
|
-
`),!
|
|
1326
|
-
`+t):
|
|
1325
|
+
`),!oe.existsSync(r))return;let s=oe.readFileSync(r,"utf8"),c=s;t==="mysql"?(c=Nn(c,"mysql"),c=kn(c)):t==="sqlite"&&(c=Nn(c,"sqlite"),c=ti(c),c=kn(c)),c!==s&&oe.writeFileSync(r,c)}import it from"fs";import L from"path";import{fileURLToPath as oi}from"url";var ri=oi(import.meta.url),ii=L.dirname(ri);async function On(e,t){if(t==="none")return;let o=L.join(ii,"../../templates/deploy");t==="vercel"?await it.promises.copyFile(L.join(o,"vercel.json"),L.join(e,"vercel.json")):t==="railway"?await it.promises.copyFile(L.join(o,"railway.toml"),L.join(e,"railway.toml")):t==="cloudflare"?await it.promises.copyFile(L.join(o,"wrangler.toml"),L.join(e,"wrangler.toml")):t==="selfhost"&&(await it.promises.copyFile(L.join(o,"docker-compose.yml"),L.join(e,"docker-compose.yml")),await it.promises.copyFile(L.join(o,"Dockerfile.web"),L.join(e,"Dockerfile.web")))}import re from"fs";import Ee from"path";import{fileURLToPath as si}from"url";var ai=si(import.meta.url),Un=Ee.dirname(ai),ci=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml)$/;function pi(e){let t=[Ee.join(Un,"..","templates","docs",e),Ee.join(Un,"..","..","templates","docs",e)];for(let o of t)if(re.existsSync(o))return o;return t[0]}async function Ln(e,t){if(t.framework==="none")return;let o=(t.framework==="fumadocs","fumadocs"),n=pi(o),r=Ee.join(e,"apps","docs");if(!re.existsSync(n))throw new Error(`Docs template not found: ${n}`);Mn(n,r),Dn(r,{"{PRODUCT_NAME}":t.projectName})}function Mn(e,t){re.mkdirSync(t,{recursive:!0});for(let o of re.readdirSync(e,{withFileTypes:!0})){let n=Ee.join(e,o.name),r=Ee.join(t,o.name);o.isDirectory()?Mn(n,r):re.copyFileSync(n,r)}}function Dn(e,t){for(let o of re.readdirSync(e,{withFileTypes:!0})){let n=Ee.join(e,o.name);if(o.isDirectory())Dn(n,t);else if(ci.test(o.name)){let r=re.readFileSync(n,"utf-8");for(let[i,s]of Object.entries(t))r=r.split(i).join(s);re.writeFileSync(n,r)}}}import ve from"fs";import he from"path";var bt=[{id:"resend",name:"Resend",region:"global",envVars:["RESEND_API_KEY","RESEND_FROM"],docs:"https://resend.com/docs",pkg:"resend",pkgVersion:"^4.0.1"},{id:"postmark",name:"Postmark",region:"global",envVars:["POSTMARK_API_KEY","POSTMARK_FROM"],docs:"https://postmarkapp.com/developer",pkg:"postmark",pkgVersion:"^4.0.5"},{id:"ses",name:"AWS SES",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_SES_REGION","SES_FROM"],docs:"https://docs.aws.amazon.com/ses",pkg:"@aws-sdk/client-sesv2",pkgVersion:"^3.658.0"},{id:"aliyun-dm",name:"\u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001",region:"cn",envVars:["ALIYUN_DM_ACCESS_KEY","ALIYUN_DM_ACCESS_SECRET","ALIYUN_DM_ACCOUNT_NAME","ALIYUN_DM_FROM_ALIAS"],docs:"https://help.aliyun.com/product/29412.html",pkg:"@alicloud/dm20151123",pkgVersion:"^3.0.0"},{id:"tencent-ses",name:"\u817E\u8BAF\u4E91 SES",region:"cn",envVars:["TENCENT_SECRET_ID","TENCENT_SECRET_KEY","TENCENT_SES_FROM_EMAIL"],docs:"https://cloud.tencent.com/document/product/1288",pkg:"tencentcloud-sdk-nodejs-ses",pkgVersion:"^4.0.900"},{id:"netease",name:"\u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1",region:"cn",envVars:["NETEASE_USER","NETEASE_PASS","NETEASE_FROM"],docs:"https://qiye.163.com/help",pkg:"nodemailer",pkgVersion:"^6.9.15"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function Fn(e){return bt.find(t=>t.id===e)}var dc=bt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var _e="@nebutra/email";function $t(e,t){ve.mkdirSync(he.dirname(e),{recursive:!0}),ve.writeFileSync(e,t)}function li(e,t){let o=he.join(e,".env.example");ve.existsSync(o)?ve.appendFileSync(o,`
|
|
1326
|
+
`+t):ve.writeFileSync(o,t)}function di(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
1327
1327
|
`);return`${t}
|
|
1328
1328
|
${o}
|
|
1329
1329
|
`}var ui=`/**
|
|
@@ -1347,7 +1347,7 @@ export interface SendEmailResult {
|
|
|
1347
1347
|
raw?: unknown;
|
|
1348
1348
|
}
|
|
1349
1349
|
`;function mi(){return`/**
|
|
1350
|
-
* @${
|
|
1350
|
+
* @${_e.slice(1)} \u2014 Resend transactional email wrapper.
|
|
1351
1351
|
*
|
|
1352
1352
|
* Docs: https://resend.com/docs
|
|
1353
1353
|
*/
|
|
@@ -1386,7 +1386,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1386
1386
|
|
|
1387
1387
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1388
1388
|
`}function gi(){return`/**
|
|
1389
|
-
* @${
|
|
1389
|
+
* @${_e.slice(1)} \u2014 Postmark transactional email wrapper.
|
|
1390
1390
|
*
|
|
1391
1391
|
* Docs: https://postmarkapp.com/developer
|
|
1392
1392
|
*/
|
|
@@ -1424,7 +1424,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1424
1424
|
|
|
1425
1425
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1426
1426
|
`}function fi(){return`/**
|
|
1427
|
-
* @${
|
|
1427
|
+
* @${_e.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
|
|
1428
1428
|
*
|
|
1429
1429
|
* Docs: https://docs.aws.amazon.com/ses
|
|
1430
1430
|
*/
|
|
@@ -1480,7 +1480,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1480
1480
|
|
|
1481
1481
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1482
1482
|
`}function yi(){return`/**
|
|
1483
|
-
* @${
|
|
1483
|
+
* @${_e.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
|
|
1484
1484
|
*
|
|
1485
1485
|
* Docs: https://help.aliyun.com/product/29412.html
|
|
1486
1486
|
*/
|
|
@@ -1530,7 +1530,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1530
1530
|
|
|
1531
1531
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1532
1532
|
`}function Si(){return`/**
|
|
1533
|
-
* @${
|
|
1533
|
+
* @${_e.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
|
|
1534
1534
|
*
|
|
1535
1535
|
* Docs: https://cloud.tencent.com/document/product/1288
|
|
1536
1536
|
*/
|
|
@@ -1578,7 +1578,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1578
1578
|
|
|
1579
1579
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1580
1580
|
`}function Ei(){return`/**
|
|
1581
|
-
* @${
|
|
1581
|
+
* @${_e.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
|
|
1582
1582
|
*
|
|
1583
1583
|
* Docs: https://qiye.163.com/help
|
|
1584
1584
|
*/
|
|
@@ -1616,8 +1616,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1616
1616
|
|
|
1617
1617
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1618
1618
|
`}function hi(e){switch(e){case"resend":return mi();case"postmark":return gi();case"ses":return fi();case"aliyun-dm":return yi();case"tencent-ses":return Si();case"netease":return Ei();case"none":return`export {};
|
|
1619
|
-
`}}function vi(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),e.id==="aliyun-dm"&&(t["@alicloud/openapi-client"]="^0.4.12");let o={name:
|
|
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(
|
|
1619
|
+
`}}function vi(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),e.id==="aliyun-dm"&&(t["@alicloud/openapi-client"]="^0.4.12");let o={name:_e,version:"0.1.0",private:!0,description:`Transactional email via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
|
|
1620
|
+
`}async function jn(e,t,o){if(t==="none")return;let n=Fn(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${bt.map(s=>s.id).join(", ")}`);let r=he.join(e,"packages","email"),i=he.join(r,"src");ve.existsSync(i)&&ve.rmSync(i,{recursive:!0,force:!0}),$t(he.join(r,"package.json"),vi(n)),$t(he.join(i,"types.ts"),ui),$t(he.join(i,"index.ts"),hi(n.id)),li(e,di(n))}import It from"fs";import Vn from"path";async function Kn(e,t){let o=`# Automatically injected by create-sailor
|
|
1621
1621
|
DATABASE_URL="${String(t.databaseUrl)}"
|
|
1622
1622
|
|
|
1623
1623
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
|
|
@@ -1625,13 +1625,13 @@ CLERK_SECRET_KEY="${String(t.clerkSecret)}"
|
|
|
1625
1625
|
|
|
1626
1626
|
NEXT_PUBLIC_SITE_URL="http://localhost:3000"
|
|
1627
1627
|
`,n=Vn.join(e,".env"),r=Vn.join(e,".env.local");!It.existsSync(n)&&!It.existsSync(r)?It.writeFileSync(r,o):It.appendFileSync(r,`
|
|
1628
|
-
`+o)}import Yn from"crypto";import
|
|
1628
|
+
`+o)}import Yn from"crypto";import st from"fs";import Bn from"path";function Pe(e){return Yn.randomBytes(e).toString("base64").replace(/=+$/,"")}function _i(e){return Yn.randomBytes(e).toString("hex")}function Pi(){return{AUTH_SECRET:Pe(32),NEXTAUTH_SECRET:Pe(32),BETTER_AUTH_SECRET:Pe(32),JWT_SECRET:Pe(32),WEBHOOK_SECRET:_i(16),ENCRYPTION_KEY:Pe(32),API_SECRET_KEY:Pe(32),SESSION_SECRET:Pe(32)}}function bi(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Ii(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=bi(o);return e.replace(n,`${t}="${r}"`)}async function $n(e){let t=Bn.join(e,".env.example"),o=Bn.join(e,".env.local");if(!st.existsSync(t))return null;try{let n=st.readFileSync(t,"utf8"),r=Pi(),s=st.existsSync(o)?st.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))s=Ii(s,c,r[c]);return st.writeFileSync(o,s),r}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate env secrets: ${r}`),new Error(`Unable to write .env.local: ${r}`)}}var At=[{id:"vercel-flags",name:"Vercel Flags SDK",region:"global",envVars:["FLAGS_SECRET"],docs:"https://vercel.com/docs/workflow-collaboration/feature-flags",description:"Native Vercel feature flags"},{id:"growthbook",name:"GrowthBook",region:"both",envVars:["GROWTHBOOK_API_HOST","GROWTHBOOK_CLIENT_KEY","GROWTHBOOK_DECRYPTION_KEY"],docs:"https://docs.growthbook.io",description:"Open-source A/B testing + flags"},{id:"configcat",name:"ConfigCat",region:"global",envVars:["CONFIGCAT_SDK_KEY"],docs:"https://configcat.com/docs/",description:"Feature flag & config management"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function qn(e){return At.find(t=>t.id===e)}var Ic=At.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Gn(e,t,o="global"){let n=qn(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${At.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"feature-flags");return}n.envVars.length>0&&q(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{execFileSync as Xn}from"child_process";import x from"fs";import Ai from"os";import ie from"path";import Ci from"ignore";var wi={mirror:{repo:process.env.SAILOR_TEMPLATE_REPO||"Nebutra/Sailor-Template",ref:process.env.SAILOR_TEMPLATE_REF||"main",applyIgnore:!1,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"},main:{repo:"Nebutra/Nebutra-Sailor",ref:"main",applyIgnore:!0,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"}};function Ri(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function xi(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function zn(e){return/^[0-9a-f]{7,40}$/i.test(e)}function Ni(e,t){let o=`https://github.com/${e}.git`,n=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of n)try{let i=Xn("git",["ls-remote",o,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!i)continue;let[s]=i.split(/\s+/);if(zn(s))return s}catch{}return null}async function ki(e,t){if(zn(t))return t;let o=await fetch(`https://api.github.com/repos/${e}/commits/${encodeURIComponent(t)}`,{headers:{Accept:"application/vnd.github+json","User-Agent":"create-sailor"}});if(!o.ok){let r=Ni(e,t);if(r)return r;throw new Error(`Failed to resolve ${e}@${t} (GitHub API ${o.status})`)}let n=await o.json();if(typeof n.sha!="string"||n.sha.length===0)throw new Error(`GitHub API did not return a commit SHA for ${e}@${t}`);return n.sha}function Qn(e,t,o){let n=x.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let i=ie.join(t,r.name),s=ie.relative(e,i).split(ie.sep).join("/");r.isDirectory()?(o.push(s+"/"),Qn(e,i,o)):o.push(s)}}function Ti(e){let t=ie.join(e,".templateignore");if(!x.existsSync(t))return;let o=x.readFileSync(t,"utf8"),n=Ci().add(o),r=[];Qn(e,e,r);let i=r.map(a=>a.endsWith("/")?a.slice(0,-1):a),s=new Set(n.filter(i)),c=i.filter(a=>!s.has(a)).sort((a,d)=>d.split("/").length-a.split("/").length);for(let a of c){let d=ie.join(e,a);try{x.existsSync(d)&&x.rmSync(d,{recursive:!0,force:!0})}catch{}}try{x.existsSync(t)&&x.rmSync(t,{force:!0})}catch{}}async function Hn(e,t){let o=await fetch(e,{headers:{Accept:"application/octet-stream","User-Agent":"create-sailor"}});if(!o.ok)throw new Error(`Failed to download archive (${o.status})`);let n=Buffer.from(await o.arrayBuffer());if(n.byteLength<1024)throw new Error(`Downloaded archive is unexpectedly small (${n.byteLength} bytes)`);x.writeFileSync(t,n);let r=x.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function Wn(e,t){Xn("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function Jn(e){try{let t=x.readdirSync(e);for(let o of t)x.rmSync(ie.join(e,o),{recursive:!0,force:!0})}catch{}}async function Oi(e,t){let o=x.mkdtempSync(ie.join(Ai.tmpdir(),"create-sailor-")),n=ie.join(o,"template.tar.gz");try{let r=await ki(e.repo,e.ref);await Hn(xi(e.repo,r),n),Wn(n,t)}catch(r){if(!e.allowMutableFallback)throw r;Jn(t),await Hn(Ri(e.repo,e.ref),n),Wn(n,t)}finally{x.rmSync(o,{recursive:!0,force:!0})}}async function Zn(e){x.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let i=wi[r];try{if(await Oi(i,e),i.applyIgnore)try{Ti(e)}catch(s){throw new Error(`Template cloned, but .templateignore processing failed: ${s instanceof Error?s.message:String(s)}`)}return}catch(s){n=s instanceof Error?s:new Error(String(s)),Jn(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
|
|
1629
1629
|
|
|
1630
1630
|
Ensure you have internet access and 'tar' installed.
|
|
1631
|
-
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import
|
|
1632
|
-
`);
|
|
1633
|
-
`);
|
|
1634
|
-
`+t):
|
|
1631
|
+
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import be from"fs";import qt from"path";async function eo(e,t){let o=qt.join(e,"packages","mcp");if(t==="off"){be.existsSync(o)&&be.rmSync(o,{recursive:!0,force:!0});let r=qt.join(e,"packages","cli","src","commands","mcp-server.ts");be.existsSync(r)&&be.rmSync(r,{force:!0});return}let n=qt.join(e,".env.example");if(be.existsSync(n)){let r=be.readFileSync(n,"utf-8"),i="# MCP Server (Agent-friendly API)";if(!r.includes(i)){let s=["","# =============================================",i,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
|
|
1632
|
+
`);be.appendFileSync(n,s)}}}import at from"fs";import to from"path";async function no(e,t,o){let n=to.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){at.existsSync(n)&&at.rmSync(n,{recursive:!0,force:!0});return}let i=to.join(e,".env.example");if(!at.existsSync(i))return;let s=at.readFileSync(i,"utf-8"),c="# Metering (usage-based billing)";if(!s.includes(c)){let a=["","# =============================================",c,"# Docs: see packages/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
|
|
1633
|
+
`);at.appendFileSync(i,a)}}import He from"fs";import T from"path";var oo=[{id:"sentry",name:"Sentry",region:"both",envVars:["SENTRY_DSN","NEXT_PUBLIC_SENTRY_DSN"],docs:"https://docs.sentry.io",pkg:"@sentry/nextjs",instrumentationFile:"apps/web/instrumentation.ts"},{id:"datadog",name:"Datadog",region:"global",envVars:["DD_API_KEY","DD_APP_KEY","DD_SITE"],docs:"https://docs.datadoghq.com",pkg:"dd-trace",instrumentationFile:"apps/web/instrumentation.ts"},{id:"bugsnag",name:"Bugsnag",region:"global",envVars:["BUGSNAG_API_KEY","NEXT_PUBLIC_BUGSNAG_API_KEY"],docs:"https://docs.bugsnag.com",pkg:"@bugsnag/js",instrumentationFile:"apps/web/src/lib/monitoring/bugsnag.ts"},{id:"aliyun-arms",name:"\u963F\u91CC\u4E91 ARMS",region:"cn",envVars:["ALIYUN_ARMS_LICENSE_KEY","ALIYUN_ARMS_APP_NAME","NEXT_PUBLIC_ARMS_PID"],docs:"https://help.aliyun.com/product/34364.html",instrumentationFile:"apps/web/src/components/monitoring/ArmsScript.tsx"},{id:"tingyun",name:"\u542C\u4E91 TingYun",region:"cn",envVars:["TINGYUN_LICENSE_KEY","NEXT_PUBLIC_TINGYUN_APP_KEY"],docs:"https://www.tingyun.com/docs",instrumentationFile:"apps/web/src/components/monitoring/TingYunScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],Kc=oo.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function ro(e){return oo.find(t=>t.id===e)}function Ui(e){He.mkdirSync(e,{recursive:!0})}function W(e,t){Ui(T.dirname(e)),He.writeFileSync(e,t)}function ct(e,t){let o=T.join(e,".env.example");He.existsSync(o)?He.appendFileSync(o,`
|
|
1634
|
+
`+t):He.writeFileSync(o,t)}function Li(e){let t=`import * as Sentry from "@sentry/nextjs";
|
|
1635
1635
|
|
|
1636
1636
|
Sentry.init({
|
|
1637
1637
|
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
@@ -1843,8 +1843,8 @@ export function TingYunScript() {
|
|
|
1843
1843
|
`)}function $i(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
|
|
1844
1844
|
TINGYUN_LICENSE_KEY=
|
|
1845
1845
|
NEXT_PUBLIC_TINGYUN_APP_KEY=
|
|
1846
|
-
`}async function io(e,t,o="global"){let n=ro(t);if(!n||n.id==="none")return;let r=T.join(e,"apps","web");if(!
|
|
1847
|
-
`)}}import Z from"fs";import
|
|
1846
|
+
`}async function io(e,t,o="global"){let n=ro(t);if(!n||n.id==="none")return;let r=T.join(e,"apps","web");if(!He.existsSync(r))return;let i=n.id;try{switch(i){case"sentry":Li(r),ct(e,Mi());return;case"datadog":Di(r),ct(e,Fi());return;case"bugsnag":ji(r),ct(e,Vi());return;case"aliyun-arms":Ki(r),ct(e,Bi());return;case"tingyun":Yi(r),ct(e,$i());return;default:return}}catch(s){throw console.error(`Failed to apply monitoring selection "${t}":`,s),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Ct=[{id:"novu",name:"Novu",region:"both",envVars:["NOVU_API_KEY","NOVU_APPLICATION_IDENTIFIER"],docs:"https://docs.novu.co",description:"Multi-channel notification infrastructure"},{id:"knock",name:"Knock",region:"global",envVars:["KNOCK_API_KEY","KNOCK_SIGNING_KEY","KNOCK_PUBLIC_API_KEY"],docs:"https://docs.knock.app",description:"Product notifications platform"},{id:"custom",name:"Custom (direct dispatchers)",region:"both",envVars:[],docs:"",description:"Use email + sms + push directly"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function so(e){return Ct.find(t=>t.id===e)}var Hc=Ct.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ao(e,t,o="global"){let n=so(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Ct.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"notifications");return}n.envVars.length>0&&q(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"NOTIFICATIONS_PROVIDER",n.id)}import Gt from"fs";import qi from"path";async function co(e,t){let o=qi.join(e,"package.json");if(Gt.existsSync(o)){let n=Gt.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",Gt.writeFileSync(o,JSON.stringify(r,null,2)+`
|
|
1847
|
+
`)}}import Z from"fs";import pt from"path";var Gi=["stripe","lemonsqueezy","chinapay","polar"];function po(e){Z.existsSync(e)&&Z.rmSync(e,{recursive:!0,force:!0})}function Hi(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Wi(e,t){let o=pt.join(e,".env.example");Z.existsSync(o)?Z.appendFileSync(o,`
|
|
1848
1848
|
`+t):Z.writeFileSync(o,t)}function Xi(e){switch(e){case"stripe":return`# Stripe
|
|
1849
1849
|
STRIPE_SECRET_KEY=
|
|
1850
1850
|
STRIPE_WEBHOOK_SECRET=
|
|
@@ -1860,13 +1860,13 @@ CHINAPAY_WECHAT_ENABLED=true
|
|
|
1860
1860
|
CHINAPAY_APP_ID=
|
|
1861
1861
|
CHINAPAY_APP_SECRET=
|
|
1862
1862
|
CHINAPAY_ALIPAY_ENABLED=true
|
|
1863
|
-
`}}async function lo(e,t){let o=
|
|
1864
|
-
`),n=[],r=e.includes("#"),i=0;for(;i<o.length;){let
|
|
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]*?)\}\)/,
|
|
1863
|
+
`}}async function lo(e,t){let o=pt.join(e,"packages","billing");if(!Z.existsSync(o))return;if(t==="none"){po(o);return}let n=pt.join(o,"src"),r=new Set(Hi(t));for(let s of Gi)r.has(s)||po(pt.join(n,s));let i=pt.join(n,"checkout","types.ts");if(Z.existsSync(i)){let s=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=Z.readFileSync(i,"utf8"),a=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${s}";`);a!==c&&Z.writeFileSync(i,a)}Wi(e,Xi(t))}import se from"fs";import We from"path";var go=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),Ht=/@sailor:([^\s*]+)/;function zi(e,t){let{providerIds:o,customEndpoint:n}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:o.includes(r)}}if(e==="cn-compatible"){let r=o.some(i=>go.has(i));return{marker:e,keep:r||!!n}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:o.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!n}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function uo(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function mo(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function fo(e,t){let o=e.split(`
|
|
1864
|
+
`),n=[],r=e.includes("#"),i=0;for(;i<o.length;){let s=o[i],c=s.match(Ht);if(!c){n.push(s),i++;continue}let{marker:a,keep:d}=zi(c[1],t);if(a==="registry-entries"){n.push(r?mo(s):uo(s)),i++;continue}if(d){let u=r?mo(s):uo(s);u.trim().length>0&&n.push(u);let h=i+1;for(;h<o.length&&o[h].trim()!==""&&!Ht.test(o[h]);)n.push(o[h]),h++;h<o.length&&o[h].trim()===""&&(n.push(o[h]),h++),i=h}else{let u=i+1;for(;u<o.length&&o[u].trim()!==""&&!Ht.test(o[u]);)u++;u<o.length&&o[u].trim()===""&&u++,i=u}}return Qi(n.join(`
|
|
1865
|
+
`),t)}function Qi(e,t){let{providerIds:o,customEndpoint:n}=t,r=new Set;for(let d of o)["openai","anthropic","google","mistral","xai"].includes(d)&&r.add(d),r.add(d.replace(/-/g,"_")),r.add(d);n&&r.add("custom");let i=/createProviderRegistry\(\{([\s\S]*?)\}\)/,s=e.match(i);if(!s)return e;let a=s[1].split(`
|
|
1866
1866
|
`).filter(d=>{let u=d.trim();if(u===""||u.startsWith("//"))return!0;let h=u.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return h?r.has(h[1]):!0}).join(`
|
|
1867
|
-
`);return e.replace(i,`createProviderRegistry({${
|
|
1868
|
-
`+r);let
|
|
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
|
|
1867
|
+
`);return e.replace(i,`createProviderRegistry({${a}})`)}function Ji(e,t){let o=We.join(t,"registry.ts.template"),n=se.readFileSync(o,"utf-8");return fo(n,e)}function Zi(e,t){let o=We.join(t,".env.example.template"),n=se.readFileSync(o,"utf-8");return fo(n,e)}async function yo(e,t,o){let n=Ji(t,o),r=Zi(t,o),i=We.join(e,"packages/agents/src");await se.promises.mkdir(i,{recursive:!0}),await se.promises.writeFile(We.join(i,"registry.ts"),n),await se.promises.appendFile(We.join(e,".env.example"),`
|
|
1868
|
+
`+r);let s={ai:"latest"},{providerIds:c,customEndpoint:a}=t;(c.includes("openai")||a||c.some(u=>go.has(u)))&&(s["@ai-sdk/openai"]="latest",s["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(s["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(s["@ai-sdk/google"]="latest"),c.includes("mistral")&&(s["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(s["@ai-sdk/openai"]="latest");let d=We.join(e,"package.json");if(se.existsSync(d)){let u=JSON.parse(await se.promises.readFile(d,"utf-8"));u.dependencies||(u.dependencies={});for(let[h,O]of Object.entries(s))u.dependencies[h]=O;await se.promises.writeFile(d,JSON.stringify(u,null,2)+`
|
|
1869
|
+
`)}}import g from"fs";import P from"path";function So(e,t){if(!g.existsSync(e))return;let o=g.readdirSync(e);for(let n of o){let r=P.join(e,n);g.statSync(r).isDirectory()?So(r,t):t(r)}}async function Eo(e,t){let o=P.join(e,"package.json");if(!g.existsSync(o))return;let n=JSON.parse(g.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=P.join(e,"packages","db");if(g.existsSync(r)){let i=P.join(r,"prisma");g.existsSync(i)&&g.rmSync(i,{recursive:!0,force:!0});let s=P.join(r,"package.json");if(g.existsSync(s)){let a=JSON.parse(g.readFileSync(s,"utf8"));a.dependencies&&delete a.dependencies["@prisma/client"],a.devDependencies&&delete a.devDependencies.prisma,g.writeFileSync(s,JSON.stringify(a,null,2)+`
|
|
1870
1870
|
`)}let c=P.join(r,"src","index.ts");g.existsSync(c)&&g.writeFileSync(c,`
|
|
1871
1871
|
export const prisma = {} as any;
|
|
1872
1872
|
export const db = {} as any;
|
|
@@ -1913,7 +1913,7 @@ export type UsageAggregate = any;
|
|
|
1913
1913
|
export type UsageLedgerEntry = any;
|
|
1914
1914
|
export type UsageType = any;
|
|
1915
1915
|
export type UsageLedgerSource = any;
|
|
1916
|
-
`)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=P.join(e,"apps");if(g.existsSync(r)){let i=g.readdirSync(r);for(let
|
|
1916
|
+
`)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=P.join(e,"apps");if(g.existsSync(r)){let i=g.readdirSync(r);for(let s of i){let c=P.join(r,s);if(!g.statSync(c).isDirectory())continue;let a=P.join(c,"src","app");if(!g.existsSync(a))continue;["[lang]","[locale]"].forEach(v=>{let l=P.join(a,v);if(g.existsSync(l)){let R=g.readdirSync(l);for(let mt of R)g.renameSync(P.join(l,mt),P.join(a,mt));g.rmdirSync(l)}}),["src/middleware.ts","middleware.ts"].forEach(v=>{let l=P.join(c,v);g.existsSync(l)&&g.rmSync(l)});let d=P.join(c,"src","lib");g.existsSync(d)||g.mkdirSync(d,{recursive:!0});let u=P.join(d,"mock-i18n.ts");g.writeFileSync(u,`
|
|
1917
1917
|
import React from 'react';
|
|
1918
1918
|
export function useTranslations(namespace?: string): any { return (key: string) => key; }
|
|
1919
1919
|
export function useLocale() { return 'en'; }
|
|
@@ -1954,13 +1954,13 @@ export * from './mock-i18n';
|
|
|
1954
1954
|
export { default } from './mock-i18n';
|
|
1955
1955
|
`);let M=P.join(c,"tsconfig.json");if(g.existsSync(M))try{let v=g.readFileSync(M,"utf8");if(v.includes('"paths": {')){let l=v.replace(/"paths":\s*\{/,`"paths": {
|
|
1956
1956
|
"next-intl": ["./src/lib/mock-i18n"],
|
|
1957
|
-
"next-intl/*": ["./src/lib/mock-i18n"],`);g.writeFileSync(M,l)}}catch{}let D=P.join(c,"src");g.existsSync(D)&&So(D,v=>{if(!v.endsWith(".ts")&&!v.endsWith(".tsx"))return;let l=g.readFileSync(v,"utf8"),R=!1;v.endsWith("src/app/layout.tsx")&&l.includes("../providers")&&(l=l.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),R=!0),l=l.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),l=l.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),l.match(/locale\s*:\s*any/)&&(l=l.replace(/locale\s*:\s*any/g,"locale: string"),R=!0),l.match(/lang\s*:\s*any/)&&(l=l.replace(/lang\s*:\s*any/g,"lang: string"),R=!0),l.match(/requestLocale\s*:\s*any/)&&(l=l.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),R=!0),l.match(/\(locale\s*=\s*(.*)\)/)&&(l=l.replace(/\(locale\s*=\s*(.*)\)/g,"() "),R=!0),l.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(l=l.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),R=!0),(v.endsWith("src/app/layout.tsx")||v.endsWith("src/app/sitemap.ts")||v.endsWith("src/app/robots.ts")||v.endsWith("src/components/ui/locale-switcher.tsx")||v.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(l=l.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),l=l.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),l=l.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),l=l.replace(/\(l\)\s*=>/g,"(l: any) =>"),R=!0),v.endsWith("src/i18n/request.ts")&&(l=l.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),R=!0),(l.match(/locale\s*:/)||l.match(/lang\s*:/))&&(R=!0),R&&g.writeFileSync(v,l)});let
|
|
1957
|
+
"next-intl/*": ["./src/lib/mock-i18n"],`);g.writeFileSync(M,l)}}catch{}let D=P.join(c,"src");g.existsSync(D)&&So(D,v=>{if(!v.endsWith(".ts")&&!v.endsWith(".tsx"))return;let l=g.readFileSync(v,"utf8"),R=!1;v.endsWith("src/app/layout.tsx")&&l.includes("../providers")&&(l=l.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),R=!0),l=l.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),l=l.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),l.match(/locale\s*:\s*any/)&&(l=l.replace(/locale\s*:\s*any/g,"locale: string"),R=!0),l.match(/lang\s*:\s*any/)&&(l=l.replace(/lang\s*:\s*any/g,"lang: string"),R=!0),l.match(/requestLocale\s*:\s*any/)&&(l=l.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),R=!0),l.match(/\(locale\s*=\s*(.*)\)/)&&(l=l.replace(/\(locale\s*=\s*(.*)\)/g,"() "),R=!0),l.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(l=l.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),R=!0),(v.endsWith("src/app/layout.tsx")||v.endsWith("src/app/sitemap.ts")||v.endsWith("src/app/robots.ts")||v.endsWith("src/components/ui/locale-switcher.tsx")||v.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(l=l.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),l=l.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),l=l.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),l=l.replace(/\(l\)\s*=>/g,"(l: any) =>"),R=!0),v.endsWith("src/i18n/request.ts")&&(l=l.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),R=!0),(l.match(/locale\s*:/)||l.match(/lang\s*:/))&&(R=!0),R&&g.writeFileSync(v,l)});let Xe=P.join(c,"package.json");if(g.existsSync(Xe)){let v=JSON.parse(g.readFileSync(Xe,"utf8"));v.dependencies&&delete v.dependencies["next-intl"],g.writeFileSync(Xe,JSON.stringify(v,null,2)+`
|
|
1958
1958
|
`)}}}}g.writeFileSync(o,JSON.stringify(n,null,2)+`
|
|
1959
|
-
`)}import{getSchema as es,printSchema as ts}from"@mrleebo/prisma-ast";var ns=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function os(e){return e.type==="comment"&&e.text.trim().startsWith("///")}function rs(e){let t=ns.exec(e.trim());if(!t)return null;let[,o,n]=t,r=n.split("|").map(i=>i.trim()).filter(i=>i.length>0);return{flag:o,values:r}}function is(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=rs(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function Wt(e,t){let o=es(e),n=new Set;for(let c=0;c<o.list.length;c++){if(o.list[c].type!=="model")continue;let d=is(o.list,c);if(!d)continue;let u=t[d.parsed.flag];if(u!==void 0&&d.parsed.values.includes(u))n.add(d.annIndex);else{n.add(c);for(let M=c-1;M>=0;M--){let D=o.list[M];if(D.type==="comment"&&os(D)){n.add(M);continue}break}let O=o.list[c+1];O&&O.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,
|
|
1960
|
-
`);
|
|
1961
|
-
`)}async function _o(e,t,o){let n=Xt.join(e,"packages","queue");if(t==="none"){
|
|
1962
|
-
`);
|
|
1963
|
-
`)}async function Io(e,t,o){let n=zt.join(e,"packages","search");if(t==="none"){
|
|
1959
|
+
`)}import{getSchema as es,printSchema as ts}from"@mrleebo/prisma-ast";var ns=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function os(e){return e.type==="comment"&&e.text.trim().startsWith("///")}function rs(e){let t=ns.exec(e.trim());if(!t)return null;let[,o,n]=t,r=n.split("|").map(i=>i.trim()).filter(i=>i.length>0);return{flag:o,values:r}}function is(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=rs(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function Wt(e,t){let o=es(e),n=new Set;for(let c=0;c<o.list.length;c++){if(o.list[c].type!=="model")continue;let d=is(o.list,c);if(!d)continue;let u=t[d.parsed.flag];if(u!==void 0&&d.parsed.values.includes(u))n.add(d.annIndex);else{n.add(c);for(let M=c-1;M>=0;M--){let D=o.list[M];if(D.type==="comment"&&os(D)){n.add(M);continue}break}let O=o.list[c+1];O&&O.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,a)=>!n.has(a)),i=[];for(let c of r){let a=i[i.length-1];c.type==="break"&&a&&a.type==="break"||i.push(c)}return ts({type:"schema",list:i})}import ae from"fs";import Xt from"path";var wt=[{id:"qstash",name:"Upstash QStash",region:"both",envVars:["QSTASH_TOKEN","QSTASH_CURRENT_SIGNING_KEY","QSTASH_NEXT_SIGNING_KEY"],docs:"https://upstash.com/docs/qstash",description:"Serverless HTTP-based queue"},{id:"bullmq",name:"BullMQ",region:"both",envVars:["REDIS_URL"],docs:"https://docs.bullmq.io",description:"Redis-backed job queue"},{id:"upstash",name:"Upstash Kafka",region:"both",envVars:["UPSTASH_KAFKA_REST_URL","UPSTASH_KAFKA_REST_USERNAME","UPSTASH_KAFKA_REST_PASSWORD"],docs:"https://upstash.com/docs/kafka",description:"Serverless Kafka"},{id:"sqs",name:"AWS SQS",region:"global",envVars:["AWS_SQS_QUEUE_URL","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"],docs:"https://docs.aws.amazon.com/AWSSimpleQueueService/",description:"AWS managed queue"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip queue package"}];function ho(e){return wt.find(t=>t.id===e)}var up=wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function vo(e){return ae.existsSync(e)?ae.readFileSync(e,"utf-8"):null}function ss(e,t){let o=Xt.join(e,".env.example"),n=vo(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
|
|
1960
|
+
`);ae.appendFileSync(o,i)}function as(e,t,o){let n=Xt.join(e,".env.example"),r=vo(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ae.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ae.appendFileSync(n,`${t}="${o}"
|
|
1961
|
+
`)}async function _o(e,t,o){let n=Xt.join(e,"packages","queue");if(t==="none"){ae.existsSync(n)&&ae.rmSync(n,{recursive:!0,force:!0});return}let r=ho(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${wt.map(i=>i.id).join(", ")}`);ae.existsSync(n)&&(ss(e,r),as(e,"QUEUE_PROVIDER",t))}import ce from"fs";import zt from"path";var Rt=[{id:"meilisearch",name:"Meilisearch",region:"both",envVars:["MEILISEARCH_HOST","MEILISEARCH_MASTER_KEY"],docs:"https://docs.meilisearch.com",description:"Self-hostable search"},{id:"typesense",name:"Typesense",region:"both",envVars:["TYPESENSE_HOST","TYPESENSE_PORT","TYPESENSE_PROTOCOL","TYPESENSE_API_KEY"],docs:"https://typesense.org/docs",description:"Open-source search"},{id:"algolia",name:"Algolia",region:"global",envVars:["ALGOLIA_APP_ID","ALGOLIA_ADMIN_API_KEY","ALGOLIA_SEARCH_API_KEY"],docs:"https://www.algolia.com/doc/",description:"Managed search as a service"},{id:"pgvector",name:"pgvector (Postgres)",region:"both",envVars:["DATABASE_URL"],docs:"https://github.com/pgvector/pgvector",description:"Postgres vector + full-text"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip search package"}];function Po(e){return Rt.find(t=>t.id===e)}var Ep=Rt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function bo(e){return ce.existsSync(e)?ce.readFileSync(e,"utf-8"):null}function cs(e,t){let o=zt.join(e,".env.example"),n=bo(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
|
|
1962
|
+
`);ce.appendFileSync(o,i)}function ps(e,t,o){let n=zt.join(e,".env.example"),r=bo(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ce.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ce.appendFileSync(n,`${t}="${o}"
|
|
1963
|
+
`)}async function Io(e,t,o){let n=zt.join(e,"packages","search");if(t==="none"){ce.existsSync(n)&&ce.rmSync(n,{recursive:!0,force:!0});return}let r=Po(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Rt.map(i=>i.id).join(", ")}`);ce.existsSync(n)&&(cs(e,r),ps(e,"SEARCH_PROVIDER",t))}import pe from"fs";import Ie from"path";function ls(e){let t=[Ie.join(e,"packages","db"),Ie.join(e,"apps","web")];for(let o of t){let n=Ie.join(o,"prisma","schema.prisma");if(pe.existsSync(n))return{packageDir:o,seedPath:Ie.join(o,"prisma","seed.ts"),packageJsonPath:Ie.join(o,"package.json")}}return null}function ds(e){try{let t=pe.readFileSync(e,"utf8"),o=new Set,n=/^\s*model\s+(\w+)\s*\{/gm,r=n.exec(t);for(;r;)o.add(r[1]),r=n.exec(t);return o}catch{return new Set}}function us(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
|
|
1964
1964
|
const admin = await prisma.user.create({
|
|
1965
1965
|
data: {
|
|
1966
1966
|
clerkId: "user_mock_admin",
|
|
@@ -1991,7 +1991,7 @@ export { default } from './mock-i18n';
|
|
|
1991
1991
|
console.log("\\u2713 Created admin user:", admin.email);
|
|
1992
1992
|
} catch (err) {
|
|
1993
1993
|
console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
|
|
1994
|
-
}`}function ms(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),i=us(e,n),
|
|
1994
|
+
}`}function ms(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),i=us(e,n),s=o?` let tenants: Array<{ id: string; name: string }> = [];
|
|
1995
1995
|
try {
|
|
1996
1996
|
tenants = await Promise.all([
|
|
1997
1997
|
prisma.tenant.create({
|
|
@@ -2041,7 +2041,7 @@ async function main(): Promise<void> {
|
|
|
2041
2041
|
console.log("\\uD83C\\uDF31 Seeding database...");
|
|
2042
2042
|
|
|
2043
2043
|
// --- Tenants ---------------------------------------------------------
|
|
2044
|
-
${
|
|
2044
|
+
${s}
|
|
2045
2045
|
|
|
2046
2046
|
// --- Admin user ------------------------------------------------------
|
|
2047
2047
|
${i}
|
|
@@ -2060,9 +2060,9 @@ main()
|
|
|
2060
2060
|
.finally(async () => {
|
|
2061
2061
|
await prisma.$disconnect();
|
|
2062
2062
|
});
|
|
2063
|
-
`}function gs(e){if(
|
|
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=
|
|
2065
|
-
`+t):
|
|
2063
|
+
`}function gs(e){if(pe.existsSync(e))try{let t=pe.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let i=o.prisma??{};if(i.seed||(i.seed="tsx prisma/seed.ts",r=!0),!r)return;let s={...o,scripts:n,prisma:i};pe.writeFileSync(e,JSON.stringify(s,null,2)+`
|
|
2064
|
+
`)}catch(t){let o=t instanceof Error?t.message:String(t);console.warn(`[create-sailor] Failed to patch seed scripts in ${e}: ${o}`)}}async function Ao(e,t){let o=ls(e);if(o)try{let n=Ie.join(o.packageDir,"prisma","schema.prisma"),r=ds(n),i=ms(t,r),s=Ie.dirname(o.seedPath);pe.existsSync(s)||pe.mkdirSync(s,{recursive:!0}),pe.writeFileSync(o.seedPath,i),gs(o.packageJsonPath)}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate seed data: ${r}`),new Error(`Unable to write prisma/seed.ts: ${r}`)}}import le from"fs";import Ae from"path";var xt=[{id:"twilio",name:"Twilio",region:"global",envVars:["TWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN","TWILIO_FROM_NUMBER"],docs:"https://www.twilio.com/docs/sms",pkgs:["twilio"]},{id:"messagebird",name:"MessageBird (Bird)",region:"global",envVars:["MESSAGEBIRD_ACCESS_KEY","MESSAGEBIRD_ORIGINATOR"],docs:"https://developers.messagebird.com/api/sms-messaging/",pkgs:["messagebird"]},{id:"plivo",name:"Plivo",region:"global",envVars:["PLIVO_AUTH_ID","PLIVO_AUTH_TOKEN","PLIVO_FROM_NUMBER"],docs:"https://www.plivo.com/docs/sms/",pkgs:["plivo"]},{id:"aliyun-sms",name:"\u963F\u91CC\u4E91\u77ED\u4FE1 Aliyun SMS",region:"cn",envVars:["ALIYUN_SMS_ACCESS_KEY","ALIYUN_SMS_ACCESS_SECRET","ALIYUN_SMS_SIGN_NAME","ALIYUN_SMS_TEMPLATE_CODE","ALIYUN_SMS_ENDPOINT"],docs:"https://help.aliyun.com/product/44282.html",pkgs:["@alicloud/dysmsapi20170525","@alicloud/openapi-client"]},{id:"tencent-sms",name:"\u817E\u8BAF\u4E91\u77ED\u4FE1 Tencent SMS",region:"cn",envVars:["TENCENT_SMS_SECRET_ID","TENCENT_SMS_SECRET_KEY","TENCENT_SMS_SDK_APP_ID","TENCENT_SMS_SIGN_NAME","TENCENT_SMS_TEMPLATE_ID","TENCENT_SMS_REGION"],docs:"https://cloud.tencent.com/document/product/382",pkgs:["tencentcloud-sdk-nodejs-sms"]},{id:"yunpian",name:"\u4E91\u7247 Yunpian",region:"cn",envVars:["YUNPIAN_API_KEY","YUNPIAN_SIGN"],docs:"https://www.yunpian.com/official/document/sms/zh_CN/introduction_product_intro",pkgs:["yunpian-nodejs-sdk"]},{id:"none",name:"None",region:"both",envVars:[],docs:""}],wp=xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Co(e){return xt.find(t=>t.id===e)}var fs="@nebutra/sms",ys={twilio:"^5.3.6",messagebird:"^4.0.1",plivo:"^4.73.0","@alicloud/dysmsapi20170525":"^2.0.24","@alicloud/openapi-client":"^0.4.12","tencentcloud-sdk-nodejs-sms":"^4.0.970","yunpian-nodejs-sdk":"^0.0.2"};function Qt(e,t){le.mkdirSync(Ae.dirname(e),{recursive:!0}),le.writeFileSync(e,t)}function Ss(e,t){let o=Ae.join(e,".env.example");le.existsSync(o)?le.appendFileSync(o,`
|
|
2065
|
+
`+t):le.writeFileSync(o,t)}function Es(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2066
2066
|
`);return`${t}
|
|
2067
2067
|
${o}
|
|
2068
2068
|
`}var hs=`/**
|
|
@@ -2365,8 +2365,8 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2365
2365
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2366
2366
|
`}function Cs(e){switch(e){case"twilio":return vs();case"messagebird":return _s();case"plivo":return Ps();case"aliyun-sms":return bs();case"tencent-sms":return Is();case"yunpian":return As();case"none":return`export {};
|
|
2367
2367
|
`}}function ws(e){let t={};for(let n of e.pkgs??[]){let r=ys[n];r&&(t[n]=r)}let o={name:fs,version:"0.1.0",private:!0,description:`Transactional SMS via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
|
|
2368
|
-
`}async function wo(e,t,o="global"){if(t==="none")return;let n=Co(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${xt.map(
|
|
2369
|
-
`+t):
|
|
2368
|
+
`}async function wo(e,t,o="global"){if(t==="none")return;let n=Co(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${xt.map(s=>s.id).join(", ")}`);let r=Ae.join(e,"packages","sms");if(!le.existsSync(r))return;let i=Ae.join(r,"src");le.existsSync(i)&&le.rmSync(i,{recursive:!0,force:!0});try{Qt(Ae.join(r,"package.json"),ws(n)),Qt(Ae.join(i,"types.ts"),hs),Qt(Ae.join(i,"index.ts"),Cs(n.id)),Ss(e,Es(n))}catch(s){throw console.error(`Failed to apply SMS selection "${t}":`,s),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import we from"fs";import Ce from"path";var lt=[{id:"r2",name:"Cloudflare R2",region:"global",envVars:["R2_ACCOUNT_ID","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY","R2_BUCKET"],docs:"https://developers.cloudflare.com/r2/api/s3/api/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"s3",name:"AWS S3",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_S3_REGION","S3_BUCKET"],docs:"https://docs.aws.amazon.com/s3/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"supabase-storage",name:"Supabase Storage",region:"global",envVars:["SUPABASE_URL","SUPABASE_SERVICE_ROLE_KEY","SUPABASE_BUCKET"],docs:"https://supabase.com/docs/guides/storage",pkg:"@supabase/supabase-js",pkgVersion:"^2.45.4"},{id:"aliyun-oss",name:"\u963F\u91CC\u4E91 OSS",region:"cn",envVars:["ALIYUN_OSS_ACCESS_KEY","ALIYUN_OSS_ACCESS_SECRET","ALIYUN_OSS_REGION","ALIYUN_OSS_BUCKET"],docs:"https://help.aliyun.com/product/31815.html",pkg:"ali-oss",pkgVersion:"^6.21.0"},{id:"tencent-cos",name:"\u817E\u8BAF\u4E91 COS",region:"cn",envVars:["TENCENT_COS_SECRET_ID","TENCENT_COS_SECRET_KEY","TENCENT_COS_BUCKET","TENCENT_COS_REGION"],docs:"https://cloud.tencent.com/document/product/436",pkg:"cos-nodejs-sdk-v5",pkgVersion:"^2.13.7"},{id:"qiniu",name:"\u4E03\u725B\u4E91 Kodo",region:"cn",envVars:["QINIU_ACCESS_KEY","QINIU_SECRET_KEY","QINIU_BUCKET","QINIU_DOMAIN"],docs:"https://developer.qiniu.com/kodo",pkg:"qiniu",pkgVersion:"^7.14.0"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function Jt(e){let t=e==="supabase"?"supabase-storage":e;return lt.some(o=>o.id===t)?t:void 0}function Ro(e){let t=Jt(e);return t?lt.find(o=>o.id===t):void 0}var Op=lt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Re="@nebutra/storage";function Zt(e,t){we.mkdirSync(Ce.dirname(e),{recursive:!0}),we.writeFileSync(e,t)}function Rs(e,t){let o=Ce.join(e,".env.example");we.existsSync(o)?we.appendFileSync(o,`
|
|
2369
|
+
`+t):we.writeFileSync(o,t)}function xs(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2370
2370
|
`);return`${t}
|
|
2371
2371
|
${o}
|
|
2372
2372
|
`}var Ns=`/**
|
|
@@ -2396,7 +2396,7 @@ export interface SignedUrlOptions {
|
|
|
2396
2396
|
contentType?: string;
|
|
2397
2397
|
}
|
|
2398
2398
|
`;function ks(){return`/**
|
|
2399
|
-
* @${
|
|
2399
|
+
* @${Re.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
|
|
2400
2400
|
*
|
|
2401
2401
|
* Docs: https://developers.cloudflare.com/r2/api/s3/api/
|
|
2402
2402
|
*/
|
|
@@ -2460,7 +2460,7 @@ export async function getSignedUrl(
|
|
|
2460
2460
|
|
|
2461
2461
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2462
2462
|
`}function Ts(){return`/**
|
|
2463
|
-
* @${
|
|
2463
|
+
* @${Re.slice(1)} \u2014 AWS S3 wrapper.
|
|
2464
2464
|
*
|
|
2465
2465
|
* Docs: https://docs.aws.amazon.com/s3/
|
|
2466
2466
|
*/
|
|
@@ -2525,7 +2525,7 @@ export async function getSignedUrl(
|
|
|
2525
2525
|
|
|
2526
2526
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2527
2527
|
`}function Os(){return`/**
|
|
2528
|
-
* @${
|
|
2528
|
+
* @${Re.slice(1)} \u2014 Supabase Storage wrapper.
|
|
2529
2529
|
*
|
|
2530
2530
|
* Docs: https://supabase.com/docs/guides/storage
|
|
2531
2531
|
*/
|
|
@@ -2588,7 +2588,7 @@ export async function getSignedUrl(
|
|
|
2588
2588
|
|
|
2589
2589
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2590
2590
|
`}function Us(){return`/**
|
|
2591
|
-
* @${
|
|
2591
|
+
* @${Re.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
|
|
2592
2592
|
*
|
|
2593
2593
|
* Docs: https://help.aliyun.com/product/31815.html
|
|
2594
2594
|
*/
|
|
@@ -2635,7 +2635,7 @@ export async function getSignedUrl(
|
|
|
2635
2635
|
|
|
2636
2636
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2637
2637
|
`}function Ls(){return`/**
|
|
2638
|
-
* @${
|
|
2638
|
+
* @${Re.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
|
|
2639
2639
|
*
|
|
2640
2640
|
* Docs: https://cloud.tencent.com/document/product/436
|
|
2641
2641
|
*/
|
|
@@ -2690,7 +2690,7 @@ export async function getSignedUrl(
|
|
|
2690
2690
|
|
|
2691
2691
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2692
2692
|
`}function Ms(){return`/**
|
|
2693
|
-
* @${
|
|
2693
|
+
* @${Re.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
|
|
2694
2694
|
*
|
|
2695
2695
|
* Docs: https://developer.qiniu.com/kodo
|
|
2696
2696
|
*/
|
|
@@ -2758,8 +2758,8 @@ export async function getSignedUrl(
|
|
|
2758
2758
|
|
|
2759
2759
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2760
2760
|
`}function Ds(e){switch(e){case"r2":return ks();case"s3":return Ts();case"supabase-storage":return Os();case"aliyun-oss":return Us();case"tencent-cos":return Ls();case"qiniu":return Ms();case"none":return`export {};
|
|
2761
|
-
`}}function Fs(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),(e.id==="r2"||e.id==="s3")&&(t["@aws-sdk/s3-request-presigner"]="^3.658.0");let o={name:
|
|
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: ${
|
|
2761
|
+
`}}function Fs(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),(e.id==="r2"||e.id==="s3")&&(t["@aws-sdk/s3-request-presigner"]="^3.658.0");let o={name:Re,version:"0.1.0",private:!0,description:`Object storage via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
|
|
2762
|
+
`}async function xo(e,t,o){if(t==="none")return;let n=Ro(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${lt.map(s=>s.id).join(", ")}`);let r=Ce.join(e,"packages","storage"),i=Ce.join(r,"src");we.existsSync(i)&&we.rmSync(i,{recursive:!0,force:!0}),Zt(Ce.join(r,"package.json"),Fs(n)),Zt(Ce.join(i,"types.ts"),Ns),Zt(Ce.join(i,"index.ts"),Ds(n.id)),Rs(e,xs(n))}var Nt=[{id:"svix",name:"Svix",region:"global",envVars:["SVIX_API_TOKEN"],docs:"https://docs.svix.com",description:"Managed webhooks platform"},{id:"custom",name:"Custom (self-hosted)",region:"both",envVars:["WEBHOOK_SIGNING_SECRET"],docs:"",description:"Custom implementation with built-in package"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function No(e){return Nt.find(t=>t.id===e)}var jp=Nt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ko(e,t,o="global"){let n=No(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Nt.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"webhooks");return}n.envVars.length>0&&q(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"WEBHOOKS_PROVIDER",n.id)}import xe from"fs";import dt from"path";function js(e){return`import Link from "next/link";
|
|
2763
2763
|
|
|
2764
2764
|
export default function WelcomePage() {
|
|
2765
2765
|
const projectName = ${JSON.stringify(e)};
|
|
@@ -2868,7 +2868,16 @@ function Step({
|
|
|
2868
2868
|
</li>
|
|
2869
2869
|
);
|
|
2870
2870
|
}
|
|
2871
|
-
`}function Vs(e
|
|
2871
|
+
`}function Vs(e=[]){return e.length===0?"":`
|
|
2872
|
+
## Production readiness holds
|
|
2873
|
+
|
|
2874
|
+
Do not enable these in production until you replace stubs, add provider credentials, and verify the integration contract:
|
|
2875
|
+
|
|
2876
|
+
${e.map(o=>{let n=qe(o.status);return`- ${o.flag}=${o.provider} ${n} \u2014 ${te(o.status)}`}).join(`
|
|
2877
|
+
`)}
|
|
2878
|
+
|
|
2879
|
+
Review the package readiness matrix before handoff: [docs/package-status.md](docs/package-status.md)
|
|
2880
|
+
`}function Ks(e,t,o=[]){return`# Next steps \u2014 ${e}
|
|
2872
2881
|
|
|
2873
2882
|
Region: ${t}
|
|
2874
2883
|
|
|
@@ -2894,32 +2903,33 @@ Your AI-native SaaS scaffold is ready. Complete these four steps to go from temp
|
|
|
2894
2903
|
\`\`\`
|
|
2895
2904
|
|
|
2896
2905
|
After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
|
|
2906
|
+
${Vs(o)}
|
|
2897
2907
|
|
|
2898
2908
|
## Resources
|
|
2899
2909
|
|
|
2900
2910
|
- [Documentation](/docs)
|
|
2901
2911
|
- [GitHub](https://github.com/nebutra/nebutra-sailor)
|
|
2902
2912
|
- [Get free license (Individual/OPC)](https://nebutra.com/get-license)
|
|
2903
|
-
`}async function To(e,t){let{projectName:o,region:n}=t;try{let
|
|
2904
|
-
`)}function
|
|
2913
|
+
`}async function To(e,t){let{projectName:o,region:n,previewSelections:r=[]}=t;try{let i=dt.join(e,".sailor");xe.existsSync(i)||xe.mkdirSync(i,{recursive:!0}),xe.writeFileSync(dt.join(i,"next-steps.md"),Ks(o,n,r))}catch(i){let s=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${s}`)}try{let i=dt.join(e,"apps","web");if(!xe.existsSync(i))return;let s=dt.join(i,"src","app","[locale]","welcome");xe.existsSync(s)||xe.mkdirSync(s,{recursive:!0}),xe.writeFileSync(dt.join(s,"page.tsx"),js(o))}catch(i){let s=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write welcome page: ${s}`)}}var Oo="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
|
|
2914
|
+
`)}function $s(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function Uo(e){switch(e){case"postgres":case"postgresql":return"postgresql";case"mysql":return"mysql";case"sqlite":return"sqlite";case"none":return"none";default:return"postgresql"}}function Lo(e){return e==="drizzle"?"drizzle":e==="none"?"none":"prisma"}function Mo(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function Do(e){if(!e)return"stripe";let t=e.toLowerCase();return t==="lemon"||t==="lemonsqueezy"?"lemon":t==="wechat"?"wechat":t==="alipay"?"alipay":t==="none"?"none":"stripe"}function Fo(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="none"?"none":"clerk"}function jo(e){if(!e)return["openai"];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}function qs(e,t){let o=e??t;return Jt(o)??o}var Vo={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Ko(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in Vo){let n=Vo[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(w.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
|
|
2905
2915
|
`)+w.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
|
|
2906
|
-
`)),"fumadocs"}return"fumadocs"}function Bo(e){switch(e){case"vercel":return"vercel";case"railway":return"railway";case"cloudflare":return"cloudflare";case"selfhost":return"selfhost";case"none":return"none";default:return"vercel"}}function Yo(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function
|
|
2907
|
-
`)),process.exit(130)}});
|
|
2908
|
-
`)),process.exit(130)}}):{};y=Yo(h?t.region:f.region),
|
|
2909
|
-
`))}}let
|
|
2916
|
+
`)),"fumadocs"}return"fumadocs"}function Bo(e){switch(e){case"vercel":return"vercel";case"railway":return"railway";case"cloudflare":return"cloudflare";case"selfhost":return"selfhost";case"none":return"none";default:return"vercel"}}function Yo(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function Gs(e){return{...e==="cn"?{email:"aliyun-dm",storage:"aliyun-oss",monitoring:"sentry",analytics:"baidu",sms:"aliyun-sms"}:e==="hybrid"?{email:"resend",storage:"aliyun-oss",monitoring:"sentry",analytics:"posthog",sms:"aliyun-sms"}:{email:"resend",storage:"r2",monitoring:"sentry",analytics:"posthog",sms:"twilio"},queue:"none",search:"none",cache:e==="global"?"upstash-redis":e==="cn"?"redis":"upstash-redis",notifications:"none",webhooks:"none",cms:"none",featureFlags:"none",captcha:e==="cn"?"aliyun-slide":"turnstile",mcp:"on",metering:"auto",billingMode:"usage",idp:"clerk"}}function $o(e){return e==="cn"?"wechat":"stripe"}async function Hs(){let e=new Bs;e.name(Oo).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ee,"-v, --version").helpOption(!1).argument("[name]","project directory",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--region <id>","global | cn | hybrid").option("--orm <id>","prisma | drizzle | none").option("--db <id>","postgres | mysql | sqlite | none").option("--auth <id>","clerk | betterauth | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <ids>","expert: comma-separated provider ids used as an AI provider seed").option("--deploy <target>","vercel | railway | cloudflare | selfhost").option("--docs <id>","fumadocs | mintlify | docusaurus | nextra | vitepress | none").option("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | none").option("--queue <id>","qstash | bullmq | upstash | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").option("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--no-install","skip package install").option("--no-git","skip git init").option("-y, --yes","accept all defaults (non-interactive)").option("--dry-run","preview actions without writing files").option("--json","machine-readable output").option("--no-color","disable color output").option("-h, --help","show help"),e.parse(process.argv);let t=e.opts(),[o]=e.args;t.help&&(an(),process.exit(0));let n=!!t.json,r=!!t.dryRun,i=!!t.yes,s=i||!process.stdin.isTTY;n||on(),p(n,{event:"start",version:ee});let c=o??(i?"./my-saas-app":void 0),a;if(c)a=c;else if(s)a="./my-saas-app";else{let m=await C.group({name:()=>C.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:f=>{if(f.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(w.red(`\u2718 Cancelled
|
|
2917
|
+
`)),process.exit(130)}});a=String(m.name)}let d=ut.basename(ut.resolve(a)),u=t.pm??$s(),h=!!t.region,O=!!t.auth,M=!!t.payment,D=!!t.ai,Xe=!!t.email,v=!!t.storage,l=!!t.monitoring,R=!!t.analytics,mt=!!t.sms,en=t.i18n!==void 0,y,ze,X,Qe,F,N,Y=En(t.socialLogin),Je,Tt,ue,Ne,z,j,gt;if(s){y=Yo(t.region),ze=Lo(t.orm),X=Uo(t.db);let m=M?t.payment:$o(y);Qe=Mo(m),F=Do(m),N=Fo(t.auth);let f=Dt({mode:D?t.ai?.trim().toLowerCase()==="none"?"none":"direct":"gateway",providerIds:D?jo(t.ai):void 0});Je=f.mode,Tt=f.routing,ue=f.providerIds,z=Bo(t.deploy),j=Ko(t.docs,n),gt=en?!!t.i18n:!0}else{let m={};h||(m.region=()=>C.select({message:"Target region?",options:[{value:"global",label:"global \u2014 \u6D77\u5916\u4F18\u5148"},{value:"cn",label:"cn \u2014 \u56FD\u5185\u4F18\u5148"},{value:"hybrid",label:"hybrid \u2014 \u53CC\u8F68\uFF08\u56FD\u5185+\u51FA\u6D77\uFF09"}],initialValue:"global"})),O||(m.auth=()=>C.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk"},{value:"betterauth",label:"Better Auth"},{value:"none",label:"None"}],initialValue:"clerk"})),D||(m.aiMode=()=>C.select({message:"AI topology?",options:[{value:"gateway",label:"Multi-provider AI Gateway / router",hint:"recommended"},{value:"direct",label:"Direct SDK/provider adapters"},{value:"custom",label:"OpenAI-compatible endpoint"},{value:"none",label:"Skip AI"}],initialValue:"gateway"}),m.aiProviders=({results:E})=>{if(E.aiMode!=="direct")return Promise.resolve([]);let Q=Mt.map(Ut=>({value:Ut.id,label:`[${Ut.category}] ${Ut.name}`}));return C.multiselect({message:"Select direct AI provider adapters (expert path)",options:Q,initialValues:["openai"],required:!1})},m.customAiName=({results:E})=>E.aiMode==="custom"?C.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),m.customAiBaseUrl=({results:E})=>E.aiMode==="custom"?C.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:Q=>{if(Q.length===0)return"Base URL is required."}}):Promise.resolve(void 0),m.customAiApiKeyEnv=({results:E})=>E.aiMode==="custom"?C.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0));let f=Object.keys(m).length>0?await C.group(m,{onCancel:()=>{process.stdout.write(w.red(`\u2718 Cancelled
|
|
2918
|
+
`)),process.exit(130)}}):{};y=Yo(h?t.region:f.region),ze=Lo(t.orm),X=Uo(t.db);let V=M?t.payment:$o(y);Qe=Mo(V),F=Do(V),N=Fo(O?t.auth:f.auth);let St=f.aiMode==="custom"?{name:f.customAiName??"custom",baseURL:f.customAiBaseUrl??"",apiKeyEnvName:f.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,S=Dt({mode:D?t.ai?.trim().toLowerCase()==="none"?"none":"direct":f.aiMode??"gateway",providerIds:D?jo(t.ai):f.aiProviders,customEndpoint:St});Je=S.mode,Tt=S.routing,ue=S.providerIds,S.customEndpoint&&(Ne={name:S.customEndpoint.name,baseURL:S.customEndpoint.baseURL,apiKeyEnvName:S.customEndpoint.apiKeyEnvName}),z=Bo(t.deploy),j=Ko(t.docs,n),gt=en?!!t.i18n:!0}let b=Gs(y),ke=Xe?t.email:b.email,Te=qs(v?t.storage:void 0,b.storage),Oe=l?t.monitoring:b.monitoring,Ue=R?t.analytics:b.analytics,Le=mt?t.sms:b.sms,Me=t.queue??b.queue,De=t.search??b.search,Ze=t.cache??b.cache,Fe=t.notifications??b.notifications,je=t.webhooks??b.webhooks,et=t.cms??b.cms,Ve=t.featureFlags??b.featureFlags,Ke=t.captcha??b.captcha,ft=t.mcp??b.mcp,tt=t.metering??b.metering,Be=t.billingMode??b.billingMode,Ye=t.idp??b.idp,$e=rn([{flag:"queue",provider:Me},{flag:"search",provider:De},{flag:"notifications",provider:Fe},{flag:"webhooks",provider:je},{flag:"feature-flags",provider:Ve},{flag:"captcha",provider:Ke}]);function Ot(){for(let m of $e)if(n)p(!0,{event:"warn",step:m.flag,provider:m.provider,packageStatus:m.status,message:te(m.status)});else{let f=qe(m.status);process.stdout.write(w.yellow(`\u26A0 ${m.flag}=${m.provider} ${f} \u2014 ${te(m.status)}
|
|
2919
|
+
`))}}let me={region:y,orm:ze,database:X,payment:Qe,aiMode:Je,aiRouting:Tt,aiProviders:ue,customAiEndpoint:Ne,deployTarget:z,docs:j,i18n:gt,email:ke,storage:Te,monitoring:Oe,analytics:Ue,sms:Le,queue:Me,search:De,cache:Ze,notifications:Fe,webhooks:je,cms:et,featureFlags:Ve,captcha:Ke,mcp:ft,metering:tt,billingMode:Be,idp:Ye},yt=[["Project name",d],["Region",y],["Auth",N],["Social login",Y.length>0?Y.map(m=>nt.find(f=>f.id===m)?.name??m).join(", "):"none"],["ORM",ze],["Database",X],["Payment",F],["AI topology",`${Je}${ue.length>0?` (${ue.join(", ")} seed)`:""}${Ne?" + custom endpoint":""}`],["Email",ke],["Storage",Te],["Monitoring",Oe],["Analytics",Ue],["SMS",Le],["Deploy Target",z],["Docs Framework",j]];n?yt.forEach(([m,f],V)=>{p(!0,{event:"step",step:m,value:f,index:V+1,total:yt.length})}):yt.forEach(([m,f],V)=>{pn({index:V+1,total:yt.length,label:m,value:f})});let qo={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},tn=Date.now();if(r){let m=ue.length,f=[`clone template \u2192 ${a}`,"write nebutra.config.json",`prune template (orm=${ze}, i18n=${gt})`,`region \u2192 ${y}`,`auth \u2192 ${N==="none"?"skip (remove packages/auth)":`configure ${N}`}`,...Y.length>0?[`social-login \u2192 generate ${Y.length} callback route${Y.length===1?"":"s"} + SocialLoginButtons.tsx (${Y.join(", ")})`]:[],`db \u2192 ${X==="none"?"skip (remove packages/db)":`configure Prisma for ${X}`}`,`payment \u2192 ${F==="none"?"skip (remove packages/billing)":`configure ${F}`}`,...j!=="none"?[`docs \u2192 scaffold apps/docs (${j==="fumadocs"?"fumadocs":`${j} \u2192 fumadocs fallback`})`]:[],...m>0||Ne?[`ai-providers \u2192 generate ${Je} registry seed + env (${m}${Ne?" + custom":""} provider${m===1&&!Ne?"":"s"})`]:[],...ke!=="none"?[`email \u2192 configure ${ke}`]:[],...Te!=="none"?[`storage \u2192 configure ${Te}`]:[],...Oe!=="none"?[`monitoring \u2192 configure ${Oe}`]:[],...Ue!=="none"?[`analytics \u2192 configure ${Ue}`]:[],...Le!=="none"?[`sms \u2192 configure ${Le}`]:[],...Me!=="none"?[`queue \u2192 configure ${Me}`]:[],...De!=="none"?[`search \u2192 configure ${De}`]:[],...Ze!=="none"?[`cache \u2192 configure ${Ze}`]:[],...Fe!=="none"?[`notifications \u2192 configure ${Fe}`]:[],...je!=="none"?[`webhooks \u2192 configure ${je}`]:[],...et!=="none"?[`cms \u2192 configure ${et}`]:[],...Ve!=="none"?[`feature-flags \u2192 configure ${Ve}`]:[],...Ke!=="none"?[`captcha \u2192 configure ${Ke}`]:[],`mcp \u2192 ${ft==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${tt==="off"?"disabled":tt==="auto"?Qe!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...Be!=="usage"?[`billing-mode \u2192 ${Be}`]:[],...Ye!=="clerk"?[`idp \u2192 ${Ye}`]:[],`compliance \u2192 inject ${y} boilerplate (ICP/Cookie/AIGC/Privacy)`,"welcome \u2192 generate dev welcome page","env \u2192 generate random secrets (AUTH_SECRET, JWT_SECRET)","seed \u2192 generate prisma/seed.ts (1 admin + 3 tenants)",...z!=="none"?[`deploy \u2192 inject ${z} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${u} install`,t.git===!1?"skip git init":"run git init"];if(n){for(let V of f)p(!0,{event:"plan",action:V});Ot(),p(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
|
|
2910
2920
|
`+w.bold(`Dry run \u2014 planned actions:
|
|
2911
2921
|
`));for(let V of f)process.stdout.write(` \u2022 ${V}
|
|
2912
|
-
`)
|
|
2922
|
+
`);$e.length>0&&(process.stdout.write(`
|
|
2913
2923
|
`+w.bold(w.yellow(`Preview-status providers selected:
|
|
2914
2924
|
`))),Ot()),process.stdout.write(w.dim(`
|
|
2915
2925
|
No files were written.
|
|
2916
2926
|
`))}process.exit(0)}let Go=async()=>{process.stdout.write(`
|
|
2917
2927
|
`+w.red(`\u2718 Cancelled
|
|
2918
|
-
`)),
|
|
2919
|
-
`))),process.exit(130)};process.on("SIGINT",Go);try{p(n,{event:"step",step:"clone",status:"start"}),await Zn(
|
|
2920
|
-
`));try{kt(S,{cwd:
|
|
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:
|
|
2922
|
-
`))}}else p(n,{event:"step",step:"git-init",status:"skip"});let
|
|
2928
|
+
`)),de.existsSync(a)&&await C.confirm({message:`Cleanup partial install at ${a}?`,initialValue:!0})===!0&&(de.rmSync(a,{recursive:!0,force:!0}),process.stdout.write(w.dim(` \u2713 Removed ${a}
|
|
2929
|
+
`))),process.exit(130)};process.on("SIGINT",Go);try{p(n,{event:"step",step:"clone",status:"start"}),await Zn(a),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await co(a,d),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await xn(a,me),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await Eo(a,me),p(n,{event:"step",step:"prune",status:"ok"});let m=ut.join(a,"packages/db/prisma/schema.prisma");if(de.existsSync(m)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let S=de.readFileSync(m,"utf-8"),E=Wt(S,{auth:N,payment:F,"billing-mode":Be,idp:Ye,template:"saas"});de.writeFileSync(m,E),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(S){let E=S instanceof Error?S.message:String(S);p(n,{event:"step",step:"schema-prune",status:"error",error:E})}}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"auth",choice:N,status:"start"}),await yn(a,N),p(n,{event:"step",step:"auth",choice:N,status:"ok"}),Y.length>0?(p(n,{event:"step",step:"social-login",providers:Y,status:"start"}),await vn(a,Y,N),p(n,{event:"step",step:"social-login",providers:Y,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:X,status:"start"}),await Tn(a,X,d),p(n,{event:"step",step:"db",choice:X,status:"ok"}),p(n,{event:"step",step:"payment",choice:F,status:"start"}),await lo(a,F),p(n,{event:"step",step:"payment",choice:F,status:"ok"}),await jn(a,ke,y),n&&p(!0,{event:"step",step:"email",choice:ke,status:"ok"}),await xo(a,Te,y),n&&p(!0,{event:"step",step:"storage",choice:Te,status:"ok"}),await io(a,Oe,y),n&&p(!0,{event:"step",step:"monitoring",choice:Oe,status:"ok"}),await un(a,Ue,y),n&&p(!0,{event:"step",step:"analytics",choice:Ue,status:"ok"}),await wo(a,Le,y),n&&p(!0,{event:"step",step:"sms",choice:Le,status:"ok"}),await _o(a,Me,y),n&&p(!0,{event:"step",step:"queue",choice:Me,status:"ok"}),await Io(a,De,y),n&&p(!0,{event:"step",step:"search",choice:De,status:"ok"}),await bn(a,Ze,y),n&&p(!0,{event:"step",step:"cache",choice:Ze,status:"ok"}),await ao(a,Fe,y),n&&p(!0,{event:"step",step:"notifications",choice:Fe,status:"ok"}),await ko(a,je,y),n&&p(!0,{event:"step",step:"webhooks",choice:je,status:"ok"}),await wn(a,et,y),n&&p(!0,{event:"step",step:"cms",choice:et,status:"ok"}),await Gn(a,Ve,y),n&&p(!0,{event:"step",step:"feature-flags",choice:Ve,status:"ok"}),await An(a,Ke,y),n&&p(!0,{event:"step",step:"captcha",choice:Ke,status:"ok"}),await eo(a,ft),n&&p(!0,{event:"step",step:"mcp",mode:ft,status:"ok"}),await no(a,tt,Qe),n&&p(!0,{event:"step",step:"metering",mode:tt,status:"ok"}),me.orm==="prisma"&&me.database!=="none"){let S=ut.join(a,"packages/db/prisma/schema.prisma");if(de.existsSync(S)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let E=de.readFileSync(S,"utf8"),Q=Wt(E,{auth:N,payment:F,"billing-mode":Be,idp:Ye,template:"saas"});de.writeFileSync(S,Q),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(E){let Q=E instanceof Error?E.message:String(E);p(n,{event:"step",step:"schema-prune",status:"error",error:Q})}}else p(n,{event:"step",step:"schema-prune",status:"skip"})}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"billing-mode",choice:Be,status:"ok"}),p(n,{event:"step",step:"idp",choice:Ye,status:"ok"}),await Rn(a,y),n&&p(!0,{event:"step",step:"compliance",region:y,status:"ok"}),await $n(a),await Ao(a,N),await To(a,{projectName:d,region:y,previewSelections:$e}),me.aiMode!=="none"){p(n,{event:"step",step:"ai-providers",status:"start"});let S={providerIds:me.aiProviders,customEndpoint:me.customAiEndpoint},E=ut.join(a,"packages/ai-providers/templates");await yo(a,S,E),p(n,{event:"step",step:"ai-providers",status:"ok"})}else p(n,{event:"step",step:"ai-providers",status:"skip"});if(p(n,{event:"step",step:"docs",status:"start"}),j!=="none"?(await Ln(a,{framework:j,projectName:d}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:j,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),z!=="none"&&await On(a,z),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await Kn(a,qo),p(n,{event:"step",step:"env",status:"ok"}),t.install!==!1){let S=u==="bun"?"bun install":`${u} install`;n?p(!0,{event:"step",step:"install",pm:u,status:"start"}):process.stdout.write(w.dim(` Installing dependencies with ${u}\u2026
|
|
2930
|
+
`));try{kt(S,{cwd:a,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(E){let Q=E instanceof Error?E.message:String(E);n?p(!0,{event:"step",step:"install",status:"error",error:Q}):process.stdout.write(w.yellow(` \u26A0 install failed \u2014 run '${S}' manually.
|
|
2931
|
+
`))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{kt("git init -q",{cwd:a,stdio:"ignore"}),kt("git add -A",{cwd:a,stdio:"ignore"}),kt('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:a,stdio:"ignore"}),p(n,{event:"step",step:"git-init",status:"ok"})}catch(S){let E=S instanceof Error?S.message:String(S);n?p(!0,{event:"step",step:"git-init",status:"error",error:E}):process.stdout.write(w.yellow(` \u26A0 git init skipped \u2014 not fatal.
|
|
2932
|
+
`))}}else p(n,{event:"step",step:"git-init",status:"skip"});let St=Math.max(1,Math.round((Date.now()-tn)/1e3));mn({template_version:ee,package_manager:u,region:y,auth:N,payment:F,ai_providers:ue,deploy_target:z,duration_ms:Date.now()-tn}),$e.length>0&&Ot(),n?p(!0,{event:"done",status:"ok",elapsedSec:St,targetDir:a,previewSelections:$e}):sn({elapsedSec:St,targetDir:a,skippedInstall:t.install===!1,previewSelections:$e});try{Ys({pkg:{name:Oo,version:ee},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(m){let f=m instanceof Error?m.message:String(m);n?p(!0,{event:"error",message:f}):process.stdout.write(w.red(`
|
|
2923
2933
|
\u2718 Failed: ${f}
|
|
2924
|
-
`)),process.exit(1)}}
|
|
2934
|
+
`)),process.exit(1)}}Hs().catch(e=>{process.stderr.write(String(e)+`
|
|
2925
2935
|
`),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-sailor",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.6",
|
|
4
4
|
"description": "Governed AI-native SaaS scaffolder for Nebutra Sailor. Bootstrap a production-ready Next.js + Hono + Prisma monorepo with multi-tenant foundations, region-aware defaults, and AI integrations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"create-sailor": "
|
|
8
|
+
"create-sailor": "dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|