create-sailor 1.7.0 → 1.7.1
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 +141 -141
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
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
|
|
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 ec}from"commander";import A from"picocolors";import tc from"update-notifier";import Mr from"cfonts";import Dr from"picocolors";import vn from"fs";import en from"path";import{fileURLToPath as Lr}from"url";function Ur(){try{let t=en.dirname(Lr(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=Ur();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}Mr.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(Dr.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 Fr={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 jr(e){return e?Fr[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=jr(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function Vr(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Pn(e){let t=Vr(),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 I of a){let U=rt(I.status),ue=` ${n} ${I.flag} (${I.provider}) ${U}`;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??{},u=C=>C!==!1,S=[];u(l.apiKeys)&&S.push("Manage API keys at /settings/api-keys"),u(l.auditLog)&&S.push("View audit log at /settings/audit-log"),S.push("Configure webhooks at /settings/webhooks"),u(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 Kr=`Usage: create-sailor [name] [options]
|
|
8
8
|
|
|
9
9
|
Arguments:
|
|
10
10
|
name project directory (default: ./my-saas-app)
|
|
@@ -74,9 +74,9 @@ Examples:
|
|
|
74
74
|
$ npx create-sailor@latest my-app --region=cn --auth=clerk
|
|
75
75
|
$ npx create-sailor@latest my-app --region=hybrid --ai=openai,deepseek
|
|
76
76
|
$ npm create sailor@latest --dry-run --region=cn
|
|
77
|
-
`;function An(){process.stdout.write(
|
|
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
|
|
77
|
+
`;function An(){process.stdout.write(Kr)}import Lt from"picocolors";function In(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Br(e){let t=In()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return In()?`${Lt.dim(o)} ${Lt.bold(n)} ${Lt.dim(t)} ${Lt.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function Cn(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:[]}],bc=tn.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var $r=["openai","anthropic","google"],Yr=["openai"];function nn(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...$r];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:[...Yr];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 K 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:""}],Ic=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 qr(e){st.mkdirSync(e,{recursive:!0})}function Z(e,t){qr(K.dirname(e)),st.writeFileSync(e,t)}function Ie(e,t){let o=K.join(e,".env.example");st.existsSync(o)?st.appendFileSync(o,`
|
|
79
|
+
`+t):st.writeFileSync(o,t)}function Gr(e){let t=`"use client";
|
|
80
80
|
/**
|
|
81
81
|
* PostHog browser SDK \u2014 lazy-initialized on first access.
|
|
82
82
|
*/
|
|
@@ -159,11 +159,11 @@ export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
|
|
|
159
159
|
|
|
160
160
|
return <>{children}</>;
|
|
161
161
|
}
|
|
162
|
-
`;Z(
|
|
162
|
+
`;Z(K.join(e,"src","lib","analytics","posthog.client.ts"),t),Z(K.join(e,"src","lib","analytics","posthog.server.ts"),o),Z(K.join(e,"src","components","analytics","AnalyticsProvider.tsx"),n)}function Hr(){return`# PostHog \u2014 product analytics
|
|
163
163
|
POSTHOG_KEY=
|
|
164
164
|
NEXT_PUBLIC_POSTHOG_KEY=
|
|
165
165
|
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
|
166
|
-
`}function
|
|
166
|
+
`}function Wr(e){Z(K.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
|
|
167
167
|
/**
|
|
168
168
|
* Plausible script tag \u2014 lightweight, privacy-friendly analytics.
|
|
169
169
|
*/
|
|
@@ -183,10 +183,10 @@ export function PlausibleScript() {
|
|
|
183
183
|
/>
|
|
184
184
|
);
|
|
185
185
|
}
|
|
186
|
-
`)}function
|
|
186
|
+
`)}function Xr(){return`# Plausible \u2014 privacy-friendly analytics
|
|
187
187
|
NEXT_PUBLIC_PLAUSIBLE_DOMAIN=
|
|
188
188
|
NEXT_PUBLIC_PLAUSIBLE_SRC=https://plausible.io/js/script.js
|
|
189
|
-
`}function
|
|
189
|
+
`}function zr(e){Z(K.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
|
|
190
190
|
/**
|
|
191
191
|
* Umami analytics \u2014 self-hosted OR umami.is cloud.
|
|
192
192
|
*/
|
|
@@ -206,10 +206,10 @@ export function UmamiScript() {
|
|
|
206
206
|
/>
|
|
207
207
|
);
|
|
208
208
|
}
|
|
209
|
-
`)}function
|
|
209
|
+
`)}function Jr(){return`# Umami \u2014 self-hostable analytics
|
|
210
210
|
NEXT_PUBLIC_UMAMI_WEBSITE_ID=
|
|
211
211
|
NEXT_PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
|
|
212
|
-
`}function
|
|
212
|
+
`}function Qr(e){let t=`"use client";
|
|
213
213
|
import mixpanel from "mixpanel-browser";
|
|
214
214
|
|
|
215
215
|
let initialized = false;
|
|
@@ -248,10 +248,10 @@ export function trackServer(
|
|
|
248
248
|
if (!c) return;
|
|
249
249
|
c.track(event, { distinct_id: distinctId, ...properties });
|
|
250
250
|
}
|
|
251
|
-
`;Z(
|
|
251
|
+
`;Z(K.join(e,"src","lib","analytics","mixpanel.client.ts"),t),Z(K.join(e,"src","lib","analytics","mixpanel.server.ts"),o)}function Zr(){return`# Mixpanel \u2014 product analytics
|
|
252
252
|
MIXPANEL_TOKEN=
|
|
253
253
|
NEXT_PUBLIC_MIXPANEL_TOKEN=
|
|
254
|
-
`}function
|
|
254
|
+
`}function es(e){Z(K.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
|
|
255
255
|
/**
|
|
256
256
|
* \u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji \u2014 hm.js \u57CB\u70B9\u811A\u672C.
|
|
257
257
|
*/
|
|
@@ -277,9 +277,9 @@ var _hmt = _hmt || [];
|
|
|
277
277
|
/>
|
|
278
278
|
);
|
|
279
279
|
}
|
|
280
|
-
`)}function
|
|
280
|
+
`)}function ts(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
|
|
281
281
|
NEXT_PUBLIC_BAIDU_STATS_ID=
|
|
282
|
-
`}function
|
|
282
|
+
`}function ns(e){Z(K.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
|
|
283
283
|
/**
|
|
284
284
|
* \u795E\u7B56\u5206\u6790 (Sensors Analytics) \u2014 sa-sdk-javascript \u5C01\u88C5.
|
|
285
285
|
*/
|
|
@@ -307,10 +307,10 @@ export function initSensors(): void {
|
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
export { sensors };
|
|
310
|
-
`)}function
|
|
310
|
+
`)}function os(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
|
|
311
311
|
NEXT_PUBLIC_SENSORS_SERVER_URL=
|
|
312
312
|
NEXT_PUBLIC_SENSORS_APP_JS_URL=
|
|
313
|
-
`}function
|
|
313
|
+
`}function rs(e){Z(K.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
|
|
314
314
|
/**
|
|
315
315
|
* GrowingIO CDP \u2014 inline snippet installer.
|
|
316
316
|
*/
|
|
@@ -335,11 +335,11 @@ gdp("send");
|
|
|
335
335
|
/>
|
|
336
336
|
);
|
|
337
337
|
}
|
|
338
|
-
`)}function
|
|
338
|
+
`)}function ss(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
|
|
339
339
|
NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
|
|
340
|
-
`}async function kn(e,t,o="global"){let n=Rn(t);if(!n||n.id==="none")return;let r=
|
|
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
|
|
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),
|
|
340
|
+
`}async function kn(e,t,o="global"){let n=Rn(t);if(!n||n.id==="none")return;let r=K.join(e,"apps","web");if(!st.existsSync(r))return;let s=n.id;try{switch(s){case"posthog":Gr(r),Ie(e,Hr());return;case"plausible":Wr(r),Ie(e,Xr());return;case"umami":zr(r),Ie(e,Jr());return;case"mixpanel":Qr(r),Ie(e,Zr());return;case"baidu":es(r),Ie(e,ts());return;case"sensors":ns(r),Ie(e,os());return;case"growingio":rs(r),Ie(e,ss());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 is="https://analytics.nebutra.com";function as(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function xn(e,t={}){as(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??is},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 cs(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),cs(e,`
|
|
343
343
|
## Auth
|
|
344
344
|
|
|
345
345
|
Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth, Supabase).
|
|
@@ -363,7 +363,7 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=
|
|
|
363
363
|
SUPABASE_URL=
|
|
364
364
|
SUPABASE_ANON_KEY=
|
|
365
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"}],
|
|
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"}],ps=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)ps.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import we from"fs";import Ce from"path";function ls(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
|
|
367
367
|
// Generated by create-sailor \u2014 OAuth callback for ${e.name}
|
|
368
368
|
// Primary auth provider: ${t}
|
|
369
369
|
// Docs: ${e.docs}`,n={wechat:` const tokenRes = await fetch(
|
|
@@ -488,7 +488,7 @@ ${n[e.id]}
|
|
|
488
488
|
void state;
|
|
489
489
|
return NextResponse.redirect(new URL("/dashboard", req.url));
|
|
490
490
|
}
|
|
491
|
-
`}function
|
|
491
|
+
`}function ds(e){return`"use client";
|
|
492
492
|
|
|
493
493
|
/**
|
|
494
494
|
* SocialLoginButtons \u2014 generated by create-sailor.
|
|
@@ -531,23 +531,23 @@ export function SocialLoginButtons() {
|
|
|
531
531
|
</div>
|
|
532
532
|
);
|
|
533
533
|
}
|
|
534
|
-
`}function Ln(e){we.mkdirSync(e,{recursive:!0})}function
|
|
535
|
-
`+t):we.writeFileSync(o,t)}function
|
|
534
|
+
`}function Ln(e){we.mkdirSync(e,{recursive:!0})}function us(e,t){let o=Ce.join(e,".env.example");we.existsSync(o)?we.appendFileSync(o,`
|
|
535
|
+
`+t):we.writeFileSync(o,t)}function ms(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
536
536
|
`);return`${t}
|
|
537
537
|
${o}
|
|
538
|
-
`}async function Un(e,t,o){if(!t||t.length===0)return;let n=
|
|
538
|
+
`}async function Un(e,t,o){if(!t||t.length===0)return;let n=Ce.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 u=Tn(l);u&&s.push(u)}if(s.length===0)return;for(let l of s)us(e,ms(l));let i=Ce.join(n,"src","app","api","auth","callback");for(let l of s){let u=Ce.join(i,l.id);Ln(u);let S=Ce.join(u,"route.ts");we.writeFileSync(S,ls(l,o))}let c=Ce.join(n,"src","components","auth");Ln(c);let a=Ce.join(c,"SocialLoginButtons.tsx");we.writeFileSync(a,ds(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 Vc=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
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(`
|
|
540
540
|
`)?"":`
|
|
541
541
|
`;ee.appendFileSync(n,`${c}${s}
|
|
542
|
-
`)}var
|
|
543
|
-
`);it.appendFileSync(o,s)}function
|
|
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&&(
|
|
542
|
+
`)}var gs=["design","iam","commerce","integrations","platform","ops","ai"];function Re(e,t){for(let n of gs){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 fs(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 ys(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&&(fs(e,r),ys(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 zc=jt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Kn(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 Kt from"fs";import Ss 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 Bn(e){return Vt.find(t=>t.id===e)}var tp=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=Bn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${Vt.map(s=>s.id).join(", ")}`);let r=Ss.join(e,"apps","studio");if(n.id==="none"){X(e,"sanity"),Kt.existsSync(r)&&Kt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(X(e,"sanity"),Kt.existsSync(r)&&Kt.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 hs=N.join("apps","web"),on=N.join("src","components","compliance"),vt=N.join("src","app","[locale]");function oe(e){return N.join(e,hs)}function Es(e){T.mkdirSync(e,{recursive:!0})}function z(e,t){Es(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
545
|
`)[0]??""))return;T.appendFileSync(o,`
|
|
546
546
|
`+t+`
|
|
547
547
|
`)}else T.writeFileSync(o,t+`
|
|
548
548
|
`)}var _t=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
|
|
549
549
|
> Consult a qualified lawyer in every jurisdiction you operate in before publishing.
|
|
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`,
|
|
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`,vs=`import Link from "next/link";
|
|
551
551
|
import { IcpFooter } from "@/components/compliance/IcpFooter";
|
|
552
552
|
import { PublicSecurityFooter } from "@/components/compliance/PublicSecurityFooter";
|
|
553
553
|
|
|
@@ -598,7 +598,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
598
598
|
</footer>
|
|
599
599
|
);
|
|
600
600
|
}
|
|
601
|
-
`,
|
|
601
|
+
`,_s=`export function IcpFooter() {
|
|
602
602
|
const icp = process.env.NEXT_PUBLIC_ICP_BEIAN;
|
|
603
603
|
if (!icp) return null;
|
|
604
604
|
return (
|
|
@@ -612,7 +612,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
612
612
|
</a>
|
|
613
613
|
);
|
|
614
614
|
}
|
|
615
|
-
`,
|
|
615
|
+
`,bs=`export function PublicSecurityFooter() {
|
|
616
616
|
const psb = process.env.NEXT_PUBLIC_PSB_BEIAN;
|
|
617
617
|
const psbCode = process.env.NEXT_PUBLIC_PSB_CODE;
|
|
618
618
|
if (!psb) return null;
|
|
@@ -629,7 +629,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
629
629
|
</a>
|
|
630
630
|
);
|
|
631
631
|
}
|
|
632
|
-
`,
|
|
632
|
+
`,Ps=`"use client";
|
|
633
633
|
|
|
634
634
|
import { useCallback, useEffect, useState } from "react";
|
|
635
635
|
|
|
@@ -856,7 +856,7 @@ function CategoryRow({ id, title, description, checked, disabled, onChange }: Ca
|
|
|
856
856
|
</label>
|
|
857
857
|
);
|
|
858
858
|
}
|
|
859
|
-
`,
|
|
859
|
+
`,As=`interface AigcDisclaimerProps {
|
|
860
860
|
className?: string;
|
|
861
861
|
}
|
|
862
862
|
|
|
@@ -876,7 +876,7 @@ export function AigcDisclaimer({ className }: AigcDisclaimerProps) {
|
|
|
876
876
|
</div>
|
|
877
877
|
);
|
|
878
878
|
}
|
|
879
|
-
`,
|
|
879
|
+
`,Is=`---
|
|
880
880
|
title: Privacy Policy / \u9690\u79C1\u653F\u7B56
|
|
881
881
|
description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal information.
|
|
882
882
|
lastUpdated: 2026-01-01
|
|
@@ -1140,7 +1140,7 @@ conflict-of-laws principles. Disputes shall be resolved in the competent courts
|
|
|
1140
1140
|
## 11. Contact / \u8054\u7CFB\u65B9\u5F0F
|
|
1141
1141
|
|
|
1142
1142
|
{{COMPANY_NAME}} \xB7 {{COMPANY_ADDRESS}} \xB7 {{COMPANY_CONTACT_EMAIL}}
|
|
1143
|
-
`,
|
|
1143
|
+
`,ws=`---
|
|
1144
1144
|
title: AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
|
|
1145
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
|
|
1146
1146
|
lastUpdated: 2026-01-01
|
|
@@ -1222,7 +1222,7 @@ human professional.
|
|
|
1222
1222
|
|
|
1223
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
|
|
1224
1224
|
\u7528\u4E8E\u533B\u7597\u3001\u6CD5\u5F8B\u3001\u91D1\u878D\u6216\u5B89\u5168\u6538\u5173\u7684\u51B3\u7B56\u3002
|
|
1225
|
-
`,
|
|
1225
|
+
`,Rs=`---
|
|
1226
1226
|
title: Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
|
|
1227
1227
|
description: Notice of cross-border transfer of personal information, per PIPL.
|
|
1228
1228
|
lastUpdated: 2026-01-01
|
|
@@ -1287,7 +1287,7 @@ Refusal may limit your ability to use features that rely on overseas services.
|
|
|
1287
1287
|
- \u4F20\u8F93\u4E2D\u52A0\u5BC6 (TLS 1.2+) \u53CA\u9759\u6001\u52A0\u5BC6 (AES-256)\u3002
|
|
1288
1288
|
- \u5408\u540C\u6761\u6B3E\u8981\u6C42\u5883\u5916\u63A5\u6536\u65B9\u63D0\u4F9B\u7B49\u540C\u4E8E PIPL \u7684\u4FDD\u62A4\u3002
|
|
1289
1289
|
- \u8BBF\u95EE\u63A7\u5236\u3001\u5BA1\u8BA1\u65E5\u5FD7\u548C\u8FDD\u89C4\u901A\u77E5\u7A0B\u5E8F\u3002
|
|
1290
|
-
`,
|
|
1290
|
+
`,ks=`---
|
|
1291
1291
|
title: Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
|
|
1292
1292
|
description: Itemized list of personal information collected, per PIPL Article 17.
|
|
1293
1293
|
lastUpdated: 2026-01-01
|
|
@@ -1329,26 +1329,26 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
|
|
|
1329
1329
|
**{{COMPANY_CONTACT_EMAIL}}**.
|
|
1330
1330
|
|
|
1331
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
|
|
1332
|
-
`;async function
|
|
1333
|
-
`))}async function
|
|
1334
|
-
`))}async function
|
|
1335
|
-
`))}async function
|
|
1336
|
-
`))}async function
|
|
1337
|
-
`)}import
|
|
1338
|
-
`+t):
|
|
1332
|
+
`;async function xs(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,"src","components","compliance","Footer.tsx");z(n,vs);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 Ns(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,"src","components","compliance","CookieBanner.tsx");z(n,Ps)}async function Ts(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,vt,"privacy","page.mdx");z(n,Is)}async function Os(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 Ls(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,on,"IcpFooter.tsx");z(o,_s),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 Us(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,on,"PublicSecurityFooter.tsx");z(o,bs),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 Ms(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,on,"AigcDisclaimer.tsx");z(o,As),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 Ds(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"aigc-disclosure","page.mdx");z(o,ws)}async function Fs(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"cross-border-data","page.mdx");z(o,Rs)}async function js(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"pii-collection","page.mdx");z(o,ks)}async function Yn(e,t){try{await xs(e,t),await Ns(e,t),await Ts(e,t),await Os(e,t),(t==="cn"||t==="hybrid")&&(await Ls(e),await Us(e),await Ms(e),await Ds(e),await Fs(e),await js(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 Vs from"fs";import Ks from"path";async function qn(e,t){let o=Ks.join(e,"nebutra.config.json");Vs.writeFileSync(o,JSON.stringify(t,null,2)+`
|
|
1337
|
+
`)}import R 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 Bt(e){return sn.find(t=>t.id===e)}function Gn(e){return e==="cn"||e==="hybrid"?"local":"supabase"}function Bs(e){R.existsSync(e)&&R.rmSync(e,{recursive:!0,force:!0})}function Hn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function $s(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 Ys(e,t){let o=ke.join(e,".env.example");R.existsSync(o)?R.appendFileSync(o,`
|
|
1338
|
+
`+t):R.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",Ys(e,`# Database (${t})
|
|
1339
1339
|
DATABASE_URL="${s}"
|
|
1340
|
-
`),!
|
|
1340
|
+
`),!R.existsSync(r))return;let i=R.readFileSync(r,"utf8"),c=i;t==="mysql"?(c=Hn(c,"mysql"),c=Wn(c)):t==="sqlite"&&(c=Hn(c,"sqlite"),c=$s(c),c=Wn(c)),c!==i&&R.writeFileSync(r,c)}function qs(e){let t=ke.join(e,".env.example");return R.existsSync(t)?R.readFileSync(t,"utf8"):""}function Gs(e,t,o,n){let r=ke.join(e,".env.example"),s=qs(e),i=n?`# ${n}
|
|
1341
1341
|
${t}="${o}"
|
|
1342
1342
|
`:`${t}="${o}"
|
|
1343
|
-
`,c=new RegExp(`^\\s*${t}\\s*=.*$`,"m");if(c.test(s)){
|
|
1344
|
-
${i}`):
|
|
1343
|
+
`,c=new RegExp(`^\\s*${t}\\s*=.*$`,"m");if(c.test(s)){R.writeFileSync(r,s.replace(c,`${t}="${o}"`));return}s?R.appendFileSync(r,`
|
|
1344
|
+
${i}`):R.writeFileSync(r,i)}function Hs(e,t){let o=ke.join(e,"packages","platform","db","prisma","schema.prisma");if(!R.existsSync(o))return;let n=R.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(`
|
|
1345
1345
|
`),a=n.replace(r,`$1
|
|
1346
|
-
${c}$2`);
|
|
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);
|
|
1348
|
-
`+t):Te.writeFileSync(o,t)}function
|
|
1346
|
+
${c}$2`);R.writeFileSync(o,a)}function Ws(e){let t=ke.join(e,"packages","platform","db","prisma","schema.prisma");if(!R.existsSync(t))return;let o=R.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)&&R.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);Gs(e,n.name,r,n.comment)}t.prismaDatasourceExtras&&t.prismaDatasourceExtras.length>0&&Hs(e,t.prismaDatasourceExtras),t.keepDirectUrl&&Ws(e)}}import at from"fs";import $ from"path";import{fileURLToPath as Xs}from"url";var zs=Xs(import.meta.url),Jn=$.dirname(zs);function Js(){let e=[$.join(Jn,"..","templates","deploy"),$.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=Js();t==="vercel"?await at.promises.copyFile($.join(o,"vercel.json"),$.join(e,"vercel.json")):t==="railway"?await at.promises.copyFile($.join(o,"railway.toml"),$.join(e,"railway.toml")):t==="cloudflare"?await at.promises.copyFile($.join(o,"wrangler.toml"),$.join(e,"wrangler.toml")):t==="selfhost"&&(await at.promises.copyFile($.join(o,"docker-compose.yml"),$.join(e,"docker-compose.yml")),await at.promises.copyFile($.join(o,"Dockerfile.web"),$.join(e,"Dockerfile.web")))}import ge from"fs";import xe from"path";import{fileURLToPath as Qs}from"url";var Zs=Qs(import.meta.url),Zn=xe.dirname(Zs),ei=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|vue)$/,eo=["fumadocs","nextra","mintlify","docusaurus","vitepress"];function ti(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=ti(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(ei.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 wp=$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 ni(e,t){let o=Ne.join(e,".env.example");Te.existsSync(o)?Te.appendFileSync(o,`
|
|
1348
|
+
`+t):Te.writeFileSync(o,t)}function oi(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
1349
1349
|
`);return`${t}
|
|
1350
1350
|
${o}
|
|
1351
|
-
`}var
|
|
1351
|
+
`}var ri=`/**
|
|
1352
1352
|
* Public inputs accepted by the \`sendEmail\` wrapper.
|
|
1353
1353
|
* Keep the surface minimal \u2014 individual providers may accept more, but
|
|
1354
1354
|
* consumers should code against this shape for portability.
|
|
@@ -1368,7 +1368,7 @@ export interface SendEmailResult {
|
|
|
1368
1368
|
/** Raw provider response \u2014 useful for debugging, not a stable contract. */
|
|
1369
1369
|
raw?: unknown;
|
|
1370
1370
|
}
|
|
1371
|
-
`;function
|
|
1371
|
+
`;function si(){return`/**
|
|
1372
1372
|
* @${Oe.slice(1)} \u2014 Resend transactional email wrapper.
|
|
1373
1373
|
*
|
|
1374
1374
|
* Docs: https://resend.com/docs
|
|
@@ -1407,7 +1407,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1407
1407
|
}
|
|
1408
1408
|
|
|
1409
1409
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1410
|
-
`}function
|
|
1410
|
+
`}function ii(){return`/**
|
|
1411
1411
|
* @${Oe.slice(1)} \u2014 Postmark transactional email wrapper.
|
|
1412
1412
|
*
|
|
1413
1413
|
* Docs: https://postmarkapp.com/developer
|
|
@@ -1445,7 +1445,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1445
1445
|
}
|
|
1446
1446
|
|
|
1447
1447
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1448
|
-
`}function
|
|
1448
|
+
`}function ai(){return`/**
|
|
1449
1449
|
* @${Oe.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
|
|
1450
1450
|
*
|
|
1451
1451
|
* Docs: https://docs.aws.amazon.com/ses
|
|
@@ -1501,7 +1501,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1501
1501
|
}
|
|
1502
1502
|
|
|
1503
1503
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1504
|
-
`}function
|
|
1504
|
+
`}function ci(){return`/**
|
|
1505
1505
|
* @${Oe.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
|
|
1506
1506
|
*
|
|
1507
1507
|
* Docs: https://help.aliyun.com/product/29412.html
|
|
@@ -1551,7 +1551,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1551
1551
|
}
|
|
1552
1552
|
|
|
1553
1553
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1554
|
-
`}function
|
|
1554
|
+
`}function pi(){return`/**
|
|
1555
1555
|
* @${Oe.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
|
|
1556
1556
|
*
|
|
1557
1557
|
* Docs: https://cloud.tencent.com/document/product/1288
|
|
@@ -1599,7 +1599,7 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1599
1599
|
}
|
|
1600
1600
|
|
|
1601
1601
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1602
|
-
`}function
|
|
1602
|
+
`}function li(){return`/**
|
|
1603
1603
|
* @${Oe.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
|
|
1604
1604
|
*
|
|
1605
1605
|
* Docs: https://qiye.163.com/help
|
|
@@ -1637,9 +1637,9 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1637
1637
|
}
|
|
1638
1638
|
|
|
1639
1639
|
export type { SendEmailInput, SendEmailResult } from "./types";
|
|
1640
|
-
`}function
|
|
1641
|
-
`}}function
|
|
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"),
|
|
1640
|
+
`}function di(e){switch(e){case"resend":return si();case"postmark":return ii();case"ses":return ai();case"aliyun-dm":return ci();case"tencent-ses":return pi();case"netease":return li();case"none":return`export {};
|
|
1641
|
+
`}}function ui(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"),ui(n)),an(Ne.join(s,"types.ts"),ri),an(Ne.join(s,"index.ts"),di(n.id)),ni(e,oi(n))}import Yt from"fs";import io from"path";async function ao(e,t){let o=`# Automatically injected by create-sailor
|
|
1643
1643
|
DATABASE_URL="${String(t.databaseUrl)}"
|
|
1644
1644
|
|
|
1645
1645
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
|
|
@@ -1647,21 +1647,21 @@ CLERK_SECRET_KEY="${String(t.clerkSecret)}"
|
|
|
1647
1647
|
|
|
1648
1648
|
NEXT_PUBLIC_SITE_URL="http://localhost:3000"
|
|
1649
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
|
|
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 mi(e){return po.randomBytes(e).toString("hex")}function gi(){return{AUTH_SECRET:Le(32),NEXTAUTH_SECRET:Le(32),BETTER_AUTH_SECRET:Le(32),JWT_SECRET:Le(32),WEBHOOK_SECRET:mi(16),ENCRYPTION_KEY:Le(32),API_SECRET_KEY:Le(32),SESSION_SECRET:Le(32)}}function fi(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function yi(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=fi(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=gi(),i=bt.existsSync(o)?bt.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))i=yi(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 Vp=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 D from"fs";import Si from"os";import fe from"path";import hi from"ignore";var Ei={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 vi(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function _i(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function So(e){return/^[0-9a-f]{7,40}$/i.test(e)}function bi(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 Pi(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=bi(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=D.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 Ai(e){let t=fe.join(e,".templateignore");if(!D.existsSync(t))return;let o=D.readFileSync(t,"utf8"),n=hi().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{D.existsSync(l)&&D.rmSync(l,{recursive:!0,force:!0})}catch{}}try{D.existsSync(t)&&D.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)`);D.writeFileSync(t,n);let r=D.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=D.readdirSync(e);for(let o of t)D.rmSync(fe.join(e,o),{recursive:!0,force:!0})}catch{}}async function Ii(e,t){let o=D.mkdtempSync(fe.join(Si.tmpdir(),"create-sailor-")),n=fe.join(o,"template.tar.gz");try{let r=await Pi(e.repo,e.ref);await go(_i(e.repo,r),n),fo(n,t)}catch(r){if(!e.allowMutableFallback)throw r;Eo(t),await go(vi(e.repo,e.ref),n),fo(n,t)}finally{D.rmSync(o,{recursive:!0,force:!0})}}async function vo(e){D.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let s=Ei[r];try{if(await Ii(s,e),s.applyIgnore)try{Ai(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"}
|
|
1651
1651
|
|
|
1652
1652
|
Ensure you have internet access and 'tar' installed.
|
|
1653
|
-
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import{createHmac as
|
|
1654
|
-
`),o.push(`${
|
|
1653
|
+
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import{createHmac as wi,randomBytes as Ri}from"crypto";import J from"fs";import re from"path";import{fileURLToPath as ki}from"url";var Ci=[{id:"v1",key:"nebutra-sailor:scaffold-marker:v1"}];function _o(){let e=Ci[0];if(!e)throw new Error("license-signing-keys: registry is empty \u2014 at least one key is required.");return e}var xi=ki(import.meta.url),bo=re.dirname(xi),Po="scaffold-meta.json",Ao=".nebutra";function Ni(e){if(e)return e;let t=[re.join(bo,"..","templates"),re.join(bo,"..","..","templates")];for(let o of t)if(J.existsSync(o))return o;return t[0]}function Ti(e,t){let o=`${e.cliVersion}|${e.scaffoldedAt}|${e.projectName}|${e.nonce}`;return wi("sha256",t).update(o).digest("hex")}function Io(e,t){let o=[],n=Ni(t.templatesRoot),r=re.join(e,"LICENSE");if(J.existsSync(r)){let I=J.readFileSync(r,"utf-8").slice(0,256);/GNU AFFERO GENERAL PUBLIC LICENSE/i.test(I)&&(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=Ri(12).toString("hex"),a=_o(),l=Ti({cliVersion:t.cliVersion,scaffoldedAt:i,projectName:t.projectName,nonce:c},a.key),u={schemaVersion:1,cliVersion:t.cliVersion,scaffoldedAt:i,projectName:t.projectName,nonce:c,signature:l,signingKeyId:a.id,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"}},S=re.join(e,Ao);J.mkdirSync(S,{recursive:!0}),J.writeFileSync(re.join(S,Po),`${JSON.stringify(u,null,2)}
|
|
1654
|
+
`),o.push(`${Ao}/${Po}`);let C=re.join(e,"README.md");if(J.existsSync(C)){let I=J.readFileSync(C,"utf-8");I.includes("Nebutra-Sailor Independent Developer License")||(J.writeFileSync(C,`> **License notice:** scaffolded by \`create-sailor\` under the
|
|
1655
1655
|
> [Nebutra-Sailor Independent Developer License](./LICENSE). Free for
|
|
1656
1656
|
> individuals/OPC with \u2264 1 FTE and < $1M ARR; upgrade for larger teams at
|
|
1657
1657
|
> https://nebutra.com/get-license. The upstream repository remains
|
|
1658
1658
|
> AGPL-3.0 \u2014 see \`LICENSE-AGPL-REFERENCE.md\`.
|
|
1659
1659
|
|
|
1660
|
-
`+
|
|
1661
|
-
`);Ue.appendFileSync(n,i)}}}import Pt from"fs";import
|
|
1662
|
-
`);Pt.appendFileSync(s,a)}}import ce from"fs";import
|
|
1663
|
-
`)}function se(e,t){
|
|
1664
|
-
`+t):ce.writeFileSync(o,t)}function
|
|
1660
|
+
`+I),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 wo from"path";async function Ro(e,t,o){let n=wo.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=wo.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 F from"path";var ko=[{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:""}],dl=ko.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function xo(e){return ko.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 Oi(e){ce.mkdirSync(e,{recursive:!0})}function ln(e,t){let o=F.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){Oi(F.dirname(e)),ce.writeFileSync(e,t)}function At(e,t){let o=F.join(e,".env.example");ce.existsSync(o)?ce.appendFileSync(o,`
|
|
1664
|
+
`+t):ce.writeFileSync(o,t)}function Li(e){let t=`import * as Sentry from "@sentry/nextjs";
|
|
1665
1665
|
|
|
1666
1666
|
Sentry.init({
|
|
1667
1667
|
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
@@ -1704,14 +1704,14 @@ export async function register() {
|
|
|
1704
1704
|
}
|
|
1705
1705
|
|
|
1706
1706
|
export { captureRequestError as onRequestError } from "@sentry/nextjs";
|
|
1707
|
-
`;se(
|
|
1707
|
+
`;se(F.join(e,"sentry.client.config.ts"),t),se(F.join(e,"sentry.server.config.ts"),o),se(F.join(e,"sentry.edge.config.ts"),n),se(F.join(e,"instrumentation.ts"),r)}function Ui(){return`# Sentry \u2014 error tracking + performance monitoring
|
|
1708
1708
|
# Get your DSN from https://sentry.io/settings/projects/<project>/keys/
|
|
1709
1709
|
SENTRY_DSN=
|
|
1710
1710
|
NEXT_PUBLIC_SENTRY_DSN=
|
|
1711
1711
|
SENTRY_ORG=
|
|
1712
1712
|
SENTRY_PROJECT=
|
|
1713
1713
|
SENTRY_AUTH_TOKEN=
|
|
1714
|
-
`}function
|
|
1714
|
+
`}function Mi(e){let t=`/**
|
|
1715
1715
|
* Next.js instrumentation hook \u2014 wires Datadog APM (dd-trace) into Node runtime.
|
|
1716
1716
|
* Edge runtime is not supported by dd-trace; only nodejs is initialized.
|
|
1717
1717
|
*/
|
|
@@ -1759,7 +1759,7 @@ export function initDatadogRum(): void {
|
|
|
1759
1759
|
});
|
|
1760
1760
|
initialized = true;
|
|
1761
1761
|
}
|
|
1762
|
-
`;se(
|
|
1762
|
+
`;se(F.join(e,"instrumentation.ts"),t),se(F.join(e,"src","lib","monitoring","datadog-rum.ts"),o)}function Di(){return`# Datadog \u2014 APM + RUM
|
|
1763
1763
|
# Server APM (dd-trace)
|
|
1764
1764
|
DD_API_KEY=
|
|
1765
1765
|
DD_APP_KEY=
|
|
@@ -1774,7 +1774,7 @@ NEXT_PUBLIC_DD_SITE=datadoghq.com
|
|
|
1774
1774
|
NEXT_PUBLIC_DD_SERVICE=sailor-web
|
|
1775
1775
|
NEXT_PUBLIC_DD_ENV=production
|
|
1776
1776
|
NEXT_PUBLIC_DD_VERSION=
|
|
1777
|
-
`}function
|
|
1777
|
+
`}function Fi(e){let t=`/**
|
|
1778
1778
|
* Bugsnag server-side initialization.
|
|
1779
1779
|
* Import this once at the top of your server entrypoint or a shared init module.
|
|
1780
1780
|
*/
|
|
@@ -1823,11 +1823,11 @@ export function getBugsnagErrorBoundary() {
|
|
|
1823
1823
|
errorBoundary = plugin.createErrorBoundary(React) as typeof errorBoundary;
|
|
1824
1824
|
return errorBoundary;
|
|
1825
1825
|
}
|
|
1826
|
-
`;se(
|
|
1826
|
+
`;se(F.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),se(F.join(e,"src","lib","monitoring","bugsnag.client.tsx"),o)}function ji(){return`# Bugsnag \u2014 error tracking
|
|
1827
1827
|
BUGSNAG_API_KEY=
|
|
1828
1828
|
NEXT_PUBLIC_BUGSNAG_API_KEY=
|
|
1829
1829
|
APP_VERSION=
|
|
1830
|
-
`}function
|
|
1830
|
+
`}function Vi(e){se(F.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
|
|
1831
1831
|
/**
|
|
1832
1832
|
* \u963F\u91CC\u4E91 ARMS (Application Real-time Monitoring Service) browser agent.
|
|
1833
1833
|
* Injects the official JS agent via next/script.
|
|
@@ -1848,11 +1848,11 @@ export function ArmsScript() {
|
|
|
1848
1848
|
/>
|
|
1849
1849
|
);
|
|
1850
1850
|
}
|
|
1851
|
-
`)}function
|
|
1851
|
+
`)}function Ki(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
|
|
1852
1852
|
ALIYUN_ARMS_LICENSE_KEY=
|
|
1853
1853
|
ALIYUN_ARMS_APP_NAME=
|
|
1854
1854
|
NEXT_PUBLIC_ARMS_PID=
|
|
1855
|
-
`}function Bi(e){se(
|
|
1855
|
+
`}function Bi(e){se(F.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
|
|
1856
1856
|
/**
|
|
1857
1857
|
* \u542C\u4E91 Browser Agent (\u524D\u7AEF\u6027\u80FD\u76D1\u63A7).
|
|
1858
1858
|
* Docs: https://www.tingyun.com/docs
|
|
@@ -1870,12 +1870,12 @@ export function TingYunScript() {
|
|
|
1870
1870
|
/>
|
|
1871
1871
|
);
|
|
1872
1872
|
}
|
|
1873
|
-
`)}function
|
|
1873
|
+
`)}function $i(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
|
|
1874
1874
|
TINGYUN_LICENSE_KEY=
|
|
1875
1875
|
NEXT_PUBLIC_TINGYUN_APP_KEY=
|
|
1876
|
-
`}async function
|
|
1877
|
-
`)}}import Ht from"fs";import ct from"path";import{fileURLToPath as
|
|
1878
|
-
`+t):pe.writeFileSync(o,t)}function
|
|
1876
|
+
`}async function No(e,t,o="global"){let n=xo(t);if(!n||n.id==="none")return;let r=F.join(e,"apps","web");if(!ce.existsSync(r))return;let s=n.id;try{switch(s){case"sentry":Li(r),ln(r,pn.sentry),At(e,Ui());return;case"datadog":Mi(r),ln(r,pn.datadog),At(e,Di());return;case"bugsnag":Fi(r),ln(r,pn.bugsnag),At(e,ji());return;case"aliyun-arms":Vi(r),At(e,Ki());return;case"tingyun":Bi(r),At(e,$i());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 To(e){return Gt.find(t=>t.id===e)}var Sl=Gt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Oo(e,t,o="global"){let n=To(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 Yi from"path";async function Lo(e,t){let o=Yi.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 qi}from"url";var Gi=qi(import.meta.url),Uo=ct.dirname(Gi);function Hi(){let e=[ct.join(Uo,"..","templates","orm","drizzle"),ct.join(Uo,"..","..","templates","orm","drizzle")];for(let t of e)if(Ht.existsSync(t))return t;return null}function Mo(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()?Mo(n,r):Ht.copyFileSync(n,r)}}async function Do(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=Hi();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 Mo(n,r),{applied:!0}}import pe from"fs";import It from"path";var Wi=["stripe","lemonsqueezy","chinapay","polar"];function Fo(e){pe.existsSync(e)&&pe.rmSync(e,{recursive:!0,force:!0})}function Xi(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function zi(e,t){let o=It.join(e,".env.example");pe.existsSync(o)?pe.appendFileSync(o,`
|
|
1878
|
+
`+t):pe.writeFileSync(o,t)}function Ji(e){switch(e){case"stripe":return`# Stripe
|
|
1879
1879
|
STRIPE_SECRET_KEY=
|
|
1880
1880
|
STRIPE_WEBHOOK_SECRET=
|
|
1881
1881
|
`;case"lemon":return`# Lemon Squeezy
|
|
@@ -1890,14 +1890,14 @@ CHINAPAY_WECHAT_ENABLED=true
|
|
|
1890
1890
|
CHINAPAY_APP_ID=
|
|
1891
1891
|
CHINAPAY_APP_SECRET=
|
|
1892
1892
|
CHINAPAY_ALIPAY_ENABLED=true
|
|
1893
|
-
`}}async function
|
|
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}=
|
|
1895
|
-
`),t)}function
|
|
1896
|
-
`).filter(l=>{let
|
|
1897
|
-
`);return e.replace(s,`createProviderRegistry({${a}})`)}function
|
|
1898
|
-
`+r);let i={ai:"latest"},{providerIds:c,customEndpoint:a}=t;(c.includes("openai")||a||c.some(
|
|
1899
|
-
`)}}import y from"fs";import
|
|
1900
|
-
`)}let c=
|
|
1893
|
+
`}}async function jo(e,t){let o=It.join(e,"packages","commerce","billing");if(!pe.existsSync(o))return;if(t==="none"){Fo(o);return}let n=It.join(o,"src"),r=new Set(Xi(t));for(let i of Wi)r.has(i)||Fo(It.join(n,i));let s=It.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)}zi(e,Ji(t))}import ye from"fs";import pt from"path";var Bo=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),un=/@sailor:([^\s*]+)/;function Qi(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 Vo(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function Ko(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function $o(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}=Qi(c[1],t);if(a==="registry-entries"){n.push(r?Ko(i):Vo(i)),s++;continue}if(l){let u=r?Ko(i):Vo(i);u.trim().length>0&&n.push(u);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 u=s+1;for(;u<o.length&&o[u].trim()!==""&&!un.test(o[u]);)u++;u<o.length&&o[u].trim()===""&&u++,s=u}}return Zi(n.join(`
|
|
1895
|
+
`),t)}function Zi(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 u=l.trim();if(u===""||u.startsWith("//"))return!0;let S=u.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return S?r.has(S[1]):!0}).join(`
|
|
1897
|
+
`);return e.replace(s,`createProviderRegistry({${a}})`)}function ea(e,t){let o=pt.join(t,"registry.ts.template"),n=ye.readFileSync(o,"utf-8");return $o(n,e)}function ta(e,t){let o=pt.join(t,".env.example.template"),n=ye.readFileSync(o,"utf-8");return $o(n,e)}async function Yo(e,t,o){let n=ea(t,o),r=ta(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(u=>Bo.has(u)))&&(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 u=JSON.parse(await ye.promises.readFile(l,"utf-8"));u.dependencies||(u.dependencies={});for(let[S,C]of Object.entries(i))u.dependencies[S]=C;await ye.promises.writeFile(l,JSON.stringify(u,null,2)+`
|
|
1899
|
+
`)}}import y from"fs";import d from"path";function qo(e,t){if(!y.existsSync(e))return;let o=y.readdirSync(e);for(let n of o){let r=d.join(e,n);y.statSync(r).isDirectory()?qo(r,t):t(r)}}async function Go(e,t){let o=d.join(e,"package.json");if(!y.existsSync(o))return;let n=JSON.parse(y.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=d.join(e,"packages","db");if(y.existsSync(r)){let s=d.join(r,"prisma");y.existsSync(s)&&y.rmSync(s,{recursive:!0,force:!0});let i=d.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=d.join(r,"src","index.ts");y.existsSync(c)&&y.writeFileSync(c,`
|
|
1901
1901
|
export const prisma = {} as any;
|
|
1902
1902
|
export const db = {} as any;
|
|
1903
1903
|
export type PrismaClient = any;
|
|
@@ -1943,7 +1943,7 @@ export type UsageAggregate = any;
|
|
|
1943
1943
|
export type UsageLedgerEntry = any;
|
|
1944
1944
|
export type UsageType = any;
|
|
1945
1945
|
export type UsageLedgerSource = any;
|
|
1946
|
-
`)}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=d.join(e,"apps");if(y.existsSync(r)){let s=y.readdirSync(r);for(let i of s){let c=d.join(r,i);if(!y.statSync(c).isDirectory())continue;let a=d.join(c,"src","app");if(!y.existsSync(a))continue;["[lang]","[locale]"].forEach(b=>{let m=d.join(a,b);if(y.existsSync(m)){let M=y.readdirSync(m);for(let kt of M)y.renameSync(d.join(m,kt),d.join(a,kt));y.rmdirSync(m)}}),["src/middleware.ts","middleware.ts"].forEach(b=>{let m=d.join(c,b);y.existsSync(m)&&y.rmSync(m)});let l=d.join(c,"src","lib");y.existsSync(l)||y.mkdirSync(l,{recursive:!0});let u=d.join(l,"mock-i18n.ts");y.writeFileSync(u,`
|
|
1947
1947
|
import React from 'react';
|
|
1948
1948
|
export function useTranslations(namespace?: string): any { return (key: string) => key; }
|
|
1949
1949
|
export function useLocale() { return 'en'; }
|
|
@@ -1961,7 +1961,7 @@ export const useRouter = () => ({ push: (...args: any[]) => {}, replace: (...arg
|
|
|
1961
1961
|
export default function createMiddleware(...args: any[]) { return (req: any) => req; }
|
|
1962
1962
|
export function createNavigation(...args: any[]) { return { Link, redirect, usePathname, useRouter, getPathname: () => '/' }; }
|
|
1963
1963
|
export function defineRouting<T>(config: T): T { return config; }
|
|
1964
|
-
`);let C=
|
|
1964
|
+
`);let C=d.join(l,"mock-i18n.d.ts");y.writeFileSync(C,`declare module '@/lib/mock-i18n' {
|
|
1965
1965
|
export function useTranslations(namespace?: string): any;
|
|
1966
1966
|
export function useLocale(): string;
|
|
1967
1967
|
export const NextIntlClientProvider: React.FC<any>;
|
|
@@ -1979,19 +1979,19 @@ export function defineRouting<T>(config: T): T { return config; }
|
|
|
1979
1979
|
export function createNavigation(...args: any[]): any;
|
|
1980
1980
|
export function defineRouting<T>(config: T): T;
|
|
1981
1981
|
}
|
|
1982
|
-
`),y.writeFileSync(
|
|
1982
|
+
`),y.writeFileSync(d.join(l,"mock-i18n-index.ts"),`
|
|
1983
1983
|
export * from './mock-i18n';
|
|
1984
1984
|
export { default } from './mock-i18n';
|
|
1985
|
-
`);let
|
|
1985
|
+
`);let I=d.join(c,"tsconfig.json");if(y.existsSync(I))try{let b=y.readFileSync(I,"utf8");if(b.includes('"paths": {')){let m=b.replace(/"paths":\s*\{/,`"paths": {
|
|
1986
1986
|
"next-intl": ["./src/lib/mock-i18n"],
|
|
1987
|
-
"next-intl/*": ["./src/lib/mock-i18n"],`);y.writeFileSync(
|
|
1987
|
+
"next-intl/*": ["./src/lib/mock-i18n"],`);y.writeFileSync(I,m)}}catch{}let U=d.join(c,"src");y.existsSync(U)&&qo(U,b=>{if(!b.endsWith(".ts")&&!b.endsWith(".tsx"))return;let m=y.readFileSync(b,"utf8"),M=!1;b.endsWith("src/app/layout.tsx")&&m.includes("../providers")&&(m=m.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),M=!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"),M=!0),m.match(/lang\s*:\s*any/)&&(m=m.replace(/lang\s*:\s*any/g,"lang: string"),M=!0),m.match(/requestLocale\s*:\s*any/)&&(m=m.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),M=!0),m.match(/\(locale\s*=\s*(.*)\)/)&&(m=m.replace(/\(locale\s*=\s*(.*)\)/g,"() "),M=!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 })"),M=!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) =>"),M=!0),b.endsWith("src/i18n/request.ts")&&(m=m.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),M=!0),(m.match(/locale\s*:/)||m.match(/lang\s*:/))&&(M=!0),M&&y.writeFileSync(b,m)});let ue=d.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
1988
|
`)}}}}y.writeFileSync(o,JSON.stringify(n,null,2)+`
|
|
1989
|
-
`)}function v(e){try{y.rmSync(e,{recursive:!0,force:!0})}catch{}}function
|
|
1990
|
-
`)}function
|
|
1991
|
-
`);dt.appendFileSync(o,s)}function
|
|
1992
|
-
`)}async function
|
|
1993
|
-
`);ut.appendFileSync(o,s)}function
|
|
1994
|
-
`)}async function
|
|
1989
|
+
`)}function v(e){try{y.rmSync(e,{recursive:!0,force:!0})}catch{}}function na(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 Ho(e,t){t.cronJobs||(v(d.join(e,"apps/web/src/app/api/cron")),v(d.join(e,"packages/integrations/queue/src/scheduled"))),t.auditLog||(v(d.join(e,"apps/web/src/app/[locale]/(app)/settings/audit-log")),v(d.join(e,"apps/web/src/app/api/audit-logs")),v(d.join(e,"apps/web/src/components/audit"))),t.apiKeys||(v(d.join(e,"apps/web/src/app/[locale]/(app)/settings/api-keys")),v(d.join(e,"apps/web/src/app/api/api-keys")),v(d.join(e,"apps/web/src/components/api-keys"))),t.webhooks||(v(d.join(e,"apps/web/src/app/[locale]/(app)/settings/webhooks")),v(d.join(e,"apps/web/src/app/api/webhooks")),v(d.join(e,"apps/web/src/components/webhooks")),v(d.join(e,"packages/integrations/webhooks"))),t.commandPalette||(v(d.join(e,"apps/web/src/components/command-palette")),v(d.join(e,"apps/web/src/app/[locale]/providers/command-palette-mount.tsx"))),t.cookieConsent||(v(d.join(e,"apps/landing-page/src/components/cookie-consent-banner.tsx")),v(d.join(e,"apps/landing-page/src/components/__tests__/cookie-consent-banner.test.tsx")),v(d.join(e,"apps/landing-page/src/lib/cookie-consent.ts")),v(d.join(e,"apps/landing-page/src/lib/__tests__/cookie-consent.test.ts")),v(d.join(e,"apps/web/src/app/api/cookie-consent"))),t.legalPages||(v(d.join(e,"apps/landing-page/src/app/[lang]/(legal)/legal")),v(d.join(e,"apps/landing-page/src/lib/legal-documents.ts")),v(d.join(e,"apps/landing-page/src/lib/__tests__/legal-documents.test.ts"))),t.chinaCompliance||(v(d.join(e,"packages/ops/china-compliance")),v(d.join(e,"apps/landing-page/src/components/icp-footer.tsx")),v(d.join(e,"apps/landing-page/src/components/__tests__/icp-footer.test.tsx")),v(d.join(e,"apps/web/src/components/auth/wechat-login-button.tsx")),v(d.join(e,"apps/web/src/components/auth/__tests__/wechat-login-button.test.tsx")),na(d.join(e,"apps/web/package.json"),"@nebutra/china-compliance"))}import lt from"fs";import Wo from"path";var Xo=/^--\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/m;function oa(e){let t=Xo.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 ra(e){return e.replace(Xo,"").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=Wo.join(e,r.name),i=Wo.join(s,"migration.sql");if(!lt.existsSync(i)){o.skipped.push(r.name);continue}let c=lt.readFileSync(i,"utf8"),a=oa(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,ra(c)),o.kept.push(r.name);continue}lt.rmSync(s,{recursive:!0,force:!0}),o.removed.push(r.name)}return o}import{getSchema as sa,printSchema as ia}from"@mrleebo/prisma-ast";var aa=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function ca(e){return e.type==="comment"&&e.text.trim().startsWith("//")}function pa(e){let t=aa.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 la(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=pa(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function da(e){return e.type==="model"||e.type==="enum"}function gn(e,t){let o=sa(e),n=new Set;for(let c=0;c<o.list.length;c++){let a=o.list[c];if(!da(a))continue;let l=la(o.list,c);if(!l)continue;let u=t[l.parsed.flag];if(u!==void 0&&l.parsed.values.includes(u))n.add(l.annIndex);else{n.add(c);for(let I=c-1;I>=0;I--){let U=o.list[I];if(ca(U)){n.add(I);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 ia({type:"schema",list:s})}import dt from"fs";import Jo 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 zo(e){return Wt.find(t=>t.id===e)}var $l=Wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Qo(e){return dt.existsSync(e)?dt.readFileSync(e,"utf-8"):null}function ua(e,t){let o=Jo.join(e,".env.example"),n=Qo(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 ma(e,t,o){let n=Jo.join(e,".env.example"),r=Qo(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 Zo(e,t,o){let n=Re(e,"queue");if(t==="none"){n&&dt.rmSync(n,{recursive:!0,force:!0});return}let r=zo(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${Wt.map(s=>s.id).join(", ")}`);n&&(ua(e,r),ma(e,"QUEUE_PROVIDER",t))}import le from"fs";import Se from"path";import{fileURLToPath as ga}from"url";var fa=ga(import.meta.url),er=Se.dirname(fa),ya=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|toml|py)$/,Sa=["backends/gateway","infra","e2e","tests"];function ha(){let e=[Se.join(er,"..","templates"),Se.join(er,"..","..","templates")];for(let t of e)if(le.existsSync(t))return t;return e[0]}async function tr(e,t){let o=ha(),n=[],r=[],s=[...Sa,...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);nr(c,a),or(a,{"{PRODUCT_NAME}":t.projectName}),n.push(i)}return{applied:n,skipped:r}}function nr(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()?nr(n,r):le.existsSync(r)||le.copyFileSync(n,r)}}function or(e,t){for(let o of le.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name);if(o.isDirectory()){or(n,t);continue}if(!ya.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 sr 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 rr(e){return Xt.find(t=>t.id===e)}var ed=Xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function ir(e){return ut.existsSync(e)?ut.readFileSync(e,"utf-8"):null}function Ea(e,t){let o=sr.join(e,".env.example"),n=ir(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 va(e,t,o){let n=sr.join(e,".env.example"),r=ir(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 ar(e,t,o){let n=Re(e,"search");if(t==="none"){n&&ut.rmSync(n,{recursive:!0,force:!0});return}let r=rr(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Xt.map(s=>s.id).join(", ")}`);n&&(Ea(e,r),va(e,"SEARCH_PROVIDER",t))}import he from"fs";import Me from"path";function _a(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 ba(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 Pa(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
|
|
1995
1995
|
const admin = await prisma.user.create({
|
|
1996
1996
|
data: {
|
|
1997
1997
|
clerkId: "user_mock_admin",
|
|
@@ -2022,7 +2022,7 @@ export { default } from './mock-i18n';
|
|
|
2022
2022
|
console.log("\\u2713 Created admin user:", admin.email);
|
|
2023
2023
|
} catch (err) {
|
|
2024
2024
|
console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
|
|
2025
|
-
}`}function
|
|
2025
|
+
}`}function Aa(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),s=Pa(e,n),i=o?` let tenants: Array<{ id: string; name: string }> = [];
|
|
2026
2026
|
try {
|
|
2027
2027
|
tenants = await Promise.all([
|
|
2028
2028
|
prisma.tenant.create({
|
|
@@ -2091,12 +2091,12 @@ main()
|
|
|
2091
2091
|
.finally(async () => {
|
|
2092
2092
|
await prisma.$disconnect();
|
|
2093
2093
|
});
|
|
2094
|
-
`}function
|
|
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
|
|
2096
|
-
`+t):Ee.writeFileSync(o,t)}function
|
|
2094
|
+
`}function Ia(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 cr(e,t){let o=_a(e);if(o)try{let n=Me.join(o.packageDir,"prisma","schema.prisma"),r=ba(n),s=Aa(t,r),i=Me.dirname(o.seedPath);he.existsSync(i)||he.mkdirSync(i,{recursive:!0}),he.writeFileSync(o.seedPath,s),Ia(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:""}],ld=zt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function pr(e){return zt.find(t=>t.id===e)}var Ca="@nebutra/sms",wa={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 Ra(e,t){let o=De.join(e,".env.example");Ee.existsSync(o)?Ee.appendFileSync(o,`
|
|
2096
|
+
`+t):Ee.writeFileSync(o,t)}function ka(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2097
2097
|
`);return`${t}
|
|
2098
2098
|
${o}
|
|
2099
|
-
`}var
|
|
2099
|
+
`}var xa=`/**
|
|
2100
2100
|
* Inputs for the \`sendSms\` wrapper. Keep this surface portable across
|
|
2101
2101
|
* providers \u2014 provider-specific options belong in the wrapper itself.
|
|
2102
2102
|
*/
|
|
@@ -2116,7 +2116,7 @@ export interface SendSmsResult {
|
|
|
2116
2116
|
provider: string;
|
|
2117
2117
|
raw?: unknown;
|
|
2118
2118
|
}
|
|
2119
|
-
`;function
|
|
2119
|
+
`;function Na(){return`import twilio from "twilio";
|
|
2120
2120
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2121
2121
|
|
|
2122
2122
|
let client: ReturnType<typeof twilio> | null = null;
|
|
@@ -2151,7 +2151,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2151
2151
|
}
|
|
2152
2152
|
|
|
2153
2153
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2154
|
-
`}function
|
|
2154
|
+
`}function Ta(){return`import messagebird from "messagebird";
|
|
2155
2155
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2156
2156
|
|
|
2157
2157
|
let client: ReturnType<typeof messagebird> | null = null;
|
|
@@ -2189,7 +2189,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2189
2189
|
}
|
|
2190
2190
|
|
|
2191
2191
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2192
|
-
`}function
|
|
2192
|
+
`}function Oa(){return`import plivo from "plivo";
|
|
2193
2193
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2194
2194
|
|
|
2195
2195
|
let client: InstanceType<typeof plivo.Client> | null = null;
|
|
@@ -2228,7 +2228,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2228
2228
|
}
|
|
2229
2229
|
|
|
2230
2230
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2231
|
-
`}function
|
|
2231
|
+
`}function La(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
|
|
2232
2232
|
import * as $OpenApi from "@alicloud/openapi-client";
|
|
2233
2233
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2234
2234
|
|
|
@@ -2277,7 +2277,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2277
2277
|
}
|
|
2278
2278
|
|
|
2279
2279
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2280
|
-
`}function
|
|
2280
|
+
`}function Ua(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
|
|
2281
2281
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2282
2282
|
|
|
2283
2283
|
const SmsClient = tencentcloud.sms.v20210111.Client;
|
|
@@ -2342,7 +2342,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2342
2342
|
}
|
|
2343
2343
|
|
|
2344
2344
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2345
|
-
`}function
|
|
2345
|
+
`}function Ma(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
|
|
2346
2346
|
import Yunpian from "yunpian-nodejs-sdk";
|
|
2347
2347
|
import type { SendSmsInput, SendSmsResult } from "./types";
|
|
2348
2348
|
|
|
@@ -2394,13 +2394,13 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2394
2394
|
}
|
|
2395
2395
|
|
|
2396
2396
|
export type { SendSmsInput, SendSmsResult } from "./types";
|
|
2397
|
-
`}function
|
|
2398
|
-
`}}function
|
|
2399
|
-
`}async function
|
|
2400
|
-
`+t):je.writeFileSync(o,t)}function
|
|
2397
|
+
`}function Da(e){switch(e){case"twilio":return Na();case"messagebird":return Ta();case"plivo":return Oa();case"aliyun-sms":return La();case"tencent-sms":return Ua();case"yunpian":return Ma();case"none":return`export {};
|
|
2398
|
+
`}}function Fa(e){let t={};for(let n of e.pkgs??[]){let r=wa[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 lr(e,t,o="global"){if(t==="none")return;let n=pr(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"),Fa(n)),fn(De.join(s,"types.ts"),xa),fn(De.join(s,"index.ts"),Da(n.id)),Ra(e,ka(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 Ct=[{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 Ct.some(o=>o.id===t)?t:void 0}function dr(e){let t=yn(e);return t?Ct.find(o=>o.id===t):void 0}var yd=Ct.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 ja(e,t){let o=Fe.join(e,".env.example");je.existsSync(o)?je.appendFileSync(o,`
|
|
2400
|
+
`+t):je.writeFileSync(o,t)}function Va(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2401
2401
|
`);return`${t}
|
|
2402
2402
|
${o}
|
|
2403
|
-
`}var
|
|
2403
|
+
`}var Ka=`/**
|
|
2404
2404
|
* Inputs for the \`uploadFile\` wrapper. Keep this surface portable across
|
|
2405
2405
|
* providers \u2014 provider-specific options belong in the wrapper itself.
|
|
2406
2406
|
*/
|
|
@@ -2490,7 +2490,7 @@ export async function getSignedUrl(
|
|
|
2490
2490
|
}
|
|
2491
2491
|
|
|
2492
2492
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2493
|
-
`}function
|
|
2493
|
+
`}function $a(){return`/**
|
|
2494
2494
|
* @${Ve.slice(1)} \u2014 AWS S3 wrapper.
|
|
2495
2495
|
*
|
|
2496
2496
|
* Docs: https://docs.aws.amazon.com/s3/
|
|
@@ -2555,7 +2555,7 @@ export async function getSignedUrl(
|
|
|
2555
2555
|
}
|
|
2556
2556
|
|
|
2557
2557
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2558
|
-
`}function
|
|
2558
|
+
`}function Ya(){return`/**
|
|
2559
2559
|
* @${Ve.slice(1)} \u2014 Supabase Storage wrapper.
|
|
2560
2560
|
*
|
|
2561
2561
|
* Docs: https://supabase.com/docs/guides/storage
|
|
@@ -2618,7 +2618,7 @@ export async function getSignedUrl(
|
|
|
2618
2618
|
}
|
|
2619
2619
|
|
|
2620
2620
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2621
|
-
`}function
|
|
2621
|
+
`}function qa(){return`/**
|
|
2622
2622
|
* @${Ve.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
|
|
2623
2623
|
*
|
|
2624
2624
|
* Docs: https://help.aliyun.com/product/31815.html
|
|
@@ -2665,7 +2665,7 @@ export async function getSignedUrl(
|
|
|
2665
2665
|
}
|
|
2666
2666
|
|
|
2667
2667
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2668
|
-
`}function
|
|
2668
|
+
`}function Ga(){return`/**
|
|
2669
2669
|
* @${Ve.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
|
|
2670
2670
|
*
|
|
2671
2671
|
* Docs: https://cloud.tencent.com/document/product/436
|
|
@@ -2720,7 +2720,7 @@ export async function getSignedUrl(
|
|
|
2720
2720
|
}
|
|
2721
2721
|
|
|
2722
2722
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2723
|
-
`}function
|
|
2723
|
+
`}function Ha(){return`/**
|
|
2724
2724
|
* @${Ve.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
|
|
2725
2725
|
*
|
|
2726
2726
|
* Docs: https://developer.qiniu.com/kodo
|
|
@@ -2788,9 +2788,9 @@ export async function getSignedUrl(
|
|
|
2788
2788
|
}
|
|
2789
2789
|
|
|
2790
2790
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
|
|
2791
|
-
`}function
|
|
2792
|
-
`}}function
|
|
2793
|
-
`}async function
|
|
2791
|
+
`}function Wa(e){switch(e){case"r2":return Ba();case"s3":return $a();case"supabase-storage":return Ya();case"aliyun-oss":return qa();case"tencent-cos":return Ga();case"qiniu":return Ha();case"none":return`export {};
|
|
2792
|
+
`}}function Xa(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 ur(e,t,o){if(t==="none")return;let n=dr(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${Ct.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"),Xa(n)),Sn(Fe.join(s,"types.ts"),Ka),Sn(Fe.join(s,"index.ts"),Wa(n.id)),ja(e,Va(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 mr(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 gr(e){return Jt.find(t=>t.id===e)}var Pd=Jt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function fr(e,t,o="global"){let n=gr(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 Ke from"fs";import wt from"path";function za(e){return`import Link from "next/link";
|
|
2794
2794
|
|
|
2795
2795
|
export default function WelcomePage() {
|
|
2796
2796
|
const projectName = ${JSON.stringify(e)};
|
|
@@ -2899,12 +2899,12 @@ function Step({
|
|
|
2899
2899
|
</li>
|
|
2900
2900
|
);
|
|
2901
2901
|
}
|
|
2902
|
-
`}function
|
|
2902
|
+
`}function Ja(e={}){return`
|
|
2903
2903
|
## What you can do next
|
|
2904
2904
|
|
|
2905
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(`
|
|
2906
2906
|
`)}
|
|
2907
|
-
`}function
|
|
2907
|
+
`}function Qa(e=[]){return e.length===0?"":`
|
|
2908
2908
|
## Production readiness holds
|
|
2909
2909
|
|
|
2910
2910
|
Do not enable these in production until you replace stubs, add provider credentials, and verify the integration contract:
|
|
@@ -2913,7 +2913,7 @@ ${e.map(o=>{let n=rt(o.status);return`- ${o.flag}=${o.provider} ${n} \u2014 ${me
|
|
|
2913
2913
|
`)}
|
|
2914
2914
|
|
|
2915
2915
|
Review the package readiness matrix before handoff: [docs/package-status.md](docs/package-status.md)
|
|
2916
|
-
`}function
|
|
2916
|
+
`}function Za(e,t,o=[],n={}){return`# Next steps \u2014 ${e}
|
|
2917
2917
|
|
|
2918
2918
|
Region: ${t}
|
|
2919
2919
|
|
|
@@ -2939,17 +2939,17 @@ Your AI-native SaaS scaffold is ready. Complete these four steps to go from temp
|
|
|
2939
2939
|
\`\`\`
|
|
2940
2940
|
|
|
2941
2941
|
After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
|
|
2942
|
-
${
|
|
2942
|
+
${Ja(n)}${Qa(o)}
|
|
2943
2943
|
|
|
2944
2944
|
## Resources
|
|
2945
2945
|
|
|
2946
2946
|
- [Documentation](/docs)
|
|
2947
2947
|
- [GitHub](https://github.com/nebutra/nebutra-sailor)
|
|
2948
2948
|
- [Get free license (Individual/OPC)](https://nebutra.com/get-license)
|
|
2949
|
-
`}async function
|
|
2950
|
-
`)}function
|
|
2949
|
+
`}async function yr(e,t){let{projectName:o,region:n,previewSelections:r=[],waveFeatures:s={}}=t;try{let i=wt.join(e,".sailor");Ke.existsSync(i)||Ke.mkdirSync(i,{recursive:!0}),Ke.writeFileSync(wt.join(i,"next-steps.md"),Za(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(!Ke.existsSync(i))return;let c=wt.join(i,"src","app","[locale]","welcome");Ke.existsSync(c)||Ke.mkdirSync(c,{recursive:!0}),Ke.writeFileSync(wt.join(c,"page.tsx"),za(o))}catch(i){let c=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write welcome page: ${c}`)}}var Sr="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
|
|
2950
|
+
`)}function nc(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function hr(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 Er(e,t,o){let n=e?.trim().toLowerCase()??Gn(t),r=Bt(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 vr(e){return e==="drizzle"?"drizzle":"prisma"}function _r(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function br(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 Pr(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 oc=new Set(["gateway","direct","custom","none"]);function xr(e){if(!e)return!1;let t=e.trim().toLowerCase();return oc.has(t)}function Ar(e){if(!e)return["openai"];if(xr(e))return[];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}function rc(e,t){let o=e??t;return yn(o)??o}var Ir={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 Ir){let n=Ir[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
2951
|
`)+A.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
|
|
2952
|
-
`)),"fumadocs"}return"fumadocs"}function
|
|
2952
|
+
`)),"fumadocs"}return"fumadocs"}function wr(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 Rr(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function sc(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 kr(e){return e==="cn"?"wechat":"stripe"}async function ic(){let e=new ec;e.name(Sr).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
2953
|
${A.red("\u2718")} ${A.bold("pnpm is required")} but was not found on PATH.
|
|
2954
2954
|
|
|
2955
2955
|
The scaffold uses pnpm workspaces + Turborepo. Install pnpm first:
|
|
@@ -2959,24 +2959,24 @@ Then retry: ${A.cyan("pnpm dlx create-sailor@latest")}
|
|
|
2959
2959
|
(or pass ${A.dim("--pm=npm")} if you know workspace:* won't resolve in your setup)
|
|
2960
2960
|
|
|
2961
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)),
|
|
2963
|
-
`)),process.exit(130)}}):{};E=
|
|
2964
|
-
`))}}let Pe={region:E,orm:
|
|
2962
|
+
`)),process.exit(130)}});a=String(g.name)}let l=de.basename(de.resolve(a)),u=t.pm??nc(),S=!!t.region,C=!!t.auth,I=!!t.payment,U=!!t.ai,ue=!!t.email,b=!!t.storage,m=!!t.monitoring,M=!!t.analytics,kt=!!t.sms,hn=t.i18n!==void 0,E,Be,G,xt="local",mt,H,j,Q=On(t.socialLogin),gt,Qt,be,$e,ie,W,Nt;if(i){E=Rr(t.region),Be=vr(t.orm);{let Ae=hr(t.db),V=Er(t.dbHost,E,Ae);G=V.engine,xt=V.hostId}let g=I?t.payment:kr(E);mt=_r(g),H=br(g),j=Pr(t.auth);let h="gateway";if(U){let Ae=t.ai?.trim().toLowerCase()??"";xr(Ae)?h=Ae:h="direct"}let L=nn({mode:h,providerIds:U?Ar(t.ai):void 0});gt=L.mode,Qt=L.routing,be=L.providerIds,ie=wr(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"})),U||(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=Rr(S?t.region:h.region),Be=vr(t.orm);{let f=hr(t.db),_=Er(t.dbHost,E,f);G=_.engine,xt=_.hostId}let L=I?t.payment:kr(E);mt=_r(L),H=br(L),j=Pr(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,V=nn({mode:U?t.ai?.trim().toLowerCase()==="none"?"none":"direct":h.aiMode??"gateway",providerIds:U?Ar(t.ai):h.aiProviders,customEndpoint:Ae});gt=V.mode,Qt=V.routing,be=V.providerIds,V.customEndpoint&&($e={name:V.customEndpoint.name,baseURL:V.customEndpoint.baseURL,apiKeyEnvName:V.customEndpoint.apiKeyEnvName}),ie=wr(t.deploy),W=Cr(t.docs,n),Nt=hn?!!t.i18n:!0}let k=sc(E),Ye=ue?t.email:k.email,qe=rc(b?t.storage:void 0,k.storage),Ge=m?t.monitoring:k.monitoring,He=M?t.analytics:k.analytics,We=kt?t.sms:k.sms,Xe=t.queue??k.queue,ze=t.search??k.search,ft=t.cache??k.cache,Je=t.notifications??k.notifications,Qe=t.webhooks??k.webhooks,yt=t.cms??k.cms,Ze=t.featureFlags??k.featureFlags,et=t.captcha??k.captcha,Tt=t.mcp??k.mcp,St=t.metering??k.metering,tt=t.billingMode??k.billingMode,nt=t.idp??k.idp,ht=t.accessGate==="invite"?"invite":k.accessGate,w=mr({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:Be,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:w.cronJobs,auditLog:w.auditLog,apiKeys:w.apiKeys,commandPalette:w.commandPalette,cookieConsent:w.cookieConsent,legalPages:w.legalPages,chinaCompliance:w.chinaCompliance},Ot=[["Project name",l],["Region",E],["Auth",j],["Social login",Q.length>0?Q.map(g=>Et.find(h=>h.id===g)?.name??g).join(", "):"none"],["ORM",Be],["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)=>{Cn({index:L+1,total:Ot.length,label:g,value:h})});let Nr={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=${Be}, i18n=${Nt})`,`region \u2192 ${E}`,`auth \u2192 ${j==="none"?"skip (remove packages/auth)":`configure ${j}`}`,...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 ${w.cronJobs?"enabled":"disabled"}`,`audit-log \u2192 ${w.auditLog?"enabled":"disabled"}`,`api-keys \u2192 ${w.apiKeys?"enabled":"disabled"}`,`command-palette \u2192 ${w.commandPalette?"enabled":"disabled"}`,`cookie-consent \u2192 ${w.cookieConsent?"enabled":"disabled"}`,`legal-pages \u2192 ${w.legalPages?"enabled":"disabled"}`,`china-compliance \u2192 ${w.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 ${u} 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
2965
|
`+A.bold(`Dry run \u2014 planned actions:
|
|
2966
2966
|
`));for(let L of h)process.stdout.write(` \u2022 ${L}
|
|
2967
2967
|
`);ot.length>0&&(process.stdout.write(`
|
|
2968
2968
|
`+A.bold(A.yellow(`Preview-status providers selected:
|
|
2969
2969
|
`))),Zt()),process.stdout.write(A.dim(`
|
|
2970
2970
|
No files were written.
|
|
2971
|
-
`))}process.exit(0)}let
|
|
2971
|
+
`))}process.exit(0)}let Tr=async()=>{process.stdout.write(`
|
|
2972
2972
|
`+A.red(`\u2718 Cancelled
|
|
2973
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",
|
|
2974
|
+
`))),process.exit(130)};process.on("SIGINT",Tr);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 Lo(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 Go(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:j,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:j,status:"start"}),await Nn(a,j),p(n,{event:"step",step:"auth",choice:j,status:"ok"}),Q.length>0?(p(n,{event:"step",step:"social-login",providers:Q,status:"start"}),await Un(a,Q,j),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=Bt(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"}),Be==="drizzle"){p(n,{event:"step",step:"orm",choice:"drizzle",status:"start"});let f=await Do(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 jo(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 ur(a,qe,E),n&&p(!0,{event:"step",step:"storage",choice:qe,status:"ok"}),await No(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 lr(a,We,E),n&&p(!0,{event:"step",step:"sms",choice:We,status:"ok"}),await Zo(a,Xe,E),n&&p(!0,{event:"step",step:"queue",choice:Xe,status:"ok"}),await ar(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 Oo(a,Je,E),n&&p(!0,{event:"step",step:"notifications",choice:Je,status:"ok"}),await fr(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 Kn(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 Ro(a,St,mt),n&&p(!0,{event:"step",step:"metering",mode:St,status:"ok"}),p(n,{event:"step",step:"prune-wave-features",status:"start"}),Ho(a,w),p(n,{event:"step",step:"prune-wave-features",status:"ok",toggles:w}),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:j,payment:H,"billing-mode":tt,idp:nt,template:"saas","access-gate":ht},Or=gn(_,Y);_e.writeFileSync(f,Or),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 cr(a,j),await yr(a,{projectName:l,region:E,previewSelections:ot,waveFeatures:w}),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 Yo(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,Nr),p(n,{event:"step",step:"env",status:"ok"}),p(n,{event:"step",step:"scaffold-extras",status:"start"});let h=await tr(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=Io(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
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=
|
|
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=u==="bun"?"bun install":`${u} install`;n?p(!0,{event:"step",step:"install",pm:u,status:"start"}):process.stdout.write(A.dim(` Installing dependencies with ${u}\u2026
|
|
2977
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
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
|
|
2979
|
+
`))}}else p(n,{event:"step",step:"git-init",status:"skip"});let V=Math.max(1,Math.round((Date.now()-En)/1e3));xn({template_version:ae,package_manager:u,region:E,auth:j,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:V,targetDir:a,previewSelections:ot,waveFeatures:w}):Pn({elapsedSec:V,targetDir:a,skippedInstall:t.install===!1,previewSelections:ot,waveFeatures:w});try{tc({pkg:{name:Sr,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(`
|
|
2980
2980
|
\u2718 Failed: ${h}
|
|
2981
|
-
`)),process.exit(1)}}
|
|
2981
|
+
`)),process.exit(1)}}ic().catch(e=>{process.stderr.write(String(e)+`
|
|
2982
2982
|
`),process.exit(1)});
|