create-sailor 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{execSync as
|
|
3
|
-
`));return}
|
|
2
|
+
import{execSync as Rt}from"child_process";import _e from"fs";import de from"path";import*as O from"@clack/prompts";import{Command as Za}from"commander";import A from"picocolors";import ec from"update-notifier";import Ur from"cfonts";import Mr from"picocolors";import vn from"fs";import en from"path";import{fileURLToPath as Or}from"url";function Lr(){try{let t=en.dirname(Or(import.meta.url));for(let o=0;o<4;o++){let n=en.join(t,"package.json");if(vn.existsSync(n)){let r=vn.readFileSync(n,"utf-8"),s=JSON.parse(r);if(s.name==="create-sailor"&&typeof s.version=="string")return s.version}t=en.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ae=Lr();function _n(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ae}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
|
|
3
|
+
`));return}Ur.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(Mr.dim(` AI-Native SaaS Template \xB7 v${ae} \xB7 nebutra.com
|
|
4
4
|
|
|
5
|
-
`))}import P from"picocolors";var
|
|
5
|
+
`))}import P from"picocolors";var Dr={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",invite:"foundation"};function Fr(e){return e?Dr[e]??"stable":"stable"}function rt(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function me(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 bn(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=Fr(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function jr(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Pn(e){let t=jr(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",s=t?"\u{1F4E7}":"*",c=["",` ${t?P.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?P.bold("Next:"):"Next:"}`,` ${n} cd ${e.targetDir}`];e.skippedInstall&&c.push(` ${n} pnpm install (if --no-install was set)`),c.push(` ${n} fill in .env.local ${t?P.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?P.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?P.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?P.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?P.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?P.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?P.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?P.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?P.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?P.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?P.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?P.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`,` ${n} pnpm audit ${t?P.dim("\u2192 scan deps for known CVEs"):"-> scan deps for known CVEs"}`);let a=e.previewSelections??[];if(a.length>0){let C=t?P.bold(P.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${C}`);for(let k of a){let $=rt(k.status),ue=` ${n} ${k.flag} (${k.provider}) ${$}`;c.push(t?P.yellow(ue):ue)}c.push("",` ${t?P.dim(me("foundation")):me("foundation")}`,` ${t?P.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?P.dim("See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"):"See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"}`)}let l=e.waveFeatures??{},d=C=>C!==!1,S=[];d(l.apiKeys)&&S.push("Manage API keys at /settings/api-keys"),d(l.auditLog)&&S.push("View audit log at /settings/audit-log"),S.push("Configure webhooks at /settings/webhooks"),d(l.commandPalette)&&S.push("Press Cmd/Ctrl+K to open the command palette"),S.push("Edit notification preferences at /settings/notifications"),S.push("Export your data at /settings/account/export"),l.chinaCompliance&&S.push("China deployments \u2014 see packages/ops/china-compliance/README.md"),c.push("",` ${t?P.bold("What you can do next:"):"What you can do next:"}`);for(let C of S)c.push(` ${n} ${C}`);c.push("",` ${t?P.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 Vr=`Usage: create-sailor [name] [options]
|
|
8
8
|
|
|
9
9
|
Arguments:
|
|
10
10
|
name project directory (default: ./my-saas-app)
|
|
@@ -12,7 +12,7 @@ Arguments:
|
|
|
12
12
|
Core options:
|
|
13
13
|
-p, --pm <id> npm | pnpm | yarn | bun (auto-detected)
|
|
14
14
|
--region <id> global | cn | hybrid (default: global)
|
|
15
|
-
--auth <id> clerk | betterauth | none
|
|
15
|
+
--auth <id> clerk | betterauth | nextauth | supabase | none
|
|
16
16
|
--ai <ids> expert/non-interactive provider seed (e.g. openai,anthropic)
|
|
17
17
|
|
|
18
18
|
Interactive AI topology:
|
|
@@ -45,6 +45,7 @@ Feature flags (region-based smart defaults):
|
|
|
45
45
|
--captcha <id> turnstile | hcaptcha | aliyun-slide | none [WIP]
|
|
46
46
|
--billing-mode <mode> usage | seat | credits (default: usage)
|
|
47
47
|
--idp <id> clerk | oauth-server (default: clerk)
|
|
48
|
+
--access-gate <mode> none | invite (default: none)
|
|
48
49
|
|
|
49
50
|
Preview statuses:
|
|
50
51
|
[Foundation] \u2014 types + factory complete; adapters need external credentials & may not work out-of-the-box
|
|
@@ -73,9 +74,9 @@ Examples:
|
|
|
73
74
|
$ npx create-sailor@latest my-app --region=cn --auth=clerk
|
|
74
75
|
$ npx create-sailor@latest my-app --region=hybrid --ai=openai,deepseek
|
|
75
76
|
$ npm create sailor@latest --dry-run --region=cn
|
|
76
|
-
`;function
|
|
77
|
-
`)}var Xt=[{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:[]}],Za=Xt.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var xr=["openai","anthropic","google"],Tr=["openai"];function zt(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...xr];return{mode:"gateway",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:o,runtimeGovernance:!0}}}case"direct":{let o=t.length>0?t:[...Tr];return{mode:"direct",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:o,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}import nt from"fs";import V from"path";var bn=[{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:""}],nc=bn.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Pn(e){return bn.find(t=>t.id===e)}function Nr(e){nt.mkdirSync(e,{recursive:!0})}function z(e,t){Nr(V.dirname(e)),nt.writeFileSync(e,t)}function _e(e,t){let o=V.join(e,".env.example");nt.existsSync(o)?nt.appendFileSync(o,`
|
|
78
|
-
`+t):
|
|
77
|
+
`;function An(){process.stdout.write(Vr)}import Lt from"picocolors";function Cn(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Br(e){let t=Cn()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return Cn()?`${Lt.dim(o)} ${Lt.bold(n)} ${Lt.dim(t)} ${Lt.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function In(e){process.stdout.write(Br(e)+`
|
|
78
|
+
`)}var tn=[{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:[]}],_c=tn.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var Kr=["openai","anthropic","google"],$r=["openai"];function nn(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...Kr];return{mode:"gateway",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:o,runtimeGovernance:!0}}}case"direct":{let o=t.length>0?t:[...$r];return{mode:"direct",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:o,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}import st from"fs";import V from"path";var wn=[{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:""}],Ac=wn.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Rn(e){return wn.find(t=>t.id===e)}function Yr(e){st.mkdirSync(e,{recursive:!0})}function Z(e,t){Yr(V.dirname(e)),st.writeFileSync(e,t)}function Ce(e,t){let o=V.join(e,".env.example");st.existsSync(o)?st.appendFileSync(o,`
|
|
79
|
+
`+t):st.writeFileSync(o,t)}function qr(e){let t=`"use client";
|
|
79
80
|
/**
|
|
80
81
|
* PostHog browser SDK \u2014 lazy-initialized on first access.
|
|
81
82
|
*/
|
|
@@ -158,11 +159,11 @@ export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
|
|
|
158
159
|
|
|
159
160
|
return <>{children}</>;
|
|
160
161
|
}
|
|
161
|
-
`;
|
|
162
|
+
`;Z(V.join(e,"src","lib","analytics","posthog.client.ts"),t),Z(V.join(e,"src","lib","analytics","posthog.server.ts"),o),Z(V.join(e,"src","components","analytics","AnalyticsProvider.tsx"),n)}function Gr(){return`# PostHog \u2014 product analytics
|
|
162
163
|
POSTHOG_KEY=
|
|
163
164
|
NEXT_PUBLIC_POSTHOG_KEY=
|
|
164
165
|
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
|
165
|
-
`}function
|
|
166
|
+
`}function Hr(e){Z(V.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
|
|
166
167
|
/**
|
|
167
168
|
* Plausible script tag \u2014 lightweight, privacy-friendly analytics.
|
|
168
169
|
*/
|
|
@@ -182,10 +183,10 @@ export function PlausibleScript() {
|
|
|
182
183
|
/>
|
|
183
184
|
);
|
|
184
185
|
}
|
|
185
|
-
`)}function
|
|
186
|
+
`)}function Wr(){return`# Plausible \u2014 privacy-friendly analytics
|
|
186
187
|
NEXT_PUBLIC_PLAUSIBLE_DOMAIN=
|
|
187
188
|
NEXT_PUBLIC_PLAUSIBLE_SRC=https://plausible.io/js/script.js
|
|
188
|
-
`}function
|
|
189
|
+
`}function Xr(e){Z(V.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
|
|
189
190
|
/**
|
|
190
191
|
* Umami analytics \u2014 self-hosted OR umami.is cloud.
|
|
191
192
|
*/
|
|
@@ -205,10 +206,10 @@ export function UmamiScript() {
|
|
|
205
206
|
/>
|
|
206
207
|
);
|
|
207
208
|
}
|
|
208
|
-
`)}function
|
|
209
|
+
`)}function zr(){return`# Umami \u2014 self-hostable analytics
|
|
209
210
|
NEXT_PUBLIC_UMAMI_WEBSITE_ID=
|
|
210
211
|
NEXT_PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
|
|
211
|
-
`}function
|
|
212
|
+
`}function Jr(e){let t=`"use client";
|
|
212
213
|
import mixpanel from "mixpanel-browser";
|
|
213
214
|
|
|
214
215
|
let initialized = false;
|
|
@@ -247,10 +248,10 @@ export function trackServer(
|
|
|
247
248
|
if (!c) return;
|
|
248
249
|
c.track(event, { distinct_id: distinctId, ...properties });
|
|
249
250
|
}
|
|
250
|
-
`;
|
|
251
|
+
`;Z(V.join(e,"src","lib","analytics","mixpanel.client.ts"),t),Z(V.join(e,"src","lib","analytics","mixpanel.server.ts"),o)}function Qr(){return`# Mixpanel \u2014 product analytics
|
|
251
252
|
MIXPANEL_TOKEN=
|
|
252
253
|
NEXT_PUBLIC_MIXPANEL_TOKEN=
|
|
253
|
-
`}function
|
|
254
|
+
`}function Zr(e){Z(V.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
|
|
254
255
|
/**
|
|
255
256
|
* \u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji \u2014 hm.js \u57CB\u70B9\u811A\u672C.
|
|
256
257
|
*/
|
|
@@ -276,9 +277,9 @@ var _hmt = _hmt || [];
|
|
|
276
277
|
/>
|
|
277
278
|
);
|
|
278
279
|
}
|
|
279
|
-
`)}function
|
|
280
|
+
`)}function es(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
|
|
280
281
|
NEXT_PUBLIC_BAIDU_STATS_ID=
|
|
281
|
-
`}function
|
|
282
|
+
`}function ts(e){Z(V.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
|
|
282
283
|
/**
|
|
283
284
|
* \u795E\u7B56\u5206\u6790 (Sensors Analytics) \u2014 sa-sdk-javascript \u5C01\u88C5.
|
|
284
285
|
*/
|
|
@@ -306,10 +307,10 @@ export function initSensors(): void {
|
|
|
306
307
|
}
|
|
307
308
|
|
|
308
309
|
export { sensors };
|
|
309
|
-
`)}function
|
|
310
|
+
`)}function ns(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
|
|
310
311
|
NEXT_PUBLIC_SENSORS_SERVER_URL=
|
|
311
312
|
NEXT_PUBLIC_SENSORS_APP_JS_URL=
|
|
312
|
-
`}function
|
|
313
|
+
`}function os(e){Z(V.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
|
|
313
314
|
/**
|
|
314
315
|
* GrowingIO CDP \u2014 inline snippet installer.
|
|
315
316
|
*/
|
|
@@ -334,21 +335,21 @@ gdp("send");
|
|
|
334
335
|
/>
|
|
335
336
|
);
|
|
336
337
|
}
|
|
337
|
-
`)}function
|
|
338
|
+
`)}function rs(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
|
|
338
339
|
NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
|
|
339
|
-
`}async function
|
|
340
|
-
`+t):
|
|
341
|
-
`+t)}async function
|
|
340
|
+
`}async function kn(e,t,o="global"){let n=Rn(t);if(!n||n.id==="none")return;let r=V.join(e,"apps","web");if(!st.existsSync(r))return;let s=n.id;try{switch(s){case"posthog":qr(r),Ce(e,Gr());return;case"plausible":Hr(r),Ce(e,Wr());return;case"umami":Xr(r),Ce(e,zr());return;case"mixpanel":Jr(r),Ce(e,Qr());return;case"baidu":Zr(r),Ce(e,es());return;case"sensors":ts(r),Ce(e,ns());return;case"growingio":os(r),Ce(e,rs());return;default:return}}catch(i){throw console.error(`Failed to apply analytics selection "${t}":`,i),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var ss="https://analytics.nebutra.com";function is(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function xn(e,t={}){is(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??ss},onError:()=>{}});if(typeof n?.track!="function")return;let r=n.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import q from"fs";import x from"path";function B(e){q.existsSync(e)&&q.rmSync(e,{recursive:!0,force:!0})}function Ut(e,t){let o=x.join(e,".env.example");q.existsSync(o)?q.appendFileSync(o,`
|
|
341
|
+
`+t):q.writeFileSync(o,t)}function Mt(e,t){if(!q.existsSync(e))return;let o=q.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*(?:"[^"]+"\s*\|\s*)+"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&q.writeFileSync(e,n)}function as(e,t){let o=x.join(e,"README.md");if(!q.existsSync(o)){q.writeFileSync(o,t);return}q.appendFileSync(o,`
|
|
342
|
+
`+t)}async function Nn(e,t){let o=x.join(e,"packages","iam","auth");if(!q.existsSync(o))return;if(t==="none"){B(o),as(e,`
|
|
342
343
|
## Auth
|
|
343
344
|
|
|
344
|
-
Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth).
|
|
345
|
-
`);return}let n=
|
|
345
|
+
Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth, Supabase).
|
|
346
|
+
`);return}let n=x.join(o,"src","providers"),r=x.join(o,"src","types.ts");if(t==="clerk"){B(x.join(n,"better-auth.ts")),B(x.join(n,"nextauth.ts")),B(x.join(n,"supabase.ts")),Mt(r,"clerk"),Ut(e,`# Clerk auth
|
|
346
347
|
CLERK_PUBLISHABLE_KEY=
|
|
347
348
|
CLERK_SECRET_KEY=
|
|
348
|
-
`);return}if(t==="betterauth"){
|
|
349
|
+
`);return}if(t==="betterauth"){B(x.join(n,"clerk.ts")),B(x.join(n,"nextauth.ts")),B(x.join(n,"supabase.ts")),Mt(r,"better-auth"),Ut(e,`# Better Auth
|
|
349
350
|
BETTER_AUTH_SECRET=
|
|
350
351
|
BETTER_AUTH_URL=http://localhost:3000
|
|
351
|
-
`);return}if(t==="nextauth"){
|
|
352
|
+
`);return}if(t==="nextauth"){B(x.join(n,"clerk.ts")),B(x.join(n,"better-auth.ts")),B(x.join(n,"supabase.ts")),Mt(r,"nextauth"),Ut(e,`# NextAuth (Auth.js v5)
|
|
352
353
|
AUTH_SECRET=
|
|
353
354
|
NEXTAUTH_URL=http://localhost:3000
|
|
354
355
|
# OAuth (optional \u2014 leave blank to disable that provider)
|
|
@@ -356,7 +357,13 @@ GOOGLE_CLIENT_ID=
|
|
|
356
357
|
GOOGLE_CLIENT_SECRET=
|
|
357
358
|
GITHUB_CLIENT_ID=
|
|
358
359
|
GITHUB_CLIENT_SECRET=
|
|
359
|
-
`);return}
|
|
360
|
+
`);return}if(t==="supabase"){B(x.join(n,"clerk.ts")),B(x.join(n,"better-auth.ts")),B(x.join(n,"nextauth.ts")),Mt(r,"supabase"),Ut(e,`# Supabase Auth
|
|
361
|
+
NEXT_PUBLIC_SUPABASE_URL=
|
|
362
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=
|
|
363
|
+
SUPABASE_URL=
|
|
364
|
+
SUPABASE_ANON_KEY=
|
|
365
|
+
SUPABASE_SERVICE_ROLE_KEY=
|
|
366
|
+
`);return}}var Et=[{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"}],cs=new Set(Et.map(e=>e.id));function Tn(e){return Et.find(t=>t.id===e)}function On(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)cs.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import we from"fs";import Ie from"path";function ps(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
|
|
360
367
|
// Generated by create-sailor \u2014 OAuth callback for ${e.name}
|
|
361
368
|
// Primary auth provider: ${t}
|
|
362
369
|
// Docs: ${e.docs}`,n={wechat:` const tokenRes = await fetch(
|
|
@@ -481,7 +488,7 @@ ${n[e.id]}
|
|
|
481
488
|
void state;
|
|
482
489
|
return NextResponse.redirect(new URL("/dashboard", req.url));
|
|
483
490
|
}
|
|
484
|
-
`}function
|
|
491
|
+
`}function ls(e){return`"use client";
|
|
485
492
|
|
|
486
493
|
/**
|
|
487
494
|
* SocialLoginButtons \u2014 generated by create-sailor.
|
|
@@ -524,23 +531,23 @@ export function SocialLoginButtons() {
|
|
|
524
531
|
</div>
|
|
525
532
|
);
|
|
526
533
|
}
|
|
527
|
-
`}function
|
|
528
|
-
`+t):
|
|
534
|
+
`}function Ln(e){we.mkdirSync(e,{recursive:!0})}function ds(e,t){let o=Ie.join(e,".env.example");we.existsSync(o)?we.appendFileSync(o,`
|
|
535
|
+
`+t):we.writeFileSync(o,t)}function us(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
529
536
|
`);return`${t}
|
|
530
537
|
${o}
|
|
531
|
-
`}async function
|
|
532
|
-
`);
|
|
538
|
+
`}async function Un(e,t,o){if(!t||t.length===0)return;let n=Ie.join(e,"apps","web");if(!we.existsSync(n))return;let r=new Set,s=[];for(let l of t){if(r.has(l))continue;r.add(l);let d=Tn(l);d&&s.push(d)}if(s.length===0)return;for(let l of s)ds(e,us(l));let i=Ie.join(n,"src","app","api","auth","callback");for(let l of s){let d=Ie.join(i,l.id);Ln(d);let S=Ie.join(d,"route.ts");we.writeFileSync(S,ps(l,o))}let c=Ie.join(n,"src","components","auth");Ln(c);let a=Ie.join(c,"SocialLoginButtons.tsx");we.writeFileSync(a,ls(s))}import it from"fs";import Dn from"path";var Dt=[{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 Mn(e){return Dt.find(t=>t.id===e)}var jc=Dt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import ee from"fs";import Ft from"path";function te(e,t){let o=Ft.join(e,".env.example");if(!ee.existsSync(o)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(ee.readFileSync(o,"utf-8").includes(r))return;let c=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].filter(a=>a!==null).join(`
|
|
539
|
+
`);ee.appendFileSync(o,c)}function ne(e,t,o){let n=Ft.join(e,".env.example");if(!ee.existsSync(n))return;let r=ee.readFileSync(n,"utf-8"),s=`${t}="${o}"`,i=new RegExp(`^${t}=.*$`,"m");if(i.test(r)){ee.writeFileSync(n,r.replace(i,s));return}let c=r.endsWith(`
|
|
533
540
|
`)?"":`
|
|
534
|
-
`;
|
|
535
|
-
`)}var
|
|
536
|
-
`);
|
|
537
|
-
`)}async function
|
|
538
|
-
`)[0]??""))return;
|
|
541
|
+
`;ee.appendFileSync(n,`${c}${s}
|
|
542
|
+
`)}var ms=["design","iam","commerce","integrations","platform","ops","ai"];function Re(e,t){for(let n of ms){let r=Ft.join(e,"packages",n,t);if(ee.existsSync(r))return r}let o=Ft.join(e,"packages",t);return ee.existsSync(o)?o:null}function X(e,t){let o=Re(e,t);o&&ee.rmSync(o,{recursive:!0,force:!0})}function Fn(e){return it.existsSync(e)?it.readFileSync(e,"utf-8"):null}function gs(e,t){let o=Dn.join(e,".env.example"),n=Fn(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
|
|
543
|
+
`);it.appendFileSync(o,s)}function fs(e,t,o){let n=Dn.join(e,".env.example"),r=Fn(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?it.writeFileSync(n,r.replace(s,`${t}="${o}"`)):it.appendFileSync(n,`${t}="${o}"
|
|
544
|
+
`)}async function jn(e,t,o){let n=Re(e,"cache");if(t==="none"){n&&it.rmSync(n,{recursive:!0,force:!0});return}let r=Mn(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${Dt.map(s=>s.id).join(", ")}`);n&&(gs(e,r),fs(e,"CACHE_PROVIDER",t))}var jt=[{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 Vn(e){return jt.find(t=>t.id===e)}var Xc=jt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Bn(e,t,o="global"){let n=Vn(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${jt.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"captcha");return}n.envVars.length>0&&te(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"CAPTCHA_PROVIDER",n.id)}import Bt from"fs";import ys from"path";var Vt=[{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 Kn(e){return Vt.find(t=>t.id===e)}var ep=Vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function $n(e,t,o="global"){let n=Kn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${Vt.map(s=>s.id).join(", ")}`);let r=ys.join(e,"apps","studio");if(n.id==="none"){X(e,"sanity"),Bt.existsSync(r)&&Bt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(X(e,"sanity"),Bt.existsSync(r)&&Bt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&te(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"CMS_PROVIDER",n.id)}import T from"fs";import N from"path";var Ss=N.join("apps","web"),on=N.join("src","components","compliance"),vt=N.join("src","app","[locale]");function oe(e){return N.join(e,Ss)}function hs(e){T.mkdirSync(e,{recursive:!0})}function z(e,t){hs(N.dirname(e)),T.writeFileSync(e,t,"utf8")}function rn(e,t){let o=N.join(e,".env.example");if(T.existsSync(o)){if(T.readFileSync(o,"utf8").includes(t.split(`
|
|
545
|
+
`)[0]??""))return;T.appendFileSync(o,`
|
|
539
546
|
`+t+`
|
|
540
|
-
`)}else
|
|
541
|
-
`)}var
|
|
547
|
+
`)}else T.writeFileSync(o,t+`
|
|
548
|
+
`)}var _t=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
|
|
542
549
|
> Consult a qualified lawyer in every jurisdiction you operate in before publishing.
|
|
543
|
-
> \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,
|
|
550
|
+
> \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`,Es=`import Link from "next/link";
|
|
544
551
|
import { IcpFooter } from "@/components/compliance/IcpFooter";
|
|
545
552
|
import { PublicSecurityFooter } from "@/components/compliance/PublicSecurityFooter";
|
|
546
553
|
|
|
@@ -591,7 +598,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
591
598
|
</footer>
|
|
592
599
|
);
|
|
593
600
|
}
|
|
594
|
-
`,
|
|
601
|
+
`,vs=`export function IcpFooter() {
|
|
595
602
|
const icp = process.env.NEXT_PUBLIC_ICP_BEIAN;
|
|
596
603
|
if (!icp) return null;
|
|
597
604
|
return (
|
|
@@ -605,7 +612,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
605
612
|
</a>
|
|
606
613
|
);
|
|
607
614
|
}
|
|
608
|
-
`,
|
|
615
|
+
`,_s=`export function PublicSecurityFooter() {
|
|
609
616
|
const psb = process.env.NEXT_PUBLIC_PSB_BEIAN;
|
|
610
617
|
const psbCode = process.env.NEXT_PUBLIC_PSB_CODE;
|
|
611
618
|
if (!psb) return null;
|
|
@@ -622,7 +629,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
622
629
|
</a>
|
|
623
630
|
);
|
|
624
631
|
}
|
|
625
|
-
`,
|
|
632
|
+
`,bs=`"use client";
|
|
626
633
|
|
|
627
634
|
import { useCallback, useEffect, useState } from "react";
|
|
628
635
|
|
|
@@ -786,7 +793,7 @@ export function CookieBanner() {
|
|
|
786
793
|
<button
|
|
787
794
|
type="button"
|
|
788
795
|
onClick={saveCustom}
|
|
789
|
-
className="rounded-md bg-[var(--
|
|
796
|
+
className="rounded-md border border-[var(--neutral-12)] bg-[var(--neutral-12)] px-4 py-2 text-sm font-medium text-[var(--neutral-1)] shadow-sm hover:bg-[var(--neutral-11)]"
|
|
790
797
|
>
|
|
791
798
|
Save Preferences / \u4FDD\u5B58\u504F\u597D
|
|
792
799
|
</button>
|
|
@@ -809,7 +816,7 @@ export function CookieBanner() {
|
|
|
809
816
|
<button
|
|
810
817
|
type="button"
|
|
811
818
|
onClick={acceptAll}
|
|
812
|
-
className="rounded-md bg-[var(--
|
|
819
|
+
className="rounded-md border border-[var(--neutral-12)] bg-[var(--neutral-12)] px-4 py-2 text-sm font-medium text-[var(--neutral-1)] shadow-sm hover:bg-[var(--neutral-11)]"
|
|
813
820
|
>
|
|
814
821
|
Accept All / \u5168\u90E8\u63A5\u53D7
|
|
815
822
|
</button>
|
|
@@ -849,7 +856,7 @@ function CategoryRow({ id, title, description, checked, disabled, onChange }: Ca
|
|
|
849
856
|
</label>
|
|
850
857
|
);
|
|
851
858
|
}
|
|
852
|
-
`,
|
|
859
|
+
`,Ps=`interface AigcDisclaimerProps {
|
|
853
860
|
className?: string;
|
|
854
861
|
}
|
|
855
862
|
|
|
@@ -869,13 +876,13 @@ export function AigcDisclaimer({ className }: AigcDisclaimerProps) {
|
|
|
869
876
|
</div>
|
|
870
877
|
);
|
|
871
878
|
}
|
|
872
|
-
`,
|
|
879
|
+
`,As=`---
|
|
873
880
|
title: Privacy Policy / \u9690\u79C1\u653F\u7B56
|
|
874
881
|
description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal information.
|
|
875
882
|
lastUpdated: 2026-01-01
|
|
876
883
|
---
|
|
877
884
|
|
|
878
|
-
${
|
|
885
|
+
${_t}
|
|
879
886
|
|
|
880
887
|
# Privacy Policy / \u9690\u79C1\u653F\u7B56
|
|
881
888
|
|
|
@@ -1014,13 +1021,13 @@ or in-app notification before the change takes effect.
|
|
|
1014
1021
|
**Data Controller / \u6570\u636E\u63A7\u5236\u8005:** {{COMPANY_NAME}}
|
|
1015
1022
|
**Address / \u5730\u5740:** {{COMPANY_ADDRESS}}
|
|
1016
1023
|
**Email / \u90AE\u7BB1:** {{COMPANY_CONTACT_EMAIL}}
|
|
1017
|
-
`,
|
|
1024
|
+
`,Cs=`---
|
|
1018
1025
|
title: Terms of Service / \u670D\u52A1\u6761\u6B3E
|
|
1019
1026
|
description: Terms governing your use of {{COMPANY_NAME}}.
|
|
1020
1027
|
lastUpdated: 2026-01-01
|
|
1021
1028
|
---
|
|
1022
1029
|
|
|
1023
|
-
${
|
|
1030
|
+
${_t}
|
|
1024
1031
|
|
|
1025
1032
|
# Terms of Service / \u670D\u52A1\u6761\u6B3E
|
|
1026
1033
|
|
|
@@ -1133,13 +1140,13 @@ conflict-of-laws principles. Disputes shall be resolved in the competent courts
|
|
|
1133
1140
|
## 11. Contact / \u8054\u7CFB\u65B9\u5F0F
|
|
1134
1141
|
|
|
1135
1142
|
{{COMPANY_NAME}} \xB7 {{COMPANY_ADDRESS}} \xB7 {{COMPANY_CONTACT_EMAIL}}
|
|
1136
|
-
`,
|
|
1143
|
+
`,Is=`---
|
|
1137
1144
|
title: AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
|
|
1138
1145
|
description: Disclosure required by \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300B
|
|
1139
1146
|
lastUpdated: 2026-01-01
|
|
1140
1147
|
---
|
|
1141
1148
|
|
|
1142
|
-
${
|
|
1149
|
+
${_t}
|
|
1143
1150
|
|
|
1144
1151
|
# AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
|
|
1145
1152
|
|
|
@@ -1215,13 +1222,13 @@ human professional.
|
|
|
1215
1222
|
|
|
1216
1223
|
AI \u8F93\u51FA\u53EF\u80FD\u4E0D\u51C6\u786E\u3001\u5B58\u5728\u504F\u89C1\u6216\u8FC7\u65F6\u3002**\u8BF7\u52FF**\u5728\u672A\u7ECF\u5408\u683C\u4E13\u4E1A\u4EBA\u58EB\u72EC\u7ACB\u6838\u5B9E\u7684\u60C5\u51B5\u4E0B\uFF0C\u5C06 AI \u8F93\u51FA
|
|
1217
1224
|
\u7528\u4E8E\u533B\u7597\u3001\u6CD5\u5F8B\u3001\u91D1\u878D\u6216\u5B89\u5168\u6538\u5173\u7684\u51B3\u7B56\u3002
|
|
1218
|
-
`,
|
|
1225
|
+
`,ws=`---
|
|
1219
1226
|
title: Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
|
|
1220
1227
|
description: Notice of cross-border transfer of personal information, per PIPL.
|
|
1221
1228
|
lastUpdated: 2026-01-01
|
|
1222
1229
|
---
|
|
1223
1230
|
|
|
1224
|
-
${
|
|
1231
|
+
${_t}
|
|
1225
1232
|
|
|
1226
1233
|
# Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
|
|
1227
1234
|
|
|
@@ -1280,13 +1287,13 @@ Refusal may limit your ability to use features that rely on overseas services.
|
|
|
1280
1287
|
- \u4F20\u8F93\u4E2D\u52A0\u5BC6 (TLS 1.2+) \u53CA\u9759\u6001\u52A0\u5BC6 (AES-256)\u3002
|
|
1281
1288
|
- \u5408\u540C\u6761\u6B3E\u8981\u6C42\u5883\u5916\u63A5\u6536\u65B9\u63D0\u4F9B\u7B49\u540C\u4E8E PIPL \u7684\u4FDD\u62A4\u3002
|
|
1282
1289
|
- \u8BBF\u95EE\u63A7\u5236\u3001\u5BA1\u8BA1\u65E5\u5FD7\u548C\u8FDD\u89C4\u901A\u77E5\u7A0B\u5E8F\u3002
|
|
1283
|
-
`,
|
|
1290
|
+
`,Rs=`---
|
|
1284
1291
|
title: Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
|
|
1285
1292
|
description: Itemized list of personal information collected, per PIPL Article 17.
|
|
1286
1293
|
lastUpdated: 2026-01-01
|
|
1287
1294
|
---
|
|
1288
1295
|
|
|
1289
|
-
${
|
|
1296
|
+
${_t}
|
|
1290
1297
|
|
|
1291
1298
|
# Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
|
|
1292
1299
|
|
|
@@ -1322,26 +1329,26 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
|
|
|
1322
1329
|
**{{COMPANY_CONTACT_EMAIL}}**.
|
|
1323
1330
|
|
|
1324
1331
|
\u5982\u9700\u884C\u4F7F\u60A8\u7684\u6743\u5229\uFF08\u8BBF\u95EE\u3001\u66F4\u6B63\u3001\u5220\u9664\u3001\u5BFC\u51FA\u3001\u64A4\u56DE\u540C\u610F\uFF09\uFF0C\u8BF7\u8054\u7CFB **{{COMPANY_CONTACT_EMAIL}}**\u3002
|
|
1325
|
-
`;async function
|
|
1326
|
-
`))}async function
|
|
1327
|
-
`))}async function
|
|
1328
|
-
`))}async function
|
|
1329
|
-
`))}async function
|
|
1330
|
-
`)}import w from"fs";import
|
|
1331
|
-
`+t):w.writeFileSync(o,t)}async function
|
|
1332
|
+
`;async function ks(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,"src","components","compliance","Footer.tsx");z(n,Es);let r=N.join(o,"src","components","compliance","README.md");z(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(`
|
|
1333
|
+
`))}async function xs(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,"src","components","compliance","CookieBanner.tsx");z(n,bs)}async function Ns(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,vt,"privacy","page.mdx");z(n,As)}async function Ts(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,vt,"terms","page.mdx");z(n,Cs)}async function Os(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,on,"IcpFooter.tsx");z(o,vs),rn(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(`
|
|
1334
|
+
`))}async function Ls(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,on,"PublicSecurityFooter.tsx");z(o,_s),rn(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(`
|
|
1335
|
+
`))}async function Us(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,on,"AigcDisclaimer.tsx");z(o,Ps),rn(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(`
|
|
1336
|
+
`))}async function Ms(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"aigc-disclosure","page.mdx");z(o,Is)}async function Ds(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"cross-border-data","page.mdx");z(o,ws)}async function Fs(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"pii-collection","page.mdx");z(o,Rs)}async function Yn(e,t){try{await ks(e,t),await xs(e,t),await Ns(e,t),await Ts(e,t),(t==="cn"||t==="hybrid")&&(await Os(e),await Ls(e),await Us(e),await Ms(e),await Ds(e),await Fs(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 js from"fs";import Vs from"path";async function qn(e,t){let o=Vs.join(e,"nebutra.config.json");js.writeFileSync(o,JSON.stringify(t,null,2)+`
|
|
1337
|
+
`)}import w from"fs";import ke from"path";var sn=[{id:"local",name:"Local / Self-hosted Docker",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres:postgres@localhost:5432/$PROJECT",comment:"Local Postgres via docker-compose (pnpm infra:up)"}],docs:"https://www.postgresql.org/docs/",description:"Docker on localhost. You operate it.",tier:"self-hosted"},{id:"supabase",name:"Supabase",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:6543/postgres?pgbouncer=true",comment:"Supabase pooler \u2014 use for runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres",comment:"Supabase direct \u2014 use for Prisma migrations"},{name:"NEXT_PUBLIC_SUPABASE_URL",placeholder:"https://<project>.supabase.co"},{name:"NEXT_PUBLIC_SUPABASE_ANON_KEY",placeholder:""},{name:"SUPABASE_SERVICE_ROLE_KEY",placeholder:""}],docs:"https://supabase.com/docs",description:"Managed Postgres + auth/storage/realtime/edge-functions.",tier:"managed"},{id:"neon",name:"Neon",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>-pooler.<region>.neon.tech/<db>?sslmode=require",comment:"Neon pooled \u2014 runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>.<region>.neon.tech/<db>?sslmode=require",comment:"Neon direct (no -pooler) \u2014 migrations"}],docs:"https://neon.tech/docs",description:"Serverless Postgres with branching and scale-to-zero.",tier:"managed"},{id:"vercel-postgres",name:"Vercel Postgres",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"$POSTGRES_PRISMA_URL",comment:"Vercel Marketplace injects POSTGRES_PRISMA_URL automatically"},{name:"DIRECT_URL",placeholder:"$POSTGRES_URL_NON_POOLING",comment:"Vercel Marketplace injects POSTGRES_URL_NON_POOLING automatically"}],docs:"https://vercel.com/docs/storage/vercel-postgres",description:"Neon-backed, auto-provisioned via Vercel Marketplace.",tier:"managed"},{id:"planetscale",name:"PlanetScale",region:"global",supportedEngines:["mysql"],forcedEngine:"mysql",prismaDatasourceExtras:['relationMode = "prisma"'],envVars:[{name:"DATABASE_URL",placeholder:"mysql://<user>:<pass>@<host>.psdb.cloud/<db>?sslaccept=strict",comment:'PlanetScale: relationMode = "prisma" (no FK support server-side)'}],docs:"https://planetscale.com/docs",description:"Managed MySQL with branching. No foreign keys.",tier:"managed"},{id:"railway",name:"Railway",region:"global",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"$DATABASE_URL",comment:"Railway service env var; injected when you link a Postgres service"}],docs:"https://docs.railway.app/databases/postgresql",description:"Generalist managed infra; standard TCP Postgres/MySQL.",tier:"managed"},{id:"aliyun-rds",name:"Aliyun RDS",region:"cn",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@<rds-instance>.rds.aliyuncs.com:5432/<db>",comment:"Aliyun RDS Postgres \u2014 internal VPC endpoint recommended"}],docs:"https://www.alibabacloud.com/help/en/rds",description:"Aliyun RDS \u2014 China compliance + intranet routing.",tier:"managed"},{id:"tencent-cdb",name:"Tencent CloudDB (CDB)",region:"cn",supportedEngines:["mysql","postgresql"],envVars:[{name:"DATABASE_URL",placeholder:"mysql://<user>:<pwd>@<cdb-instance>.tencentcdb.com:3306/<db>",comment:"Tencent CloudDB \u2014 VPC endpoint recommended"}],docs:"https://intl.cloud.tencent.com/document/product/236",description:"Tencent CloudDB \u2014 China compliance.",tier:"managed"},{id:"none",name:"None",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[],docs:"",description:"Skip database scaffolding.",tier:"self-hosted"}];function Kt(e){return sn.find(t=>t.id===e)}function Gn(e){return e==="cn"||e==="hybrid"?"local":"supabase"}function Bs(e){w.existsSync(e)&&w.rmSync(e,{recursive:!0,force:!0})}function Hn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function Ks(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function Wn(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 $s(e,t){let o=ke.join(e,".env.example");w.existsSync(o)?w.appendFileSync(o,`
|
|
1338
|
+
`+t):w.writeFileSync(o,t)}async function Xn(e,t,o){let n=ke.join(e,"packages","platform","db");if(t==="none"){Bs(n);return}let r=ke.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",$s(e,`# Database (${t})
|
|
1332
1339
|
DATABASE_URL="${s}"
|
|
1333
|
-
`),!w.existsSync(r))return;let i=w.readFileSync(r,"utf8"),c=i;t==="mysql"?(c=
|
|
1340
|
+
`),!w.existsSync(r))return;let i=w.readFileSync(r,"utf8"),c=i;t==="mysql"?(c=Hn(c,"mysql"),c=Wn(c)):t==="sqlite"&&(c=Hn(c,"sqlite"),c=Ks(c),c=Wn(c)),c!==i&&w.writeFileSync(r,c)}function Ys(e){let t=ke.join(e,".env.example");return w.existsSync(t)?w.readFileSync(t,"utf8"):""}function qs(e,t,o,n){let r=ke.join(e,".env.example"),s=Ys(e),i=n?`# ${n}
|
|
1334
1341
|
${t}="${o}"
|
|
1335
1342
|
`:`${t}="${o}"
|
|
1336
1343
|
`,c=new RegExp(`^\\s*${t}\\s*=.*$`,"m");if(c.test(s)){w.writeFileSync(r,s.replace(c,`${t}="${o}"`));return}s?w.appendFileSync(r,`
|
|
1337
|
-
${i}`):w.writeFileSync(r,i)}function
|
|
1344
|
+
${i}`):w.writeFileSync(r,i)}function Gs(e,t){let o=ke.join(e,"packages","platform","db","prisma","schema.prisma");if(!w.existsSync(o))return;let n=w.readFileSync(o,"utf8"),r=/(datasource\s+db\s*\{[^}]*?)(\n})/;if(!n.match(r))return;let i=t.filter(l=>!n.includes(l.trim()));if(i.length===0)return;let c=i.map(l=>` ${l}`).join(`
|
|
1338
1345
|
`),a=n.replace(r,`$1
|
|
1339
|
-
${c}$2`);w.writeFileSync(o,a)}function
|
|
1340
|
-
`))}async function
|
|
1341
|
-
`+t):
|
|
1346
|
+
${c}$2`);w.writeFileSync(o,a)}function Hs(e){let t=ke.join(e,"packages","platform","db","prisma","schema.prisma");if(!w.existsSync(t))return;let o=w.readFileSync(t,"utf8");if(/directUrl\s*=\s*env\(/.test(o))return;let n=/(datasource\s+db\s*\{[\s\S]*?url\s*=\s*env\(\s*"DATABASE_URL"\s*\)[^\n]*\n)/;n.test(o)&&w.writeFileSync(t,o.replace(n,`$1 directUrl = env("DIRECT_URL")
|
|
1347
|
+
`))}async function zn(e,t,o){if(!(t.id==="none"||t.id==="local")){for(let n of t.envVars){let r=n.placeholder.replace(/\$PROJECT/g,o);qs(e,n.name,r,n.comment)}t.prismaDatasourceExtras&&t.prismaDatasourceExtras.length>0&&Gs(e,t.prismaDatasourceExtras),t.keepDirectUrl&&Hs(e)}}import at from"fs";import K from"path";import{fileURLToPath as Ws}from"url";var Xs=Ws(import.meta.url),Jn=K.dirname(Xs);function zs(){let e=[K.join(Jn,"..","templates","deploy"),K.join(Jn,"..","..","templates","deploy")];for(let t of e)if(at.existsSync(t))return t;return e[0]}async function Qn(e,t){if(t==="none")return;let o=zs();t==="vercel"?await at.promises.copyFile(K.join(o,"vercel.json"),K.join(e,"vercel.json")):t==="railway"?await at.promises.copyFile(K.join(o,"railway.toml"),K.join(e,"railway.toml")):t==="cloudflare"?await at.promises.copyFile(K.join(o,"wrangler.toml"),K.join(e,"wrangler.toml")):t==="selfhost"&&(await at.promises.copyFile(K.join(o,"docker-compose.yml"),K.join(e,"docker-compose.yml")),await at.promises.copyFile(K.join(o,"Dockerfile.web"),K.join(e,"Dockerfile.web")))}import ge from"fs";import xe from"path";import{fileURLToPath as Js}from"url";var Qs=Js(import.meta.url),Zn=xe.dirname(Qs),Zs=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|vue)$/,eo=["fumadocs","nextra","mintlify","docusaurus","vitepress"];function ei(e){let t=[xe.join(Zn,"..","templates","docs",e),xe.join(Zn,"..","..","templates","docs",e)];for(let o of t)if(ge.existsSync(o))return o;return t[0]}async function to(e,t){if(t.framework==="none")return;if(!eo.includes(t.framework))throw new Error(`Unsupported docs framework: "${t.framework}". Supported: ${eo.join(", ")}, none.`);let o=ei(t.framework),n=xe.join(e,"apps","docs");if(!ge.existsSync(o))throw new Error(`Docs template not found: ${o}`);no(o,n),oo(n,{"{PRODUCT_NAME}":t.projectName})}function no(e,t){ge.mkdirSync(t,{recursive:!0});for(let o of ge.readdirSync(e,{withFileTypes:!0})){let n=xe.join(e,o.name),r=xe.join(t,o.name);o.isDirectory()?no(n,r):ge.copyFileSync(n,r)}}function oo(e,t){for(let o of ge.readdirSync(e,{withFileTypes:!0})){let n=xe.join(e,o.name);if(o.isDirectory())oo(n,t);else if(Zs.test(o.name)){let r=ge.readFileSync(n,"utf-8");for(let[s,i]of Object.entries(t))r=r.split(s).join(i);ge.writeFileSync(n,r)}}}import Te from"fs";import Ne from"path";var $t=[{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 ro(e){return $t.find(t=>t.id===e)}var Ip=$t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Oe="@nebutra/email";function an(e,t){Te.mkdirSync(Ne.dirname(e),{recursive:!0}),Te.writeFileSync(e,t)}function ti(e,t){let o=Ne.join(e,".env.example");Te.existsSync(o)?Te.appendFileSync(o,`
|
|
1348
|
+
`+t):Te.writeFileSync(o,t)}function ni(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
1342
1349
|
`);return`${t}
|
|
1343
1350
|
${o}
|
|
1344
|
-
`}var
|
|
1351
|
+
`}var oi=`/**
|
|
1345
1352
|
* Public inputs accepted by the \`sendEmail\` wrapper.
|
|
1346
1353
|
* Keep the surface minimal \u2014 individual providers may accept more, but
|
|
1347
1354
|
* consumers should code against this shape for portability.
|
|
@@ -1361,8 +1368,8 @@ export interface SendEmailResult {
|
|
|
1361
1368
|
/** Raw provider response \u2014 useful for debugging, not a stable contract. */
|
|
1362
1369
|
raw?: unknown;
|
|
1363
1370
|
}
|
|
1364
|
-
`;function
|
|
1365
|
-
* @${
|
|
1371
|
+
`;function ri(){return`/**
|
|
1372
|
+
* @${Oe.slice(1)} \u2014 Resend transactional email wrapper.
|
|
1366
1373
|
*
|
|
1367
1374
|
* Docs: https://resend.com/docs
|
|
1368
1375
|
*/
|
|
@@ -1400,8 +1407,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1400
1407
|
}
|
|
1401
1408
|
|
|
1402
1409
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1403
|
-
`}function
|
|
1404
|
-
* @${
|
|
1410
|
+
`}function si(){return`/**
|
|
1411
|
+
* @${Oe.slice(1)} \u2014 Postmark transactional email wrapper.
|
|
1405
1412
|
*
|
|
1406
1413
|
* Docs: https://postmarkapp.com/developer
|
|
1407
1414
|
*/
|
|
@@ -1438,8 +1445,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1438
1445
|
}
|
|
1439
1446
|
|
|
1440
1447
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1441
|
-
`}function
|
|
1442
|
-
* @${
|
|
1448
|
+
`}function ii(){return`/**
|
|
1449
|
+
* @${Oe.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
|
|
1443
1450
|
*
|
|
1444
1451
|
* Docs: https://docs.aws.amazon.com/ses
|
|
1445
1452
|
*/
|
|
@@ -1494,8 +1501,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1494
1501
|
}
|
|
1495
1502
|
|
|
1496
1503
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1497
|
-
`}function
|
|
1498
|
-
* @${
|
|
1504
|
+
`}function ai(){return`/**
|
|
1505
|
+
* @${Oe.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
|
|
1499
1506
|
*
|
|
1500
1507
|
* Docs: https://help.aliyun.com/product/29412.html
|
|
1501
1508
|
*/
|
|
@@ -1544,8 +1551,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1544
1551
|
}
|
|
1545
1552
|
|
|
1546
1553
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1547
|
-
`}function
|
|
1548
|
-
* @${
|
|
1554
|
+
`}function ci(){return`/**
|
|
1555
|
+
* @${Oe.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
|
|
1549
1556
|
*
|
|
1550
1557
|
* Docs: https://cloud.tencent.com/document/product/1288
|
|
1551
1558
|
*/
|
|
@@ -1592,8 +1599,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1592
1599
|
}
|
|
1593
1600
|
|
|
1594
1601
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1595
|
-
`}function
|
|
1596
|
-
* @${
|
|
1602
|
+
`}function pi(){return`/**
|
|
1603
|
+
* @${Oe.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
|
|
1597
1604
|
*
|
|
1598
1605
|
* Docs: https://qiye.163.com/help
|
|
1599
1606
|
*/
|
|
@@ -1630,24 +1637,31 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1630
1637
|
}
|
|
1631
1638
|
|
|
1632
1639
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1633
|
-
`}function
|
|
1634
|
-
`}}function
|
|
1635
|
-
`}async function
|
|
1640
|
+
`}function li(e){switch(e){case"resend":return ri();case"postmark":return si();case"ses":return ii();case"aliyun-dm":return ai();case"tencent-ses":return ci();case"netease":return pi();case"none":return`export {};
|
|
1641
|
+
`}}function di(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:Oe,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)+`
|
|
1642
|
+
`}async function so(e,t,o){if(t==="none")return;let n=ro(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${$t.map(i=>i.id).join(", ")}`);let r=Ne.join(e,"packages","email"),s=Ne.join(r,"src");Te.existsSync(s)&&Te.rmSync(s,{recursive:!0,force:!0}),an(Ne.join(r,"package.json"),di(n)),an(Ne.join(s,"types.ts"),oi),an(Ne.join(s,"index.ts"),li(n.id)),ti(e,ni(n))}import Yt from"fs";import io from"path";async function ao(e,t){let o=`# Automatically injected by create-sailor
|
|
1636
1643
|
DATABASE_URL="${String(t.databaseUrl)}"
|
|
1637
1644
|
|
|
1638
1645
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
|
|
1639
1646
|
CLERK_SECRET_KEY="${String(t.clerkSecret)}"
|
|
1640
1647
|
|
|
1641
1648
|
NEXT_PUBLIC_SITE_URL="http://localhost:3000"
|
|
1642
|
-
`,n=
|
|
1643
|
-
`+o)}import
|
|
1649
|
+
`,n=io.join(e,".env"),r=io.join(e,".env.local");!Yt.existsSync(n)&&!Yt.existsSync(r)?Yt.writeFileSync(r,o):Yt.appendFileSync(r,`
|
|
1650
|
+
`+o)}import po from"crypto";import bt from"fs";import co from"path";function Le(e){return po.randomBytes(e).toString("base64").replace(/=+$/,"")}function ui(e){return po.randomBytes(e).toString("hex")}function mi(){return{AUTH_SECRET:Le(32),NEXTAUTH_SECRET:Le(32),BETTER_AUTH_SECRET:Le(32),JWT_SECRET:Le(32),WEBHOOK_SECRET:ui(16),ENCRYPTION_KEY:Le(32),API_SECRET_KEY:Le(32),SESSION_SECRET:Le(32)}}function gi(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function fi(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=gi(o);return e.replace(n,`${t}="${r}"`)}async function lo(e){let t=co.join(e,".env.example"),o=co.join(e,".env.local");if(!bt.existsSync(t))return null;try{let n=bt.readFileSync(t,"utf8"),r=mi(),i=bt.existsSync(o)?bt.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))i=fi(i,c,r[c]);return bt.writeFileSync(o,i),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 qt=[{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 uo(e){return qt.find(t=>t.id===e)}var jp=qt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function mo(e,t,o="global"){let n=uo(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${qt.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"feature-flags");return}n.envVars.length>0&&te(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{execFileSync as yo}from"child_process";import M from"fs";import yi from"os";import fe from"path";import Si from"ignore";var hi={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 Ei(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function vi(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function So(e){return/^[0-9a-f]{7,40}$/i.test(e)}function _i(e,t){let o=`https://github.com/${e}.git`,n=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of n)try{let s=yo("git",["ls-remote",o,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!s)continue;let[i]=s.split(/\s+/);if(So(i))return i}catch{}return null}async function bi(e,t){if(So(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=_i(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 ho(e,t,o){let n=M.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let s=fe.join(t,r.name),i=fe.relative(e,s).split(fe.sep).join("/");r.isDirectory()?(o.push(i+"/"),ho(e,s,o)):o.push(i)}}function Pi(e){let t=fe.join(e,".templateignore");if(!M.existsSync(t))return;let o=M.readFileSync(t,"utf8"),n=Si().add(o),r=[];ho(e,e,r);let s=r.map(a=>a.endsWith("/")?a.slice(0,-1):a),i=new Set(n.filter(s)),c=s.filter(a=>!i.has(a)).sort((a,l)=>l.split("/").length-a.split("/").length);for(let a of c){let l=fe.join(e,a);try{M.existsSync(l)&&M.rmSync(l,{recursive:!0,force:!0})}catch{}}try{M.existsSync(t)&&M.rmSync(t,{force:!0})}catch{}}async function go(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)`);M.writeFileSync(t,n);let r=M.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function fo(e,t){yo("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function Eo(e){try{let t=M.readdirSync(e);for(let o of t)M.rmSync(fe.join(e,o),{recursive:!0,force:!0})}catch{}}async function Ai(e,t){let o=M.mkdtempSync(fe.join(yi.tmpdir(),"create-sailor-")),n=fe.join(o,"template.tar.gz");try{let r=await bi(e.repo,e.ref);await go(vi(e.repo,r),n),fo(n,t)}catch(r){if(!e.allowMutableFallback)throw r;Eo(t),await go(Ei(e.repo,e.ref),n),fo(n,t)}finally{M.rmSync(o,{recursive:!0,force:!0})}}async function vo(e){M.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let s=hi[r];try{if(await Ai(s,e),s.applyIgnore)try{Pi(e)}catch(i){throw new Error(`Template cloned, but .templateignore processing failed: ${i instanceof Error?i.message:String(i)}`)}return}catch(i){n=i instanceof Error?i:new Error(String(i)),Eo(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
|
|
1644
1651
|
|
|
1645
1652
|
Ensure you have internet access and 'tar' installed.
|
|
1646
|
-
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import
|
|
1647
|
-
`)
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1653
|
+
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import{createHmac as Ci,randomBytes as Ii}from"crypto";import J from"fs";import re from"path";import{fileURLToPath as wi}from"url";var Ri=wi(import.meta.url),_o=re.dirname(Ri),bo="scaffold-meta.json",Po=".nebutra",ki="nebutra-sailor:scaffold-marker:v1";function xi(e){if(e)return e;let t=[re.join(_o,"..","templates"),re.join(_o,"..","..","templates")];for(let o of t)if(J.existsSync(o))return o;return t[0]}function Ni(e){let t=`${e.cliVersion}|${e.scaffoldedAt}|${e.projectName}|${e.nonce}`;return Ci("sha256",ki).update(t).digest("hex")}function Ao(e,t){let o=[],n=xi(t.templatesRoot),r=re.join(e,"LICENSE");if(J.existsSync(r)){let C=J.readFileSync(r,"utf-8").slice(0,256);/GNU AFFERO GENERAL PUBLIC LICENSE/i.test(C)&&(J.renameSync(r,re.join(e,"LICENSE-AGPL-REFERENCE.md")),o.push("LICENSE-AGPL-REFERENCE.md (preserved upstream AGPL)"))}let s=re.join(n,"LICENSE-INDEPENDENT.md");if(!J.existsSync(s))throw new Error(`LICENSE-INDEPENDENT.md template missing at ${s}; cannot emit license.`);J.copyFileSync(s,re.join(e,"LICENSE")),o.push("LICENSE");let i=new Date().toISOString(),c=Ii(12).toString("hex"),a=Ni({cliVersion:t.cliVersion,scaffoldedAt:i,projectName:t.projectName,nonce:c}),l={schemaVersion:1,cliVersion:t.cliVersion,scaffoldedAt:i,projectName:t.projectName,nonce:c,signature:a,purpose:"Marks this project as scaffolded by the official `create-sailor` CLI. The Independent Developer License in LICENSE applies as long as this file is present and the signature verifies.",license:{tier:"independent",file:"LICENSE",upgradeUrl:"https://nebutra.com/get-license"}},d=re.join(e,Po);J.mkdirSync(d,{recursive:!0}),J.writeFileSync(re.join(d,bo),`${JSON.stringify(l,null,2)}
|
|
1654
|
+
`),o.push(`${Po}/${bo}`);let S=re.join(e,"README.md");if(J.existsSync(S)){let C=J.readFileSync(S,"utf-8");C.includes("Nebutra-Sailor Independent Developer License")||(J.writeFileSync(S,`> **License notice:** scaffolded by \`create-sailor\` under the
|
|
1655
|
+
> [Nebutra-Sailor Independent Developer License](./LICENSE). Free for
|
|
1656
|
+
> individuals/OPC with \u2264 1 FTE and < $1M ARR; upgrade for larger teams at
|
|
1657
|
+
> https://nebutra.com/get-license. The upstream repository remains
|
|
1658
|
+
> AGPL-3.0 \u2014 see \`LICENSE-AGPL-REFERENCE.md\`.
|
|
1659
|
+
|
|
1660
|
+
`+C),o.push("README.md (prepended license notice)"))}return{wrote:o}}import Ue from"fs";import cn from"path";async function Co(e,t){let o=cn.join(e,"packages","mcp");if(t==="off"){Ue.existsSync(o)&&Ue.rmSync(o,{recursive:!0,force:!0});let r=cn.join(e,"packages","cli","src","commands","mcp-server.ts");Ue.existsSync(r)&&Ue.rmSync(r,{force:!0});return}let n=cn.join(e,".env.example");if(Ue.existsSync(n)){let r=Ue.readFileSync(n,"utf-8"),s="# MCP Server (Agent-friendly API)";if(!r.includes(s)){let i=["","# =============================================",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(`
|
|
1661
|
+
`);Ue.appendFileSync(n,i)}}}import Pt from"fs";import Io from"path";async function wo(e,t,o){let n=Io.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){Pt.existsSync(n)&&Pt.rmSync(n,{recursive:!0,force:!0});return}let s=Io.join(e,".env.example");if(!Pt.existsSync(s))return;let i=Pt.readFileSync(s,"utf-8"),c="# Metering (usage-based billing)";if(!i.includes(c)){let a=["","# =============================================",c,"# Docs: see packages/commerce/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
|
|
1662
|
+
`);Pt.appendFileSync(s,a)}}import ce from"fs";import D from"path";var Ro=[{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:""}],al=Ro.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function ko(e){return Ro.find(t=>t.id===e)}var pn={sentry:{"@sentry/nextjs":"^8.45.0"},datadog:{"dd-trace":"^5.32.0","@datadog/browser-rum":"^5.30.0"},bugsnag:{"@bugsnag/js":"^8.2.0","@bugsnag/plugin-react":"^8.2.0"}};function Ti(e){ce.mkdirSync(e,{recursive:!0})}function ln(e,t){let o=D.join(e,"package.json");if(!ce.existsSync(o))return;let n;try{n=JSON.parse(ce.readFileSync(o,"utf-8"))}catch(c){console.error(`Failed to parse ${o}:`,c);return}let s={...n.dependencies??{}};for(let[c,a]of Object.entries(t))s[c]||(s[c]=a);let i={...n,dependencies:s};ce.writeFileSync(o,JSON.stringify(i,null,2)+`
|
|
1663
|
+
`)}function se(e,t){Ti(D.dirname(e)),ce.writeFileSync(e,t)}function At(e,t){let o=D.join(e,".env.example");ce.existsSync(o)?ce.appendFileSync(o,`
|
|
1664
|
+
`+t):ce.writeFileSync(o,t)}function Oi(e){let t=`import * as Sentry from "@sentry/nextjs";
|
|
1651
1665
|
|
|
1652
1666
|
Sentry.init({
|
|
1653
1667
|
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
@@ -1690,14 +1704,14 @@ export async function register() {
|
|
|
1690
1704
|
}
|
|
1691
1705
|
|
|
1692
1706
|
export { captureRequestError as onRequestError } from "@sentry/nextjs";
|
|
1693
|
-
`;
|
|
1707
|
+
`;se(D.join(e,"sentry.client.config.ts"),t),se(D.join(e,"sentry.server.config.ts"),o),se(D.join(e,"sentry.edge.config.ts"),n),se(D.join(e,"instrumentation.ts"),r)}function Li(){return`# Sentry \u2014 error tracking + performance monitoring
|
|
1694
1708
|
# Get your DSN from https://sentry.io/settings/projects/<project>/keys/
|
|
1695
1709
|
SENTRY_DSN=
|
|
1696
1710
|
NEXT_PUBLIC_SENTRY_DSN=
|
|
1697
1711
|
SENTRY_ORG=
|
|
1698
1712
|
SENTRY_PROJECT=
|
|
1699
1713
|
SENTRY_AUTH_TOKEN=
|
|
1700
|
-
`}function
|
|
1714
|
+
`}function Ui(e){let t=`/**
|
|
1701
1715
|
* Next.js instrumentation hook \u2014 wires Datadog APM (dd-trace) into Node runtime.
|
|
1702
1716
|
* Edge runtime is not supported by dd-trace; only nodejs is initialized.
|
|
1703
1717
|
*/
|
|
@@ -1745,7 +1759,7 @@ export function initDatadogRum(): void {
|
|
|
1745
1759
|
});
|
|
1746
1760
|
initialized = true;
|
|
1747
1761
|
}
|
|
1748
|
-
`;
|
|
1762
|
+
`;se(D.join(e,"instrumentation.ts"),t),se(D.join(e,"src","lib","monitoring","datadog-rum.ts"),o)}function Mi(){return`# Datadog \u2014 APM + RUM
|
|
1749
1763
|
# Server APM (dd-trace)
|
|
1750
1764
|
DD_API_KEY=
|
|
1751
1765
|
DD_APP_KEY=
|
|
@@ -1760,7 +1774,7 @@ NEXT_PUBLIC_DD_SITE=datadoghq.com
|
|
|
1760
1774
|
NEXT_PUBLIC_DD_SERVICE=sailor-web
|
|
1761
1775
|
NEXT_PUBLIC_DD_ENV=production
|
|
1762
1776
|
NEXT_PUBLIC_DD_VERSION=
|
|
1763
|
-
`}function
|
|
1777
|
+
`}function Di(e){let t=`/**
|
|
1764
1778
|
* Bugsnag server-side initialization.
|
|
1765
1779
|
* Import this once at the top of your server entrypoint or a shared init module.
|
|
1766
1780
|
*/
|
|
@@ -1809,11 +1823,11 @@ export function getBugsnagErrorBoundary() {
|
|
|
1809
1823
|
errorBoundary = plugin.createErrorBoundary(React) as typeof errorBoundary;
|
|
1810
1824
|
return errorBoundary;
|
|
1811
1825
|
}
|
|
1812
|
-
`;
|
|
1826
|
+
`;se(D.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),se(D.join(e,"src","lib","monitoring","bugsnag.client.tsx"),o)}function Fi(){return`# Bugsnag \u2014 error tracking
|
|
1813
1827
|
BUGSNAG_API_KEY=
|
|
1814
1828
|
NEXT_PUBLIC_BUGSNAG_API_KEY=
|
|
1815
1829
|
APP_VERSION=
|
|
1816
|
-
`}function
|
|
1830
|
+
`}function ji(e){se(D.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
|
|
1817
1831
|
/**
|
|
1818
1832
|
* \u963F\u91CC\u4E91 ARMS (Application Real-time Monitoring Service) browser agent.
|
|
1819
1833
|
* Injects the official JS agent via next/script.
|
|
@@ -1834,11 +1848,11 @@ export function ArmsScript() {
|
|
|
1834
1848
|
/>
|
|
1835
1849
|
);
|
|
1836
1850
|
}
|
|
1837
|
-
`)}function
|
|
1851
|
+
`)}function Vi(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
|
|
1838
1852
|
ALIYUN_ARMS_LICENSE_KEY=
|
|
1839
1853
|
ALIYUN_ARMS_APP_NAME=
|
|
1840
1854
|
NEXT_PUBLIC_ARMS_PID=
|
|
1841
|
-
`}function
|
|
1855
|
+
`}function Bi(e){se(D.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
|
|
1842
1856
|
/**
|
|
1843
1857
|
* \u542C\u4E91 Browser Agent (\u524D\u7AEF\u6027\u80FD\u76D1\u63A7).
|
|
1844
1858
|
* Docs: https://www.tingyun.com/docs
|
|
@@ -1856,12 +1870,12 @@ export function TingYunScript() {
|
|
|
1856
1870
|
/>
|
|
1857
1871
|
);
|
|
1858
1872
|
}
|
|
1859
|
-
`)}function
|
|
1873
|
+
`)}function Ki(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
|
|
1860
1874
|
TINGYUN_LICENSE_KEY=
|
|
1861
1875
|
NEXT_PUBLIC_TINGYUN_APP_KEY=
|
|
1862
|
-
`}async function
|
|
1863
|
-
`)}}import
|
|
1864
|
-
`+t):
|
|
1876
|
+
`}async function xo(e,t,o="global"){let n=ko(t);if(!n||n.id==="none")return;let r=D.join(e,"apps","web");if(!ce.existsSync(r))return;let s=n.id;try{switch(s){case"sentry":Oi(r),ln(r,pn.sentry),At(e,Li());return;case"datadog":Ui(r),ln(r,pn.datadog),At(e,Mi());return;case"bugsnag":Di(r),ln(r,pn.bugsnag),At(e,Fi());return;case"aliyun-arms":ji(r),At(e,Vi());return;case"tingyun":Bi(r),At(e,Ki());return;default:return}}catch(i){throw console.error(`Failed to apply monitoring selection "${t}":`,i),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Gt=[{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 No(e){return Gt.find(t=>t.id===e)}var ml=Gt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function To(e,t,o="global"){let n=No(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Gt.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"notifications");return}n.envVars.length>0&&te(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"NOTIFICATIONS_PROVIDER",n.id)}import dn from"fs";import $i from"path";async function Oo(e,t){let o=$i.join(e,"package.json");if(dn.existsSync(o)){let n=dn.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",dn.writeFileSync(o,JSON.stringify(r,null,2)+`
|
|
1877
|
+
`)}}import Ht from"fs";import ct from"path";import{fileURLToPath as Yi}from"url";var qi=Yi(import.meta.url),Lo=ct.dirname(qi);function Gi(){let e=[ct.join(Lo,"..","templates","orm","drizzle"),ct.join(Lo,"..","..","templates","orm","drizzle")];for(let t of e)if(Ht.existsSync(t))return t;return null}function Uo(e,t){Ht.mkdirSync(t,{recursive:!0});for(let o of Ht.readdirSync(e,{withFileTypes:!0})){let n=ct.join(e,o.name),r=ct.join(t,o.name);o.isDirectory()?Uo(n,r):Ht.copyFileSync(n,r)}}async function Mo(e,t,o){if(t!=="drizzle")return{applied:!1};if(o!=="postgresql")return{applied:!1,reason:`Drizzle template currently targets Postgres only; --db=${o} keeps Prisma as sole ORM`};let n=Gi();if(!n)return{applied:!1,reason:"Drizzle template directory not found in package \u2014 bundling error"};let r=ct.join(e,"packages","platform","db-drizzle");return Uo(n,r),{applied:!0}}import pe from"fs";import Ct from"path";var Hi=["stripe","lemonsqueezy","chinapay","polar"];function Do(e){pe.existsSync(e)&&pe.rmSync(e,{recursive:!0,force:!0})}function Wi(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Xi(e,t){let o=Ct.join(e,".env.example");pe.existsSync(o)?pe.appendFileSync(o,`
|
|
1878
|
+
`+t):pe.writeFileSync(o,t)}function zi(e){switch(e){case"stripe":return`# Stripe
|
|
1865
1879
|
STRIPE_SECRET_KEY=
|
|
1866
1880
|
STRIPE_WEBHOOK_SECRET=
|
|
1867
1881
|
`;case"lemon":return`# Lemon Squeezy
|
|
@@ -1876,14 +1890,14 @@ CHINAPAY_WECHAT_ENABLED=true
|
|
|
1876
1890
|
CHINAPAY_APP_ID=
|
|
1877
1891
|
CHINAPAY_APP_SECRET=
|
|
1878
1892
|
CHINAPAY_ALIPAY_ENABLED=true
|
|
1879
|
-
`}}async function
|
|
1880
|
-
`),n=[],r=e.includes("#"),s=0;for(;s<o.length;){let i=o[s],c=i.match(
|
|
1881
|
-
`),t)}function
|
|
1882
|
-
`).filter(l=>{let
|
|
1883
|
-
`);return e.replace(s,`createProviderRegistry({${a}})`)}function
|
|
1884
|
-
`+r);let i={ai:"latest"},{providerIds:c,customEndpoint:a}=t;(c.includes("openai")||a||c.some(
|
|
1885
|
-
`)}}import
|
|
1886
|
-
`)}let c=
|
|
1893
|
+
`}}async function Fo(e,t){let o=Ct.join(e,"packages","commerce","billing");if(!pe.existsSync(o))return;if(t==="none"){Do(o);return}let n=Ct.join(o,"src"),r=new Set(Wi(t));for(let i of Hi)r.has(i)||Do(Ct.join(n,i));let s=Ct.join(n,"checkout","types.ts");if(pe.existsSync(s)){let i=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=pe.readFileSync(s,"utf8"),a=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${i}";`);a!==c&&pe.writeFileSync(s,a)}Xi(e,zi(t))}import ye from"fs";import pt from"path";var Bo=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),un=/@sailor:([^\s*]+)/;function Ji(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=>Bo.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 jo(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function Vo(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function Ko(e,t){let o=e.split(`
|
|
1894
|
+
`),n=[],r=e.includes("#"),s=0;for(;s<o.length;){let i=o[s],c=i.match(un);if(!c){n.push(i),s++;continue}let{marker:a,keep:l}=Ji(c[1],t);if(a==="registry-entries"){n.push(r?Vo(i):jo(i)),s++;continue}if(l){let d=r?Vo(i):jo(i);d.trim().length>0&&n.push(d);let S=s+1;for(;S<o.length&&o[S].trim()!==""&&!un.test(o[S]);)n.push(o[S]),S++;S<o.length&&o[S].trim()===""&&(n.push(o[S]),S++),s=S}else{let d=s+1;for(;d<o.length&&o[d].trim()!==""&&!un.test(o[d]);)d++;d<o.length&&o[d].trim()===""&&d++,s=d}}return Qi(n.join(`
|
|
1895
|
+
`),t)}function Qi(e,t){let{providerIds:o,customEndpoint:n}=t,r=new Set;for(let l of o)["openai","anthropic","google","mistral","xai"].includes(l)&&r.add(l),r.add(l.replace(/-/g,"_")),r.add(l);n&&r.add("custom");let s=/createProviderRegistry\(\{([\s\S]*?)\}\)/,i=e.match(s);if(!i)return e;let a=i[1].split(`
|
|
1896
|
+
`).filter(l=>{let d=l.trim();if(d===""||d.startsWith("//"))return!0;let S=d.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return S?r.has(S[1]):!0}).join(`
|
|
1897
|
+
`);return e.replace(s,`createProviderRegistry({${a}})`)}function Zi(e,t){let o=pt.join(t,"registry.ts.template"),n=ye.readFileSync(o,"utf-8");return Ko(n,e)}function ea(e,t){let o=pt.join(t,".env.example.template"),n=ye.readFileSync(o,"utf-8");return Ko(n,e)}async function $o(e,t,o){let n=Zi(t,o),r=ea(t,o),s=pt.join(e,"packages/ai/agents/src");await ye.promises.mkdir(s,{recursive:!0}),await ye.promises.writeFile(pt.join(s,"registry.ts"),n),await ye.promises.appendFile(pt.join(e,".env.example"),`
|
|
1898
|
+
`+r);let i={ai:"latest"},{providerIds:c,customEndpoint:a}=t;(c.includes("openai")||a||c.some(d=>Bo.has(d)))&&(i["@ai-sdk/openai"]="latest",i["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(i["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(i["@ai-sdk/google"]="latest"),c.includes("mistral")&&(i["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(i["@ai-sdk/openai"]="latest");let l=pt.join(e,"package.json");if(ye.existsSync(l)){let d=JSON.parse(await ye.promises.readFile(l,"utf-8"));d.dependencies||(d.dependencies={});for(let[S,C]of Object.entries(i))d.dependencies[S]=C;await ye.promises.writeFile(l,JSON.stringify(d,null,2)+`
|
|
1899
|
+
`)}}import y from"fs";import u from"path";function Yo(e,t){if(!y.existsSync(e))return;let o=y.readdirSync(e);for(let n of o){let r=u.join(e,n);y.statSync(r).isDirectory()?Yo(r,t):t(r)}}async function qo(e,t){let o=u.join(e,"package.json");if(!y.existsSync(o))return;let n=JSON.parse(y.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=u.join(e,"packages","db");if(y.existsSync(r)){let s=u.join(r,"prisma");y.existsSync(s)&&y.rmSync(s,{recursive:!0,force:!0});let i=u.join(r,"package.json");if(y.existsSync(i)){let a=JSON.parse(y.readFileSync(i,"utf8"));a.dependencies&&delete a.dependencies["@prisma/client"],a.devDependencies&&delete a.devDependencies.prisma,y.writeFileSync(i,JSON.stringify(a,null,2)+`
|
|
1900
|
+
`)}let c=u.join(r,"src","index.ts");y.existsSync(c)&&y.writeFileSync(c,`
|
|
1887
1901
|
export const prisma = {} as any;
|
|
1888
1902
|
export const db = {} as any;
|
|
1889
1903
|
export type PrismaClient = any;
|
|
@@ -1929,7 +1943,7 @@ export type UsageAggregate = any;
|
|
|
1929
1943
|
export type UsageLedgerEntry = any;
|
|
1930
1944
|
export type UsageType = any;
|
|
1931
1945
|
export type UsageLedgerSource = any;
|
|
1932
|
-
`)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=
|
|
1946
|
+
`)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=u.join(e,"apps");if(y.existsSync(r)){let s=y.readdirSync(r);for(let i of s){let c=u.join(r,i);if(!y.statSync(c).isDirectory())continue;let a=u.join(c,"src","app");if(!y.existsSync(a))continue;["[lang]","[locale]"].forEach(b=>{let m=u.join(a,b);if(y.existsSync(m)){let U=y.readdirSync(m);for(let kt of U)y.renameSync(u.join(m,kt),u.join(a,kt));y.rmdirSync(m)}}),["src/middleware.ts","middleware.ts"].forEach(b=>{let m=u.join(c,b);y.existsSync(m)&&y.rmSync(m)});let l=u.join(c,"src","lib");y.existsSync(l)||y.mkdirSync(l,{recursive:!0});let d=u.join(l,"mock-i18n.ts");y.writeFileSync(d,`
|
|
1933
1947
|
import React from 'react';
|
|
1934
1948
|
export function useTranslations(namespace?: string): any { return (key: string) => key; }
|
|
1935
1949
|
export function useLocale() { return 'en'; }
|
|
@@ -1947,7 +1961,7 @@ export const useRouter = () => ({ push: (...args: any[]) => {}, replace: (...arg
|
|
|
1947
1961
|
export default function createMiddleware(...args: any[]) { return (req: any) => req; }
|
|
1948
1962
|
export function createNavigation(...args: any[]) { return { Link, redirect, usePathname, useRouter, getPathname: () => '/' }; }
|
|
1949
1963
|
export function defineRouting<T>(config: T): T { return config; }
|
|
1950
|
-
`);let
|
|
1964
|
+
`);let C=u.join(l,"mock-i18n.d.ts");y.writeFileSync(C,`declare module '@/lib/mock-i18n' {
|
|
1951
1965
|
export function useTranslations(namespace?: string): any;
|
|
1952
1966
|
export function useLocale(): string;
|
|
1953
1967
|
export const NextIntlClientProvider: React.FC<any>;
|
|
@@ -1965,19 +1979,19 @@ export function defineRouting<T>(config: T): T { return config; }
|
|
|
1965
1979
|
export function createNavigation(...args: any[]): any;
|
|
1966
1980
|
export function defineRouting<T>(config: T): T;
|
|
1967
1981
|
}
|
|
1968
|
-
`),
|
|
1982
|
+
`),y.writeFileSync(u.join(l,"mock-i18n-index.ts"),`
|
|
1969
1983
|
export * from './mock-i18n';
|
|
1970
1984
|
export { default } from './mock-i18n';
|
|
1971
|
-
`);let
|
|
1985
|
+
`);let k=u.join(c,"tsconfig.json");if(y.existsSync(k))try{let b=y.readFileSync(k,"utf8");if(b.includes('"paths": {')){let m=b.replace(/"paths":\s*\{/,`"paths": {
|
|
1972
1986
|
"next-intl": ["./src/lib/mock-i18n"],
|
|
1973
|
-
"next-intl/*": ["./src/lib/mock-i18n"],`);
|
|
1974
|
-
`)}}}}
|
|
1975
|
-
`)}function v(e){try{
|
|
1976
|
-
`)}function
|
|
1977
|
-
`);
|
|
1978
|
-
`)}async function
|
|
1979
|
-
`);
|
|
1980
|
-
`)}async function
|
|
1987
|
+
"next-intl/*": ["./src/lib/mock-i18n"],`);y.writeFileSync(k,m)}}catch{}let $=u.join(c,"src");y.existsSync($)&&Yo($,b=>{if(!b.endsWith(".ts")&&!b.endsWith(".tsx"))return;let m=y.readFileSync(b,"utf8"),U=!1;b.endsWith("src/app/layout.tsx")&&m.includes("../providers")&&(m=m.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),U=!0),m=m.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),m=m.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),m.match(/locale\s*:\s*any/)&&(m=m.replace(/locale\s*:\s*any/g,"locale: string"),U=!0),m.match(/lang\s*:\s*any/)&&(m=m.replace(/lang\s*:\s*any/g,"lang: string"),U=!0),m.match(/requestLocale\s*:\s*any/)&&(m=m.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),U=!0),m.match(/\(locale\s*=\s*(.*)\)/)&&(m=m.replace(/\(locale\s*=\s*(.*)\)/g,"() "),U=!0),m.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(m=m.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 })"),U=!0),(b.endsWith("src/app/layout.tsx")||b.endsWith("src/app/sitemap.ts")||b.endsWith("src/app/robots.ts")||b.endsWith("src/components/ui/locale-switcher.tsx")||b.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(m=m.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),m=m.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),m=m.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),m=m.replace(/\(l\)\s*=>/g,"(l: any) =>"),U=!0),b.endsWith("src/i18n/request.ts")&&(m=m.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),U=!0),(m.match(/locale\s*:/)||m.match(/lang\s*:/))&&(U=!0),U&&y.writeFileSync(b,m)});let ue=u.join(c,"package.json");if(y.existsSync(ue)){let b=JSON.parse(y.readFileSync(ue,"utf8"));b.dependencies&&delete b.dependencies["next-intl"],y.writeFileSync(ue,JSON.stringify(b,null,2)+`
|
|
1988
|
+
`)}}}}y.writeFileSync(o,JSON.stringify(n,null,2)+`
|
|
1989
|
+
`)}function v(e){try{y.rmSync(e,{recursive:!0,force:!0})}catch{}}function ta(e,t){if(!y.existsSync(e))return;let o;try{o=JSON.parse(y.readFileSync(e,"utf8"))}catch{return}let n=!1;if(o.dependencies&&t in o.dependencies){let{[t]:r,...s}=o.dependencies;o={...o,dependencies:s},n=!0}if(o.devDependencies&&t in o.devDependencies){let{[t]:r,...s}=o.devDependencies;o={...o,devDependencies:s},n=!0}n&&y.writeFileSync(e,JSON.stringify(o,null,2)+`
|
|
1990
|
+
`)}function Go(e,t){t.cronJobs||(v(u.join(e,"apps/web/src/app/api/cron")),v(u.join(e,"packages/integrations/queue/src/scheduled"))),t.auditLog||(v(u.join(e,"apps/web/src/app/[locale]/(app)/settings/audit-log")),v(u.join(e,"apps/web/src/app/api/audit-logs")),v(u.join(e,"apps/web/src/components/audit"))),t.apiKeys||(v(u.join(e,"apps/web/src/app/[locale]/(app)/settings/api-keys")),v(u.join(e,"apps/web/src/app/api/api-keys")),v(u.join(e,"apps/web/src/components/api-keys"))),t.webhooks||(v(u.join(e,"apps/web/src/app/[locale]/(app)/settings/webhooks")),v(u.join(e,"apps/web/src/app/api/webhooks")),v(u.join(e,"apps/web/src/components/webhooks")),v(u.join(e,"packages/integrations/webhooks"))),t.commandPalette||(v(u.join(e,"apps/web/src/components/command-palette")),v(u.join(e,"apps/web/src/app/[locale]/providers/command-palette-mount.tsx"))),t.cookieConsent||(v(u.join(e,"apps/landing-page/src/components/cookie-consent-banner.tsx")),v(u.join(e,"apps/landing-page/src/components/__tests__/cookie-consent-banner.test.tsx")),v(u.join(e,"apps/landing-page/src/lib/cookie-consent.ts")),v(u.join(e,"apps/landing-page/src/lib/__tests__/cookie-consent.test.ts")),v(u.join(e,"apps/web/src/app/api/cookie-consent"))),t.legalPages||(v(u.join(e,"apps/landing-page/src/app/[lang]/(legal)/legal")),v(u.join(e,"apps/landing-page/src/lib/legal-documents.ts")),v(u.join(e,"apps/landing-page/src/lib/__tests__/legal-documents.test.ts"))),t.chinaCompliance||(v(u.join(e,"packages/ops/china-compliance")),v(u.join(e,"apps/landing-page/src/components/icp-footer.tsx")),v(u.join(e,"apps/landing-page/src/components/__tests__/icp-footer.test.tsx")),v(u.join(e,"apps/web/src/components/auth/wechat-login-button.tsx")),v(u.join(e,"apps/web/src/components/auth/__tests__/wechat-login-button.test.tsx")),ta(u.join(e,"apps/web/package.json"),"@nebutra/china-compliance"))}import lt from"fs";import Ho from"path";var Wo=/^--\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/m;function na(e){let t=Wo.exec(e);if(!t)return null;let[,o,n]=t,r=n.split("|").map(s=>s.trim()).filter(Boolean);return{flag:o,values:r}}function oa(e){return e.replace(Wo,"").replace(/^\n/,"")}function mn(e,t){let o={kept:[],removed:[],skipped:[]};if(!lt.existsSync(e))return o;let n=lt.readdirSync(e,{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,s)=>r.name.localeCompare(s.name));for(let r of n){let s=Ho.join(e,r.name),i=Ho.join(s,"migration.sql");if(!lt.existsSync(i)){o.skipped.push(r.name);continue}let c=lt.readFileSync(i,"utf8"),a=na(c);if(!a){o.skipped.push(r.name);continue}let l=t[a.flag];if(l!==void 0&&a.values.includes(l)){lt.writeFileSync(i,oa(c)),o.kept.push(r.name);continue}lt.rmSync(s,{recursive:!0,force:!0}),o.removed.push(r.name)}return o}import{getSchema as ra,printSchema as sa}from"@mrleebo/prisma-ast";var ia=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function aa(e){return e.type==="comment"&&e.text.trim().startsWith("//")}function ca(e){let t=ia.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 pa(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=ca(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function la(e){return e.type==="model"||e.type==="enum"}function gn(e,t){let o=ra(e),n=new Set;for(let c=0;c<o.list.length;c++){let a=o.list[c];if(!la(a))continue;let l=pa(o.list,c);if(!l)continue;let d=t[l.parsed.flag];if(d!==void 0&&l.parsed.values.includes(d))n.add(l.annIndex);else{n.add(c);for(let k=c-1;k>=0;k--){let $=o.list[k];if(aa($)){n.add(k);continue}break}let C=o.list[c+1];C&&C.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,a)=>!n.has(a)),s=[];for(let c of r){let a=s[s.length-1];c.type==="break"&&a&&a.type==="break"||s.push(c)}return sa({type:"schema",list:s})}import dt from"fs";import zo from"path";var Wt=[{id:"qstash",name:"Upstash QStash",region:"both",envVars:["QSTASH_TOKEN","QSTASH_CURRENT_SIGNING_KEY","QSTASH_NEXT_SIGNING_KEY"],docs:"https://upstash.com/docs/qstash",description:"Serverless HTTP-based queue"},{id:"bullmq",name:"BullMQ",region:"both",envVars:["REDIS_URL"],docs:"https://docs.bullmq.io",description:"Redis-backed job queue"},{id:"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 Xo(e){return Wt.find(t=>t.id===e)}var jl=Wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Jo(e){return dt.existsSync(e)?dt.readFileSync(e,"utf-8"):null}function da(e,t){let o=zo.join(e,".env.example"),n=Jo(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
|
|
1991
|
+
`);dt.appendFileSync(o,s)}function ua(e,t,o){let n=zo.join(e,".env.example"),r=Jo(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?dt.writeFileSync(n,r.replace(s,`${t}="${o}"`)):dt.appendFileSync(n,`${t}="${o}"
|
|
1992
|
+
`)}async function Qo(e,t,o){let n=Re(e,"queue");if(t==="none"){n&&dt.rmSync(n,{recursive:!0,force:!0});return}let r=Xo(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${Wt.map(s=>s.id).join(", ")}`);n&&(da(e,r),ua(e,"QUEUE_PROVIDER",t))}import le from"fs";import Se from"path";import{fileURLToPath as ma}from"url";var ga=ma(import.meta.url),Zo=Se.dirname(ga),fa=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|toml|py)$/,ya=["backends/gateway","infra","e2e","tests"];function Sa(){let e=[Se.join(Zo,"..","templates"),Se.join(Zo,"..","..","templates")];for(let t of e)if(le.existsSync(t))return t;return e[0]}async function er(e,t){let o=Sa(),n=[],r=[],s=[...ya,...t.withWorkflows?["workflows"]:[],...t.withPythonBackend?["backends/python"]:[]];for(let i of s){let c=Se.join(o,i);if(!le.existsSync(c)){r.push(i);continue}let a=Se.join(e,i);tr(c,a),nr(a,{"{PRODUCT_NAME}":t.projectName}),n.push(i)}return{applied:n,skipped:r}}function tr(e,t){le.mkdirSync(t,{recursive:!0});for(let o of le.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name),r=Se.join(t,o.name);o.isDirectory()?tr(n,r):le.existsSync(r)||le.copyFileSync(n,r)}}function nr(e,t){for(let o of le.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name);if(o.isDirectory()){nr(n,t);continue}if(!fa.test(o.name))continue;let r=le.readFileSync(n,"utf-8"),s=!1;for(let[i,c]of Object.entries(t))r.includes(i)&&(r=r.split(i).join(c),s=!0);s&&le.writeFileSync(n,r)}}import ut from"fs";import rr from"path";var Xt=[{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 or(e){return Xt.find(t=>t.id===e)}var zl=Xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function sr(e){return ut.existsSync(e)?ut.readFileSync(e,"utf-8"):null}function ha(e,t){let o=rr.join(e,".env.example"),n=sr(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
|
|
1993
|
+
`);ut.appendFileSync(o,s)}function Ea(e,t,o){let n=rr.join(e,".env.example"),r=sr(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?ut.writeFileSync(n,r.replace(s,`${t}="${o}"`)):ut.appendFileSync(n,`${t}="${o}"
|
|
1994
|
+
`)}async function ir(e,t,o){let n=Re(e,"search");if(t==="none"){n&&ut.rmSync(n,{recursive:!0,force:!0});return}let r=or(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Xt.map(s=>s.id).join(", ")}`);n&&(ha(e,r),Ea(e,"SEARCH_PROVIDER",t))}import he from"fs";import Me from"path";function va(e){let t=[Me.join(e,"packages","db"),Me.join(e,"apps","web")];for(let o of t){let n=Me.join(o,"prisma","schema.prisma");if(he.existsSync(n))return{packageDir:o,seedPath:Me.join(o,"prisma","seed.ts"),packageJsonPath:Me.join(o,"package.json")}}return null}function _a(e){try{let t=he.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 ba(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
|
|
1981
1995
|
const admin = await prisma.user.create({
|
|
1982
1996
|
data: {
|
|
1983
1997
|
clerkId: "user_mock_admin",
|
|
@@ -2008,7 +2022,7 @@ export { default } from './mock-i18n';
|
|
|
2008
2022
|
console.log("\\u2713 Created admin user:", admin.email);
|
|
2009
2023
|
} catch (err) {
|
|
2010
2024
|
console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
|
|
2011
|
-
}`}function
|
|
2025
|
+
}`}function Pa(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),s=ba(e,n),i=o?` let tenants: Array<{ id: string; name: string }> = [];
|
|
2012
2026
|
try {
|
|
2013
2027
|
tenants = await Promise.all([
|
|
2014
2028
|
prisma.tenant.create({
|
|
@@ -2077,12 +2091,12 @@ main()
|
|
|
2077
2091
|
.finally(async () => {
|
|
2078
2092
|
await prisma.$disconnect();
|
|
2079
2093
|
});
|
|
2080
|
-
`}function
|
|
2081
|
-
`)}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
|
|
2082
|
-
`+t):
|
|
2094
|
+
`}function Aa(e){if(he.existsSync(e))try{let t=he.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 i={...o,scripts:n,prisma:s};he.writeFileSync(e,JSON.stringify(i,null,2)+`
|
|
2095
|
+
`)}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 ar(e,t){let o=va(e);if(o)try{let n=Me.join(o.packageDir,"prisma","schema.prisma"),r=_a(n),s=Pa(t,r),i=Me.dirname(o.seedPath);he.existsSync(i)||he.mkdirSync(i,{recursive:!0}),he.writeFileSync(o.seedPath,s),Aa(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 Ee from"fs";import De from"path";var zt=[{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:""}],id=zt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function cr(e){return zt.find(t=>t.id===e)}var Ca="@nebutra/sms",Ia={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 fn(e,t){Ee.mkdirSync(De.dirname(e),{recursive:!0}),Ee.writeFileSync(e,t)}function wa(e,t){let o=De.join(e,".env.example");Ee.existsSync(o)?Ee.appendFileSync(o,`
|
|
2096
|
+
`+t):Ee.writeFileSync(o,t)}function Ra(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2083
2097
|
`);return`${t}
|
|
2084
2098
|
${o}
|
|
2085
|
-
`}var
|
|
2099
|
+
`}var ka=`/**
|
|
2086
2100
|
* Inputs for the \`sendSms\` wrapper. Keep this surface portable across
|
|
2087
2101
|
* providers \u2014 provider-specific options belong in the wrapper itself.
|
|
2088
2102
|
*/
|
|
@@ -2102,7 +2116,7 @@ export interface SendSmsResult {
|
|
|
2102
2116
|
provider: string;
|
|
2103
2117
|
raw?: unknown;
|
|
2104
2118
|
}
|
|
2105
|
-
`;function
|
|
2119
|
+
`;function xa(){return`import twilio from "twilio";
|
|
2106
2120
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2107
2121
|
|
|
2108
2122
|
let client: ReturnType<typeof twilio> | null = null;
|
|
@@ -2137,7 +2151,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2137
2151
|
}
|
|
2138
2152
|
|
|
2139
2153
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2140
|
-
`}function
|
|
2154
|
+
`}function Na(){return`import messagebird from "messagebird";
|
|
2141
2155
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2142
2156
|
|
|
2143
2157
|
let client: ReturnType<typeof messagebird> | null = null;
|
|
@@ -2175,7 +2189,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2175
2189
|
}
|
|
2176
2190
|
|
|
2177
2191
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2178
|
-
`}function
|
|
2192
|
+
`}function Ta(){return`import plivo from "plivo";
|
|
2179
2193
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2180
2194
|
|
|
2181
2195
|
let client: InstanceType<typeof plivo.Client> | null = null;
|
|
@@ -2214,7 +2228,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2214
2228
|
}
|
|
2215
2229
|
|
|
2216
2230
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2217
|
-
`}function
|
|
2231
|
+
`}function Oa(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
|
|
2218
2232
|
import * as $OpenApi from "@alicloud/openapi-client";
|
|
2219
2233
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2220
2234
|
|
|
@@ -2263,7 +2277,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2263
2277
|
}
|
|
2264
2278
|
|
|
2265
2279
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2266
|
-
`}function
|
|
2280
|
+
`}function La(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
|
|
2267
2281
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2268
2282
|
|
|
2269
2283
|
const SmsClient = tencentcloud.sms.v20210111.Client;
|
|
@@ -2328,7 +2342,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2328
2342
|
}
|
|
2329
2343
|
|
|
2330
2344
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2331
|
-
`}function
|
|
2345
|
+
`}function Ua(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
|
|
2332
2346
|
import Yunpian from "yunpian-nodejs-sdk";
|
|
2333
2347
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2334
2348
|
|
|
@@ -2380,13 +2394,13 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2380
2394
|
}
|
|
2381
2395
|
|
|
2382
2396
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2383
|
-
`}function
|
|
2384
|
-
`}}function
|
|
2385
|
-
`}async function
|
|
2386
|
-
`+t):
|
|
2397
|
+
`}function Ma(e){switch(e){case"twilio":return xa();case"messagebird":return Na();case"plivo":return Ta();case"aliyun-sms":return Oa();case"tencent-sms":return La();case"yunpian":return Ua();case"none":return`export {};
|
|
2398
|
+
`}}function Da(e){let t={};for(let n of e.pkgs??[]){let r=Ia[n];r&&(t[n]=r)}let o={name:Ca,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)+`
|
|
2399
|
+
`}async function pr(e,t,o="global"){if(t==="none")return;let n=cr(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${zt.map(i=>i.id).join(", ")}`);let r=De.join(e,"packages","sms");if(!Ee.existsSync(r))return;let s=De.join(r,"src");Ee.existsSync(s)&&Ee.rmSync(s,{recursive:!0,force:!0});try{fn(De.join(r,"package.json"),Da(n)),fn(De.join(s,"types.ts"),ka),fn(De.join(s,"index.ts"),Ma(n.id)),wa(e,Ra(n))}catch(i){throw console.error(`Failed to apply SMS selection "${t}":`,i),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import je from"fs";import Fe from"path";var It=[{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 yn(e){let t=e==="supabase"?"supabase-storage":e;return It.some(o=>o.id===t)?t:void 0}function lr(e){let t=yn(e);return t?It.find(o=>o.id===t):void 0}var ud=It.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Ve="@nebutra/storage";function Sn(e,t){je.mkdirSync(Fe.dirname(e),{recursive:!0}),je.writeFileSync(e,t)}function Fa(e,t){let o=Fe.join(e,".env.example");je.existsSync(o)?je.appendFileSync(o,`
|
|
2400
|
+
`+t):je.writeFileSync(o,t)}function ja(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2387
2401
|
`);return`${t}
|
|
2388
2402
|
${o}
|
|
2389
|
-
`}var
|
|
2403
|
+
`}var Va=`/**
|
|
2390
2404
|
* Inputs for the \`uploadFile\` wrapper. Keep this surface portable across
|
|
2391
2405
|
* providers \u2014 provider-specific options belong in the wrapper itself.
|
|
2392
2406
|
*/
|
|
@@ -2412,8 +2426,8 @@ export interface SignedUrlOptions {
|
|
|
2412
2426
|
operation?: "get" | "put";
|
|
2413
2427
|
contentType?: string;
|
|
2414
2428
|
}
|
|
2415
|
-
`;function
|
|
2416
|
-
* @${
|
|
2429
|
+
`;function Ba(){return`/**
|
|
2430
|
+
* @${Ve.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
|
|
2417
2431
|
*
|
|
2418
2432
|
* Docs: https://developers.cloudflare.com/r2/api/s3/api/
|
|
2419
2433
|
*/
|
|
@@ -2476,8 +2490,8 @@ export async function getSignedUrl(
|
|
|
2476
2490
|
}
|
|
2477
2491
|
|
|
2478
2492
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2479
|
-
`}function
|
|
2480
|
-
* @${
|
|
2493
|
+
`}function Ka(){return`/**
|
|
2494
|
+
* @${Ve.slice(1)} \u2014 AWS S3 wrapper.
|
|
2481
2495
|
*
|
|
2482
2496
|
* Docs: https://docs.aws.amazon.com/s3/
|
|
2483
2497
|
*/
|
|
@@ -2541,8 +2555,8 @@ export async function getSignedUrl(
|
|
|
2541
2555
|
}
|
|
2542
2556
|
|
|
2543
2557
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2544
|
-
`}function
|
|
2545
|
-
* @${
|
|
2558
|
+
`}function $a(){return`/**
|
|
2559
|
+
* @${Ve.slice(1)} \u2014 Supabase Storage wrapper.
|
|
2546
2560
|
*
|
|
2547
2561
|
* Docs: https://supabase.com/docs/guides/storage
|
|
2548
2562
|
*/
|
|
@@ -2604,8 +2618,8 @@ export async function getSignedUrl(
|
|
|
2604
2618
|
}
|
|
2605
2619
|
|
|
2606
2620
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2607
|
-
`}function
|
|
2608
|
-
* @${
|
|
2621
|
+
`}function Ya(){return`/**
|
|
2622
|
+
* @${Ve.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
|
|
2609
2623
|
*
|
|
2610
2624
|
* Docs: https://help.aliyun.com/product/31815.html
|
|
2611
2625
|
*/
|
|
@@ -2651,8 +2665,8 @@ export async function getSignedUrl(
|
|
|
2651
2665
|
}
|
|
2652
2666
|
|
|
2653
2667
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2654
|
-
`}function
|
|
2655
|
-
* @${
|
|
2668
|
+
`}function qa(){return`/**
|
|
2669
|
+
* @${Ve.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
|
|
2656
2670
|
*
|
|
2657
2671
|
* Docs: https://cloud.tencent.com/document/product/436
|
|
2658
2672
|
*/
|
|
@@ -2706,8 +2720,8 @@ export async function getSignedUrl(
|
|
|
2706
2720
|
}
|
|
2707
2721
|
|
|
2708
2722
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2709
|
-
`}function
|
|
2710
|
-
* @${
|
|
2723
|
+
`}function Ga(){return`/**
|
|
2724
|
+
* @${Ve.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
|
|
2711
2725
|
*
|
|
2712
2726
|
* Docs: https://developer.qiniu.com/kodo
|
|
2713
2727
|
*/
|
|
@@ -2774,9 +2788,9 @@ export async function getSignedUrl(
|
|
|
2774
2788
|
}
|
|
2775
2789
|
|
|
2776
2790
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2777
|
-
`}function
|
|
2778
|
-
`}}function
|
|
2779
|
-
`}async function
|
|
2791
|
+
`}function Ha(e){switch(e){case"r2":return Ba();case"s3":return Ka();case"supabase-storage":return $a();case"aliyun-oss":return Ya();case"tencent-cos":return qa();case"qiniu":return Ga();case"none":return`export {};
|
|
2792
|
+
`}}function Wa(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:Ve,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)+`
|
|
2793
|
+
`}async function dr(e,t,o){if(t==="none")return;let n=lr(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${It.map(i=>i.id).join(", ")}`);let r=Fe.join(e,"packages","storage"),s=Fe.join(r,"src");je.existsSync(s)&&je.rmSync(s,{recursive:!0,force:!0}),Sn(Fe.join(r,"package.json"),Wa(n)),Sn(Fe.join(s,"types.ts"),Va),Sn(Fe.join(s,"index.ts"),Ha(n.id)),Fa(e,ja(n))}function ve(e,t){if(e===void 0)return t;let o=String(e).trim().toLowerCase();return o==="true"||o==="1"||o==="yes"||o==="on"?!0:o==="false"||o==="0"||o==="no"||o==="off"?!1:t}function ur(e,t){let o=t==="cn";return{cronJobs:ve(e.cronJobs,!0),auditLog:ve(e.auditLog,!0),apiKeys:ve(e.apiKeys,!0),webhooks:ve(e.webhooks,!0),commandPalette:ve(e.commandPalette,!0),cookieConsent:ve(e.cookieConsent,!0),legalPages:ve(e.legalPages,!0),chinaCompliance:ve(e.chinaCompliance,o)}}var Jt=[{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 mr(e){return Jt.find(t=>t.id===e)}var Ed=Jt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function gr(e,t,o="global"){let n=mr(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Jt.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"webhooks");return}n.envVars.length>0&&te(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"WEBHOOKS_PROVIDER",n.id)}import Be from"fs";import wt from"path";function Xa(e){return`import Link from "next/link";
|
|
2780
2794
|
|
|
2781
2795
|
export default function WelcomePage() {
|
|
2782
2796
|
const projectName = ${JSON.stringify(e)};
|
|
@@ -2885,21 +2899,21 @@ function Step({
|
|
|
2885
2899
|
</li>
|
|
2886
2900
|
);
|
|
2887
2901
|
}
|
|
2888
|
-
`}function
|
|
2902
|
+
`}function za(e={}){return`
|
|
2889
2903
|
## What you can do next
|
|
2890
2904
|
|
|
2891
2905
|
${[e.apiKeys===!1?"- Manage API keys at `/settings/api-keys` (disabled \u2014 re-enable with `--api-keys=true`)":"- Manage API keys at `/settings/api-keys`",e.auditLog===!1?"- View audit log at `/settings/audit-log` (disabled \u2014 re-enable with `--audit-log=true`)":"- View audit log at `/settings/audit-log`","- Configure webhooks at `/settings/webhooks`",e.commandPalette===!1?"- Press \u2318K to open the command palette (disabled \u2014 re-enable with `--command-palette=true`)":"- Press \u2318K to open the command palette","- Edit notification preferences at `/settings/notifications`","- Export your data at `/settings/account/export`","- For China deployments, see `packages/ops/china-compliance/README.md`"].join(`
|
|
2892
2906
|
`)}
|
|
2893
|
-
`}function
|
|
2907
|
+
`}function Ja(e=[]){return e.length===0?"":`
|
|
2894
2908
|
## Production readiness holds
|
|
2895
2909
|
|
|
2896
2910
|
Do not enable these in production until you replace stubs, add provider credentials, and verify the integration contract:
|
|
2897
2911
|
|
|
2898
|
-
${e.map(o=>{let n=
|
|
2912
|
+
${e.map(o=>{let n=rt(o.status);return`- ${o.flag}=${o.provider} ${n} \u2014 ${me(o.status)}`}).join(`
|
|
2899
2913
|
`)}
|
|
2900
2914
|
|
|
2901
2915
|
Review the package readiness matrix before handoff: [docs/package-status.md](docs/package-status.md)
|
|
2902
|
-
`}function
|
|
2916
|
+
`}function Qa(e,t,o=[],n={}){return`# Next steps \u2014 ${e}
|
|
2903
2917
|
|
|
2904
2918
|
Region: ${t}
|
|
2905
2919
|
|
|
@@ -2925,42 +2939,44 @@ Your AI-native SaaS scaffold is ready. Complete these four steps to go from temp
|
|
|
2925
2939
|
\`\`\`
|
|
2926
2940
|
|
|
2927
2941
|
After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
|
|
2928
|
-
${
|
|
2942
|
+
${za(n)}${Ja(o)}
|
|
2929
2943
|
|
|
2930
2944
|
## Resources
|
|
2931
2945
|
|
|
2932
2946
|
- [Documentation](/docs)
|
|
2933
2947
|
- [GitHub](https://github.com/nebutra/nebutra-sailor)
|
|
2934
2948
|
- [Get free license (Individual/OPC)](https://nebutra.com/get-license)
|
|
2935
|
-
`}async function
|
|
2936
|
-
`)}function
|
|
2937
|
-
`)+
|
|
2938
|
-
`)),"fumadocs"}return"fumadocs"}function
|
|
2939
|
-
${
|
|
2949
|
+
`}async function fr(e,t){let{projectName:o,region:n,previewSelections:r=[],waveFeatures:s={}}=t;try{let i=wt.join(e,".sailor");Be.existsSync(i)||Be.mkdirSync(i,{recursive:!0}),Be.writeFileSync(wt.join(i,"next-steps.md"),Qa(o,n,r,s))}catch(i){let c=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${c}`)}try{let i=wt.join(e,"apps","web");if(!Be.existsSync(i))return;let c=wt.join(i,"src","app","[locale]","welcome");Be.existsSync(c)||Be.mkdirSync(c,{recursive:!0}),Be.writeFileSync(wt.join(c,"page.tsx"),Xa(o))}catch(i){let c=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write welcome page: ${c}`)}}var yr="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
|
|
2950
|
+
`)}function tc(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function Sr(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 hr(e,t,o){let n=e?.trim().toLowerCase()??Gn(t),r=Kt(n);if(!r){let i=sn.map(c=>c.id).join(", ");throw new Error(`Unknown --db-host="${n}". Valid: ${i}`)}let s=o;return r.forcedEngine&&s!=="none"&&s!==r.forcedEngine&&(s=r.forcedEngine),{hostId:r.id,engine:s}}function Er(e){return e==="drizzle"?"drizzle":"prisma"}function vr(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function _r(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 br(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="nextauth"||t==="next-auth"||t==="authjs"||t==="auth.js"?"nextauth":t==="supabase"||t==="supabase-auth"?"supabase":t==="none"?"none":"clerk"}var nc=new Set(["gateway","direct","custom","none"]);function kr(e){if(!e)return!1;let t=e.trim().toLowerCase();return nc.has(t)}function Pr(e){if(!e)return["openai"];if(kr(e))return[];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}function oc(e,t){let o=e??t;return yn(o)??o}var Ar={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Cr(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in Ar){let n=Ar[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(A.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
|
|
2951
|
+
`)+A.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
|
|
2952
|
+
`)),"fumadocs"}return"fumadocs"}function Ir(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 wr(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function rc(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",accessGate:"none"}}function Rr(e){return e==="cn"?"wechat":"stripe"}async function sc(){let e=new Za;e.name(yr).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ae,"-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 (default, primary) | drizzle (dual-ORM: adds db-drizzle alongside Prisma \u2014 Postgres only)").option("--db <id>","postgres | mysql | sqlite | none \u2014 engine (Prisma provider)").option("--db-host <id>","local | supabase | neon | vercel-postgres | planetscale | railway | aliyun-rds | tencent-cdb | none \u2014 managed-provider (region default: supabase global, local cn)").option("--auth <id>","clerk | betterauth | nextauth | supabase | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <mode-or-ids>","topology shorthand (gateway | direct | custom | none) OR comma-separated provider ids (e.g. openai,anthropic)").option("--deploy <target>","vercel | railway | cloudflare | selfhost").option("--docs <id>","fumadocs | mintlify | docusaurus | nextra | vitepress | none").option("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | none").option("--queue <id>","qstash | bullmq | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").option("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").option("--access-gate <mode>","none | invite (default: none)").option("--cron-jobs <bool>","true | false \u2014 scaffold scheduled cron handlers (default: true)").option("--audit-log <bool>","true | false \u2014 enable /settings/audit-log + arch test (default: true)").option("--api-keys <bool>","true | false \u2014 enable /settings/api-keys page (default: true)").option("--command-palette <bool>","true | false \u2014 enable \u2318K command palette (default: true)").option("--cookie-consent <bool>","true | false \u2014 enable GDPR/CCPA cookie banner (default: true)").option("--legal-pages <bool>","true | false \u2014 enable dynamic /legal/[slug] route (default: true)").option("--china-compliance <bool>","true | false \u2014 enable @nebutra/china-compliance + ICP footer (default: true when --region=cn, otherwise false)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--with-workflows","scaffold workflows/ (inngest + n8n + pusher stubs)").option("--with-python-backend","scaffold backends/python/ (FastAPI stub \u2014 only when TS-by-Default ADR exception applies)").option("--no-install","skip package install").option("--no-git","skip git init").option("-y, --yes","accept all defaults (non-interactive)").option("--dry-run","preview actions without writing files").option("--json","machine-readable output").option("--no-color","disable color output").option("-h, --help","show help"),e.parse(process.argv);let t=e.opts(),[o]=e.args;t.help&&(An(),process.exit(0));let n=!!t.json,r=!!t.dryRun,s=!!t.yes,i=s||!process.stdin.isTTY;if(n||_n(),p(n,{event:"start",version:ae}),!t.pm)try{Rt("pnpm --version",{stdio:"ignore"})}catch{n||process.stderr.write(`
|
|
2953
|
+
${A.red("\u2718")} ${A.bold("pnpm is required")} but was not found on PATH.
|
|
2940
2954
|
|
|
2941
2955
|
The scaffold uses pnpm workspaces + Turborepo. Install pnpm first:
|
|
2942
|
-
${
|
|
2943
|
-
|
|
2944
|
-
Then retry: ${
|
|
2945
|
-
(or pass ${
|
|
2946
|
-
|
|
2947
|
-
`),p(n,{event:"error",code:"PNPM_MISSING"}),process.exit(1)}let c=o??(s?"./my-saas-app":void 0),a;if(c)a=c;else if(i)a="./my-saas-app";else{let g=await
|
|
2948
|
-
`)),process.exit(130)}});a=String(g.name)}let l=
|
|
2949
|
-
`)),process.exit(130)}}):{};E=
|
|
2950
|
-
`))}}let
|
|
2951
|
-
`+
|
|
2952
|
-
`));for(let
|
|
2953
|
-
`);
|
|
2954
|
-
`+
|
|
2955
|
-
`))),
|
|
2956
|
+
${A.cyan("npm i -g pnpm@10")}
|
|
2957
|
+
|
|
2958
|
+
Then retry: ${A.cyan("pnpm dlx create-sailor@latest")}
|
|
2959
|
+
(or pass ${A.dim("--pm=npm")} if you know workspace:* won't resolve in your setup)
|
|
2960
|
+
|
|
2961
|
+
`),p(n,{event:"error",code:"PNPM_MISSING"}),process.exit(1)}let c=o??(s?"./my-saas-app":void 0),a;if(c)a=c;else if(i)a="./my-saas-app";else{let g=await O.group({name:()=>O.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:h=>{if(h.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(A.red(`\u2718 Cancelled
|
|
2962
|
+
`)),process.exit(130)}});a=String(g.name)}let l=de.basename(de.resolve(a)),d=t.pm??tc(),S=!!t.region,C=!!t.auth,k=!!t.payment,$=!!t.ai,ue=!!t.email,b=!!t.storage,m=!!t.monitoring,U=!!t.analytics,kt=!!t.sms,hn=t.i18n!==void 0,E,Ke,G,xt="local",mt,H,F,Q=On(t.socialLogin),gt,Qt,be,$e,ie,W,Nt;if(i){E=wr(t.region),Ke=Er(t.orm);{let Ae=Sr(t.db),j=hr(t.dbHost,E,Ae);G=j.engine,xt=j.hostId}let g=k?t.payment:Rr(E);mt=vr(g),H=_r(g),F=br(t.auth);let h="gateway";if($){let Ae=t.ai?.trim().toLowerCase()??"";kr(Ae)?h=Ae:h="direct"}let L=nn({mode:h,providerIds:$?Pr(t.ai):void 0});gt=L.mode,Qt=L.routing,be=L.providerIds,ie=Ir(t.deploy),W=Cr(t.docs,n),Nt=hn?!!t.i18n:!0}else{let g={};S||(g.region=()=>O.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"})),C||(g.auth=()=>O.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk",hint:"managed, fastest setup"},{value:"betterauth",label:"Better Auth",hint:"self-hosted, modern (2FA / passkeys / RBAC)"},{value:"nextauth",label:"NextAuth (Auth.js v5)",hint:"self-hosted, mature, large ecosystem"},{value:"supabase",label:"Supabase Auth",hint:"managed auth with Supabase storage/realtime ecosystem"},{value:"none",label:"None"}],initialValue:"clerk"})),$||(g.aiMode=()=>O.select({message:"AI topology?",options:[{value:"gateway",label:"Multi-provider AI Gateway / router",hint:"recommended"},{value:"direct",label:"Direct SDK/provider adapters"},{value:"custom",label:"OpenAI-compatible endpoint"},{value:"none",label:"Skip AI"}],initialValue:"gateway"}),g.aiProviders=({results:f})=>{if(f.aiMode!=="direct")return Promise.resolve([]);let _=tn.map(Y=>({value:Y.id,label:`[${Y.category}] ${Y.name}`}));return O.multiselect({message:"Select direct AI provider adapters (expert path)",options:_,initialValues:["openai"],required:!1})},g.customAiName=({results:f})=>f.aiMode==="custom"?O.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),g.customAiBaseUrl=({results:f})=>f.aiMode==="custom"?O.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:_=>{if(_.length===0)return"Base URL is required."}}):Promise.resolve(void 0),g.customAiApiKeyEnv=({results:f})=>f.aiMode==="custom"?O.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0));let h=Object.keys(g).length>0?await O.group(g,{onCancel:()=>{process.stdout.write(A.red(`\u2718 Cancelled
|
|
2963
|
+
`)),process.exit(130)}}):{};E=wr(S?t.region:h.region),Ke=Er(t.orm);{let f=Sr(t.db),_=hr(t.dbHost,E,f);G=_.engine,xt=_.hostId}let L=k?t.payment:Rr(E);mt=vr(L),H=_r(L),F=br(C?t.auth:h.auth);let Ae=h.aiMode==="custom"?{name:h.customAiName??"custom",baseURL:h.customAiBaseUrl??"",apiKeyEnvName:h.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,j=nn({mode:$?t.ai?.trim().toLowerCase()==="none"?"none":"direct":h.aiMode??"gateway",providerIds:$?Pr(t.ai):h.aiProviders,customEndpoint:Ae});gt=j.mode,Qt=j.routing,be=j.providerIds,j.customEndpoint&&($e={name:j.customEndpoint.name,baseURL:j.customEndpoint.baseURL,apiKeyEnvName:j.customEndpoint.apiKeyEnvName}),ie=Ir(t.deploy),W=Cr(t.docs,n),Nt=hn?!!t.i18n:!0}let R=rc(E),Ye=ue?t.email:R.email,qe=oc(b?t.storage:void 0,R.storage),Ge=m?t.monitoring:R.monitoring,He=U?t.analytics:R.analytics,We=kt?t.sms:R.sms,Xe=t.queue??R.queue,ze=t.search??R.search,ft=t.cache??R.cache,Je=t.notifications??R.notifications,Qe=t.webhooks??R.webhooks,yt=t.cms??R.cms,Ze=t.featureFlags??R.featureFlags,et=t.captcha??R.captcha,Tt=t.mcp??R.mcp,St=t.metering??R.metering,tt=t.billingMode??R.billingMode,nt=t.idp??R.idp,ht=t.accessGate==="invite"?"invite":R.accessGate,I=ur({cronJobs:t.cronJobs,auditLog:t.auditLog,apiKeys:t.apiKeys,commandPalette:t.commandPalette,cookieConsent:t.cookieConsent,legalPages:t.legalPages,chinaCompliance:t.chinaCompliance},E),ot=bn([{flag:"queue",provider:Xe},{flag:"search",provider:ze},{flag:"notifications",provider:Je},{flag:"webhooks",provider:Qe},{flag:"feature-flags",provider:Ze},{flag:"captcha",provider:et},{flag:"access-gate",provider:ht}]);function Zt(){for(let g of ot)if(n)p(!0,{event:"warn",step:g.flag,provider:g.provider,packageStatus:g.status,message:me(g.status)});else{let h=rt(g.status);process.stdout.write(A.yellow(`\u26A0 ${g.flag}=${g.provider} ${h} \u2014 ${me(g.status)}
|
|
2964
|
+
`))}}let Pe={region:E,orm:Ke,database:G,payment:mt,aiMode:gt,aiRouting:Qt,aiProviders:be,customAiEndpoint:$e,deployTarget:ie,docs:W,i18n:Nt,email:Ye,storage:qe,monitoring:Ge,analytics:He,sms:We,queue:Xe,search:ze,cache:ft,notifications:Je,webhooks:Qe,cms:yt,featureFlags:Ze,captcha:et,mcp:Tt,metering:St,billingMode:tt,idp:nt,accessGate:ht,cronJobs:I.cronJobs,auditLog:I.auditLog,apiKeys:I.apiKeys,commandPalette:I.commandPalette,cookieConsent:I.cookieConsent,legalPages:I.legalPages,chinaCompliance:I.chinaCompliance},Ot=[["Project name",l],["Region",E],["Auth",F],["Social login",Q.length>0?Q.map(g=>Et.find(h=>h.id===g)?.name??g).join(", "):"none"],["ORM",Ke],["Database",G],["Payment",H],["AI topology",`${gt}${be.length>0?` (${be.join(", ")} seed)`:""}${$e?" + custom endpoint":""}`],["Email",Ye],["Storage",qe],["Monitoring",Ge],["Analytics",He],["SMS",We],["Deploy Target",ie],["Docs Framework",W],["Access gate",ht]];n?Ot.forEach(([g,h],L)=>{p(!0,{event:"step",step:g,value:h,index:L+1,total:Ot.length})}):Ot.forEach(([g,h],L)=>{In({index:L+1,total:Ot.length,label:g,value:h})});let xr={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},En=Date.now();if(r){let g=be.length,h=[`clone template \u2192 ${a}`,"write nebutra.config.json",`prune template (orm=${Ke}, i18n=${Nt})`,`region \u2192 ${E}`,`auth \u2192 ${F==="none"?"skip (remove packages/auth)":`configure ${F}`}`,...Q.length>0?[`social-login \u2192 generate ${Q.length} callback route${Q.length===1?"":"s"} + SocialLoginButtons.tsx (${Q.join(", ")})`]:[],`db \u2192 ${G==="none"?"skip (remove packages/db)":`configure Prisma for ${G}`}`,`payment \u2192 ${H==="none"?"skip (remove packages/billing)":`configure ${H}`}`,...W!=="none"?[`docs \u2192 scaffold apps/docs (${W==="fumadocs"?"fumadocs":`${W} \u2192 fumadocs fallback`})`]:[],...g>0||$e?[`ai-providers \u2192 generate ${gt} registry seed + env (${g}${$e?" + custom":""} provider${g===1&&!$e?"":"s"})`]:[],...Ye!=="none"?[`email \u2192 configure ${Ye}`]:[],...qe!=="none"?[`storage \u2192 configure ${qe}`]:[],...Ge!=="none"?[`monitoring \u2192 configure ${Ge}`]:[],...He!=="none"?[`analytics \u2192 configure ${He}`]:[],...We!=="none"?[`sms \u2192 configure ${We}`]:[],...Xe!=="none"?[`queue \u2192 configure ${Xe}`]:[],...ze!=="none"?[`search \u2192 configure ${ze}`]:[],...ft!=="none"?[`cache \u2192 configure ${ft}`]:[],...Je!=="none"?[`notifications \u2192 configure ${Je}`]:[],...Qe!=="none"?[`webhooks \u2192 configure ${Qe}`]:[],...yt!=="none"?[`cms \u2192 configure ${yt}`]:[],...Ze!=="none"?[`feature-flags \u2192 configure ${Ze}`]:[],...et!=="none"?[`captcha \u2192 configure ${et}`]:[],`mcp \u2192 ${Tt==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${St==="off"?"disabled":St==="auto"?mt!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...tt!=="usage"?[`billing-mode \u2192 ${tt}`]:[],...nt!=="clerk"?[`idp \u2192 ${nt}`]:[],`cron-jobs \u2192 ${I.cronJobs?"enabled":"disabled"}`,`audit-log \u2192 ${I.auditLog?"enabled":"disabled"}`,`api-keys \u2192 ${I.apiKeys?"enabled":"disabled"}`,`command-palette \u2192 ${I.commandPalette?"enabled":"disabled"}`,`cookie-consent \u2192 ${I.cookieConsent?"enabled":"disabled"}`,`legal-pages \u2192 ${I.legalPages?"enabled":"disabled"}`,`china-compliance \u2192 ${I.chinaCompliance?"enabled (@nebutra/china-compliance + ICP footer)":"disabled"}`,`compliance \u2192 inject ${E} 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)",...ie!=="none"?[`deploy \u2192 inject ${ie} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${d} install`,t.git===!1?"skip git init":"run git init"];if(n){for(let L of h)p(!0,{event:"plan",action:L});Zt(),p(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
|
|
2965
|
+
`+A.bold(`Dry run \u2014 planned actions:
|
|
2966
|
+
`));for(let L of h)process.stdout.write(` \u2022 ${L}
|
|
2967
|
+
`);ot.length>0&&(process.stdout.write(`
|
|
2968
|
+
`+A.bold(A.yellow(`Preview-status providers selected:
|
|
2969
|
+
`))),Zt()),process.stdout.write(A.dim(`
|
|
2956
2970
|
No files were written.
|
|
2957
|
-
`))}process.exit(0)}let
|
|
2958
|
-
`+
|
|
2959
|
-
`)),
|
|
2960
|
-
`))),process.exit(130)};process.on("SIGINT",
|
|
2961
|
-
|
|
2962
|
-
`))}
|
|
2963
|
-
`))
|
|
2971
|
+
`))}process.exit(0)}let Nr=async()=>{process.stdout.write(`
|
|
2972
|
+
`+A.red(`\u2718 Cancelled
|
|
2973
|
+
`)),_e.existsSync(a)&&await O.confirm({message:`Cleanup partial install at ${a}?`,initialValue:!0})===!0&&(_e.rmSync(a,{recursive:!0,force:!0}),process.stdout.write(A.dim(` \u2713 Removed ${a}
|
|
2974
|
+
`))),process.exit(130)};process.on("SIGINT",Nr);try{p(n,{event:"step",step:"clone",status:"start"}),await vo(a),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await Oo(a,l),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await qn(a,Pe),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await qo(a,Pe),p(n,{event:"step",step:"prune",status:"ok"});let g=de.join(a,"packages/platform/db/prisma/schema.prisma");if(_e.existsSync(g)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let f=_e.readFileSync(g,"utf-8"),_={auth:F,payment:H,"billing-mode":tt,idp:nt,template:"saas","access-gate":ht},Y=gn(f,_);_e.writeFileSync(g,Y),mn(de.join(de.dirname(g),"migrations"),_),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(f){let _=f instanceof Error?f.message:String(f);p(n,{event:"step",step:"schema-prune",status:"error",error:_})}}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"auth",choice:F,status:"start"}),await Nn(a,F),p(n,{event:"step",step:"auth",choice:F,status:"ok"}),Q.length>0?(p(n,{event:"step",step:"social-login",providers:Q,status:"start"}),await Un(a,Q,F),p(n,{event:"step",step:"social-login",providers:Q,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:G,status:"start"}),await Xn(a,G,l),G!=="none"){let f=Kt(xt);f&&(await zn(a,f,l),p(n,{event:"step",step:"db-host",choice:xt,status:"ok"}))}if(p(n,{event:"step",step:"db",choice:G,status:"ok"}),Ke==="drizzle"){p(n,{event:"step",step:"orm",choice:"drizzle",status:"start"});let f=await Mo(a,"drizzle",G);p(n,{event:"step",step:"orm",choice:"drizzle",status:f.applied?"ok":"skip",...f.reason?{reason:f.reason}:{}})}if(p(n,{event:"step",step:"payment",choice:H,status:"start"}),await Fo(a,H),p(n,{event:"step",step:"payment",choice:H,status:"ok"}),await so(a,Ye,E),n&&p(!0,{event:"step",step:"email",choice:Ye,status:"ok"}),await dr(a,qe,E),n&&p(!0,{event:"step",step:"storage",choice:qe,status:"ok"}),await xo(a,Ge,E),n&&p(!0,{event:"step",step:"monitoring",choice:Ge,status:"ok"}),await kn(a,He,E),n&&p(!0,{event:"step",step:"analytics",choice:He,status:"ok"}),await pr(a,We,E),n&&p(!0,{event:"step",step:"sms",choice:We,status:"ok"}),await Qo(a,Xe,E),n&&p(!0,{event:"step",step:"queue",choice:Xe,status:"ok"}),await ir(a,ze,E),n&&p(!0,{event:"step",step:"search",choice:ze,status:"ok"}),await jn(a,ft,E),n&&p(!0,{event:"step",step:"cache",choice:ft,status:"ok"}),await To(a,Je,E),n&&p(!0,{event:"step",step:"notifications",choice:Je,status:"ok"}),await gr(a,Qe,E),n&&p(!0,{event:"step",step:"webhooks",choice:Qe,status:"ok"}),await $n(a,yt,E),n&&p(!0,{event:"step",step:"cms",choice:yt,status:"ok"}),await mo(a,Ze,E),n&&p(!0,{event:"step",step:"feature-flags",choice:Ze,status:"ok"}),await Bn(a,et,E),n&&p(!0,{event:"step",step:"captcha",choice:et,status:"ok"}),await Co(a,Tt),n&&p(!0,{event:"step",step:"mcp",mode:Tt,status:"ok"}),await wo(a,St,mt),n&&p(!0,{event:"step",step:"metering",mode:St,status:"ok"}),p(n,{event:"step",step:"prune-wave-features",status:"start"}),Go(a,I),p(n,{event:"step",step:"prune-wave-features",status:"ok",toggles:I}),Pe.orm==="prisma"&&Pe.database!=="none"){let f=de.join(a,"packages/platform/db/prisma/schema.prisma");if(_e.existsSync(f)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let _=_e.readFileSync(f,"utf8"),Y={auth:F,payment:H,"billing-mode":tt,idp:nt,template:"saas","access-gate":ht},Tr=gn(_,Y);_e.writeFileSync(f,Tr),mn(de.join(de.dirname(f),"migrations"),Y),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(_){let Y=_ instanceof Error?_.message:String(_);p(n,{event:"step",step:"schema-prune",status:"error",error:Y})}}else p(n,{event:"step",step:"schema-prune",status:"skip"})}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"billing-mode",choice:tt,status:"ok"}),p(n,{event:"step",step:"idp",choice:nt,status:"ok"}),await Yn(a,E),n&&p(!0,{event:"step",step:"compliance",region:E,status:"ok"}),await lo(a),await ar(a,F),await fr(a,{projectName:l,region:E,previewSelections:ot,waveFeatures:I}),Pe.aiMode!=="none"){p(n,{event:"step",step:"ai-providers",status:"start"});let f={providerIds:Pe.aiProviders,customEndpoint:Pe.customAiEndpoint},_=de.join(a,"packages/ai/ai-providers/templates");await $o(a,f,_),p(n,{event:"step",step:"ai-providers",status:"ok"})}else p(n,{event:"step",step:"ai-providers",status:"skip"});p(n,{event:"step",step:"docs",status:"start"}),W!=="none"?(await to(a,{framework:W,projectName:l}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:W,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),ie!=="none"&&await Qn(a,ie),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await ao(a,xr),p(n,{event:"step",step:"env",status:"ok"}),p(n,{event:"step",step:"scaffold-extras",status:"start"});let h=await er(a,{projectName:l,withWorkflows:!!t.withWorkflows,withPythonBackend:!!t.withPythonBackend});p(n,{event:"step",step:"scaffold-extras",status:"ok",applied:h.applied,skipped:h.skipped}),p(n,{event:"step",step:"license",status:"start"});try{let f=Ao(a,{projectName:l,cliVersion:ae});p(n,{event:"step",step:"license",status:"ok",tier:"independent",wrote:f.wrote}),n||process.stdout.write(A.dim(` License: Nebutra-Sailor Independent Developer License (free for \u2264 1 FTE, < $1M ARR).
|
|
2975
|
+
Upstream AGPL preserved as LICENSE-AGPL-REFERENCE.md.
|
|
2976
|
+
`))}catch(f){p(n,{event:"step",step:"license",status:"warn",message:f instanceof Error?f.message:String(f)})}if(t.install!==!1){let f=d==="bun"?"bun install":`${d} install`;n?p(!0,{event:"step",step:"install",pm:d,status:"start"}):process.stdout.write(A.dim(` Installing dependencies with ${d}\u2026
|
|
2977
|
+
`));try{Rt(f,{cwd:a,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(_){let Y=_ instanceof Error?_.message:String(_);n?p(!0,{event:"step",step:"install",status:"error",error:Y}):process.stdout.write(A.yellow(` \u26A0 install failed \u2014 run '${f}' manually.
|
|
2978
|
+
`))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{Rt("git init -q",{cwd:a,stdio:"ignore"}),Rt("git add -A",{cwd:a,stdio:"ignore"}),Rt('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:a,stdio:"ignore"}),p(n,{event:"step",step:"git-init",status:"ok"})}catch(f){let _=f instanceof Error?f.message:String(f);n?p(!0,{event:"step",step:"git-init",status:"error",error:_}):process.stdout.write(A.yellow(` \u26A0 git init skipped \u2014 not fatal.
|
|
2979
|
+
`))}}else p(n,{event:"step",step:"git-init",status:"skip"});let j=Math.max(1,Math.round((Date.now()-En)/1e3));xn({template_version:ae,package_manager:d,region:E,auth:F,payment:H,ai_providers:be,deploy_target:ie,duration_ms:Date.now()-En}),ot.length>0&&Zt(),n?p(!0,{event:"done",status:"ok",elapsedSec:j,targetDir:a,previewSelections:ot,waveFeatures:I}):Pn({elapsedSec:j,targetDir:a,skippedInstall:t.install===!1,previewSelections:ot,waveFeatures:I});try{ec({pkg:{name:yr,version:ae},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(g){let h=g instanceof Error?g.message:String(g);n?p(!0,{event:"error",message:h}):process.stdout.write(A.red(`
|
|
2964
2980
|
\u2718 Failed: ${h}
|
|
2965
|
-
`)),process.exit(1)}}
|
|
2981
|
+
`)),process.exit(1)}}sc().catch(e=>{process.stderr.write(String(e)+`
|
|
2966
2982
|
`),process.exit(1)});
|