create-sailor 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aws-kms-BRGZLC2X.js +1 -0
- package/dist/chunk-2VIWVVHK.js +1 -0
- package/dist/chunk-4F23MJOI.js +1 -0
- package/dist/chunk-6EI2BXXZ.js +1 -0
- package/dist/chunk-7DCGNQSQ.js +5 -0
- package/dist/chunk-7HOF72FC.js +1 -0
- package/dist/chunk-7VJYOZUP.js +2 -0
- package/dist/chunk-7Z3O7WJM.js +49 -0
- package/dist/chunk-B35GFLVZ.js +5 -0
- package/dist/chunk-BAI5W3AB.js +1 -0
- package/dist/chunk-DGJUBN33.js +1 -0
- package/dist/chunk-DIXI4M5O.js +1 -0
- package/dist/chunk-EA5HU2X4.js +9 -0
- package/dist/chunk-EXLRPVEX.js +1 -0
- package/dist/chunk-FGJ5K4WM.js +1 -0
- package/dist/chunk-HC3S5NWW.js +1 -0
- package/dist/chunk-KIX47M2V.js +40 -0
- package/dist/chunk-LOPYJ44X.js +31 -0
- package/dist/chunk-O3WYNHSC.js +20 -0
- package/dist/chunk-OJM5Y4UT.js +1 -0
- package/dist/chunk-PXU2OOBT.js +1 -0
- package/dist/chunk-QEIMNOY2.js +1 -0
- package/dist/chunk-QMKVUKS6.js +1 -0
- package/dist/chunk-RR5R4AKJ.js +1 -0
- package/dist/chunk-XSSPJU77.js +1 -0
- package/dist/chunk-YW4FFW47.js +1 -0
- package/dist/chunk-ZEEOYOWD.js +1 -0
- package/dist/credits-L2HL2UEU.js +1787 -0
- package/dist/dist-XS6SQF6X.js +5 -0
- package/dist/dist-Z6UUHTH2.js +8 -0
- package/dist/dist-es-M3FWVZJF.js +1 -0
- package/dist/dist-es-NDZJSZR3.js +2 -0
- package/dist/dist-es-NVFYVK4E.js +1 -0
- package/dist/dist-es-OUTR3NFA.js +5 -0
- package/dist/dist-es-UGE2JJUB.js +1 -0
- package/dist/dist-es-VHZAJVLW.js +1 -0
- package/dist/dist-es-WTYBIVJ2.js +2 -0
- package/dist/event-streams-WTP73PI5.js +1 -0
- package/dist/getMachineId-bsd-DVN24SFH.js +1 -0
- package/dist/getMachineId-darwin-LMU6AYNV.js +2 -0
- package/dist/getMachineId-linux-BHWLMOUW.js +1 -0
- package/dist/getMachineId-unsupported-G5LY7Y3J.js +1 -0
- package/dist/getMachineId-win-CWK62SDK.js +1 -0
- package/dist/index.js +211 -176
- package/dist/loadSso-O5OGD76B.js +1 -0
- package/dist/local-V5XPOCXA.js +1 -0
- package/dist/multipart-parser-73SROTP5.js +2 -0
- package/dist/query_compiler_fast_bg.postgresql-7BFUBDOL.js +2 -0
- package/dist/query_compiler_fast_bg.postgresql.wasm-base64-I4FAC6EL.js +1 -0
- package/dist/signin-DZIPNQBV.js +1 -0
- package/dist/src-BFSJ5KFS.js +3 -0
- package/dist/src-ERQKJBBE.js +1 -0
- package/dist/sso-oidc-SYBBWZG3.js +1 -0
- package/dist/sts-DREA5KZD.js +6 -0
- package/package.json +14 -11
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{execSync as
|
|
3
|
-
`));return}
|
|
2
|
+
import"./chunk-DGJUBN33.js";import{execSync as Ot}from"child_process";import ue from"fs";import dt from"path";import*as C from"@clack/prompts";import{Command as Li}from"commander";import R from"picocolors";import Mi from"update-notifier";import $o from"cfonts";import qo from"picocolors";import Zt from"fs";import Lt from"path";import{fileURLToPath as Bo}from"url";function Yo(){try{let t=Lt.dirname(Bo(import.meta.url));for(let o=0;o<4;o++){let n=Lt.join(t,"package.json");if(Zt.existsSync(n)){let r=Zt.readFileSync(n,"utf-8"),s=JSON.parse(r);if(s.name==="create-sailor"&&typeof s.version=="string")return s.version}t=Lt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ne=Yo();function en(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ne}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
|
|
3
|
+
`));return}$o.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(qo.dim(` AI-Native SaaS Template \xB7 v${ne} \xB7 nebutra.com
|
|
4
4
|
|
|
5
|
-
`))}import
|
|
5
|
+
`))}import h from"picocolors";var Go={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 Ho(e){return e?Go[e]??"stable":"stable"}function St(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function qe(e){switch(e){case"stable":return"Production-ready.";case"foundation":return"Foundation status \u2014 types + factory are complete, but provider adapters are stub-level and require external credentials.";case"wip":return"WIP \u2014 actively being built, should not be used in production.";case"deprecated":return"Deprecated \u2014 scheduled for removal, do not use."}}function tn(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=Ho(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function Wo(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function nn(e){let t=Wo(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",s=t?"\u{1F4E7}":"*",c=["",` ${t?h.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?h.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?h.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?h.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?h.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?h.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?h.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?h.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?h.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?h.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?h.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?h.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?h.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?h.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`);let i=e.previewSelections??[];if(i.length>0){let d=t?h.bold(h.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${d}`);for(let u of i){let S=St(u.status),U=` ${n} ${u.flag} (${u.provider}) ${S}`;c.push(t?h.yellow(U):U)}c.push("",` ${t?h.dim(qe("foundation")):qe("foundation")}`,` ${t?h.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?h.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?h.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${s} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
|
|
6
6
|
`)+`
|
|
7
|
-
`)}var
|
|
7
|
+
`)}var Xo=`Usage: create-sailor [name] [options]
|
|
8
8
|
|
|
9
9
|
Arguments:
|
|
10
10
|
name project directory (default: ./my-saas-app)
|
|
@@ -28,6 +28,25 @@ Feature flags (region-based smart defaults):
|
|
|
28
28
|
--monitoring <id> sentry | datadog | aliyun-arms | tingyun | none
|
|
29
29
|
--analytics <id> posthog | plausible | umami | baidu | sensors | none
|
|
30
30
|
--sms <id> twilio | aliyun-sms | tencent-sms | yunpian | none
|
|
31
|
+
--queue <id> qstash | bullmq | upstash | sqs | none [Foundation]
|
|
32
|
+
--search <id> meilisearch | typesense | algolia | pgvector | none [Foundation]
|
|
33
|
+
--cache <id> upstash-redis | vercel-kv | redis | dragonfly | none
|
|
34
|
+
--notifications <id> novu | knock | custom | none [Foundation]
|
|
35
|
+
--webhooks <id> svix | custom | none [Foundation]
|
|
36
|
+
--cms <id> sanity | contentful | strapi | none
|
|
37
|
+
--feature-flags <id> vercel-flags | growthbook | configcat | none [WIP]
|
|
38
|
+
--captcha <id> turnstile | hcaptcha | aliyun-slide | none [WIP]
|
|
39
|
+
--billing-mode <mode> usage | seat | credits (default: usage)
|
|
40
|
+
--idp <id> clerk | oauth-server (default: clerk)
|
|
41
|
+
|
|
42
|
+
Preview statuses:
|
|
43
|
+
[Foundation] \u2014 types + factory complete; adapters need external credentials & may not work out-of-the-box
|
|
44
|
+
[WIP] \u2014 actively being built; do not use in production
|
|
45
|
+
See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md
|
|
46
|
+
|
|
47
|
+
Sailor features:
|
|
48
|
+
--mcp <mode> on | off (default: on \u2014 Agent-friendly MCP server)
|
|
49
|
+
--metering <mode> auto | on | off (default: auto)
|
|
31
50
|
|
|
32
51
|
Toggles:
|
|
33
52
|
--i18n enable i18n (default: true)
|
|
@@ -47,9 +66,9 @@ Examples:
|
|
|
47
66
|
$ npm create sailor@latest my-app --region=cn --auth=clerk
|
|
48
67
|
$ npm create sailor@latest my-app --region=hybrid --ai=openai,deepseek
|
|
49
68
|
$ npm create sailor@latest --dry-run --region=cn
|
|
50
|
-
`;function
|
|
51
|
-
`)}var Ge=[{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:[]}],hs=Ge.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});import Ie from"fs";import A from"path";var St=[{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:""}],vs=St.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Et(e){return St.find(t=>t.id===e)}function Ln(e){Ie.mkdirSync(e,{recursive:!0})}function j(e,t){Ln(A.dirname(e)),Ie.writeFileSync(e,t)}function Q(e,t){let n=A.join(e,".env.example");Ie.existsSync(n)?Ie.appendFileSync(n,`
|
|
52
|
-
`+t):
|
|
69
|
+
`;function on(){process.stdout.write(Xo)}import Et from"picocolors";function rn(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function zo(e){let t=rn()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return rn()?`${Et.dim(o)} ${Et.bold(n)} ${Et.dim(t)} ${Et.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function sn(e){process.stdout.write(zo(e)+`
|
|
70
|
+
`)}var ht=[{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:[]}],ta=ht.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var Qo="https://analytics.nebutra.com";function Jo(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function an(e,t={}){Jo(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??Qo},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:""}],ra=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 Zo(e){Ge.mkdirSync(e,{recursive:!0})}function q(e,t){Zo(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 er(e){let t=`"use client";
|
|
53
72
|
/**
|
|
54
73
|
* PostHog browser SDK \u2014 lazy-initialized on first access.
|
|
55
74
|
*/
|
|
@@ -74,7 +93,7 @@ export function initPostHog(): void {
|
|
|
74
93
|
}
|
|
75
94
|
|
|
76
95
|
export { posthog };
|
|
77
|
-
`,
|
|
96
|
+
`,o=`import { PostHog } from "posthog-node";
|
|
78
97
|
|
|
79
98
|
/**
|
|
80
99
|
* PostHog server-side client. Remember to await client.shutdown() at the end
|
|
@@ -105,7 +124,7 @@ export async function captureServerEvent(
|
|
|
105
124
|
ph.capture({ distinctId, event, properties });
|
|
106
125
|
await ph.shutdown();
|
|
107
126
|
}
|
|
108
|
-
`,
|
|
127
|
+
`,n=`"use client";
|
|
109
128
|
/**
|
|
110
129
|
* <AnalyticsProvider /> \u2014 wrap the app root to enable PostHog + auto page views.
|
|
111
130
|
*/
|
|
@@ -132,11 +151,11 @@ export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
|
|
|
132
151
|
|
|
133
152
|
return <>{children}</>;
|
|
134
153
|
}
|
|
135
|
-
`;
|
|
154
|
+
`;q(T.join(e,"src","lib","analytics","posthog.client.ts"),t),q(T.join(e,"src","lib","analytics","posthog.server.ts"),o),q(T.join(e,"src","components","analytics","AnalyticsProvider.tsx"),n)}function tr(){return`# PostHog \u2014 product analytics
|
|
136
155
|
POSTHOG_KEY=
|
|
137
156
|
NEXT_PUBLIC_POSTHOG_KEY=
|
|
138
157
|
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
|
139
|
-
`}function
|
|
158
|
+
`}function nr(e){q(T.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
|
|
140
159
|
/**
|
|
141
160
|
* Plausible script tag \u2014 lightweight, privacy-friendly analytics.
|
|
142
161
|
*/
|
|
@@ -156,10 +175,10 @@ export function PlausibleScript() {
|
|
|
156
175
|
/>
|
|
157
176
|
);
|
|
158
177
|
}
|
|
159
|
-
`)}function
|
|
178
|
+
`)}function or(){return`# Plausible \u2014 privacy-friendly analytics
|
|
160
179
|
NEXT_PUBLIC_PLAUSIBLE_DOMAIN=
|
|
161
180
|
NEXT_PUBLIC_PLAUSIBLE_SRC=https://plausible.io/js/script.js
|
|
162
|
-
`}function
|
|
181
|
+
`}function rr(e){q(T.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
|
|
163
182
|
/**
|
|
164
183
|
* Umami analytics \u2014 self-hosted OR umami.is cloud.
|
|
165
184
|
*/
|
|
@@ -179,10 +198,10 @@ export function UmamiScript() {
|
|
|
179
198
|
/>
|
|
180
199
|
);
|
|
181
200
|
}
|
|
182
|
-
`)}function
|
|
201
|
+
`)}function sr(){return`# Umami \u2014 self-hostable analytics
|
|
183
202
|
NEXT_PUBLIC_UMAMI_WEBSITE_ID=
|
|
184
203
|
NEXT_PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
|
|
185
|
-
`}function
|
|
204
|
+
`}function ir(e){let t=`"use client";
|
|
186
205
|
import mixpanel from "mixpanel-browser";
|
|
187
206
|
|
|
188
207
|
let initialized = false;
|
|
@@ -200,7 +219,7 @@ export function initMixpanel(): void {
|
|
|
200
219
|
}
|
|
201
220
|
|
|
202
221
|
export { mixpanel };
|
|
203
|
-
`,
|
|
222
|
+
`,o=`import Mixpanel from "mixpanel";
|
|
204
223
|
|
|
205
224
|
let client: Mixpanel.Mixpanel | null = null;
|
|
206
225
|
|
|
@@ -221,10 +240,10 @@ export function trackServer(
|
|
|
221
240
|
if (!c) return;
|
|
222
241
|
c.track(event, { distinct_id: distinctId, ...properties });
|
|
223
242
|
}
|
|
224
|
-
`;
|
|
243
|
+
`;q(T.join(e,"src","lib","analytics","mixpanel.client.ts"),t),q(T.join(e,"src","lib","analytics","mixpanel.server.ts"),o)}function ar(){return`# Mixpanel \u2014 product analytics
|
|
225
244
|
MIXPANEL_TOKEN=
|
|
226
245
|
NEXT_PUBLIC_MIXPANEL_TOKEN=
|
|
227
|
-
`}function
|
|
246
|
+
`}function cr(e){q(T.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
|
|
228
247
|
/**
|
|
229
248
|
* \u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji \u2014 hm.js \u57CB\u70B9\u811A\u672C.
|
|
230
249
|
*/
|
|
@@ -250,9 +269,9 @@ var _hmt = _hmt || [];
|
|
|
250
269
|
/>
|
|
251
270
|
);
|
|
252
271
|
}
|
|
253
|
-
`)}function
|
|
272
|
+
`)}function pr(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
|
|
254
273
|
NEXT_PUBLIC_BAIDU_STATS_ID=
|
|
255
|
-
`}function
|
|
274
|
+
`}function lr(e){q(T.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
|
|
256
275
|
/**
|
|
257
276
|
* \u795E\u7B56\u5206\u6790 (Sensors Analytics) \u2014 sa-sdk-javascript \u5C01\u88C5.
|
|
258
277
|
*/
|
|
@@ -280,10 +299,10 @@ export function initSensors(): void {
|
|
|
280
299
|
}
|
|
281
300
|
|
|
282
301
|
export { sensors };
|
|
283
|
-
`)}function
|
|
302
|
+
`)}function dr(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
|
|
284
303
|
NEXT_PUBLIC_SENSORS_SERVER_URL=
|
|
285
304
|
NEXT_PUBLIC_SENSORS_APP_JS_URL=
|
|
286
|
-
`}function
|
|
305
|
+
`}function ur(e){q(T.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
|
|
287
306
|
/**
|
|
288
307
|
* GrowingIO CDP \u2014 inline snippet installer.
|
|
289
308
|
*/
|
|
@@ -308,24 +327,24 @@ gdp("send");
|
|
|
308
327
|
/>
|
|
309
328
|
);
|
|
310
329
|
}
|
|
311
|
-
`)}function
|
|
330
|
+
`)}function mr(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
|
|
312
331
|
NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
|
|
313
|
-
`}async function
|
|
314
|
-
`+t):
|
|
315
|
-
`+t)}async function
|
|
332
|
+
`}async function ln(e,t,o="global"){let n=pn(t);if(!n||n.id==="none")return;let r=T.join(e,"apps","web");if(!Ge.existsSync(r))return;let s=n.id;try{switch(s){case"posthog":er(r),me(e,tr());return;case"plausible":nr(r),me(e,or());return;case"umami":rr(r),me(e,sr());return;case"mixpanel":ir(r),me(e,ar());return;case"baidu":cr(r),me(e,pr());return;case"sensors":lr(r),me(e,dr());return;case"growingio":ur(r),me(e,mr());return;default:return}}catch(a){throw console.error(`Failed to apply analytics selection "${t}":`,a),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}import M from"fs";import ge from"path";function Mt(e){M.existsSync(e)&&M.rmSync(e,{recursive:!0,force:!0})}function dn(e,t){let o=ge.join(e,".env.example");M.existsSync(o)?M.appendFileSync(o,`
|
|
333
|
+
`+t):M.writeFileSync(o,t)}function un(e,t){if(!M.existsSync(e))return;let o=M.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*"[^"]+"\s*\|\s*"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&M.writeFileSync(e,n)}function gr(e,t){let o=ge.join(e,"README.md");if(!M.existsSync(o)){M.writeFileSync(o,t);return}M.appendFileSync(o,`
|
|
334
|
+
`+t)}async function mn(e,t){let o=ge.join(e,"packages","auth");if(!M.existsSync(o))return;if(t==="none"){Mt(o),gr(e,`
|
|
316
335
|
## Auth
|
|
317
336
|
|
|
318
337
|
Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth).
|
|
319
|
-
`);return}let
|
|
338
|
+
`);return}let n=ge.join(o,"src","providers"),r=ge.join(o,"src","types.ts");if(t==="clerk"){Mt(ge.join(n,"better-auth.ts")),un(r,"clerk"),dn(e,`# Clerk auth
|
|
320
339
|
CLERK_PUBLISHABLE_KEY=
|
|
321
340
|
CLERK_SECRET_KEY=
|
|
322
|
-
`);return}if(t==="betterauth"){
|
|
341
|
+
`);return}if(t==="betterauth"){Mt(ge.join(n,"clerk.ts")),un(r,"better-auth"),dn(e,`# Better Auth
|
|
323
342
|
BETTER_AUTH_SECRET=
|
|
324
343
|
BETTER_AUTH_URL=http://localhost:3000
|
|
325
|
-
`);return}}var
|
|
344
|
+
`);return}}var nt=[{id:"wechat",name:"\u5FAE\u4FE1\u5F00\u653E\u5E73\u53F0",region:"cn",envVars:["WECHAT_APP_ID","WECHAT_APP_SECRET"],docs:"https://open.weixin.qq.com/cgi-bin/showdocument",callbackUrl:"/api/auth/callback/wechat",tokenEndpoint:"https://api.weixin.qq.com/sns/oauth2/access_token"},{id:"qq",name:"QQ \u767B\u5F55",region:"cn",envVars:["QQ_APP_ID","QQ_APP_KEY"],docs:"https://wiki.connect.qq.com",callbackUrl:"/api/auth/callback/qq",tokenEndpoint:"https://graph.qq.com/oauth2.0/token"},{id:"dingtalk",name:"\u9489\u9489",region:"cn",envVars:["DINGTALK_APP_ID","DINGTALK_APP_SECRET"],docs:"https://open.dingtalk.com/document/",callbackUrl:"/api/auth/callback/dingtalk",tokenEndpoint:"https://api.dingtalk.com/v1.0/oauth2/userAccessToken"},{id:"workweixin",name:"\u4F01\u4E1A\u5FAE\u4FE1",region:"cn",envVars:["WORKWEIXIN_CORP_ID","WORKWEIXIN_AGENT_ID","WORKWEIXIN_SECRET"],docs:"https://developer.work.weixin.qq.com",callbackUrl:"/api/auth/callback/workweixin",tokenEndpoint:"https://qyapi.weixin.qq.com/cgi-bin/gettoken"},{id:"feishu",name:"\u98DE\u4E66 / Lark",region:"cn",envVars:["FEISHU_APP_ID","FEISHU_APP_SECRET"],docs:"https://open.feishu.cn/document/",callbackUrl:"/api/auth/callback/feishu",tokenEndpoint:"https://open.feishu.cn/open-apis/authen/v1/access_token"},{id:"weibo",name:"\u5FAE\u535A",region:"cn",envVars:["WEIBO_APP_KEY","WEIBO_APP_SECRET"],docs:"https://open.weibo.com/wiki/",callbackUrl:"/api/auth/callback/weibo",tokenEndpoint:"https://api.weibo.com/oauth2/access_token"}],fr=new Set(nt.map(e=>e.id));function gn(e){return nt.find(t=>t.id===e)}function fn(e){if(!e)return[];let t=e.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean);if(t.includes("none"))return[];let o=[],n=new Set;for(let r of t)fr.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import ye from"fs";import fe from"path";function yr(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
|
|
326
345
|
// Generated by create-sailor \u2014 OAuth callback for ${e.name}
|
|
327
346
|
// Primary auth provider: ${t}
|
|
328
|
-
// Docs: ${e.docs}`,
|
|
347
|
+
// Docs: ${e.docs}`,n={wechat:` const tokenRes = await fetch(
|
|
329
348
|
"${e.tokenEndpoint}?" +
|
|
330
349
|
new URLSearchParams({
|
|
331
350
|
appid: process.env.WECHAT_APP_ID ?? "",
|
|
@@ -426,7 +445,7 @@ BETTER_AUTH_URL=http://localhost:3000
|
|
|
426
445
|
const token = (await tokenRes.json()) as { access_token?: string; uid?: string };
|
|
427
446
|
if (!token.access_token) {
|
|
428
447
|
return NextResponse.redirect(new URL("/login?error=weibo_token", req.url));
|
|
429
|
-
}`};return`${
|
|
448
|
+
}`};return`${o}
|
|
430
449
|
import { type NextRequest, NextResponse } from "next/server";
|
|
431
450
|
|
|
432
451
|
export async function GET(req: NextRequest) {
|
|
@@ -437,7 +456,7 @@ export async function GET(req: NextRequest) {
|
|
|
437
456
|
return NextResponse.redirect(new URL("/login?error=no_code", req.url));
|
|
438
457
|
}
|
|
439
458
|
|
|
440
|
-
${
|
|
459
|
+
${n[e.id]}
|
|
441
460
|
|
|
442
461
|
// TODO: fetch user profile from ${e.name} using the access token.
|
|
443
462
|
// TODO: upsert the user into your primary auth provider (${t}).
|
|
@@ -447,7 +466,7 @@ ${r[e.id]}
|
|
|
447
466
|
void state;
|
|
448
467
|
return NextResponse.redirect(new URL("/dashboard", req.url));
|
|
449
468
|
}
|
|
450
|
-
`}function
|
|
469
|
+
`}function Sr(e){return`"use client";
|
|
451
470
|
|
|
452
471
|
/**
|
|
453
472
|
* SocialLoginButtons \u2014 generated by create-sailor.
|
|
@@ -467,7 +486,7 @@ interface SocialProvider {
|
|
|
467
486
|
}
|
|
468
487
|
|
|
469
488
|
const PROVIDERS: SocialProvider[] = [
|
|
470
|
-
${e.map(
|
|
489
|
+
${e.map(o=>` { id: ${JSON.stringify(o.id)}, name: ${JSON.stringify(o.name)}, href: ${JSON.stringify(`/api/auth/oauth/${o.id}`)} }`).join(`,
|
|
471
490
|
`)},
|
|
472
491
|
];
|
|
473
492
|
|
|
@@ -490,17 +509,23 @@ export function SocialLoginButtons() {
|
|
|
490
509
|
</div>
|
|
491
510
|
);
|
|
492
511
|
}
|
|
493
|
-
`}function
|
|
494
|
-
`+t):
|
|
512
|
+
`}function yn(e){ye.mkdirSync(e,{recursive:!0})}function Er(e,t){let o=fe.join(e,".env.example");ye.existsSync(o)?ye.appendFileSync(o,`
|
|
513
|
+
`+t):ye.writeFileSync(o,t)}function hr(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
495
514
|
`);return`${t}
|
|
496
|
-
${
|
|
497
|
-
`}async function
|
|
498
|
-
`)
|
|
515
|
+
${o}
|
|
516
|
+
`}async function Sn(e,t,o){if(!t||t.length===0)return;let n=fe.join(e,"apps","web");if(!ye.existsSync(n))return;let r=new Set,s=[];for(let d of t){if(r.has(d))continue;r.add(d);let u=gn(d);u&&s.push(u)}if(s.length===0)return;for(let d of s)Er(e,hr(d));let a=fe.join(n,"src","app","api","auth","callback");for(let d of s){let u=fe.join(a,d.id);yn(u);let S=fe.join(u,"route.ts");ye.writeFileSync(S,yr(d,o))}let c=fe.join(n,"src","components","auth");yn(c);let i=fe.join(c,"SocialLoginButtons.tsx");ye.writeFileSync(i,Sr(s))}import oe from"fs";import Dt from"path";var vt=[{id:"upstash-redis",name:"Upstash Redis",region:"both",envVars:["UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"],docs:"https://upstash.com/docs/redis",description:"Serverless Redis"},{id:"vercel-kv",name:"Vercel KV",region:"global",envVars:["KV_URL","KV_REST_API_URL","KV_REST_API_TOKEN","KV_REST_API_READ_ONLY_TOKEN"],docs:"https://vercel.com/docs/storage/vercel-kv",description:"Vercel native KV"},{id:"redis",name:"Redis (self-hosted)",region:"both",envVars:["REDIS_URL"],docs:"https://redis.io/docs/",description:"Self-hosted Redis"},{id:"dragonfly",name:"Dragonfly",region:"global",envVars:["DRAGONFLY_URL"],docs:"https://www.dragonflydb.io/docs",description:"Drop-in Redis replacement, faster"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip cache package"}];function En(e){return vt.find(t=>t.id===e)}var Ea=vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function hn(e){return oe.existsSync(e)?oe.readFileSync(e,"utf-8"):null}function vr(e,t){let o=Dt.join(e,".env.example"),n=hn(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
|
|
517
|
+
`);oe.appendFileSync(o,s)}function _r(e,t,o){let n=Dt.join(e,".env.example"),r=hn(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?oe.writeFileSync(n,r.replace(s,`${t}="${o}"`)):oe.appendFileSync(n,`${t}="${o}"
|
|
518
|
+
`)}async function vn(e,t,o){let n=Dt.join(e,"packages","cache");if(t==="none"){oe.existsSync(n)&&oe.rmSync(n,{recursive:!0,force:!0});return}let r=En(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${vt.map(s=>s.id).join(", ")}`);oe.existsSync(n)&&(vr(e,r),_r(e,"CACHE_PROVIDER",t))}var _t=[{id:"turnstile",name:"Cloudflare Turnstile",region:"global",envVars:["NEXT_PUBLIC_TURNSTILE_SITE_KEY","TURNSTILE_SECRET_KEY"],docs:"https://developers.cloudflare.com/turnstile/",description:"Free, privacy-focused captcha alternative"},{id:"hcaptcha",name:"hCaptcha",region:"global",envVars:["NEXT_PUBLIC_HCAPTCHA_SITE_KEY","HCAPTCHA_SECRET_KEY"],docs:"https://docs.hcaptcha.com/",description:"Privacy-respecting captcha"},{id:"aliyun-slide",name:"\u963F\u91CC\u4E91\u9A8C\u8BC1\u7801 2.0",region:"cn",envVars:["ALIYUN_CAPTCHA_ACCESS_KEY_ID","ALIYUN_CAPTCHA_ACCESS_KEY_SECRET","ALIYUN_CAPTCHA_APP_KEY","NEXT_PUBLIC_ALIYUN_CAPTCHA_APP_KEY"],docs:"https://help.aliyun.com/product/28308.html",description:"\u963F\u91CC\u4E91\u667A\u80FD\u9A8C\u8BC1 (\u6ED1\u5757/\u65E0\u75D5)"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function _n(e){return _t.find(t=>t.id===e)}var Ia=_t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import J from"fs";import Ft from"path";function G(e,t){let o=Ft.join(e,".env.example");if(!J.existsSync(o)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(J.readFileSync(o,"utf-8").includes(r))return;let c=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].filter(i=>i!==null).join(`
|
|
519
|
+
`);J.appendFileSync(o,c)}function H(e,t,o){let n=Ft.join(e,".env.example");if(!J.existsSync(n))return;let r=J.readFileSync(n,"utf-8"),s=`${t}="${o}"`,a=new RegExp(`^${t}=.*$`,"m");if(a.test(r)){J.writeFileSync(n,r.replace(a,s));return}let c=r.endsWith(`
|
|
520
|
+
`)?"":`
|
|
521
|
+
`;J.appendFileSync(n,`${c}${s}
|
|
522
|
+
`)}function B(e,t){let o=Ft.join(e,"packages",t);J.existsSync(o)&&J.rmSync(o,{recursive:!0,force:!0})}async function Pn(e,t,o="global"){let n=_n(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${_t.map(r=>r.id).join(", ")}`);if(n.id==="none"){B(e,"captcha");return}n.envVars.length>0&&G(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),H(e,"CAPTCHA_PROVIDER",n.id)}import bt from"fs";import Pr from"path";var Pt=[{id:"sanity",name:"Sanity",region:"global",envVars:["SANITY_PROJECT_ID","SANITY_DATASET","SANITY_API_TOKEN","SANITY_API_VERSION"],docs:"https://www.sanity.io/docs",description:"Structured content platform with Studio"},{id:"contentful",name:"Contentful",region:"global",envVars:["CONTENTFUL_SPACE_ID","CONTENTFUL_ACCESS_TOKEN","CONTENTFUL_PREVIEW_ACCESS_TOKEN"],docs:"https://www.contentful.com/developers/docs/",description:"Headless CMS"},{id:"strapi",name:"Strapi",region:"both",envVars:["STRAPI_URL","STRAPI_API_TOKEN"],docs:"https://docs.strapi.io",description:"Open-source self-hosted CMS"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function bn(e){return Pt.find(t=>t.id===e)}var Ta=Pt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function In(e,t,o="global"){let n=bn(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${Pt.map(s=>s.id).join(", ")}`);let r=Pr.join(e,"apps","studio");if(n.id==="none"){B(e,"sanity"),bt.existsSync(r)&&bt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(B(e,"sanity"),bt.existsSync(r)&&bt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&G(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),H(e,"CMS_PROVIDER",n.id)}import A from"fs";import I from"path";var br=I.join("apps","web"),jt=I.join("src","components","compliance"),ot=I.join("src","app","[locale]");function W(e){return I.join(e,br)}function Ir(e){A.mkdirSync(e,{recursive:!0})}function Y(e,t){Ir(I.dirname(e)),A.writeFileSync(e,t,"utf8")}function Vt(e,t){let o=I.join(e,".env.example");if(A.existsSync(o)){if(A.readFileSync(o,"utf8").includes(t.split(`
|
|
523
|
+
`)[0]??""))return;A.appendFileSync(o,`
|
|
499
524
|
`+t+`
|
|
500
|
-
`)}else
|
|
501
|
-
`)}var
|
|
525
|
+
`)}else A.writeFileSync(o,t+`
|
|
526
|
+
`)}var rt=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
|
|
502
527
|
> Consult a qualified lawyer in every jurisdiction you operate in before publishing.
|
|
503
|
-
> \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,
|
|
528
|
+
> \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,Cr=`import Link from "next/link";
|
|
504
529
|
import { IcpFooter } from "@/components/compliance/IcpFooter";
|
|
505
530
|
import { PublicSecurityFooter } from "@/components/compliance/PublicSecurityFooter";
|
|
506
531
|
|
|
@@ -551,7 +576,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
551
576
|
</footer>
|
|
552
577
|
);
|
|
553
578
|
}
|
|
554
|
-
`,
|
|
579
|
+
`,Ar=`export function IcpFooter() {
|
|
555
580
|
const icp = process.env.NEXT_PUBLIC_ICP_BEIAN;
|
|
556
581
|
if (!icp) return null;
|
|
557
582
|
return (
|
|
@@ -565,7 +590,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
565
590
|
</a>
|
|
566
591
|
);
|
|
567
592
|
}
|
|
568
|
-
`,
|
|
593
|
+
`,wr=`export function PublicSecurityFooter() {
|
|
569
594
|
const psb = process.env.NEXT_PUBLIC_PSB_BEIAN;
|
|
570
595
|
const psbCode = process.env.NEXT_PUBLIC_PSB_CODE;
|
|
571
596
|
if (!psb) return null;
|
|
@@ -582,7 +607,7 @@ export function Footer({ region = "global" }: FooterProps) {
|
|
|
582
607
|
</a>
|
|
583
608
|
);
|
|
584
609
|
}
|
|
585
|
-
`,
|
|
610
|
+
`,Rr=`"use client";
|
|
586
611
|
|
|
587
612
|
import { useCallback, useEffect, useState } from "react";
|
|
588
613
|
|
|
@@ -809,7 +834,7 @@ function CategoryRow({ id, title, description, checked, disabled, onChange }: Ca
|
|
|
809
834
|
</label>
|
|
810
835
|
);
|
|
811
836
|
}
|
|
812
|
-
`,
|
|
837
|
+
`,Nr=`interface AigcDisclaimerProps {
|
|
813
838
|
className?: string;
|
|
814
839
|
}
|
|
815
840
|
|
|
@@ -829,13 +854,13 @@ export function AigcDisclaimer({ className }: AigcDisclaimerProps) {
|
|
|
829
854
|
</div>
|
|
830
855
|
);
|
|
831
856
|
}
|
|
832
|
-
`,
|
|
857
|
+
`,xr=`---
|
|
833
858
|
title: Privacy Policy / \u9690\u79C1\u653F\u7B56
|
|
834
859
|
description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal information.
|
|
835
860
|
lastUpdated: 2026-01-01
|
|
836
861
|
---
|
|
837
862
|
|
|
838
|
-
${
|
|
863
|
+
${rt}
|
|
839
864
|
|
|
840
865
|
# Privacy Policy / \u9690\u79C1\u653F\u7B56
|
|
841
866
|
|
|
@@ -974,13 +999,13 @@ or in-app notification before the change takes effect.
|
|
|
974
999
|
**Data Controller / \u6570\u636E\u63A7\u5236\u8005:** {{COMPANY_NAME}}
|
|
975
1000
|
**Address / \u5730\u5740:** {{COMPANY_ADDRESS}}
|
|
976
1001
|
**Email / \u90AE\u7BB1:** {{COMPANY_CONTACT_EMAIL}}
|
|
977
|
-
`,
|
|
1002
|
+
`,kr=`---
|
|
978
1003
|
title: Terms of Service / \u670D\u52A1\u6761\u6B3E
|
|
979
1004
|
description: Terms governing your use of {{COMPANY_NAME}}.
|
|
980
1005
|
lastUpdated: 2026-01-01
|
|
981
1006
|
---
|
|
982
1007
|
|
|
983
|
-
${
|
|
1008
|
+
${rt}
|
|
984
1009
|
|
|
985
1010
|
# Terms of Service / \u670D\u52A1\u6761\u6B3E
|
|
986
1011
|
|
|
@@ -1093,13 +1118,13 @@ conflict-of-laws principles. Disputes shall be resolved in the competent courts
|
|
|
1093
1118
|
## 11. Contact / \u8054\u7CFB\u65B9\u5F0F
|
|
1094
1119
|
|
|
1095
1120
|
{{COMPANY_NAME}} \xB7 {{COMPANY_ADDRESS}} \xB7 {{COMPANY_CONTACT_EMAIL}}
|
|
1096
|
-
`,
|
|
1121
|
+
`,Tr=`---
|
|
1097
1122
|
title: AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
|
|
1098
1123
|
description: Disclosure required by \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300B
|
|
1099
1124
|
lastUpdated: 2026-01-01
|
|
1100
1125
|
---
|
|
1101
1126
|
|
|
1102
|
-
${
|
|
1127
|
+
${rt}
|
|
1103
1128
|
|
|
1104
1129
|
# AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
|
|
1105
1130
|
|
|
@@ -1175,13 +1200,13 @@ human professional.
|
|
|
1175
1200
|
|
|
1176
1201
|
AI \u8F93\u51FA\u53EF\u80FD\u4E0D\u51C6\u786E\u3001\u5B58\u5728\u504F\u89C1\u6216\u8FC7\u65F6\u3002**\u8BF7\u52FF**\u5728\u672A\u7ECF\u5408\u683C\u4E13\u4E1A\u4EBA\u58EB\u72EC\u7ACB\u6838\u5B9E\u7684\u60C5\u51B5\u4E0B\uFF0C\u5C06 AI \u8F93\u51FA
|
|
1177
1202
|
\u7528\u4E8E\u533B\u7597\u3001\u6CD5\u5F8B\u3001\u91D1\u878D\u6216\u5B89\u5168\u6538\u5173\u7684\u51B3\u7B56\u3002
|
|
1178
|
-
`,
|
|
1203
|
+
`,Or=`---
|
|
1179
1204
|
title: Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
|
|
1180
1205
|
description: Notice of cross-border transfer of personal information, per PIPL.
|
|
1181
1206
|
lastUpdated: 2026-01-01
|
|
1182
1207
|
---
|
|
1183
1208
|
|
|
1184
|
-
${
|
|
1209
|
+
${rt}
|
|
1185
1210
|
|
|
1186
1211
|
# Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
|
|
1187
1212
|
|
|
@@ -1240,13 +1265,13 @@ Refusal may limit your ability to use features that rely on overseas services.
|
|
|
1240
1265
|
- \u4F20\u8F93\u4E2D\u52A0\u5BC6 (TLS 1.2+) \u53CA\u9759\u6001\u52A0\u5BC6 (AES-256)\u3002
|
|
1241
1266
|
- \u5408\u540C\u6761\u6B3E\u8981\u6C42\u5883\u5916\u63A5\u6536\u65B9\u63D0\u4F9B\u7B49\u540C\u4E8E PIPL \u7684\u4FDD\u62A4\u3002
|
|
1242
1267
|
- \u8BBF\u95EE\u63A7\u5236\u3001\u5BA1\u8BA1\u65E5\u5FD7\u548C\u8FDD\u89C4\u901A\u77E5\u7A0B\u5E8F\u3002
|
|
1243
|
-
`,
|
|
1268
|
+
`,Ur=`---
|
|
1244
1269
|
title: Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
|
|
1245
1270
|
description: Itemized list of personal information collected, per PIPL Article 17.
|
|
1246
1271
|
lastUpdated: 2026-01-01
|
|
1247
1272
|
---
|
|
1248
1273
|
|
|
1249
|
-
${
|
|
1274
|
+
${rt}
|
|
1250
1275
|
|
|
1251
1276
|
# Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
|
|
1252
1277
|
|
|
@@ -1282,19 +1307,19 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
|
|
|
1282
1307
|
**{{COMPANY_CONTACT_EMAIL}}**.
|
|
1283
1308
|
|
|
1284
1309
|
\u5982\u9700\u884C\u4F7F\u60A8\u7684\u6743\u5229\uFF08\u8BBF\u95EE\u3001\u66F4\u6B63\u3001\u5220\u9664\u3001\u5BFC\u51FA\u3001\u64A4\u56DE\u540C\u610F\uFF09\uFF0C\u8BF7\u8054\u7CFB **{{COMPANY_CONTACT_EMAIL}}**\u3002
|
|
1285
|
-
`;async function
|
|
1286
|
-
`))}async function
|
|
1287
|
-
`))}async function
|
|
1288
|
-
`))}async function
|
|
1289
|
-
`))}async function
|
|
1290
|
-
`)}import
|
|
1291
|
-
`+t):
|
|
1310
|
+
`;async function Lr(e,t){let o=W(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","Footer.tsx");Y(n,Cr);let r=I.join(o,"src","components","compliance","README.md");Y(r,["# Compliance Components","",`Auto-generated by \`create-sailor\` for region: \`${t}\`.`,"","## Mounting the Footer","","```tsx",'import { Footer } from "@/components/compliance/Footer";','import { CookieBanner } from "@/components/compliance/CookieBanner";',"","export default function RootLayout({ children }) {"," return ("," <html>"," <body>"," {children}",` <Footer region="${t}" />`," <CookieBanner />"," </body>"," </html>"," );","}","```","","## Placeholders","","Policy MDX files contain `{{COMPANY_NAME}}`, `{{COMPANY_ADDRESS}}`,","`{{COMPANY_CONTACT_EMAIL}}`, `{{GOVERNING_JURISDICTION}}`, and","`{{AIGC_ALGORITHM_FILING_NUMBER}}`. These are filled by the `brand-apply` step.",""].join(`
|
|
1311
|
+
`))}async function Mr(e,t){let o=W(e);if(!A.existsSync(o))return;let n=I.join(o,"src","components","compliance","CookieBanner.tsx");Y(n,Rr)}async function Dr(e,t){let o=W(e);if(!A.existsSync(o))return;let n=I.join(o,ot,"privacy","page.mdx");Y(n,xr)}async function Fr(e,t){let o=W(e);if(!A.existsSync(o))return;let n=I.join(o,ot,"terms","page.mdx");Y(n,kr)}async function jr(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,jt,"IcpFooter.tsx");Y(o,Ar),Vt(e,["# Chinese ICP filing (\u5DE5\u4FE1\u90E8 ICP \u5907\u6848) \u2014 required to legally host a","# public-facing site from mainland China. Apply at https://beian.miit.gov.cn/",'NEXT_PUBLIC_ICP_BEIAN="" # \u5982 \u82CFICP\u59072024XXXXXX\u53F7'].join(`
|
|
1312
|
+
`))}async function Vr(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,jt,"PublicSecurityFooter.tsx");Y(o,wr),Vt(e,["# Chinese Public Security Bureau filing (\u516C\u5B89\u8054\u7F51\u5907\u6848)","# Required in addition to ICP. Apply at http://www.beian.gov.cn/",'NEXT_PUBLIC_PSB_BEIAN="" # \u5982 \u82CF\u516C\u7F51\u5B89\u5907 32011402XXXXXX\u53F7','NEXT_PUBLIC_PSB_CODE="" # 14-digit record code'].join(`
|
|
1313
|
+
`))}async function Kr(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,jt,"AigcDisclaimer.tsx");Y(o,Nr),Vt(e,["# Generative AI algorithm filing (\u7B97\u6CD5\u5907\u6848\u53F7) \u2014 required by","# \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300Bfor services offered in China.",'NEXT_PUBLIC_AIGC_FILING_NUMBER="" # e.g. \u7F51\u4FE1\u7B97\u5907XXXXXXXX\u53F7'].join(`
|
|
1314
|
+
`))}async function Br(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"aigc-disclosure","page.mdx");Y(o,Tr)}async function Yr(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"cross-border-data","page.mdx");Y(o,Or)}async function $r(e){let t=W(e);if(!A.existsSync(t))return;let o=I.join(t,ot,"pii-collection","page.mdx");Y(o,Ur)}async function Cn(e,t){try{await Lr(e,t),await Mr(e,t),await Dr(e,t),await Fr(e,t),(t==="cn"||t==="hybrid")&&(await jr(e),await Vr(e),await Kr(e),await Br(e),await Yr(e),await $r(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 qr from"fs";import Gr from"path";async function An(e,t){let o=Gr.join(e,"nebutra.config.json");qr.writeFileSync(o,JSON.stringify(t,null,2)+`
|
|
1315
|
+
`)}import re from"fs";import Kt from"path";function Hr(e){re.existsSync(e)&&re.rmSync(e,{recursive:!0,force:!0})}function wn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function Wr(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function Rn(e){let t=e.replace(/^\s*extensions\s*=\s*\[[^\]]*\]\s*\n/gm,"");return t=t.replace(/previewFeatures\s*=\s*\[\s*"postgresqlExtensions"\s*\]\s*\n/g,""),t}function Xr(e,t){let o=Kt.join(e,".env.example");re.existsSync(o)?re.appendFileSync(o,`
|
|
1316
|
+
`+t):re.writeFileSync(o,t)}async function Nn(e,t,o){let n=Kt.join(e,"packages","db");if(t==="none"){Hr(n);return}let r=Kt.join(n,"prisma","schema.prisma"),s;if(t==="postgresql"?s=`postgresql://postgres:postgres@localhost:5432/${o}`:t==="mysql"?s=`mysql://root:root@localhost:3306/${o}`:s="file:./dev.db",Xr(e,`# Database (${t})
|
|
1292
1317
|
DATABASE_URL="${s}"
|
|
1293
|
-
`),!
|
|
1294
|
-
`+t):
|
|
1318
|
+
`),!re.existsSync(r))return;let a=re.readFileSync(r,"utf8"),c=a;t==="mysql"?(c=wn(c,"mysql"),c=Rn(c)):t==="sqlite"&&(c=wn(c,"sqlite"),c=Wr(c),c=Rn(c)),c!==a&&re.writeFileSync(r,c)}import st from"fs";import D from"path";import{fileURLToPath as zr}from"url";var Qr=zr(import.meta.url),Jr=D.dirname(Qr);async function xn(e,t){if(t==="none")return;let o=D.join(Jr,"../../templates/deploy");t==="vercel"?await st.promises.copyFile(D.join(o,"vercel.json"),D.join(e,"vercel.json")):t==="railway"?await st.promises.copyFile(D.join(o,"railway.toml"),D.join(e,"railway.toml")):t==="cloudflare"?await st.promises.copyFile(D.join(o,"wrangler.toml"),D.join(e,"wrangler.toml")):t==="selfhost"&&(await st.promises.copyFile(D.join(o,"docker-compose.yml"),D.join(e,"docker-compose.yml")),await st.promises.copyFile(D.join(o,"Dockerfile.web"),D.join(e,"Dockerfile.web")))}import se from"fs";import Se from"path";import{fileURLToPath as Zr}from"url";var es=Zr(import.meta.url),kn=Se.dirname(es),ts=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml)$/;function ns(e){let t=[Se.join(kn,"..","templates","docs",e),Se.join(kn,"..","..","templates","docs",e)];for(let o of t)if(se.existsSync(o))return o;return t[0]}async function Tn(e,t){if(t.framework==="none")return;let o=(t.framework==="fumadocs","fumadocs"),n=ns(o),r=Se.join(e,"apps","docs");if(!se.existsSync(n))throw new Error(`Docs template not found: ${n}`);On(n,r),Un(r,{"{PRODUCT_NAME}":t.projectName})}function On(e,t){se.mkdirSync(t,{recursive:!0});for(let o of se.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name),r=Se.join(t,o.name);o.isDirectory()?On(n,r):se.copyFileSync(n,r)}}function Un(e,t){for(let o of se.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name);if(o.isDirectory())Un(n,t);else if(ts.test(o.name)){let r=se.readFileSync(n,"utf-8");for(let[s,a]of Object.entries(t))r=r.split(s).join(a);se.writeFileSync(n,r)}}}import he from"fs";import Ee from"path";var It=[{id:"resend",name:"Resend",region:"global",envVars:["RESEND_API_KEY","RESEND_FROM"],docs:"https://resend.com/docs",pkg:"resend",pkgVersion:"^4.0.1"},{id:"postmark",name:"Postmark",region:"global",envVars:["POSTMARK_API_KEY","POSTMARK_FROM"],docs:"https://postmarkapp.com/developer",pkg:"postmark",pkgVersion:"^4.0.5"},{id:"ses",name:"AWS SES",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_SES_REGION","SES_FROM"],docs:"https://docs.aws.amazon.com/ses",pkg:"@aws-sdk/client-sesv2",pkgVersion:"^3.658.0"},{id:"aliyun-dm",name:"\u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001",region:"cn",envVars:["ALIYUN_DM_ACCESS_KEY","ALIYUN_DM_ACCESS_SECRET","ALIYUN_DM_ACCOUNT_NAME","ALIYUN_DM_FROM_ALIAS"],docs:"https://help.aliyun.com/product/29412.html",pkg:"@alicloud/dm20151123",pkgVersion:"^3.0.0"},{id:"tencent-ses",name:"\u817E\u8BAF\u4E91 SES",region:"cn",envVars:["TENCENT_SECRET_ID","TENCENT_SECRET_KEY","TENCENT_SES_FROM_EMAIL"],docs:"https://cloud.tencent.com/document/product/1288",pkg:"tencentcloud-sdk-nodejs-ses",pkgVersion:"^4.0.900"},{id:"netease",name:"\u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1",region:"cn",envVars:["NETEASE_USER","NETEASE_PASS","NETEASE_FROM"],docs:"https://qiye.163.com/help",pkg:"nodemailer",pkgVersion:"^6.9.15"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function Ln(e){return It.find(t=>t.id===e)}var nc=It.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var ve="@nebutra/email";function Bt(e,t){he.mkdirSync(Ee.dirname(e),{recursive:!0}),he.writeFileSync(e,t)}function os(e,t){let o=Ee.join(e,".env.example");he.existsSync(o)?he.appendFileSync(o,`
|
|
1319
|
+
`+t):he.writeFileSync(o,t)}function rs(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
1295
1320
|
`);return`${t}
|
|
1296
|
-
${
|
|
1297
|
-
`}var
|
|
1321
|
+
${o}
|
|
1322
|
+
`}var ss=`/**
|
|
1298
1323
|
* Public inputs accepted by the \`sendEmail\` wrapper.
|
|
1299
1324
|
* Keep the surface minimal \u2014 individual providers may accept more, but
|
|
1300
1325
|
* consumers should code against this shape for portability.
|
|
@@ -1314,8 +1339,8 @@ export interface SendEmailResult {
|
|
|
1314
1339
|
/** Raw provider response \u2014 useful for debugging, not a stable contract. */
|
|
1315
1340
|
raw?: unknown;
|
|
1316
1341
|
}
|
|
1317
|
-
`;function
|
|
1318
|
-
* @${
|
|
1342
|
+
`;function is(){return`/**
|
|
1343
|
+
* @${ve.slice(1)} \u2014 Resend transactional email wrapper.
|
|
1319
1344
|
*
|
|
1320
1345
|
* Docs: https://resend.com/docs
|
|
1321
1346
|
*/
|
|
@@ -1353,8 +1378,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1353
1378
|
}
|
|
1354
1379
|
|
|
1355
1380
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1356
|
-
`}function
|
|
1357
|
-
* @${
|
|
1381
|
+
`}function as(){return`/**
|
|
1382
|
+
* @${ve.slice(1)} \u2014 Postmark transactional email wrapper.
|
|
1358
1383
|
*
|
|
1359
1384
|
* Docs: https://postmarkapp.com/developer
|
|
1360
1385
|
*/
|
|
@@ -1391,8 +1416,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1391
1416
|
}
|
|
1392
1417
|
|
|
1393
1418
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1394
|
-
`}function
|
|
1395
|
-
* @${
|
|
1419
|
+
`}function cs(){return`/**
|
|
1420
|
+
* @${ve.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
|
|
1396
1421
|
*
|
|
1397
1422
|
* Docs: https://docs.aws.amazon.com/ses
|
|
1398
1423
|
*/
|
|
@@ -1447,8 +1472,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1447
1472
|
}
|
|
1448
1473
|
|
|
1449
1474
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1450
|
-
`}function
|
|
1451
|
-
* @${
|
|
1475
|
+
`}function ps(){return`/**
|
|
1476
|
+
* @${ve.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
|
|
1452
1477
|
*
|
|
1453
1478
|
* Docs: https://help.aliyun.com/product/29412.html
|
|
1454
1479
|
*/
|
|
@@ -1497,8 +1522,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1497
1522
|
}
|
|
1498
1523
|
|
|
1499
1524
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1500
|
-
`}function
|
|
1501
|
-
* @${
|
|
1525
|
+
`}function ls(){return`/**
|
|
1526
|
+
* @${ve.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
|
|
1502
1527
|
*
|
|
1503
1528
|
* Docs: https://cloud.tencent.com/document/product/1288
|
|
1504
1529
|
*/
|
|
@@ -1545,8 +1570,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1545
1570
|
}
|
|
1546
1571
|
|
|
1547
1572
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1548
|
-
`}function
|
|
1549
|
-
* @${
|
|
1573
|
+
`}function ds(){return`/**
|
|
1574
|
+
* @${ve.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
|
|
1550
1575
|
*
|
|
1551
1576
|
* Docs: https://qiye.163.com/help
|
|
1552
1577
|
*/
|
|
@@ -1583,21 +1608,23 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
|
|
|
1583
1608
|
}
|
|
1584
1609
|
|
|
1585
1610
|
export type { SendEmailInput, SendEmailResult } from "./types.js";
|
|
1586
|
-
`}function
|
|
1587
|
-
`}}function
|
|
1588
|
-
`}async function
|
|
1611
|
+
`}function us(e){switch(e){case"resend":return is();case"postmark":return as();case"ses":return cs();case"aliyun-dm":return ps();case"tencent-ses":return ls();case"netease":return ds();case"none":return`export {};
|
|
1612
|
+
`}}function ms(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),e.id==="aliyun-dm"&&(t["@alicloud/openapi-client"]="^0.4.12");let o={name:ve,version:"0.1.0",private:!0,description:`Transactional email via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
|
|
1613
|
+
`}async function Mn(e,t,o){if(t==="none")return;let n=Ln(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${It.map(a=>a.id).join(", ")}`);let r=Ee.join(e,"packages","email"),s=Ee.join(r,"src");he.existsSync(s)&&he.rmSync(s,{recursive:!0,force:!0}),Bt(Ee.join(r,"package.json"),ms(n)),Bt(Ee.join(s,"types.ts"),ss),Bt(Ee.join(s,"index.ts"),us(n.id)),os(e,rs(n))}import Ct from"fs";import Dn from"path";async function Fn(e,t){let o=`# Automatically injected by create-sailor
|
|
1589
1614
|
DATABASE_URL="${String(t.databaseUrl)}"
|
|
1590
1615
|
|
|
1591
1616
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
|
|
1592
1617
|
CLERK_SECRET_KEY="${String(t.clerkSecret)}"
|
|
1593
1618
|
|
|
1594
1619
|
NEXT_PUBLIC_SITE_URL="http://localhost:3000"
|
|
1595
|
-
`,
|
|
1596
|
-
`+n)}import{
|
|
1620
|
+
`,n=Dn.join(e,".env"),r=Dn.join(e,".env.local");!Ct.existsSync(n)&&!Ct.existsSync(r)?Ct.writeFileSync(r,o):Ct.appendFileSync(r,`
|
|
1621
|
+
`+o)}import Vn from"crypto";import it from"fs";import jn from"path";function _e(e){return Vn.randomBytes(e).toString("base64").replace(/=+$/,"")}function gs(e){return Vn.randomBytes(e).toString("hex")}function fs(){return{AUTH_SECRET:_e(32),NEXTAUTH_SECRET:_e(32),BETTER_AUTH_SECRET:_e(32),JWT_SECRET:_e(32),WEBHOOK_SECRET:gs(16),ENCRYPTION_KEY:_e(32),API_SECRET_KEY:_e(32),SESSION_SECRET:_e(32)}}function ys(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Ss(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=ys(o);return e.replace(n,`${t}="${r}"`)}async function Kn(e){let t=jn.join(e,".env.example"),o=jn.join(e,".env.local");if(!it.existsSync(t))return null;try{let n=it.readFileSync(t,"utf8"),r=fs(),a=it.existsSync(o)?it.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))a=Ss(a,c,r[c]);return it.writeFileSync(o,a),r}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate env secrets: ${r}`),new Error(`Unable to write .env.local: ${r}`)}}var At=[{id:"vercel-flags",name:"Vercel Flags SDK",region:"global",envVars:["FLAGS_SECRET"],docs:"https://vercel.com/docs/workflow-collaboration/feature-flags",description:"Native Vercel feature flags"},{id:"growthbook",name:"GrowthBook",region:"both",envVars:["GROWTHBOOK_API_HOST","GROWTHBOOK_CLIENT_KEY","GROWTHBOOK_DECRYPTION_KEY"],docs:"https://docs.growthbook.io",description:"Open-source A/B testing + flags"},{id:"configcat",name:"ConfigCat",region:"global",envVars:["CONFIGCAT_SDK_KEY"],docs:"https://configcat.com/docs/",description:"Feature flag & config management"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Bn(e){return At.find(t=>t.id===e)}var fc=At.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Yn(e,t,o="global"){let n=Bn(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${At.map(r=>r.id).join(", ")}`);if(n.id==="none"){B(e,"feature-flags");return}n.envVars.length>0&&G(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),H(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{execFileSync as Es}from"child_process";import x from"fs";import hs from"os";import ie from"path";import vs from"ignore";var _s={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 Ps(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function bs(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function Is(e){return/^[0-9a-f]{7,40}$/i.test(e)}async function Cs(e,t){if(Is(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)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 Gn(e,t,o){let n=x.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let s=ie.join(t,r.name),a=ie.relative(e,s).split(ie.sep).join("/");r.isDirectory()?(o.push(a+"/"),Gn(e,s,o)):o.push(a)}}function As(e){let t=ie.join(e,".templateignore");if(!x.existsSync(t))return;let o=x.readFileSync(t,"utf8"),n=vs().add(o),r=[];Gn(e,e,r);let s=r.map(i=>i.endsWith("/")?i.slice(0,-1):i),a=new Set(n.filter(s)),c=s.filter(i=>!a.has(i)).sort((i,d)=>d.split("/").length-i.split("/").length);for(let i of c){let d=ie.join(e,i);try{x.existsSync(d)&&x.rmSync(d,{recursive:!0,force:!0})}catch{}}try{x.existsSync(t)&&x.rmSync(t,{force:!0})}catch{}}async function $n(e,t){let o=await fetch(e,{headers:{Accept:"application/octet-stream","User-Agent":"create-sailor"}});if(!o.ok)throw new Error(`Failed to download archive (${o.status})`);let n=Buffer.from(await o.arrayBuffer());if(n.byteLength<1024)throw new Error(`Downloaded archive is unexpectedly small (${n.byteLength} bytes)`);x.writeFileSync(t,n);let r=x.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function qn(e,t){Es("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function Hn(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 ws(e,t){let o=x.mkdtempSync(ie.join(hs.tmpdir(),"create-sailor-")),n=ie.join(o,"template.tar.gz");try{let r=await Cs(e.repo,e.ref);await $n(bs(e.repo,r),n),qn(n,t)}catch(r){if(!e.allowMutableFallback)throw r;Hn(t),await $n(Ps(e.repo,e.ref),n),qn(n,t)}finally{x.rmSync(o,{recursive:!0,force:!0})}}async function Wn(e){x.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let s=_s[r];try{if(await ws(s,e),s.applyIgnore)try{As(e)}catch(a){throw new Error(`Template cloned, but .templateignore processing failed: ${a instanceof Error?a.message:String(a)}`)}return}catch(a){n=a instanceof Error?a:new Error(String(a)),Hn(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
|
|
1597
1622
|
|
|
1598
|
-
Ensure you have internet access and
|
|
1599
|
-
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import
|
|
1600
|
-
|
|
1623
|
+
Ensure you have internet access and 'tar' installed.
|
|
1624
|
+
You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import Pe from"fs";import Yt from"path";async function Xn(e,t){let o=Yt.join(e,"packages","mcp");if(t==="off"){Pe.existsSync(o)&&Pe.rmSync(o,{recursive:!0,force:!0});let r=Yt.join(e,"packages","cli","src","commands","mcp-server.ts");Pe.existsSync(r)&&Pe.rmSync(r,{force:!0});return}let n=Yt.join(e,".env.example");if(Pe.existsSync(n)){let r=Pe.readFileSync(n,"utf-8"),s="# MCP Server (Agent-friendly API)";if(!r.includes(s)){let a=["","# =============================================",s,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
|
|
1625
|
+
`);Pe.appendFileSync(n,a)}}}import at from"fs";import zn from"path";async function Qn(e,t,o){let n=zn.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){at.existsSync(n)&&at.rmSync(n,{recursive:!0,force:!0});return}let s=zn.join(e,".env.example");if(!at.existsSync(s))return;let a=at.readFileSync(s,"utf-8"),c="# Metering (usage-based billing)";if(!a.includes(c)){let i=["","# =============================================",c,"# Docs: see packages/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
|
|
1626
|
+
`);at.appendFileSync(s,i)}}import He from"fs";import O from"path";var Jn=[{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:""}],Tc=Jn.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Zn(e){return Jn.find(t=>t.id===e)}function Rs(e){He.mkdirSync(e,{recursive:!0})}function X(e,t){Rs(O.dirname(e)),He.writeFileSync(e,t)}function ct(e,t){let o=O.join(e,".env.example");He.existsSync(o)?He.appendFileSync(o,`
|
|
1627
|
+
`+t):He.writeFileSync(o,t)}function Ns(e){let t=`import * as Sentry from "@sentry/nextjs";
|
|
1601
1628
|
|
|
1602
1629
|
Sentry.init({
|
|
1603
1630
|
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
@@ -1612,21 +1639,21 @@ Sentry.init({
|
|
|
1612
1639
|
],
|
|
1613
1640
|
environment: process.env.NODE_ENV,
|
|
1614
1641
|
});
|
|
1615
|
-
`,
|
|
1642
|
+
`,o=`import * as Sentry from "@sentry/nextjs";
|
|
1616
1643
|
|
|
1617
1644
|
Sentry.init({
|
|
1618
1645
|
dsn: process.env.SENTRY_DSN ?? process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
1619
1646
|
tracesSampleRate: 1.0,
|
|
1620
1647
|
environment: process.env.NODE_ENV,
|
|
1621
1648
|
});
|
|
1622
|
-
`,
|
|
1649
|
+
`,n=`import * as Sentry from "@sentry/nextjs";
|
|
1623
1650
|
|
|
1624
1651
|
Sentry.init({
|
|
1625
1652
|
dsn: process.env.SENTRY_DSN ?? process.env.NEXT_PUBLIC_SENTRY_DSN,
|
|
1626
1653
|
tracesSampleRate: 1.0,
|
|
1627
1654
|
environment: process.env.NODE_ENV,
|
|
1628
1655
|
});
|
|
1629
|
-
`,
|
|
1656
|
+
`,r=`/**
|
|
1630
1657
|
* Next.js instrumentation hook \u2014 wires Sentry into Node and Edge runtimes.
|
|
1631
1658
|
* See https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation
|
|
1632
1659
|
*/
|
|
@@ -1640,14 +1667,14 @@ export async function register() {
|
|
|
1640
1667
|
}
|
|
1641
1668
|
|
|
1642
1669
|
export { captureRequestError as onRequestError } from "@sentry/nextjs";
|
|
1643
|
-
`;
|
|
1670
|
+
`;X(O.join(e,"sentry.client.config.ts"),t),X(O.join(e,"sentry.server.config.ts"),o),X(O.join(e,"sentry.edge.config.ts"),n),X(O.join(e,"instrumentation.ts"),r)}function xs(){return`# Sentry \u2014 error tracking + performance monitoring
|
|
1644
1671
|
# Get your DSN from https://sentry.io/settings/projects/<project>/keys/
|
|
1645
1672
|
SENTRY_DSN=
|
|
1646
1673
|
NEXT_PUBLIC_SENTRY_DSN=
|
|
1647
1674
|
SENTRY_ORG=
|
|
1648
1675
|
SENTRY_PROJECT=
|
|
1649
1676
|
SENTRY_AUTH_TOKEN=
|
|
1650
|
-
`}function
|
|
1677
|
+
`}function ks(e){let t=`/**
|
|
1651
1678
|
* Next.js instrumentation hook \u2014 wires Datadog APM (dd-trace) into Node runtime.
|
|
1652
1679
|
* Edge runtime is not supported by dd-trace; only nodejs is initialized.
|
|
1653
1680
|
*/
|
|
@@ -1664,7 +1691,7 @@ export async function register() {
|
|
|
1664
1691
|
});
|
|
1665
1692
|
}
|
|
1666
1693
|
}
|
|
1667
|
-
`,
|
|
1694
|
+
`,o=`"use client";
|
|
1668
1695
|
/**
|
|
1669
1696
|
* Datadog RUM (Real User Monitoring) \u2014 browser-side tracking.
|
|
1670
1697
|
* Initialize once in your root layout via <DatadogRumProvider />.
|
|
@@ -1695,7 +1722,7 @@ export function initDatadogRum(): void {
|
|
|
1695
1722
|
});
|
|
1696
1723
|
initialized = true;
|
|
1697
1724
|
}
|
|
1698
|
-
`;
|
|
1725
|
+
`;X(O.join(e,"instrumentation.ts"),t),X(O.join(e,"src","lib","monitoring","datadog-rum.ts"),o)}function Ts(){return`# Datadog \u2014 APM + RUM
|
|
1699
1726
|
# Server APM (dd-trace)
|
|
1700
1727
|
DD_API_KEY=
|
|
1701
1728
|
DD_APP_KEY=
|
|
@@ -1710,7 +1737,7 @@ NEXT_PUBLIC_DD_SITE=datadoghq.com
|
|
|
1710
1737
|
NEXT_PUBLIC_DD_SERVICE=sailor-web
|
|
1711
1738
|
NEXT_PUBLIC_DD_ENV=production
|
|
1712
1739
|
NEXT_PUBLIC_DD_VERSION=
|
|
1713
|
-
`}function
|
|
1740
|
+
`}function Os(e){let t=`/**
|
|
1714
1741
|
* Bugsnag server-side initialization.
|
|
1715
1742
|
* Import this once at the top of your server entrypoint or a shared init module.
|
|
1716
1743
|
*/
|
|
@@ -1730,7 +1757,7 @@ export function startBugsnagServer(): void {
|
|
|
1730
1757
|
});
|
|
1731
1758
|
started = true;
|
|
1732
1759
|
}
|
|
1733
|
-
`,
|
|
1760
|
+
`,o=`"use client";
|
|
1734
1761
|
/**
|
|
1735
1762
|
* Bugsnag browser initialization \u2014 wrap your app root with the returned provider.
|
|
1736
1763
|
*/
|
|
@@ -1759,11 +1786,11 @@ export function getBugsnagErrorBoundary() {
|
|
|
1759
1786
|
errorBoundary = plugin.createErrorBoundary(React) as typeof errorBoundary;
|
|
1760
1787
|
return errorBoundary;
|
|
1761
1788
|
}
|
|
1762
|
-
`;
|
|
1789
|
+
`;X(O.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),X(O.join(e,"src","lib","monitoring","bugsnag.client.tsx"),o)}function Us(){return`# Bugsnag \u2014 error tracking
|
|
1763
1790
|
BUGSNAG_API_KEY=
|
|
1764
1791
|
NEXT_PUBLIC_BUGSNAG_API_KEY=
|
|
1765
1792
|
APP_VERSION=
|
|
1766
|
-
`}function
|
|
1793
|
+
`}function Ls(e){X(O.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
|
|
1767
1794
|
/**
|
|
1768
1795
|
* \u963F\u91CC\u4E91 ARMS (Application Real-time Monitoring Service) browser agent.
|
|
1769
1796
|
* Injects the official JS agent via next/script.
|
|
@@ -1784,11 +1811,11 @@ export function ArmsScript() {
|
|
|
1784
1811
|
/>
|
|
1785
1812
|
);
|
|
1786
1813
|
}
|
|
1787
|
-
`)}function
|
|
1814
|
+
`)}function Ms(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
|
|
1788
1815
|
ALIYUN_ARMS_LICENSE_KEY=
|
|
1789
1816
|
ALIYUN_ARMS_APP_NAME=
|
|
1790
1817
|
NEXT_PUBLIC_ARMS_PID=
|
|
1791
|
-
`}function
|
|
1818
|
+
`}function Ds(e){X(O.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
|
|
1792
1819
|
/**
|
|
1793
1820
|
* \u542C\u4E91 Browser Agent (\u524D\u7AEF\u6027\u80FD\u76D1\u63A7).
|
|
1794
1821
|
* Docs: https://www.tingyun.com/docs
|
|
@@ -1806,12 +1833,12 @@ export function TingYunScript() {
|
|
|
1806
1833
|
/>
|
|
1807
1834
|
);
|
|
1808
1835
|
}
|
|
1809
|
-
`)}function
|
|
1836
|
+
`)}function Fs(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
|
|
1810
1837
|
TINGYUN_LICENSE_KEY=
|
|
1811
1838
|
NEXT_PUBLIC_TINGYUN_APP_KEY=
|
|
1812
|
-
`}async function
|
|
1813
|
-
`)}}import
|
|
1814
|
-
`+t):
|
|
1839
|
+
`}async function eo(e,t,o="global"){let n=Zn(t);if(!n||n.id==="none")return;let r=O.join(e,"apps","web");if(!He.existsSync(r))return;let s=n.id;try{switch(s){case"sentry":Ns(r),ct(e,xs());return;case"datadog":ks(r),ct(e,Ts());return;case"bugsnag":Os(r),ct(e,Us());return;case"aliyun-arms":Ls(r),ct(e,Ms());return;case"tingyun":Ds(r),ct(e,Fs());return;default:return}}catch(a){throw console.error(`Failed to apply monitoring selection "${t}":`,a),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var wt=[{id:"novu",name:"Novu",region:"both",envVars:["NOVU_API_KEY","NOVU_APPLICATION_IDENTIFIER"],docs:"https://docs.novu.co",description:"Multi-channel notification infrastructure"},{id:"knock",name:"Knock",region:"global",envVars:["KNOCK_API_KEY","KNOCK_SIGNING_KEY","KNOCK_PUBLIC_API_KEY"],docs:"https://docs.knock.app",description:"Product notifications platform"},{id:"custom",name:"Custom (direct dispatchers)",region:"both",envVars:[],docs:"",description:"Use email + sms + push directly"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function to(e){return wt.find(t=>t.id===e)}var Fc=wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function no(e,t,o="global"){let n=to(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${wt.map(r=>r.id).join(", ")}`);if(n.id==="none"){B(e,"notifications");return}n.envVars.length>0&&G(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),H(e,"NOTIFICATIONS_PROVIDER",n.id)}import $t from"fs";import js from"path";async function oo(e,t){let o=js.join(e,"package.json");if($t.existsSync(o)){let n=$t.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",$t.writeFileSync(o,JSON.stringify(r,null,2)+`
|
|
1840
|
+
`)}}import Z from"fs";import pt from"path";var Vs=["stripe","lemonsqueezy","chinapay","polar"];function ro(e){Z.existsSync(e)&&Z.rmSync(e,{recursive:!0,force:!0})}function Ks(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Bs(e,t){let o=pt.join(e,".env.example");Z.existsSync(o)?Z.appendFileSync(o,`
|
|
1841
|
+
`+t):Z.writeFileSync(o,t)}function Ys(e){switch(e){case"stripe":return`# Stripe
|
|
1815
1842
|
STRIPE_SECRET_KEY=
|
|
1816
1843
|
STRIPE_WEBHOOK_SECRET=
|
|
1817
1844
|
`;case"lemon":return`# Lemon Squeezy
|
|
@@ -1826,14 +1853,14 @@ CHINAPAY_WECHAT_ENABLED=true
|
|
|
1826
1853
|
CHINAPAY_APP_ID=
|
|
1827
1854
|
CHINAPAY_APP_SECRET=
|
|
1828
1855
|
CHINAPAY_ALIPAY_ENABLED=true
|
|
1829
|
-
`}}async function
|
|
1830
|
-
`),
|
|
1831
|
-
`),t)}function
|
|
1832
|
-
`).filter(d=>{let
|
|
1833
|
-
`);return e.replace(s,`createProviderRegistry({${i}})`)}function
|
|
1834
|
-
`+
|
|
1835
|
-
`)}}import
|
|
1836
|
-
`)}let c=
|
|
1856
|
+
`}}async function so(e,t){let o=pt.join(e,"packages","billing");if(!Z.existsSync(o))return;if(t==="none"){ro(o);return}let n=pt.join(o,"src"),r=new Set(Ks(t));for(let a of Vs)r.has(a)||ro(pt.join(n,a));let s=pt.join(n,"checkout","types.ts");if(Z.existsSync(s)){let a=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=Z.readFileSync(s,"utf8"),i=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${a}";`);i!==c&&Z.writeFileSync(s,i)}Bs(e,Ys(t))}import ae from"fs";import We from"path";var co=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),qt=/@sailor:([^\s*]+)/;function $s(e,t){let{providerIds:o,customEndpoint:n}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:o.includes(r)}}if(e==="cn-compatible"){let r=o.some(s=>co.has(s));return{marker:e,keep:r||!!n}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:o.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!n}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function io(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function ao(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function po(e,t){let o=e.split(`
|
|
1857
|
+
`),n=[],r=e.includes("#"),s=0;for(;s<o.length;){let a=o[s],c=a.match(qt);if(!c){n.push(a),s++;continue}let{marker:i,keep:d}=$s(c[1],t);if(i==="registry-entries"){n.push(r?ao(a):io(a)),s++;continue}if(d){let u=r?ao(a):io(a);u.trim().length>0&&n.push(u);let S=s+1;for(;S<o.length&&o[S].trim()!==""&&!qt.test(o[S]);)n.push(o[S]),S++;S<o.length&&o[S].trim()===""&&(n.push(o[S]),S++),s=S}else{let u=s+1;for(;u<o.length&&o[u].trim()!==""&&!qt.test(o[u]);)u++;u<o.length&&o[u].trim()===""&&u++,s=u}}return qs(n.join(`
|
|
1858
|
+
`),t)}function qs(e,t){let{providerIds:o,customEndpoint:n}=t,r=new Set;for(let d of o)["openai","anthropic","google","mistral","xai"].includes(d)&&r.add(d),r.add(d.replace(/-/g,"_")),r.add(d);n&&r.add("custom");let s=/createProviderRegistry\(\{([\s\S]*?)\}\)/,a=e.match(s);if(!a)return e;let i=a[1].split(`
|
|
1859
|
+
`).filter(d=>{let u=d.trim();if(u===""||u.startsWith("//"))return!0;let S=u.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return S?r.has(S[1]):!0}).join(`
|
|
1860
|
+
`);return e.replace(s,`createProviderRegistry({${i}})`)}function Gs(e,t){let o=We.join(t,"registry.ts.template"),n=ae.readFileSync(o,"utf-8");return po(n,e)}function Hs(e,t){let o=We.join(t,".env.example.template"),n=ae.readFileSync(o,"utf-8");return po(n,e)}async function lo(e,t,o){let n=Gs(t,o),r=Hs(t,o),s=We.join(e,"packages/agents/src");await ae.promises.mkdir(s,{recursive:!0}),await ae.promises.writeFile(We.join(s,"registry.ts"),n),await ae.promises.appendFile(We.join(e,".env.example"),`
|
|
1861
|
+
`+r);let a={ai:"latest"},{providerIds:c,customEndpoint:i}=t;(c.includes("openai")||i||c.some(u=>co.has(u)))&&(a["@ai-sdk/openai"]="latest",a["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(a["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(a["@ai-sdk/google"]="latest"),c.includes("mistral")&&(a["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(a["@ai-sdk/openai"]="latest");let d=We.join(e,"package.json");if(ae.existsSync(d)){let u=JSON.parse(await ae.promises.readFile(d,"utf-8"));u.dependencies||(u.dependencies={});for(let[S,U]of Object.entries(a))u.dependencies[S]=U;await ae.promises.writeFile(d,JSON.stringify(u,null,2)+`
|
|
1862
|
+
`)}}import g from"fs";import v from"path";function uo(e,t){if(!g.existsSync(e))return;let o=g.readdirSync(e);for(let n of o){let r=v.join(e,n);g.statSync(r).isDirectory()?uo(r,t):t(r)}}async function mo(e,t){let o=v.join(e,"package.json");if(!g.existsSync(o))return;let n=JSON.parse(g.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=v.join(e,"packages","db");if(g.existsSync(r)){let s=v.join(r,"prisma");g.existsSync(s)&&g.rmSync(s,{recursive:!0,force:!0});let a=v.join(r,"package.json");if(g.existsSync(a)){let i=JSON.parse(g.readFileSync(a,"utf8"));i.dependencies&&delete i.dependencies["@prisma/client"],i.devDependencies&&delete i.devDependencies.prisma,g.writeFileSync(a,JSON.stringify(i,null,2)+`
|
|
1863
|
+
`)}let c=v.join(r,"src","index.ts");g.existsSync(c)&&g.writeFileSync(c,`
|
|
1837
1864
|
export const prisma = {} as any;
|
|
1838
1865
|
export const db = {} as any;
|
|
1839
1866
|
export type PrismaClient = any;
|
|
@@ -1879,7 +1906,7 @@ export type UsageAggregate = any;
|
|
|
1879
1906
|
export type UsageLedgerEntry = any;
|
|
1880
1907
|
export type UsageType = any;
|
|
1881
1908
|
export type UsageLedgerSource = any;
|
|
1882
|
-
`)}
|
|
1909
|
+
`)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=v.join(e,"apps");if(g.existsSync(r)){let s=g.readdirSync(r);for(let a of s){let c=v.join(r,a);if(!g.statSync(c).isDirectory())continue;let i=v.join(c,"src","app");if(!g.existsSync(i))continue;["[lang]","[locale]"].forEach(E=>{let l=v.join(i,E);if(g.existsSync(l)){let N=g.readdirSync(l);for(let ut of N)g.renameSync(v.join(l,ut),v.join(i,ut));g.rmdirSync(l)}}),["src/middleware.ts","middleware.ts"].forEach(E=>{let l=v.join(c,E);g.existsSync(l)&&g.rmSync(l)});let d=v.join(c,"src","lib");g.existsSync(d)||g.mkdirSync(d,{recursive:!0});let u=v.join(d,"mock-i18n.ts");g.writeFileSync(u,`
|
|
1883
1910
|
import React from 'react';
|
|
1884
1911
|
export function useTranslations(namespace?: string): any { return (key: string) => key; }
|
|
1885
1912
|
export function useLocale() { return 'en'; }
|
|
@@ -1897,7 +1924,7 @@ export const useRouter = () => ({ push: (...args: any[]) => {}, replace: (...arg
|
|
|
1897
1924
|
export default function createMiddleware(...args: any[]) { return (req: any) => req; }
|
|
1898
1925
|
export function createNavigation(...args: any[]) { return { Link, redirect, usePathname, useRouter, getPathname: () => '/' }; }
|
|
1899
1926
|
export function defineRouting<T>(config: T): T { return config; }
|
|
1900
|
-
`);let
|
|
1927
|
+
`);let U=v.join(d,"mock-i18n.d.ts");g.writeFileSync(U,`declare module '@/lib/mock-i18n' {
|
|
1901
1928
|
export function useTranslations(namespace?: string): any;
|
|
1902
1929
|
export function useLocale(): string;
|
|
1903
1930
|
export const NextIntlClientProvider: React.FC<any>;
|
|
@@ -1915,14 +1942,18 @@ export function defineRouting<T>(config: T): T { return config; }
|
|
|
1915
1942
|
export function createNavigation(...args: any[]): any;
|
|
1916
1943
|
export function defineRouting<T>(config: T): T;
|
|
1917
1944
|
}
|
|
1918
|
-
`),
|
|
1945
|
+
`),g.writeFileSync(v.join(d,"mock-i18n-index.ts"),`
|
|
1919
1946
|
export * from './mock-i18n';
|
|
1920
1947
|
export { default } from './mock-i18n';
|
|
1921
|
-
`);let
|
|
1948
|
+
`);let F=v.join(c,"tsconfig.json");if(g.existsSync(F))try{let E=g.readFileSync(F,"utf8");if(E.includes('"paths": {')){let l=E.replace(/"paths":\s*\{/,`"paths": {
|
|
1922
1949
|
"next-intl": ["./src/lib/mock-i18n"],
|
|
1923
|
-
"next-intl/*": ["./src/lib/mock-i18n"],`);
|
|
1924
|
-
`)}}}}
|
|
1925
|
-
`)}import
|
|
1950
|
+
"next-intl/*": ["./src/lib/mock-i18n"],`);g.writeFileSync(F,l)}}catch{}let ee=v.join(c,"src");g.existsSync(ee)&&uo(ee,E=>{if(!E.endsWith(".ts")&&!E.endsWith(".tsx"))return;let l=g.readFileSync(E,"utf8"),N=!1;E.endsWith("src/app/layout.tsx")&&l.includes("../providers")&&(l=l.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),N=!0),l=l.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),l=l.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),l.match(/locale\s*:\s*any/)&&(l=l.replace(/locale\s*:\s*any/g,"locale: string"),N=!0),l.match(/lang\s*:\s*any/)&&(l=l.replace(/lang\s*:\s*any/g,"lang: string"),N=!0),l.match(/requestLocale\s*:\s*any/)&&(l=l.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),N=!0),l.match(/\(locale\s*=\s*(.*)\)/)&&(l=l.replace(/\(locale\s*=\s*(.*)\)/g,"() "),N=!0),l.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(l=l.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),N=!0),(E.endsWith("src/app/layout.tsx")||E.endsWith("src/app/sitemap.ts")||E.endsWith("src/app/robots.ts")||E.endsWith("src/components/ui/locale-switcher.tsx")||E.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(l=l.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),l=l.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),l=l.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),l=l.replace(/\(l\)\s*=>/g,"(l: any) =>"),N=!0),E.endsWith("src/i18n/request.ts")&&(l=l.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),N=!0),(l.match(/locale\s*:/)||l.match(/lang\s*:/))&&(N=!0),N&&g.writeFileSync(E,l)});let Xe=v.join(c,"package.json");if(g.existsSync(Xe)){let E=JSON.parse(g.readFileSync(Xe,"utf8"));E.dependencies&&delete E.dependencies["next-intl"],g.writeFileSync(Xe,JSON.stringify(E,null,2)+`
|
|
1951
|
+
`)}}}}g.writeFileSync(o,JSON.stringify(n,null,2)+`
|
|
1952
|
+
`)}import{getSchema as Ws,printSchema as Xs}from"@mrleebo/prisma-ast";var zs=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function Qs(e){return e.type==="comment"&&e.text.trim().startsWith("///")}function Js(e){let t=zs.exec(e.trim());if(!t)return null;let[,o,n]=t,r=n.split("|").map(s=>s.trim()).filter(s=>s.length>0);return{flag:o,values:r}}function Zs(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=Js(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function Gt(e,t){let o=Ws(e),n=new Set;for(let c=0;c<o.list.length;c++){if(o.list[c].type!=="model")continue;let d=Zs(o.list,c);if(!d)continue;let u=t[d.parsed.flag];if(u!==void 0&&d.parsed.values.includes(u))n.add(d.annIndex);else{n.add(c);for(let F=c-1;F>=0;F--){let ee=o.list[F];if(ee.type==="comment"&&Qs(ee)){n.add(F);continue}break}let U=o.list[c+1];U&&U.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,i)=>!n.has(i)),s=[];for(let c of r){let i=s[s.length-1];c.type==="break"&&i&&i.type==="break"||s.push(c)}return Xs({type:"schema",list:s})}import ce from"fs";import Ht from"path";var Rt=[{id:"qstash",name:"Upstash QStash",region:"both",envVars:["QSTASH_TOKEN","QSTASH_CURRENT_SIGNING_KEY","QSTASH_NEXT_SIGNING_KEY"],docs:"https://upstash.com/docs/qstash",description:"Serverless HTTP-based queue"},{id:"bullmq",name:"BullMQ",region:"both",envVars:["REDIS_URL"],docs:"https://docs.bullmq.io",description:"Redis-backed job queue"},{id:"upstash",name:"Upstash Kafka",region:"both",envVars:["UPSTASH_KAFKA_REST_URL","UPSTASH_KAFKA_REST_USERNAME","UPSTASH_KAFKA_REST_PASSWORD"],docs:"https://upstash.com/docs/kafka",description:"Serverless Kafka"},{id:"sqs",name:"AWS SQS",region:"global",envVars:["AWS_SQS_QUEUE_URL","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"],docs:"https://docs.aws.amazon.com/AWSSimpleQueueService/",description:"AWS managed queue"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip queue package"}];function go(e){return Rt.find(t=>t.id===e)}var op=Rt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function fo(e){return ce.existsSync(e)?ce.readFileSync(e,"utf-8"):null}function ei(e,t){let o=Ht.join(e,".env.example"),n=fo(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
|
|
1953
|
+
`);ce.appendFileSync(o,s)}function ti(e,t,o){let n=Ht.join(e,".env.example"),r=fo(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?ce.writeFileSync(n,r.replace(s,`${t}="${o}"`)):ce.appendFileSync(n,`${t}="${o}"
|
|
1954
|
+
`)}async function yo(e,t,o){let n=Ht.join(e,"packages","queue");if(t==="none"){ce.existsSync(n)&&ce.rmSync(n,{recursive:!0,force:!0});return}let r=go(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${Rt.map(s=>s.id).join(", ")}`);ce.existsSync(n)&&(ei(e,r),ti(e,"QUEUE_PROVIDER",t))}import pe from"fs";import Wt from"path";var Nt=[{id:"meilisearch",name:"Meilisearch",region:"both",envVars:["MEILISEARCH_HOST","MEILISEARCH_MASTER_KEY"],docs:"https://docs.meilisearch.com",description:"Self-hostable search"},{id:"typesense",name:"Typesense",region:"both",envVars:["TYPESENSE_HOST","TYPESENSE_PORT","TYPESENSE_PROTOCOL","TYPESENSE_API_KEY"],docs:"https://typesense.org/docs",description:"Open-source search"},{id:"algolia",name:"Algolia",region:"global",envVars:["ALGOLIA_APP_ID","ALGOLIA_ADMIN_API_KEY","ALGOLIA_SEARCH_API_KEY"],docs:"https://www.algolia.com/doc/",description:"Managed search as a service"},{id:"pgvector",name:"pgvector (Postgres)",region:"both",envVars:["DATABASE_URL"],docs:"https://github.com/pgvector/pgvector",description:"Postgres vector + full-text"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip search package"}];function So(e){return Nt.find(t=>t.id===e)}var pp=Nt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Eo(e){return pe.existsSync(e)?pe.readFileSync(e,"utf-8"):null}function ni(e,t){let o=Wt.join(e,".env.example"),n=Eo(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].join(`
|
|
1955
|
+
`);pe.appendFileSync(o,s)}function oi(e,t,o){let n=Wt.join(e,".env.example"),r=Eo(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?pe.writeFileSync(n,r.replace(s,`${t}="${o}"`)):pe.appendFileSync(n,`${t}="${o}"
|
|
1956
|
+
`)}async function ho(e,t,o){let n=Wt.join(e,"packages","search");if(t==="none"){pe.existsSync(n)&&pe.rmSync(n,{recursive:!0,force:!0});return}let r=So(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Nt.map(s=>s.id).join(", ")}`);pe.existsSync(n)&&(ni(e,r),oi(e,"SEARCH_PROVIDER",t))}import le from"fs";import be from"path";function ri(e){let t=[be.join(e,"packages","db"),be.join(e,"apps","web")];for(let o of t){let n=be.join(o,"prisma","schema.prisma");if(le.existsSync(n))return{packageDir:o,seedPath:be.join(o,"prisma","seed.ts"),packageJsonPath:be.join(o,"package.json")}}return null}function si(e){try{let t=le.readFileSync(e,"utf8"),o=new Set,n=/^\s*model\s+(\w+)\s*\{/gm,r=n.exec(t);for(;r;)o.add(r[1]),r=n.exec(t);return o}catch{return new Set}}function ii(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
|
|
1926
1957
|
const admin = await prisma.user.create({
|
|
1927
1958
|
data: {
|
|
1928
1959
|
clerkId: "user_mock_admin",
|
|
@@ -1953,7 +1984,7 @@ export { default } from './mock-i18n';
|
|
|
1953
1984
|
console.log("\\u2713 Created admin user:", admin.email);
|
|
1954
1985
|
} catch (err) {
|
|
1955
1986
|
console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
|
|
1956
|
-
}`}function
|
|
1987
|
+
}`}function ai(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),s=ii(e,n),a=o?` let tenants: Array<{ id: string; name: string }> = [];
|
|
1957
1988
|
try {
|
|
1958
1989
|
tenants = await Promise.all([
|
|
1959
1990
|
prisma.tenant.create({
|
|
@@ -1970,7 +2001,7 @@ export { default } from './mock-i18n';
|
|
|
1970
2001
|
} catch (err) {
|
|
1971
2002
|
console.warn("\\u26A0 Tenant creation skipped:", (err as Error).message);
|
|
1972
2003
|
}`:` const tenants: Array<{ id: string; name: string }> = [];
|
|
1973
|
-
console.log("\\u2139 No Tenant model in schema \u2014 skipping tenant seed.");`,c=o
|
|
2004
|
+
console.log("\\u2139 No Tenant model in schema \u2014 skipping tenant seed.");`,c=r&&o?` for (const tenant of tenants) {
|
|
1974
2005
|
try {
|
|
1975
2006
|
await prisma.project.createMany({
|
|
1976
2007
|
data: [
|
|
@@ -2022,12 +2053,12 @@ main()
|
|
|
2022
2053
|
.finally(async () => {
|
|
2023
2054
|
await prisma.$disconnect();
|
|
2024
2055
|
});
|
|
2025
|
-
`}function
|
|
2026
|
-
`)}catch(t){let
|
|
2027
|
-
`+t):
|
|
2056
|
+
`}function ci(e){if(le.existsSync(e))try{let t=le.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let s=o.prisma??{};if(s.seed||(s.seed="tsx prisma/seed.ts",r=!0),!r)return;let a={...o,scripts:n,prisma:s};le.writeFileSync(e,JSON.stringify(a,null,2)+`
|
|
2057
|
+
`)}catch(t){let o=t instanceof Error?t.message:String(t);console.warn(`[create-sailor] Failed to patch seed scripts in ${e}: ${o}`)}}async function vo(e,t){let o=ri(e);if(o)try{let n=be.join(o.packageDir,"prisma","schema.prisma"),r=si(n),s=ai(t,r),a=be.dirname(o.seedPath);le.existsSync(a)||le.mkdirSync(a,{recursive:!0}),le.writeFileSync(o.seedPath,s),ci(o.packageJsonPath)}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate seed data: ${r}`),new Error(`Unable to write prisma/seed.ts: ${r}`)}}import de from"fs";import Ie from"path";var xt=[{id:"twilio",name:"Twilio",region:"global",envVars:["TWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN","TWILIO_FROM_NUMBER"],docs:"https://www.twilio.com/docs/sms",pkgs:["twilio"]},{id:"messagebird",name:"MessageBird (Bird)",region:"global",envVars:["MESSAGEBIRD_ACCESS_KEY","MESSAGEBIRD_ORIGINATOR"],docs:"https://developers.messagebird.com/api/sms-messaging/",pkgs:["messagebird"]},{id:"plivo",name:"Plivo",region:"global",envVars:["PLIVO_AUTH_ID","PLIVO_AUTH_TOKEN","PLIVO_FROM_NUMBER"],docs:"https://www.plivo.com/docs/sms/",pkgs:["plivo"]},{id:"aliyun-sms",name:"\u963F\u91CC\u4E91\u77ED\u4FE1 Aliyun SMS",region:"cn",envVars:["ALIYUN_SMS_ACCESS_KEY","ALIYUN_SMS_ACCESS_SECRET","ALIYUN_SMS_SIGN_NAME","ALIYUN_SMS_TEMPLATE_CODE","ALIYUN_SMS_ENDPOINT"],docs:"https://help.aliyun.com/product/44282.html",pkgs:["@alicloud/dysmsapi20170525","@alicloud/openapi-client"]},{id:"tencent-sms",name:"\u817E\u8BAF\u4E91\u77ED\u4FE1 Tencent SMS",region:"cn",envVars:["TENCENT_SMS_SECRET_ID","TENCENT_SMS_SECRET_KEY","TENCENT_SMS_SDK_APP_ID","TENCENT_SMS_SIGN_NAME","TENCENT_SMS_TEMPLATE_ID","TENCENT_SMS_REGION"],docs:"https://cloud.tencent.com/document/product/382",pkgs:["tencentcloud-sdk-nodejs-sms"]},{id:"yunpian",name:"\u4E91\u7247 Yunpian",region:"cn",envVars:["YUNPIAN_API_KEY","YUNPIAN_SIGN"],docs:"https://www.yunpian.com/official/document/sms/zh_CN/introduction_product_intro",pkgs:["yunpian-nodejs-sdk"]},{id:"none",name:"None",region:"both",envVars:[],docs:""}],Ep=xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function _o(e){return xt.find(t=>t.id===e)}var pi="@nebutra/sms",li={twilio:"^5.3.6",messagebird:"^4.0.1",plivo:"^4.73.0","@alicloud/dysmsapi20170525":"^2.0.24","@alicloud/openapi-client":"^0.4.12","tencentcloud-sdk-nodejs-sms":"^4.0.970","yunpian-nodejs-sdk":"^0.0.2"};function Xt(e,t){de.mkdirSync(Ie.dirname(e),{recursive:!0}),de.writeFileSync(e,t)}function di(e,t){let o=Ie.join(e,".env.example");de.existsSync(o)?de.appendFileSync(o,`
|
|
2058
|
+
`+t):de.writeFileSync(o,t)}function ui(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2028
2059
|
`);return`${t}
|
|
2029
|
-
${
|
|
2030
|
-
`}var
|
|
2060
|
+
${o}
|
|
2061
|
+
`}var mi=`/**
|
|
2031
2062
|
* Inputs for the \`sendSms\` wrapper. Keep this surface portable across
|
|
2032
2063
|
* providers \u2014 provider-specific options belong in the wrapper itself.
|
|
2033
2064
|
*/
|
|
@@ -2047,7 +2078,7 @@ export interface SendSmsResult {
|
|
|
2047
2078
|
provider: string;
|
|
2048
2079
|
raw?: unknown;
|
|
2049
2080
|
}
|
|
2050
|
-
`;function
|
|
2081
|
+
`;function gi(){return`import twilio from "twilio";
|
|
2051
2082
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2052
2083
|
|
|
2053
2084
|
let client: ReturnType<typeof twilio> | null = null;
|
|
@@ -2082,7 +2113,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2082
2113
|
}
|
|
2083
2114
|
|
|
2084
2115
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2085
|
-
`}function
|
|
2116
|
+
`}function fi(){return`import messagebird from "messagebird";
|
|
2086
2117
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2087
2118
|
|
|
2088
2119
|
let client: ReturnType<typeof messagebird> | null = null;
|
|
@@ -2120,7 +2151,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2120
2151
|
}
|
|
2121
2152
|
|
|
2122
2153
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2123
|
-
`}function
|
|
2154
|
+
`}function yi(){return`import plivo from "plivo";
|
|
2124
2155
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2125
2156
|
|
|
2126
2157
|
let client: InstanceType<typeof plivo.Client> | null = null;
|
|
@@ -2159,7 +2190,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2159
2190
|
}
|
|
2160
2191
|
|
|
2161
2192
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2162
|
-
`}function
|
|
2193
|
+
`}function Si(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
|
|
2163
2194
|
import * as $OpenApi from "@alicloud/openapi-client";
|
|
2164
2195
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2165
2196
|
|
|
@@ -2208,7 +2239,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2208
2239
|
}
|
|
2209
2240
|
|
|
2210
2241
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2211
|
-
`}function
|
|
2242
|
+
`}function Ei(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
|
|
2212
2243
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2213
2244
|
|
|
2214
2245
|
const SmsClient = tencentcloud.sms.v20210111.Client;
|
|
@@ -2273,7 +2304,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2273
2304
|
}
|
|
2274
2305
|
|
|
2275
2306
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2276
|
-
`}function
|
|
2307
|
+
`}function hi(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
|
|
2277
2308
|
import Yunpian from "yunpian-nodejs-sdk";
|
|
2278
2309
|
import type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2279
2310
|
|
|
@@ -2325,13 +2356,13 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
|
|
|
2325
2356
|
}
|
|
2326
2357
|
|
|
2327
2358
|
export type { SendSmsInput, SendSmsResult } from "./types.js";
|
|
2328
|
-
`}function
|
|
2329
|
-
`}}function
|
|
2330
|
-
`}async function
|
|
2331
|
-
`+t):
|
|
2359
|
+
`}function vi(e){switch(e){case"twilio":return gi();case"messagebird":return fi();case"plivo":return yi();case"aliyun-sms":return Si();case"tencent-sms":return Ei();case"yunpian":return hi();case"none":return`export {};
|
|
2360
|
+
`}}function _i(e){let t={};for(let n of e.pkgs??[]){let r=li[n];r&&(t[n]=r)}let o={name:pi,version:"0.1.0",private:!0,description:`Transactional SMS via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
|
|
2361
|
+
`}async function Po(e,t,o="global"){if(t==="none")return;let n=_o(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${xt.map(a=>a.id).join(", ")}`);let r=Ie.join(e,"packages","sms");if(!de.existsSync(r))return;let s=Ie.join(r,"src");de.existsSync(s)&&de.rmSync(s,{recursive:!0,force:!0});try{Xt(Ie.join(r,"package.json"),_i(n)),Xt(Ie.join(s,"types.ts"),mi),Xt(Ie.join(s,"index.ts"),vi(n.id)),di(e,ui(n))}catch(a){throw console.error(`Failed to apply SMS selection "${t}":`,a),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import Ae from"fs";import Ce from"path";var kt=[{id:"r2",name:"Cloudflare R2",region:"global",envVars:["R2_ACCOUNT_ID","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY","R2_BUCKET"],docs:"https://developers.cloudflare.com/r2/api/s3/api/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"s3",name:"AWS S3",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_S3_REGION","S3_BUCKET"],docs:"https://docs.aws.amazon.com/s3/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"supabase-storage",name:"Supabase Storage",region:"global",envVars:["SUPABASE_URL","SUPABASE_SERVICE_ROLE_KEY","SUPABASE_BUCKET"],docs:"https://supabase.com/docs/guides/storage",pkg:"@supabase/supabase-js",pkgVersion:"^2.45.4"},{id:"aliyun-oss",name:"\u963F\u91CC\u4E91 OSS",region:"cn",envVars:["ALIYUN_OSS_ACCESS_KEY","ALIYUN_OSS_ACCESS_SECRET","ALIYUN_OSS_REGION","ALIYUN_OSS_BUCKET"],docs:"https://help.aliyun.com/product/31815.html",pkg:"ali-oss",pkgVersion:"^6.21.0"},{id:"tencent-cos",name:"\u817E\u8BAF\u4E91 COS",region:"cn",envVars:["TENCENT_COS_SECRET_ID","TENCENT_COS_SECRET_KEY","TENCENT_COS_BUCKET","TENCENT_COS_REGION"],docs:"https://cloud.tencent.com/document/product/436",pkg:"cos-nodejs-sdk-v5",pkgVersion:"^2.13.7"},{id:"qiniu",name:"\u4E03\u725B\u4E91 Kodo",region:"cn",envVars:["QINIU_ACCESS_KEY","QINIU_SECRET_KEY","QINIU_BUCKET","QINIU_DOMAIN"],docs:"https://developer.qiniu.com/kodo",pkg:"qiniu",pkgVersion:"^7.14.0"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function bo(e){return kt.find(t=>t.id===e)}var Ip=kt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var we="@nebutra/storage";function zt(e,t){Ae.mkdirSync(Ce.dirname(e),{recursive:!0}),Ae.writeFileSync(e,t)}function Pi(e,t){let o=Ce.join(e,".env.example");Ae.existsSync(o)?Ae.appendFileSync(o,`
|
|
2362
|
+
`+t):Ae.writeFileSync(o,t)}function bi(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
|
|
2332
2363
|
`);return`${t}
|
|
2333
|
-
${
|
|
2334
|
-
`}var
|
|
2364
|
+
${o}
|
|
2365
|
+
`}var Ii=`/**
|
|
2335
2366
|
* Inputs for the \`uploadFile\` wrapper. Keep this surface portable across
|
|
2336
2367
|
* providers \u2014 provider-specific options belong in the wrapper itself.
|
|
2337
2368
|
*/
|
|
@@ -2357,8 +2388,8 @@ export interface SignedUrlOptions {
|
|
|
2357
2388
|
operation?: "get" | "put";
|
|
2358
2389
|
contentType?: string;
|
|
2359
2390
|
}
|
|
2360
|
-
`;function
|
|
2361
|
-
* @${
|
|
2391
|
+
`;function Ci(){return`/**
|
|
2392
|
+
* @${we.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
|
|
2362
2393
|
*
|
|
2363
2394
|
* Docs: https://developers.cloudflare.com/r2/api/s3/api/
|
|
2364
2395
|
*/
|
|
@@ -2421,8 +2452,8 @@ export async function getSignedUrl(
|
|
|
2421
2452
|
}
|
|
2422
2453
|
|
|
2423
2454
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2424
|
-
`}function
|
|
2425
|
-
* @${
|
|
2455
|
+
`}function Ai(){return`/**
|
|
2456
|
+
* @${we.slice(1)} \u2014 AWS S3 wrapper.
|
|
2426
2457
|
*
|
|
2427
2458
|
* Docs: https://docs.aws.amazon.com/s3/
|
|
2428
2459
|
*/
|
|
@@ -2486,8 +2517,8 @@ export async function getSignedUrl(
|
|
|
2486
2517
|
}
|
|
2487
2518
|
|
|
2488
2519
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2489
|
-
`}function
|
|
2490
|
-
* @${
|
|
2520
|
+
`}function wi(){return`/**
|
|
2521
|
+
* @${we.slice(1)} \u2014 Supabase Storage wrapper.
|
|
2491
2522
|
*
|
|
2492
2523
|
* Docs: https://supabase.com/docs/guides/storage
|
|
2493
2524
|
*/
|
|
@@ -2549,8 +2580,8 @@ export async function getSignedUrl(
|
|
|
2549
2580
|
}
|
|
2550
2581
|
|
|
2551
2582
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2552
|
-
`}function
|
|
2553
|
-
* @${
|
|
2583
|
+
`}function Ri(){return`/**
|
|
2584
|
+
* @${we.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
|
|
2554
2585
|
*
|
|
2555
2586
|
* Docs: https://help.aliyun.com/product/31815.html
|
|
2556
2587
|
*/
|
|
@@ -2596,8 +2627,8 @@ export async function getSignedUrl(
|
|
|
2596
2627
|
}
|
|
2597
2628
|
|
|
2598
2629
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2599
|
-
`}function
|
|
2600
|
-
* @${
|
|
2630
|
+
`}function Ni(){return`/**
|
|
2631
|
+
* @${we.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
|
|
2601
2632
|
*
|
|
2602
2633
|
* Docs: https://cloud.tencent.com/document/product/436
|
|
2603
2634
|
*/
|
|
@@ -2651,8 +2682,8 @@ export async function getSignedUrl(
|
|
|
2651
2682
|
}
|
|
2652
2683
|
|
|
2653
2684
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2654
|
-
`}function
|
|
2655
|
-
* @${
|
|
2685
|
+
`}function xi(){return`/**
|
|
2686
|
+
* @${we.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
|
|
2656
2687
|
*
|
|
2657
2688
|
* Docs: https://developer.qiniu.com/kodo
|
|
2658
2689
|
*/
|
|
@@ -2719,9 +2750,9 @@ export async function getSignedUrl(
|
|
|
2719
2750
|
}
|
|
2720
2751
|
|
|
2721
2752
|
export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types.js";
|
|
2722
|
-
`}function
|
|
2723
|
-
`}}function
|
|
2724
|
-
`}async function
|
|
2753
|
+
`}function ki(e){switch(e){case"r2":return Ci();case"s3":return Ai();case"supabase-storage":return wi();case"aliyun-oss":return Ri();case"tencent-cos":return Ni();case"qiniu":return xi();case"none":return`export {};
|
|
2754
|
+
`}}function Ti(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),(e.id==="r2"||e.id==="s3")&&(t["@aws-sdk/s3-request-presigner"]="^3.658.0");let o={name:we,version:"0.1.0",private:!0,description:`Object storage via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
|
|
2755
|
+
`}async function Io(e,t,o){if(t==="none")return;let n=bo(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${kt.map(a=>a.id).join(", ")}`);let r=Ce.join(e,"packages","storage"),s=Ce.join(r,"src");Ae.existsSync(s)&&Ae.rmSync(s,{recursive:!0,force:!0}),zt(Ce.join(r,"package.json"),Ti(n)),zt(Ce.join(s,"types.ts"),Ii),zt(Ce.join(s,"index.ts"),ki(n.id)),Pi(e,bi(n))}var Tt=[{id:"svix",name:"Svix",region:"global",envVars:["SVIX_API_TOKEN"],docs:"https://docs.svix.com",description:"Managed webhooks platform"},{id:"custom",name:"Custom (self-hosted)",region:"both",envVars:["WEBHOOK_SIGNING_SECRET"],docs:"",description:"Custom implementation with built-in package"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Co(e){return Tt.find(t=>t.id===e)}var xp=Tt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Ao(e,t,o="global"){let n=Co(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Tt.map(r=>r.id).join(", ")}`);if(n.id==="none"){B(e,"webhooks");return}n.envVars.length>0&&G(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),H(e,"WEBHOOKS_PROVIDER",n.id)}import Re from"fs";import lt from"path";function Oi(e){return`import Link from "next/link";
|
|
2725
2756
|
|
|
2726
2757
|
export default function WelcomePage() {
|
|
2727
2758
|
const projectName = ${JSON.stringify(e)};
|
|
@@ -2761,9 +2792,9 @@ export default function WelcomePage() {
|
|
|
2761
2792
|
/>
|
|
2762
2793
|
<Step
|
|
2763
2794
|
number={4}
|
|
2764
|
-
title="
|
|
2765
|
-
description="
|
|
2766
|
-
command="pnpm
|
|
2795
|
+
title="Initialize brand config"
|
|
2796
|
+
description="Generate brand.config.ts, then run pnpm brand:apply after edits"
|
|
2797
|
+
command="pnpm brand:init"
|
|
2767
2798
|
/>
|
|
2768
2799
|
</ol>
|
|
2769
2800
|
</section>
|
|
@@ -2830,7 +2861,7 @@ function Step({
|
|
|
2830
2861
|
</li>
|
|
2831
2862
|
);
|
|
2832
2863
|
}
|
|
2833
|
-
`}function
|
|
2864
|
+
`}function Ui(e,t){return`# Next steps \u2014 ${e}
|
|
2834
2865
|
|
|
2835
2866
|
Region: ${t}
|
|
2836
2867
|
|
|
@@ -2849,9 +2880,10 @@ Your AI-native SaaS scaffold is ready. Complete these four steps to go from temp
|
|
|
2849
2880
|
pnpm db:seed
|
|
2850
2881
|
\`\`\`
|
|
2851
2882
|
|
|
2852
|
-
4. **
|
|
2883
|
+
4. **Initialize your brand config** \u2014 generate \`brand.config.ts\`, then apply it after edits
|
|
2853
2884
|
\`\`\`bash
|
|
2854
|
-
pnpm
|
|
2885
|
+
pnpm brand:init
|
|
2886
|
+
pnpm brand:apply
|
|
2855
2887
|
\`\`\`
|
|
2856
2888
|
|
|
2857
2889
|
After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
|
|
@@ -2861,23 +2893,26 @@ After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
|
|
|
2861
2893
|
- [Documentation](/docs)
|
|
2862
2894
|
- [GitHub](https://github.com/nebutra/nebutra-sailor)
|
|
2863
2895
|
- [Get free license (Individual/OPC)](https://nebutra.com/get-license)
|
|
2864
|
-
`}async function
|
|
2865
|
-
`)}function
|
|
2866
|
-
`)+
|
|
2867
|
-
`)),"fumadocs"}return"fumadocs"}function
|
|
2868
|
-
`)),process.exit(130)}});i=String(
|
|
2869
|
-
`)),process.exit(130)}}):{};
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
`);process.stdout.write(
|
|
2896
|
+
`}async function wo(e,t){let{projectName:o,region:n}=t;try{let r=lt.join(e,".sailor");Re.existsSync(r)||Re.mkdirSync(r,{recursive:!0}),Re.writeFileSync(lt.join(r,"next-steps.md"),Ui(o,n))}catch(r){let s=r instanceof Error?r.message:String(r);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${s}`)}try{let r=lt.join(e,"apps","web");if(!Re.existsSync(r))return;let s=lt.join(r,"src","app","[locale]","welcome");Re.existsSync(s)||Re.mkdirSync(s,{recursive:!0}),Re.writeFileSync(lt.join(s,"page.tsx"),Oi(o))}catch(r){let s=r instanceof Error?r.message:String(r);console.warn(`[create-sailor] Failed to write welcome page: ${s}`)}}var Ro="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
|
|
2897
|
+
`)}function Di(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function No(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 xo(e){return e==="drizzle"?"drizzle":e==="none"?"none":"prisma"}function ko(e){return e==="lemon"||e==="lemonsqueezy"?"lemonsqueezy":e==="none"?"none":"stripe"}function To(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 Oo(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="none"?"none":"clerk"}function Uo(e){if(!e)return["openai"];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}var Lo={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Mo(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in Lo){let n=Lo[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(R.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
|
|
2898
|
+
`)+R.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
|
|
2899
|
+
`)),"fumadocs"}return"fumadocs"}function Do(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 Fo(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function Fi(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 jo(e){return e==="cn"?"wechat":"stripe"}async function ji(){let e=new Li;e.name(Ro).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ne,"-v, --version").helpOption(!1).argument("[name]","project directory",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--region <id>","global | cn | hybrid").option("--orm <id>","prisma | drizzle | none").option("--db <id>","postgres | mysql | sqlite | none").option("--auth <id>","clerk | betterauth | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <ids>","comma-separated provider ids").option("--deploy <target>","vercel | railway | cloudflare | selfhost").option("--docs <id>","fumadocs | mintlify | docusaurus | nextra | vitepress | none").option("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | none").option("--queue <id>","qstash | bullmq | upstash | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").option("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--no-install","skip package install").option("--no-git","skip git init").option("-y, --yes","accept all defaults (non-interactive)").option("--dry-run","preview actions without writing files").option("--json","machine-readable output").option("--no-color","disable color output").option("-h, --help","show help"),e.parse(process.argv);let t=e.opts(),[o]=e.args;t.help&&(on(),process.exit(0));let n=!!t.json,r=!!t.dryRun,s=!!t.yes,a=s||!process.stdin.isTTY;n||en(),p(n,{event:"start",version:ne});let c=o??(s?"./my-saas-app":void 0),i;if(c)i=c;else if(a)i="./my-saas-app";else{let m=await C.group({name:()=>C.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:y=>{if(y.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(R.red(`\u2718 Cancelled
|
|
2900
|
+
`)),process.exit(130)}});i=String(m.name)}let d=dt.basename(dt.resolve(i)),u=t.pm??Di(),S=!!t.region,U=!!t.auth,F=!!t.payment,ee=!!t.ai,Xe=!!t.email,E=!!t.storage,l=!!t.monitoring,N=!!t.analytics,ut=!!t.sms,Qt=t.i18n!==void 0,f,ze,z,Qe,j,k,$=fn(t.socialLogin),te,Ne,Q,V,mt;if(a){f=Fo(t.region),ze=xo(t.orm),z=No(t.db);let m=F?t.payment:jo(f);Qe=ko(m),j=To(m),k=Oo(t.auth),te=Uo(t.ai),Q=Do(t.deploy),V=Mo(t.docs,n),mt=Qt?!!t.i18n:!0}else{let m={};if(S||(m.region=()=>C.select({message:"Target region?",options:[{value:"global",label:"global \u2014 \u6D77\u5916\u4F18\u5148"},{value:"cn",label:"cn \u2014 \u56FD\u5185\u4F18\u5148"},{value:"hybrid",label:"hybrid \u2014 \u53CC\u8F68\uFF08\u56FD\u5185+\u51FA\u6D77\uFF09"}],initialValue:"global"})),U||(m.auth=()=>C.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk"},{value:"betterauth",label:"Better Auth"},{value:"none",label:"None"}],initialValue:"clerk"})),!ee){let yt=Array.from(new Set(ht.map(w=>w.category)));m.aiCategories=()=>C.multiselect({message:"Which AI Provider categories do you want to explore? (Select multiple)",options:yt.map(w=>({value:w,label:w})),initialValues:["\u76F4\u63A5\u5B9E\u9A8C\u5BA4","\u7EDF\u4E00\u7F51\u5173"]}),m.aiProviders=({results:w})=>{let $e=w.aiCategories||[],_=ht.filter(K=>$e.includes(K.category)).map(K=>({value:K.id,label:`[${K.category}] ${K.name}`}));return _.push({value:"custom",label:"[\u81EA\u5B9A\u4E49] Custom OpenAI-compatible endpoint"}),C.multiselect({message:"Select AI Providers (Space to select, Enter to submit)",options:_,initialValues:["openai","anthropic"],required:!1})},m.enableCustom=({results:w})=>w.aiProviders?.includes("custom")?C.confirm({message:"Configure custom OpenAI-compatible endpoint?",initialValue:!0}):Promise.resolve(!1),m.customAiName=({results:w})=>w.enableCustom?C.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),m.customAiBaseUrl=({results:w})=>w.enableCustom?C.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:$e=>{if($e.length===0)return"Base URL is required."}}):Promise.resolve(void 0),m.customAiApiKeyEnv=({results:w})=>w.enableCustom?C.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0)}let y=Object.keys(m).length>0?await C.group(m,{onCancel:()=>{process.stdout.write(R.red(`\u2718 Cancelled
|
|
2901
|
+
`)),process.exit(130)}}):{};f=Fo(S?t.region:y.region),ze=xo(t.orm),z=No(t.db);let L=F?t.payment:jo(f);Qe=ko(L),j=To(L),k=Oo(U?t.auth:y.auth),te=ee?Uo(t.ai):y.aiProviders?.filter(yt=>yt!=="custom")??[],y.enableCustom&&(Ne={name:y.customAiName,baseURL:y.customAiBaseUrl,apiKeyEnvName:y.customAiApiKeyEnv}),Q=Do(t.deploy),V=Mo(t.docs,n),mt=Qt?!!t.i18n:!0}let P=Fi(f),xe=Xe?t.email:P.email,ke=E?t.storage:P.storage,Te=l?t.monitoring:P.monitoring,Oe=N?t.analytics:P.analytics,Ue=ut?t.sms:P.sms,Le=t.queue??P.queue,Me=t.search??P.search,Je=t.cache??P.cache,De=t.notifications??P.notifications,Fe=t.webhooks??P.webhooks,Ze=t.cms??P.cms,je=t.featureFlags??P.featureFlags,Ve=t.captcha??P.captcha,gt=t.mcp??P.mcp,et=t.metering??P.metering,Ke=t.billingMode??P.billingMode,Be=t.idp??P.idp,tt=tn([{flag:"queue",provider:Le},{flag:"search",provider:Me},{flag:"notifications",provider:De},{flag:"webhooks",provider:Fe},{flag:"feature-flags",provider:je},{flag:"captcha",provider:Ve}]);function Ut(){for(let m of tt)if(n)p(!0,{event:"warn",step:m.flag,provider:m.provider,packageStatus:m.status,message:qe(m.status)});else{let y=St(m.status);process.stdout.write(R.yellow(`\u26A0 ${m.flag}=${m.provider} ${y} \u2014 ${qe(m.status)}
|
|
2902
|
+
`))}}let Ye={region:f,orm:ze,database:z,payment:Qe,aiProviders:te,customAiEndpoint:Ne,deployTarget:Q,docs:V,i18n:mt,email:xe,storage:ke,monitoring:Te,analytics:Oe,sms:Ue,queue:Le,search:Me,cache:Je,notifications:De,webhooks:Fe,cms:Ze,featureFlags:je,captcha:Ve,mcp:gt,metering:et,billingMode:Ke,idp:Be},ft=[["Project name",d],["Region",f],["Auth",k],["Social login",$.length>0?$.map(m=>nt.find(y=>y.id===m)?.name??m).join(", "):"none"],["ORM",ze],["Database",z],["Payment",j],["AI",Array.isArray(te)?te.join(", ")+(Ne?", custom":""):String(te)],["Email",xe],["Storage",ke],["Monitoring",Te],["Analytics",Oe],["SMS",Ue],["Deploy Target",Q],["Docs Framework",V]];n?ft.forEach(([m,y],L)=>{p(!0,{event:"step",step:m,value:y,index:L+1,total:ft.length})}):ft.forEach(([m,y],L)=>{sn({index:L+1,total:ft.length,label:m,value:y})});let Vo={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},Jt=Date.now();if(r){let m=te.length,y=[`clone template \u2192 ${i}`,"write nebutra.config.json",`prune template (orm=${ze}, i18n=${mt})`,`region \u2192 ${f}`,`auth \u2192 ${k==="none"?"skip (remove packages/auth)":`configure ${k}`}`,...$.length>0?[`social-login \u2192 generate ${$.length} callback route${$.length===1?"":"s"} + SocialLoginButtons.tsx (${$.join(", ")})`]:[],`db \u2192 ${z==="none"?"skip (remove packages/db)":`configure Prisma for ${z}`}`,`payment \u2192 ${j==="none"?"skip (remove packages/billing)":`configure ${j}`}`,...V!=="none"?[`docs \u2192 scaffold apps/docs (${V==="fumadocs"?"fumadocs":`${V} \u2192 fumadocs fallback`})`]:[],...m>0||Ne?[`ai-providers \u2192 generate registry.ts + env (${m}${Ne?" + custom":""} provider${m===1&&!Ne?"":"s"})`]:[],...xe!=="none"?[`email \u2192 configure ${xe}`]:[],...ke!=="none"?[`storage \u2192 configure ${ke}`]:[],...Te!=="none"?[`monitoring \u2192 configure ${Te}`]:[],...Oe!=="none"?[`analytics \u2192 configure ${Oe}`]:[],...Ue!=="none"?[`sms \u2192 configure ${Ue}`]:[],...Le!=="none"?[`queue \u2192 configure ${Le}`]:[],...Me!=="none"?[`search \u2192 configure ${Me}`]:[],...Je!=="none"?[`cache \u2192 configure ${Je}`]:[],...De!=="none"?[`notifications \u2192 configure ${De}`]:[],...Fe!=="none"?[`webhooks \u2192 configure ${Fe}`]:[],...Ze!=="none"?[`cms \u2192 configure ${Ze}`]:[],...je!=="none"?[`feature-flags \u2192 configure ${je}`]:[],...Ve!=="none"?[`captcha \u2192 configure ${Ve}`]:[],`mcp \u2192 ${gt==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${et==="off"?"disabled":et==="auto"?Qe!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...Ke!=="usage"?[`billing-mode \u2192 ${Ke}`]:[],...Be!=="clerk"?[`idp \u2192 ${Be}`]:[],`compliance \u2192 inject ${f} boilerplate (ICP/Cookie/AIGC/Privacy)`,"welcome \u2192 generate dev welcome page","env \u2192 generate random secrets (AUTH_SECRET, JWT_SECRET)","seed \u2192 generate prisma/seed.ts (1 admin + 3 tenants)",...Q!=="none"?[`deploy \u2192 inject ${Q} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${u} install`,t.git===!1?"skip git init":"run git init"];if(n)y.forEach(L=>p(!0,{event:"plan",action:L})),Ut(),p(!0,{event:"done",dryRun:!0});else{process.stdout.write(`
|
|
2903
|
+
`+R.bold(`Dry run \u2014 planned actions:
|
|
2904
|
+
`));for(let L of y)process.stdout.write(` \u2022 ${L}
|
|
2905
|
+
`);tt.length>0&&(process.stdout.write(`
|
|
2906
|
+
`+R.bold(R.yellow(`Preview-status providers selected:
|
|
2907
|
+
`))),Ut()),process.stdout.write(R.dim(`
|
|
2873
2908
|
No files were written.
|
|
2874
|
-
`))}process.exit(0)}let
|
|
2875
|
-
`+
|
|
2876
|
-
`)),
|
|
2877
|
-
`))),process.exit(130)};process.on("SIGINT",
|
|
2878
|
-
`));try{
|
|
2879
|
-
`))}}else
|
|
2880
|
-
`))}}else
|
|
2909
|
+
`))}process.exit(0)}let Ko=async()=>{process.stdout.write(`
|
|
2910
|
+
`+R.red(`\u2718 Cancelled
|
|
2911
|
+
`)),ue.existsSync(i)&&await C.confirm({message:`Cleanup partial install at ${i}?`,initialValue:!0})===!0&&(ue.rmSync(i,{recursive:!0,force:!0}),process.stdout.write(R.dim(` \u2713 Removed ${i}
|
|
2912
|
+
`))),process.exit(130)};process.on("SIGINT",Ko);try{p(n,{event:"step",step:"clone",status:"start"}),await Wn(i),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await oo(i,d),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await An(i,Ye),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await mo(i,Ye),p(n,{event:"step",step:"prune",status:"ok"});let m=dt.join(i,"packages/db/prisma/schema.prisma");if(ue.existsSync(m)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let b=ue.readFileSync(m,"utf-8"),_=Gt(b,{auth:k,payment:j,"billing-mode":Ke,idp:Be,template:"saas"});ue.writeFileSync(m,_),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(b){let _=b instanceof Error?b.message:String(b);p(n,{event:"step",step:"schema-prune",status:"error",error:_})}}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"auth",choice:k,status:"start"}),await mn(i,k),p(n,{event:"step",step:"auth",choice:k,status:"ok"}),$.length>0?(p(n,{event:"step",step:"social-login",providers:$,status:"start"}),await Sn(i,$,k),p(n,{event:"step",step:"social-login",providers:$,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:z,status:"start"}),await Nn(i,z,d),p(n,{event:"step",step:"db",choice:z,status:"ok"}),p(n,{event:"step",step:"payment",choice:j,status:"start"}),await so(i,j),p(n,{event:"step",step:"payment",choice:j,status:"ok"}),await Mn(i,xe,f),n&&p(!0,{event:"step",step:"email",choice:xe,status:"ok"}),await Io(i,ke,f),n&&p(!0,{event:"step",step:"storage",choice:ke,status:"ok"}),await eo(i,Te,f),n&&p(!0,{event:"step",step:"monitoring",choice:Te,status:"ok"}),await ln(i,Oe,f),n&&p(!0,{event:"step",step:"analytics",choice:Oe,status:"ok"}),await Po(i,Ue,f),n&&p(!0,{event:"step",step:"sms",choice:Ue,status:"ok"}),await yo(i,Le,f),n&&p(!0,{event:"step",step:"queue",choice:Le,status:"ok"}),await ho(i,Me,f),n&&p(!0,{event:"step",step:"search",choice:Me,status:"ok"}),await vn(i,Je,f),n&&p(!0,{event:"step",step:"cache",choice:Je,status:"ok"}),await no(i,De,f),n&&p(!0,{event:"step",step:"notifications",choice:De,status:"ok"}),await Ao(i,Fe,f),n&&p(!0,{event:"step",step:"webhooks",choice:Fe,status:"ok"}),await In(i,Ze,f),n&&p(!0,{event:"step",step:"cms",choice:Ze,status:"ok"}),await Yn(i,je,f),n&&p(!0,{event:"step",step:"feature-flags",choice:je,status:"ok"}),await Pn(i,Ve,f),n&&p(!0,{event:"step",step:"captcha",choice:Ve,status:"ok"}),await Xn(i,gt),n&&p(!0,{event:"step",step:"mcp",mode:gt,status:"ok"}),await Qn(i,et,Qe),n&&p(!0,{event:"step",step:"metering",mode:et,status:"ok"}),Ye.orm==="prisma"&&Ye.database!=="none"){let b=dt.join(i,"packages/db/prisma/schema.prisma");if(ue.existsSync(b)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let _=ue.readFileSync(b,"utf8"),K=Gt(_,{auth:k,payment:j,"billing-mode":Ke,idp:Be,template:"saas"});ue.writeFileSync(b,K),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(_){let K=_ instanceof Error?_.message:String(_);p(n,{event:"step",step:"schema-prune",status:"error",error:K})}}else p(n,{event:"step",step:"schema-prune",status:"skip"})}else p(n,{event:"step",step:"schema-prune",status:"skip"});p(n,{event:"step",step:"billing-mode",choice:Ke,status:"ok"}),p(n,{event:"step",step:"idp",choice:Be,status:"ok"}),await Cn(i,f),n&&p(!0,{event:"step",step:"compliance",region:f,status:"ok"}),await Kn(i),await vo(i,k),await wo(i,{projectName:d,region:f}),p(n,{event:"step",step:"ai-providers",status:"start"});let y={providerIds:Ye.aiProviders,customEndpoint:Ye.customAiEndpoint},L=dt.join(i,"packages/ai-providers/templates");if(await lo(i,y,L),p(n,{event:"step",step:"ai-providers",status:"ok"}),p(n,{event:"step",step:"docs",status:"start"}),V!=="none"?(await Tn(i,{framework:V,projectName:d}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:V,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),Q!=="none"&&await xn(i,Q),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await Fn(i,Vo),p(n,{event:"step",step:"env",status:"ok"}),t.install!==!1){let b=u==="bun"?"bun install":`${u} install`;n?p(!0,{event:"step",step:"install",pm:u,status:"start"}):process.stdout.write(R.dim(` Installing dependencies with ${u}\u2026
|
|
2913
|
+
`));try{Ot(b,{cwd:i,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(_){let K=_ instanceof Error?_.message:String(_);n?p(!0,{event:"step",step:"install",status:"error",error:K}):process.stdout.write(R.yellow(` \u26A0 install failed \u2014 run '${b}' manually.
|
|
2914
|
+
`))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{Ot("git init -q",{cwd:i,stdio:"ignore"}),Ot("git add -A",{cwd:i,stdio:"ignore"}),Ot('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:i,stdio:"ignore"}),p(n,{event:"step",step:"git-init",status:"ok"})}catch(b){let _=b instanceof Error?b.message:String(b);n?p(!0,{event:"step",step:"git-init",status:"error",error:_}):process.stdout.write(R.yellow(` \u26A0 git init skipped \u2014 not fatal.
|
|
2915
|
+
`))}}else p(n,{event:"step",step:"git-init",status:"skip"});let $e=Math.max(1,Math.round((Date.now()-Jt)/1e3));an({template_version:ne,package_manager:u,region:f,auth:k,payment:j,ai_providers:te,deploy_target:Q,duration_ms:Date.now()-Jt}),tt.length>0&&Ut(),n?p(!0,{event:"done",status:"ok",elapsedSec:$e,targetDir:i,previewSelections:tt}):nn({elapsedSec:$e,targetDir:i,skippedInstall:t.install===!1,previewSelections:tt});try{Mi({pkg:{name:Ro,version:ne},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(m){let y=m instanceof Error?m.message:String(m);n?p(!0,{event:"error",message:y}):process.stdout.write(R.red(`
|
|
2881
2916
|
\u2718 Failed: ${y}
|
|
2882
|
-
`)),process.exit(1)}}
|
|
2917
|
+
`)),process.exit(1)}}ji().catch(e=>{process.stderr.write(String(e)+`
|
|
2883
2918
|
`),process.exit(1)});
|