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