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