create-sailor 1.3.4 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -11
- package/dist/aws-kms-ZX6CTY62.js +1 -0
- package/dist/{chunk-6EI2BXXZ.js → chunk-4NVBWJ2Q.js} +1 -1
- package/dist/chunk-A2KGYHAM.js +1 -0
- package/dist/{chunk-ZEEOYOWD.js → chunk-A75AMTOI.js} +1 -1
- package/dist/{chunk-KIX47M2V.js → chunk-B5RLHF2U.js} +1 -1
- package/dist/chunk-FSRPMVAS.js +1 -0
- package/dist/{chunk-O3WYNHSC.js → chunk-J7NVVT5I.js} +2 -2
- package/dist/{chunk-EA5HU2X4.js → chunk-LDOHSEAR.js} +2 -2
- package/dist/{chunk-4F23MJOI.js → chunk-NK255JZN.js} +1 -1
- package/dist/chunk-SDX64WW4.js +23 -0
- package/dist/{chunk-2VIWVVHK.js → chunk-YR32FZAX.js} +1 -1
- package/dist/{credits-L2HL2UEU.js → credits-6AUSU6X6.js} +2 -2
- package/dist/{dist-XS6SQF6X.js → dist-B4YTE2SQ.js} +2 -2
- package/dist/{dist-es-M3FWVZJF.js → dist-es-4EORLV5B.js} +1 -1
- package/dist/{dist-es-VHZAJVLW.js → dist-es-7IMKW7US.js} +1 -1
- package/dist/{dist-es-WTYBIVJ2.js → dist-es-FJUQ4DBK.js} +1 -1
- package/dist/{dist-es-OUTR3NFA.js → dist-es-GP7DK3S3.js} +1 -1
- package/dist/{dist-es-UGE2JJUB.js → dist-es-JXNWCJHW.js} +1 -1
- package/dist/{dist-es-NVFYVK4E.js → dist-es-YKXA2GQ2.js} +1 -1
- package/dist/{dist-es-NDZJSZR3.js → dist-es-ZA2NRM7G.js} +1 -1
- package/dist/{event-streams-WTP73PI5.js → event-streams-T5RU6C4N.js} +1 -1
- package/dist/index.js +181 -164
- package/dist/{loadSso-O5OGD76B.js → loadSso-YQ73JVR6.js} +1 -1
- package/dist/local-WW37QOXE.js +1 -0
- package/dist/{query_compiler_fast_bg.postgresql-7BFUBDOL.js → query_compiler_fast_bg.postgresql-PN2AWLCP.js} +1 -1
- package/dist/{query_compiler_fast_bg.postgresql.wasm-base64-I4FAC6EL.js → query_compiler_fast_bg.postgresql.wasm-base64-CASS54LO.js} +1 -1
- package/dist/{signin-DZIPNQBV.js → signin-LD4OP44K.js} +1 -1
- package/dist/src-MVDQLN5F.js +1 -0
- package/dist/{sso-oidc-SYBBWZG3.js → sso-oidc-4BAF7BYK.js} +1 -1
- package/dist/{sts-DREA5KZD.js → sts-3V5Q4UTA.js} +1 -1
- package/package.json +15 -14
- package/dist/aws-kms-BRGZLC2X.js +0 -1
- package/dist/chunk-7Z3O7WJM.js +0 -49
- package/dist/chunk-B35GFLVZ.js +0 -5
- package/dist/chunk-BAI5W3AB.js +0 -1
- package/dist/chunk-DGJUBN33.js +0 -1
- package/dist/chunk-HC3S5NWW.js +0 -1
- package/dist/chunk-LOPYJ44X.js +0 -31
- package/dist/chunk-YW4FFW47.js +0 -1
- package/dist/dist-Z6UUHTH2.js +0 -8
- package/dist/getMachineId-bsd-DVN24SFH.js +0 -1
- package/dist/getMachineId-darwin-LMU6AYNV.js +0 -2
- package/dist/getMachineId-linux-BHWLMOUW.js +0 -1
- package/dist/getMachineId-unsupported-G5LY7Y3J.js +0 -1
- package/dist/getMachineId-win-CWK62SDK.js +0 -1
- package/dist/local-V5XPOCXA.js +0 -1
- package/dist/multipart-parser-73SROTP5.js +0 -2
- package/dist/src-BFSJ5KFS.js +0 -3
- package/dist/src-ERQKJBBE.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import"./chunk-
|
|
3
|
-
`));return}
|
|
2
|
+
import"./chunk-FSRPMVAS.js";import{execSync as kt}from"child_process";import de from"fs";import ut from"path";import*as C from"@clack/prompts";import{Command as Bs}from"commander";import w from"picocolors";import Ys from"update-notifier";import Xo from"cfonts";import zo from"picocolors";import nn from"fs";import Lt from"path";import{fileURLToPath as Ho}from"url";function Wo(){try{let t=Lt.dirname(Ho(import.meta.url));for(let o=0;o<4;o++){let n=Lt.join(t,"package.json");if(nn.existsSync(n)){let r=nn.readFileSync(n,"utf-8"),i=JSON.parse(r);if(i.name==="create-sailor"&&typeof i.version=="string")return i.version}t=Lt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ee=Wo();function on(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ee}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
|
|
3
|
+
`));return}Xo.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(zo.dim(` AI-Native SaaS Template \xB7 v${ee} \xB7 nebutra.com
|
|
4
4
|
|
|
5
|
-
`))}import
|
|
5
|
+
`))}import _ from"picocolors";var Qo={qstash:"foundation",bullmq:"foundation",upstash:"foundation",sqs:"foundation",meilisearch:"foundation",typesense:"foundation",algolia:"foundation",pgvector:"foundation",novu:"foundation",knock:"foundation",svix:"foundation","vercel-flags":"wip",growthbook:"wip",configcat:"wip",turnstile:"wip",hcaptcha:"wip","aliyun-slide":"wip"};function Jo(e){return e?Qo[e]??"stable":"stable"}function qe(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function te(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 rn(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=Jo(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function Zo(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function sn(e){let t=Zo(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",i=t?"\u{1F4E7}":"*",c=["",` ${t?_.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?_.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?_.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?_.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?_.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?_.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?_.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?_.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?_.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?_.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?_.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?_.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?_.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?_.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`);let a=e.previewSelections??[];if(a.length>0){let d=t?_.bold(_.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${d}`);for(let u of a){let h=qe(u.status),O=` ${n} ${u.flag} (${u.provider}) ${h}`;c.push(t?_.yellow(O):O)}c.push("",` ${t?_.dim(te("foundation")):te("foundation")}`,` ${t?_.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?_.dim("See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"):"See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"}`)}c.push("",` ${t?_.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${i} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
|
|
6
6
|
`)+`
|
|
7
|
-
`)}var
|
|
7
|
+
`)}var er=`Usage: create-sailor [name] [options]
|
|
8
8
|
|
|
9
9
|
Arguments:
|
|
10
10
|
name project directory (default: ./my-saas-app)
|
|
@@ -13,7 +13,14 @@ Core options:
|
|
|
13
13
|
-p, --pm <id> npm | pnpm | yarn | bun (auto-detected)
|
|
14
14
|
--region <id> global | cn | hybrid (default: global)
|
|
15
15
|
--auth <id> clerk | betterauth | none
|
|
16
|
-
--ai <ids>
|
|
16
|
+
--ai <ids> expert/non-interactive provider seed (e.g. openai,anthropic)
|
|
17
|
+
|
|
18
|
+
Interactive AI topology:
|
|
19
|
+
Default first-run asks for topology, not individual provider enablement:
|
|
20
|
+
gateway Multi-provider AI Gateway / router (recommended)
|
|
21
|
+
direct Direct SDK/provider adapters
|
|
22
|
+
custom OpenAI-compatible endpoint
|
|
23
|
+
none Skip AI
|
|
17
24
|
|
|
18
25
|
Stack flags (region-based smart defaults):
|
|
19
26
|
--orm <id> prisma | drizzle | none (default: prisma)
|
|
@@ -24,7 +31,7 @@ Stack flags (region-based smart defaults):
|
|
|
24
31
|
|
|
25
32
|
Feature flags (region-based smart defaults):
|
|
26
33
|
--email <id> resend | postmark | ses | aliyun-dm | tencent-ses | netease | none
|
|
27
|
-
--storage <id> r2 | s3 | supabase | aliyun-oss | tencent-cos | qiniu | none
|
|
34
|
+
--storage <id> r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none
|
|
28
35
|
--monitoring <id> sentry | datadog | aliyun-arms | tingyun | none
|
|
29
36
|
--analytics <id> posthog | plausible | umami | baidu | sensors | none
|
|
30
37
|
--sms <id> twilio | aliyun-sms | tencent-sms | yunpian | none
|
|
@@ -66,9 +73,9 @@ Examples:
|
|
|
66
73
|
$ npx create-sailor@latest my-app --region=cn --auth=clerk
|
|
67
74
|
$ npx create-sailor@latest my-app --region=hybrid --ai=openai,deepseek
|
|
68
75
|
$ npm create sailor@latest --dry-run --region=cn
|
|
69
|
-
`;function
|
|
70
|
-
`)}var Et=[{id:"anthropic",name:"Anthropic",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.anthropic.com",envVarPrefix:"ANTHROPIC",requiredEnvVars:["ANTHROPIC_API_KEY"]},{id:"openai",name:"OpenAI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.openai.com/docs",envVarPrefix:"OPENAI",requiredEnvVars:["OPENAI_API_KEY"]},{id:"deepseek",name:"DeepSeek",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.deepseek.com/api-docs",envVarPrefix:"DEEPSEEK",requiredEnvVars:["DEEPSEEK_API_KEY"]},{id:"xai",name:"xAI (Grok)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.x.ai/api",envVarPrefix:"XAI",requiredEnvVars:["XAI_API_KEY"]},{id:"moonshot",name:"Moonshot (Kimi)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.moonshot.cn/docs",envVarPrefix:"MOONSHOT",requiredEnvVars:["MOONSHOT_API_KEY","MOONSHOT_BASE_URL"]},{id:"google",name:"Google Gemini",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://ai.google.dev/gemini-api/docs",envVarPrefix:"GOOGLE_GENERATIVE_AI",requiredEnvVars:["GOOGLE_GENERATIVE_AI_API_KEY"]},{id:"mistral",name:"Mistral AI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.mistral.ai",envVarPrefix:"MISTRAL",requiredEnvVars:["MISTRAL_API_KEY"]},{id:"cohere",name:"Cohere",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.cohere.com",envVarPrefix:"COHERE",requiredEnvVars:["COHERE_API_KEY"]},{id:"perplexity",name:"Perplexity",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.perplexity.ai",baseURL:"https://api.perplexity.ai",envVarPrefix:"PERPLEXITY",requiredEnvVars:["PERPLEXITY_API_KEY"]},{id:"ai21",name:"AI21 Labs",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.ai21.com",baseURL:"https://api.ai21.com/studio/v1",envVarPrefix:"AI21",requiredEnvVars:["AI21_API_KEY"]},{id:"upstage",name:"Upstage (Solar)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://developers.upstage.ai/docs",baseURL:"https://api.upstage.ai/v1/solar",envVarPrefix:"UPSTAGE",requiredEnvVars:["UPSTAGE_API_KEY"]},{id:"siliconflow",name:"\u7845\u57FA\u6D41\u52A8 SiliconFlow",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://docs.siliconflow.cn",baseURL:"https://api.siliconflow.cn/v1",envVarPrefix:"SILICONFLOW",requiredEnvVars:["SILICONFLOW_API_KEY"]},{id:"volcengine-ark",name:"\u706B\u5C71\u5F15\u64CE ARK (\u8C46\u5305)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://www.volcengine.com/docs/82379",baseURL:"https://ark.cn-beijing.volces.com/api/v3",envVarPrefix:"ARK",requiredEnvVars:["ARK_API_KEY"]},{id:"bailian",name:"\u767E\u70BC Bailian (\u901A\u4E49)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://help.aliyun.com/zh/model-studio",baseURL:"https://dashscope.aliyuncs.com/compatible-mode/v1",envVarPrefix:"DASHSCOPE",requiredEnvVars:["DASHSCOPE_API_KEY"]},{id:"zhipu",name:"\u667A\u8C31 AI Zhipu",category:"\u56FD\u5185\u5E73\u53F0",status:"ai-sdk",docs:"https://docs.bigmodel.cn",baseURL:"https://open.bigmodel.cn/api/paas/v4",envVarPrefix:"ZHIPU",requiredEnvVars:["ZHIPU_API_KEY"]},{id:"baichuan",name:"\u767E\u5DDD\u667A\u80FD Baichuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.baichuan-ai.com/docs",baseURL:"https://api.baichuan-ai.com/v1",envVarPrefix:"BAICHUAN",requiredEnvVars:["BAICHUAN_API_KEY"]},{id:"minimax",name:"MiniMax (ABAB)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.minimaxi.com/document/guides",baseURL:"https://api.minimax.chat/v1",envVarPrefix:"MINIMAX",requiredEnvVars:["MINIMAX_API_KEY","MINIMAX_GROUP_ID"]},{id:"stepfun",name:"\u9636\u8DC3\u661F\u8FB0 StepFun",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.stepfun.com/docs",baseURL:"https://api.stepfun.com/v1",envVarPrefix:"STEPFUN",requiredEnvVars:["STEPFUN_API_KEY"]},{id:"sensetime",name:"\u5546\u6C64 SenseNova",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.sensetime.com",baseURL:"https://api.sensenova.cn/v1",envVarPrefix:"SENSENOVA",requiredEnvVars:["SENSENOVA_API_KEY"]},{id:"tencent",name:"\u817E\u8BAF\u6DF7\u5143 Hunyuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://cloud.tencent.com/document/product/1729",baseURL:"https://api.hunyuan.cloud.tencent.com/v1",envVarPrefix:"HUNYUAN",requiredEnvVars:["HUNYUAN_API_KEY"]},{id:"lingyi",name:"\u96F6\u4E00\u4E07\u7269 Yi",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.lingyiwanwu.com/docs",baseURL:"https://api.lingyiwanwu.com/v1",envVarPrefix:"YI",requiredEnvVars:["YI_API_KEY"]},{id:"openrouter",name:"OpenRouter",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://openrouter.ai/docs",envVarPrefix:"OPENROUTER",requiredEnvVars:["OPENROUTER_API_KEY"]},{id:"vercel-gateway",name:"Vercel AI Gateway",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://vercel.com/docs/ai-gateway",envVarPrefix:"AI_GATEWAY",requiredEnvVars:["AI_GATEWAY_API_KEY"]},{id:"litellm",name:"LiteLLM Proxy",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://docs.litellm.ai",baseURL:"http://localhost:4000/v1",envVarPrefix:"LITELLM",requiredEnvVars:["LITELLM_API_KEY"]},{id:"portkey",name:"Portkey",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://portkey.ai/docs",baseURL:"https://api.portkey.ai/v1",envVarPrefix:"PORTKEY",requiredEnvVars:["PORTKEY_API_KEY"]},{id:"aws-bedrock",name:"AWS Bedrock",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://aws.amazon.com/bedrock/",envVarPrefix:"AWS_BEDROCK",requiredEnvVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"]},{id:"azure-openai",name:"Azure OpenAI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://azure.microsoft.com/en-us/products/cognitive-services/openai-service/",envVarPrefix:"AZURE_OPENAI",requiredEnvVars:["AZURE_OPENAI_API_KEY","AZURE_OPENAI_ENDPOINT"]},{id:"gcp-vertex",name:"GCP Vertex AI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://cloud.google.com/vertex-ai",envVarPrefix:"GOOGLE_VERTEX",requiredEnvVars:["GOOGLE_APPLICATION_CREDENTIALS"]},{id:"groq",name:"Groq",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://console.groq.com/docs",envVarPrefix:"GROQ",requiredEnvVars:["GROQ_API_KEY"]},{id:"fireworks",name:"Fireworks AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.fireworks.ai",envVarPrefix:"FIREWORKS",requiredEnvVars:["FIREWORKS_API_KEY"]},{id:"together",name:"Together AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.together.ai",envVarPrefix:"TOGETHER",requiredEnvVars:["TOGETHER_API_KEY"]},{id:"huggingface",name:"Hugging Face",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://huggingface.co/docs/inference-providers",envVarPrefix:"HF",requiredEnvVars:["HF_API_KEY"]},{id:"replicate",name:"Replicate",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://replicate.com/docs",envVarPrefix:"REPLICATE",requiredEnvVars:["REPLICATE_API_TOKEN"]},{id:"lepton",name:"Lepton AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://www.lepton.ai/docs",baseURL:"https://api.lepton.ai/v1",envVarPrefix:"LEPTON",requiredEnvVars:["LEPTON_API_KEY"]},{id:"anyscale",name:"Anyscale Endpoints",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://docs.endpoints.anyscale.com/",baseURL:"https://api.endpoints.anyscale.com/v1",envVarPrefix:"ANYSCALE",requiredEnvVars:["ANYSCALE_API_KEY"]},{id:"octoai",name:"OctoAI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://octoai.cloud/docs",baseURL:"https://text.octoai.run/v1",envVarPrefix:"OCTOAI",requiredEnvVars:["OCTOAI_TOKEN"]},{id:"deepinfra",name:"DeepInfra",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://deepinfra.com/docs",baseURL:"https://api.deepinfra.com/v1/openai",envVarPrefix:"DEEPINFRA",requiredEnvVars:["DEEPINFRA_API_KEY"]},{id:"novita",name:"Novita AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://novita.ai/docs",baseURL:"https://api.novita.ai/v3/openai",envVarPrefix:"NOVITA",requiredEnvVars:["NOVITA_API_KEY"]},{id:"black-forest-labs",name:"Black Forest Labs (FLUX)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://docs.bfl.ml",envVarPrefix:"BFL",requiredEnvVars:["BFL_API_KEY"]},{id:"elevenlabs",name:"ElevenLabs (TTS)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://elevenlabs.io/docs",envVarPrefix:"ELEVENLABS",requiredEnvVars:["ELEVENLABS_API_KEY"]},{id:"runway",name:"Runway (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://runwayml.com",envVarPrefix:"RUNWAY",requiredEnvVars:["RUNWAY_API_KEY"]},{id:"luma",name:"Luma (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://lumalabs.ai",envVarPrefix:"LUMA",requiredEnvVars:["LUMA_API_KEY"]},{id:"midjourney",name:"Midjourney",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://docs.midjourney.com",envVarPrefix:"MIDJOURNEY",requiredEnvVars:[]},{id:"ollama",name:"Ollama (\u672C\u5730)",category:"\u672C\u5730\u90E8\u7F72",status:"opencode",docs:"https://github.com/ollama/ollama",baseURL:"http://localhost:11434/v1",envVarPrefix:"OLLAMA",requiredEnvVars:["OLLAMA_BASE_URL"]},{id:"lmstudio",name:"LM Studio",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://lmstudio.ai/docs",baseURL:"http://localhost:1234/v1",envVarPrefix:"LMSTUDIO",requiredEnvVars:[]},{id:"vllm",name:"vLLM",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://docs.vllm.ai",baseURL:"http://localhost:8000/v1",envVarPrefix:"VLLM",requiredEnvVars:[]},{id:"tgi",name:"HF TGI",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://huggingface.co/docs/text-generation-inference",baseURL:"http://localhost:8080/v1",envVarPrefix:"TGI",requiredEnvVars:[]}],na=Et.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var Zo="https://analytics.nebutra.com";function er(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function an(e,t={}){er(t)||(async()=>{try{let o=await import("./dist-XS6SQF6X.js");if(typeof o.createAnalyticsClient!="function")return;let n=o.createAnalyticsClient({posthog:{apiKey:process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.NEBUTRA_POSTHOG_HOST??Zo},onError:()=>{}});if(typeof n?.track!="function")return;let r=n.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import Ge from"fs";import T from"path";var cn=[{id:"posthog",name:"PostHog",region:"both",envVars:["POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_HOST"],docs:"https://posthog.com/docs",pkgs:["posthog-js","posthog-node"],providerFile:"apps/web/src/lib/analytics/posthog.client.ts"},{id:"plausible",name:"Plausible",region:"global",envVars:["NEXT_PUBLIC_PLAUSIBLE_DOMAIN","NEXT_PUBLIC_PLAUSIBLE_SRC"],docs:"https://plausible.io/docs",providerFile:"apps/web/src/components/analytics/PlausibleScript.tsx"},{id:"umami",name:"Umami",region:"both",envVars:["NEXT_PUBLIC_UMAMI_WEBSITE_ID","NEXT_PUBLIC_UMAMI_SRC"],docs:"https://umami.is/docs",providerFile:"apps/web/src/components/analytics/UmamiScript.tsx"},{id:"mixpanel",name:"Mixpanel",region:"global",envVars:["MIXPANEL_TOKEN","NEXT_PUBLIC_MIXPANEL_TOKEN"],docs:"https://docs.mixpanel.com",pkgs:["mixpanel-browser","mixpanel"],providerFile:"apps/web/src/lib/analytics/mixpanel.client.ts"},{id:"baidu",name:"\u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji",region:"cn",envVars:["NEXT_PUBLIC_BAIDU_STATS_ID"],docs:"https://tongji.baidu.com",providerFile:"apps/web/src/components/analytics/BaiduStatsScript.tsx"},{id:"sensors",name:"\u795E\u7B56 Sensors Analytics",region:"cn",envVars:["NEXT_PUBLIC_SENSORS_SERVER_URL","NEXT_PUBLIC_SENSORS_APP_JS_URL"],docs:"https://manual.sensorsdata.cn",pkgs:["sa-sdk-javascript"],providerFile:"apps/web/src/lib/analytics/sensors.client.ts"},{id:"growingio",name:"GrowingIO",region:"cn",envVars:["NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID"],docs:"https://growingio.com/docs",providerFile:"apps/web/src/components/analytics/GrowingIoScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],sa=cn.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function pn(e){return cn.find(t=>t.id===e)}function tr(e){Ge.mkdirSync(e,{recursive:!0})}function q(e,t){tr(T.dirname(e)),Ge.writeFileSync(e,t)}function me(e,t){let o=T.join(e,".env.example");Ge.existsSync(o)?Ge.appendFileSync(o,`
|
|
71
|
-
`+t):Ge.writeFileSync(o,t)}function
|
|
76
|
+
`;function an(){process.stdout.write(er)}import Et from"picocolors";function cn(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function tr(e){let t=cn()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return cn()?`${Et.dim(o)} ${Et.bold(n)} ${Et.dim(t)} ${Et.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function pn(e){process.stdout.write(tr(e)+`
|
|
77
|
+
`)}var Mt=[{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:[]}],pa=Mt.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var nr=["openai","anthropic","google"],or=["openai"];function Dt(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...nr];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:[...or];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 Ge from"fs";import k from"path";var ln=[{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:""}],ua=ln.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function dn(e){return ln.find(t=>t.id===e)}function rr(e){Ge.mkdirSync(e,{recursive:!0})}function $(e,t){rr(k.dirname(e)),Ge.writeFileSync(e,t)}function ge(e,t){let o=k.join(e,".env.example");Ge.existsSync(o)?Ge.appendFileSync(o,`
|
|
78
|
+
`+t):Ge.writeFileSync(o,t)}function ir(e){let t=`"use client";
|
|
72
79
|
/**
|
|
73
80
|
* PostHog browser SDK \u2014 lazy-initialized on first access.
|
|
74
81
|
*/
|
|
@@ -151,11 +158,11 @@ export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
|
|
|
151
158
|
|
|
152
159
|
return <>{children}</>;
|
|
153
160
|
}
|
|
154
|
-
|
|
161
|
+
`;$(k.join(e,"src","lib","analytics","posthog.client.ts"),t),$(k.join(e,"src","lib","analytics","posthog.server.ts"),o),$(k.join(e,"src","components","analytics","AnalyticsProvider.tsx"),n)}function sr(){return`# PostHog \u2014 product analytics
|
|
155
162
|
POSTHOG_KEY=
|
|
156
163
|
NEXT_PUBLIC_POSTHOG_KEY=
|
|
157
164
|
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
|
158
|
-
`}function
|
|
165
|
+
`}function ar(e){$(k.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
|
|
159
166
|
/**
|
|
160
167
|
* Plausible script tag \u2014 lightweight, privacy-friendly analytics.
|
|
161
168
|
*/
|
|
@@ -175,10 +182,10 @@ export function PlausibleScript() {
|
|
|
175
182
|
/>
|
|
176
183
|
);
|
|
177
184
|
}
|
|
178
|
-
`)}function
|
|
185
|
+
`)}function cr(){return`# Plausible \u2014 privacy-friendly analytics
|
|
179
186
|
NEXT_PUBLIC_PLAUSIBLE_DOMAIN=
|
|
180
187
|
NEXT_PUBLIC_PLAUSIBLE_SRC=https://plausible.io/js/script.js
|
|
181
|
-
`}function
|
|
188
|
+
`}function pr(e){$(k.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
|
|
182
189
|
/**
|
|
183
190
|
* Umami analytics \u2014 self-hosted OR umami.is cloud.
|
|
184
191
|
*/
|
|
@@ -198,10 +205,10 @@ export function UmamiScript() {
|
|
|
198
205
|
/>
|
|
199
206
|
);
|
|
200
207
|
}
|
|
201
|
-
`)}function
|
|
208
|
+
`)}function lr(){return`# Umami \u2014 self-hostable analytics
|
|
202
209
|
NEXT_PUBLIC_UMAMI_WEBSITE_ID=
|
|
203
210
|
NEXT_PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
|
|
204
|
-
`}function
|
|
211
|
+
`}function dr(e){let t=`"use client";
|
|
205
212
|
import mixpanel from "mixpanel-browser";
|
|
206
213
|
|
|
207
214
|
let initialized = false;
|
|
@@ -240,10 +247,10 @@ export function trackServer(
|
|
|
240
247
|
if (!c) return;
|
|
241
248
|
c.track(event, { distinct_id: distinctId, ...properties });
|
|
242
249
|
}
|
|
243
|
-
|
|
250
|
+
`;$(k.join(e,"src","lib","analytics","mixpanel.client.ts"),t),$(k.join(e,"src","lib","analytics","mixpanel.server.ts"),o)}function ur(){return`# Mixpanel \u2014 product analytics
|
|
244
251
|
MIXPANEL_TOKEN=
|
|
245
252
|
NEXT_PUBLIC_MIXPANEL_TOKEN=
|
|
246
|
-
`}function
|
|
253
|
+
`}function mr(e){$(k.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
|
|
247
254
|
/**
|
|
248
255
|
* \u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji \u2014 hm.js \u57CB\u70B9\u811A\u672C.
|
|
249
256
|
*/
|
|
@@ -269,9 +276,9 @@ var _hmt = _hmt || [];
|
|
|
269
276
|
/>
|
|
270
277
|
);
|
|
271
278
|
}
|
|
272
|
-
`)}function
|
|
279
|
+
`)}function gr(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
|
|
273
280
|
NEXT_PUBLIC_BAIDU_STATS_ID=
|
|
274
|
-
`}function
|
|
281
|
+
`}function fr(e){$(k.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
|
|
275
282
|
/**
|
|
276
283
|
* \u795E\u7B56\u5206\u6790 (Sensors Analytics) \u2014 sa-sdk-javascript \u5C01\u88C5.
|
|
277
284
|
*/
|
|
@@ -299,10 +306,10 @@ export function initSensors(): void {
|
|
|
299
306
|
}
|
|
300
307
|
|
|
301
308
|
export { sensors };
|
|
302
|
-
`)}function
|
|
309
|
+
`)}function yr(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
|
|
303
310
|
NEXT_PUBLIC_SENSORS_SERVER_URL=
|
|
304
311
|
NEXT_PUBLIC_SENSORS_APP_JS_URL=
|
|
305
|
-
`}function
|
|
312
|
+
`}function Sr(e){$(k.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
|
|
306
313
|
/**
|
|
307
314
|
* GrowingIO CDP \u2014 inline snippet installer.
|
|
308
315
|
*/
|
|
@@ -327,21 +334,21 @@ gdp("send");
|
|
|
327
334
|
/>
|
|
328
335
|
);
|
|
329
336
|
}
|
|
330
|
-
`)}function
|
|
337
|
+
`)}function Er(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
|
|
331
338
|
NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
|
|
332
|
-
`}async function
|
|
333
|
-
`+t):
|
|
334
|
-
`+t)}async function
|
|
339
|
+
`}async function un(e,t,o="global"){let n=dn(t);if(!n||n.id==="none")return;let r=k.join(e,"apps","web");if(!Ge.existsSync(r))return;let i=n.id;try{switch(i){case"posthog":ir(r),ge(e,sr());return;case"plausible":ar(r),ge(e,cr());return;case"umami":pr(r),ge(e,lr());return;case"mixpanel":dr(r),ge(e,ur());return;case"baidu":mr(r),ge(e,gr());return;case"sensors":fr(r),ge(e,yr());return;case"growingio":Sr(r),ge(e,Er());return;default:return}}catch(s){throw console.error(`Failed to apply analytics selection "${t}":`,s),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var hr="https://analytics.nebutra.com";function vr(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function mn(e,t={}){vr(t)||(async()=>{try{let o=await import("./dist-B4YTE2SQ.js");if(typeof o.createAnalyticsClient!="function")return;let n=o.createAnalyticsClient({posthog:{apiKey:process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.NEBUTRA_POSTHOG_HOST??hr},onError:()=>{}});if(typeof n?.track!="function")return;let r=n.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import U from"fs";import fe from"path";function Ft(e){U.existsSync(e)&&U.rmSync(e,{recursive:!0,force:!0})}function gn(e,t){let o=fe.join(e,".env.example");U.existsSync(o)?U.appendFileSync(o,`
|
|
340
|
+
`+t):U.writeFileSync(o,t)}function fn(e,t){if(!U.existsSync(e))return;let o=U.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*"[^"]+"\s*\|\s*"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&U.writeFileSync(e,n)}function _r(e,t){let o=fe.join(e,"README.md");if(!U.existsSync(o)){U.writeFileSync(o,t);return}U.appendFileSync(o,`
|
|
341
|
+
`+t)}async function yn(e,t){let o=fe.join(e,"packages","auth");if(!U.existsSync(o))return;if(t==="none"){Ft(o),_r(e,`
|
|
335
342
|
## Auth
|
|
336
343
|
|
|
337
344
|
Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth).
|
|
338
|
-
`);return}let n=
|
|
345
|
+
`);return}let n=fe.join(o,"src","providers"),r=fe.join(o,"src","types.ts");if(t==="clerk"){Ft(fe.join(n,"better-auth.ts")),fn(r,"clerk"),gn(e,`# Clerk auth
|
|
339
346
|
CLERK_PUBLISHABLE_KEY=
|
|
340
347
|
CLERK_SECRET_KEY=
|
|
341
|
-
`);return}if(t==="betterauth"){
|
|
348
|
+
`);return}if(t==="betterauth"){Ft(fe.join(n,"clerk.ts")),fn(r,"better-auth"),gn(e,`# Better Auth
|
|
342
349
|
BETTER_AUTH_SECRET=
|
|
343
350
|
BETTER_AUTH_URL=http://localhost:3000
|
|
344
|
-
`);return}}var nt=[{id:"wechat",name:"\u5FAE\u4FE1\u5F00\u653E\u5E73\u53F0",region:"cn",envVars:["WECHAT_APP_ID","WECHAT_APP_SECRET"],docs:"https://open.weixin.qq.com/cgi-bin/showdocument",callbackUrl:"/api/auth/callback/wechat",tokenEndpoint:"https://api.weixin.qq.com/sns/oauth2/access_token"},{id:"qq",name:"QQ \u767B\u5F55",region:"cn",envVars:["QQ_APP_ID","QQ_APP_KEY"],docs:"https://wiki.connect.qq.com",callbackUrl:"/api/auth/callback/qq",tokenEndpoint:"https://graph.qq.com/oauth2.0/token"},{id:"dingtalk",name:"\u9489\u9489",region:"cn",envVars:["DINGTALK_APP_ID","DINGTALK_APP_SECRET"],docs:"https://open.dingtalk.com/document/",callbackUrl:"/api/auth/callback/dingtalk",tokenEndpoint:"https://api.dingtalk.com/v1.0/oauth2/userAccessToken"},{id:"workweixin",name:"\u4F01\u4E1A\u5FAE\u4FE1",region:"cn",envVars:["WORKWEIXIN_CORP_ID","WORKWEIXIN_AGENT_ID","WORKWEIXIN_SECRET"],docs:"https://developer.work.weixin.qq.com",callbackUrl:"/api/auth/callback/workweixin",tokenEndpoint:"https://qyapi.weixin.qq.com/cgi-bin/gettoken"},{id:"feishu",name:"\u98DE\u4E66 / Lark",region:"cn",envVars:["FEISHU_APP_ID","FEISHU_APP_SECRET"],docs:"https://open.feishu.cn/document/",callbackUrl:"/api/auth/callback/feishu",tokenEndpoint:"https://open.feishu.cn/open-apis/authen/v1/access_token"},{id:"weibo",name:"\u5FAE\u535A",region:"cn",envVars:["WEIBO_APP_KEY","WEIBO_APP_SECRET"],docs:"https://open.weibo.com/wiki/",callbackUrl:"/api/auth/callback/weibo",tokenEndpoint:"https://api.weibo.com/oauth2/access_token"}],
|
|
351
|
+
`);return}}var nt=[{id:"wechat",name:"\u5FAE\u4FE1\u5F00\u653E\u5E73\u53F0",region:"cn",envVars:["WECHAT_APP_ID","WECHAT_APP_SECRET"],docs:"https://open.weixin.qq.com/cgi-bin/showdocument",callbackUrl:"/api/auth/callback/wechat",tokenEndpoint:"https://api.weixin.qq.com/sns/oauth2/access_token"},{id:"qq",name:"QQ \u767B\u5F55",region:"cn",envVars:["QQ_APP_ID","QQ_APP_KEY"],docs:"https://wiki.connect.qq.com",callbackUrl:"/api/auth/callback/qq",tokenEndpoint:"https://graph.qq.com/oauth2.0/token"},{id:"dingtalk",name:"\u9489\u9489",region:"cn",envVars:["DINGTALK_APP_ID","DINGTALK_APP_SECRET"],docs:"https://open.dingtalk.com/document/",callbackUrl:"/api/auth/callback/dingtalk",tokenEndpoint:"https://api.dingtalk.com/v1.0/oauth2/userAccessToken"},{id:"workweixin",name:"\u4F01\u4E1A\u5FAE\u4FE1",region:"cn",envVars:["WORKWEIXIN_CORP_ID","WORKWEIXIN_AGENT_ID","WORKWEIXIN_SECRET"],docs:"https://developer.work.weixin.qq.com",callbackUrl:"/api/auth/callback/workweixin",tokenEndpoint:"https://qyapi.weixin.qq.com/cgi-bin/gettoken"},{id:"feishu",name:"\u98DE\u4E66 / Lark",region:"cn",envVars:["FEISHU_APP_ID","FEISHU_APP_SECRET"],docs:"https://open.feishu.cn/document/",callbackUrl:"/api/auth/callback/feishu",tokenEndpoint:"https://open.feishu.cn/open-apis/authen/v1/access_token"},{id:"weibo",name:"\u5FAE\u535A",region:"cn",envVars:["WEIBO_APP_KEY","WEIBO_APP_SECRET"],docs:"https://open.weibo.com/wiki/",callbackUrl:"/api/auth/callback/weibo",tokenEndpoint:"https://api.weibo.com/oauth2/access_token"}],Pr=new Set(nt.map(e=>e.id));function Sn(e){return nt.find(t=>t.id===e)}function En(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)Pr.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import Se from"fs";import ye from"path";function br(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
|
|
345
352
|
// Generated by create-sailor \u2014 OAuth callback for ${e.name}
|
|
346
353
|
// Primary auth provider: ${t}
|
|
347
354
|
// Docs: ${e.docs}`,n={wechat:` const tokenRes = await fetch(
|
|
@@ -466,7 +473,7 @@ ${n[e.id]}
|
|
|
466
473
|
void state;
|
|
467
474
|
return NextResponse.redirect(new URL("/dashboard", req.url));
|
|
468
475
|
}
|
|
469
|
-
`}function
|
|
476
|
+
`}function Ir(e){return`"use client";
|
|
470
477
|
|
|
471
478
|
/**
|
|
472
479
|
* SocialLoginButtons \u2014 generated by create-sailor.
|
|
@@ -509,23 +516,23 @@ export function SocialLoginButtons() {
|
|
|
509
516
|
</div>
|
|
510
517
|
);
|
|
511
518
|
}
|
|
512
|
-
`}function
|
|
513
|
-
`+t):
|
|
519
|
+
`}function hn(e){Se.mkdirSync(e,{recursive:!0})}function Ar(e,t){let o=ye.join(e,".env.example");Se.existsSync(o)?Se.appendFileSync(o,`
|
|
520
|
+
`+t):Se.writeFileSync(o,t)}function Cr(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
514
521
|
`);return`${t}
|
|
515
522
|
${o}
|
|
516
|
-
`}async function
|
|
517
|
-
`);
|
|
518
|
-
`)}async function
|
|
519
|
-
`);J.appendFileSync(o,c)}function
|
|
523
|
+
`}async function vn(e,t,o){if(!t||t.length===0)return;let n=ye.join(e,"apps","web");if(!Se.existsSync(n))return;let r=new Set,i=[];for(let d of t){if(r.has(d))continue;r.add(d);let u=Sn(d);u&&i.push(u)}if(i.length===0)return;for(let d of i)Ar(e,Cr(d));let s=ye.join(n,"src","app","api","auth","callback");for(let d of i){let u=ye.join(s,d.id);hn(u);let h=ye.join(u,"route.ts");Se.writeFileSync(h,br(d,o))}let c=ye.join(n,"src","components","auth");hn(c);let a=ye.join(c,"SocialLoginButtons.tsx");Se.writeFileSync(a,Ir(i))}import ne from"fs";import jt from"path";var ht=[{id:"upstash-redis",name:"Upstash Redis",region:"both",envVars:["UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"],docs:"https://upstash.com/docs/redis",description:"Serverless Redis"},{id:"vercel-kv",name:"Vercel KV",region:"global",envVars:["KV_URL","KV_REST_API_URL","KV_REST_API_TOKEN","KV_REST_API_READ_ONLY_TOKEN"],docs:"https://vercel.com/docs/storage/vercel-kv",description:"Vercel native KV"},{id:"redis",name:"Redis (self-hosted)",region:"both",envVars:["REDIS_URL"],docs:"https://redis.io/docs/",description:"Self-hosted Redis"},{id:"dragonfly",name:"Dragonfly",region:"global",envVars:["DRAGONFLY_URL"],docs:"https://www.dragonflydb.io/docs",description:"Drop-in Redis replacement, faster"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip cache package"}];function _n(e){return ht.find(t=>t.id===e)}var wa=ht.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Pn(e){return ne.existsSync(e)?ne.readFileSync(e,"utf-8"):null}function wr(e,t){let o=jt.join(e,".env.example"),n=Pn(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
|
|
524
|
+
`);ne.appendFileSync(o,i)}function Rr(e,t,o){let n=jt.join(e,".env.example"),r=Pn(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ne.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ne.appendFileSync(n,`${t}="${o}"
|
|
525
|
+
`)}async function bn(e,t,o){let n=jt.join(e,"packages","cache");if(t==="none"){ne.existsSync(n)&&ne.rmSync(n,{recursive:!0,force:!0});return}let r=_n(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${ht.map(i=>i.id).join(", ")}`);ne.existsSync(n)&&(wr(e,r),Rr(e,"CACHE_PROVIDER",t))}var vt=[{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 In(e){return vt.find(t=>t.id===e)}var Oa=vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import J from"fs";import Vt from"path";function q(e,t){let o=Vt.join(e,".env.example");if(!J.existsSync(o)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(J.readFileSync(o,"utf-8").includes(r))return;let c=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].filter(a=>a!==null).join(`
|
|
526
|
+
`);J.appendFileSync(o,c)}function G(e,t,o){let n=Vt.join(e,".env.example");if(!J.existsSync(n))return;let r=J.readFileSync(n,"utf-8"),i=`${t}="${o}"`,s=new RegExp(`^${t}=.*$`,"m");if(s.test(r)){J.writeFileSync(n,r.replace(s,i));return}let c=r.endsWith(`
|
|
520
527
|
`)?"":`
|
|
521
|
-
`;J.appendFileSync(n,`${c}${
|
|
522
|
-
`)}function
|
|
528
|
+
`;J.appendFileSync(n,`${c}${i}
|
|
529
|
+
`)}function K(e,t){let o=Vt.join(e,"packages",t);J.existsSync(o)&&J.rmSync(o,{recursive:!0,force:!0})}async function An(e,t,o="global"){let n=In(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${vt.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"captcha");return}n.envVars.length>0&&q(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"CAPTCHA_PROVIDER",n.id)}import Pt from"fs";import xr from"path";var _t=[{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 Cn(e){return _t.find(t=>t.id===e)}var Ka=_t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function wn(e,t,o="global"){let n=Cn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${_t.map(i=>i.id).join(", ")}`);let r=xr.join(e,"apps","studio");if(n.id==="none"){K(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(K(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&q(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"CMS_PROVIDER",n.id)}import A from"fs";import I from"path";var Nr=I.join("apps","web"),Kt=I.join("src","components","compliance"),ot=I.join("src","app","[locale]");function H(e){return I.join(e,Nr)}function kr(e){A.mkdirSync(e,{recursive:!0})}function B(e,t){kr(I.dirname(e)),A.writeFileSync(e,t,"utf8")}function Bt(e,t){let o=I.join(e,".env.example");if(A.existsSync(o)){if(A.readFileSync(o,"utf8").includes(t.split(`
|
|
523
530
|
`)[0]??""))return;A.appendFileSync(o,`
|
|
524
531
|
`+t+`
|
|
525
532
|
`)}else A.writeFileSync(o,t+`
|
|
526
533
|
`)}var rt=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
|
|
527
534
|
> Consult a qualified lawyer in every jurisdiction you operate in before publishing.
|
|
528
|
-
> \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,
|
|
535
|
+
> \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`,Tr=`import Link from "next/link";
|
|
529
536
|
import { IcpFooter } from "@/components/compliance/IcpFooter";
|
|
530
537
|
import { PublicSecurityFooter } from "@/components/compliance/PublicSecurityFooter";
|
|
531
538
|
|
|
@@ -576,7 +583,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
576
583
|
</footer>
|
|
577
584
|
);
|
|
578
585
|
}
|
|
579
|
-
`,
|
|
586
|
+
`,Or=`export function IcpFooter() {
|
|
580
587
|
const icp = process.env.NEXT_PUBLIC_ICP_BEIAN;
|
|
581
588
|
if (!icp) return null;
|
|
582
589
|
return (
|
|
@@ -590,7 +597,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
590
597
|
</a>
|
|
591
598
|
);
|
|
592
599
|
}
|
|
593
|
-
`,
|
|
600
|
+
`,Ur=`export function PublicSecurityFooter() {
|
|
594
601
|
const psb = process.env.NEXT_PUBLIC_PSB_BEIAN;
|
|
595
602
|
const psbCode = process.env.NEXT_PUBLIC_PSB_CODE;
|
|
596
603
|
if (!psb) return null;
|
|
@@ -607,7 +614,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
607
614
|
</a>
|
|
608
615
|
);
|
|
609
616
|
}
|
|
610
|
-
`,
|
|
617
|
+
`,Lr=`"use client";
|
|
611
618
|
|
|
612
619
|
import { useCallback, useEffect, useState } from "react";
|
|
613
620
|
|
|
@@ -834,7 +841,7 @@ function CategoryRow({ id, title, description, checked, disabled, onChange }: Ca
|
|
|
834
841
|
</label>
|
|
835
842
|
);
|
|
836
843
|
}
|
|
837
|
-
`,
|
|
844
|
+
`,Mr=`interface AigcDisclaimerProps {
|
|
838
845
|
className?: string;
|
|
839
846
|
}
|
|
840
847
|
|
|
@@ -854,7 +861,7 @@ export function AigcDisclaimer({ className }: AigcDisclaimerProps) {
|
|
|
854
861
|
</div>
|
|
855
862
|
);
|
|
856
863
|
}
|
|
857
|
-
`,
|
|
864
|
+
`,Dr=`---
|
|
858
865
|
title: Privacy Policy / \u9690\u79C1\u653F\u7B56
|
|
859
866
|
description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal information.
|
|
860
867
|
lastUpdated: 2026-01-01
|
|
@@ -999,7 +1006,7 @@ or in-app notification before the change takes effect.
|
|
|
999
1006
|
**Data Controller / \u6570\u636E\u63A7\u5236\u8005:** {{COMPANY_NAME}}
|
|
1000
1007
|
**Address / \u5730\u5740:** {{COMPANY_ADDRESS}}
|
|
1001
1008
|
**Email / \u90AE\u7BB1:** {{COMPANY_CONTACT_EMAIL}}
|
|
1002
|
-
`,
|
|
1009
|
+
`,Fr=`---
|
|
1003
1010
|
title: Terms of Service / \u670D\u52A1\u6761\u6B3E
|
|
1004
1011
|
description: Terms governing your use of {{COMPANY_NAME}}.
|
|
1005
1012
|
lastUpdated: 2026-01-01
|
|
@@ -1118,7 +1125,7 @@ conflict-of-laws principles. Disputes shall be resolved in the competent courts
|
|
|
1118
1125
|
## 11. Contact / \u8054\u7CFB\u65B9\u5F0F
|
|
1119
1126
|
|
|
1120
1127
|
{{COMPANY_NAME}} \xB7 {{COMPANY_ADDRESS}} \xB7 {{COMPANY_CONTACT_EMAIL}}
|
|
1121
|
-
`,
|
|
1128
|
+
`,jr=`---
|
|
1122
1129
|
title: AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
|
|
1123
1130
|
description: Disclosure required by \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300B
|
|
1124
1131
|
lastUpdated: 2026-01-01
|
|
@@ -1200,7 +1207,7 @@ human professional.
|
|
|
1200
1207
|
|
|
1201
1208
|
AI \u8F93\u51FA\u53EF\u80FD\u4E0D\u51C6\u786E\u3001\u5B58\u5728\u504F\u89C1\u6216\u8FC7\u65F6\u3002**\u8BF7\u52FF**\u5728\u672A\u7ECF\u5408\u683C\u4E13\u4E1A\u4EBA\u58EB\u72EC\u7ACB\u6838\u5B9E\u7684\u60C5\u51B5\u4E0B\uFF0C\u5C06 AI \u8F93\u51FA
|
|
1202
1209
|
\u7528\u4E8E\u533B\u7597\u3001\u6CD5\u5F8B\u3001\u91D1\u878D\u6216\u5B89\u5168\u6538\u5173\u7684\u51B3\u7B56\u3002
|
|
1203
|
-
`,
|
|
1210
|
+
`,Vr=`---
|
|
1204
1211
|
title: Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
|
|
1205
1212
|
description: Notice of cross-border transfer of personal information, per PIPL.
|
|
1206
1213
|
lastUpdated: 2026-01-01
|
|
@@ -1265,7 +1272,7 @@ Refusal may limit your ability to use features that rely on overseas services.
|
|
|
1265
1272
|
- \u4F20\u8F93\u4E2D\u52A0\u5BC6 (TLS 1.2+) \u53CA\u9759\u6001\u52A0\u5BC6 (AES-256)\u3002
|
|
1266
1273
|
- \u5408\u540C\u6761\u6B3E\u8981\u6C42\u5883\u5916\u63A5\u6536\u65B9\u63D0\u4F9B\u7B49\u540C\u4E8E PIPL \u7684\u4FDD\u62A4\u3002
|
|
1267
1274
|
- \u8BBF\u95EE\u63A7\u5236\u3001\u5BA1\u8BA1\u65E5\u5FD7\u548C\u8FDD\u89C4\u901A\u77E5\u7A0B\u5E8F\u3002
|
|
1268
|
-
`,
|
|
1275
|
+
`,Kr=`---
|
|
1269
1276
|
title: Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
|
|
1270
1277
|
description: Itemized list of personal information collected, per PIPL Article 17.
|
|
1271
1278
|
lastUpdated: 2026-01-01
|
|
@@ -1307,19 +1314,19 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
|
|
|
1307
1314
|
**{{COMPANY_CONTACT_EMAIL}}**.
|
|
1308
1315
|
|
|
1309
1316
|
\u5982\u9700\u884C\u4F7F\u60A8\u7684\u6743\u5229\uFF08\u8BBF\u95EE\u3001\u66F4\u6B63\u3001\u5220\u9664\u3001\u5BFC\u51FA\u3001\u64A4\u56DE\u540C\u610F\uFF09\uFF0C\u8BF7\u8054\u7CFB **{{COMPANY_CONTACT_EMAIL}}**\u3002
|
|
1310
|
-
`;async function
|
|
1311
|
-
`))}async function
|
|
1312
|
-
`))}async function
|
|
1313
|
-
`))}async function
|
|
1314
|
-
`))}async function
|
|
1315
|
-
`)}import
|
|
1316
|
-
`+t):
|
|
1317
|
-
DATABASE_URL="${
|
|
1318
|
-
`),!
|
|
1319
|
-
`+t):
|
|
1317
|
+
`;async function Br(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","Footer.tsx");B(n,Tr);let r=I.join(o,"src","components","compliance","README.md");B(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(`
|
|
1318
|
+
`))}async function Yr(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","CookieBanner.tsx");B(n,Lr)}async function $r(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,ot,"privacy","page.mdx");B(n,Dr)}async function qr(e,t){let o=H(e);if(!A.existsSync(o))return;let n=I.join(o,ot,"terms","page.mdx");B(n,Fr)}async function Gr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"IcpFooter.tsx");B(o,Or),Bt(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(`
|
|
1319
|
+
`))}async function Hr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"PublicSecurityFooter.tsx");B(o,Ur),Bt(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(`
|
|
1320
|
+
`))}async function Wr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,Kt,"AigcDisclaimer.tsx");B(o,Mr),Bt(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(`
|
|
1321
|
+
`))}async function Xr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"aigc-disclosure","page.mdx");B(o,jr)}async function zr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"cross-border-data","page.mdx");B(o,Vr)}async function Qr(e){let t=H(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"pii-collection","page.mdx");B(o,Kr)}async function Rn(e,t){try{await Br(e,t),await Yr(e,t),await $r(e,t),await qr(e,t),(t==="cn"||t==="hybrid")&&(await Gr(e),await Hr(e),await Wr(e),await Xr(e),await zr(e),await Qr(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 Jr from"fs";import Zr from"path";async function xn(e,t){let o=Zr.join(e,"nebutra.config.json");Jr.writeFileSync(o,JSON.stringify(t,null,2)+`
|
|
1322
|
+
`)}import oe from"fs";import Yt from"path";function ei(e){oe.existsSync(e)&&oe.rmSync(e,{recursive:!0,force:!0})}function Nn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function ti(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function kn(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 ni(e,t){let o=Yt.join(e,".env.example");oe.existsSync(o)?oe.appendFileSync(o,`
|
|
1323
|
+
`+t):oe.writeFileSync(o,t)}async function Tn(e,t,o){let n=Yt.join(e,"packages","db");if(t==="none"){ei(n);return}let r=Yt.join(n,"prisma","schema.prisma"),i;if(t==="postgresql"?i=`postgresql://postgres:postgres@localhost:5432/${o}`:t==="mysql"?i=`mysql://root:root@localhost:3306/${o}`:i="file:./dev.db",ni(e,`# Database (${t})
|
|
1324
|
+
DATABASE_URL="${i}"
|
|
1325
|
+
`),!oe.existsSync(r))return;let s=oe.readFileSync(r,"utf8"),c=s;t==="mysql"?(c=Nn(c,"mysql"),c=kn(c)):t==="sqlite"&&(c=Nn(c,"sqlite"),c=ti(c),c=kn(c)),c!==s&&oe.writeFileSync(r,c)}import it from"fs";import L from"path";import{fileURLToPath as oi}from"url";var ri=oi(import.meta.url),ii=L.dirname(ri);async function On(e,t){if(t==="none")return;let o=L.join(ii,"../../templates/deploy");t==="vercel"?await it.promises.copyFile(L.join(o,"vercel.json"),L.join(e,"vercel.json")):t==="railway"?await it.promises.copyFile(L.join(o,"railway.toml"),L.join(e,"railway.toml")):t==="cloudflare"?await it.promises.copyFile(L.join(o,"wrangler.toml"),L.join(e,"wrangler.toml")):t==="selfhost"&&(await it.promises.copyFile(L.join(o,"docker-compose.yml"),L.join(e,"docker-compose.yml")),await it.promises.copyFile(L.join(o,"Dockerfile.web"),L.join(e,"Dockerfile.web")))}import re from"fs";import Ee from"path";import{fileURLToPath as si}from"url";var ai=si(import.meta.url),Un=Ee.dirname(ai),ci=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml)$/;function pi(e){let t=[Ee.join(Un,"..","templates","docs",e),Ee.join(Un,"..","..","templates","docs",e)];for(let o of t)if(re.existsSync(o))return o;return t[0]}async function Ln(e,t){if(t.framework==="none")return;let o=(t.framework==="fumadocs","fumadocs"),n=pi(o),r=Ee.join(e,"apps","docs");if(!re.existsSync(n))throw new Error(`Docs template not found: ${n}`);Mn(n,r),Dn(r,{"{PRODUCT_NAME}":t.projectName})}function Mn(e,t){re.mkdirSync(t,{recursive:!0});for(let o of re.readdirSync(e,{withFileTypes:!0})){let n=Ee.join(e,o.name),r=Ee.join(t,o.name);o.isDirectory()?Mn(n,r):re.copyFileSync(n,r)}}function Dn(e,t){for(let o of re.readdirSync(e,{withFileTypes:!0})){let n=Ee.join(e,o.name);if(o.isDirectory())Dn(n,t);else if(ci.test(o.name)){let r=re.readFileSync(n,"utf-8");for(let[i,s]of Object.entries(t))r=r.split(i).join(s);re.writeFileSync(n,r)}}}import ve from"fs";import he from"path";var bt=[{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 Fn(e){return bt.find(t=>t.id===e)}var dc=bt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var _e="@nebutra/email";function $t(e,t){ve.mkdirSync(he.dirname(e),{recursive:!0}),ve.writeFileSync(e,t)}function li(e,t){let o=he.join(e,".env.example");ve.existsSync(o)?ve.appendFileSync(o,`
|
|
1326
|
+
`+t):ve.writeFileSync(o,t)}function di(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
1320
1327
|
`);return`${t}
|
|
1321
1328
|
${o}
|
|
1322
|
-
`}var
|
|
1329
|
+
`}var ui=`/**
|
|
1323
1330
|
* Public inputs accepted by the \`sendEmail\` wrapper.
|
|
1324
1331
|
* Keep the surface minimal \u2014 individual providers may accept more, but
|
|
1325
1332
|
* consumers should code against this shape for portability.
|
|
@@ -1339,8 +1346,8 @@ export interface SendEmailResult {
|
|
|
1339
1346
|
/** Raw provider response \u2014 useful for debugging, not a stable contract. */
|
|
1340
1347
|
raw?: unknown;
|
|
1341
1348
|
}
|
|
1342
|
-
`;function
|
|
1343
|
-
* @${
|
|
1349
|
+
`;function mi(){return`/**
|
|
1350
|
+
* @${_e.slice(1)} \u2014 Resend transactional email wrapper.
|
|
1344
1351
|
*
|
|
1345
1352
|
* Docs: https://resend.com/docs
|
|
1346
1353
|
*/
|
|
@@ -1378,8 +1385,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1378
1385
|
}
|
|
1379
1386
|
|
|
1380
1387
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1381
|
-
`}function
|
|
1382
|
-
* @${
|
|
1388
|
+
`}function gi(){return`/**
|
|
1389
|
+
* @${_e.slice(1)} \u2014 Postmark transactional email wrapper.
|
|
1383
1390
|
*
|
|
1384
1391
|
* Docs: https://postmarkapp.com/developer
|
|
1385
1392
|
*/
|
|
@@ -1416,8 +1423,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1416
1423
|
}
|
|
1417
1424
|
|
|
1418
1425
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1419
|
-
`}function
|
|
1420
|
-
* @${
|
|
1426
|
+
`}function fi(){return`/**
|
|
1427
|
+
* @${_e.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
|
|
1421
1428
|
*
|
|
1422
1429
|
* Docs: https://docs.aws.amazon.com/ses
|
|
1423
1430
|
*/
|
|
@@ -1472,8 +1479,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1472
1479
|
}
|
|
1473
1480
|
|
|
1474
1481
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1475
|
-
`}function
|
|
1476
|
-
* @${
|
|
1482
|
+
`}function yi(){return`/**
|
|
1483
|
+
* @${_e.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
|
|
1477
1484
|
*
|
|
1478
1485
|
* Docs: https://help.aliyun.com/product/29412.html
|
|
1479
1486
|
*/
|
|
@@ -1522,8 +1529,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1522
1529
|
}
|
|
1523
1530
|
|
|
1524
1531
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1525
|
-
`}function
|
|
1526
|
-
* @${
|
|
1532
|
+
`}function Si(){return`/**
|
|
1533
|
+
* @${_e.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
|
|
1527
1534
|
*
|
|
1528
1535
|
* Docs: https://cloud.tencent.com/document/product/1288
|
|
1529
1536
|
*/
|
|
@@ -1570,8 +1577,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1570
1577
|
}
|
|
1571
1578
|
|
|
1572
1579
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1573
|
-
`}function
|
|
1574
|
-
* @${
|
|
1580
|
+
`}function Ei(){return`/**
|
|
1581
|
+
* @${_e.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
|
|
1575
1582
|
*
|
|
1576
1583
|
* Docs: https://qiye.163.com/help
|
|
1577
1584
|
*/
|
|
@@ -1608,23 +1615,23 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1608
1615
|
}
|
|
1609
1616
|
|
|
1610
1617
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1611
|
-
`}function
|
|
1612
|
-
`}}function
|
|
1613
|
-
`}async function
|
|
1618
|
+
`}function hi(e){switch(e){case"resend":return mi();case"postmark":return gi();case"ses":return fi();case"aliyun-dm":return yi();case"tencent-ses":return Si();case"netease":return Ei();case"none":return`export {};
|
|
1619
|
+
`}}function vi(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:_e,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)+`
|
|
1620
|
+
`}async function jn(e,t,o){if(t==="none")return;let n=Fn(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${bt.map(s=>s.id).join(", ")}`);let r=he.join(e,"packages","email"),i=he.join(r,"src");ve.existsSync(i)&&ve.rmSync(i,{recursive:!0,force:!0}),$t(he.join(r,"package.json"),vi(n)),$t(he.join(i,"types.ts"),ui),$t(he.join(i,"index.ts"),hi(n.id)),li(e,di(n))}import It from"fs";import Vn from"path";async function Kn(e,t){let o=`# Automatically injected by create-sailor
|
|
1614
1621
|
DATABASE_URL="${String(t.databaseUrl)}"
|
|
1615
1622
|
|
|
1616
1623
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
|
|
1617
1624
|
CLERK_SECRET_KEY="${String(t.clerkSecret)}"
|
|
1618
1625
|
|
|
1619
1626
|
NEXT_PUBLIC_SITE_URL="http://localhost:3000"
|
|
1620
|
-
`,n=
|
|
1621
|
-
`+o)}import
|
|
1627
|
+
`,n=Vn.join(e,".env"),r=Vn.join(e,".env.local");!It.existsSync(n)&&!It.existsSync(r)?It.writeFileSync(r,o):It.appendFileSync(r,`
|
|
1628
|
+
`+o)}import Yn from"crypto";import st from"fs";import Bn from"path";function Pe(e){return Yn.randomBytes(e).toString("base64").replace(/=+$/,"")}function _i(e){return Yn.randomBytes(e).toString("hex")}function Pi(){return{AUTH_SECRET:Pe(32),NEXTAUTH_SECRET:Pe(32),BETTER_AUTH_SECRET:Pe(32),JWT_SECRET:Pe(32),WEBHOOK_SECRET:_i(16),ENCRYPTION_KEY:Pe(32),API_SECRET_KEY:Pe(32),SESSION_SECRET:Pe(32)}}function bi(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Ii(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=bi(o);return e.replace(n,`${t}="${r}"`)}async function $n(e){let t=Bn.join(e,".env.example"),o=Bn.join(e,".env.local");if(!st.existsSync(t))return null;try{let n=st.readFileSync(t,"utf8"),r=Pi(),s=st.existsSync(o)?st.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))s=Ii(s,c,r[c]);return st.writeFileSync(o,s),r}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate env secrets: ${r}`),new Error(`Unable to write .env.local: ${r}`)}}var At=[{id:"vercel-flags",name:"Vercel Flags SDK",region:"global",envVars:["FLAGS_SECRET"],docs:"https://vercel.com/docs/workflow-collaboration/feature-flags",description:"Native Vercel feature flags"},{id:"growthbook",name:"GrowthBook",region:"both",envVars:["GROWTHBOOK_API_HOST","GROWTHBOOK_CLIENT_KEY","GROWTHBOOK_DECRYPTION_KEY"],docs:"https://docs.growthbook.io",description:"Open-source A/B testing + flags"},{id:"configcat",name:"ConfigCat",region:"global",envVars:["CONFIGCAT_SDK_KEY"],docs:"https://configcat.com/docs/",description:"Feature flag & config management"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function qn(e){return At.find(t=>t.id===e)}var Ic=At.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Gn(e,t,o="global"){let n=qn(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${At.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"feature-flags");return}n.envVars.length>0&&q(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{execFileSync as Xn}from"child_process";import x from"fs";import Ai from"os";import ie from"path";import Ci from"ignore";var wi={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 Ri(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function xi(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function zn(e){return/^[0-9a-f]{7,40}$/i.test(e)}function Ni(e,t){let o=`https://github.com/${e}.git`,n=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of n)try{let i=Xn("git",["ls-remote",o,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!i)continue;let[s]=i.split(/\s+/);if(zn(s))return s}catch{}return null}async function ki(e,t){if(zn(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=Ni(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 Qn(e,t,o){let n=x.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let i=ie.join(t,r.name),s=ie.relative(e,i).split(ie.sep).join("/");r.isDirectory()?(o.push(s+"/"),Qn(e,i,o)):o.push(s)}}function Ti(e){let t=ie.join(e,".templateignore");if(!x.existsSync(t))return;let o=x.readFileSync(t,"utf8"),n=Ci().add(o),r=[];Qn(e,e,r);let i=r.map(a=>a.endsWith("/")?a.slice(0,-1):a),s=new Set(n.filter(i)),c=i.filter(a=>!s.has(a)).sort((a,d)=>d.split("/").length-a.split("/").length);for(let a of c){let d=ie.join(e,a);try{x.existsSync(d)&&x.rmSync(d,{recursive:!0,force:!0})}catch{}}try{x.existsSync(t)&&x.rmSync(t,{force:!0})}catch{}}async function Hn(e,t){let o=await fetch(e,{headers:{Accept:"application/octet-stream","User-Agent":"create-sailor"}});if(!o.ok)throw new Error(`Failed to download archive (${o.status})`);let n=Buffer.from(await o.arrayBuffer());if(n.byteLength<1024)throw new Error(`Downloaded archive is unexpectedly small (${n.byteLength} bytes)`);x.writeFileSync(t,n);let r=x.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function Wn(e,t){Xn("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function Jn(e){try{let t=x.readdirSync(e);for(let o of t)x.rmSync(ie.join(e,o),{recursive:!0,force:!0})}catch{}}async function Oi(e,t){let o=x.mkdtempSync(ie.join(Ai.tmpdir(),"create-sailor-")),n=ie.join(o,"template.tar.gz");try{let r=await ki(e.repo,e.ref);await Hn(xi(e.repo,r),n),Wn(n,t)}catch(r){if(!e.allowMutableFallback)throw r;Jn(t),await Hn(Ri(e.repo,e.ref),n),Wn(n,t)}finally{x.rmSync(o,{recursive:!0,force:!0})}}async function Zn(e){x.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let i=wi[r];try{if(await Oi(i,e),i.applyIgnore)try{Ti(e)}catch(s){throw new Error(`Template cloned, but .templateignore processing failed: ${s instanceof Error?s.message:String(s)}`)}return}catch(s){n=s instanceof Error?s:new Error(String(s)),Jn(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
|
|
1622
1629
|
|
|
1623
1630
|
Ensure you have internet access and 'tar' installed.
|
|
1624
|
-
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import
|
|
1625
|
-
`);
|
|
1626
|
-
`);at.appendFileSync(
|
|
1627
|
-
`+t):He.writeFileSync(o,t)}function
|
|
1631
|
+
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import be from"fs";import qt from"path";async function eo(e,t){let o=qt.join(e,"packages","mcp");if(t==="off"){be.existsSync(o)&&be.rmSync(o,{recursive:!0,force:!0});let r=qt.join(e,"packages","cli","src","commands","mcp-server.ts");be.existsSync(r)&&be.rmSync(r,{force:!0});return}let n=qt.join(e,".env.example");if(be.existsSync(n)){let r=be.readFileSync(n,"utf-8"),i="# MCP Server (Agent-friendly API)";if(!r.includes(i)){let s=["","# =============================================",i,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
|
|
1632
|
+
`);be.appendFileSync(n,s)}}}import at from"fs";import to from"path";async function no(e,t,o){let n=to.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){at.existsSync(n)&&at.rmSync(n,{recursive:!0,force:!0});return}let i=to.join(e,".env.example");if(!at.existsSync(i))return;let s=at.readFileSync(i,"utf-8"),c="# Metering (usage-based billing)";if(!s.includes(c)){let a=["","# =============================================",c,"# Docs: see packages/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
|
|
1633
|
+
`);at.appendFileSync(i,a)}}import He from"fs";import T from"path";var oo=[{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:""}],Kc=oo.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function ro(e){return oo.find(t=>t.id===e)}function Ui(e){He.mkdirSync(e,{recursive:!0})}function W(e,t){Ui(T.dirname(e)),He.writeFileSync(e,t)}function ct(e,t){let o=T.join(e,".env.example");He.existsSync(o)?He.appendFileSync(o,`
|
|
1634
|
+
`+t):He.writeFileSync(o,t)}function Li(e){let t=`import * as Sentry from "@sentry/nextjs";
|
|
1628
1635
|
|
|
1629
1636
|
Sentry.init({
|
|
1630
1637
|
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
@@ -1667,14 +1674,14 @@ export async function register() {
|
|
|
1667
1674
|
}
|
|
1668
1675
|
|
|
1669
1676
|
export { captureRequestError as onRequestError } from "@sentry/nextjs";
|
|
1670
|
-
`;
|
|
1677
|
+
`;W(T.join(e,"sentry.client.config.ts"),t),W(T.join(e,"sentry.server.config.ts"),o),W(T.join(e,"sentry.edge.config.ts"),n),W(T.join(e,"instrumentation.ts"),r)}function Mi(){return`# Sentry \u2014 error tracking + performance monitoring
|
|
1671
1678
|
# Get your DSN from https://sentry.io/settings/projects/<project>/keys/
|
|
1672
1679
|
SENTRY_DSN=
|
|
1673
1680
|
NEXT_PUBLIC_SENTRY_DSN=
|
|
1674
1681
|
SENTRY_ORG=
|
|
1675
1682
|
SENTRY_PROJECT=
|
|
1676
1683
|
SENTRY_AUTH_TOKEN=
|
|
1677
|
-
`}function
|
|
1684
|
+
`}function Di(e){let t=`/**
|
|
1678
1685
|
* Next.js instrumentation hook \u2014 wires Datadog APM (dd-trace) into Node runtime.
|
|
1679
1686
|
* Edge runtime is not supported by dd-trace; only nodejs is initialized.
|
|
1680
1687
|
*/
|
|
@@ -1722,7 +1729,7 @@ export function initDatadogRum(): void {
|
|
|
1722
1729
|
});
|
|
1723
1730
|
initialized = true;
|
|
1724
1731
|
}
|
|
1725
|
-
`;
|
|
1732
|
+
`;W(T.join(e,"instrumentation.ts"),t),W(T.join(e,"src","lib","monitoring","datadog-rum.ts"),o)}function Fi(){return`# Datadog \u2014 APM + RUM
|
|
1726
1733
|
# Server APM (dd-trace)
|
|
1727
1734
|
DD_API_KEY=
|
|
1728
1735
|
DD_APP_KEY=
|
|
@@ -1737,7 +1744,7 @@ NEXT_PUBLIC_DD_SITE=datadoghq.com
|
|
|
1737
1744
|
NEXT_PUBLIC_DD_SERVICE=sailor-web
|
|
1738
1745
|
NEXT_PUBLIC_DD_ENV=production
|
|
1739
1746
|
NEXT_PUBLIC_DD_VERSION=
|
|
1740
|
-
`}function
|
|
1747
|
+
`}function ji(e){let t=`/**
|
|
1741
1748
|
* Bugsnag server-side initialization.
|
|
1742
1749
|
* Import this once at the top of your server entrypoint or a shared init module.
|
|
1743
1750
|
*/
|
|
@@ -1786,11 +1793,11 @@ export function getBugsnagErrorBoundary() {
|
|
|
1786
1793
|
errorBoundary = plugin.createErrorBoundary(React) as typeof errorBoundary;
|
|
1787
1794
|
return errorBoundary;
|
|
1788
1795
|
}
|
|
1789
|
-
`;
|
|
1796
|
+
`;W(T.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),W(T.join(e,"src","lib","monitoring","bugsnag.client.tsx"),o)}function Vi(){return`# Bugsnag \u2014 error tracking
|
|
1790
1797
|
BUGSNAG_API_KEY=
|
|
1791
1798
|
NEXT_PUBLIC_BUGSNAG_API_KEY=
|
|
1792
1799
|
APP_VERSION=
|
|
1793
|
-
`}function
|
|
1800
|
+
`}function Ki(e){W(T.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
|
|
1794
1801
|
/**
|
|
1795
1802
|
* \u963F\u91CC\u4E91 ARMS (Application Real-time Monitoring Service) browser agent.
|
|
1796
1803
|
* Injects the official JS agent via next/script.
|
|
@@ -1811,11 +1818,11 @@ export function ArmsScript() {
|
|
|
1811
1818
|
/>
|
|
1812
1819
|
);
|
|
1813
1820
|
}
|
|
1814
|
-
`)}function
|
|
1821
|
+
`)}function Bi(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
|
|
1815
1822
|
ALIYUN_ARMS_LICENSE_KEY=
|
|
1816
1823
|
ALIYUN_ARMS_APP_NAME=
|
|
1817
1824
|
NEXT_PUBLIC_ARMS_PID=
|
|
1818
|
-
`}function
|
|
1825
|
+
`}function Yi(e){W(T.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
|
|
1819
1826
|
/**
|
|
1820
1827
|
* \u542C\u4E91 Browser Agent (\u524D\u7AEF\u6027\u80FD\u76D1\u63A7).
|
|
1821
1828
|
* Docs: https://www.tingyun.com/docs
|
|
@@ -1833,12 +1840,12 @@ export function TingYunScript() {
|
|
|
1833
1840
|
/>
|
|
1834
1841
|
);
|
|
1835
1842
|
}
|
|
1836
|
-
`)}function
|
|
1843
|
+
`)}function $i(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
|
|
1837
1844
|
TINGYUN_LICENSE_KEY=
|
|
1838
1845
|
NEXT_PUBLIC_TINGYUN_APP_KEY=
|
|
1839
|
-
`}async function
|
|
1840
|
-
`)}}import Z from"fs";import pt from"path";var
|
|
1841
|
-
`+t):Z.writeFileSync(o,t)}function
|
|
1846
|
+
`}async function io(e,t,o="global"){let n=ro(t);if(!n||n.id==="none")return;let r=T.join(e,"apps","web");if(!He.existsSync(r))return;let i=n.id;try{switch(i){case"sentry":Li(r),ct(e,Mi());return;case"datadog":Di(r),ct(e,Fi());return;case"bugsnag":ji(r),ct(e,Vi());return;case"aliyun-arms":Ki(r),ct(e,Bi());return;case"tingyun":Yi(r),ct(e,$i());return;default:return}}catch(s){throw console.error(`Failed to apply monitoring selection "${t}":`,s),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Ct=[{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 so(e){return Ct.find(t=>t.id===e)}var Hc=Ct.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ao(e,t,o="global"){let n=so(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Ct.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"notifications");return}n.envVars.length>0&&q(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"NOTIFICATIONS_PROVIDER",n.id)}import Gt from"fs";import qi from"path";async function co(e,t){let o=qi.join(e,"package.json");if(Gt.existsSync(o)){let n=Gt.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",Gt.writeFileSync(o,JSON.stringify(r,null,2)+`
|
|
1847
|
+
`)}}import Z from"fs";import pt from"path";var Gi=["stripe","lemonsqueezy","chinapay","polar"];function po(e){Z.existsSync(e)&&Z.rmSync(e,{recursive:!0,force:!0})}function Hi(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Wi(e,t){let o=pt.join(e,".env.example");Z.existsSync(o)?Z.appendFileSync(o,`
|
|
1848
|
+
`+t):Z.writeFileSync(o,t)}function Xi(e){switch(e){case"stripe":return`# Stripe
|
|
1842
1849
|
STRIPE_SECRET_KEY=
|
|
1843
1850
|
STRIPE_WEBHOOK_SECRET=
|
|
1844
1851
|
`;case"lemon":return`# Lemon Squeezy
|
|
@@ -1853,14 +1860,14 @@ CHINAPAY_WECHAT_ENABLED=true
|
|
|
1853
1860
|
CHINAPAY_APP_ID=
|
|
1854
1861
|
CHINAPAY_APP_SECRET=
|
|
1855
1862
|
CHINAPAY_ALIPAY_ENABLED=true
|
|
1856
|
-
`}}async function
|
|
1857
|
-
`),n=[],r=e.includes("#"),
|
|
1858
|
-
`),t)}function
|
|
1859
|
-
`).filter(d=>{let u=d.trim();if(u===""||u.startsWith("//"))return!0;let
|
|
1860
|
-
`);return e.replace(
|
|
1861
|
-
`+r);let
|
|
1862
|
-
`)}}import g from"fs";import
|
|
1863
|
-
`)}let c=
|
|
1863
|
+
`}}async function lo(e,t){let o=pt.join(e,"packages","billing");if(!Z.existsSync(o))return;if(t==="none"){po(o);return}let n=pt.join(o,"src"),r=new Set(Hi(t));for(let s of Gi)r.has(s)||po(pt.join(n,s));let i=pt.join(n,"checkout","types.ts");if(Z.existsSync(i)){let s=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=Z.readFileSync(i,"utf8"),a=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${s}";`);a!==c&&Z.writeFileSync(i,a)}Wi(e,Xi(t))}import se from"fs";import We from"path";var go=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),Ht=/@sailor:([^\s*]+)/;function zi(e,t){let{providerIds:o,customEndpoint:n}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:o.includes(r)}}if(e==="cn-compatible"){let r=o.some(i=>go.has(i));return{marker:e,keep:r||!!n}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:o.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!n}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function uo(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function mo(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function fo(e,t){let o=e.split(`
|
|
1864
|
+
`),n=[],r=e.includes("#"),i=0;for(;i<o.length;){let s=o[i],c=s.match(Ht);if(!c){n.push(s),i++;continue}let{marker:a,keep:d}=zi(c[1],t);if(a==="registry-entries"){n.push(r?mo(s):uo(s)),i++;continue}if(d){let u=r?mo(s):uo(s);u.trim().length>0&&n.push(u);let h=i+1;for(;h<o.length&&o[h].trim()!==""&&!Ht.test(o[h]);)n.push(o[h]),h++;h<o.length&&o[h].trim()===""&&(n.push(o[h]),h++),i=h}else{let u=i+1;for(;u<o.length&&o[u].trim()!==""&&!Ht.test(o[u]);)u++;u<o.length&&o[u].trim()===""&&u++,i=u}}return Qi(n.join(`
|
|
1865
|
+
`),t)}function Qi(e,t){let{providerIds:o,customEndpoint:n}=t,r=new Set;for(let d of o)["openai","anthropic","google","mistral","xai"].includes(d)&&r.add(d),r.add(d.replace(/-/g,"_")),r.add(d);n&&r.add("custom");let i=/createProviderRegistry\(\{([\s\S]*?)\}\)/,s=e.match(i);if(!s)return e;let a=s[1].split(`
|
|
1866
|
+
`).filter(d=>{let u=d.trim();if(u===""||u.startsWith("//"))return!0;let h=u.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return h?r.has(h[1]):!0}).join(`
|
|
1867
|
+
`);return e.replace(i,`createProviderRegistry({${a}})`)}function Ji(e,t){let o=We.join(t,"registry.ts.template"),n=se.readFileSync(o,"utf-8");return fo(n,e)}function Zi(e,t){let o=We.join(t,".env.example.template"),n=se.readFileSync(o,"utf-8");return fo(n,e)}async function yo(e,t,o){let n=Ji(t,o),r=Zi(t,o),i=We.join(e,"packages/agents/src");await se.promises.mkdir(i,{recursive:!0}),await se.promises.writeFile(We.join(i,"registry.ts"),n),await se.promises.appendFile(We.join(e,".env.example"),`
|
|
1868
|
+
`+r);let s={ai:"latest"},{providerIds:c,customEndpoint:a}=t;(c.includes("openai")||a||c.some(u=>go.has(u)))&&(s["@ai-sdk/openai"]="latest",s["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(s["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(s["@ai-sdk/google"]="latest"),c.includes("mistral")&&(s["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(s["@ai-sdk/openai"]="latest");let d=We.join(e,"package.json");if(se.existsSync(d)){let u=JSON.parse(await se.promises.readFile(d,"utf-8"));u.dependencies||(u.dependencies={});for(let[h,O]of Object.entries(s))u.dependencies[h]=O;await se.promises.writeFile(d,JSON.stringify(u,null,2)+`
|
|
1869
|
+
`)}}import g from"fs";import P from"path";function So(e,t){if(!g.existsSync(e))return;let o=g.readdirSync(e);for(let n of o){let r=P.join(e,n);g.statSync(r).isDirectory()?So(r,t):t(r)}}async function Eo(e,t){let o=P.join(e,"package.json");if(!g.existsSync(o))return;let n=JSON.parse(g.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=P.join(e,"packages","db");if(g.existsSync(r)){let i=P.join(r,"prisma");g.existsSync(i)&&g.rmSync(i,{recursive:!0,force:!0});let s=P.join(r,"package.json");if(g.existsSync(s)){let a=JSON.parse(g.readFileSync(s,"utf8"));a.dependencies&&delete a.dependencies["@prisma/client"],a.devDependencies&&delete a.devDependencies.prisma,g.writeFileSync(s,JSON.stringify(a,null,2)+`
|
|
1870
|
+
`)}let c=P.join(r,"src","index.ts");g.existsSync(c)&&g.writeFileSync(c,`
|
|
1864
1871
|
export const prisma = {} as any;
|
|
1865
1872
|
export const db = {} as any;
|
|
1866
1873
|
export type PrismaClient = any;
|
|
@@ -1906,7 +1913,7 @@ export type UsageAggregate = any;
|
|
|
1906
1913
|
export type UsageLedgerEntry = any;
|
|
1907
1914
|
export type UsageType = any;
|
|
1908
1915
|
export type UsageLedgerSource = any;
|
|
1909
|
-
`)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=
|
|
1916
|
+
`)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=P.join(e,"apps");if(g.existsSync(r)){let i=g.readdirSync(r);for(let s of i){let c=P.join(r,s);if(!g.statSync(c).isDirectory())continue;let a=P.join(c,"src","app");if(!g.existsSync(a))continue;["[lang]","[locale]"].forEach(v=>{let l=P.join(a,v);if(g.existsSync(l)){let R=g.readdirSync(l);for(let mt of R)g.renameSync(P.join(l,mt),P.join(a,mt));g.rmdirSync(l)}}),["src/middleware.ts","middleware.ts"].forEach(v=>{let l=P.join(c,v);g.existsSync(l)&&g.rmSync(l)});let d=P.join(c,"src","lib");g.existsSync(d)||g.mkdirSync(d,{recursive:!0});let u=P.join(d,"mock-i18n.ts");g.writeFileSync(u,`
|
|
1910
1917
|
import React from 'react';
|
|
1911
1918
|
export function useTranslations(namespace?: string): any { return (key: string) => key; }
|
|
1912
1919
|
export function useLocale() { return 'en'; }
|
|
@@ -1924,7 +1931,7 @@ export const useRouter = () => ({ push: (...args: any[]) => {}, replace: (...arg
|
|
|
1924
1931
|
export default function createMiddleware(...args: any[]) { return (req: any) => req; }
|
|
1925
1932
|
export function createNavigation(...args: any[]) { return { Link, redirect, usePathname, useRouter, getPathname: () => '/' }; }
|
|
1926
1933
|
export function defineRouting<T>(config: T): T { return config; }
|
|
1927
|
-
`);let
|
|
1934
|
+
`);let O=P.join(d,"mock-i18n.d.ts");g.writeFileSync(O,`declare module '@/lib/mock-i18n' {
|
|
1928
1935
|
export function useTranslations(namespace?: string): any;
|
|
1929
1936
|
export function useLocale(): string;
|
|
1930
1937
|
export const NextIntlClientProvider: React.FC<any>;
|
|
@@ -1942,18 +1949,18 @@ export function defineRouting<T>(config: T): T { return config; }
|
|
|
1942
1949
|
export function createNavigation(...args: any[]): any;
|
|
1943
1950
|
export function defineRouting<T>(config: T): T;
|
|
1944
1951
|
}
|
|
1945
|
-
`),g.writeFileSync(
|
|
1952
|
+
`),g.writeFileSync(P.join(d,"mock-i18n-index.ts"),`
|
|
1946
1953
|
export * from './mock-i18n';
|
|
1947
1954
|
export { default } from './mock-i18n';
|
|
1948
|
-
`);let
|
|
1955
|
+
`);let M=P.join(c,"tsconfig.json");if(g.existsSync(M))try{let v=g.readFileSync(M,"utf8");if(v.includes('"paths": {')){let l=v.replace(/"paths":\s*\{/,`"paths": {
|
|
1949
1956
|
"next-intl": ["./src/lib/mock-i18n"],
|
|
1950
|
-
"next-intl/*": ["./src/lib/mock-i18n"],`);g.writeFileSync(
|
|
1957
|
+
"next-intl/*": ["./src/lib/mock-i18n"],`);g.writeFileSync(M,l)}}catch{}let D=P.join(c,"src");g.existsSync(D)&&So(D,v=>{if(!v.endsWith(".ts")&&!v.endsWith(".tsx"))return;let l=g.readFileSync(v,"utf8"),R=!1;v.endsWith("src/app/layout.tsx")&&l.includes("../providers")&&(l=l.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),R=!0),l=l.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),l=l.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),l.match(/locale\s*:\s*any/)&&(l=l.replace(/locale\s*:\s*any/g,"locale: string"),R=!0),l.match(/lang\s*:\s*any/)&&(l=l.replace(/lang\s*:\s*any/g,"lang: string"),R=!0),l.match(/requestLocale\s*:\s*any/)&&(l=l.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),R=!0),l.match(/\(locale\s*=\s*(.*)\)/)&&(l=l.replace(/\(locale\s*=\s*(.*)\)/g,"() "),R=!0),l.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(l=l.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),R=!0),(v.endsWith("src/app/layout.tsx")||v.endsWith("src/app/sitemap.ts")||v.endsWith("src/app/robots.ts")||v.endsWith("src/components/ui/locale-switcher.tsx")||v.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(l=l.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),l=l.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),l=l.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),l=l.replace(/\(l\)\s*=>/g,"(l: any) =>"),R=!0),v.endsWith("src/i18n/request.ts")&&(l=l.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),R=!0),(l.match(/locale\s*:/)||l.match(/lang\s*:/))&&(R=!0),R&&g.writeFileSync(v,l)});let Xe=P.join(c,"package.json");if(g.existsSync(Xe)){let v=JSON.parse(g.readFileSync(Xe,"utf8"));v.dependencies&&delete v.dependencies["next-intl"],g.writeFileSync(Xe,JSON.stringify(v,null,2)+`
|
|
1951
1958
|
`)}}}}g.writeFileSync(o,JSON.stringify(n,null,2)+`
|
|
1952
|
-
`)}import{getSchema as
|
|
1953
|
-
`);
|
|
1954
|
-
`)}async function
|
|
1955
|
-
`);
|
|
1956
|
-
`)}async function
|
|
1959
|
+
`)}import{getSchema as es,printSchema as ts}from"@mrleebo/prisma-ast";var ns=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function os(e){return e.type==="comment"&&e.text.trim().startsWith("///")}function rs(e){let t=ns.exec(e.trim());if(!t)return null;let[,o,n]=t,r=n.split("|").map(i=>i.trim()).filter(i=>i.length>0);return{flag:o,values:r}}function is(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=rs(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function Wt(e,t){let o=es(e),n=new Set;for(let c=0;c<o.list.length;c++){if(o.list[c].type!=="model")continue;let d=is(o.list,c);if(!d)continue;let u=t[d.parsed.flag];if(u!==void 0&&d.parsed.values.includes(u))n.add(d.annIndex);else{n.add(c);for(let M=c-1;M>=0;M--){let D=o.list[M];if(D.type==="comment"&&os(D)){n.add(M);continue}break}let O=o.list[c+1];O&&O.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,a)=>!n.has(a)),i=[];for(let c of r){let a=i[i.length-1];c.type==="break"&&a&&a.type==="break"||i.push(c)}return ts({type:"schema",list:i})}import ae from"fs";import Xt 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:"upstash",name:"Upstash Kafka",region:"both",envVars:["UPSTASH_KAFKA_REST_URL","UPSTASH_KAFKA_REST_USERNAME","UPSTASH_KAFKA_REST_PASSWORD"],docs:"https://upstash.com/docs/kafka",description:"Serverless Kafka"},{id:"sqs",name:"AWS SQS",region:"global",envVars:["AWS_SQS_QUEUE_URL","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"],docs:"https://docs.aws.amazon.com/AWSSimpleQueueService/",description:"AWS managed queue"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip queue package"}];function ho(e){return wt.find(t=>t.id===e)}var up=wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function vo(e){return ae.existsSync(e)?ae.readFileSync(e,"utf-8"):null}function ss(e,t){let o=Xt.join(e,".env.example"),n=vo(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
|
|
1960
|
+
`);ae.appendFileSync(o,i)}function as(e,t,o){let n=Xt.join(e,".env.example"),r=vo(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ae.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ae.appendFileSync(n,`${t}="${o}"
|
|
1961
|
+
`)}async function _o(e,t,o){let n=Xt.join(e,"packages","queue");if(t==="none"){ae.existsSync(n)&&ae.rmSync(n,{recursive:!0,force:!0});return}let r=ho(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${wt.map(i=>i.id).join(", ")}`);ae.existsSync(n)&&(ss(e,r),as(e,"QUEUE_PROVIDER",t))}import ce from"fs";import zt from"path";var Rt=[{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 Po(e){return Rt.find(t=>t.id===e)}var Ep=Rt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function bo(e){return ce.existsSync(e)?ce.readFileSync(e,"utf-8"):null}function cs(e,t){let o=zt.join(e,".env.example"),n=bo(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let i=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(s=>`${s}=""`),""].join(`
|
|
1962
|
+
`);ce.appendFileSync(o,i)}function ps(e,t,o){let n=zt.join(e,".env.example"),r=bo(n);if(r===null)return;let i=new RegExp(`^${t}=.*$`,"m");i.test(r)?ce.writeFileSync(n,r.replace(i,`${t}="${o}"`)):ce.appendFileSync(n,`${t}="${o}"
|
|
1963
|
+
`)}async function Io(e,t,o){let n=zt.join(e,"packages","search");if(t==="none"){ce.existsSync(n)&&ce.rmSync(n,{recursive:!0,force:!0});return}let r=Po(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Rt.map(i=>i.id).join(", ")}`);ce.existsSync(n)&&(cs(e,r),ps(e,"SEARCH_PROVIDER",t))}import pe from"fs";import Ie from"path";function ls(e){let t=[Ie.join(e,"packages","db"),Ie.join(e,"apps","web")];for(let o of t){let n=Ie.join(o,"prisma","schema.prisma");if(pe.existsSync(n))return{packageDir:o,seedPath:Ie.join(o,"prisma","seed.ts"),packageJsonPath:Ie.join(o,"package.json")}}return null}function ds(e){try{let t=pe.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 us(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
|
|
1957
1964
|
const admin = await prisma.user.create({
|
|
1958
1965
|
data: {
|
|
1959
1966
|
clerkId: "user_mock_admin",
|
|
@@ -1984,7 +1991,7 @@ export { default } from './mock-i18n';
|
|
|
1984
1991
|
console.log("\\u2713 Created admin user:", admin.email);
|
|
1985
1992
|
} catch (err) {
|
|
1986
1993
|
console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
|
|
1987
|
-
}`}function
|
|
1994
|
+
}`}function ms(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),i=us(e,n),s=o?` let tenants: Array<{ id: string; name: string }> = [];
|
|
1988
1995
|
try {
|
|
1989
1996
|
tenants = await Promise.all([
|
|
1990
1997
|
prisma.tenant.create({
|
|
@@ -2034,10 +2041,10 @@ async function main(): Promise<void> {
|
|
|
2034
2041
|
console.log("\\uD83C\\uDF31 Seeding database...");
|
|
2035
2042
|
|
|
2036
2043
|
// --- Tenants ---------------------------------------------------------
|
|
2037
|
-
${
|
|
2044
|
+
${s}
|
|
2038
2045
|
|
|
2039
2046
|
// --- Admin user ------------------------------------------------------
|
|
2040
|
-
${
|
|
2047
|
+
${i}
|
|
2041
2048
|
|
|
2042
2049
|
// --- Sample projects per tenant --------------------------------------
|
|
2043
2050
|
${c}
|
|
@@ -2053,12 +2060,12 @@ main()
|
|
|
2053
2060
|
.finally(async () => {
|
|
2054
2061
|
await prisma.$disconnect();
|
|
2055
2062
|
});
|
|
2056
|
-
`}function
|
|
2057
|
-
`)}catch(t){let o=t instanceof Error?t.message:String(t);console.warn(`[create-sailor] Failed to patch seed scripts in ${e}: ${o}`)}}async function
|
|
2058
|
-
`+t):
|
|
2063
|
+
`}function gs(e){if(pe.existsSync(e))try{let t=pe.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let i=o.prisma??{};if(i.seed||(i.seed="tsx prisma/seed.ts",r=!0),!r)return;let s={...o,scripts:n,prisma:i};pe.writeFileSync(e,JSON.stringify(s,null,2)+`
|
|
2064
|
+
`)}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 Ao(e,t){let o=ls(e);if(o)try{let n=Ie.join(o.packageDir,"prisma","schema.prisma"),r=ds(n),i=ms(t,r),s=Ie.dirname(o.seedPath);pe.existsSync(s)||pe.mkdirSync(s,{recursive:!0}),pe.writeFileSync(o.seedPath,i),gs(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 le from"fs";import Ae from"path";var xt=[{id:"twilio",name:"Twilio",region:"global",envVars:["TWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN","TWILIO_FROM_NUMBER"],docs:"https://www.twilio.com/docs/sms",pkgs:["twilio"]},{id:"messagebird",name:"MessageBird (Bird)",region:"global",envVars:["MESSAGEBIRD_ACCESS_KEY","MESSAGEBIRD_ORIGINATOR"],docs:"https://developers.messagebird.com/api/sms-messaging/",pkgs:["messagebird"]},{id:"plivo",name:"Plivo",region:"global",envVars:["PLIVO_AUTH_ID","PLIVO_AUTH_TOKEN","PLIVO_FROM_NUMBER"],docs:"https://www.plivo.com/docs/sms/",pkgs:["plivo"]},{id:"aliyun-sms",name:"\u963F\u91CC\u4E91\u77ED\u4FE1 Aliyun SMS",region:"cn",envVars:["ALIYUN_SMS_ACCESS_KEY","ALIYUN_SMS_ACCESS_SECRET","ALIYUN_SMS_SIGN_NAME","ALIYUN_SMS_TEMPLATE_CODE","ALIYUN_SMS_ENDPOINT"],docs:"https://help.aliyun.com/product/44282.html",pkgs:["@alicloud/dysmsapi20170525","@alicloud/openapi-client"]},{id:"tencent-sms",name:"\u817E\u8BAF\u4E91\u77ED\u4FE1 Tencent SMS",region:"cn",envVars:["TENCENT_SMS_SECRET_ID","TENCENT_SMS_SECRET_KEY","TENCENT_SMS_SDK_APP_ID","TENCENT_SMS_SIGN_NAME","TENCENT_SMS_TEMPLATE_ID","TENCENT_SMS_REGION"],docs:"https://cloud.tencent.com/document/product/382",pkgs:["tencentcloud-sdk-nodejs-sms"]},{id:"yunpian",name:"\u4E91\u7247 Yunpian",region:"cn",envVars:["YUNPIAN_API_KEY","YUNPIAN_SIGN"],docs:"https://www.yunpian.com/official/document/sms/zh_CN/introduction_product_intro",pkgs:["yunpian-nodejs-sdk"]},{id:"none",name:"None",region:"both",envVars:[],docs:""}],wp=xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Co(e){return xt.find(t=>t.id===e)}var fs="@nebutra/sms",ys={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 Qt(e,t){le.mkdirSync(Ae.dirname(e),{recursive:!0}),le.writeFileSync(e,t)}function Ss(e,t){let o=Ae.join(e,".env.example");le.existsSync(o)?le.appendFileSync(o,`
|
|
2065
|
+
`+t):le.writeFileSync(o,t)}function Es(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2059
2066
|
`);return`${t}
|
|
2060
2067
|
${o}
|
|
2061
|
-
`}var
|
|
2068
|
+
`}var hs=`/**
|
|
2062
2069
|
* Inputs for the \`sendSms\` wrapper. Keep this surface portable across
|
|
2063
2070
|
* providers \u2014 provider-specific options belong in the wrapper itself.
|
|
2064
2071
|
*/
|
|
@@ -2078,7 +2085,7 @@ export interface SendSmsResult {
|
|
|
2078
2085
|
provider: string;
|
|
2079
2086
|
raw?: unknown;
|
|
2080
2087
|
}
|
|
2081
|
-
`;function
|
|
2088
|
+
`;function vs(){return`import twilio from "twilio";
|
|
2082
2089
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2083
2090
|
|
|
2084
2091
|
let client: ReturnType<typeof twilio> | null = null;
|
|
@@ -2113,7 +2120,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2113
2120
|
}
|
|
2114
2121
|
|
|
2115
2122
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2116
|
-
`}function
|
|
2123
|
+
`}function _s(){return`import messagebird from "messagebird";
|
|
2117
2124
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2118
2125
|
|
|
2119
2126
|
let client: ReturnType<typeof messagebird> | null = null;
|
|
@@ -2151,7 +2158,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2151
2158
|
}
|
|
2152
2159
|
|
|
2153
2160
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2154
|
-
`}function
|
|
2161
|
+
`}function Ps(){return`import plivo from "plivo";
|
|
2155
2162
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2156
2163
|
|
|
2157
2164
|
let client: InstanceType<typeof plivo.Client> | null = null;
|
|
@@ -2190,7 +2197,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2190
2197
|
}
|
|
2191
2198
|
|
|
2192
2199
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2193
|
-
`}function
|
|
2200
|
+
`}function bs(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
|
|
2194
2201
|
import * as $OpenApi from "@alicloud/openapi-client";
|
|
2195
2202
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2196
2203
|
|
|
@@ -2239,7 +2246,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2239
2246
|
}
|
|
2240
2247
|
|
|
2241
2248
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2242
|
-
`}function
|
|
2249
|
+
`}function Is(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
|
|
2243
2250
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2244
2251
|
|
|
2245
2252
|
const SmsClient = tencentcloud.sms.v20210111.Client;
|
|
@@ -2304,7 +2311,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2304
2311
|
}
|
|
2305
2312
|
|
|
2306
2313
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2307
|
-
`}function
|
|
2314
|
+
`}function As(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
|
|
2308
2315
|
import Yunpian from "yunpian-nodejs-sdk";
|
|
2309
2316
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2310
2317
|
|
|
@@ -2356,13 +2363,13 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2356
2363
|
}
|
|
2357
2364
|
|
|
2358
2365
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2359
|
-
`}function
|
|
2360
|
-
`}}function
|
|
2361
|
-
`}async function
|
|
2362
|
-
`+t):
|
|
2366
|
+
`}function Cs(e){switch(e){case"twilio":return vs();case"messagebird":return _s();case"plivo":return Ps();case"aliyun-sms":return bs();case"tencent-sms":return Is();case"yunpian":return As();case"none":return`export {};
|
|
2367
|
+
`}}function ws(e){let t={};for(let n of e.pkgs??[]){let r=ys[n];r&&(t[n]=r)}let o={name:fs,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)+`
|
|
2368
|
+
`}async function wo(e,t,o="global"){if(t==="none")return;let n=Co(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${xt.map(s=>s.id).join(", ")}`);let r=Ae.join(e,"packages","sms");if(!le.existsSync(r))return;let i=Ae.join(r,"src");le.existsSync(i)&&le.rmSync(i,{recursive:!0,force:!0});try{Qt(Ae.join(r,"package.json"),ws(n)),Qt(Ae.join(i,"types.ts"),hs),Qt(Ae.join(i,"index.ts"),Cs(n.id)),Ss(e,Es(n))}catch(s){throw console.error(`Failed to apply SMS selection "${t}":`,s),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import we from"fs";import Ce from"path";var lt=[{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 Jt(e){let t=e==="supabase"?"supabase-storage":e;return lt.some(o=>o.id===t)?t:void 0}function Ro(e){let t=Jt(e);return t?lt.find(o=>o.id===t):void 0}var Op=lt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Re="@nebutra/storage";function Zt(e,t){we.mkdirSync(Ce.dirname(e),{recursive:!0}),we.writeFileSync(e,t)}function Rs(e,t){let o=Ce.join(e,".env.example");we.existsSync(o)?we.appendFileSync(o,`
|
|
2369
|
+
`+t):we.writeFileSync(o,t)}function xs(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2363
2370
|
`);return`${t}
|
|
2364
2371
|
${o}
|
|
2365
|
-
`}var
|
|
2372
|
+
`}var Ns=`/**
|
|
2366
2373
|
* Inputs for the \`uploadFile\` wrapper. Keep this surface portable across
|
|
2367
2374
|
* providers \u2014 provider-specific options belong in the wrapper itself.
|
|
2368
2375
|
*/
|
|
@@ -2388,8 +2395,8 @@ export interface SignedUrlOptions {
|
|
|
2388
2395
|
operation?: "get" | "put";
|
|
2389
2396
|
contentType?: string;
|
|
2390
2397
|
}
|
|
2391
|
-
`;function
|
|
2392
|
-
* @${
|
|
2398
|
+
`;function ks(){return`/**
|
|
2399
|
+
* @${Re.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
|
|
2393
2400
|
*
|
|
2394
2401
|
* Docs: https://developers.cloudflare.com/r2/api/s3/api/
|
|
2395
2402
|
*/
|
|
@@ -2452,8 +2459,8 @@ export async function getSignedUrl(
|
|
|
2452
2459
|
}
|
|
2453
2460
|
|
|
2454
2461
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2455
|
-
`}function
|
|
2456
|
-
* @${
|
|
2462
|
+
`}function Ts(){return`/**
|
|
2463
|
+
* @${Re.slice(1)} \u2014 AWS S3 wrapper.
|
|
2457
2464
|
*
|
|
2458
2465
|
* Docs: https://docs.aws.amazon.com/s3/
|
|
2459
2466
|
*/
|
|
@@ -2517,8 +2524,8 @@ export async function getSignedUrl(
|
|
|
2517
2524
|
}
|
|
2518
2525
|
|
|
2519
2526
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2520
|
-
`}function
|
|
2521
|
-
* @${
|
|
2527
|
+
`}function Os(){return`/**
|
|
2528
|
+
* @${Re.slice(1)} \u2014 Supabase Storage wrapper.
|
|
2522
2529
|
*
|
|
2523
2530
|
* Docs: https://supabase.com/docs/guides/storage
|
|
2524
2531
|
*/
|
|
@@ -2580,8 +2587,8 @@ export async function getSignedUrl(
|
|
|
2580
2587
|
}
|
|
2581
2588
|
|
|
2582
2589
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2583
|
-
`}function
|
|
2584
|
-
* @${
|
|
2590
|
+
`}function Us(){return`/**
|
|
2591
|
+
* @${Re.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
|
|
2585
2592
|
*
|
|
2586
2593
|
* Docs: https://help.aliyun.com/product/31815.html
|
|
2587
2594
|
*/
|
|
@@ -2627,8 +2634,8 @@ export async function getSignedUrl(
|
|
|
2627
2634
|
}
|
|
2628
2635
|
|
|
2629
2636
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2630
|
-
`}function
|
|
2631
|
-
* @${
|
|
2637
|
+
`}function Ls(){return`/**
|
|
2638
|
+
* @${Re.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
|
|
2632
2639
|
*
|
|
2633
2640
|
* Docs: https://cloud.tencent.com/document/product/436
|
|
2634
2641
|
*/
|
|
@@ -2682,8 +2689,8 @@ export async function getSignedUrl(
|
|
|
2682
2689
|
}
|
|
2683
2690
|
|
|
2684
2691
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2685
|
-
`}function
|
|
2686
|
-
* @${
|
|
2692
|
+
`}function Ms(){return`/**
|
|
2693
|
+
* @${Re.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
|
|
2687
2694
|
*
|
|
2688
2695
|
* Docs: https://developer.qiniu.com/kodo
|
|
2689
2696
|
*/
|
|
@@ -2750,9 +2757,9 @@ export async function getSignedUrl(
|
|
|
2750
2757
|
}
|
|
2751
2758
|
|
|
2752
2759
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2753
|
-
`}function
|
|
2754
|
-
`}}function
|
|
2755
|
-
`}async function
|
|
2760
|
+
`}function Ds(e){switch(e){case"r2":return ks();case"s3":return Ts();case"supabase-storage":return Os();case"aliyun-oss":return Us();case"tencent-cos":return Ls();case"qiniu":return Ms();case"none":return`export {};
|
|
2761
|
+
`}}function Fs(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:Re,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)+`
|
|
2762
|
+
`}async function xo(e,t,o){if(t==="none")return;let n=Ro(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${lt.map(s=>s.id).join(", ")}`);let r=Ce.join(e,"packages","storage"),i=Ce.join(r,"src");we.existsSync(i)&&we.rmSync(i,{recursive:!0,force:!0}),Zt(Ce.join(r,"package.json"),Fs(n)),Zt(Ce.join(i,"types.ts"),Ns),Zt(Ce.join(i,"index.ts"),Ds(n.id)),Rs(e,xs(n))}var Nt=[{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 No(e){return Nt.find(t=>t.id===e)}var jp=Nt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ko(e,t,o="global"){let n=No(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Nt.map(r=>r.id).join(", ")}`);if(n.id==="none"){K(e,"webhooks");return}n.envVars.length>0&&q(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),G(e,"WEBHOOKS_PROVIDER",n.id)}import xe from"fs";import dt from"path";function js(e){return`import Link from "next/link";
|
|
2756
2763
|
|
|
2757
2764
|
export default function WelcomePage() {
|
|
2758
2765
|
const projectName = ${JSON.stringify(e)};
|
|
@@ -2861,7 +2868,16 @@ function Step({
|
|
|
2861
2868
|
</li>
|
|
2862
2869
|
);
|
|
2863
2870
|
}
|
|
2864
|
-
`}function
|
|
2871
|
+
`}function Vs(e=[]){return e.length===0?"":`
|
|
2872
|
+
## Production readiness holds
|
|
2873
|
+
|
|
2874
|
+
Do not enable these in production until you replace stubs, add provider credentials, and verify the integration contract:
|
|
2875
|
+
|
|
2876
|
+
${e.map(o=>{let n=qe(o.status);return`- ${o.flag}=${o.provider} ${n} \u2014 ${te(o.status)}`}).join(`
|
|
2877
|
+
`)}
|
|
2878
|
+
|
|
2879
|
+
Review the package readiness matrix before handoff: [docs/package-status.md](docs/package-status.md)
|
|
2880
|
+
`}function Ks(e,t,o=[]){return`# Next steps \u2014 ${e}
|
|
2865
2881
|
|
|
2866
2882
|
Region: ${t}
|
|
2867
2883
|
|
|
@@ -2887,32 +2903,33 @@ Your AI-native SaaS scaffold is ready. Complete these four steps to go from temp
|
|
|
2887
2903
|
\`\`\`
|
|
2888
2904
|
|
|
2889
2905
|
After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
|
|
2906
|
+
${Vs(o)}
|
|
2890
2907
|
|
|
2891
2908
|
## Resources
|
|
2892
2909
|
|
|
2893
2910
|
- [Documentation](/docs)
|
|
2894
2911
|
- [GitHub](https://github.com/nebutra/nebutra-sailor)
|
|
2895
2912
|
- [Get free license (Individual/OPC)](https://nebutra.com/get-license)
|
|
2896
|
-
`}async function
|
|
2897
|
-
`)}function
|
|
2898
|
-
`)+
|
|
2899
|
-
`)),"fumadocs"}return"fumadocs"}function
|
|
2900
|
-
`)),process.exit(130)}});
|
|
2901
|
-
`)),process.exit(130)}}):{};
|
|
2902
|
-
`))}}let
|
|
2903
|
-
`+
|
|
2904
|
-
`));for(let
|
|
2905
|
-
`)
|
|
2906
|
-
`+
|
|
2907
|
-
`))),
|
|
2913
|
+
`}async function To(e,t){let{projectName:o,region:n,previewSelections:r=[]}=t;try{let i=dt.join(e,".sailor");xe.existsSync(i)||xe.mkdirSync(i,{recursive:!0}),xe.writeFileSync(dt.join(i,"next-steps.md"),Ks(o,n,r))}catch(i){let s=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${s}`)}try{let i=dt.join(e,"apps","web");if(!xe.existsSync(i))return;let s=dt.join(i,"src","app","[locale]","welcome");xe.existsSync(s)||xe.mkdirSync(s,{recursive:!0}),xe.writeFileSync(dt.join(s,"page.tsx"),js(o))}catch(i){let s=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write welcome page: ${s}`)}}var Oo="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
|
|
2914
|
+
`)}function $s(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function Uo(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 Lo(e){return e==="drizzle"?"drizzle":e==="none"?"none":"prisma"}function Mo(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function Do(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 Fo(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="none"?"none":"clerk"}function jo(e){if(!e)return["openai"];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}function qs(e,t){let o=e??t;return Jt(o)??o}var Vo={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Ko(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in Vo){let n=Vo[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(w.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
|
|
2915
|
+
`)+w.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
|
|
2916
|
+
`)),"fumadocs"}return"fumadocs"}function Bo(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 Yo(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function Gs(e){return{...e==="cn"?{email:"aliyun-dm",storage:"aliyun-oss",monitoring:"sentry",analytics:"baidu",sms:"aliyun-sms"}:e==="hybrid"?{email:"resend",storage:"aliyun-oss",monitoring:"sentry",analytics:"posthog",sms:"aliyun-sms"}:{email:"resend",storage:"r2",monitoring:"sentry",analytics:"posthog",sms:"twilio"},queue:"none",search:"none",cache:e==="global"?"upstash-redis":e==="cn"?"redis":"upstash-redis",notifications:"none",webhooks:"none",cms:"none",featureFlags:"none",captcha:e==="cn"?"aliyun-slide":"turnstile",mcp:"on",metering:"auto",billingMode:"usage",idp:"clerk"}}function $o(e){return e==="cn"?"wechat":"stripe"}async function Hs(){let e=new Bs;e.name(Oo).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ee,"-v, --version").helpOption(!1).argument("[name]","project directory",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--region <id>","global | cn | hybrid").option("--orm <id>","prisma | drizzle | none").option("--db <id>","postgres | mysql | sqlite | none").option("--auth <id>","clerk | betterauth | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <ids>","expert: comma-separated provider ids used as an AI provider seed").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 | upstash | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").option("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--no-install","skip package install").option("--no-git","skip git init").option("-y, --yes","accept all defaults (non-interactive)").option("--dry-run","preview actions without writing files").option("--json","machine-readable output").option("--no-color","disable color output").option("-h, --help","show help"),e.parse(process.argv);let t=e.opts(),[o]=e.args;t.help&&(an(),process.exit(0));let n=!!t.json,r=!!t.dryRun,i=!!t.yes,s=i||!process.stdin.isTTY;n||on(),p(n,{event:"start",version:ee});let c=o??(i?"./my-saas-app":void 0),a;if(c)a=c;else if(s)a="./my-saas-app";else{let m=await C.group({name:()=>C.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:f=>{if(f.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(w.red(`\u2718 Cancelled
|
|
2917
|
+
`)),process.exit(130)}});a=String(m.name)}let d=ut.basename(ut.resolve(a)),u=t.pm??$s(),h=!!t.region,O=!!t.auth,M=!!t.payment,D=!!t.ai,Xe=!!t.email,v=!!t.storage,l=!!t.monitoring,R=!!t.analytics,mt=!!t.sms,en=t.i18n!==void 0,y,ze,X,Qe,F,N,Y=En(t.socialLogin),Je,Tt,ue,Ne,z,j,gt;if(s){y=Yo(t.region),ze=Lo(t.orm),X=Uo(t.db);let m=M?t.payment:$o(y);Qe=Mo(m),F=Do(m),N=Fo(t.auth);let f=Dt({mode:D?t.ai?.trim().toLowerCase()==="none"?"none":"direct":"gateway",providerIds:D?jo(t.ai):void 0});Je=f.mode,Tt=f.routing,ue=f.providerIds,z=Bo(t.deploy),j=Ko(t.docs,n),gt=en?!!t.i18n:!0}else{let m={};h||(m.region=()=>C.select({message:"Target region?",options:[{value:"global",label:"global \u2014 \u6D77\u5916\u4F18\u5148"},{value:"cn",label:"cn \u2014 \u56FD\u5185\u4F18\u5148"},{value:"hybrid",label:"hybrid \u2014 \u53CC\u8F68\uFF08\u56FD\u5185+\u51FA\u6D77\uFF09"}],initialValue:"global"})),O||(m.auth=()=>C.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk"},{value:"betterauth",label:"Better Auth"},{value:"none",label:"None"}],initialValue:"clerk"})),D||(m.aiMode=()=>C.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"}),m.aiProviders=({results:E})=>{if(E.aiMode!=="direct")return Promise.resolve([]);let Q=Mt.map(Ut=>({value:Ut.id,label:`[${Ut.category}] ${Ut.name}`}));return C.multiselect({message:"Select direct AI provider adapters (expert path)",options:Q,initialValues:["openai"],required:!1})},m.customAiName=({results:E})=>E.aiMode==="custom"?C.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),m.customAiBaseUrl=({results:E})=>E.aiMode==="custom"?C.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:Q=>{if(Q.length===0)return"Base URL is required."}}):Promise.resolve(void 0),m.customAiApiKeyEnv=({results:E})=>E.aiMode==="custom"?C.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0));let f=Object.keys(m).length>0?await C.group(m,{onCancel:()=>{process.stdout.write(w.red(`\u2718 Cancelled
|
|
2918
|
+
`)),process.exit(130)}}):{};y=Yo(h?t.region:f.region),ze=Lo(t.orm),X=Uo(t.db);let V=M?t.payment:$o(y);Qe=Mo(V),F=Do(V),N=Fo(O?t.auth:f.auth);let St=f.aiMode==="custom"?{name:f.customAiName??"custom",baseURL:f.customAiBaseUrl??"",apiKeyEnvName:f.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,S=Dt({mode:D?t.ai?.trim().toLowerCase()==="none"?"none":"direct":f.aiMode??"gateway",providerIds:D?jo(t.ai):f.aiProviders,customEndpoint:St});Je=S.mode,Tt=S.routing,ue=S.providerIds,S.customEndpoint&&(Ne={name:S.customEndpoint.name,baseURL:S.customEndpoint.baseURL,apiKeyEnvName:S.customEndpoint.apiKeyEnvName}),z=Bo(t.deploy),j=Ko(t.docs,n),gt=en?!!t.i18n:!0}let b=Gs(y),ke=Xe?t.email:b.email,Te=qs(v?t.storage:void 0,b.storage),Oe=l?t.monitoring:b.monitoring,Ue=R?t.analytics:b.analytics,Le=mt?t.sms:b.sms,Me=t.queue??b.queue,De=t.search??b.search,Ze=t.cache??b.cache,Fe=t.notifications??b.notifications,je=t.webhooks??b.webhooks,et=t.cms??b.cms,Ve=t.featureFlags??b.featureFlags,Ke=t.captcha??b.captcha,ft=t.mcp??b.mcp,tt=t.metering??b.metering,Be=t.billingMode??b.billingMode,Ye=t.idp??b.idp,$e=rn([{flag:"queue",provider:Me},{flag:"search",provider:De},{flag:"notifications",provider:Fe},{flag:"webhooks",provider:je},{flag:"feature-flags",provider:Ve},{flag:"captcha",provider:Ke}]);function Ot(){for(let m of $e)if(n)p(!0,{event:"warn",step:m.flag,provider:m.provider,packageStatus:m.status,message:te(m.status)});else{let f=qe(m.status);process.stdout.write(w.yellow(`\u26A0 ${m.flag}=${m.provider} ${f} \u2014 ${te(m.status)}
|
|
2919
|
+
`))}}let me={region:y,orm:ze,database:X,payment:Qe,aiMode:Je,aiRouting:Tt,aiProviders:ue,customAiEndpoint:Ne,deployTarget:z,docs:j,i18n:gt,email:ke,storage:Te,monitoring:Oe,analytics:Ue,sms:Le,queue:Me,search:De,cache:Ze,notifications:Fe,webhooks:je,cms:et,featureFlags:Ve,captcha:Ke,mcp:ft,metering:tt,billingMode:Be,idp:Ye},yt=[["Project name",d],["Region",y],["Auth",N],["Social login",Y.length>0?Y.map(m=>nt.find(f=>f.id===m)?.name??m).join(", "):"none"],["ORM",ze],["Database",X],["Payment",F],["AI topology",`${Je}${ue.length>0?` (${ue.join(", ")} seed)`:""}${Ne?" + custom endpoint":""}`],["Email",ke],["Storage",Te],["Monitoring",Oe],["Analytics",Ue],["SMS",Le],["Deploy Target",z],["Docs Framework",j]];n?yt.forEach(([m,f],V)=>{p(!0,{event:"step",step:m,value:f,index:V+1,total:yt.length})}):yt.forEach(([m,f],V)=>{pn({index:V+1,total:yt.length,label:m,value:f})});let qo={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},tn=Date.now();if(r){let m=ue.length,f=[`clone template \u2192 ${a}`,"write nebutra.config.json",`prune template (orm=${ze}, i18n=${gt})`,`region \u2192 ${y}`,`auth \u2192 ${N==="none"?"skip (remove packages/auth)":`configure ${N}`}`,...Y.length>0?[`social-login \u2192 generate ${Y.length} callback route${Y.length===1?"":"s"} + SocialLoginButtons.tsx (${Y.join(", ")})`]:[],`db \u2192 ${X==="none"?"skip (remove packages/db)":`configure Prisma for ${X}`}`,`payment \u2192 ${F==="none"?"skip (remove packages/billing)":`configure ${F}`}`,...j!=="none"?[`docs \u2192 scaffold apps/docs (${j==="fumadocs"?"fumadocs":`${j} \u2192 fumadocs fallback`})`]:[],...m>0||Ne?[`ai-providers \u2192 generate ${Je} registry seed + env (${m}${Ne?" + custom":""} provider${m===1&&!Ne?"":"s"})`]:[],...ke!=="none"?[`email \u2192 configure ${ke}`]:[],...Te!=="none"?[`storage \u2192 configure ${Te}`]:[],...Oe!=="none"?[`monitoring \u2192 configure ${Oe}`]:[],...Ue!=="none"?[`analytics \u2192 configure ${Ue}`]:[],...Le!=="none"?[`sms \u2192 configure ${Le}`]:[],...Me!=="none"?[`queue \u2192 configure ${Me}`]:[],...De!=="none"?[`search \u2192 configure ${De}`]:[],...Ze!=="none"?[`cache \u2192 configure ${Ze}`]:[],...Fe!=="none"?[`notifications \u2192 configure ${Fe}`]:[],...je!=="none"?[`webhooks \u2192 configure ${je}`]:[],...et!=="none"?[`cms \u2192 configure ${et}`]:[],...Ve!=="none"?[`feature-flags \u2192 configure ${Ve}`]:[],...Ke!=="none"?[`captcha \u2192 configure ${Ke}`]:[],`mcp \u2192 ${ft==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${tt==="off"?"disabled":tt==="auto"?Qe!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...Be!=="usage"?[`billing-mode \u2192 ${Be}`]:[],...Ye!=="clerk"?[`idp \u2192 ${Ye}`]:[],`compliance \u2192 inject ${y} boilerplate (ICP/Cookie/AIGC/Privacy)`,"welcome \u2192 generate dev welcome page","env \u2192 generate random secrets (AUTH_SECRET, JWT_SECRET)","seed \u2192 generate prisma/seed.ts (1 admin + 3 tenants)",...z!=="none"?[`deploy \u2192 inject ${z} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${u} install`,t.git===!1?"skip git init":"run git init"];if(n){for(let V of f)p(!0,{event:"plan",action:V});Ot(),p(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
|
|
2920
|
+
`+w.bold(`Dry run \u2014 planned actions:
|
|
2921
|
+
`));for(let V of f)process.stdout.write(` \u2022 ${V}
|
|
2922
|
+
`);$e.length>0&&(process.stdout.write(`
|
|
2923
|
+
`+w.bold(w.yellow(`Preview-status providers selected:
|
|
2924
|
+
`))),Ot()),process.stdout.write(w.dim(`
|
|
2908
2925
|
No files were written.
|
|
2909
|
-
`))}process.exit(0)}let
|
|
2910
|
-
`+
|
|
2911
|
-
`)),
|
|
2912
|
-
`))),process.exit(130)};process.on("SIGINT",
|
|
2913
|
-
`));try{
|
|
2914
|
-
`))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{
|
|
2915
|
-
`))}}else p(n,{event:"step",step:"git-init",status:"skip"});let
|
|
2916
|
-
\u2718 Failed: ${
|
|
2917
|
-
`)),process.exit(1)}}
|
|
2926
|
+
`))}process.exit(0)}let Go=async()=>{process.stdout.write(`
|
|
2927
|
+
`+w.red(`\u2718 Cancelled
|
|
2928
|
+
`)),de.existsSync(a)&&await C.confirm({message:`Cleanup partial install at ${a}?`,initialValue:!0})===!0&&(de.rmSync(a,{recursive:!0,force:!0}),process.stdout.write(w.dim(` \u2713 Removed ${a}
|
|
2929
|
+
`))),process.exit(130)};process.on("SIGINT",Go);try{p(n,{event:"step",step:"clone",status:"start"}),await Zn(a),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await co(a,d),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await xn(a,me),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await Eo(a,me),p(n,{event:"step",step:"prune",status:"ok"});let m=ut.join(a,"packages/db/prisma/schema.prisma");if(de.existsSync(m)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let S=de.readFileSync(m,"utf-8"),E=Wt(S,{auth:N,payment:F,"billing-mode":Be,idp:Ye,template:"saas"});de.writeFileSync(m,E),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(S){let E=S instanceof Error?S.message:String(S);p(n,{event:"step",step:"schema-prune",status:"error",error:E})}}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"auth",choice:N,status:"start"}),await yn(a,N),p(n,{event:"step",step:"auth",choice:N,status:"ok"}),Y.length>0?(p(n,{event:"step",step:"social-login",providers:Y,status:"start"}),await vn(a,Y,N),p(n,{event:"step",step:"social-login",providers:Y,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:X,status:"start"}),await Tn(a,X,d),p(n,{event:"step",step:"db",choice:X,status:"ok"}),p(n,{event:"step",step:"payment",choice:F,status:"start"}),await lo(a,F),p(n,{event:"step",step:"payment",choice:F,status:"ok"}),await jn(a,ke,y),n&&p(!0,{event:"step",step:"email",choice:ke,status:"ok"}),await xo(a,Te,y),n&&p(!0,{event:"step",step:"storage",choice:Te,status:"ok"}),await io(a,Oe,y),n&&p(!0,{event:"step",step:"monitoring",choice:Oe,status:"ok"}),await un(a,Ue,y),n&&p(!0,{event:"step",step:"analytics",choice:Ue,status:"ok"}),await wo(a,Le,y),n&&p(!0,{event:"step",step:"sms",choice:Le,status:"ok"}),await _o(a,Me,y),n&&p(!0,{event:"step",step:"queue",choice:Me,status:"ok"}),await Io(a,De,y),n&&p(!0,{event:"step",step:"search",choice:De,status:"ok"}),await bn(a,Ze,y),n&&p(!0,{event:"step",step:"cache",choice:Ze,status:"ok"}),await ao(a,Fe,y),n&&p(!0,{event:"step",step:"notifications",choice:Fe,status:"ok"}),await ko(a,je,y),n&&p(!0,{event:"step",step:"webhooks",choice:je,status:"ok"}),await wn(a,et,y),n&&p(!0,{event:"step",step:"cms",choice:et,status:"ok"}),await Gn(a,Ve,y),n&&p(!0,{event:"step",step:"feature-flags",choice:Ve,status:"ok"}),await An(a,Ke,y),n&&p(!0,{event:"step",step:"captcha",choice:Ke,status:"ok"}),await eo(a,ft),n&&p(!0,{event:"step",step:"mcp",mode:ft,status:"ok"}),await no(a,tt,Qe),n&&p(!0,{event:"step",step:"metering",mode:tt,status:"ok"}),me.orm==="prisma"&&me.database!=="none"){let S=ut.join(a,"packages/db/prisma/schema.prisma");if(de.existsSync(S)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let E=de.readFileSync(S,"utf8"),Q=Wt(E,{auth:N,payment:F,"billing-mode":Be,idp:Ye,template:"saas"});de.writeFileSync(S,Q),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(E){let Q=E instanceof Error?E.message:String(E);p(n,{event:"step",step:"schema-prune",status:"error",error:Q})}}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:Be,status:"ok"}),p(n,{event:"step",step:"idp",choice:Ye,status:"ok"}),await Rn(a,y),n&&p(!0,{event:"step",step:"compliance",region:y,status:"ok"}),await $n(a),await Ao(a,N),await To(a,{projectName:d,region:y,previewSelections:$e}),me.aiMode!=="none"){p(n,{event:"step",step:"ai-providers",status:"start"});let S={providerIds:me.aiProviders,customEndpoint:me.customAiEndpoint},E=ut.join(a,"packages/ai-providers/templates");await yo(a,S,E),p(n,{event:"step",step:"ai-providers",status:"ok"})}else p(n,{event:"step",step:"ai-providers",status:"skip"});if(p(n,{event:"step",step:"docs",status:"start"}),j!=="none"?(await Ln(a,{framework:j,projectName:d}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:j,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),z!=="none"&&await On(a,z),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await Kn(a,qo),p(n,{event:"step",step:"env",status:"ok"}),t.install!==!1){let S=u==="bun"?"bun install":`${u} install`;n?p(!0,{event:"step",step:"install",pm:u,status:"start"}):process.stdout.write(w.dim(` Installing dependencies with ${u}\u2026
|
|
2930
|
+
`));try{kt(S,{cwd:a,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(E){let Q=E instanceof Error?E.message:String(E);n?p(!0,{event:"step",step:"install",status:"error",error:Q}):process.stdout.write(w.yellow(` \u26A0 install failed \u2014 run '${S}' manually.
|
|
2931
|
+
`))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{kt("git init -q",{cwd:a,stdio:"ignore"}),kt("git add -A",{cwd:a,stdio:"ignore"}),kt('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(S){let E=S instanceof Error?S.message:String(S);n?p(!0,{event:"step",step:"git-init",status:"error",error:E}):process.stdout.write(w.yellow(` \u26A0 git init skipped \u2014 not fatal.
|
|
2932
|
+
`))}}else p(n,{event:"step",step:"git-init",status:"skip"});let St=Math.max(1,Math.round((Date.now()-tn)/1e3));mn({template_version:ee,package_manager:u,region:y,auth:N,payment:F,ai_providers:ue,deploy_target:z,duration_ms:Date.now()-tn}),$e.length>0&&Ot(),n?p(!0,{event:"done",status:"ok",elapsedSec:St,targetDir:a,previewSelections:$e}):sn({elapsedSec:St,targetDir:a,skippedInstall:t.install===!1,previewSelections:$e});try{Ys({pkg:{name:Oo,version:ee},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(m){let f=m instanceof Error?m.message:String(m);n?p(!0,{event:"error",message:f}):process.stdout.write(w.red(`
|
|
2933
|
+
\u2718 Failed: ${f}
|
|
2934
|
+
`)),process.exit(1)}}Hs().catch(e=>{process.stderr.write(String(e)+`
|
|
2918
2935
|
`),process.exit(1)});
|