create-sailor 1.4.1 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +156 -156
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{execSync as
|
|
3
|
-
`));return}
|
|
2
|
+
import{execSync as St}from"child_process";import Se from"fs";import ht from"path";import*as k from"@clack/prompts";import{Command as ea}from"commander";import C from"picocolors";import ta from"update-notifier";import ir from"cfonts";import sr from"picocolors";import ln from"fs";import jt from"path";import{fileURLToPath as or}from"url";function rr(){try{let t=jt.dirname(or(import.meta.url));for(let o=0;o<4;o++){let n=jt.join(t,"package.json");if(ln.existsSync(n)){let r=ln.readFileSync(n,"utf-8"),i=JSON.parse(r);if(i.name==="create-sailor"&&typeof i.version=="string")return i.version}t=jt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ie=rr();function dn(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ie}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
|
|
3
|
+
`));return}ir.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(sr.dim(` AI-Native SaaS Template \xB7 v${ie} \xB7 nebutra.com
|
|
4
4
|
|
|
5
|
-
`))}import P from"picocolors";var
|
|
5
|
+
`))}import P from"picocolors";var ar={qstash:"foundation",bullmq:"foundation",upstash:"foundation",sqs:"foundation",meilisearch:"foundation",typesense:"foundation",algolia:"foundation",pgvector:"foundation",novu:"foundation",knock:"foundation",svix:"foundation","vercel-flags":"wip",growthbook:"wip",configcat:"wip",turnstile:"wip",hcaptcha:"wip","aliyun-slide":"wip"};function cr(e){return e?ar[e]??"stable":"stable"}function Qe(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function se(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 un(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=cr(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function pr(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function mn(e){let t=pr(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",i=t?"\u{1F4E7}":"*",c=["",` ${t?P.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?P.bold("Next:"):"Next:"}`,` ${n} cd ${e.targetDir}`];e.skippedInstall&&c.push(` ${n} pnpm install (if --no-install was set)`),c.push(` ${n} fill in .env.local ${t?P.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?P.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?P.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?P.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?P.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?P.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?P.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?P.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?P.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?P.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?P.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?P.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`,` ${n} pnpm audit ${t?P.dim("\u2192 scan deps for known CVEs"):"-> scan deps for known CVEs"}`);let a=e.previewSelections??[];if(a.length>0){let x=t?P.bold(P.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${x}`);for(let N of a){let M=Qe(N.status),re=` ${n} ${N.flag} (${N.provider}) ${M}`;c.push(t?P.yellow(re):re)}c.push("",` ${t?P.dim(se("foundation")):se("foundation")}`,` ${t?P.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?P.dim("See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"):"See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"}`)}let l=e.waveFeatures??{},m=x=>x!==!1,y=[];m(l.apiKeys)&&y.push("Manage API keys at /settings/api-keys"),m(l.auditLog)&&y.push("View audit log at /settings/audit-log"),y.push("Configure webhooks at /settings/webhooks"),m(l.commandPalette)&&y.push("Press Cmd/Ctrl+K to open the command palette"),y.push("Edit notification preferences at /settings/notifications"),y.push("Export your data at /settings/account/export"),l.chinaCompliance&&y.push("China deployments \u2014 see packages/ops/china-compliance/README.md"),c.push("",` ${t?P.bold("What you can do next:"):"What you can do next:"}`);for(let x of y)c.push(` ${n} ${x}`);c.push("",` ${t?P.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${i} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
|
|
6
6
|
`)+`
|
|
7
|
-
`)}var
|
|
7
|
+
`)}var lr=`Usage: create-sailor [name] [options]
|
|
8
8
|
|
|
9
9
|
Arguments:
|
|
10
10
|
name project directory (default: ./my-saas-app)
|
|
@@ -73,9 +73,9 @@ Examples:
|
|
|
73
73
|
$ npx create-sailor@latest my-app --region=cn --auth=clerk
|
|
74
74
|
$ npx create-sailor@latest my-app --region=hybrid --ai=openai,deepseek
|
|
75
75
|
$ npm create sailor@latest --dry-run --region=cn
|
|
76
|
-
`;function gn(){process.stdout.write(
|
|
77
|
-
`)}var Kt=[{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:[]}],va=Kt.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var dr=["openai","anthropic","google"],ur=["openai"];function Vt(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...dr];return{mode:"gateway",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:o,runtimeGovernance:!0}}}case"direct":{let o=t.length>0?t:[...ur];return{mode:"direct",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:o,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}import Qe from"fs";import F from"path";var Sn=[{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:""}],Pa=Sn.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function hn(e){return Sn.find(t=>t.id===e)}function mr(e){Qe.mkdirSync(e,{recursive:!0})}function W(e,t){mr(F.dirname(e)),Qe.writeFileSync(e,t)}function ve(e,t){let o=F.join(e,".env.example");Qe.existsSync(o)?Qe.appendFileSync(o,`
|
|
78
|
-
`+t):
|
|
76
|
+
`;function gn(){process.stdout.write(lr)}import Pt from"picocolors";function fn(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function dr(e){let t=fn()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return fn()?`${Pt.dim(o)} ${Pt.bold(n)} ${Pt.dim(t)} ${Pt.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function yn(e){process.stdout.write(dr(e)+`
|
|
77
|
+
`)}var Kt=[{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:[]}],ba=Kt.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var ur=["openai","anthropic","google"],mr=["openai"];function Vt(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...ur];return{mode:"gateway",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:o,runtimeGovernance:!0}}}case"direct":{let o=t.length>0?t:[...mr];return{mode:"direct",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:o,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}import Ze from"fs";import D from"path";var Sn=[{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:""}],Ia=Sn.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function hn(e){return Sn.find(t=>t.id===e)}function gr(e){Ze.mkdirSync(e,{recursive:!0})}function W(e,t){gr(D.dirname(e)),Ze.writeFileSync(e,t)}function _e(e,t){let o=D.join(e,".env.example");Ze.existsSync(o)?Ze.appendFileSync(o,`
|
|
78
|
+
`+t):Ze.writeFileSync(o,t)}function fr(e){let t=`"use client";
|
|
79
79
|
/**
|
|
80
80
|
* PostHog browser SDK \u2014 lazy-initialized on first access.
|
|
81
81
|
*/
|
|
@@ -158,11 +158,11 @@ export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
|
|
|
158
158
|
|
|
159
159
|
return <>{children}</>;
|
|
160
160
|
}
|
|
161
|
-
`;W(
|
|
161
|
+
`;W(D.join(e,"src","lib","analytics","posthog.client.ts"),t),W(D.join(e,"src","lib","analytics","posthog.server.ts"),o),W(D.join(e,"src","components","analytics","AnalyticsProvider.tsx"),n)}function yr(){return`# PostHog \u2014 product analytics
|
|
162
162
|
POSTHOG_KEY=
|
|
163
163
|
NEXT_PUBLIC_POSTHOG_KEY=
|
|
164
164
|
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
|
165
|
-
`}function
|
|
165
|
+
`}function Sr(e){W(D.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
|
|
166
166
|
/**
|
|
167
167
|
* Plausible script tag \u2014 lightweight, privacy-friendly analytics.
|
|
168
168
|
*/
|
|
@@ -182,10 +182,10 @@ export function PlausibleScript() {
|
|
|
182
182
|
/>
|
|
183
183
|
);
|
|
184
184
|
}
|
|
185
|
-
`)}function
|
|
185
|
+
`)}function hr(){return`# Plausible \u2014 privacy-friendly analytics
|
|
186
186
|
NEXT_PUBLIC_PLAUSIBLE_DOMAIN=
|
|
187
187
|
NEXT_PUBLIC_PLAUSIBLE_SRC=https://plausible.io/js/script.js
|
|
188
|
-
`}function
|
|
188
|
+
`}function Er(e){W(D.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
|
|
189
189
|
/**
|
|
190
190
|
* Umami analytics \u2014 self-hosted OR umami.is cloud.
|
|
191
191
|
*/
|
|
@@ -205,10 +205,10 @@ export function UmamiScript() {
|
|
|
205
205
|
/>
|
|
206
206
|
);
|
|
207
207
|
}
|
|
208
|
-
`)}function
|
|
208
|
+
`)}function vr(){return`# Umami \u2014 self-hostable analytics
|
|
209
209
|
NEXT_PUBLIC_UMAMI_WEBSITE_ID=
|
|
210
210
|
NEXT_PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
|
|
211
|
-
`}function
|
|
211
|
+
`}function _r(e){let t=`"use client";
|
|
212
212
|
import mixpanel from "mixpanel-browser";
|
|
213
213
|
|
|
214
214
|
let initialized = false;
|
|
@@ -247,10 +247,10 @@ export function trackServer(
|
|
|
247
247
|
if (!c) return;
|
|
248
248
|
c.track(event, { distinct_id: distinctId, ...properties });
|
|
249
249
|
}
|
|
250
|
-
`;W(
|
|
250
|
+
`;W(D.join(e,"src","lib","analytics","mixpanel.client.ts"),t),W(D.join(e,"src","lib","analytics","mixpanel.server.ts"),o)}function br(){return`# Mixpanel \u2014 product analytics
|
|
251
251
|
MIXPANEL_TOKEN=
|
|
252
252
|
NEXT_PUBLIC_MIXPANEL_TOKEN=
|
|
253
|
-
`}function
|
|
253
|
+
`}function Pr(e){W(D.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
|
|
254
254
|
/**
|
|
255
255
|
* \u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji \u2014 hm.js \u57CB\u70B9\u811A\u672C.
|
|
256
256
|
*/
|
|
@@ -276,9 +276,9 @@ var _hmt = _hmt || [];
|
|
|
276
276
|
/>
|
|
277
277
|
);
|
|
278
278
|
}
|
|
279
|
-
`)}function
|
|
279
|
+
`)}function Cr(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
|
|
280
280
|
NEXT_PUBLIC_BAIDU_STATS_ID=
|
|
281
|
-
`}function
|
|
281
|
+
`}function Ir(e){W(D.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
|
|
282
282
|
/**
|
|
283
283
|
* \u795E\u7B56\u5206\u6790 (Sensors Analytics) \u2014 sa-sdk-javascript \u5C01\u88C5.
|
|
284
284
|
*/
|
|
@@ -306,10 +306,10 @@ export function initSensors(): void {
|
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
export { sensors };
|
|
309
|
-
`)}function
|
|
309
|
+
`)}function Ar(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
|
|
310
310
|
NEXT_PUBLIC_SENSORS_SERVER_URL=
|
|
311
311
|
NEXT_PUBLIC_SENSORS_APP_JS_URL=
|
|
312
|
-
`}function
|
|
312
|
+
`}function wr(e){W(D.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
|
|
313
313
|
/**
|
|
314
314
|
* GrowingIO CDP \u2014 inline snippet installer.
|
|
315
315
|
*/
|
|
@@ -334,21 +334,21 @@ gdp("send");
|
|
|
334
334
|
/>
|
|
335
335
|
);
|
|
336
336
|
}
|
|
337
|
-
`)}function
|
|
337
|
+
`)}function Rr(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
|
|
338
338
|
NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
|
|
339
|
-
`}async function En(e,t,o="global"){let n=hn(t);if(!n||n.id==="none")return;let r=
|
|
340
|
-
`+t):
|
|
341
|
-
`+t)}async function _n(e,t){let o=$.join(e,"packages","auth");if(!
|
|
339
|
+
`}async function En(e,t,o="global"){let n=hn(t);if(!n||n.id==="none")return;let r=D.join(e,"apps","web");if(!Ze.existsSync(r))return;let i=n.id;try{switch(i){case"posthog":fr(r),_e(e,yr());return;case"plausible":Sr(r),_e(e,hr());return;case"umami":Er(r),_e(e,vr());return;case"mixpanel":_r(r),_e(e,br());return;case"baidu":Pr(r),_e(e,Cr());return;case"sensors":Ir(r),_e(e,Ar());return;case"growingio":wr(r),_e(e,Rr());return;default:return}}catch(s){throw console.error(`Failed to apply analytics selection "${t}":`,s),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var kr="https://analytics.nebutra.com";function xr(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function vn(e,t={}){xr(t)||(async()=>{try{let o=await import("@nebutra/analytics");if(typeof o.createAnalyticsClient!="function")return;let n=o.createAnalyticsClient({posthog:{apiKey:process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.NEBUTRA_POSTHOG_HOST??kr},onError:()=>{}});if(typeof n?.track!="function")return;let r=n.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import K from"fs";import $ from"path";function be(e){K.existsSync(e)&&K.rmSync(e,{recursive:!0,force:!0})}function Bt(e,t){let o=$.join(e,".env.example");K.existsSync(o)?K.appendFileSync(o,`
|
|
340
|
+
`+t):K.writeFileSync(o,t)}function $t(e,t){if(!K.existsSync(e))return;let o=K.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*(?:"[^"]+"\s*\|\s*)+"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&K.writeFileSync(e,n)}function Nr(e,t){let o=$.join(e,"README.md");if(!K.existsSync(o)){K.writeFileSync(o,t);return}K.appendFileSync(o,`
|
|
341
|
+
`+t)}async function _n(e,t){let o=$.join(e,"packages","iam","auth");if(!K.existsSync(o))return;if(t==="none"){be(o),Nr(e,`
|
|
342
342
|
## Auth
|
|
343
343
|
|
|
344
344
|
Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth).
|
|
345
|
-
`);return}let n=$.join(o,"src","providers"),r=$.join(o,"src","types.ts");if(t==="clerk"){
|
|
345
|
+
`);return}let n=$.join(o,"src","providers"),r=$.join(o,"src","types.ts");if(t==="clerk"){be($.join(n,"better-auth.ts")),be($.join(n,"nextauth.ts")),$t(r,"clerk"),Bt(e,`# Clerk auth
|
|
346
346
|
CLERK_PUBLISHABLE_KEY=
|
|
347
347
|
CLERK_SECRET_KEY=
|
|
348
|
-
`);return}if(t==="betterauth"){
|
|
348
|
+
`);return}if(t==="betterauth"){be($.join(n,"clerk.ts")),be($.join(n,"nextauth.ts")),$t(r,"better-auth"),Bt(e,`# Better Auth
|
|
349
349
|
BETTER_AUTH_SECRET=
|
|
350
350
|
BETTER_AUTH_URL=http://localhost:3000
|
|
351
|
-
`);return}if(t==="nextauth"){
|
|
351
|
+
`);return}if(t==="nextauth"){be($.join(n,"clerk.ts")),be($.join(n,"better-auth.ts")),$t(r,"nextauth"),Bt(e,`# NextAuth (Auth.js v5)
|
|
352
352
|
AUTH_SECRET=
|
|
353
353
|
NEXTAUTH_URL=http://localhost:3000
|
|
354
354
|
# OAuth (optional \u2014 leave blank to disable that provider)
|
|
@@ -356,7 +356,7 @@ GOOGLE_CLIENT_ID=
|
|
|
356
356
|
GOOGLE_CLIENT_SECRET=
|
|
357
357
|
GITHUB_CLIENT_ID=
|
|
358
358
|
GITHUB_CLIENT_SECRET=
|
|
359
|
-
`);return}}var
|
|
359
|
+
`);return}}var ct=[{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"}],Tr=new Set(ct.map(e=>e.id));function bn(e){return ct.find(t=>t.id===e)}function Pn(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)Tr.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import Ce from"fs";import Pe from"path";function Or(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
|
|
360
360
|
// Generated by create-sailor \u2014 OAuth callback for ${e.name}
|
|
361
361
|
// Primary auth provider: ${t}
|
|
362
362
|
// Docs: ${e.docs}`,n={wechat:` const tokenRes = await fetch(
|
|
@@ -481,7 +481,7 @@ ${n[e.id]}
|
|
|
481
481
|
void state;
|
|
482
482
|
return NextResponse.redirect(new URL("/dashboard", req.url));
|
|
483
483
|
}
|
|
484
|
-
`}function
|
|
484
|
+
`}function Ur(e){return`"use client";
|
|
485
485
|
|
|
486
486
|
/**
|
|
487
487
|
* SocialLoginButtons \u2014 generated by create-sailor.
|
|
@@ -524,23 +524,23 @@ export function SocialLoginButtons() {
|
|
|
524
524
|
</div>
|
|
525
525
|
);
|
|
526
526
|
}
|
|
527
|
-
`}function Cn(e){
|
|
528
|
-
`+t):
|
|
527
|
+
`}function Cn(e){Ce.mkdirSync(e,{recursive:!0})}function Lr(e,t){let o=Pe.join(e,".env.example");Ce.existsSync(o)?Ce.appendFileSync(o,`
|
|
528
|
+
`+t):Ce.writeFileSync(o,t)}function Mr(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
529
529
|
`);return`${t}
|
|
530
530
|
${o}
|
|
531
|
-
`}async function In(e,t,o){if(!t||t.length===0)return;let n=
|
|
532
|
-
`);ae.appendFileSync(o,i)}function
|
|
533
|
-
`)}async function Rn(e,t,o){let n=Yt.join(e,"packages","cache");if(t==="none"){ae.existsSync(n)&&ae.rmSync(n,{recursive:!0,force:!0});return}let r=An(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${Ct.map(i=>i.id).join(", ")}`);ae.existsSync(n)&&(
|
|
531
|
+
`}async function In(e,t,o){if(!t||t.length===0)return;let n=Pe.join(e,"apps","web");if(!Ce.existsSync(n))return;let r=new Set,i=[];for(let l of t){if(r.has(l))continue;r.add(l);let m=bn(l);m&&i.push(m)}if(i.length===0)return;for(let l of i)Lr(e,Mr(l));let s=Pe.join(n,"src","app","api","auth","callback");for(let l of i){let m=Pe.join(s,l.id);Cn(m);let y=Pe.join(m,"route.ts");Ce.writeFileSync(y,Or(l,o))}let c=Pe.join(n,"src","components","auth");Cn(c);let a=Pe.join(c,"SocialLoginButtons.tsx");Ce.writeFileSync(a,Ur(i))}import ae from"fs";import Yt from"path";var Ct=[{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 An(e){return Ct.find(t=>t.id===e)}var Ka=Ct.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function wn(e){return ae.existsSync(e)?ae.readFileSync(e,"utf-8"):null}function Fr(e,t){let o=Yt.join(e,".env.example"),n=wn(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
|
|
532
|
+
`);ae.appendFileSync(o,i)}function Dr(e,t,o){let n=Yt.join(e,".env.example"),r=wn(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ae.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ae.appendFileSync(n,`${t}="${o}"
|
|
533
|
+
`)}async function Rn(e,t,o){let n=Yt.join(e,"packages","cache");if(t==="none"){ae.existsSync(n)&&ae.rmSync(n,{recursive:!0,force:!0});return}let r=An(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${Ct.map(i=>i.id).join(", ")}`);ae.existsSync(n)&&(Fr(e,r),Dr(e,"CACHE_PROVIDER",t))}var It=[{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 kn(e){return It.find(t=>t.id===e)}var Ga=It.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import te from"fs";import qt from"path";function H(e,t){let o=qt.join(e,".env.example");if(!te.existsSync(o)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(te.readFileSync(o,"utf-8").includes(r))return;let c=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].filter(a=>a!==null).join(`
|
|
534
534
|
`);te.appendFileSync(o,c)}function X(e,t,o){let n=qt.join(e,".env.example");if(!te.existsSync(n))return;let r=te.readFileSync(n,"utf-8"),i=`${t}="${o}"`,s=new RegExp(`^${t}=.*$`,"m");if(s.test(r)){te.writeFileSync(n,r.replace(s,i));return}let c=r.endsWith(`
|
|
535
535
|
`)?"":`
|
|
536
536
|
`;te.appendFileSync(n,`${c}${i}
|
|
537
|
-
`)}function Y(e,t){let o=qt.join(e,"packages",t);te.existsSync(o)&&te.rmSync(o,{recursive:!0,force:!0})}async function xn(e,t,o="global"){let n=kn(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${It.map(r=>r.id).join(", ")}`);if(n.id==="none"){Y(e,"captcha");return}n.envVars.length>0&&H(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),X(e,"CAPTCHA_PROVIDER",n.id)}import wt from"fs";import
|
|
537
|
+
`)}function Y(e,t){let o=qt.join(e,"packages",t);te.existsSync(o)&&te.rmSync(o,{recursive:!0,force:!0})}async function xn(e,t,o="global"){let n=kn(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${It.map(r=>r.id).join(", ")}`);if(n.id==="none"){Y(e,"captcha");return}n.envVars.length>0&&H(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),X(e,"CAPTCHA_PROVIDER",n.id)}import wt from"fs";import jr from"path";var At=[{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 Nn(e){return At.find(t=>t.id===e)}var ec=At.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Tn(e,t,o="global"){let n=Nn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${At.map(i=>i.id).join(", ")}`);let r=jr.join(e,"apps","studio");if(n.id==="none"){Y(e,"sanity"),wt.existsSync(r)&&wt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(Y(e,"sanity"),wt.existsSync(r)&&wt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&H(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),X(e,"CMS_PROVIDER",n.id)}import R from"fs";import w from"path";var Kr=w.join("apps","web"),Gt=w.join("src","components","compliance"),pt=w.join("src","app","[locale]");function z(e){return w.join(e,Kr)}function Vr(e){R.mkdirSync(e,{recursive:!0})}function q(e,t){Vr(w.dirname(e)),R.writeFileSync(e,t,"utf8")}function Wt(e,t){let o=w.join(e,".env.example");if(R.existsSync(o)){if(R.readFileSync(o,"utf8").includes(t.split(`
|
|
538
538
|
`)[0]??""))return;R.appendFileSync(o,`
|
|
539
539
|
`+t+`
|
|
540
540
|
`)}else R.writeFileSync(o,t+`
|
|
541
|
-
`)}var
|
|
541
|
+
`)}var lt=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
|
|
542
542
|
> Consult a qualified lawyer in every jurisdiction you operate in before publishing.
|
|
543
|
-
> \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,
|
|
543
|
+
> \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,Br=`import Link from "next/link";
|
|
544
544
|
import { IcpFooter } from "@/components/compliance/IcpFooter";
|
|
545
545
|
import { PublicSecurityFooter } from "@/components/compliance/PublicSecurityFooter";
|
|
546
546
|
|
|
@@ -591,7 +591,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
591
591
|
</footer>
|
|
592
592
|
);
|
|
593
593
|
}
|
|
594
|
-
|
|
594
|
+
`,$r=`export function IcpFooter() {
|
|
595
595
|
const icp = process.env.NEXT_PUBLIC_ICP_BEIAN;
|
|
596
596
|
if (!icp) return null;
|
|
597
597
|
return (
|
|
@@ -605,7 +605,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
605
605
|
</a>
|
|
606
606
|
);
|
|
607
607
|
}
|
|
608
|
-
|
|
608
|
+
`,Yr=`export function PublicSecurityFooter() {
|
|
609
609
|
const psb = process.env.NEXT_PUBLIC_PSB_BEIAN;
|
|
610
610
|
const psbCode = process.env.NEXT_PUBLIC_PSB_CODE;
|
|
611
611
|
if (!psb) return null;
|
|
@@ -622,7 +622,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
622
622
|
</a>
|
|
623
623
|
);
|
|
624
624
|
}
|
|
625
|
-
`,
|
|
625
|
+
`,qr=`"use client";
|
|
626
626
|
|
|
627
627
|
import { useCallback, useEffect, useState } from "react";
|
|
628
628
|
|
|
@@ -849,7 +849,7 @@ function CategoryRow({ id, title, description, checked, disabled, onChange }: Ca
|
|
|
849
849
|
</label>
|
|
850
850
|
);
|
|
851
851
|
}
|
|
852
|
-
`,
|
|
852
|
+
`,Gr=`interface AigcDisclaimerProps {
|
|
853
853
|
className?: string;
|
|
854
854
|
}
|
|
855
855
|
|
|
@@ -869,13 +869,13 @@ export function AigcDisclaimer({ className }: AigcDisclaimerProps) {
|
|
|
869
869
|
</div>
|
|
870
870
|
);
|
|
871
871
|
}
|
|
872
|
-
`,
|
|
872
|
+
`,Wr=`---
|
|
873
873
|
title: Privacy Policy / \u9690\u79C1\u653F\u7B56
|
|
874
874
|
description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal information.
|
|
875
875
|
lastUpdated: 2026-01-01
|
|
876
876
|
---
|
|
877
877
|
|
|
878
|
-
${
|
|
878
|
+
${lt}
|
|
879
879
|
|
|
880
880
|
# Privacy Policy / \u9690\u79C1\u653F\u7B56
|
|
881
881
|
|
|
@@ -1014,13 +1014,13 @@ or in-app notification before the change takes effect.
|
|
|
1014
1014
|
**Data Controller / \u6570\u636E\u63A7\u5236\u8005:** {{COMPANY_NAME}}
|
|
1015
1015
|
**Address / \u5730\u5740:** {{COMPANY_ADDRESS}}
|
|
1016
1016
|
**Email / \u90AE\u7BB1:** {{COMPANY_CONTACT_EMAIL}}
|
|
1017
|
-
`,
|
|
1017
|
+
`,Hr=`---
|
|
1018
1018
|
title: Terms of Service / \u670D\u52A1\u6761\u6B3E
|
|
1019
1019
|
description: Terms governing your use of {{COMPANY_NAME}}.
|
|
1020
1020
|
lastUpdated: 2026-01-01
|
|
1021
1021
|
---
|
|
1022
1022
|
|
|
1023
|
-
${
|
|
1023
|
+
${lt}
|
|
1024
1024
|
|
|
1025
1025
|
# Terms of Service / \u670D\u52A1\u6761\u6B3E
|
|
1026
1026
|
|
|
@@ -1133,13 +1133,13 @@ conflict-of-laws principles. Disputes shall be resolved in the competent courts
|
|
|
1133
1133
|
## 11. Contact / \u8054\u7CFB\u65B9\u5F0F
|
|
1134
1134
|
|
|
1135
1135
|
{{COMPANY_NAME}} \xB7 {{COMPANY_ADDRESS}} \xB7 {{COMPANY_CONTACT_EMAIL}}
|
|
1136
|
-
`,
|
|
1136
|
+
`,Xr=`---
|
|
1137
1137
|
title: AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
|
|
1138
1138
|
description: Disclosure required by \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300B
|
|
1139
1139
|
lastUpdated: 2026-01-01
|
|
1140
1140
|
---
|
|
1141
1141
|
|
|
1142
|
-
${
|
|
1142
|
+
${lt}
|
|
1143
1143
|
|
|
1144
1144
|
# AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
|
|
1145
1145
|
|
|
@@ -1215,13 +1215,13 @@ human professional.
|
|
|
1215
1215
|
|
|
1216
1216
|
AI \u8F93\u51FA\u53EF\u80FD\u4E0D\u51C6\u786E\u3001\u5B58\u5728\u504F\u89C1\u6216\u8FC7\u65F6\u3002**\u8BF7\u52FF**\u5728\u672A\u7ECF\u5408\u683C\u4E13\u4E1A\u4EBA\u58EB\u72EC\u7ACB\u6838\u5B9E\u7684\u60C5\u51B5\u4E0B\uFF0C\u5C06 AI \u8F93\u51FA
|
|
1217
1217
|
\u7528\u4E8E\u533B\u7597\u3001\u6CD5\u5F8B\u3001\u91D1\u878D\u6216\u5B89\u5168\u6538\u5173\u7684\u51B3\u7B56\u3002
|
|
1218
|
-
`,
|
|
1218
|
+
`,zr=`---
|
|
1219
1219
|
title: Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
|
|
1220
1220
|
description: Notice of cross-border transfer of personal information, per PIPL.
|
|
1221
1221
|
lastUpdated: 2026-01-01
|
|
1222
1222
|
---
|
|
1223
1223
|
|
|
1224
|
-
${
|
|
1224
|
+
${lt}
|
|
1225
1225
|
|
|
1226
1226
|
# Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
|
|
1227
1227
|
|
|
@@ -1280,13 +1280,13 @@ Refusal may limit your ability to use features that rely on overseas services.
|
|
|
1280
1280
|
- \u4F20\u8F93\u4E2D\u52A0\u5BC6 (TLS 1.2+) \u53CA\u9759\u6001\u52A0\u5BC6 (AES-256)\u3002
|
|
1281
1281
|
- \u5408\u540C\u6761\u6B3E\u8981\u6C42\u5883\u5916\u63A5\u6536\u65B9\u63D0\u4F9B\u7B49\u540C\u4E8E PIPL \u7684\u4FDD\u62A4\u3002
|
|
1282
1282
|
- \u8BBF\u95EE\u63A7\u5236\u3001\u5BA1\u8BA1\u65E5\u5FD7\u548C\u8FDD\u89C4\u901A\u77E5\u7A0B\u5E8F\u3002
|
|
1283
|
-
`,
|
|
1283
|
+
`,Jr=`---
|
|
1284
1284
|
title: Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
|
|
1285
1285
|
description: Itemized list of personal information collected, per PIPL Article 17.
|
|
1286
1286
|
lastUpdated: 2026-01-01
|
|
1287
1287
|
---
|
|
1288
1288
|
|
|
1289
|
-
${
|
|
1289
|
+
${lt}
|
|
1290
1290
|
|
|
1291
1291
|
# Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
|
|
1292
1292
|
|
|
@@ -1322,19 +1322,19 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
|
|
|
1322
1322
|
**{{COMPANY_CONTACT_EMAIL}}**.
|
|
1323
1323
|
|
|
1324
1324
|
\u5982\u9700\u884C\u4F7F\u60A8\u7684\u6743\u5229\uFF08\u8BBF\u95EE\u3001\u66F4\u6B63\u3001\u5220\u9664\u3001\u5BFC\u51FA\u3001\u64A4\u56DE\u540C\u610F\uFF09\uFF0C\u8BF7\u8054\u7CFB **{{COMPANY_CONTACT_EMAIL}}**\u3002
|
|
1325
|
-
`;async function
|
|
1326
|
-
`))}async function
|
|
1327
|
-
`))}async function
|
|
1328
|
-
`))}async function
|
|
1329
|
-
`))}async function
|
|
1330
|
-
`)}import ce from"fs";import Ht from"path";function
|
|
1331
|
-
`+t):ce.writeFileSync(o,t)}async function Fn(e,t,o){let n=Ht.join(e,"packages","db");if(t==="none"){
|
|
1325
|
+
`;async function Qr(e,t){let o=z(e);if(!R.existsSync(o))return;let n=w.join(o,"src","components","compliance","Footer.tsx");q(n,Br);let r=w.join(o,"src","components","compliance","README.md");q(r,["# Compliance Components","",`Auto-generated by \`create-sailor\` for region: \`${t}\`.`,"","## Mounting the Footer","","```tsx",'import { Footer } from "@/components/compliance/Footer";','import { CookieBanner } from "@/components/compliance/CookieBanner";',"","export default function RootLayout({ children }) {"," return ("," <html>"," <body>"," {children}",` <Footer region="${t}" />`," <CookieBanner />"," </body>"," </html>"," );","}","```","","## Placeholders","","Policy MDX files contain `{{COMPANY_NAME}}`, `{{COMPANY_ADDRESS}}`,","`{{COMPANY_CONTACT_EMAIL}}`, `{{GOVERNING_JURISDICTION}}`, and","`{{AIGC_ALGORITHM_FILING_NUMBER}}`. These are filled by the `brand-apply` step.",""].join(`
|
|
1326
|
+
`))}async function Zr(e,t){let o=z(e);if(!R.existsSync(o))return;let n=w.join(o,"src","components","compliance","CookieBanner.tsx");q(n,qr)}async function ei(e,t){let o=z(e);if(!R.existsSync(o))return;let n=w.join(o,pt,"privacy","page.mdx");q(n,Wr)}async function ti(e,t){let o=z(e);if(!R.existsSync(o))return;let n=w.join(o,pt,"terms","page.mdx");q(n,Hr)}async function ni(e){let t=z(e);if(!R.existsSync(t))return;let o=w.join(t,Gt,"IcpFooter.tsx");q(o,$r),Wt(e,["# Chinese ICP filing (\u5DE5\u4FE1\u90E8 ICP \u5907\u6848) \u2014 required to legally host a","# public-facing site from mainland China. Apply at https://beian.miit.gov.cn/",'NEXT_PUBLIC_ICP_BEIAN="" # \u5982 \u82CFICP\u59072024XXXXXX\u53F7'].join(`
|
|
1327
|
+
`))}async function oi(e){let t=z(e);if(!R.existsSync(t))return;let o=w.join(t,Gt,"PublicSecurityFooter.tsx");q(o,Yr),Wt(e,["# Chinese Public Security Bureau filing (\u516C\u5B89\u8054\u7F51\u5907\u6848)","# Required in addition to ICP. Apply at http://www.beian.gov.cn/",'NEXT_PUBLIC_PSB_BEIAN="" # \u5982 \u82CF\u516C\u7F51\u5B89\u5907 32011402XXXXXX\u53F7','NEXT_PUBLIC_PSB_CODE="" # 14-digit record code'].join(`
|
|
1328
|
+
`))}async function ri(e){let t=z(e);if(!R.existsSync(t))return;let o=w.join(t,Gt,"AigcDisclaimer.tsx");q(o,Gr),Wt(e,["# Generative AI algorithm filing (\u7B97\u6CD5\u5907\u6848\u53F7) \u2014 required by","# \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300Bfor services offered in China.",'NEXT_PUBLIC_AIGC_FILING_NUMBER="" # e.g. \u7F51\u4FE1\u7B97\u5907XXXXXXXX\u53F7'].join(`
|
|
1329
|
+
`))}async function ii(e){let t=z(e);if(!R.existsSync(t))return;let o=w.join(t,pt,"aigc-disclosure","page.mdx");q(o,Xr)}async function si(e){let t=z(e);if(!R.existsSync(t))return;let o=w.join(t,pt,"cross-border-data","page.mdx");q(o,zr)}async function ai(e){let t=z(e);if(!R.existsSync(t))return;let o=w.join(t,pt,"pii-collection","page.mdx");q(o,Jr)}async function On(e,t){try{await Qr(e,t),await Zr(e,t),await ei(e,t),await ti(e,t),(t==="cn"||t==="hybrid")&&(await ni(e),await oi(e),await ri(e),await ii(e),await si(e),await ai(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 ci from"fs";import pi from"path";async function Un(e,t){let o=pi.join(e,"nebutra.config.json");ci.writeFileSync(o,JSON.stringify(t,null,2)+`
|
|
1330
|
+
`)}import ce from"fs";import Ht from"path";function li(e){ce.existsSync(e)&&ce.rmSync(e,{recursive:!0,force:!0})}function Ln(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function di(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function Mn(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 ui(e,t){let o=Ht.join(e,".env.example");ce.existsSync(o)?ce.appendFileSync(o,`
|
|
1331
|
+
`+t):ce.writeFileSync(o,t)}async function Fn(e,t,o){let n=Ht.join(e,"packages","platform","db");if(t==="none"){li(n);return}let r=Ht.join(n,"prisma","schema.prisma"),i;if(t==="postgresql"?i=`postgresql://postgres:postgres@localhost:5432/${o}`:t==="mysql"?i=`mysql://root:root@localhost:3306/${o}`:i="file:./dev.db",ui(e,`# Database (${t})
|
|
1332
1332
|
DATABASE_URL="${i}"
|
|
1333
|
-
`),!ce.existsSync(r))return;let s=ce.readFileSync(r,"utf8"),c=s;t==="mysql"?(c=Ln(c,"mysql"),c=Mn(c)):t==="sqlite"&&(c=Ln(c,"sqlite"),c=
|
|
1334
|
-
`+t):
|
|
1333
|
+
`),!ce.existsSync(r))return;let s=ce.readFileSync(r,"utf8"),c=s;t==="mysql"?(c=Ln(c,"mysql"),c=Mn(c)):t==="sqlite"&&(c=Ln(c,"sqlite"),c=di(c),c=Mn(c)),c!==s&&ce.writeFileSync(r,c)}import et from"fs";import j from"path";import{fileURLToPath as mi}from"url";var gi=mi(import.meta.url),Dn=j.dirname(gi);function fi(){let e=[j.join(Dn,"..","templates","deploy"),j.join(Dn,"..","..","templates","deploy")];for(let t of e)if(et.existsSync(t))return t;return e[0]}async function jn(e,t){if(t==="none")return;let o=fi();t==="vercel"?await et.promises.copyFile(j.join(o,"vercel.json"),j.join(e,"vercel.json")):t==="railway"?await et.promises.copyFile(j.join(o,"railway.toml"),j.join(e,"railway.toml")):t==="cloudflare"?await et.promises.copyFile(j.join(o,"wrangler.toml"),j.join(e,"wrangler.toml")):t==="selfhost"&&(await et.promises.copyFile(j.join(o,"docker-compose.yml"),j.join(e,"docker-compose.yml")),await et.promises.copyFile(j.join(o,"Dockerfile.web"),j.join(e,"Dockerfile.web")))}import pe from"fs";import Ie from"path";import{fileURLToPath as yi}from"url";var Si=yi(import.meta.url),Kn=Ie.dirname(Si),hi=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|vue)$/,Vn=["fumadocs","nextra","mintlify","docusaurus","vitepress"];function Ei(e){let t=[Ie.join(Kn,"..","templates","docs",e),Ie.join(Kn,"..","..","templates","docs",e)];for(let o of t)if(pe.existsSync(o))return o;return t[0]}async function Bn(e,t){if(t.framework==="none")return;if(!Vn.includes(t.framework))throw new Error(`Unsupported docs framework: "${t.framework}". Supported: ${Vn.join(", ")}, none.`);let o=Ei(t.framework),n=Ie.join(e,"apps","docs");if(!pe.existsSync(o))throw new Error(`Docs template not found: ${o}`);$n(o,n),Yn(n,{"{PRODUCT_NAME}":t.projectName})}function $n(e,t){pe.mkdirSync(t,{recursive:!0});for(let o of pe.readdirSync(e,{withFileTypes:!0})){let n=Ie.join(e,o.name),r=Ie.join(t,o.name);o.isDirectory()?$n(n,r):pe.copyFileSync(n,r)}}function Yn(e,t){for(let o of pe.readdirSync(e,{withFileTypes:!0})){let n=Ie.join(e,o.name);if(o.isDirectory())Yn(n,t);else if(hi.test(o.name)){let r=pe.readFileSync(n,"utf-8");for(let[i,s]of Object.entries(t))r=r.split(i).join(s);pe.writeFileSync(n,r)}}}import we from"fs";import Ae from"path";var Rt=[{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 qn(e){return Rt.find(t=>t.id===e)}var Cc=Rt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Re="@nebutra/email";function Xt(e,t){we.mkdirSync(Ae.dirname(e),{recursive:!0}),we.writeFileSync(e,t)}function vi(e,t){let o=Ae.join(e,".env.example");we.existsSync(o)?we.appendFileSync(o,`
|
|
1334
|
+
`+t):we.writeFileSync(o,t)}function _i(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
1335
1335
|
`);return`${t}
|
|
1336
1336
|
${o}
|
|
1337
|
-
`}var
|
|
1337
|
+
`}var bi=`/**
|
|
1338
1338
|
* Public inputs accepted by the \`sendEmail\` wrapper.
|
|
1339
1339
|
* Keep the surface minimal \u2014 individual providers may accept more, but
|
|
1340
1340
|
* consumers should code against this shape for portability.
|
|
@@ -1354,8 +1354,8 @@ export interface SendEmailResult {
|
|
|
1354
1354
|
/** Raw provider response \u2014 useful for debugging, not a stable contract. */
|
|
1355
1355
|
raw?: unknown;
|
|
1356
1356
|
}
|
|
1357
|
-
`;function
|
|
1358
|
-
* @${
|
|
1357
|
+
`;function Pi(){return`/**
|
|
1358
|
+
* @${Re.slice(1)} \u2014 Resend transactional email wrapper.
|
|
1359
1359
|
*
|
|
1360
1360
|
* Docs: https://resend.com/docs
|
|
1361
1361
|
*/
|
|
@@ -1393,8 +1393,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1393
1393
|
}
|
|
1394
1394
|
|
|
1395
1395
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1396
|
-
`}function
|
|
1397
|
-
* @${
|
|
1396
|
+
`}function Ci(){return`/**
|
|
1397
|
+
* @${Re.slice(1)} \u2014 Postmark transactional email wrapper.
|
|
1398
1398
|
*
|
|
1399
1399
|
* Docs: https://postmarkapp.com/developer
|
|
1400
1400
|
*/
|
|
@@ -1431,8 +1431,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1431
1431
|
}
|
|
1432
1432
|
|
|
1433
1433
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1434
|
-
`}function
|
|
1435
|
-
* @${
|
|
1434
|
+
`}function Ii(){return`/**
|
|
1435
|
+
* @${Re.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
|
|
1436
1436
|
*
|
|
1437
1437
|
* Docs: https://docs.aws.amazon.com/ses
|
|
1438
1438
|
*/
|
|
@@ -1487,8 +1487,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1487
1487
|
}
|
|
1488
1488
|
|
|
1489
1489
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1490
|
-
`}function
|
|
1491
|
-
* @${
|
|
1490
|
+
`}function Ai(){return`/**
|
|
1491
|
+
* @${Re.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
|
|
1492
1492
|
*
|
|
1493
1493
|
* Docs: https://help.aliyun.com/product/29412.html
|
|
1494
1494
|
*/
|
|
@@ -1537,8 +1537,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1537
1537
|
}
|
|
1538
1538
|
|
|
1539
1539
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1540
|
-
`}function
|
|
1541
|
-
* @${
|
|
1540
|
+
`}function wi(){return`/**
|
|
1541
|
+
* @${Re.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
|
|
1542
1542
|
*
|
|
1543
1543
|
* Docs: https://cloud.tencent.com/document/product/1288
|
|
1544
1544
|
*/
|
|
@@ -1585,8 +1585,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1585
1585
|
}
|
|
1586
1586
|
|
|
1587
1587
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1588
|
-
`}function
|
|
1589
|
-
* @${
|
|
1588
|
+
`}function Ri(){return`/**
|
|
1589
|
+
* @${Re.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
|
|
1590
1590
|
*
|
|
1591
1591
|
* Docs: https://qiye.163.com/help
|
|
1592
1592
|
*/
|
|
@@ -1623,9 +1623,9 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1623
1623
|
}
|
|
1624
1624
|
|
|
1625
1625
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1626
|
-
`}function
|
|
1627
|
-
`}}function
|
|
1628
|
-
`}async function Gn(e,t,o){if(t==="none")return;let n=qn(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${Rt.map(s=>s.id).join(", ")}`);let r=
|
|
1626
|
+
`}function ki(e){switch(e){case"resend":return Pi();case"postmark":return Ci();case"ses":return Ii();case"aliyun-dm":return Ai();case"tencent-ses":return wi();case"netease":return Ri();case"none":return`export {};
|
|
1627
|
+
`}}function xi(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:Re,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)+`
|
|
1628
|
+
`}async function Gn(e,t,o){if(t==="none")return;let n=qn(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${Rt.map(s=>s.id).join(", ")}`);let r=Ae.join(e,"packages","email"),i=Ae.join(r,"src");we.existsSync(i)&&we.rmSync(i,{recursive:!0,force:!0}),Xt(Ae.join(r,"package.json"),xi(n)),Xt(Ae.join(i,"types.ts"),bi),Xt(Ae.join(i,"index.ts"),ki(n.id)),vi(e,_i(n))}import kt from"fs";import Wn from"path";async function Hn(e,t){let o=`# Automatically injected by create-sailor
|
|
1629
1629
|
DATABASE_URL="${String(t.databaseUrl)}"
|
|
1630
1630
|
|
|
1631
1631
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
|
|
@@ -1633,14 +1633,14 @@ CLERK_SECRET_KEY="${String(t.clerkSecret)}"
|
|
|
1633
1633
|
|
|
1634
1634
|
NEXT_PUBLIC_SITE_URL="http://localhost:3000"
|
|
1635
1635
|
`,n=Wn.join(e,".env"),r=Wn.join(e,".env.local");!kt.existsSync(n)&&!kt.existsSync(r)?kt.writeFileSync(r,o):kt.appendFileSync(r,`
|
|
1636
|
-
`+o)}import zn from"crypto";import
|
|
1636
|
+
`+o)}import zn from"crypto";import dt from"fs";import Xn from"path";function ke(e){return zn.randomBytes(e).toString("base64").replace(/=+$/,"")}function Ni(e){return zn.randomBytes(e).toString("hex")}function Ti(){return{AUTH_SECRET:ke(32),NEXTAUTH_SECRET:ke(32),BETTER_AUTH_SECRET:ke(32),JWT_SECRET:ke(32),WEBHOOK_SECRET:Ni(16),ENCRYPTION_KEY:ke(32),API_SECRET_KEY:ke(32),SESSION_SECRET:ke(32)}}function Oi(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Ui(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=Oi(o);return e.replace(n,`${t}="${r}"`)}async function Jn(e){let t=Xn.join(e,".env.example"),o=Xn.join(e,".env.local");if(!dt.existsSync(t))return null;try{let n=dt.readFileSync(t,"utf8"),r=Ti(),s=dt.existsSync(o)?dt.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))s=Ui(s,c,r[c]);return dt.writeFileSync(o,s),r}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate env secrets: ${r}`),new Error(`Unable to write .env.local: ${r}`)}}var xt=[{id:"vercel-flags",name:"Vercel Flags SDK",region:"global",envVars:["FLAGS_SECRET"],docs:"https://vercel.com/docs/workflow-collaboration/feature-flags",description:"Native Vercel feature flags"},{id:"growthbook",name:"GrowthBook",region:"both",envVars:["GROWTHBOOK_API_HOST","GROWTHBOOK_CLIENT_KEY","GROWTHBOOK_DECRYPTION_KEY"],docs:"https://docs.growthbook.io",description:"Open-source A/B testing + flags"},{id:"configcat",name:"ConfigCat",region:"global",envVars:["CONFIGCAT_SDK_KEY"],docs:"https://configcat.com/docs/",description:"Feature flag & config management"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Qn(e){return xt.find(t=>t.id===e)}var Fc=xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Zn(e,t,o="global"){let n=Qn(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${xt.map(r=>r.id).join(", ")}`);if(n.id==="none"){Y(e,"feature-flags");return}n.envVars.length>0&&H(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),X(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{execFileSync as no}from"child_process";import U from"fs";import Li from"os";import le from"path";import Mi from"ignore";var Fi={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 Di(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function ji(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function oo(e){return/^[0-9a-f]{7,40}$/i.test(e)}function Ki(e,t){let o=`https://github.com/${e}.git`,n=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of n)try{let i=no("git",["ls-remote",o,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!i)continue;let[s]=i.split(/\s+/);if(oo(s))return s}catch{}return null}async function Vi(e,t){if(oo(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=Ki(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 ro(e,t,o){let n=U.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let i=le.join(t,r.name),s=le.relative(e,i).split(le.sep).join("/");r.isDirectory()?(o.push(s+"/"),ro(e,i,o)):o.push(s)}}function Bi(e){let t=le.join(e,".templateignore");if(!U.existsSync(t))return;let o=U.readFileSync(t,"utf8"),n=Mi().add(o),r=[];ro(e,e,r);let i=r.map(a=>a.endsWith("/")?a.slice(0,-1):a),s=new Set(n.filter(i)),c=i.filter(a=>!s.has(a)).sort((a,l)=>l.split("/").length-a.split("/").length);for(let a of c){let l=le.join(e,a);try{U.existsSync(l)&&U.rmSync(l,{recursive:!0,force:!0})}catch{}}try{U.existsSync(t)&&U.rmSync(t,{force:!0})}catch{}}async function eo(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)`);U.writeFileSync(t,n);let r=U.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function to(e,t){no("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function io(e){try{let t=U.readdirSync(e);for(let o of t)U.rmSync(le.join(e,o),{recursive:!0,force:!0})}catch{}}async function $i(e,t){let o=U.mkdtempSync(le.join(Li.tmpdir(),"create-sailor-")),n=le.join(o,"template.tar.gz");try{let r=await Vi(e.repo,e.ref);await eo(ji(e.repo,r),n),to(n,t)}catch(r){if(!e.allowMutableFallback)throw r;io(t),await eo(Di(e.repo,e.ref),n),to(n,t)}finally{U.rmSync(o,{recursive:!0,force:!0})}}async function so(e){U.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let i=Fi[r];try{if(await $i(i,e),i.applyIgnore)try{Bi(e)}catch(s){throw new Error(`Template cloned, but .templateignore processing failed: ${s instanceof Error?s.message:String(s)}`)}return}catch(s){n=s instanceof Error?s:new Error(String(s)),io(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
|
|
1637
1637
|
|
|
1638
1638
|
Ensure you have internet access and 'tar' installed.
|
|
1639
|
-
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import
|
|
1640
|
-
`);
|
|
1641
|
-
`);
|
|
1642
|
-
`)}function J(e,t){
|
|
1643
|
-
`+t):ne.writeFileSync(o,t)}function
|
|
1639
|
+
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import xe from"fs";import zt from"path";async function ao(e,t){let o=zt.join(e,"packages","mcp");if(t==="off"){xe.existsSync(o)&&xe.rmSync(o,{recursive:!0,force:!0});let r=zt.join(e,"packages","cli","src","commands","mcp-server.ts");xe.existsSync(r)&&xe.rmSync(r,{force:!0});return}let n=zt.join(e,".env.example");if(xe.existsSync(n)){let r=xe.readFileSync(n,"utf-8"),i="# MCP Server (Agent-friendly API)";if(!r.includes(i)){let s=["","# =============================================",i,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
|
|
1640
|
+
`);xe.appendFileSync(n,s)}}}import ut from"fs";import co from"path";async function po(e,t,o){let n=co.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){ut.existsSync(n)&&ut.rmSync(n,{recursive:!0,force:!0});return}let i=co.join(e,".env.example");if(!ut.existsSync(i))return;let s=ut.readFileSync(i,"utf-8"),c="# Metering (usage-based billing)";if(!s.includes(c)){let a=["","# =============================================",c,"# Docs: see packages/commerce/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
|
|
1641
|
+
`);ut.appendFileSync(i,a)}}import ne from"fs";import L from"path";var lo=[{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:""}],ep=lo.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function uo(e){return lo.find(t=>t.id===e)}var Jt={sentry:{"@sentry/nextjs":"^8.45.0"},datadog:{"dd-trace":"^5.32.0","@datadog/browser-rum":"^5.30.0"},bugsnag:{"@bugsnag/js":"^8.2.0","@bugsnag/plugin-react":"^8.2.0"}};function Yi(e){ne.mkdirSync(e,{recursive:!0})}function Qt(e,t){let o=L.join(e,"package.json");if(!ne.existsSync(o))return;let n;try{n=JSON.parse(ne.readFileSync(o,"utf-8"))}catch(c){console.error(`Failed to parse ${o}:`,c);return}let i={...n.dependencies??{}};for(let[c,a]of Object.entries(t))i[c]||(i[c]=a);let s={...n,dependencies:i};ne.writeFileSync(o,JSON.stringify(s,null,2)+`
|
|
1642
|
+
`)}function J(e,t){Yi(L.dirname(e)),ne.writeFileSync(e,t)}function mt(e,t){let o=L.join(e,".env.example");ne.existsSync(o)?ne.appendFileSync(o,`
|
|
1643
|
+
`+t):ne.writeFileSync(o,t)}function qi(e){let t=`import * as Sentry from "@sentry/nextjs";
|
|
1644
1644
|
|
|
1645
1645
|
Sentry.init({
|
|
1646
1646
|
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
@@ -1683,14 +1683,14 @@ export async function register() {
|
|
|
1683
1683
|
}
|
|
1684
1684
|
|
|
1685
1685
|
export { captureRequestError as onRequestError } from "@sentry/nextjs";
|
|
1686
|
-
`;J(
|
|
1686
|
+
`;J(L.join(e,"sentry.client.config.ts"),t),J(L.join(e,"sentry.server.config.ts"),o),J(L.join(e,"sentry.edge.config.ts"),n),J(L.join(e,"instrumentation.ts"),r)}function Gi(){return`# Sentry \u2014 error tracking + performance monitoring
|
|
1687
1687
|
# Get your DSN from https://sentry.io/settings/projects/<project>/keys/
|
|
1688
1688
|
SENTRY_DSN=
|
|
1689
1689
|
NEXT_PUBLIC_SENTRY_DSN=
|
|
1690
1690
|
SENTRY_ORG=
|
|
1691
1691
|
SENTRY_PROJECT=
|
|
1692
1692
|
SENTRY_AUTH_TOKEN=
|
|
1693
|
-
`}function
|
|
1693
|
+
`}function Wi(e){let t=`/**
|
|
1694
1694
|
* Next.js instrumentation hook \u2014 wires Datadog APM (dd-trace) into Node runtime.
|
|
1695
1695
|
* Edge runtime is not supported by dd-trace; only nodejs is initialized.
|
|
1696
1696
|
*/
|
|
@@ -1738,7 +1738,7 @@ export function initDatadogRum(): void {
|
|
|
1738
1738
|
});
|
|
1739
1739
|
initialized = true;
|
|
1740
1740
|
}
|
|
1741
|
-
`;J(
|
|
1741
|
+
`;J(L.join(e,"instrumentation.ts"),t),J(L.join(e,"src","lib","monitoring","datadog-rum.ts"),o)}function Hi(){return`# Datadog \u2014 APM + RUM
|
|
1742
1742
|
# Server APM (dd-trace)
|
|
1743
1743
|
DD_API_KEY=
|
|
1744
1744
|
DD_APP_KEY=
|
|
@@ -1753,7 +1753,7 @@ NEXT_PUBLIC_DD_SITE=datadoghq.com
|
|
|
1753
1753
|
NEXT_PUBLIC_DD_SERVICE=sailor-web
|
|
1754
1754
|
NEXT_PUBLIC_DD_ENV=production
|
|
1755
1755
|
NEXT_PUBLIC_DD_VERSION=
|
|
1756
|
-
`}function
|
|
1756
|
+
`}function Xi(e){let t=`/**
|
|
1757
1757
|
* Bugsnag server-side initialization.
|
|
1758
1758
|
* Import this once at the top of your server entrypoint or a shared init module.
|
|
1759
1759
|
*/
|
|
@@ -1802,11 +1802,11 @@ export function getBugsnagErrorBoundary() {
|
|
|
1802
1802
|
errorBoundary = plugin.createErrorBoundary(React) as typeof errorBoundary;
|
|
1803
1803
|
return errorBoundary;
|
|
1804
1804
|
}
|
|
1805
|
-
`;J(
|
|
1805
|
+
`;J(L.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),J(L.join(e,"src","lib","monitoring","bugsnag.client.tsx"),o)}function zi(){return`# Bugsnag \u2014 error tracking
|
|
1806
1806
|
BUGSNAG_API_KEY=
|
|
1807
1807
|
NEXT_PUBLIC_BUGSNAG_API_KEY=
|
|
1808
1808
|
APP_VERSION=
|
|
1809
|
-
`}function
|
|
1809
|
+
`}function Ji(e){J(L.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
|
|
1810
1810
|
/**
|
|
1811
1811
|
* \u963F\u91CC\u4E91 ARMS (Application Real-time Monitoring Service) browser agent.
|
|
1812
1812
|
* Injects the official JS agent via next/script.
|
|
@@ -1827,11 +1827,11 @@ export function ArmsScript() {
|
|
|
1827
1827
|
/>
|
|
1828
1828
|
);
|
|
1829
1829
|
}
|
|
1830
|
-
`)}function
|
|
1830
|
+
`)}function Qi(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
|
|
1831
1831
|
ALIYUN_ARMS_LICENSE_KEY=
|
|
1832
1832
|
ALIYUN_ARMS_APP_NAME=
|
|
1833
1833
|
NEXT_PUBLIC_ARMS_PID=
|
|
1834
|
-
`}function
|
|
1834
|
+
`}function Zi(e){J(L.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
|
|
1835
1835
|
/**
|
|
1836
1836
|
* \u542C\u4E91 Browser Agent (\u524D\u7AEF\u6027\u80FD\u76D1\u63A7).
|
|
1837
1837
|
* Docs: https://www.tingyun.com/docs
|
|
@@ -1849,12 +1849,12 @@ export function TingYunScript() {
|
|
|
1849
1849
|
/>
|
|
1850
1850
|
);
|
|
1851
1851
|
}
|
|
1852
|
-
`)}function
|
|
1852
|
+
`)}function es(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
|
|
1853
1853
|
TINGYUN_LICENSE_KEY=
|
|
1854
1854
|
NEXT_PUBLIC_TINGYUN_APP_KEY=
|
|
1855
|
-
`}async function mo(e,t,o="global"){let n=uo(t);if(!n||n.id==="none")return;let r=
|
|
1856
|
-
`)}}import oe from"fs";import
|
|
1857
|
-
`+t):oe.writeFileSync(o,t)}function
|
|
1855
|
+
`}async function mo(e,t,o="global"){let n=uo(t);if(!n||n.id==="none")return;let r=L.join(e,"apps","web");if(!ne.existsSync(r))return;let i=n.id;try{switch(i){case"sentry":qi(r),Qt(r,Jt.sentry),mt(e,Gi());return;case"datadog":Wi(r),Qt(r,Jt.datadog),mt(e,Hi());return;case"bugsnag":Xi(r),Qt(r,Jt.bugsnag),mt(e,zi());return;case"aliyun-arms":Ji(r),mt(e,Qi());return;case"tingyun":Zi(r),mt(e,es());return;default:return}}catch(s){throw console.error(`Failed to apply monitoring selection "${t}":`,s),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Nt=[{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 go(e){return Nt.find(t=>t.id===e)}var sp=Nt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function fo(e,t,o="global"){let n=go(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Nt.map(r=>r.id).join(", ")}`);if(n.id==="none"){Y(e,"notifications");return}n.envVars.length>0&&H(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),X(e,"NOTIFICATIONS_PROVIDER",n.id)}import Zt from"fs";import ts from"path";async function yo(e,t){let o=ts.join(e,"package.json");if(Zt.existsSync(o)){let n=Zt.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",Zt.writeFileSync(o,JSON.stringify(r,null,2)+`
|
|
1856
|
+
`)}}import oe from"fs";import gt from"path";var ns=["stripe","lemonsqueezy","chinapay","polar"];function So(e){oe.existsSync(e)&&oe.rmSync(e,{recursive:!0,force:!0})}function os(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function rs(e,t){let o=gt.join(e,".env.example");oe.existsSync(o)?oe.appendFileSync(o,`
|
|
1857
|
+
`+t):oe.writeFileSync(o,t)}function is(e){switch(e){case"stripe":return`# Stripe
|
|
1858
1858
|
STRIPE_SECRET_KEY=
|
|
1859
1859
|
STRIPE_WEBHOOK_SECRET=
|
|
1860
1860
|
`;case"lemon":return`# Lemon Squeezy
|
|
@@ -1869,12 +1869,12 @@ CHINAPAY_WECHAT_ENABLED=true
|
|
|
1869
1869
|
CHINAPAY_APP_ID=
|
|
1870
1870
|
CHINAPAY_APP_SECRET=
|
|
1871
1871
|
CHINAPAY_ALIPAY_ENABLED=true
|
|
1872
|
-
`}}async function ho(e,t){let o=
|
|
1873
|
-
`),n=[],r=e.includes("#"),i=0;for(;i<o.length;){let s=o[i],c=s.match(en);if(!c){n.push(s),i++;continue}let{marker:a,keep:l}=
|
|
1874
|
-
`),t)}function
|
|
1872
|
+
`}}async function ho(e,t){let o=gt.join(e,"packages","commerce","billing");if(!oe.existsSync(o))return;if(t==="none"){So(o);return}let n=gt.join(o,"src"),r=new Set(os(t));for(let s of ns)r.has(s)||So(gt.join(n,s));let i=gt.join(n,"checkout","types.ts");if(oe.existsSync(i)){let s=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=oe.readFileSync(i,"utf8"),a=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${s}";`);a!==c&&oe.writeFileSync(i,a)}rs(e,is(t))}import de from"fs";import tt from"path";var _o=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),en=/@sailor:([^\s*]+)/;function ss(e,t){let{providerIds:o,customEndpoint:n}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:o.includes(r)}}if(e==="cn-compatible"){let r=o.some(i=>_o.has(i));return{marker:e,keep:r||!!n}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:o.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!n}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function Eo(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function vo(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function bo(e,t){let o=e.split(`
|
|
1873
|
+
`),n=[],r=e.includes("#"),i=0;for(;i<o.length;){let s=o[i],c=s.match(en);if(!c){n.push(s),i++;continue}let{marker:a,keep:l}=ss(c[1],t);if(a==="registry-entries"){n.push(r?vo(s):Eo(s)),i++;continue}if(l){let m=r?vo(s):Eo(s);m.trim().length>0&&n.push(m);let y=i+1;for(;y<o.length&&o[y].trim()!==""&&!en.test(o[y]);)n.push(o[y]),y++;y<o.length&&o[y].trim()===""&&(n.push(o[y]),y++),i=y}else{let m=i+1;for(;m<o.length&&o[m].trim()!==""&&!en.test(o[m]);)m++;m<o.length&&o[m].trim()===""&&m++,i=m}}return as(n.join(`
|
|
1874
|
+
`),t)}function as(e,t){let{providerIds:o,customEndpoint:n}=t,r=new Set;for(let l of o)["openai","anthropic","google","mistral","xai"].includes(l)&&r.add(l),r.add(l.replace(/-/g,"_")),r.add(l);n&&r.add("custom");let i=/createProviderRegistry\(\{([\s\S]*?)\}\)/,s=e.match(i);if(!s)return e;let a=s[1].split(`
|
|
1875
1875
|
`).filter(l=>{let m=l.trim();if(m===""||m.startsWith("//"))return!0;let y=m.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return y?r.has(y[1]):!0}).join(`
|
|
1876
|
-
`);return e.replace(i,`createProviderRegistry({${a}})`)}function
|
|
1877
|
-
`+r);let s={ai:"latest"},{providerIds:c,customEndpoint:a}=t;(c.includes("openai")||a||c.some(m=>_o.has(m)))&&(s["@ai-sdk/openai"]="latest",s["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(s["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(s["@ai-sdk/google"]="latest"),c.includes("mistral")&&(s["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(s["@ai-sdk/openai"]="latest");let l=
|
|
1876
|
+
`);return e.replace(i,`createProviderRegistry({${a}})`)}function cs(e,t){let o=tt.join(t,"registry.ts.template"),n=de.readFileSync(o,"utf-8");return bo(n,e)}function ps(e,t){let o=tt.join(t,".env.example.template"),n=de.readFileSync(o,"utf-8");return bo(n,e)}async function Po(e,t,o){let n=cs(t,o),r=ps(t,o),i=tt.join(e,"packages/ai/agents/src");await de.promises.mkdir(i,{recursive:!0}),await de.promises.writeFile(tt.join(i,"registry.ts"),n),await de.promises.appendFile(tt.join(e,".env.example"),`
|
|
1877
|
+
`+r);let s={ai:"latest"},{providerIds:c,customEndpoint:a}=t;(c.includes("openai")||a||c.some(m=>_o.has(m)))&&(s["@ai-sdk/openai"]="latest",s["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(s["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(s["@ai-sdk/google"]="latest"),c.includes("mistral")&&(s["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(s["@ai-sdk/openai"]="latest");let l=tt.join(e,"package.json");if(de.existsSync(l)){let m=JSON.parse(await de.promises.readFile(l,"utf-8"));m.dependencies||(m.dependencies={});for(let[y,x]of Object.entries(s))m.dependencies[y]=x;await de.promises.writeFile(l,JSON.stringify(m,null,2)+`
|
|
1878
1878
|
`)}}import f from"fs";import d from"path";function Co(e,t){if(!f.existsSync(e))return;let o=f.readdirSync(e);for(let n of o){let r=d.join(e,n);f.statSync(r).isDirectory()?Co(r,t):t(r)}}async function Io(e,t){let o=d.join(e,"package.json");if(!f.existsSync(o))return;let n=JSON.parse(f.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=d.join(e,"packages","db");if(f.existsSync(r)){let i=d.join(r,"prisma");f.existsSync(i)&&f.rmSync(i,{recursive:!0,force:!0});let s=d.join(r,"package.json");if(f.existsSync(s)){let a=JSON.parse(f.readFileSync(s,"utf8"));a.dependencies&&delete a.dependencies["@prisma/client"],a.devDependencies&&delete a.devDependencies.prisma,f.writeFileSync(s,JSON.stringify(a,null,2)+`
|
|
1879
1879
|
`)}let c=d.join(r,"src","index.ts");f.existsSync(c)&&f.writeFileSync(c,`
|
|
1880
1880
|
export const prisma = {} as any;
|
|
@@ -1922,7 +1922,7 @@ export type UsageAggregate = any;
|
|
|
1922
1922
|
export type UsageLedgerEntry = any;
|
|
1923
1923
|
export type UsageType = any;
|
|
1924
1924
|
export type UsageLedgerSource = any;
|
|
1925
|
-
`)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=d.join(e,"apps");if(f.existsSync(r)){let i=f.readdirSync(r);for(let s of i){let c=d.join(r,s);if(!f.statSync(c).isDirectory())continue;let a=d.join(c,"src","app");if(!f.existsSync(a))continue;["[lang]","[locale]"].forEach(b=>{let u=d.join(a,b);if(f.existsSync(u)){let
|
|
1925
|
+
`)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=d.join(e,"apps");if(f.existsSync(r)){let i=f.readdirSync(r);for(let s of i){let c=d.join(r,s);if(!f.statSync(c).isDirectory())continue;let a=d.join(c,"src","app");if(!f.existsSync(a))continue;["[lang]","[locale]"].forEach(b=>{let u=d.join(a,b);if(f.existsSync(u)){let O=f.readdirSync(u);for(let Et of O)f.renameSync(d.join(u,Et),d.join(a,Et));f.rmdirSync(u)}}),["src/middleware.ts","middleware.ts"].forEach(b=>{let u=d.join(c,b);f.existsSync(u)&&f.rmSync(u)});let l=d.join(c,"src","lib");f.existsSync(l)||f.mkdirSync(l,{recursive:!0});let m=d.join(l,"mock-i18n.ts");f.writeFileSync(m,`
|
|
1926
1926
|
import React from 'react';
|
|
1927
1927
|
export function useTranslations(namespace?: string): any { return (key: string) => key; }
|
|
1928
1928
|
export function useLocale() { return 'en'; }
|
|
@@ -1963,14 +1963,14 @@ export * from './mock-i18n';
|
|
|
1963
1963
|
export { default } from './mock-i18n';
|
|
1964
1964
|
`);let N=d.join(c,"tsconfig.json");if(f.existsSync(N))try{let b=f.readFileSync(N,"utf8");if(b.includes('"paths": {')){let u=b.replace(/"paths":\s*\{/,`"paths": {
|
|
1965
1965
|
"next-intl": ["./src/lib/mock-i18n"],
|
|
1966
|
-
"next-intl/*": ["./src/lib/mock-i18n"],`);f.writeFileSync(N,u)}}catch{}let
|
|
1966
|
+
"next-intl/*": ["./src/lib/mock-i18n"],`);f.writeFileSync(N,u)}}catch{}let M=d.join(c,"src");f.existsSync(M)&&Co(M,b=>{if(!b.endsWith(".ts")&&!b.endsWith(".tsx"))return;let u=f.readFileSync(b,"utf8"),O=!1;b.endsWith("src/app/layout.tsx")&&u.includes("../providers")&&(u=u.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),O=!0),u=u.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),u=u.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),u.match(/locale\s*:\s*any/)&&(u=u.replace(/locale\s*:\s*any/g,"locale: string"),O=!0),u.match(/lang\s*:\s*any/)&&(u=u.replace(/lang\s*:\s*any/g,"lang: string"),O=!0),u.match(/requestLocale\s*:\s*any/)&&(u=u.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),O=!0),u.match(/\(locale\s*=\s*(.*)\)/)&&(u=u.replace(/\(locale\s*=\s*(.*)\)/g,"() "),O=!0),u.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(u=u.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),O=!0),(b.endsWith("src/app/layout.tsx")||b.endsWith("src/app/sitemap.ts")||b.endsWith("src/app/robots.ts")||b.endsWith("src/components/ui/locale-switcher.tsx")||b.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(u=u.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),u=u.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),u=u.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),u=u.replace(/\(l\)\s*=>/g,"(l: any) =>"),O=!0),b.endsWith("src/i18n/request.ts")&&(u=u.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),O=!0),(u.match(/locale\s*:/)||u.match(/lang\s*:/))&&(O=!0),O&&f.writeFileSync(b,u)});let re=d.join(c,"package.json");if(f.existsSync(re)){let b=JSON.parse(f.readFileSync(re,"utf8"));b.dependencies&&delete b.dependencies["next-intl"],f.writeFileSync(re,JSON.stringify(b,null,2)+`
|
|
1967
1967
|
`)}}}}f.writeFileSync(o,JSON.stringify(n,null,2)+`
|
|
1968
|
-
`)}function E(e){try{f.rmSync(e,{recursive:!0,force:!0})}catch{}}function
|
|
1969
|
-
`)}function Ao(e,t){t.cronJobs||(E(d.join(e,"apps/web/src/app/api/cron")),E(d.join(e,"packages/integrations/queue/src/scheduled"))),t.auditLog||(E(d.join(e,"apps/web/src/app/[locale]/(app)/settings/audit-log")),E(d.join(e,"apps/web/src/app/api/audit-logs")),E(d.join(e,"apps/web/src/components/audit"))),t.apiKeys||(E(d.join(e,"apps/web/src/app/[locale]/(app)/settings/api-keys")),E(d.join(e,"apps/web/src/app/api/api-keys")),E(d.join(e,"apps/web/src/components/api-keys"))),t.webhooks||(E(d.join(e,"apps/web/src/app/[locale]/(app)/settings/webhooks")),E(d.join(e,"apps/web/src/app/api/webhooks")),E(d.join(e,"apps/web/src/components/webhooks")),E(d.join(e,"packages/webhooks"))),t.commandPalette||(E(d.join(e,"apps/web/src/components/command-palette")),E(d.join(e,"apps/web/src/app/[locale]/providers/command-palette-mount.tsx"))),t.cookieConsent||(E(d.join(e,"apps/landing-page/src/components/cookie-consent-banner.tsx")),E(d.join(e,"apps/landing-page/src/components/__tests__/cookie-consent-banner.test.tsx")),E(d.join(e,"apps/landing-page/src/lib/cookie-consent.ts")),E(d.join(e,"apps/landing-page/src/lib/__tests__/cookie-consent.test.ts")),E(d.join(e,"apps/web/src/app/api/cookie-consent"))),t.legalPages||(E(d.join(e,"apps/landing-page/src/app/[lang]/(legal)/legal")),E(d.join(e,"apps/landing-page/src/lib/legal-documents.ts")),E(d.join(e,"apps/landing-page/src/lib/__tests__/legal-documents.test.ts"))),t.chinaCompliance||(E(d.join(e,"packages/china-compliance")),E(d.join(e,"apps/landing-page/src/components/icp-footer.tsx")),E(d.join(e,"apps/landing-page/src/components/__tests__/icp-footer.test.tsx")),E(d.join(e,"apps/web/src/components/auth/wechat-login-button.tsx")),E(d.join(e,"apps/web/src/components/auth/__tests__/wechat-login-button.test.tsx")),
|
|
1970
|
-
`);ue.appendFileSync(o,i)}function
|
|
1971
|
-
`)}async function ko(e,t,o){let n=nn.join(e,"packages","queue");if(t==="none"){ue.existsSync(n)&&ue.rmSync(n,{recursive:!0,force:!0});return}let r=wo(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${Tt.map(i=>i.id).join(", ")}`);ue.existsSync(n)&&(
|
|
1972
|
-
`);me.appendFileSync(o,i)}function
|
|
1973
|
-
`)}async function To(e,t,o){let n=on.join(e,"packages","search");if(t==="none"){me.existsSync(n)&&me.rmSync(n,{recursive:!0,force:!0});return}let r=xo(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Ot.map(i=>i.id).join(", ")}`);me.existsSync(n)&&(
|
|
1968
|
+
`)}function E(e){try{f.rmSync(e,{recursive:!0,force:!0})}catch{}}function ls(e,t){if(!f.existsSync(e))return;let o;try{o=JSON.parse(f.readFileSync(e,"utf8"))}catch{return}let n=!1;if(o.dependencies&&t in o.dependencies){let{[t]:r,...i}=o.dependencies;o={...o,dependencies:i},n=!0}if(o.devDependencies&&t in o.devDependencies){let{[t]:r,...i}=o.devDependencies;o={...o,devDependencies:i},n=!0}n&&f.writeFileSync(e,JSON.stringify(o,null,2)+`
|
|
1969
|
+
`)}function Ao(e,t){t.cronJobs||(E(d.join(e,"apps/web/src/app/api/cron")),E(d.join(e,"packages/integrations/queue/src/scheduled"))),t.auditLog||(E(d.join(e,"apps/web/src/app/[locale]/(app)/settings/audit-log")),E(d.join(e,"apps/web/src/app/api/audit-logs")),E(d.join(e,"apps/web/src/components/audit"))),t.apiKeys||(E(d.join(e,"apps/web/src/app/[locale]/(app)/settings/api-keys")),E(d.join(e,"apps/web/src/app/api/api-keys")),E(d.join(e,"apps/web/src/components/api-keys"))),t.webhooks||(E(d.join(e,"apps/web/src/app/[locale]/(app)/settings/webhooks")),E(d.join(e,"apps/web/src/app/api/webhooks")),E(d.join(e,"apps/web/src/components/webhooks")),E(d.join(e,"packages/webhooks"))),t.commandPalette||(E(d.join(e,"apps/web/src/components/command-palette")),E(d.join(e,"apps/web/src/app/[locale]/providers/command-palette-mount.tsx"))),t.cookieConsent||(E(d.join(e,"apps/landing-page/src/components/cookie-consent-banner.tsx")),E(d.join(e,"apps/landing-page/src/components/__tests__/cookie-consent-banner.test.tsx")),E(d.join(e,"apps/landing-page/src/lib/cookie-consent.ts")),E(d.join(e,"apps/landing-page/src/lib/__tests__/cookie-consent.test.ts")),E(d.join(e,"apps/web/src/app/api/cookie-consent"))),t.legalPages||(E(d.join(e,"apps/landing-page/src/app/[lang]/(legal)/legal")),E(d.join(e,"apps/landing-page/src/lib/legal-documents.ts")),E(d.join(e,"apps/landing-page/src/lib/__tests__/legal-documents.test.ts"))),t.chinaCompliance||(E(d.join(e,"packages/china-compliance")),E(d.join(e,"apps/landing-page/src/components/icp-footer.tsx")),E(d.join(e,"apps/landing-page/src/components/__tests__/icp-footer.test.tsx")),E(d.join(e,"apps/web/src/components/auth/wechat-login-button.tsx")),E(d.join(e,"apps/web/src/components/auth/__tests__/wechat-login-button.test.tsx")),ls(d.join(e,"apps/web/package.json"),"@nebutra/china-compliance"))}import{getSchema as ds,printSchema as us}from"@mrleebo/prisma-ast";var ms=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function gs(e){return e.type==="comment"&&e.text.trim().startsWith("///")}function fs(e){let t=ms.exec(e.trim());if(!t)return null;let[,o,n]=t,r=n.split("|").map(i=>i.trim()).filter(i=>i.length>0);return{flag:o,values:r}}function ys(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=fs(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function tn(e,t){let o=ds(e),n=new Set;for(let c=0;c<o.list.length;c++){if(o.list[c].type!=="model")continue;let l=ys(o.list,c);if(!l)continue;let m=t[l.parsed.flag];if(m!==void 0&&l.parsed.values.includes(m))n.add(l.annIndex);else{n.add(c);for(let N=c-1;N>=0;N--){let M=o.list[N];if(M.type==="comment"&&gs(M)){n.add(N);continue}break}let x=o.list[c+1];x&&x.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,a)=>!n.has(a)),i=[];for(let c of r){let a=i[i.length-1];c.type==="break"&&a&&a.type==="break"||i.push(c)}return us({type:"schema",list:i})}import ue from"fs";import nn from"path";var Tt=[{id:"qstash",name:"Upstash QStash",region:"both",envVars:["QSTASH_TOKEN","QSTASH_CURRENT_SIGNING_KEY","QSTASH_NEXT_SIGNING_KEY"],docs:"https://upstash.com/docs/qstash",description:"Serverless HTTP-based queue"},{id:"bullmq",name:"BullMQ",region:"both",envVars:["REDIS_URL"],docs:"https://docs.bullmq.io",description:"Redis-backed job queue"},{id:"sqs",name:"AWS SQS",region:"global",envVars:["AWS_SQS_QUEUE_URL","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"],docs:"https://docs.aws.amazon.com/AWSSimpleQueueService/",description:"AWS managed queue"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip queue package"}];function wo(e){return Tt.find(t=>t.id===e)}var Ip=Tt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Ro(e){return ue.existsSync(e)?ue.readFileSync(e,"utf-8"):null}function Ss(e,t){let o=nn.join(e,".env.example"),n=Ro(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
|
|
1970
|
+
`);ue.appendFileSync(o,i)}function hs(e,t,o){let n=nn.join(e,".env.example"),r=Ro(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ue.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ue.appendFileSync(n,`${t}="${o}"
|
|
1971
|
+
`)}async function ko(e,t,o){let n=nn.join(e,"packages","queue");if(t==="none"){ue.existsSync(n)&&ue.rmSync(n,{recursive:!0,force:!0});return}let r=wo(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${Tt.map(i=>i.id).join(", ")}`);ue.existsSync(n)&&(Ss(e,r),hs(e,"QUEUE_PROVIDER",t))}import me from"fs";import on from"path";var Ot=[{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 xo(e){return Ot.find(t=>t.id===e)}var Np=Ot.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function No(e){return me.existsSync(e)?me.readFileSync(e,"utf-8"):null}function Es(e,t){let o=on.join(e,".env.example"),n=No(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
|
|
1972
|
+
`);me.appendFileSync(o,i)}function vs(e,t,o){let n=on.join(e,".env.example"),r=No(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?me.writeFileSync(n,r.replace(i,`${t}="${o}"`)):me.appendFileSync(n,`${t}="${o}"
|
|
1973
|
+
`)}async function To(e,t,o){let n=on.join(e,"packages","search");if(t==="none"){me.existsSync(n)&&me.rmSync(n,{recursive:!0,force:!0});return}let r=xo(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Ot.map(i=>i.id).join(", ")}`);me.existsSync(n)&&(Es(e,r),vs(e,"SEARCH_PROVIDER",t))}import ge from"fs";import Ne from"path";function _s(e){let t=[Ne.join(e,"packages","db"),Ne.join(e,"apps","web")];for(let o of t){let n=Ne.join(o,"prisma","schema.prisma");if(ge.existsSync(n))return{packageDir:o,seedPath:Ne.join(o,"prisma","seed.ts"),packageJsonPath:Ne.join(o,"package.json")}}return null}function bs(e){try{let t=ge.readFileSync(e,"utf8"),o=new Set,n=/^\s*model\s+(\w+)\s*\{/gm,r=n.exec(t);for(;r;)o.add(r[1]),r=n.exec(t);return o}catch{return new Set}}function Ps(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
|
|
1974
1974
|
const admin = await prisma.user.create({
|
|
1975
1975
|
data: {
|
|
1976
1976
|
clerkId: "user_mock_admin",
|
|
@@ -2001,7 +2001,7 @@ export { default } from './mock-i18n';
|
|
|
2001
2001
|
console.log("\\u2713 Created admin user:", admin.email);
|
|
2002
2002
|
} catch (err) {
|
|
2003
2003
|
console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
|
|
2004
|
-
}`}function
|
|
2004
|
+
}`}function Cs(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),i=Ps(e,n),s=o?` let tenants: Array<{ id: string; name: string }> = [];
|
|
2005
2005
|
try {
|
|
2006
2006
|
tenants = await Promise.all([
|
|
2007
2007
|
prisma.tenant.create({
|
|
@@ -2070,12 +2070,12 @@ main()
|
|
|
2070
2070
|
.finally(async () => {
|
|
2071
2071
|
await prisma.$disconnect();
|
|
2072
2072
|
});
|
|
2073
|
-
`}function
|
|
2074
|
-
`)}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 Oo(e,t){let o=
|
|
2075
|
-
`+t):fe.writeFileSync(o,t)}function
|
|
2073
|
+
`}function Is(e){if(ge.existsSync(e))try{let t=ge.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let i=o.prisma??{};if(i.seed||(i.seed="tsx prisma/seed.ts",r=!0),!r)return;let s={...o,scripts:n,prisma:i};ge.writeFileSync(e,JSON.stringify(s,null,2)+`
|
|
2074
|
+
`)}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 Oo(e,t){let o=_s(e);if(o)try{let n=Ne.join(o.packageDir,"prisma","schema.prisma"),r=bs(n),i=Cs(t,r),s=Ne.dirname(o.seedPath);ge.existsSync(s)||ge.mkdirSync(s,{recursive:!0}),ge.writeFileSync(o.seedPath,i),Is(o.packageJsonPath)}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate seed data: ${r}`),new Error(`Unable to write prisma/seed.ts: ${r}`)}}import fe from"fs";import Te from"path";var Ut=[{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:""}],Kp=Ut.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Uo(e){return Ut.find(t=>t.id===e)}var As="@nebutra/sms",ws={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 rn(e,t){fe.mkdirSync(Te.dirname(e),{recursive:!0}),fe.writeFileSync(e,t)}function Rs(e,t){let o=Te.join(e,".env.example");fe.existsSync(o)?fe.appendFileSync(o,`
|
|
2075
|
+
`+t):fe.writeFileSync(o,t)}function ks(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2076
2076
|
`);return`${t}
|
|
2077
2077
|
${o}
|
|
2078
|
-
`}var
|
|
2078
|
+
`}var xs=`/**
|
|
2079
2079
|
* Inputs for the \`sendSms\` wrapper. Keep this surface portable across
|
|
2080
2080
|
* providers \u2014 provider-specific options belong in the wrapper itself.
|
|
2081
2081
|
*/
|
|
@@ -2095,7 +2095,7 @@ export interface SendSmsResult {
|
|
|
2095
2095
|
provider: string;
|
|
2096
2096
|
raw?: unknown;
|
|
2097
2097
|
}
|
|
2098
|
-
`;function
|
|
2098
|
+
`;function Ns(){return`import twilio from "twilio";
|
|
2099
2099
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2100
2100
|
|
|
2101
2101
|
let client: ReturnType<typeof twilio> | null = null;
|
|
@@ -2130,7 +2130,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2130
2130
|
}
|
|
2131
2131
|
|
|
2132
2132
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2133
|
-
`}function
|
|
2133
|
+
`}function Ts(){return`import messagebird from "messagebird";
|
|
2134
2134
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2135
2135
|
|
|
2136
2136
|
let client: ReturnType<typeof messagebird> | null = null;
|
|
@@ -2168,7 +2168,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2168
2168
|
}
|
|
2169
2169
|
|
|
2170
2170
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2171
|
-
`}function
|
|
2171
|
+
`}function Os(){return`import plivo from "plivo";
|
|
2172
2172
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2173
2173
|
|
|
2174
2174
|
let client: InstanceType<typeof plivo.Client> | null = null;
|
|
@@ -2207,7 +2207,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2207
2207
|
}
|
|
2208
2208
|
|
|
2209
2209
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2210
|
-
`}function
|
|
2210
|
+
`}function Us(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
|
|
2211
2211
|
import * as $OpenApi from "@alicloud/openapi-client";
|
|
2212
2212
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2213
2213
|
|
|
@@ -2256,7 +2256,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2256
2256
|
}
|
|
2257
2257
|
|
|
2258
2258
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2259
|
-
`}function
|
|
2259
|
+
`}function Ls(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
|
|
2260
2260
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2261
2261
|
|
|
2262
2262
|
const SmsClient = tencentcloud.sms.v20210111.Client;
|
|
@@ -2321,7 +2321,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2321
2321
|
}
|
|
2322
2322
|
|
|
2323
2323
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2324
|
-
`}function
|
|
2324
|
+
`}function Ms(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
|
|
2325
2325
|
import Yunpian from "yunpian-nodejs-sdk";
|
|
2326
2326
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2327
2327
|
|
|
@@ -2373,13 +2373,13 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2373
2373
|
}
|
|
2374
2374
|
|
|
2375
2375
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2376
|
-
`}function
|
|
2377
|
-
`}}function
|
|
2378
|
-
`}async function Lo(e,t,o="global"){if(t==="none")return;let n=Uo(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${Ut.map(s=>s.id).join(", ")}`);let r=
|
|
2379
|
-
`+t):
|
|
2376
|
+
`}function Fs(e){switch(e){case"twilio":return Ns();case"messagebird":return Ts();case"plivo":return Os();case"aliyun-sms":return Us();case"tencent-sms":return Ls();case"yunpian":return Ms();case"none":return`export {};
|
|
2377
|
+
`}}function Ds(e){let t={};for(let n of e.pkgs??[]){let r=ws[n];r&&(t[n]=r)}let o={name:As,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)+`
|
|
2378
|
+
`}async function Lo(e,t,o="global"){if(t==="none")return;let n=Uo(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${Ut.map(s=>s.id).join(", ")}`);let r=Te.join(e,"packages","sms");if(!fe.existsSync(r))return;let i=Te.join(r,"src");fe.existsSync(i)&&fe.rmSync(i,{recursive:!0,force:!0});try{rn(Te.join(r,"package.json"),Ds(n)),rn(Te.join(i,"types.ts"),xs),rn(Te.join(i,"index.ts"),Fs(n.id)),Rs(e,ks(n))}catch(s){throw console.error(`Failed to apply SMS selection "${t}":`,s),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import Ue from"fs";import Oe from"path";var ft=[{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 sn(e){let t=e==="supabase"?"supabase-storage":e;return ft.some(o=>o.id===t)?t:void 0}function Mo(e){let t=sn(e);return t?ft.find(o=>o.id===t):void 0}var Gp=ft.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Le="@nebutra/storage";function an(e,t){Ue.mkdirSync(Oe.dirname(e),{recursive:!0}),Ue.writeFileSync(e,t)}function js(e,t){let o=Oe.join(e,".env.example");Ue.existsSync(o)?Ue.appendFileSync(o,`
|
|
2379
|
+
`+t):Ue.writeFileSync(o,t)}function Ks(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2380
2380
|
`);return`${t}
|
|
2381
2381
|
${o}
|
|
2382
|
-
`}var
|
|
2382
|
+
`}var Vs=`/**
|
|
2383
2383
|
* Inputs for the \`uploadFile\` wrapper. Keep this surface portable across
|
|
2384
2384
|
* providers \u2014 provider-specific options belong in the wrapper itself.
|
|
2385
2385
|
*/
|
|
@@ -2405,8 +2405,8 @@ export interface SignedUrlOptions {
|
|
|
2405
2405
|
operation?: "get" | "put";
|
|
2406
2406
|
contentType?: string;
|
|
2407
2407
|
}
|
|
2408
|
-
`;function
|
|
2409
|
-
* @${
|
|
2408
|
+
`;function Bs(){return`/**
|
|
2409
|
+
* @${Le.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
|
|
2410
2410
|
*
|
|
2411
2411
|
* Docs: https://developers.cloudflare.com/r2/api/s3/api/
|
|
2412
2412
|
*/
|
|
@@ -2469,8 +2469,8 @@ export async function getSignedUrl(
|
|
|
2469
2469
|
}
|
|
2470
2470
|
|
|
2471
2471
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2472
|
-
`}function
|
|
2473
|
-
* @${
|
|
2472
|
+
`}function $s(){return`/**
|
|
2473
|
+
* @${Le.slice(1)} \u2014 AWS S3 wrapper.
|
|
2474
2474
|
*
|
|
2475
2475
|
* Docs: https://docs.aws.amazon.com/s3/
|
|
2476
2476
|
*/
|
|
@@ -2534,8 +2534,8 @@ export async function getSignedUrl(
|
|
|
2534
2534
|
}
|
|
2535
2535
|
|
|
2536
2536
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2537
|
-
`}function
|
|
2538
|
-
* @${
|
|
2537
|
+
`}function Ys(){return`/**
|
|
2538
|
+
* @${Le.slice(1)} \u2014 Supabase Storage wrapper.
|
|
2539
2539
|
*
|
|
2540
2540
|
* Docs: https://supabase.com/docs/guides/storage
|
|
2541
2541
|
*/
|
|
@@ -2597,8 +2597,8 @@ export async function getSignedUrl(
|
|
|
2597
2597
|
}
|
|
2598
2598
|
|
|
2599
2599
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2600
|
-
`}function
|
|
2601
|
-
* @${
|
|
2600
|
+
`}function qs(){return`/**
|
|
2601
|
+
* @${Le.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
|
|
2602
2602
|
*
|
|
2603
2603
|
* Docs: https://help.aliyun.com/product/31815.html
|
|
2604
2604
|
*/
|
|
@@ -2644,8 +2644,8 @@ export async function getSignedUrl(
|
|
|
2644
2644
|
}
|
|
2645
2645
|
|
|
2646
2646
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2647
|
-
`}function
|
|
2648
|
-
* @${
|
|
2647
|
+
`}function Gs(){return`/**
|
|
2648
|
+
* @${Le.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
|
|
2649
2649
|
*
|
|
2650
2650
|
* Docs: https://cloud.tencent.com/document/product/436
|
|
2651
2651
|
*/
|
|
@@ -2699,8 +2699,8 @@ export async function getSignedUrl(
|
|
|
2699
2699
|
}
|
|
2700
2700
|
|
|
2701
2701
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2702
|
-
`}function
|
|
2703
|
-
* @${
|
|
2702
|
+
`}function Ws(){return`/**
|
|
2703
|
+
* @${Le.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
|
|
2704
2704
|
*
|
|
2705
2705
|
* Docs: https://developer.qiniu.com/kodo
|
|
2706
2706
|
*/
|
|
@@ -2767,9 +2767,9 @@ export async function getSignedUrl(
|
|
|
2767
2767
|
}
|
|
2768
2768
|
|
|
2769
2769
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2770
|
-
`}function
|
|
2771
|
-
`}}function
|
|
2772
|
-
`}async function Fo(e,t,o){if(t==="none")return;let n=Mo(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${
|
|
2770
|
+
`}function Hs(e){switch(e){case"r2":return Bs();case"s3":return $s();case"supabase-storage":return Ys();case"aliyun-oss":return qs();case"tencent-cos":return Gs();case"qiniu":return Ws();case"none":return`export {};
|
|
2771
|
+
`}}function Xs(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:Le,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)+`
|
|
2772
|
+
`}async function Fo(e,t,o){if(t==="none")return;let n=Mo(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${ft.map(s=>s.id).join(", ")}`);let r=Oe.join(e,"packages","storage"),i=Oe.join(r,"src");Ue.existsSync(i)&&Ue.rmSync(i,{recursive:!0,force:!0}),an(Oe.join(r,"package.json"),Xs(n)),an(Oe.join(i,"types.ts"),Vs),an(Oe.join(i,"index.ts"),Hs(n.id)),js(e,Ks(n))}function ye(e,t){if(e===void 0)return t;let o=String(e).trim().toLowerCase();return o==="true"||o==="1"||o==="yes"||o==="on"?!0:o==="false"||o==="0"||o==="no"||o==="off"?!1:t}function Do(e,t){let o=t==="cn";return{cronJobs:ye(e.cronJobs,!0),auditLog:ye(e.auditLog,!0),apiKeys:ye(e.apiKeys,!0),webhooks:ye(e.webhooks,!0),commandPalette:ye(e.commandPalette,!0),cookieConsent:ye(e.cookieConsent,!0),legalPages:ye(e.legalPages,!0),chinaCompliance:ye(e.chinaCompliance,o)}}var Lt=[{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 jo(e){return Lt.find(t=>t.id===e)}var Zp=Lt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Ko(e,t,o="global"){let n=jo(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Lt.map(r=>r.id).join(", ")}`);if(n.id==="none"){Y(e,"webhooks");return}n.envVars.length>0&&H(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),X(e,"WEBHOOKS_PROVIDER",n.id)}import Me from"fs";import yt from"path";function zs(e){return`import Link from "next/link";
|
|
2773
2773
|
|
|
2774
2774
|
export default function WelcomePage() {
|
|
2775
2775
|
const projectName = ${JSON.stringify(e)};
|
|
@@ -2878,21 +2878,21 @@ function Step({
|
|
|
2878
2878
|
</li>
|
|
2879
2879
|
);
|
|
2880
2880
|
}
|
|
2881
|
-
`}function
|
|
2881
|
+
`}function Js(e={}){return`
|
|
2882
2882
|
## What you can do next
|
|
2883
2883
|
|
|
2884
2884
|
${[e.apiKeys===!1?"- Manage API keys at `/settings/api-keys` (disabled \u2014 re-enable with `--api-keys=true`)":"- Manage API keys at `/settings/api-keys`",e.auditLog===!1?"- View audit log at `/settings/audit-log` (disabled \u2014 re-enable with `--audit-log=true`)":"- View audit log at `/settings/audit-log`","- Configure webhooks at `/settings/webhooks`",e.commandPalette===!1?"- Press \u2318K to open the command palette (disabled \u2014 re-enable with `--command-palette=true`)":"- Press \u2318K to open the command palette","- Edit notification preferences at `/settings/notifications`","- Export your data at `/settings/account/export`","- For China deployments, see `packages/ops/china-compliance/README.md`"].join(`
|
|
2885
2885
|
`)}
|
|
2886
|
-
`}function
|
|
2886
|
+
`}function Qs(e=[]){return e.length===0?"":`
|
|
2887
2887
|
## Production readiness holds
|
|
2888
2888
|
|
|
2889
2889
|
Do not enable these in production until you replace stubs, add provider credentials, and verify the integration contract:
|
|
2890
2890
|
|
|
2891
|
-
${e.map(o=>{let n=
|
|
2891
|
+
${e.map(o=>{let n=Qe(o.status);return`- ${o.flag}=${o.provider} ${n} \u2014 ${se(o.status)}`}).join(`
|
|
2892
2892
|
`)}
|
|
2893
2893
|
|
|
2894
2894
|
Review the package readiness matrix before handoff: [docs/package-status.md](docs/package-status.md)
|
|
2895
|
-
`}function
|
|
2895
|
+
`}function Zs(e,t,o=[],n={}){return`# Next steps \u2014 ${e}
|
|
2896
2896
|
|
|
2897
2897
|
Region: ${t}
|
|
2898
2898
|
|
|
@@ -2918,17 +2918,17 @@ Your AI-native SaaS scaffold is ready. Complete these four steps to go from temp
|
|
|
2918
2918
|
\`\`\`
|
|
2919
2919
|
|
|
2920
2920
|
After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
|
|
2921
|
-
${
|
|
2921
|
+
${Js(n)}${Qs(o)}
|
|
2922
2922
|
|
|
2923
2923
|
## Resources
|
|
2924
2924
|
|
|
2925
2925
|
- [Documentation](/docs)
|
|
2926
2926
|
- [GitHub](https://github.com/nebutra/nebutra-sailor)
|
|
2927
2927
|
- [Get free license (Individual/OPC)](https://nebutra.com/get-license)
|
|
2928
|
-
`}async function Vo(e,t){let{projectName:o,region:n,previewSelections:r=[],waveFeatures:i={}}=t;try{let s=
|
|
2929
|
-
`)}function
|
|
2928
|
+
`}async function Vo(e,t){let{projectName:o,region:n,previewSelections:r=[],waveFeatures:i={}}=t;try{let s=yt.join(e,".sailor");Me.existsSync(s)||Me.mkdirSync(s,{recursive:!0}),Me.writeFileSync(yt.join(s,"next-steps.md"),Zs(o,n,r,i))}catch(s){let c=s instanceof Error?s.message:String(s);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${c}`)}try{let s=yt.join(e,"apps","web");if(!Me.existsSync(s))return;let c=yt.join(s,"src","app","[locale]","welcome");Me.existsSync(c)||Me.mkdirSync(c,{recursive:!0}),Me.writeFileSync(yt.join(c,"page.tsx"),zs(o))}catch(s){let c=s instanceof Error?s.message:String(s);console.warn(`[create-sailor] Failed to write welcome page: ${c}`)}}var Bo="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
|
|
2929
|
+
`)}function na(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function $o(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 Yo(e){return e==="drizzle"?"drizzle":e==="none"?"none":"prisma"}function qo(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function Go(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 Wo(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="nextauth"||t==="next-auth"||t==="authjs"||t==="auth.js"?"nextauth":t==="none"?"none":"clerk"}var oa=new Set(["gateway","direct","custom","none"]);function er(e){if(!e)return!1;let t=e.trim().toLowerCase();return oa.has(t)}function Ho(e){if(!e)return["openai"];if(er(e))return[];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}function ra(e,t){let o=e??t;return sn(o)??o}var Xo={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function zo(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in Xo){let n=Xo[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(C.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
|
|
2930
2930
|
`)+C.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
|
|
2931
|
-
`)),"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 Qo(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function
|
|
2931
|
+
`)),"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 Qo(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function ia(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 Zo(e){return e==="cn"?"wechat":"stripe"}async function sa(){let e=new ea;e.name(Bo).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ie,"-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 | nextauth | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <mode-or-ids>","topology shorthand (gateway | direct | custom | none) OR comma-separated provider ids (e.g. openai,anthropic)").option("--deploy <target>","vercel | railway | cloudflare | selfhost").option("--docs <id>","fumadocs | mintlify | docusaurus | nextra | vitepress | none").option("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | none").option("--queue <id>","qstash | bullmq | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").option("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").option("--cron-jobs <bool>","true | false \u2014 scaffold scheduled cron handlers (default: true)").option("--audit-log <bool>","true | false \u2014 enable /settings/audit-log + arch test (default: true)").option("--api-keys <bool>","true | false \u2014 enable /settings/api-keys page (default: true)").option("--command-palette <bool>","true | false \u2014 enable \u2318K command palette (default: true)").option("--cookie-consent <bool>","true | false \u2014 enable GDPR/CCPA cookie banner (default: true)").option("--legal-pages <bool>","true | false \u2014 enable dynamic /legal/[slug] route (default: true)").option("--china-compliance <bool>","true | false \u2014 enable @nebutra/china-compliance + ICP footer (default: true when --region=cn, otherwise false)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--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&&(gn(),process.exit(0));let n=!!t.json,r=!!t.dryRun,i=!!t.yes,s=i||!process.stdin.isTTY;if(n||dn(),p(n,{event:"start",version:ie}),!t.pm)try{St("pnpm --version",{stdio:"ignore"})}catch{n||process.stderr.write(`
|
|
2932
2932
|
${C.red("\u2718")} ${C.bold("pnpm is required")} but was not found on PATH.
|
|
2933
2933
|
|
|
2934
2934
|
The scaffold uses pnpm workspaces + Turborepo. Install pnpm first:
|
|
@@ -2938,22 +2938,22 @@ Then retry: ${C.cyan("pnpm dlx create-sailor@latest")}
|
|
|
2938
2938
|
(or pass ${C.dim("--pm=npm")} if you know workspace:* won't resolve in your setup)
|
|
2939
2939
|
|
|
2940
2940
|
`),p(n,{event:"error",code:"PNPM_MISSING"}),process.exit(1)}let c=o??(i?"./my-saas-app":void 0),a;if(c)a=c;else if(s)a="./my-saas-app";else{let g=await k.group({name:()=>k.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:S=>{if(S.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(C.red(`\u2718 Cancelled
|
|
2941
|
-
`)),process.exit(130)}});a=String(g.name)}let l=
|
|
2942
|
-
`)),process.exit(130)}}):{};h=Qo(y?t.region:S.region),
|
|
2943
|
-
`))}}let Ee={region:h,orm:
|
|
2941
|
+
`)),process.exit(130)}});a=String(g.name)}let l=ht.basename(ht.resolve(a)),m=t.pm??na(),y=!!t.region,x=!!t.auth,N=!!t.payment,M=!!t.ai,re=!!t.email,b=!!t.storage,u=!!t.monitoring,O=!!t.analytics,Et=!!t.sms,cn=t.i18n!==void 0,h,nt,Q,ot,V,F,G=Pn(t.socialLogin),rt,Mt,he,Fe,Z,B,vt;if(s){h=Qo(t.region),nt=Yo(t.orm),Q=$o(t.db);let g=N?t.payment:Zo(h);ot=qo(g),V=Go(g),F=Wo(t.auth);let S="gateway";if(M){let ve=t.ai?.trim().toLowerCase()??"";er(ve)?S=ve:S="direct"}let T=Vt({mode:S,providerIds:M?Ho(t.ai):void 0});rt=T.mode,Mt=T.routing,he=T.providerIds,Z=Jo(t.deploy),B=zo(t.docs,n),vt=cn?!!t.i18n:!0}else{let g={};y||(g.region=()=>k.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"})),x||(g.auth=()=>k.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk",hint:"managed, fastest setup"},{value:"betterauth",label:"Better Auth",hint:"self-hosted, modern (2FA / passkeys / RBAC)"},{value:"nextauth",label:"NextAuth (Auth.js v5)",hint:"self-hosted, mature, large ecosystem"},{value:"none",label:"None"}],initialValue:"clerk"})),M||(g.aiMode=()=>k.select({message:"AI topology?",options:[{value:"gateway",label:"Multi-provider AI Gateway / router",hint:"recommended"},{value:"direct",label:"Direct SDK/provider adapters"},{value:"custom",label:"OpenAI-compatible endpoint"},{value:"none",label:"Skip AI"}],initialValue:"gateway"}),g.aiProviders=({results:_})=>{if(_.aiMode!=="direct")return Promise.resolve([]);let ee=Kt.map(Dt=>({value:Dt.id,label:`[${Dt.category}] ${Dt.name}`}));return k.multiselect({message:"Select direct AI provider adapters (expert path)",options:ee,initialValues:["openai"],required:!1})},g.customAiName=({results:_})=>_.aiMode==="custom"?k.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),g.customAiBaseUrl=({results:_})=>_.aiMode==="custom"?k.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:ee=>{if(ee.length===0)return"Base URL is required."}}):Promise.resolve(void 0),g.customAiApiKeyEnv=({results:_})=>_.aiMode==="custom"?k.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0));let S=Object.keys(g).length>0?await k.group(g,{onCancel:()=>{process.stdout.write(C.red(`\u2718 Cancelled
|
|
2942
|
+
`)),process.exit(130)}}):{};h=Qo(y?t.region:S.region),nt=Yo(t.orm),Q=$o(t.db);let T=N?t.payment:Zo(h);ot=qo(T),V=Go(T),F=Wo(x?t.auth:S.auth);let ve=S.aiMode==="custom"?{name:S.customAiName??"custom",baseURL:S.customAiBaseUrl??"",apiKeyEnvName:S.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,v=Vt({mode:M?t.ai?.trim().toLowerCase()==="none"?"none":"direct":S.aiMode??"gateway",providerIds:M?Ho(t.ai):S.aiProviders,customEndpoint:ve});rt=v.mode,Mt=v.routing,he=v.providerIds,v.customEndpoint&&(Fe={name:v.customEndpoint.name,baseURL:v.customEndpoint.baseURL,apiKeyEnvName:v.customEndpoint.apiKeyEnvName}),Z=Jo(t.deploy),B=zo(t.docs,n),vt=cn?!!t.i18n:!0}let A=ia(h),De=re?t.email:A.email,je=ra(b?t.storage:void 0,A.storage),Ke=u?t.monitoring:A.monitoring,Ve=O?t.analytics:A.analytics,Be=Et?t.sms:A.sms,$e=t.queue??A.queue,Ye=t.search??A.search,it=t.cache??A.cache,qe=t.notifications??A.notifications,Ge=t.webhooks??A.webhooks,st=t.cms??A.cms,We=t.featureFlags??A.featureFlags,He=t.captcha??A.captcha,_t=t.mcp??A.mcp,at=t.metering??A.metering,Xe=t.billingMode??A.billingMode,ze=t.idp??A.idp,I=Do({cronJobs:t.cronJobs,auditLog:t.auditLog,apiKeys:t.apiKeys,commandPalette:t.commandPalette,cookieConsent:t.cookieConsent,legalPages:t.legalPages,chinaCompliance:t.chinaCompliance},h),Je=un([{flag:"queue",provider:$e},{flag:"search",provider:Ye},{flag:"notifications",provider:qe},{flag:"webhooks",provider:Ge},{flag:"feature-flags",provider:We},{flag:"captcha",provider:He}]);function Ft(){for(let g of Je)if(n)p(!0,{event:"warn",step:g.flag,provider:g.provider,packageStatus:g.status,message:se(g.status)});else{let S=Qe(g.status);process.stdout.write(C.yellow(`\u26A0 ${g.flag}=${g.provider} ${S} \u2014 ${se(g.status)}
|
|
2943
|
+
`))}}let Ee={region:h,orm:nt,database:Q,payment:ot,aiMode:rt,aiRouting:Mt,aiProviders:he,customAiEndpoint:Fe,deployTarget:Z,docs:B,i18n:vt,email:De,storage:je,monitoring:Ke,analytics:Ve,sms:Be,queue:$e,search:Ye,cache:it,notifications:qe,webhooks:Ge,cms:st,featureFlags:We,captcha:He,mcp:_t,metering:at,billingMode:Xe,idp:ze,cronJobs:I.cronJobs,auditLog:I.auditLog,apiKeys:I.apiKeys,commandPalette:I.commandPalette,cookieConsent:I.cookieConsent,legalPages:I.legalPages,chinaCompliance:I.chinaCompliance},bt=[["Project name",l],["Region",h],["Auth",F],["Social login",G.length>0?G.map(g=>ct.find(S=>S.id===g)?.name??g).join(", "):"none"],["ORM",nt],["Database",Q],["Payment",V],["AI topology",`${rt}${he.length>0?` (${he.join(", ")} seed)`:""}${Fe?" + custom endpoint":""}`],["Email",De],["Storage",je],["Monitoring",Ke],["Analytics",Ve],["SMS",Be],["Deploy Target",Z],["Docs Framework",B]];n?bt.forEach(([g,S],T)=>{p(!0,{event:"step",step:g,value:S,index:T+1,total:bt.length})}):bt.forEach(([g,S],T)=>{yn({index:T+1,total:bt.length,label:g,value:S})});let tr={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},pn=Date.now();if(r){let g=he.length,S=[`clone template \u2192 ${a}`,"write nebutra.config.json",`prune template (orm=${nt}, i18n=${vt})`,`region \u2192 ${h}`,`auth \u2192 ${F==="none"?"skip (remove packages/auth)":`configure ${F}`}`,...G.length>0?[`social-login \u2192 generate ${G.length} callback route${G.length===1?"":"s"} + SocialLoginButtons.tsx (${G.join(", ")})`]:[],`db \u2192 ${Q==="none"?"skip (remove packages/db)":`configure Prisma for ${Q}`}`,`payment \u2192 ${V==="none"?"skip (remove packages/billing)":`configure ${V}`}`,...B!=="none"?[`docs \u2192 scaffold apps/docs (${B==="fumadocs"?"fumadocs":`${B} \u2192 fumadocs fallback`})`]:[],...g>0||Fe?[`ai-providers \u2192 generate ${rt} registry seed + env (${g}${Fe?" + custom":""} provider${g===1&&!Fe?"":"s"})`]:[],...De!=="none"?[`email \u2192 configure ${De}`]:[],...je!=="none"?[`storage \u2192 configure ${je}`]:[],...Ke!=="none"?[`monitoring \u2192 configure ${Ke}`]:[],...Ve!=="none"?[`analytics \u2192 configure ${Ve}`]:[],...Be!=="none"?[`sms \u2192 configure ${Be}`]:[],...$e!=="none"?[`queue \u2192 configure ${$e}`]:[],...Ye!=="none"?[`search \u2192 configure ${Ye}`]:[],...it!=="none"?[`cache \u2192 configure ${it}`]:[],...qe!=="none"?[`notifications \u2192 configure ${qe}`]:[],...Ge!=="none"?[`webhooks \u2192 configure ${Ge}`]:[],...st!=="none"?[`cms \u2192 configure ${st}`]:[],...We!=="none"?[`feature-flags \u2192 configure ${We}`]:[],...He!=="none"?[`captcha \u2192 configure ${He}`]:[],`mcp \u2192 ${_t==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${at==="off"?"disabled":at==="auto"?ot!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...Xe!=="usage"?[`billing-mode \u2192 ${Xe}`]:[],...ze!=="clerk"?[`idp \u2192 ${ze}`]:[],`cron-jobs \u2192 ${I.cronJobs?"enabled":"disabled"}`,`audit-log \u2192 ${I.auditLog?"enabled":"disabled"}`,`api-keys \u2192 ${I.apiKeys?"enabled":"disabled"}`,`command-palette \u2192 ${I.commandPalette?"enabled":"disabled"}`,`cookie-consent \u2192 ${I.cookieConsent?"enabled":"disabled"}`,`legal-pages \u2192 ${I.legalPages?"enabled":"disabled"}`,`china-compliance \u2192 ${I.chinaCompliance?"enabled (@nebutra/china-compliance + ICP footer)":"disabled"}`,`compliance \u2192 inject ${h} boilerplate (ICP/Cookie/AIGC/Privacy)`,"welcome \u2192 generate dev welcome page","env \u2192 generate random secrets (AUTH_SECRET, JWT_SECRET)","seed \u2192 generate prisma/seed.ts (1 admin + 3 tenants)",...Z!=="none"?[`deploy \u2192 inject ${Z} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${m} install`,t.git===!1?"skip git init":"run git init"];if(n){for(let T of S)p(!0,{event:"plan",action:T});Ft(),p(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
|
|
2944
2944
|
`+C.bold(`Dry run \u2014 planned actions:
|
|
2945
|
-
`));for(let
|
|
2946
|
-
`);
|
|
2945
|
+
`));for(let T of S)process.stdout.write(` \u2022 ${T}
|
|
2946
|
+
`);Je.length>0&&(process.stdout.write(`
|
|
2947
2947
|
`+C.bold(C.yellow(`Preview-status providers selected:
|
|
2948
2948
|
`))),Ft()),process.stdout.write(C.dim(`
|
|
2949
2949
|
No files were written.
|
|
2950
|
-
`))}process.exit(0)}let
|
|
2950
|
+
`))}process.exit(0)}let nr=async()=>{process.stdout.write(`
|
|
2951
2951
|
`+C.red(`\u2718 Cancelled
|
|
2952
2952
|
`)),Se.existsSync(a)&&await k.confirm({message:`Cleanup partial install at ${a}?`,initialValue:!0})===!0&&(Se.rmSync(a,{recursive:!0,force:!0}),process.stdout.write(C.dim(` \u2713 Removed ${a}
|
|
2953
|
-
`))),process.exit(130)};process.on("SIGINT",
|
|
2954
|
-
`));try{
|
|
2955
|
-
`))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{
|
|
2956
|
-
`))}}else p(n,{event:"step",step:"git-init",status:"skip"});let
|
|
2953
|
+
`))),process.exit(130)};process.on("SIGINT",nr);try{p(n,{event:"step",step:"clone",status:"start"}),await so(a),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await yo(a,l),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await Un(a,Ee),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await Io(a,Ee),p(n,{event:"step",step:"prune",status:"ok"});let g=ht.join(a,"packages/platform/db/prisma/schema.prisma");if(Se.existsSync(g)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let v=Se.readFileSync(g,"utf-8"),_=tn(v,{auth:F,payment:V,"billing-mode":Xe,idp:ze,template:"saas"});Se.writeFileSync(g,_),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(v){let _=v instanceof Error?v.message:String(v);p(n,{event:"step",step:"schema-prune",status:"error",error:_})}}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"auth",choice:F,status:"start"}),await _n(a,F),p(n,{event:"step",step:"auth",choice:F,status:"ok"}),G.length>0?(p(n,{event:"step",step:"social-login",providers:G,status:"start"}),await In(a,G,F),p(n,{event:"step",step:"social-login",providers:G,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:Q,status:"start"}),await Fn(a,Q,l),p(n,{event:"step",step:"db",choice:Q,status:"ok"}),p(n,{event:"step",step:"payment",choice:V,status:"start"}),await ho(a,V),p(n,{event:"step",step:"payment",choice:V,status:"ok"}),await Gn(a,De,h),n&&p(!0,{event:"step",step:"email",choice:De,status:"ok"}),await Fo(a,je,h),n&&p(!0,{event:"step",step:"storage",choice:je,status:"ok"}),await mo(a,Ke,h),n&&p(!0,{event:"step",step:"monitoring",choice:Ke,status:"ok"}),await En(a,Ve,h),n&&p(!0,{event:"step",step:"analytics",choice:Ve,status:"ok"}),await Lo(a,Be,h),n&&p(!0,{event:"step",step:"sms",choice:Be,status:"ok"}),await ko(a,$e,h),n&&p(!0,{event:"step",step:"queue",choice:$e,status:"ok"}),await To(a,Ye,h),n&&p(!0,{event:"step",step:"search",choice:Ye,status:"ok"}),await Rn(a,it,h),n&&p(!0,{event:"step",step:"cache",choice:it,status:"ok"}),await fo(a,qe,h),n&&p(!0,{event:"step",step:"notifications",choice:qe,status:"ok"}),await Ko(a,Ge,h),n&&p(!0,{event:"step",step:"webhooks",choice:Ge,status:"ok"}),await Tn(a,st,h),n&&p(!0,{event:"step",step:"cms",choice:st,status:"ok"}),await Zn(a,We,h),n&&p(!0,{event:"step",step:"feature-flags",choice:We,status:"ok"}),await xn(a,He,h),n&&p(!0,{event:"step",step:"captcha",choice:He,status:"ok"}),await ao(a,_t),n&&p(!0,{event:"step",step:"mcp",mode:_t,status:"ok"}),await po(a,at,ot),n&&p(!0,{event:"step",step:"metering",mode:at,status:"ok"}),p(n,{event:"step",step:"prune-wave-features",status:"start"}),Ao(a,I),p(n,{event:"step",step:"prune-wave-features",status:"ok",toggles:I}),Ee.orm==="prisma"&&Ee.database!=="none"){let v=ht.join(a,"packages/platform/db/prisma/schema.prisma");if(Se.existsSync(v)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let _=Se.readFileSync(v,"utf8"),ee=tn(_,{auth:F,payment:V,"billing-mode":Xe,idp:ze,template:"saas"});Se.writeFileSync(v,ee),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(_){let ee=_ instanceof Error?_.message:String(_);p(n,{event:"step",step:"schema-prune",status:"error",error:ee})}}else p(n,{event:"step",step:"schema-prune",status:"skip"})}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"billing-mode",choice:Xe,status:"ok"}),p(n,{event:"step",step:"idp",choice:ze,status:"ok"}),await On(a,h),n&&p(!0,{event:"step",step:"compliance",region:h,status:"ok"}),await Jn(a),await Oo(a,F),await Vo(a,{projectName:l,region:h,previewSelections:Je,waveFeatures:I}),Ee.aiMode!=="none"){p(n,{event:"step",step:"ai-providers",status:"start"});let v={providerIds:Ee.aiProviders,customEndpoint:Ee.customAiEndpoint},_=ht.join(a,"packages/ai/ai-providers/templates");await Po(a,v,_),p(n,{event:"step",step:"ai-providers",status:"ok"})}else p(n,{event:"step",step:"ai-providers",status:"skip"});if(p(n,{event:"step",step:"docs",status:"start"}),B!=="none"?(await Bn(a,{framework:B,projectName:l}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:B,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),Z!=="none"&&await jn(a,Z),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await Hn(a,tr),p(n,{event:"step",step:"env",status:"ok"}),t.install!==!1){let v=m==="bun"?"bun install":`${m} install`;n?p(!0,{event:"step",step:"install",pm:m,status:"start"}):process.stdout.write(C.dim(` Installing dependencies with ${m}\u2026
|
|
2954
|
+
`));try{St(v,{cwd:a,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(_){let ee=_ instanceof Error?_.message:String(_);n?p(!0,{event:"step",step:"install",status:"error",error:ee}):process.stdout.write(C.yellow(` \u26A0 install failed \u2014 run '${v}' manually.
|
|
2955
|
+
`))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{St("git init -q",{cwd:a,stdio:"ignore"}),St("git add -A",{cwd:a,stdio:"ignore"}),St('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:a,stdio:"ignore"}),p(n,{event:"step",step:"git-init",status:"ok"})}catch(v){let _=v instanceof Error?v.message:String(v);n?p(!0,{event:"step",step:"git-init",status:"error",error:_}):process.stdout.write(C.yellow(` \u26A0 git init skipped \u2014 not fatal.
|
|
2956
|
+
`))}}else p(n,{event:"step",step:"git-init",status:"skip"});let ve=Math.max(1,Math.round((Date.now()-pn)/1e3));vn({template_version:ie,package_manager:m,region:h,auth:F,payment:V,ai_providers:he,deploy_target:Z,duration_ms:Date.now()-pn}),Je.length>0&&Ft(),n?p(!0,{event:"done",status:"ok",elapsedSec:ve,targetDir:a,previewSelections:Je,waveFeatures:I}):mn({elapsedSec:ve,targetDir:a,skippedInstall:t.install===!1,previewSelections:Je,waveFeatures:I});try{ta({pkg:{name:Bo,version:ie},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(g){let S=g instanceof Error?g.message:String(g);n?p(!0,{event:"error",message:S}):process.stdout.write(C.red(`
|
|
2957
2957
|
\u2718 Failed: ${S}
|
|
2958
|
-
`)),process.exit(1)}}
|
|
2958
|
+
`)),process.exit(1)}}sa().catch(e=>{process.stderr.write(String(e)+`
|
|
2959
2959
|
`),process.exit(1)});
|