create-sailor 1.7.3 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +9 -0
  2. package/dist/aws-kms-W5N62I3Q.js +1 -0
  3. package/dist/chunk-224RJRPV.js +5 -0
  4. package/dist/chunk-2YUF6TO6.js +2 -0
  5. package/dist/chunk-3T4EOSMQ.js +1 -0
  6. package/dist/chunk-44JV4JDH.js +1 -0
  7. package/dist/chunk-5ECPN42W.js +1 -0
  8. package/dist/chunk-5LSLUC7O.js +9 -0
  9. package/dist/chunk-AAIUIEEA.js +1 -0
  10. package/dist/chunk-CHWVD37K.js +1 -0
  11. package/dist/chunk-DATQDZ23.js +1 -0
  12. package/dist/chunk-IY2KKEUD.js +1 -0
  13. package/dist/chunk-IYWUY3VA.js +1 -0
  14. package/dist/chunk-M2Z4KZL3.js +20 -0
  15. package/dist/chunk-M3QJPQWS.js +1 -0
  16. package/dist/chunk-QSLKOXQ6.js +1 -0
  17. package/dist/chunk-S4HCBMFP.js +1 -0
  18. package/dist/chunk-TX7AAHER.js +1 -0
  19. package/dist/chunk-U4BHGI6P.js +1 -0
  20. package/dist/chunk-WI7DO2VU.js +1 -0
  21. package/dist/chunk-XB6R2VIU.js +1 -0
  22. package/dist/chunk-XE3I3HCZ.js +40 -0
  23. package/dist/chunk-YHGYZK4L.js +1 -0
  24. package/dist/chunk-ZCWB3HFB.js +1 -0
  25. package/dist/chunk-ZIBRKYXP.js +23 -0
  26. package/dist/credits-RR7B3C4K.js +2635 -0
  27. package/dist/dist-27O4E2DL.js +1 -0
  28. package/dist/dist-NJH3URWV.js +5 -0
  29. package/dist/dist-es-2W7PQEXN.js +5 -0
  30. package/dist/dist-es-CAS2CDUC.js +2 -0
  31. package/dist/dist-es-DQDVBBVA.js +1 -0
  32. package/dist/dist-es-GO22VTF3.js +1 -0
  33. package/dist/dist-es-KKEGJGC4.js +2 -0
  34. package/dist/dist-es-LARTXLYL.js +1 -0
  35. package/dist/dist-es-O2XJNCOH.js +1 -0
  36. package/dist/event-streams-BXAP5G2H.js +1 -0
  37. package/dist/index.js +361 -423
  38. package/dist/loadSso-LSHML5XP.js +1 -0
  39. package/dist/local-6WWVOMA7.js +1 -0
  40. package/dist/query_compiler_fast_bg.postgresql-JA2BFVW5.js +2 -0
  41. package/dist/query_compiler_fast_bg.postgresql.wasm-base64-URHQ2Y3Y.js +1 -0
  42. package/dist/signin-3DEIU5DH.js +1 -0
  43. package/dist/sso-oidc-5FB6AI4I.js +1 -0
  44. package/dist/sts-7GUSARTO.js +6 -0
  45. package/package.json +21 -20
  46. package/templates/backends/gateway/package.json +4 -3
  47. package/templates/backends/gateway/src/index.ts +0 -4
  48. package/templates/backends/gateway/src/node.ts +5 -0
  49. package/templates/backends/gateway/src/worker.ts +11 -0
  50. package/templates/deploy/Dockerfile.web +1 -1
  51. package/templates/deploy/wrangler.gateway.toml +11 -0
package/dist/index.js CHANGED
@@ -1,82 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import{execSync as kt}from"child_process";import _e from"fs";import de from"path";import*as O from"@clack/prompts";import{Command as pc}from"commander";import A from"picocolors";import lc from"update-notifier";import Br from"cfonts";import Kr from"picocolors";import _n from"fs";import tn from"path";import{fileURLToPath as jr}from"url";function Vr(){try{let t=tn.dirname(jr(import.meta.url));for(let o=0;o<4;o++){let n=tn.join(t,"package.json");if(_n.existsSync(n)){let r=_n.readFileSync(n,"utf-8"),s=JSON.parse(r);if(s.name==="create-sailor"&&typeof s.version=="string")return s.version}t=tn.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var ae=Vr();function bn(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${ae}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
3
- `));return}Br.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(Kr.dim(` AI-Native SaaS Template \xB7 v${ae} \xB7 nebutra.com
4
-
5
- `))}import P from"picocolors";var $r={qstash:"foundation",bullmq:"foundation",upstash:"foundation",sqs:"foundation",meilisearch:"foundation",typesense:"foundation",algolia:"foundation",pgvector:"foundation",novu:"foundation",knock:"foundation",svix:"foundation","vercel-flags":"wip",growthbook:"wip",configcat:"wip",turnstile:"wip",hcaptcha:"wip","aliyun-slide":"wip",invite:"foundation"};function Yr(e){return e?$r[e]??"stable":"stable"}function rt(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function me(e){switch(e){case"stable":return"Production-ready.";case"foundation":return"Foundation status \u2014 types + factory are complete, but provider adapters are stub-level and require external credentials.";case"wip":return"WIP \u2014 actively being built, should not be used in production.";case"deprecated":return"Deprecated \u2014 scheduled for removal, do not use."}}function Pn(e){let t=[];for(let{flag:o,provider:n}of e){if(!n||n==="none")continue;let r=Yr(n);r!=="stable"&&t.push({flag:o,provider:n,status:r})}return t}function qr(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function An(e){let t=qr(),o=t?"\u2693":"-",n=t?"\u25B8":"->",r=t?"\u2605":"*",s=t?"\u{1F4E7}":"*",c=["",` ${t?P.bold(`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${o} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?P.bold("Next:"):"Next:"}`,` ${n} cd ${e.targetDir}`];e.skippedInstall&&c.push(` ${n} pnpm install (if --no-install was set)`),c.push(` ${n} fill in .env.local ${t?P.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${n} pnpm db:migrate ${t?P.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${n} pnpm db:seed ${t?P.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${n} pnpm dev ${t?P.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?P.bold("Customize:"):"Customize:"}`,` ${n} pnpm brand:init ${t?P.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${n} pnpm brand:apply ${t?P.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${n} pnpm preset:env ${t?P.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?P.bold("Useful scripts:"):"Useful scripts:"}`,` ${n} pnpm infra:up ${t?P.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${n} pnpm generate:api-types ${t?P.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${n} pnpm lint ${t?P.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`,` ${n} pnpm audit ${t?P.dim("\u2192 scan deps for known CVEs"):"-> scan deps for known CVEs"}`);let a=e.previewSelections??[];if(a.length>0){let I=t?P.bold(P.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";c.push("",` ${I}`);for(let C of a){let U=rt(C.status),ue=` ${n} ${C.flag} (${C.provider}) ${U}`;c.push(t?P.yellow(ue):ue)}c.push("",` ${t?P.dim(me("foundation")):me("foundation")}`,` ${t?P.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?P.dim("See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"):"See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"}`)}let l=e.waveFeatures??{},u=I=>I!==!1,S=[];u(l.apiKeys)&&S.push("Manage API keys at /settings/api-keys"),u(l.auditLog)&&S.push("View audit log at /settings/audit-log"),S.push("Configure webhooks at /settings/webhooks"),u(l.commandPalette)&&S.push("Press Cmd/Ctrl+K to open the command palette"),S.push("Edit notification preferences at /settings/notifications"),S.push("Export your data at /settings/account/export"),l.chinaCompliance&&S.push("China deployments \u2014 see packages/ops/china-compliance/README.md"),c.push("",` ${t?P.bold("What you can do next:"):"What you can do next:"}`);for(let I of S)c.push(` ${n} ${I}`);c.push("",` ${t?P.bold("Ship faster:"):"Ship faster:"}`,` ${r} Star us https://github.com/nebutra/nebutra-sailor`,` ${s} Free license https://nebutra.com/get-license`,""),process.stdout.write(c.join(`
2
+ import"./chunk-IYWUY3VA.js";import{execSync as Vc}from"child_process";import Vr from"fs";import Kr from"path";import*as ot from"@clack/prompts";import F from"picocolors";import{Command as Hr}from"commander";import In from"fs";import Vt from"path";import{fileURLToPath as qr}from"url";function Gr(){try{let t=Vt.dirname(qr(import.meta.url));for(let n=0;n<4;n++){let o=Vt.join(t,"package.json");if(In.existsSync(o)){let r=In.readFileSync(o,"utf-8"),s=JSON.parse(r);if(s.name==="create-sailor"&&typeof s.version=="string")return s.version}t=Vt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var X=Gr();var Wr="create-sailor";function Cn(){let e=new Hr;return e.name(Wr).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(X,"-v, --version").helpOption(!1).argument("[name]","project directory",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--region <id>","global | cn | hybrid").option("--orm <id>","prisma (default, primary) | drizzle (dual-ORM: adds db-drizzle alongside Prisma \u2014 Postgres only)").option("--db <id>","postgres | mysql | sqlite | none \u2014 engine (Prisma provider)").option("--db-host <id>","local | supabase | neon | vercel-postgres | planetscale | railway | aliyun-rds | tencent-cdb | none \u2014 managed-provider (region default: supabase global, local cn)").option("--auth <id>","clerk | betterauth | nextauth | supabase | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <mode-or-ids>","topology shorthand (gateway | direct | custom | none) OR comma-separated provider ids (e.g. openai,anthropic)").option("--deploy <target>","vercel | railway | cloudflare | selfhost").option("--docs <id>","fumadocs | mintlify | docusaurus | nextra | vitepress | none").option("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | none").option("--queue <id>","qstash | bullmq | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").option("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").option("--access-gate <mode>","none | invite (default: none)").option("--cron-jobs <bool>","true | false \u2014 scaffold scheduled cron handlers (default: true)").option("--audit-log <bool>","true | false \u2014 enable /settings/audit-log + arch test (default: false \u2014 @nebutra/audit is WIP)").option("--api-keys <bool>","true | false \u2014 enable /settings/api-keys page (default: true)").option("--command-palette <bool>","true | false \u2014 enable \u2318K command palette (default: true)").option("--cookie-consent <bool>","true | false \u2014 enable GDPR/CCPA cookie banner (default: true)").option("--legal-pages <bool>","true | false \u2014 enable dynamic /legal/[slug] route (default: true)").option("--china-compliance <bool>","true | false \u2014 enable @nebutra/china-compliance + ICP footer (default: true when --region=cn, otherwise false)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--with-workflows","scaffold workflows/ (inngest + n8n + pusher stubs)").option("--with-python-backend","scaffold backends/python/ (FastAPI stub \u2014 only when TS-by-Default ADR exception applies)").option("--no-install","skip package install").option("--no-git","skip git init").option("-y, --yes","accept all defaults (non-interactive)").option("--dry-run","preview actions without writing files").option("--json","machine-readable output").option("--no-color","disable color output").option("-h, --help","show help"),e}import kn from"picocolors";var Kt=[{id:"local",name:"Local / Self-hosted Docker",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres:postgres@localhost:5432/$PROJECT",comment:"Local Postgres via docker-compose (pnpm infra:up)"}],docs:"https://www.postgresql.org/docs/",description:"Docker on localhost. You operate it.",tier:"self-hosted"},{id:"supabase",name:"Supabase",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres?sslmode=require",comment:"Supabase session pooler \u2014 use for runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://postgres:<password>@db.<project-ref>.supabase.co:5432/postgres?sslmode=require",comment:"Supabase direct \u2014 use for Prisma migrations"},{name:"NEXT_PUBLIC_SUPABASE_URL",placeholder:"https://<project>.supabase.co"},{name:"NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY",placeholder:""},{name:"NEXT_PUBLIC_SUPABASE_ANON_KEY",placeholder:""},{name:"SUPABASE_PUBLISHABLE_KEY",placeholder:""},{name:"SUPABASE_SERVICE_ROLE_KEY",placeholder:""}],docs:"https://supabase.com/docs",description:"Managed Postgres + auth/storage/realtime/edge-functions.",tier:"managed"},{id:"neon",name:"Neon",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>-pooler.<region>.neon.tech/<db>?sslmode=require",comment:"Neon pooled \u2014 runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>.<region>.neon.tech/<db>?sslmode=require",comment:"Neon direct (no -pooler) \u2014 migrations"}],docs:"https://neon.tech/docs",description:"Serverless Postgres with branching and scale-to-zero.",tier:"managed"},{id:"vercel-postgres",name:"Vercel Postgres",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"$POSTGRES_PRISMA_URL",comment:"Vercel Marketplace injects POSTGRES_PRISMA_URL automatically"},{name:"DIRECT_URL",placeholder:"$POSTGRES_URL_NON_POOLING",comment:"Vercel Marketplace injects POSTGRES_URL_NON_POOLING automatically"}],docs:"https://vercel.com/docs/storage/vercel-postgres",description:"Neon-backed, auto-provisioned via Vercel Marketplace.",tier:"managed"},{id:"planetscale",name:"PlanetScale Postgres",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres.<branch-id>:<password>@<host>.horizon.psdb.cloud:6432/postgres?sslmode=require",comment:"PlanetScale Postgres pooled/PgBouncer URL \u2014 runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://postgres.<branch-id>:<password>@<host>.horizon.psdb.cloud:5432/postgres?sslmode=require",comment:"PlanetScale Postgres direct URL \u2014 Prisma migrations"}],docs:"https://planetscale.com/docs/postgres",description:"Managed Postgres with branching; compatible with Sailor migrations.",tier:"managed"},{id:"railway",name:"Railway",region:"global",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"$DATABASE_URL",comment:"Railway service env var; injected when you link a Postgres service"}],docs:"https://docs.railway.app/databases/postgresql",description:"Generalist managed infra; standard TCP Postgres/MySQL.",tier:"managed"},{id:"aliyun-rds",name:"Aliyun RDS",region:"cn",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@<rds-instance>.rds.aliyuncs.com:5432/<db>",comment:"Aliyun RDS Postgres \u2014 internal VPC endpoint recommended"}],docs:"https://www.alibabacloud.com/help/en/rds",description:"Aliyun RDS \u2014 China compliance + intranet routing.",tier:"managed"},{id:"tencent-cdb",name:"Tencent CloudDB (CDB)",region:"cn",supportedEngines:["mysql","postgresql"],envVars:[{name:"DATABASE_URL",placeholder:"mysql://<user>:<pwd>@<cdb-instance>.tencentcdb.com:3306/<db>",comment:"Tencent CloudDB \u2014 VPC endpoint recommended"}],docs:"https://intl.cloud.tencent.com/document/product/236",description:"Tencent CloudDB \u2014 China compliance.",tier:"managed"},{id:"none",name:"None",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[],docs:"",description:"Skip database scaffolding.",tier:"self-hosted"}];function st(e){return Kt.find(t=>t.id===e)}function xn(e){return e==="cn"||e==="hybrid"?"local":"supabase"}var it=[{id:"r2",name:"Cloudflare R2",region:"global",envVars:["R2_ACCOUNT_ID","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY","R2_BUCKET"],docs:"https://developers.cloudflare.com/r2/api/s3/api/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"s3",name:"AWS S3",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_S3_REGION","S3_BUCKET"],docs:"https://docs.aws.amazon.com/s3/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"supabase-storage",name:"Supabase Storage",region:"global",envVars:["SUPABASE_URL","SUPABASE_SERVICE_ROLE_KEY","SUPABASE_BUCKET"],docs:"https://supabase.com/docs/guides/storage",pkg:"@supabase/supabase-js",pkgVersion:"^2.45.4"},{id:"aliyun-oss",name:"\u963F\u91CC\u4E91 OSS",region:"cn",envVars:["ALIYUN_OSS_ACCESS_KEY","ALIYUN_OSS_ACCESS_SECRET","ALIYUN_OSS_REGION","ALIYUN_OSS_BUCKET"],docs:"https://help.aliyun.com/product/31815.html",pkg:"ali-oss",pkgVersion:"^6.21.0"},{id:"tencent-cos",name:"\u817E\u8BAF\u4E91 COS",region:"cn",envVars:["TENCENT_COS_SECRET_ID","TENCENT_COS_SECRET_KEY","TENCENT_COS_BUCKET","TENCENT_COS_REGION"],docs:"https://cloud.tencent.com/document/product/436",pkg:"cos-nodejs-sdk-v5",pkgVersion:"^2.13.7"},{id:"qiniu",name:"\u4E03\u725B\u4E91 Kodo",region:"cn",envVars:["QINIU_ACCESS_KEY","QINIU_SECRET_KEY","QINIU_BUCKET","QINIU_DOMAIN"],docs:"https://developer.qiniu.com/kodo",pkg:"qiniu",pkgVersion:"^7.14.0"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function $t(e){let t=e==="supabase"?"supabase-storage":e;return it.some(n=>n.id===t)?t:void 0}function Rn(e){let t=$t(e);return t?it.find(n=>n.id===t):void 0}var Qc=it.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Nn(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function Yt(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 qt(e,t,n){let o=e?.trim().toLowerCase()??xn(t),r=st(o);if(!r){let i=Kt.map(a=>a.id).join(", ");throw new Error(`Unknown --db-host="${o}". Valid: ${i}`)}let s=n;return r.forcedEngine&&s!=="none"&&s!==r.forcedEngine&&(s=r.forcedEngine),{hostId:r.id,engine:s}}function Gt(e){return e==="drizzle"?"drizzle":"prisma"}function Ht(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function Wt(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 Xt(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="nextauth"||t==="next-auth"||t==="authjs"||t==="auth.js"?"nextauth":t==="supabase"||t==="supabase-auth"?"supabase":t==="none"?"none":"clerk"}var Xr=new Set(["gateway","direct","custom","none"]);function zt(e){if(!e)return!1;let t=e.trim().toLowerCase();return Xr.has(t)}function Jt(e){if(!e)return["openai"];if(zt(e))return[];let t=e.split(",").map(n=>n.trim().toLowerCase());return t.includes("none")?[]:t}function On(e,t){let n=e??t;return $t(n)??n}var Tn={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Qt(e,t){if(!e)return"fumadocs";let n=e.toLowerCase();if(n==="fumadocs"||n==="none")return n;if(n in Tn){let o=Tn[n];return t?process.stdout.write(JSON.stringify({event:"notice",kind:"docs-fallback",requested:n,effective:"fumadocs"})+`
3
+ `):process.stdout.write(kn.yellow(`\u26A0 ${o} support is coming in v1.2. Falling back to fumadocs.
4
+ `)+kn.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
5
+ `)),"fumadocs"}return"fumadocs"}function Zt(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 en(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function Ln(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:"none",mcp:"on",metering:"auto",billingMode:"usage",idp:"clerk",accessGate:"none"}}function tn(e){return e==="cn"?"wechat":"stripe"}import*as Y from"@clack/prompts";import is from"picocolors";var nn=[{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:[]}],rp=nn.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var zr=["openai","anthropic","google"],Jr=["openai"];function on(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let n=t.length>0?t:[...zr];return{mode:"gateway",providerIds:n,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:n,runtimeGovernance:!0}}}case"direct":{let n=t.length>0?t:[...Jr];return{mode:"direct",providerIds:n,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:n,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}var We=[{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"}],Qr=new Set(We.map(e=>e.id));function Un(e){return We.find(t=>t.id===e)}function Mn(e){if(!e)return[];let t=e.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean);if(t.includes("none"))return[];let n=[],o=new Set;for(let r of t)Qr.has(r)&&!o.has(r)&&(n.push(r),o.add(r));return n}import ee from"fs";import T from"path";import{fileURLToPath as Zr}from"url";var es=Zr(import.meta.url),Dn=T.dirname(es),ts={web:"vercel","landing-page":"vercel","design-docs":"vercel","sailor-docs":"vercel",gateway:"cloudflare-workers","python-ai":"ecs-docker"};function ns(){let e=[T.join(Dn,"..","templates","deploy"),T.join(Dn,"..","..","templates","deploy")];for(let t of e)if(ee.existsSync(t))return t;return e[0]}function jn(e){switch(e){case"cloudflare":return{web:"cloudflare-pages","landing-page":"cloudflare-pages","design-docs":"cloudflare-pages","sailor-docs":"cloudflare-pages",gateway:"cloudflare-workers","python-ai":"ecs-docker"};case"selfhost":return{web:"standalone","landing-page":"standalone","design-docs":"standalone","sailor-docs":"standalone",gateway:"ecs-docker","python-ai":"ecs-docker"};case"railway":return{web:"railway","landing-page":"railway","design-docs":"railway","sailor-docs":"railway",gateway:"railway","python-ai":"railway"};case"none":case"vercel":return{...ts}}}function os(e){return`DEPLOY_TARGET_${e.toUpperCase().replace(/-/g,"_")}`}async function Fn(e,t){let n=T.join(e,"backends","gateway");ee.existsSync(n)&&await ee.promises.copyFile(T.join(t,"wrangler.gateway.toml"),T.join(n,"wrangler.toml"))}async function Bn(e,t){let n=T.join(e,".env.example"),o;try{o=await ee.promises.readFile(n,"utf8")}catch(i){if(i.code==="ENOENT")return;throw i}if(o.includes("# Deployment Targets"))return;let s=["","# Deployment Targets",...Object.entries(t).map(([i,a])=>`${os(i)}="${a}"`)].join(`
6
+ `);await ee.promises.appendFile(n,`${s}
7
+ `)}async function Vn(e,t){if(t==="none")return;let n=ns();t==="vercel"?(await ee.promises.copyFile(T.join(n,"vercel.json"),T.join(e,"vercel.json")),await Fn(e,n)):t==="railway"?await ee.promises.copyFile(T.join(n,"railway.toml"),T.join(e,"railway.toml")):t==="cloudflare"?(await ee.promises.copyFile(T.join(n,"wrangler.toml"),T.join(e,"wrangler.toml")),await Fn(e,n)):t==="selfhost"&&(await ee.promises.copyFile(T.join(n,"docker-compose.yml"),T.join(e,"docker-compose.yml")),await ee.promises.copyFile(T.join(n,"Dockerfile.web"),T.join(e,"Dockerfile.web")))}var rs={qstash:"foundation",bullmq:"foundation",upstash:"foundation",sqs:"foundation",meilisearch:"foundation",typesense:"foundation",algolia:"foundation",pgvector:"foundation","vercel-flags":"foundation",growthbook:"foundation",configcat:"foundation",turnstile:"wip",hcaptcha:"wip","aliyun-slide":"wip",invite:"foundation"};function ss(e){return e?rs[e]??"stable":"stable"}function Xe(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function he(e){switch(e){case"stable":return"Production-ready.";case"foundation":return"Foundation status \u2014 core contracts work, but production use still requires provider credentials, adapter wiring, or a verified integration contract.";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 Kn(e){let t=[];for(let{flag:n,provider:o}of e){if(!o||o==="none")continue;let r=ss(o);r!=="stable"&&t.push({flag:n,provider:o,status:r})}return t}function Ee(e,t){if(e===void 0)return t;let n=String(e).trim().toLowerCase();return n==="true"||n==="1"||n==="yes"||n==="on"?!0:n==="false"||n==="0"||n==="no"||n==="off"?!1:t}function $n(e,t){let n=t==="cn";return{cronJobs:Ee(e.cronJobs,!0),auditLog:Ee(e.auditLog,!1),apiKeys:Ee(e.apiKeys,!0),webhooks:Ee(e.webhooks,!0),commandPalette:Ee(e.commandPalette,!0),cookieConsent:Ee(e.cookieConsent,!0),legalPages:Ee(e.legalPages,!0),chinaCompliance:Ee(e.chinaCompliance,n)}}async function as(e,t,n,o){let r={};return t||(r.region=()=>Y.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"})),n||(r.auth=()=>Y.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk",hint:"managed, fastest setup"},{value:"betterauth",label:"Better Auth",hint:"self-hosted, modern (2FA / passkeys / RBAC)"},{value:"nextauth",label:"NextAuth (Auth.js v5)",hint:"self-hosted, mature, large ecosystem"},{value:"supabase",label:"Supabase Auth",hint:"managed auth with Supabase storage/realtime ecosystem"},{value:"none",label:"None"}],initialValue:"clerk"})),o||(r.aiMode=()=>Y.select({message:"AI topology?",options:[{value:"gateway",label:"Multi-provider AI Gateway / router",hint:"recommended"},{value:"direct",label:"Direct SDK/provider adapters"},{value:"custom",label:"OpenAI-compatible endpoint"},{value:"none",label:"Skip AI"}],initialValue:"gateway"}),r.aiProviders=({results:s})=>{if(s.aiMode!=="direct")return Promise.resolve([]);let i=nn.map(a=>({value:a.id,label:`[${a.category}] ${a.name}`}));return Y.multiselect({message:"Select direct AI provider adapters (expert path)",options:i,initialValues:["openai"],required:!1})},r.customAiName=({results:s})=>s.aiMode==="custom"?Y.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),r.customAiBaseUrl=({results:s})=>s.aiMode==="custom"?Y.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:i=>{if(!i?.length)return"Base URL is required."}}):Promise.resolve(void 0),r.customAiApiKeyEnv=({results:s})=>s.aiMode==="custom"?Y.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0)),Object.keys(r).length===0?{}:await Y.group(r,{onCancel:()=>{process.stdout.write(is.red(`\u2718 Cancelled
8
+ `)),process.exit(130)}})}async function Yn(e,t){let n=!!e.region,o=!!e.auth,r=!!e.payment,s=!!e.ai,i=!!e.email,a=!!e.storage,c=!!e.monitoring,p=!!e.analytics,u=!!e.sms,d=e.i18n!==void 0,h=!!e.yes||!process.stdin.isTTY,f,E,S,m,P,G,M,ge=Mn(e.socialLogin),pe,Z,j,K,C,H,le;if(h){f=en(e.region),E=Gt(e.orm);{let $=Yt(e.db),yt=qt(e.dbHost,f,$);S=yt.engine,m=yt.hostId}let W=r?e.payment:tn(f);P=Ht(W),G=Wt(W),M=Xt(e.auth);let He="gateway";if(s){let $=e.ai?.trim().toLowerCase()??"";zt($)?He=$:He="direct"}let rt=on({mode:He,providerIds:s?Jt(e.ai):void 0});pe=rt.mode,Z=rt.routing,j=rt.providerIds,C=Zt(e.deploy),H=Qt(e.docs,t),le=d?!!e.i18n:!0}else{let W=await as(e,n,o,s);f=en(n?e.region:W.region),E=Gt(e.orm);{let yt=Yt(e.db),An=qt(e.dbHost,f,yt);S=An.engine,m=An.hostId}let He=r?e.payment:tn(f);P=Ht(He),G=Wt(He),M=Xt(o?e.auth:W.auth);let rt=W.aiMode==="custom"?{name:W.customAiName??"custom",baseURL:W.customAiBaseUrl??"",apiKeyEnvName:W.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,$=on({mode:s?e.ai?.trim().toLowerCase()==="none"?"none":"direct":W.aiMode??"gateway",providerIds:s?Jt(e.ai):W.aiProviders,customEndpoint:rt});pe=$.mode,Z=$.routing,j=$.providerIds,$.customEndpoint&&(K={name:$.customEndpoint.name,baseURL:$.customEndpoint.baseURL,apiKeyEnvName:$.customEndpoint.apiKeyEnvName}),C=Zt(e.deploy),H=Qt(e.docs,t),le=d?!!e.i18n:!0}let w=Ln(f),fe=i?e.email:w.email,qe=On(a?e.storage:void 0,w.storage),Ge=c?e.monitoring:w.monitoring,ye=p?e.analytics:w.analytics,v=u?e.sms:w.sms,k=e.queue??w.queue,I=e.search??w.search,x=e.cache??w.cache,Mt=e.notifications??w.notifications,Dt=e.webhooks??w.webhooks,En=e.cms??w.cms,Ft=e.featureFlags??w.featureFlags,jt=e.captcha??w.captcha,vn=e.mcp??w.mcp,bn=e.metering??w.metering,_n=e.billingMode??w.billingMode,Pn=e.idp??w.idp,Bt=e.accessGate==="invite"?"invite":w.accessGate,wn=jn(C),Se=$n({cronJobs:e.cronJobs,auditLog:e.auditLog,apiKeys:e.apiKeys,commandPalette:e.commandPalette,cookieConsent:e.cookieConsent,legalPages:e.legalPages,chinaCompliance:e.chinaCompliance},f),$r=Kn([{flag:"queue",provider:k},{flag:"search",provider:I},{flag:"notifications",provider:Mt},{flag:"webhooks",provider:Dt},{flag:"feature-flags",provider:Ft},{flag:"captcha",provider:jt},{flag:"access-gate",provider:Bt}]),Yr={region:f,orm:E,database:S,databaseHost:m,payment:P,aiMode:pe,aiRouting:Z,aiProviders:j,customAiEndpoint:K,deployTarget:C,deployTargets:wn,docs:H,i18n:le,email:fe,storage:qe,monitoring:Ge,analytics:ye,sms:v,queue:k,search:I,cache:x,notifications:Mt,webhooks:Dt,cms:En,featureFlags:Ft,captcha:jt,mcp:vn,metering:bn,billingMode:_n,idp:Pn,accessGate:Bt,cronJobs:Se.cronJobs,auditLog:Se.auditLog,apiKeys:Se.apiKeys,commandPalette:Se.commandPalette,cookieConsent:Se.cookieConsent,legalPages:Se.legalPages,chinaCompliance:Se.chinaCompliance};return{region:f,orm:E,database:S,databaseHost:m,payment:P,paymentChoice:G,auth:M,socialLoginIds:ge,aiMode:pe,aiRouting:Z,aiProviders:j,customAiEndpoint:K,deployTarget:C,deployTargets:wn,docs:H,i18n:le,email:fe,storage:qe,monitoring:Ge,analytics:ye,sms:v,queue:k,search:I,cache:x,notifications:Mt,webhooks:Dt,cms:En,featureFlags:Ft,captcha:jt,mcp:vn,metering:bn,billingMode:_n,idp:Pn,accessGate:Bt,waveToggles:Se,previewSelections:$r,config:Yr}}import{execFileSync as Ot}from"child_process";import Lt from"fs";import $e from"path";import gt from"picocolors";import kc from"update-notifier";import A from"picocolors";function cs(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function qn(e){let t=cs(),n=t?"\u2693":"-",o=t?"\u25B8":"->",r=t?"\u2605":"*",s=t?"\u{1F4E7}":"*",a=["",` ${t?A.bold(`${n} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`):`${n} Done in ${e.elapsedSec}s \xB7 ${e.targetDir}/`}`,"",` ${t?A.bold("Next:"):"Next:"}`,` ${o} cd ${e.targetDir}`];e.skippedInstall&&a.push(` ${o} pnpm install (if --no-install was set)`),a.push(` ${o} fill in .env.local ${t?A.dim("\u2192 add provider keys before booting apps"):"-> add provider keys before booting apps"}`,` ${o} pnpm db:migrate ${t?A.dim("\u2192 sync Prisma schema"):"-> sync Prisma schema"}`,` ${o} pnpm db:seed ${t?A.dim("\u2192 load example tenants and records"):"-> load example tenants and records"}`,` ${o} pnpm dev ${t?A.dim("\u2192 http://localhost:3000"):"-> http://localhost:3000"}`,"",` ${t?A.bold("Customize:"):"Customize:"}`,` ${o} pnpm brand:init ${t?A.dim("\u2192 create brand.config.ts"):"-> create brand.config.ts"}`,` ${o} pnpm brand:apply ${t?A.dim("\u2192 propagate brand changes"):"-> propagate brand changes"}`,` ${o} pnpm preset:env ${t?A.dim("\u2192 review preset env requirements"):"-> review preset env requirements"}`,"",` ${t?A.bold("Useful scripts:"):"Useful scripts:"}`,` ${o} pnpm infra:up ${t?A.dim("\u2192 start local PostgreSQL/Redis/ClickHouse"):"-> start local PostgreSQL/Redis/ClickHouse"}`,` ${o} pnpm generate:api-types ${t?A.dim("\u2192 refresh shared API client types"):"-> refresh shared API client types"}`,` ${o} pnpm lint ${t?A.dim("\u2192 quick repo sanity check"):"-> quick repo sanity check"}`,` ${o} pnpm audit ${t?A.dim("\u2192 scan deps for known CVEs"):"-> scan deps for known CVEs"}`);let c=e.previewSelections??[];if(c.length>0){let _=t?A.bold(A.yellow("\u26A0 Preview features selected:")):"!! Preview features selected:";a.push("",` ${_}`);for(let h of c){let f=Xe(h.status),E=` ${o} ${h.flag} (${h.provider}) ${f}`;a.push(t?A.yellow(E):E)}a.push("",` ${t?A.dim(he("foundation")):he("foundation")}`,` ${t?A.dim("You may need to contribute the provider integration yourself."):"You may need to contribute the provider integration yourself."}`,` ${t?A.dim("See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"):"See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md"}`)}let p=e.waveFeatures??{},u=_=>_!==!1,d=[];u(p.apiKeys)&&d.push("Manage API keys at /settings/api-keys"),u(p.auditLog)&&d.push("View audit log at /settings/audit-log"),d.push("Configure webhooks at /settings/webhooks"),u(p.commandPalette)&&d.push("Press Cmd/Ctrl+K to open the command palette"),d.push("Edit notification preferences at /settings/notifications"),d.push("Export your data at /settings/account/export"),p.chinaCompliance&&d.push("China deployments \u2014 see packages/ops/china-compliance/README.md"),a.push("",` ${t?A.bold("What you can do next:"):"What you can do next:"}`);for(let _ of d)a.push(` ${o} ${_}`);a.push("",` ${t?A.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(a.join(`
6
9
  `)+`
7
- `)}var Gr=`Usage: create-sailor [name] [options]
8
-
9
- Arguments:
10
- name project directory (default: ./my-saas-app)
11
-
12
- Core options:
13
- -p, --pm <id> npm | pnpm | yarn | bun (auto-detected)
14
- --region <id> global | cn | hybrid (default: global)
15
- --auth <id> clerk | betterauth | nextauth | supabase | none
16
- --ai <ids> expert/non-interactive provider seed (e.g. openai,anthropic)
17
-
18
- Interactive AI topology:
19
- Default first-run asks for topology, not individual provider enablement:
20
- gateway Multi-provider AI Gateway / router (recommended)
21
- direct Direct SDK/provider adapters
22
- custom OpenAI-compatible endpoint
23
- none Skip AI
24
-
25
- Stack flags (region-based smart defaults):
26
- --orm <id> prisma | drizzle | none (default: prisma)
27
- --db <id> postgres | mysql | sqlite | none (default: postgres)
28
- --payment <id> stripe | lemon | wechat | alipay | none (default: region-based)
29
- --deploy <target> vercel | railway | cloudflare | selfhost (default: vercel)
30
- --docs <id> fumadocs | mintlify | docusaurus | nextra | vitepress | none
31
-
32
- Feature flags (region-based smart defaults):
33
- --email <id> resend | postmark | ses | aliyun-dm | tencent-ses | netease | none
34
- --storage <id> r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none
35
- --monitoring <id> sentry | datadog | aliyun-arms | tingyun | none
36
- --analytics <id> posthog | plausible | umami | baidu | sensors | none
37
- --sms <id> twilio | aliyun-sms | tencent-sms | yunpian | none
38
- --queue <id> qstash | bullmq | upstash | sqs | none [Foundation]
39
- --search <id> meilisearch | typesense | algolia | pgvector | none [Foundation]
40
- --cache <id> upstash-redis | vercel-kv | redis | dragonfly | none
41
- --notifications <id> novu | knock | custom | none [Foundation]
42
- --webhooks <id> svix | custom | none [Foundation]
43
- --cms <id> sanity | contentful | strapi | none
44
- --feature-flags <id> vercel-flags | growthbook | configcat | none [WIP]
45
- --captcha <id> turnstile | hcaptcha | aliyun-slide | none [WIP]
46
- --billing-mode <mode> usage | seat | credits (default: usage)
47
- --idp <id> clerk | oauth-server (default: clerk)
48
- --access-gate <mode> none | invite (default: none)
49
-
50
- Preview statuses:
51
- [Foundation] \u2014 types + factory complete; adapters need external credentials & may not work out-of-the-box
52
- [WIP] \u2014 actively being built; do not use in production
53
- See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md
54
-
55
- Sailor features:
56
- --mcp <mode> on | off (default: on \u2014 Agent-friendly MCP server)
57
- --metering <mode> auto | on | off (default: auto)
58
-
59
- Toggles:
60
- --i18n enable i18n (default: true)
61
- --no-i18n disable
62
- --no-install skip package install
63
- --no-git skip git init
64
- -y, --yes accept all defaults (non-interactive)
65
- --dry-run preview actions without writing files
66
- --json machine-readable output
67
- --no-color disable color output
68
- -h, --help show this help
69
- -v, --version show version
70
-
71
- Examples:
72
- $ npx create-sailor@latest
73
- $ npx create-sailor@latest my-app -y
74
- $ npx create-sailor@latest my-app --region=cn --auth=clerk
75
- $ npx create-sailor@latest my-app --region=hybrid --ai=openai,deepseek
76
- $ npm create sailor@latest --dry-run --region=cn
77
- `;function Cn(){process.stdout.write(Gr)}import Ut from"picocolors";function In(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Hr(e){let t=In()?"\u25B8":"->",o=`[${e.index}/${e.total}]`,n=e.label.padEnd(18," ");return In()?`${Ut.dim(o)} ${Ut.bold(n)} ${Ut.dim(t)} ${Ut.cyan(e.value)}`:`${o} ${n} ${t} ${e.value}`}function wn(e){process.stdout.write(Hr(e)+`
78
- `)}var nn=[{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:[]}],Nc=nn.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var Wr=["openai","anthropic","google"],Xr=["openai"];function on(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let o=t.length>0?t:[...Wr];return{mode:"gateway",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:o,runtimeGovernance:!0}}}case"direct":{let o=t.length>0?t:[...Xr];return{mode:"direct",providerIds:o,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:o,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}import st from"fs";import B from"path";var Rn=[{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:""}],Lc=Rn.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function kn(e){return Rn.find(t=>t.id===e)}function zr(e){st.mkdirSync(e,{recursive:!0})}function Z(e,t){zr(B.dirname(e)),st.writeFileSync(e,t)}function Ce(e,t){let o=B.join(e,".env.example");st.existsSync(o)?st.appendFileSync(o,`
79
- `+t):st.writeFileSync(o,t)}function Jr(e){let t=`"use client";
10
+ `)}import ze from"fs";import B from"path";var Gn=[{id:"posthog",name:"PostHog",region:"both",envVars:["POSTHOG_KEY","POSTHOG_HOST","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:""}],Cp=Gn.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Hn(e){return Gn.find(t=>t.id===e)}function ps(e){ze.mkdirSync(e,{recursive:!0})}function te(e,t){ps(B.dirname(e)),ze.writeFileSync(e,t)}function Ie(e,t){let n=B.join(e,".env.example");ze.existsSync(n)?ze.appendFileSync(n,`
11
+ `+t):ze.writeFileSync(n,t)}function ls(e){let t=`"use client";
80
12
  /**
81
13
  * PostHog browser SDK \u2014 lazy-initialized on first access.
82
14
  */
@@ -101,7 +33,7 @@ export function initPostHog(): void {
101
33
  }
102
34
 
103
35
  export { posthog };
104
- `,o=`import { PostHog } from "posthog-node";
36
+ `,n=`import { PostHog } from "posthog-node";
105
37
 
106
38
  /**
107
39
  * PostHog server-side client. Remember to await client.shutdown() at the end
@@ -115,7 +47,7 @@ export function getPostHogServerClient(): PostHog | null {
115
47
  if (!key) return null;
116
48
 
117
49
  client = new PostHog(key, {
118
- host: process.env.NEXT_PUBLIC_POSTHOG_HOST ?? "https://us.i.posthog.com",
50
+ host: process.env.POSTHOG_HOST ?? process.env.NEXT_PUBLIC_POSTHOG_HOST ?? "https://us.i.posthog.com",
119
51
  flushAt: 1,
120
52
  flushInterval: 0,
121
53
  });
@@ -132,7 +64,7 @@ export async function captureServerEvent(
132
64
  ph.capture({ distinctId, event, properties });
133
65
  await ph.shutdown();
134
66
  }
135
- `,n=`"use client";
67
+ `,o=`"use client";
136
68
  /**
137
69
  * <AnalyticsProvider /> \u2014 wrap the app root to enable PostHog + auto page views.
138
70
  */
@@ -159,11 +91,12 @@ export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
159
91
 
160
92
  return <>{children}</>;
161
93
  }
162
- `;Z(B.join(e,"src","lib","analytics","posthog.client.ts"),t),Z(B.join(e,"src","lib","analytics","posthog.server.ts"),o),Z(B.join(e,"src","components","analytics","AnalyticsProvider.tsx"),n)}function Qr(){return`# PostHog \u2014 product analytics
94
+ `;te(B.join(e,"src","lib","analytics","posthog.client.ts"),t),te(B.join(e,"src","lib","analytics","posthog.server.ts"),n),te(B.join(e,"src","components","analytics","AnalyticsProvider.tsx"),o)}function ds(){return`# PostHog \u2014 product analytics
163
95
  POSTHOG_KEY=
96
+ POSTHOG_HOST=https://us.i.posthog.com
164
97
  NEXT_PUBLIC_POSTHOG_KEY=
165
98
  NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
166
- `}function Zr(e){Z(B.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
99
+ `}function us(e){te(B.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
167
100
  /**
168
101
  * Plausible script tag \u2014 lightweight, privacy-friendly analytics.
169
102
  */
@@ -183,10 +116,10 @@ export function PlausibleScript() {
183
116
  />
184
117
  );
185
118
  }
186
- `)}function es(){return`# Plausible \u2014 privacy-friendly analytics
119
+ `)}function ms(){return`# Plausible \u2014 privacy-friendly analytics
187
120
  NEXT_PUBLIC_PLAUSIBLE_DOMAIN=
188
121
  NEXT_PUBLIC_PLAUSIBLE_SRC=https://plausible.io/js/script.js
189
- `}function ts(e){Z(B.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
122
+ `}function gs(e){te(B.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
190
123
  /**
191
124
  * Umami analytics \u2014 self-hosted OR umami.is cloud.
192
125
  */
@@ -206,10 +139,10 @@ export function UmamiScript() {
206
139
  />
207
140
  );
208
141
  }
209
- `)}function ns(){return`# Umami \u2014 self-hostable analytics
142
+ `)}function fs(){return`# Umami \u2014 self-hostable analytics
210
143
  NEXT_PUBLIC_UMAMI_WEBSITE_ID=
211
144
  NEXT_PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
212
- `}function os(e){let t=`"use client";
145
+ `}function ys(e){let t=`"use client";
213
146
  import mixpanel from "mixpanel-browser";
214
147
 
215
148
  let initialized = false;
@@ -227,7 +160,7 @@ export function initMixpanel(): void {
227
160
  }
228
161
 
229
162
  export { mixpanel };
230
- `,o=`import Mixpanel from "mixpanel";
163
+ `,n=`import Mixpanel from "mixpanel";
231
164
 
232
165
  let client: Mixpanel.Mixpanel | null = null;
233
166
 
@@ -248,10 +181,10 @@ export function trackServer(
248
181
  if (!c) return;
249
182
  c.track(event, { distinct_id: distinctId, ...properties });
250
183
  }
251
- `;Z(B.join(e,"src","lib","analytics","mixpanel.client.ts"),t),Z(B.join(e,"src","lib","analytics","mixpanel.server.ts"),o)}function rs(){return`# Mixpanel \u2014 product analytics
184
+ `;te(B.join(e,"src","lib","analytics","mixpanel.client.ts"),t),te(B.join(e,"src","lib","analytics","mixpanel.server.ts"),n)}function Ss(){return`# Mixpanel \u2014 product analytics
252
185
  MIXPANEL_TOKEN=
253
186
  NEXT_PUBLIC_MIXPANEL_TOKEN=
254
- `}function ss(e){Z(B.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
187
+ `}function hs(e){te(B.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
255
188
  /**
256
189
  * \u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji \u2014 hm.js \u57CB\u70B9\u811A\u672C.
257
190
  */
@@ -277,9 +210,9 @@ var _hmt = _hmt || [];
277
210
  />
278
211
  );
279
212
  }
280
- `)}function is(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
213
+ `)}function Es(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
281
214
  NEXT_PUBLIC_BAIDU_STATS_ID=
282
- `}function as(e){Z(B.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
215
+ `}function vs(e){te(B.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
283
216
  /**
284
217
  * \u795E\u7B56\u5206\u6790 (Sensors Analytics) \u2014 sa-sdk-javascript \u5C01\u88C5.
285
218
  */
@@ -307,10 +240,10 @@ export function initSensors(): void {
307
240
  }
308
241
 
309
242
  export { sensors };
310
- `)}function cs(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
243
+ `)}function bs(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
311
244
  NEXT_PUBLIC_SENSORS_SERVER_URL=
312
245
  NEXT_PUBLIC_SENSORS_APP_JS_URL=
313
- `}function ps(e){Z(B.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
246
+ `}function _s(e){te(B.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
314
247
  /**
315
248
  * GrowingIO CDP \u2014 inline snippet installer.
316
249
  */
@@ -335,21 +268,21 @@ gdp("send");
335
268
  />
336
269
  );
337
270
  }
338
- `)}function ls(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
271
+ `)}function Ps(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
339
272
  NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
340
- `}async function xn(e,t,o="global"){let n=kn(t);if(!n||n.id==="none")return;let r=B.join(e,"apps","web");if(!st.existsSync(r))return;let s=n.id;try{switch(s){case"posthog":Jr(r),Ce(e,Qr());return;case"plausible":Zr(r),Ce(e,es());return;case"umami":ts(r),Ce(e,ns());return;case"mixpanel":os(r),Ce(e,rs());return;case"baidu":ss(r),Ce(e,is());return;case"sensors":as(r),Ce(e,cs());return;case"growingio":ps(r),Ce(e,ls());return;default:return}}catch(i){throw console.error(`Failed to apply analytics selection "${t}":`,i),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var ds="https://analytics.nebutra.com";function us(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function Nn(e,t={}){us(t)||(async()=>{try{let o=await import("@nebutra/analytics");if(typeof o.createAnalyticsClient!="function")return;let n=o.createAnalyticsClient({posthog:{apiKey:process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.NEBUTRA_POSTHOG_HOST??ds},onError:()=>{}});if(typeof n?.track!="function")return;let r=n.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import q from"fs";import x from"path";function K(e){q.existsSync(e)&&q.rmSync(e,{recursive:!0,force:!0})}function Mt(e,t){let o=x.join(e,".env.example");q.existsSync(o)?q.appendFileSync(o,`
341
- `+t):q.writeFileSync(o,t)}function Dt(e,t){if(!q.existsSync(e))return;let o=q.readFileSync(e,"utf8"),n=o.replace(/export type AuthProviderId\s*=\s*(?:"[^"]+"\s*\|\s*)+"[^"]+";/,`export type AuthProviderId = "${t}";`);n!==o&&q.writeFileSync(e,n)}function ms(e,t){let o=x.join(e,"README.md");if(!q.existsSync(o)){q.writeFileSync(o,t);return}q.appendFileSync(o,`
342
- `+t)}async function Tn(e,t){let o=x.join(e,"packages","iam","auth");if(!q.existsSync(o))return;if(t==="none"){K(o),ms(e,`
273
+ `}async function Wn(e,t,n="global"){let o=Hn(t);if(!o||o.id==="none")return;let r=B.join(e,"apps","web");if(!ze.existsSync(r))return;let s=o.id;try{switch(s){case"posthog":ls(r),Ie(e,ds());return;case"plausible":us(r),Ie(e,ms());return;case"umami":gs(r),Ie(e,fs());return;case"mixpanel":ys(r),Ie(e,Ss());return;case"baidu":hs(r),Ie(e,Es());return;case"sensors":vs(r),Ie(e,bs());return;case"growingio":_s(r),Ie(e,Ps());return;default:return}}catch(i){throw console.error(`Failed to apply analytics selection "${t}":`,i),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var ws="https://analytics.nebutra.com";function As(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function Xn(e,t={}){As(t)||(async()=>{try{let n=await import("./dist-NJH3URWV.js");if(typeof n.createProductAnalyticsClient!="function")return;let o=n.createProductAnalyticsClient({posthog:{apiKey:process.env.POSTHOG_KEY??process.env.NEXT_PUBLIC_POSTHOG_KEY??process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.POSTHOG_HOST??process.env.NEXT_PUBLIC_POSTHOG_HOST??process.env.NEBUTRA_POSTHOG_HOST??ws},onError:()=>{}});if(typeof o?.track!="function")return;let r=o.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import q from"fs";import N from"path";function V(e){q.existsSync(e)&&q.rmSync(e,{recursive:!0,force:!0})}function St(e,t){let n=N.join(e,".env.example");q.existsSync(n)?q.appendFileSync(n,`
274
+ `+t):q.writeFileSync(n,t)}function ht(e,t){if(!q.existsSync(e))return;let n=q.readFileSync(e,"utf8"),o=n.replace(/export type AuthProviderId\s*=\s*(?:"[^"]+"\s*\|\s*)+"[^"]+";/,`export type AuthProviderId = "${t}";`);o!==n&&q.writeFileSync(e,o)}function Is(e,t){let n=N.join(e,"README.md");if(!q.existsSync(n)){q.writeFileSync(n,t);return}q.appendFileSync(n,`
275
+ `+t)}async function zn(e,t){let n=N.join(e,"packages","iam","auth");if(!q.existsSync(n))return;if(t==="none"){V(n),Is(e,`
343
276
  ## Auth
344
277
 
345
278
  Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth, Supabase).
346
- `);return}let n=x.join(o,"src","providers"),r=x.join(o,"src","types.ts");if(t==="clerk"){K(x.join(n,"better-auth.ts")),K(x.join(n,"nextauth.ts")),K(x.join(n,"supabase.ts")),Dt(r,"clerk"),Mt(e,`# Clerk auth
279
+ `);return}let o=N.join(n,"src","providers"),r=N.join(n,"src","types.ts");if(t==="clerk"){V(N.join(o,"better-auth.ts")),V(N.join(o,"nextauth.ts")),V(N.join(o,"supabase.ts")),ht(r,"clerk"),St(e,`# Clerk auth
347
280
  CLERK_PUBLISHABLE_KEY=
348
281
  CLERK_SECRET_KEY=
349
- `);return}if(t==="betterauth"){K(x.join(n,"clerk.ts")),K(x.join(n,"nextauth.ts")),K(x.join(n,"supabase.ts")),Dt(r,"better-auth"),Mt(e,`# Better Auth
282
+ `);return}if(t==="betterauth"){V(N.join(o,"clerk.ts")),V(N.join(o,"nextauth.ts")),V(N.join(o,"supabase.ts")),ht(r,"better-auth"),St(e,`# Better Auth
350
283
  BETTER_AUTH_SECRET=
351
284
  BETTER_AUTH_URL=http://localhost:3000
352
- `);return}if(t==="nextauth"){K(x.join(n,"clerk.ts")),K(x.join(n,"better-auth.ts")),K(x.join(n,"supabase.ts")),Dt(r,"nextauth"),Mt(e,`# NextAuth (Auth.js v5)
285
+ `);return}if(t==="nextauth"){V(N.join(o,"clerk.ts")),V(N.join(o,"better-auth.ts")),V(N.join(o,"supabase.ts")),ht(r,"nextauth"),St(e,`# NextAuth (Auth.js v5)
353
286
  AUTH_SECRET=
354
287
  NEXTAUTH_URL=http://localhost:3000
355
288
  # OAuth (optional \u2014 leave blank to disable that provider)
@@ -357,16 +290,18 @@ GOOGLE_CLIENT_ID=
357
290
  GOOGLE_CLIENT_SECRET=
358
291
  GITHUB_CLIENT_ID=
359
292
  GITHUB_CLIENT_SECRET=
360
- `);return}if(t==="supabase"){K(x.join(n,"clerk.ts")),K(x.join(n,"better-auth.ts")),K(x.join(n,"nextauth.ts")),Dt(r,"supabase"),Mt(e,`# Supabase Auth
293
+ `);return}if(t==="supabase"){V(N.join(o,"clerk.ts")),V(N.join(o,"better-auth.ts")),V(N.join(o,"nextauth.ts")),ht(r,"supabase"),St(e,`# Supabase Auth
361
294
  NEXT_PUBLIC_SUPABASE_URL=
295
+ NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
362
296
  NEXT_PUBLIC_SUPABASE_ANON_KEY=
363
297
  SUPABASE_URL=
298
+ SUPABASE_PUBLISHABLE_KEY=
364
299
  SUPABASE_ANON_KEY=
365
300
  SUPABASE_SERVICE_ROLE_KEY=
366
- `);return}}var Et=[{id:"wechat",name:"\u5FAE\u4FE1\u5F00\u653E\u5E73\u53F0",region:"cn",envVars:["WECHAT_APP_ID","WECHAT_APP_SECRET"],docs:"https://open.weixin.qq.com/cgi-bin/showdocument",callbackUrl:"/api/auth/callback/wechat",tokenEndpoint:"https://api.weixin.qq.com/sns/oauth2/access_token"},{id:"qq",name:"QQ \u767B\u5F55",region:"cn",envVars:["QQ_APP_ID","QQ_APP_KEY"],docs:"https://wiki.connect.qq.com",callbackUrl:"/api/auth/callback/qq",tokenEndpoint:"https://graph.qq.com/oauth2.0/token"},{id:"dingtalk",name:"\u9489\u9489",region:"cn",envVars:["DINGTALK_APP_ID","DINGTALK_APP_SECRET"],docs:"https://open.dingtalk.com/document/",callbackUrl:"/api/auth/callback/dingtalk",tokenEndpoint:"https://api.dingtalk.com/v1.0/oauth2/userAccessToken"},{id:"workweixin",name:"\u4F01\u4E1A\u5FAE\u4FE1",region:"cn",envVars:["WORKWEIXIN_CORP_ID","WORKWEIXIN_AGENT_ID","WORKWEIXIN_SECRET"],docs:"https://developer.work.weixin.qq.com",callbackUrl:"/api/auth/callback/workweixin",tokenEndpoint:"https://qyapi.weixin.qq.com/cgi-bin/gettoken"},{id:"feishu",name:"\u98DE\u4E66 / Lark",region:"cn",envVars:["FEISHU_APP_ID","FEISHU_APP_SECRET"],docs:"https://open.feishu.cn/document/",callbackUrl:"/api/auth/callback/feishu",tokenEndpoint:"https://open.feishu.cn/open-apis/authen/v1/access_token"},{id:"weibo",name:"\u5FAE\u535A",region:"cn",envVars:["WEIBO_APP_KEY","WEIBO_APP_SECRET"],docs:"https://open.weibo.com/wiki/",callbackUrl:"/api/auth/callback/weibo",tokenEndpoint:"https://api.weibo.com/oauth2/access_token"}],gs=new Set(Et.map(e=>e.id));function On(e){return Et.find(t=>t.id===e)}function Ln(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)gs.has(r)&&!n.has(r)&&(o.push(r),n.add(r));return o}import we from"fs";import Ie from"path";function fs(e,t){let o=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
301
+ `);return}}import xe from"fs";import Ce from"path";function Cs(e,t){let n=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
367
302
  // Generated by create-sailor \u2014 OAuth callback for ${e.name}
368
303
  // Primary auth provider: ${t}
369
- // Docs: ${e.docs}`,n={wechat:` const tokenRes = await fetch(
304
+ // Docs: ${e.docs}`,o={wechat:` const tokenRes = await fetch(
370
305
  "${e.tokenEndpoint}?" +
371
306
  new URLSearchParams({
372
307
  appid: process.env.WECHAT_APP_ID ?? "",
@@ -467,7 +402,7 @@ SUPABASE_SERVICE_ROLE_KEY=
467
402
  const token = (await tokenRes.json()) as { access_token?: string; uid?: string };
468
403
  if (!token.access_token) {
469
404
  return NextResponse.redirect(new URL("/login?error=weibo_token", req.url));
470
- }`};return`${o}
405
+ }`};return`${n}
471
406
  import { type NextRequest, NextResponse } from "next/server";
472
407
 
473
408
  export async function GET(req: NextRequest) {
@@ -478,7 +413,7 @@ export async function GET(req: NextRequest) {
478
413
  return NextResponse.redirect(new URL("/login?error=no_code", req.url));
479
414
  }
480
415
 
481
- ${n[e.id]}
416
+ ${o[e.id]}
482
417
 
483
418
  // TODO: fetch user profile from ${e.name} using the access token.
484
419
  // TODO: upsert the user into your primary auth provider (${t}).
@@ -488,7 +423,7 @@ ${n[e.id]}
488
423
  void state;
489
424
  return NextResponse.redirect(new URL("/dashboard", req.url));
490
425
  }
491
- `}function ys(e){return`"use client";
426
+ `}function xs(e){return`"use client";
492
427
 
493
428
  /**
494
429
  * SocialLoginButtons \u2014 generated by create-sailor.
@@ -508,7 +443,7 @@ interface SocialProvider {
508
443
  }
509
444
 
510
445
  const PROVIDERS: SocialProvider[] = [
511
- ${e.map(o=>` { id: ${JSON.stringify(o.id)}, name: ${JSON.stringify(o.name)}, href: ${JSON.stringify(`/api/auth/oauth/${o.id}`)} }`).join(`,
446
+ ${e.map(n=>` { id: ${JSON.stringify(n.id)}, name: ${JSON.stringify(n.name)}, href: ${JSON.stringify(`/api/auth/oauth/${n.id}`)} }`).join(`,
512
447
  `)},
513
448
  ];
514
449
 
@@ -531,23 +466,23 @@ export function SocialLoginButtons() {
531
466
  </div>
532
467
  );
533
468
  }
534
- `}function Un(e){we.mkdirSync(e,{recursive:!0})}function Ss(e,t){let o=Ie.join(e,".env.example");we.existsSync(o)?we.appendFileSync(o,`
535
- `+t):we.writeFileSync(o,t)}function hs(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,o=e.envVars.map(n=>`${n}=`).join(`
469
+ `}function Jn(e){xe.mkdirSync(e,{recursive:!0})}function Rs(e,t){let n=Ce.join(e,".env.example");xe.existsSync(n)?xe.appendFileSync(n,`
470
+ `+t):xe.writeFileSync(n,t)}function ks(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,n=e.envVars.map(o=>`${o}=`).join(`
536
471
  `);return`${t}
537
- ${o}
538
- `}async function Mn(e,t,o){if(!t||t.length===0)return;let n=Ie.join(e,"apps","web");if(!we.existsSync(n))return;let r=new Set,s=[];for(let l of t){if(r.has(l))continue;r.add(l);let u=On(l);u&&s.push(u)}if(s.length===0)return;for(let l of s)Ss(e,hs(l));let i=Ie.join(n,"src","app","api","auth","callback");for(let l of s){let u=Ie.join(i,l.id);Un(u);let S=Ie.join(u,"route.ts");we.writeFileSync(S,fs(l,o))}let c=Ie.join(n,"src","components","auth");Un(c);let a=Ie.join(c,"SocialLoginButtons.tsx");we.writeFileSync(a,ys(s))}import it from"fs";import Fn from"path";var Ft=[{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 Dn(e){return Ft.find(t=>t.id===e)}var Xc=Ft.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import ee from"fs";import jt from"path";function te(e,t){let o=jt.join(e,".env.example");if(!ee.existsSync(o)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(ee.readFileSync(o,"utf-8").includes(r))return;let c=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(a=>`${a}=""`),""].filter(a=>a!==null).join(`
539
- `);ee.appendFileSync(o,c)}function ne(e,t,o){let n=jt.join(e,".env.example");if(!ee.existsSync(n))return;let r=ee.readFileSync(n,"utf-8"),s=`${t}="${o}"`,i=new RegExp(`^${t}=.*$`,"m");if(i.test(r)){ee.writeFileSync(n,r.replace(i,s));return}let c=r.endsWith(`
472
+ ${n}
473
+ `}async function Qn(e,t,n){if(!t||t.length===0)return;let o=Ce.join(e,"apps","web");if(!xe.existsSync(o))return;let r=new Set,s=[];for(let p of t){if(r.has(p))continue;r.add(p);let u=Un(p);u&&s.push(u)}if(s.length===0)return;for(let p of s)Rs(e,ks(p));let i=Ce.join(o,"src","app","api","auth","callback");for(let p of s){let u=Ce.join(i,p.id);Jn(u);let d=Ce.join(u,"route.ts");xe.writeFileSync(d,Cs(p,n))}let a=Ce.join(o,"src","components","auth");Jn(a);let c=Ce.join(a,"SocialLoginButtons.tsx");xe.writeFileSync(c,xs(s))}import Je from"fs";import eo from"path";var Et=[{id:"upstash-redis",name:"Upstash Redis",region:"both",envVars:["UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"],docs:"https://upstash.com/docs/redis",description:"Serverless Redis"},{id:"vercel-kv",name:"Vercel KV",region:"global",envVars:["KV_URL","KV_REST_API_URL","KV_REST_API_TOKEN","KV_REST_API_READ_ONLY_TOKEN"],docs:"https://vercel.com/docs/storage/vercel-kv",description:"Vercel native KV"},{id:"redis",name:"Redis (self-hosted)",region:"both",envVars:["REDIS_URL"],docs:"https://redis.io/docs/",description:"Self-hosted Redis"},{id:"dragonfly",name:"Dragonfly",region:"global",envVars:["DRAGONFLY_URL"],docs:"https://www.dragonflydb.io/docs",description:"Drop-in Redis replacement, faster"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip cache package"}];function Zn(e){return Et.find(t=>t.id===e)}var Vp=Et.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import ne from"fs";import vt from"path";function oe(e,t){let n=vt.join(e,".env.example");if(!ne.existsSync(n)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(ne.readFileSync(n,"utf-8").includes(r))return;let a=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(c=>`${c}=""`),""].filter(c=>c!==null).join(`
474
+ `);ne.appendFileSync(n,a)}function re(e,t,n){let o=vt.join(e,".env.example");if(!ne.existsSync(o))return;let r=ne.readFileSync(o,"utf-8"),s=`${t}="${n}"`,i=new RegExp(`^${t}=.*$`,"m");if(i.test(r)){ne.writeFileSync(o,r.replace(i,s));return}let a=r.endsWith(`
540
475
  `)?"":`
541
- `;ee.appendFileSync(n,`${c}${s}
542
- `)}var Es=["design","iam","commerce","integrations","platform","ops","ai"];function Re(e,t){for(let n of Es){let r=jt.join(e,"packages",n,t);if(ee.existsSync(r))return r}let o=jt.join(e,"packages",t);return ee.existsSync(o)?o:null}function X(e,t){let o=Re(e,t);o&&ee.rmSync(o,{recursive:!0,force:!0})}function jn(e){return it.existsSync(e)?it.readFileSync(e,"utf-8"):null}function vs(e,t){let o=Fn.join(e,".env.example"),n=jn(o);if(n===null)return;let r=`# Cache: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
543
- `);it.appendFileSync(o,s)}function _s(e,t,o){let n=Fn.join(e,".env.example"),r=jn(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?it.writeFileSync(n,r.replace(s,`${t}="${o}"`)):it.appendFileSync(n,`${t}="${o}"
544
- `)}async function Vn(e,t,o){let n=Re(e,"cache");if(t==="none"){n&&it.rmSync(n,{recursive:!0,force:!0});return}let r=Dn(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${Ft.map(s=>s.id).join(", ")}`);n&&(vs(e,r),_s(e,"CACHE_PROVIDER",t))}var Vt=[{id:"turnstile",name:"Cloudflare Turnstile",region:"global",envVars:["NEXT_PUBLIC_TURNSTILE_SITE_KEY","TURNSTILE_SECRET_KEY"],docs:"https://developers.cloudflare.com/turnstile/",description:"Free, privacy-focused captcha alternative"},{id:"hcaptcha",name:"hCaptcha",region:"global",envVars:["NEXT_PUBLIC_HCAPTCHA_SITE_KEY","HCAPTCHA_SECRET_KEY"],docs:"https://docs.hcaptcha.com/",description:"Privacy-respecting captcha"},{id:"aliyun-slide",name:"\u963F\u91CC\u4E91\u9A8C\u8BC1\u7801 2.0",region:"cn",envVars:["ALIYUN_CAPTCHA_ACCESS_KEY_ID","ALIYUN_CAPTCHA_ACCESS_KEY_SECRET","ALIYUN_CAPTCHA_APP_KEY","NEXT_PUBLIC_ALIYUN_CAPTCHA_APP_KEY"],docs:"https://help.aliyun.com/product/28308.html",description:"\u963F\u91CC\u4E91\u667A\u80FD\u9A8C\u8BC1 (\u6ED1\u5757/\u65E0\u75D5)"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Bn(e){return Vt.find(t=>t.id===e)}var sp=Vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Kn(e,t,o="global"){let n=Bn(t);if(!n)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${Vt.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"captcha");return}n.envVars.length>0&&te(e,{category:"Captcha",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"CAPTCHA_PROVIDER",n.id)}import Kt from"fs";import bs from"path";var Bt=[{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 $n(e){return Bt.find(t=>t.id===e)}var lp=Bt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Yn(e,t,o="global"){let n=$n(t);if(!n)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${Bt.map(s=>s.id).join(", ")}`);let r=bs.join(e,"apps","studio");if(n.id==="none"){X(e,"sanity"),Kt.existsSync(r)&&Kt.rmSync(r,{recursive:!0,force:!0});return}n.id!=="sanity"&&(X(e,"sanity"),Kt.existsSync(r)&&Kt.rmSync(r,{recursive:!0,force:!0})),n.envVars.length>0&&te(e,{category:"CMS",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"CMS_PROVIDER",n.id)}import T from"fs";import N from"path";var Ps=N.join("apps","web"),rn=N.join("src","components","compliance"),vt=N.join("src","app","[locale]");function oe(e){return N.join(e,Ps)}function As(e){T.mkdirSync(e,{recursive:!0})}function z(e,t){As(N.dirname(e)),T.writeFileSync(e,t,"utf8")}function sn(e,t){let o=N.join(e,".env.example");if(T.existsSync(o)){if(T.readFileSync(o,"utf8").includes(t.split(`
545
- `)[0]??""))return;T.appendFileSync(o,`
476
+ `;ne.appendFileSync(o,`${a}${s}
477
+ `)}var Ts=["design","iam","commerce","integrations","platform","ops","ai"];function Re(e,t){for(let o of Ts){let r=vt.join(e,"packages",o,t);if(ne.existsSync(r))return r}let n=vt.join(e,"packages",t);return ne.existsSync(n)?n:null}function z(e,t){let n=Re(e,t);n&&ne.rmSync(n,{recursive:!0,force:!0})}function to(e){return Je.existsSync(e)?Je.readFileSync(e,"utf-8"):null}function Ns(e,t){let n=eo.join(e,".env.example"),o=to(n);if(o===null)return;let r=`# Cache: ${t.name}`;if(o.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
478
+ `);Je.appendFileSync(n,s)}function Os(e,t,n){let o=eo.join(e,".env.example"),r=to(o);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?Je.writeFileSync(o,r.replace(s,`${t}="${n}"`)):Je.appendFileSync(o,`${t}="${n}"
479
+ `)}async function no(e,t,n){let o=Re(e,"cache");if(t==="none"){o&&Je.rmSync(o,{recursive:!0,force:!0});return}let r=Zn(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${Et.map(s=>s.id).join(", ")}`);o&&(Ns(e,r),Os(e,"CACHE_PROVIDER",t))}var bt=[{id:"turnstile",name:"Cloudflare Turnstile",region:"global",envVars:["NEXT_PUBLIC_TURNSTILE_SITE_KEY","TURNSTILE_SECRET_KEY"],docs:"https://developers.cloudflare.com/turnstile/",description:"Free, privacy-focused captcha alternative"},{id:"hcaptcha",name:"hCaptcha",region:"global",envVars:["NEXT_PUBLIC_HCAPTCHA_SITE_KEY","HCAPTCHA_SECRET_KEY"],docs:"https://docs.hcaptcha.com/",description:"Privacy-respecting captcha"},{id:"aliyun-slide",name:"\u963F\u91CC\u4E91\u9A8C\u8BC1\u7801 2.0",region:"cn",envVars:["ALIYUN_CAPTCHA_ACCESS_KEY_ID","ALIYUN_CAPTCHA_ACCESS_KEY_SECRET","ALIYUN_CAPTCHA_APP_KEY","NEXT_PUBLIC_ALIYUN_CAPTCHA_APP_KEY"],docs:"https://help.aliyun.com/product/28308.html",description:"\u963F\u91CC\u4E91\u667A\u80FD\u9A8C\u8BC1 (\u6ED1\u5757/\u65E0\u75D5)"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function oo(e){return bt.find(t=>t.id===e)}var Jp=bt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ro(e,t,n="global"){let o=oo(t);if(!o)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${bt.map(r=>r.id).join(", ")}`);if(o.id==="none"){z(e,"captcha");return}o.envVars.length>0&&oe(e,{category:"Captcha",name:o.name,envVars:o.envVars,docs:o.docs}),re(e,"CAPTCHA_PROVIDER",o.id)}import Pt from"fs";import Ls from"path";var _t=[{id:"sanity",name:"Sanity",region:"global",envVars:["SANITY_PROJECT_ID","SANITY_DATASET","SANITY_API_TOKEN","SANITY_API_VERSION"],docs:"https://www.sanity.io/docs",description:"Structured content platform with Studio"},{id:"contentful",name:"Contentful",region:"global",envVars:["CONTENTFUL_SPACE_ID","CONTENTFUL_ACCESS_TOKEN","CONTENTFUL_PREVIEW_ACCESS_TOKEN"],docs:"https://www.contentful.com/developers/docs/",description:"Headless CMS"},{id:"strapi",name:"Strapi",region:"both",envVars:["STRAPI_URL","STRAPI_API_TOKEN"],docs:"https://docs.strapi.io",description:"Open-source self-hosted CMS"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function so(e){return _t.find(t=>t.id===e)}var nl=_t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function io(e,t,n="global"){let o=so(t);if(!o)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${_t.map(s=>s.id).join(", ")}`);let r=Ls.join(e,"apps","studio");if(o.id==="none"){z(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0});return}o.id!=="sanity"&&(z(e,"sanity"),Pt.existsSync(r)&&Pt.rmSync(r,{recursive:!0,force:!0})),o.envVars.length>0&&oe(e,{category:"CMS",name:o.name,envVars:o.envVars,docs:o.docs}),re(e,"CMS_PROVIDER",o.id)}import U from"fs";import O from"path";var Us=O.join("apps","web"),rn=O.join("src","components","compliance"),at=O.join("src","app","[locale]");function se(e){return O.join(e,Us)}function Ms(e){U.mkdirSync(e,{recursive:!0})}function J(e,t){Ms(O.dirname(e)),U.writeFileSync(e,t,"utf8")}function sn(e,t){let n=O.join(e,".env.example");if(U.existsSync(n)){if(U.readFileSync(n,"utf8").includes(t.split(`
480
+ `)[0]??""))return;U.appendFileSync(n,`
546
481
  `+t+`
547
- `)}else T.writeFileSync(o,t+`
548
- `)}var _t=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
482
+ `)}else U.writeFileSync(n,t+`
483
+ `)}var ct=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
549
484
  > Consult a qualified lawyer in every jurisdiction you operate in before publishing.
550
- > \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,Cs=`import Link from "next/link";
485
+ > \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`,Ds=`import Link from "next/link";
551
486
  import { IcpFooter } from "@/components/compliance/IcpFooter";
552
487
  import { PublicSecurityFooter } from "@/components/compliance/PublicSecurityFooter";
553
488
 
@@ -598,7 +533,7 @@ export function Footer({ region = "global" }: FooterProps) {
598
533
  </footer>
599
534
  );
600
535
  }
601
- `,Is=`export function IcpFooter() {
536
+ `,Fs=`export function IcpFooter() {
602
537
  const icp = process.env.NEXT_PUBLIC_ICP_BEIAN;
603
538
  if (!icp) return null;
604
539
  return (
@@ -612,7 +547,7 @@ export function Footer({ region = "global" }: FooterProps) {
612
547
  </a>
613
548
  );
614
549
  }
615
- `,ws=`export function PublicSecurityFooter() {
550
+ `,js=`export function PublicSecurityFooter() {
616
551
  const psb = process.env.NEXT_PUBLIC_PSB_BEIAN;
617
552
  const psbCode = process.env.NEXT_PUBLIC_PSB_CODE;
618
553
  if (!psb) return null;
@@ -629,9 +564,9 @@ export function Footer({ region = "global" }: FooterProps) {
629
564
  </a>
630
565
  );
631
566
  }
632
- `,Rs=`"use client";
567
+ `,Bs=`"use client";
633
568
 
634
- import { useCallback, useEffect, useState } from "react";
569
+ import { useEffect, useState } from "react";
635
570
 
636
571
  type ConsentMode = "accepted" | "rejected" | "custom";
637
572
 
@@ -660,41 +595,57 @@ const DEFAULT_CATEGORIES: CustomConsent = {
660
595
  preferences: false,
661
596
  };
662
597
 
598
+ function readStoredConsent(): StoredConsent | null {
599
+ if (typeof window === "undefined") return null;
600
+
601
+ const stored = localStorage.getItem(STORAGE_KEY);
602
+ if (!stored) return null;
603
+
604
+ try {
605
+ return JSON.parse(stored) as StoredConsent;
606
+ } catch {
607
+ return null;
608
+ }
609
+ }
610
+
611
+ function shouldOpenInitially(): boolean {
612
+ if (typeof window === "undefined") return false;
613
+
614
+ const stored = localStorage.getItem(STORAGE_KEY);
615
+ if (!stored) return true;
616
+
617
+ try {
618
+ JSON.parse(stored);
619
+ return false;
620
+ } catch {
621
+ return true;
622
+ }
623
+ }
624
+
663
625
  function emitConsent(consent: StoredConsent): void {
664
626
  if (typeof window === "undefined") return;
665
627
  window.dispatchEvent(new CustomEvent(CONSENT_EVENT, { detail: consent }));
666
628
  }
667
629
 
668
630
  export function CookieBanner() {
669
- const [isOpen, setIsOpen] = useState(false);
670
- const [showCustomize, setShowCustomize] = useState(false);
671
- const [categories, setCategories] = useState<CustomConsent>(DEFAULT_CATEGORIES);
631
+ const [isOpen, setIsOpen] = useState(shouldOpenInitially);
672
632
 
673
633
  useEffect(() => {
674
- try {
675
- const stored = localStorage.getItem(STORAGE_KEY);
676
- if (!stored) {
677
- setIsOpen(true);
678
- return;
679
- }
680
- const parsed = JSON.parse(stored) as StoredConsent;
681
- // Re-emit so analytics/marketing scripts mounted after consent can read state
682
- emitConsent(parsed);
683
- } catch {
684
- setIsOpen(true);
634
+ const stored = readStoredConsent();
635
+ if (stored) {
636
+ emitConsent(stored);
685
637
  }
686
638
  }, []);
687
639
 
688
640
  useEffect(() => {
689
641
  const handler = () => {
690
- setShowCustomize(true);
691
642
  setIsOpen(true);
692
643
  };
693
644
  window.addEventListener(OPEN_EVENT, handler);
694
645
  return () => window.removeEventListener(OPEN_EVENT, handler);
695
646
  }, []);
696
647
 
697
- const persist = useCallback((mode: ConsentMode, cats: CustomConsent) => {
648
+ function persist(mode: ConsentMode, cats: CustomConsent) {
698
649
  const consent: StoredConsent = {
699
650
  mode,
700
651
  categories: cats,
@@ -704,25 +655,20 @@ export function CookieBanner() {
704
655
  localStorage.setItem(STORAGE_KEY, JSON.stringify(consent));
705
656
  emitConsent(consent);
706
657
  setIsOpen(false);
707
- setShowCustomize(false);
708
- }, []);
658
+ }
709
659
 
710
- const acceptAll = useCallback(() => {
660
+ function acceptAll() {
711
661
  persist("accepted", {
712
662
  necessary: true,
713
663
  analytics: true,
714
664
  marketing: true,
715
665
  preferences: true,
716
666
  });
717
- }, [persist]);
667
+ }
718
668
 
719
- const rejectNonEssential = useCallback(() => {
669
+ function saveNecessaryOnly() {
720
670
  persist("rejected", DEFAULT_CATEGORIES);
721
- }, [persist]);
722
-
723
- const saveCustom = useCallback(() => {
724
- persist("custom", categories);
725
- }, [persist, categories]);
671
+ }
726
672
 
727
673
  if (!isOpen) return null;
728
674
 
@@ -731,132 +677,48 @@ export function CookieBanner() {
731
677
  role="dialog"
732
678
  aria-modal="false"
733
679
  aria-labelledby="cookie-banner-title"
734
- className="fixed inset-x-0 bottom-0 z-50 border-t border-[var(--neutral-7)] bg-[var(--neutral-1)] shadow-lg"
680
+ className="fixed inset-x-0 bottom-0 z-50 border-t border-[var(--neutral-6)] bg-[var(--neutral-1)]/95 text-[var(--neutral-12)] shadow-lg backdrop-blur-md"
735
681
  >
736
- <div className="mx-auto flex max-w-[1400px] flex-col gap-4 p-4 md:p-6">
737
- <div>
738
- <h2 id="cookie-banner-title" className="text-sm font-semibold text-[var(--neutral-12)]">
739
- Cookie Preferences \xB7 Cookie \u504F\u597D\u8BBE\u7F6E
740
- </h2>
741
- <p className="mt-1 text-xs text-[var(--neutral-11)]">
742
- We use cookies to provide essential functionality, analyze usage, and personalize content.
743
- You can accept all, reject non-essential, or customize your choice. See our{" "}
744
- <a href="/privacy" className="underline">
745
- Privacy Policy
746
- </a>
747
- .
748
- <br />
749
- \u6211\u4EEC\u4F7F\u7528 Cookie \u63D0\u4F9B\u5FC5\u8981\u529F\u80FD\u3001\u5206\u6790\u4F7F\u7528\u60C5\u51B5\u5E76\u4E2A\u6027\u5316\u5185\u5BB9\u3002\u60A8\u53EF\u4EE5\u63A5\u53D7\u5168\u90E8\u3001\u62D2\u7EDD\u975E\u5FC5\u8981\uFF0C\u6216\u81EA\u5B9A\u4E49\u9009\u62E9\u3002\u8BE6\u89C1
750
- <a href="/privacy" className="underline">
751
- \u9690\u79C1\u653F\u7B56
752
- </a>
753
- \u3002
754
- </p>
755
- </div>
756
-
757
- {showCustomize ? (
758
- <fieldset className="grid gap-3 md:grid-cols-2">
759
- <CategoryRow
760
- id="necessary"
761
- title="Necessary / \u5FC5\u8981"
762
- description="Required for the site to function. Cannot be disabled. / \u7AD9\u70B9\u8FD0\u884C\u6240\u5FC5\u9700\uFF0C\u65E0\u6CD5\u5173\u95ED\u3002"
763
- checked={true}
764
- disabled
765
- onChange={() => undefined}
766
- />
767
- <CategoryRow
768
- id="analytics"
769
- title="Analytics / \u5206\u6790"
770
- description="Helps us understand usage patterns. / \u5E2E\u52A9\u6211\u4EEC\u4E86\u89E3\u4F7F\u7528\u6A21\u5F0F\u3002"
771
- checked={categories.analytics}
772
- onChange={(v) => setCategories((c) => ({ ...c, analytics: v }))}
773
- />
774
- <CategoryRow
775
- id="marketing"
776
- title="Marketing / \u8425\u9500"
777
- description="Used for targeted advertising. / \u7528\u4E8E\u5B9A\u5411\u5E7F\u544A\u3002"
778
- checked={categories.marketing}
779
- onChange={(v) => setCategories((c) => ({ ...c, marketing: v }))}
780
- />
781
- <CategoryRow
782
- id="preferences"
783
- title="Preferences / \u504F\u597D"
784
- description="Remember your preferences (language, theme). / \u8BB0\u4F4F\u60A8\u7684\u504F\u597D\uFF08\u8BED\u8A00\u3001\u4E3B\u9898\uFF09\u3002"
785
- checked={categories.preferences}
786
- onChange={(v) => setCategories((c) => ({ ...c, preferences: v }))}
787
- />
788
- </fieldset>
789
- ) : null}
682
+ <div className="mx-auto flex max-w-6xl flex-col gap-3 px-4 pb-[calc(0.75rem+env(safe-area-inset-bottom))] pt-3 sm:px-6 lg:px-8">
683
+ <div className="flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between">
684
+ <div className="min-w-0 flex-1">
685
+ <h2 id="cookie-banner-title" className="text-base font-semibold text-[var(--neutral-12)]">
686
+ Your Privacy Choices / \u9690\u79C1\u504F\u597D
687
+ </h2>
688
+ <p className="mt-1 max-w-3xl text-sm leading-6 text-[var(--neutral-11)]">
689
+ Necessary cookies keep the site working. Optional cookies help us improve the product
690
+ and personalize content.{" "}
691
+ <a
692
+ href="/privacy"
693
+ className="font-medium text-[var(--brand-primary)] underline underline-offset-4 transition-colors hover:text-[var(--blue-10)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--blue-7)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--neutral-1)]"
694
+ >
695
+ Privacy Policy
696
+ </a>
697
+ </p>
698
+ </div>
790
699
 
791
- <div className="flex flex-wrap gap-2 md:justify-end">
792
- {showCustomize ? (
700
+ <div className="flex w-full flex-col-reverse gap-2 sm:w-auto sm:flex-row sm:items-center">
793
701
  <button
794
702
  type="button"
795
- onClick={saveCustom}
796
- className="rounded-md border border-[var(--neutral-12)] bg-[var(--neutral-12)] px-4 py-2 text-sm font-medium text-[var(--neutral-1)] shadow-sm hover:bg-[var(--neutral-11)]"
703
+ onClick={saveNecessaryOnly}
704
+ className="inline-flex min-h-10 items-center justify-center rounded-[var(--radius-lg)] border border-[var(--neutral-7)] bg-[var(--neutral-1)] px-4 text-sm font-medium text-[var(--neutral-12)] transition-colors hover:border-[var(--neutral-8)] hover:bg-[var(--neutral-2)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--blue-7)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--neutral-1)]"
797
705
  >
798
- Save Preferences / \u4FDD\u5B58\u504F\u597D
706
+ Only Necessary / \u4EC5\u5FC5\u8981
799
707
  </button>
800
- ) : (
801
708
  <button
802
709
  type="button"
803
- onClick={() => setShowCustomize(true)}
804
- className="rounded-md border border-[var(--neutral-7)] px-4 py-2 text-sm font-medium text-[var(--neutral-12)] hover:bg-[var(--neutral-3)]"
710
+ onClick={acceptAll}
711
+ className="inline-flex min-h-10 items-center justify-center rounded-[var(--radius-lg)] border border-[var(--neutral-12)] bg-[var(--neutral-12)] px-4 text-sm font-medium text-[var(--neutral-1)] transition-colors hover:bg-[var(--neutral-11)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--blue-7)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--neutral-1)]"
805
712
  >
806
- Customize / \u81EA\u5B9A\u4E49
713
+ Accept All / \u5168\u90E8\u63A5\u53D7
807
714
  </button>
808
- )}
809
- <button
810
- type="button"
811
- onClick={rejectNonEssential}
812
- className="rounded-md border border-[var(--neutral-7)] px-4 py-2 text-sm font-medium text-[var(--neutral-12)] hover:bg-[var(--neutral-3)]"
813
- >
814
- Reject Non-Essential / \u62D2\u7EDD\u975E\u5FC5\u8981
815
- </button>
816
- <button
817
- type="button"
818
- onClick={acceptAll}
819
- className="rounded-md border border-[var(--neutral-12)] bg-[var(--neutral-12)] px-4 py-2 text-sm font-medium text-[var(--neutral-1)] shadow-sm hover:bg-[var(--neutral-11)]"
820
- >
821
- Accept All / \u5168\u90E8\u63A5\u53D7
822
- </button>
715
+ </div>
823
716
  </div>
824
717
  </div>
825
718
  </div>
826
719
  );
827
720
  }
828
-
829
- interface CategoryRowProps {
830
- id: string;
831
- title: string;
832
- description: string;
833
- checked: boolean;
834
- disabled?: boolean;
835
- onChange: (value: boolean) => void;
836
- }
837
-
838
- function CategoryRow({ id, title, description, checked, disabled, onChange }: CategoryRowProps) {
839
- return (
840
- <label
841
- htmlFor={id}
842
- className="flex items-start gap-3 rounded-md border border-[var(--neutral-7)] p-3"
843
- >
844
- <input
845
- id={id}
846
- type="checkbox"
847
- checked={checked}
848
- disabled={disabled}
849
- onChange={(e) => onChange(e.target.checked)}
850
- className="mt-0.5 h-4 w-4"
851
- />
852
- <span className="flex flex-col">
853
- <span className="text-sm font-medium text-[var(--neutral-12)]">{title}</span>
854
- <span className="text-xs text-[var(--neutral-11)]">{description}</span>
855
- </span>
856
- </label>
857
- );
858
- }
859
- `,ks=`interface AigcDisclaimerProps {
721
+ `,Vs=`interface AigcDisclaimerProps {
860
722
  className?: string;
861
723
  }
862
724
 
@@ -876,13 +738,13 @@ export function AigcDisclaimer({ className }: AigcDisclaimerProps) {
876
738
  </div>
877
739
  );
878
740
  }
879
- `,xs=`---
741
+ `,Ks=`---
880
742
  title: Privacy Policy / \u9690\u79C1\u653F\u7B56
881
743
  description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal information.
882
744
  lastUpdated: 2026-01-01
883
745
  ---
884
746
 
885
- ${_t}
747
+ ${ct}
886
748
 
887
749
  # Privacy Policy / \u9690\u79C1\u653F\u7B56
888
750
 
@@ -1021,13 +883,13 @@ or in-app notification before the change takes effect.
1021
883
  **Data Controller / \u6570\u636E\u63A7\u5236\u8005:** {{COMPANY_NAME}}
1022
884
  **Address / \u5730\u5740:** {{COMPANY_ADDRESS}}
1023
885
  **Email / \u90AE\u7BB1:** {{COMPANY_CONTACT_EMAIL}}
1024
- `,Ns=`---
886
+ `,$s=`---
1025
887
  title: Terms of Service / \u670D\u52A1\u6761\u6B3E
1026
888
  description: Terms governing your use of {{COMPANY_NAME}}.
1027
889
  lastUpdated: 2026-01-01
1028
890
  ---
1029
891
 
1030
- ${_t}
892
+ ${ct}
1031
893
 
1032
894
  # Terms of Service / \u670D\u52A1\u6761\u6B3E
1033
895
 
@@ -1140,13 +1002,13 @@ conflict-of-laws principles. Disputes shall be resolved in the competent courts
1140
1002
  ## 11. Contact / \u8054\u7CFB\u65B9\u5F0F
1141
1003
 
1142
1004
  {{COMPANY_NAME}} \xB7 {{COMPANY_ADDRESS}} \xB7 {{COMPANY_CONTACT_EMAIL}}
1143
- `,Ts=`---
1005
+ `,Ys=`---
1144
1006
  title: AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
1145
1007
  description: Disclosure required by \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300B
1146
1008
  lastUpdated: 2026-01-01
1147
1009
  ---
1148
1010
 
1149
- ${_t}
1011
+ ${ct}
1150
1012
 
1151
1013
  # AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
1152
1014
 
@@ -1222,13 +1084,13 @@ human professional.
1222
1084
 
1223
1085
  AI \u8F93\u51FA\u53EF\u80FD\u4E0D\u51C6\u786E\u3001\u5B58\u5728\u504F\u89C1\u6216\u8FC7\u65F6\u3002**\u8BF7\u52FF**\u5728\u672A\u7ECF\u5408\u683C\u4E13\u4E1A\u4EBA\u58EB\u72EC\u7ACB\u6838\u5B9E\u7684\u60C5\u51B5\u4E0B\uFF0C\u5C06 AI \u8F93\u51FA
1224
1086
  \u7528\u4E8E\u533B\u7597\u3001\u6CD5\u5F8B\u3001\u91D1\u878D\u6216\u5B89\u5168\u6538\u5173\u7684\u51B3\u7B56\u3002
1225
- `,Os=`---
1087
+ `,qs=`---
1226
1088
  title: Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
1227
1089
  description: Notice of cross-border transfer of personal information, per PIPL.
1228
1090
  lastUpdated: 2026-01-01
1229
1091
  ---
1230
1092
 
1231
- ${_t}
1093
+ ${ct}
1232
1094
 
1233
1095
  # Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
1234
1096
 
@@ -1287,13 +1149,13 @@ Refusal may limit your ability to use features that rely on overseas services.
1287
1149
  - \u4F20\u8F93\u4E2D\u52A0\u5BC6 (TLS 1.2+) \u53CA\u9759\u6001\u52A0\u5BC6 (AES-256)\u3002
1288
1150
  - \u5408\u540C\u6761\u6B3E\u8981\u6C42\u5883\u5916\u63A5\u6536\u65B9\u63D0\u4F9B\u7B49\u540C\u4E8E PIPL \u7684\u4FDD\u62A4\u3002
1289
1151
  - \u8BBF\u95EE\u63A7\u5236\u3001\u5BA1\u8BA1\u65E5\u5FD7\u548C\u8FDD\u89C4\u901A\u77E5\u7A0B\u5E8F\u3002
1290
- `,Ls=`---
1152
+ `,Gs=`---
1291
1153
  title: Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
1292
1154
  description: Itemized list of personal information collected, per PIPL Article 17.
1293
1155
  lastUpdated: 2026-01-01
1294
1156
  ---
1295
1157
 
1296
- ${_t}
1158
+ ${ct}
1297
1159
 
1298
1160
  # Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
1299
1161
 
@@ -1329,26 +1191,26 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
1329
1191
  **{{COMPANY_CONTACT_EMAIL}}**.
1330
1192
 
1331
1193
  \u5982\u9700\u884C\u4F7F\u60A8\u7684\u6743\u5229\uFF08\u8BBF\u95EE\u3001\u66F4\u6B63\u3001\u5220\u9664\u3001\u5BFC\u51FA\u3001\u64A4\u56DE\u540C\u610F\uFF09\uFF0C\u8BF7\u8054\u7CFB **{{COMPANY_CONTACT_EMAIL}}**\u3002
1332
- `;async function Us(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,"src","components","compliance","Footer.tsx");z(n,Cs);let r=N.join(o,"src","components","compliance","README.md");z(r,["# Compliance Components","",`Auto-generated by \`create-sailor\` for region: \`${t}\`.`,"","## Mounting the Footer","","```tsx",'import { Footer } from "@/components/compliance/Footer";','import { CookieBanner } from "@/components/compliance/CookieBanner";',"","export default function RootLayout({ children }) {"," return ("," <html>"," <body>"," {children}",` <Footer region="${t}" />`," <CookieBanner />"," </body>"," </html>"," );","}","```","","## Placeholders","","Policy MDX files contain `{{COMPANY_NAME}}`, `{{COMPANY_ADDRESS}}`,","`{{COMPANY_CONTACT_EMAIL}}`, `{{GOVERNING_JURISDICTION}}`, and","`{{AIGC_ALGORITHM_FILING_NUMBER}}`. These are filled by the `brand-apply` step.",""].join(`
1333
- `))}async function Ms(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,"src","components","compliance","CookieBanner.tsx");z(n,Rs)}async function Ds(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,vt,"privacy","page.mdx");z(n,xs)}async function Fs(e,t){let o=oe(e);if(!T.existsSync(o))return;let n=N.join(o,vt,"terms","page.mdx");z(n,Ns)}async function js(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,rn,"IcpFooter.tsx");z(o,Is),sn(e,["# Chinese ICP filing (\u5DE5\u4FE1\u90E8 ICP \u5907\u6848) \u2014 required to legally host a","# public-facing site from mainland China. Apply at https://beian.miit.gov.cn/",'NEXT_PUBLIC_ICP_BEIAN="" # \u5982 \u82CFICP\u59072024XXXXXX\u53F7'].join(`
1334
- `))}async function Vs(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,rn,"PublicSecurityFooter.tsx");z(o,ws),sn(e,["# Chinese Public Security Bureau filing (\u516C\u5B89\u8054\u7F51\u5907\u6848)","# Required in addition to ICP. Apply at http://www.beian.gov.cn/",'NEXT_PUBLIC_PSB_BEIAN="" # \u5982 \u82CF\u516C\u7F51\u5B89\u5907 32011402XXXXXX\u53F7','NEXT_PUBLIC_PSB_CODE="" # 14-digit record code'].join(`
1335
- `))}async function Bs(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,rn,"AigcDisclaimer.tsx");z(o,ks),sn(e,["# Generative AI algorithm filing (\u7B97\u6CD5\u5907\u6848\u53F7) \u2014 required by","# \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300Bfor services offered in China.",'NEXT_PUBLIC_AIGC_FILING_NUMBER="" # e.g. \u7F51\u4FE1\u7B97\u5907XXXXXXXX\u53F7'].join(`
1336
- `))}async function Ks(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"aigc-disclosure","page.mdx");z(o,Ts)}async function $s(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"cross-border-data","page.mdx");z(o,Os)}async function Ys(e){let t=oe(e);if(!T.existsSync(t))return;let o=N.join(t,vt,"pii-collection","page.mdx");z(o,Ls)}async function qn(e,t){try{await Us(e,t),await Ms(e,t),await Ds(e,t),await Fs(e,t),(t==="cn"||t==="hybrid")&&(await js(e),await Vs(e),await Bs(e),await Ks(e),await $s(e),await Ys(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 qs from"fs";import Gs from"path";async function Gn(e,t){let o=Gs.join(e,"nebutra.config.json");qs.writeFileSync(o,JSON.stringify(t,null,2)+`
1337
- `)}import R from"fs";import ke from"path";var an=[{id:"local",name:"Local / Self-hosted Docker",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres:postgres@localhost:5432/$PROJECT",comment:"Local Postgres via docker-compose (pnpm infra:up)"}],docs:"https://www.postgresql.org/docs/",description:"Docker on localhost. You operate it.",tier:"self-hosted"},{id:"supabase",name:"Supabase",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:6543/postgres?pgbouncer=true",comment:"Supabase pooler \u2014 use for runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres",comment:"Supabase direct \u2014 use for Prisma migrations"},{name:"NEXT_PUBLIC_SUPABASE_URL",placeholder:"https://<project>.supabase.co"},{name:"NEXT_PUBLIC_SUPABASE_ANON_KEY",placeholder:""},{name:"SUPABASE_SERVICE_ROLE_KEY",placeholder:""}],docs:"https://supabase.com/docs",description:"Managed Postgres + auth/storage/realtime/edge-functions.",tier:"managed"},{id:"neon",name:"Neon",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>-pooler.<region>.neon.tech/<db>?sslmode=require",comment:"Neon pooled \u2014 runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>.<region>.neon.tech/<db>?sslmode=require",comment:"Neon direct (no -pooler) \u2014 migrations"}],docs:"https://neon.tech/docs",description:"Serverless Postgres with branching and scale-to-zero.",tier:"managed"},{id:"vercel-postgres",name:"Vercel Postgres",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"$POSTGRES_PRISMA_URL",comment:"Vercel Marketplace injects POSTGRES_PRISMA_URL automatically"},{name:"DIRECT_URL",placeholder:"$POSTGRES_URL_NON_POOLING",comment:"Vercel Marketplace injects POSTGRES_URL_NON_POOLING automatically"}],docs:"https://vercel.com/docs/storage/vercel-postgres",description:"Neon-backed, auto-provisioned via Vercel Marketplace.",tier:"managed"},{id:"planetscale",name:"PlanetScale",region:"global",supportedEngines:["mysql"],forcedEngine:"mysql",prismaDatasourceExtras:['relationMode = "prisma"'],envVars:[{name:"DATABASE_URL",placeholder:"mysql://<user>:<pass>@<host>.psdb.cloud/<db>?sslaccept=strict",comment:'PlanetScale: relationMode = "prisma" (no FK support server-side)'}],docs:"https://planetscale.com/docs",description:"Managed MySQL with branching. No foreign keys.",tier:"managed"},{id:"railway",name:"Railway",region:"global",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"$DATABASE_URL",comment:"Railway service env var; injected when you link a Postgres service"}],docs:"https://docs.railway.app/databases/postgresql",description:"Generalist managed infra; standard TCP Postgres/MySQL.",tier:"managed"},{id:"aliyun-rds",name:"Aliyun RDS",region:"cn",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@<rds-instance>.rds.aliyuncs.com:5432/<db>",comment:"Aliyun RDS Postgres \u2014 internal VPC endpoint recommended"}],docs:"https://www.alibabacloud.com/help/en/rds",description:"Aliyun RDS \u2014 China compliance + intranet routing.",tier:"managed"},{id:"tencent-cdb",name:"Tencent CloudDB (CDB)",region:"cn",supportedEngines:["mysql","postgresql"],envVars:[{name:"DATABASE_URL",placeholder:"mysql://<user>:<pwd>@<cdb-instance>.tencentcdb.com:3306/<db>",comment:"Tencent CloudDB \u2014 VPC endpoint recommended"}],docs:"https://intl.cloud.tencent.com/document/product/236",description:"Tencent CloudDB \u2014 China compliance.",tier:"managed"},{id:"none",name:"None",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[],docs:"",description:"Skip database scaffolding.",tier:"self-hosted"}];function $t(e){return an.find(t=>t.id===e)}function Hn(e){return e==="cn"||e==="hybrid"?"local":"supabase"}function Hs(e){R.existsSync(e)&&R.rmSync(e,{recursive:!0,force:!0})}function Wn(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function Ws(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function Xn(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 Xs(e,t){let o=ke.join(e,".env.example");R.existsSync(o)?R.appendFileSync(o,`
1338
- `+t):R.writeFileSync(o,t)}async function zn(e,t,o){let n=ke.join(e,"packages","platform","db");if(t==="none"){Hs(n);return}let r=ke.join(n,"prisma","schema.prisma"),s;if(t==="postgresql"?s=`postgresql://postgres:postgres@localhost:5432/${o}`:t==="mysql"?s=`mysql://root:root@localhost:3306/${o}`:s="file:./dev.db",Xs(e,`# Database (${t})
1194
+ `;async function Hs(e,t){let n=se(e);if(!U.existsSync(n))return;let o=O.join(n,"src","components","compliance","Footer.tsx");J(o,Ds);let r=O.join(n,"src","components","compliance","README.md");J(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(`
1195
+ `))}async function Ws(e,t){let n=se(e);if(!U.existsSync(n))return;let o=O.join(n,"src","components","compliance","CookieBanner.tsx");J(o,Bs)}async function Xs(e,t){let n=se(e);if(!U.existsSync(n))return;let o=O.join(n,at,"privacy","page.mdx");J(o,Ks)}async function zs(e,t){let n=se(e);if(!U.existsSync(n))return;let o=O.join(n,at,"terms","page.mdx");J(o,$s)}async function Js(e){let t=se(e);if(!U.existsSync(t))return;let n=O.join(t,rn,"IcpFooter.tsx");J(n,Fs),sn(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(`
1196
+ `))}async function Qs(e){let t=se(e);if(!U.existsSync(t))return;let n=O.join(t,rn,"PublicSecurityFooter.tsx");J(n,js),sn(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(`
1197
+ `))}async function Zs(e){let t=se(e);if(!U.existsSync(t))return;let n=O.join(t,rn,"AigcDisclaimer.tsx");J(n,Vs),sn(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(`
1198
+ `))}async function ei(e){let t=se(e);if(!U.existsSync(t))return;let n=O.join(t,at,"aigc-disclosure","page.mdx");J(n,Ys)}async function ti(e){let t=se(e);if(!U.existsSync(t))return;let n=O.join(t,at,"cross-border-data","page.mdx");J(n,qs)}async function ni(e){let t=se(e);if(!U.existsSync(t))return;let n=O.join(t,at,"pii-collection","page.mdx");J(n,Gs)}async function ao(e,t){try{await Hs(e,t),await Ws(e,t),await Xs(e,t),await zs(e,t),(t==="cn"||t==="hybrid")&&(await Js(e),await Qs(e),await Zs(e),await ei(e),await ti(e),await ni(e))}catch(n){throw console.error("applyComplianceTemplates failed:",n),new Error(`Failed to apply compliance templates for region "${t}". Check that ${e} is writable.`)}}import oi from"fs";import ri from"path";async function co(e,t){let n=ri.join(e,"nebutra.config.json");oi.writeFileSync(n,JSON.stringify(t,null,2)+`
1199
+ `)}import R from"fs";import ke from"path";function si(e){R.existsSync(e)&&R.rmSync(e,{recursive:!0,force:!0})}function po(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function ii(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function lo(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 ai(e,t){let n=ke.join(e,".env.example");R.existsSync(n)?R.appendFileSync(n,`
1200
+ `+t):R.writeFileSync(n,t)}async function uo(e,t,n){let o=ke.join(e,"packages","platform","db");if(t==="none"){si(o);return}let r=ke.join(o,"prisma","schema.prisma"),s;if(t==="postgresql"?s=`postgresql://postgres:postgres@localhost:5432/${n}`:t==="mysql"?s=`mysql://root:root@localhost:3306/${n}`:s="file:./dev.db",ai(e,`# Database (${t})
1339
1201
  DATABASE_URL="${s}"
1340
- `),!R.existsSync(r))return;let i=R.readFileSync(r,"utf8"),c=i;t==="mysql"?(c=Wn(c,"mysql"),c=Xn(c)):t==="sqlite"&&(c=Wn(c,"sqlite"),c=Ws(c),c=Xn(c)),c!==i&&R.writeFileSync(r,c)}function zs(e){let t=ke.join(e,".env.example");return R.existsSync(t)?R.readFileSync(t,"utf8"):""}function Js(e,t,o,n){let r=ke.join(e,".env.example"),s=zs(e),i=n?`# ${n}
1341
- ${t}="${o}"
1342
- `:`${t}="${o}"
1343
- `,c=new RegExp(`^\\s*${t}\\s*=.*$`,"m");if(c.test(s)){R.writeFileSync(r,s.replace(c,`${t}="${o}"`));return}s?R.appendFileSync(r,`
1344
- ${i}`):R.writeFileSync(r,i)}function Qs(e,t){let o=ke.join(e,"packages","platform","db","prisma","schema.prisma");if(!R.existsSync(o))return;let n=R.readFileSync(o,"utf8"),r=/(datasource\s+db\s*\{[^}]*?)(\n})/;if(!n.match(r))return;let i=t.filter(l=>!n.includes(l.trim()));if(i.length===0)return;let c=i.map(l=>` ${l}`).join(`
1345
- `),a=n.replace(r,`$1
1346
- ${c}$2`);R.writeFileSync(o,a)}function Zs(e){let t=ke.join(e,"packages","platform","db","prisma","schema.prisma");if(!R.existsSync(t))return;let o=R.readFileSync(t,"utf8");if(/directUrl\s*=\s*env\(/.test(o))return;let n=/(datasource\s+db\s*\{[\s\S]*?url\s*=\s*env\(\s*"DATABASE_URL"\s*\)[^\n]*\n)/;n.test(o)&&R.writeFileSync(t,o.replace(n,`$1 directUrl = env("DIRECT_URL")
1347
- `))}async function Jn(e,t,o){if(!(t.id==="none"||t.id==="local")){for(let n of t.envVars){let r=n.placeholder.replace(/\$PROJECT/g,o);Js(e,n.name,r,n.comment)}t.prismaDatasourceExtras&&t.prismaDatasourceExtras.length>0&&Qs(e,t.prismaDatasourceExtras),t.keepDirectUrl&&Zs(e)}}import at from"fs";import $ from"path";import{fileURLToPath as ei}from"url";var ti=ei(import.meta.url),Qn=$.dirname(ti);function ni(){let e=[$.join(Qn,"..","templates","deploy"),$.join(Qn,"..","..","templates","deploy")];for(let t of e)if(at.existsSync(t))return t;return e[0]}async function Zn(e,t){if(t==="none")return;let o=ni();t==="vercel"?await at.promises.copyFile($.join(o,"vercel.json"),$.join(e,"vercel.json")):t==="railway"?await at.promises.copyFile($.join(o,"railway.toml"),$.join(e,"railway.toml")):t==="cloudflare"?await at.promises.copyFile($.join(o,"wrangler.toml"),$.join(e,"wrangler.toml")):t==="selfhost"&&(await at.promises.copyFile($.join(o,"docker-compose.yml"),$.join(e,"docker-compose.yml")),await at.promises.copyFile($.join(o,"Dockerfile.web"),$.join(e,"Dockerfile.web")))}import ge from"fs";import xe from"path";import{fileURLToPath as oi}from"url";var ri=oi(import.meta.url),eo=xe.dirname(ri),si=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|vue)$/,to=["fumadocs","nextra","mintlify","docusaurus","vitepress"];function ii(e){let t=[xe.join(eo,"..","templates","docs",e),xe.join(eo,"..","..","templates","docs",e)];for(let o of t)if(ge.existsSync(o))return o;return t[0]}async function no(e,t){if(t.framework==="none")return;if(!to.includes(t.framework))throw new Error(`Unsupported docs framework: "${t.framework}". Supported: ${to.join(", ")}, none.`);let o=ii(t.framework),n=xe.join(e,"apps","docs");if(!ge.existsSync(o))throw new Error(`Docs template not found: ${o}`);oo(o,n),ro(n,{"{PRODUCT_NAME}":t.projectName})}function oo(e,t){ge.mkdirSync(t,{recursive:!0});for(let o of ge.readdirSync(e,{withFileTypes:!0})){let n=xe.join(e,o.name),r=xe.join(t,o.name);o.isDirectory()?oo(n,r):ge.copyFileSync(n,r)}}function ro(e,t){for(let o of ge.readdirSync(e,{withFileTypes:!0})){let n=xe.join(e,o.name);if(o.isDirectory())ro(n,t);else if(si.test(o.name)){let r=ge.readFileSync(n,"utf-8");for(let[s,i]of Object.entries(t))r=r.split(s).join(i);ge.writeFileSync(n,r)}}}import Te from"fs";import Ne from"path";var Yt=[{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 so(e){return Yt.find(t=>t.id===e)}var Mp=Yt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Oe="@nebutra/email";function cn(e,t){Te.mkdirSync(Ne.dirname(e),{recursive:!0}),Te.writeFileSync(e,t)}function ai(e,t){let o=Ne.join(e,".env.example");Te.existsSync(o)?Te.appendFileSync(o,`
1348
- `+t):Te.writeFileSync(o,t)}function ci(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
1202
+ `),!R.existsSync(r))return;let i=R.readFileSync(r,"utf8"),a=i;t==="mysql"?(a=po(a,"mysql"),a=lo(a)):t==="sqlite"&&(a=po(a,"sqlite"),a=ii(a),a=lo(a)),a!==i&&R.writeFileSync(r,a)}function ci(e){let t=ke.join(e,".env.example");return R.existsSync(t)?R.readFileSync(t,"utf8"):""}function pi(e,t,n,o){let r=ke.join(e,".env.example"),s=ci(e),i=o?`# ${o}
1203
+ ${t}="${n}"
1204
+ `:`${t}="${n}"
1205
+ `,a=new RegExp(`^\\s*${t}\\s*=.*$`,"m");if(a.test(s)){R.writeFileSync(r,s.replace(a,`${t}="${n}"`));return}s?R.appendFileSync(r,`
1206
+ ${i}`):R.writeFileSync(r,i)}function li(e,t){let n=ke.join(e,"packages","platform","db","prisma","schema.prisma");if(!R.existsSync(n))return;let o=R.readFileSync(n,"utf8"),r=/(datasource\s+db\s*\{[^}]*?)(\n})/;if(!o.match(r))return;let i=t.filter(p=>!o.includes(p.trim()));if(i.length===0)return;let a=i.map(p=>` ${p}`).join(`
1207
+ `),c=o.replace(r,`$1
1208
+ ${a}$2`);R.writeFileSync(n,c)}function di(e){let t=ke.join(e,"packages","platform","db","prisma","schema.prisma");if(!R.existsSync(t))return;let n=R.readFileSync(t,"utf8");if(/directUrl\s*=\s*env\(/.test(n))return;let o=/(datasource\s+db\s*\{[\s\S]*?url\s*=\s*env\(\s*"DATABASE_URL"\s*\)[^\n]*\n)/;o.test(n)&&R.writeFileSync(t,n.replace(o,`$1 directUrl = env("DIRECT_URL")
1209
+ `))}async function mo(e,t,n){if(!(t.id==="none"||t.id==="local")){for(let o of t.envVars){let r=o.placeholder.replace(/\$PROJECT/g,n);pi(e,o.name,r,o.comment)}t.prismaDatasourceExtras&&t.prismaDatasourceExtras.length>0&&li(e,t.prismaDatasourceExtras),t.keepDirectUrl&&di(e)}}import ve from"fs";import Te from"path";import{fileURLToPath as ui}from"url";var mi=ui(import.meta.url),go=Te.dirname(mi),gi=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|vue)$/,fo=["fumadocs","nextra","mintlify","docusaurus","vitepress"];function fi(e){let t=[Te.join(go,"..","templates","docs",e),Te.join(go,"..","..","templates","docs",e)];for(let n of t)if(ve.existsSync(n))return n;return t[0]}async function yo(e,t){if(t.framework==="none")return;if(!fo.includes(t.framework))throw new Error(`Unsupported docs framework: "${t.framework}". Supported: ${fo.join(", ")}, none.`);let n=fi(t.framework),o=Te.join(e,"apps","docs");if(!ve.existsSync(n))throw new Error(`Docs template not found: ${n}`);So(n,o),ho(o,{"{PRODUCT_NAME}":t.projectName})}function So(e,t){ve.mkdirSync(t,{recursive:!0});for(let n of ve.readdirSync(e,{withFileTypes:!0})){let o=Te.join(e,n.name),r=Te.join(t,n.name);n.isDirectory()?So(o,r):ve.copyFileSync(o,r)}}function ho(e,t){for(let n of ve.readdirSync(e,{withFileTypes:!0})){let o=Te.join(e,n.name);if(n.isDirectory())ho(o,t);else if(gi.test(n.name)){let r=ve.readFileSync(o,"utf-8");for(let[s,i]of Object.entries(t))r=r.split(s).join(i);ve.writeFileSync(o,r)}}}import Oe from"fs";import Ne from"path";var wt=[{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 Eo(e){return wt.find(t=>t.id===e)}var Pl=wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Le="@nebutra/email";function an(e,t){Oe.mkdirSync(Ne.dirname(e),{recursive:!0}),Oe.writeFileSync(e,t)}function yi(e,t){let n=Ne.join(e,".env.example");Oe.existsSync(n)?Oe.appendFileSync(n,`
1210
+ `+t):Oe.writeFileSync(n,t)}function Si(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,n=e.envVars.map(o=>`${o}=`).join(`
1349
1211
  `);return`${t}
1350
- ${o}
1351
- `}var pi=`/**
1212
+ ${n}
1213
+ `}var hi=`/**
1352
1214
  * Public inputs accepted by the \`sendEmail\` wrapper.
1353
1215
  * Keep the surface minimal \u2014 individual providers may accept more, but
1354
1216
  * consumers should code against this shape for portability.
@@ -1368,8 +1230,8 @@ export interface SendEmailResult {
1368
1230
  /** Raw provider response \u2014 useful for debugging, not a stable contract. */
1369
1231
  raw?: unknown;
1370
1232
  }
1371
- `;function li(){return`/**
1372
- * @${Oe.slice(1)} \u2014 Resend transactional email wrapper.
1233
+ `;function Ei(){return`/**
1234
+ * @${Le.slice(1)} \u2014 Resend transactional email wrapper.
1373
1235
  *
1374
1236
  * Docs: https://resend.com/docs
1375
1237
  */
@@ -1407,8 +1269,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1407
1269
  }
1408
1270
 
1409
1271
  export type { SendEmailInput, SendEmailResult } from "./types";
1410
- `}function di(){return`/**
1411
- * @${Oe.slice(1)} \u2014 Postmark transactional email wrapper.
1272
+ `}function vi(){return`/**
1273
+ * @${Le.slice(1)} \u2014 Postmark transactional email wrapper.
1412
1274
  *
1413
1275
  * Docs: https://postmarkapp.com/developer
1414
1276
  */
@@ -1445,8 +1307,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1445
1307
  }
1446
1308
 
1447
1309
  export type { SendEmailInput, SendEmailResult } from "./types";
1448
- `}function ui(){return`/**
1449
- * @${Oe.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
1310
+ `}function bi(){return`/**
1311
+ * @${Le.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
1450
1312
  *
1451
1313
  * Docs: https://docs.aws.amazon.com/ses
1452
1314
  */
@@ -1501,8 +1363,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1501
1363
  }
1502
1364
 
1503
1365
  export type { SendEmailInput, SendEmailResult } from "./types";
1504
- `}function mi(){return`/**
1505
- * @${Oe.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
1366
+ `}function _i(){return`/**
1367
+ * @${Le.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
1506
1368
  *
1507
1369
  * Docs: https://help.aliyun.com/product/29412.html
1508
1370
  */
@@ -1551,8 +1413,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1551
1413
  }
1552
1414
 
1553
1415
  export type { SendEmailInput, SendEmailResult } from "./types";
1554
- `}function gi(){return`/**
1555
- * @${Oe.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
1416
+ `}function Pi(){return`/**
1417
+ * @${Le.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
1556
1418
  *
1557
1419
  * Docs: https://cloud.tencent.com/document/product/1288
1558
1420
  */
@@ -1599,8 +1461,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1599
1461
  }
1600
1462
 
1601
1463
  export type { SendEmailInput, SendEmailResult } from "./types";
1602
- `}function fi(){return`/**
1603
- * @${Oe.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
1464
+ `}function wi(){return`/**
1465
+ * @${Le.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
1604
1466
  *
1605
1467
  * Docs: https://qiye.163.com/help
1606
1468
  */
@@ -1637,32 +1499,32 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1637
1499
  }
1638
1500
 
1639
1501
  export type { SendEmailInput, SendEmailResult } from "./types";
1640
- `}function yi(e){switch(e){case"resend":return li();case"postmark":return di();case"ses":return ui();case"aliyun-dm":return mi();case"tencent-ses":return gi();case"netease":return fi();case"none":return`export {};
1641
- `}}function Si(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),e.id==="aliyun-dm"&&(t["@alicloud/openapi-client"]="^0.4.12");let o={name:Oe,version:"0.1.0",private:!0,description:`Transactional email via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
1642
- `}async function io(e,t,o){if(t==="none")return;let n=so(t);if(!n)throw new Error(`Unknown email provider "${t}". Valid ids: ${Yt.map(i=>i.id).join(", ")}`);let r=Ne.join(e,"packages","email"),s=Ne.join(r,"src");Te.existsSync(s)&&Te.rmSync(s,{recursive:!0,force:!0}),cn(Ne.join(r,"package.json"),Si(n)),cn(Ne.join(s,"types.ts"),pi),cn(Ne.join(s,"index.ts"),yi(n.id)),ai(e,ci(n))}import qt from"fs";import ao from"path";async function co(e,t){let o=`# Automatically injected by create-sailor
1643
- DATABASE_URL="${String(t.databaseUrl)}"
1644
-
1645
- NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="${String(t.clerkPublishable)}"
1646
- CLERK_SECRET_KEY="${String(t.clerkSecret)}"
1647
-
1648
- NEXT_PUBLIC_SITE_URL="http://localhost:3000"
1649
- `,n=ao.join(e,".env"),r=ao.join(e,".env.local");!qt.existsSync(n)&&!qt.existsSync(r)?qt.writeFileSync(r,o):qt.appendFileSync(r,`
1650
- `+o)}import lo from"crypto";import bt from"fs";import po from"path";function Le(e){return lo.randomBytes(e).toString("base64").replace(/=+$/,"")}function hi(e){return lo.randomBytes(e).toString("hex")}function Ei(){return{AUTH_SECRET:Le(32),NEXTAUTH_SECRET:Le(32),BETTER_AUTH_SECRET:Le(32),JWT_SECRET:Le(32),WEBHOOK_SECRET:hi(16),ENCRYPTION_KEY:Le(32),API_SECRET_KEY:Le(32),SESSION_SECRET:Le(32)}}function vi(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function _i(e,t,o){let n=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=vi(o);return e.replace(n,`${t}="${r}"`)}async function uo(e){let t=po.join(e,".env.example"),o=po.join(e,".env.local");if(!bt.existsSync(t))return null;try{let n=bt.readFileSync(t,"utf8"),r=Ei(),i=bt.existsSync(o)?bt.readFileSync(o,"utf8"):n;for(let c of Object.keys(r))i=_i(i,c,r[c]);return bt.writeFileSync(o,i),r}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate env secrets: ${r}`),new Error(`Unable to write .env.local: ${r}`)}}var Gt=[{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 mo(e){return Gt.find(t=>t.id===e)}var Xp=Gt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function go(e,t,o="global"){let n=mo(t);if(!n)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${Gt.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"feature-flags");return}n.envVars.length>0&&te(e,{category:"Feature Flags",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"FEATURE_FLAGS_PROVIDER",n.id)}import{existsSync as bi,mkdirSync as fo,writeFileSync as yo}from"fs";import{homedir as So,platform as Pi}from"os";import{join as Pt}from"path";function Ai(){if(Pi()==="win32"){let t=process.env.LOCALAPPDATA||Pt(So(),"AppData","Local");return Pt(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?Pt(e,"nebutra"):Pt(So(),".config","nebutra")}function Ci(){let e=process.env.NEBUTRA_TELEMETRY;return e==="0"||e==="false"||e==="no"}function ho(){if(!process.stderr.isTTY||!process.stdin.isTTY||process.env.CI)return;let e=Ai(),t=Pt(e,"first-run-acked");try{if(bi(t))return}catch{return}if(Ci()){try{fo(e,{recursive:!0}),yo(t,"")}catch{}return}let o=["[36m\u2139[0m Nebutra collects anonymous usage analytics to improve the scaffolder."," Opt out at any time: export NEBUTRA_TELEMETRY=0"," Privacy policy: https://nebutra.com/legal/cli-analytics",""];try{process.stderr.write(o.join(`
1651
- `))}catch{}try{fo(e,{recursive:!0}),yo(t,"")}catch{}}import{execFileSync as _o}from"child_process";import D from"fs";import Ii from"os";import fe from"path";import wi from"ignore";var Ri={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 ki(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function xi(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function bo(e){return/^[0-9a-f]{7,40}$/i.test(e)}function Ni(e,t){let o=`https://github.com/${e}.git`,n=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of n)try{let s=_o("git",["ls-remote",o,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!s)continue;let[i]=s.split(/\s+/);if(bo(i))return i}catch{}return null}async function Ti(e,t){if(bo(t))return t;let o=await fetch(`https://api.github.com/repos/${e}/commits/${encodeURIComponent(t)}`,{headers:{Accept:"application/vnd.github+json","User-Agent":"create-sailor"}});if(!o.ok){let r=Ni(e,t);if(r)return r;throw new Error(`Failed to resolve ${e}@${t} (GitHub API ${o.status})`)}let n=await o.json();if(typeof n.sha!="string"||n.sha.length===0)throw new Error(`GitHub API did not return a commit SHA for ${e}@${t}`);return n.sha}function Po(e,t,o){let n=D.readdirSync(t,{withFileTypes:!0});for(let r of n){if(r.name==="node_modules"||r.name===".git")continue;let s=fe.join(t,r.name),i=fe.relative(e,s).split(fe.sep).join("/");r.isDirectory()?(o.push(i+"/"),Po(e,s,o)):o.push(i)}}function Oi(e){let t=fe.join(e,".templateignore");if(!D.existsSync(t))return;let o=D.readFileSync(t,"utf8"),n=wi().add(o),r=[];Po(e,e,r);let s=r.map(a=>a.endsWith("/")?a.slice(0,-1):a),i=new Set(n.filter(s)),c=s.filter(a=>!i.has(a)).sort((a,l)=>l.split("/").length-a.split("/").length);for(let a of c){let l=fe.join(e,a);try{D.existsSync(l)&&D.rmSync(l,{recursive:!0,force:!0})}catch{}}try{D.existsSync(t)&&D.rmSync(t,{force:!0})}catch{}}async function Eo(e,t){let o=await fetch(e,{headers:{Accept:"application/octet-stream","User-Agent":"create-sailor"}});if(!o.ok)throw new Error(`Failed to download archive (${o.status})`);let n=Buffer.from(await o.arrayBuffer());if(n.byteLength<1024)throw new Error(`Downloaded archive is unexpectedly small (${n.byteLength} bytes)`);D.writeFileSync(t,n);let r=D.statSync(t);if(r.size!==n.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${n.byteLength})`);return r.size}function vo(e,t){_o("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function Ao(e){try{let t=D.readdirSync(e);for(let o of t)D.rmSync(fe.join(e,o),{recursive:!0,force:!0})}catch{}}async function Li(e,t){let o=D.mkdtempSync(fe.join(Ii.tmpdir(),"create-sailor-")),n=fe.join(o,"template.tar.gz");try{let r=await Ti(e.repo,e.ref);await Eo(xi(e.repo,r),n),vo(n,t)}catch(r){if(!e.allowMutableFallback)throw r;Ao(t),await Eo(ki(e.repo,e.ref),n),vo(n,t)}finally{D.rmSync(o,{recursive:!0,force:!0})}}async function Co(e){D.mkdirSync(e,{recursive:!0});let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],n;for(let r of o){let s=Ri[r];try{if(await Li(s,e),s.applyIgnore)try{Oi(e)}catch(i){throw new Error(`Template cloned, but .templateignore processing failed: ${i instanceof Error?i.message:String(i)}`)}return}catch(i){n=i instanceof Error?i:new Error(String(i)),Ao(e)}}throw new Error(`Failed to download the template from any source. Last error: ${n?.message??"unknown"}
1502
+ `}function Ai(e){switch(e){case"resend":return Ei();case"postmark":return vi();case"ses":return bi();case"aliyun-dm":return _i();case"tencent-ses":return Pi();case"netease":return wi();case"none":return`export {};
1503
+ `}}function Ii(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),e.id==="aliyun-dm"&&(t["@alicloud/openapi-client"]="^0.4.12");let n={name:Le,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(n,null,2)+`
1504
+ `}async function vo(e,t,n){if(t==="none")return;let o=Eo(t);if(!o)throw new Error(`Unknown email provider "${t}". Valid ids: ${wt.map(i=>i.id).join(", ")}`);let r=Ne.join(e,"packages","email"),s=Ne.join(r,"src");Oe.existsSync(s)&&Oe.rmSync(s,{recursive:!0,force:!0}),an(Ne.join(r,"package.json"),Ii(o)),an(Ne.join(s,"types.ts"),hi),an(Ne.join(s,"index.ts"),Ai(o.id)),yi(e,Si(o))}import be from"fs";import bo from"path";function Ci(e,t){return new RegExp(`^\\s*${t}\\s*=`,"m").test(e)}function xi(e){return e.endsWith(`
1505
+ `)?e:`${e}
1506
+ `}async function _o(e,t){let n=bo.join(e,".env"),o=bo.join(e,".env.local"),r=be.existsSync(n)?be.readFileSync(n,"utf8"):"",s=be.existsSync(o)?be.readFileSync(o,"utf8"):"",i=`${r}
1507
+ ${s}`,a=[{name:"DATABASE_URL",value:String(t.databaseUrl)},{name:"NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY",value:String(t.clerkPublishable)},{name:"CLERK_SECRET_KEY",value:String(t.clerkSecret)},{name:"NEXT_PUBLIC_SITE_URL",value:"http://localhost:3000"}].filter(p=>!Ci(i,p.name)).map(p=>`${p.name}="${p.value}"`);if(a.length===0)return;let c=`# Automatically injected by create-sailor
1508
+ ${a.join(`
1509
+ `)}
1510
+ `;if(!be.existsSync(n)&&!be.existsSync(o))be.writeFileSync(o,c);else{let p=s?xi(s):"";be.writeFileSync(o,`${p}
1511
+ ${c}`)}}import wo from"crypto";import pt from"fs";import Po from"path";function Ue(e){return wo.randomBytes(e).toString("base64").replace(/=+$/,"")}function Ri(e){return wo.randomBytes(e).toString("hex")}function ki(){return{AUTH_SECRET:Ue(32),NEXTAUTH_SECRET:Ue(32),BETTER_AUTH_SECRET:Ue(32),JWT_SECRET:Ue(32),WEBHOOK_SECRET:Ri(16),ENCRYPTION_KEY:Ue(32),API_SECRET_KEY:Ue(32),SESSION_SECRET:Ue(32)}}function Ti(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Ni(e,t,n){let o=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=Ti(n);return e.replace(o,`${t}="${r}"`)}async function Ao(e){let t=Po.join(e,".env.example"),n=Po.join(e,".env.local");if(!pt.existsSync(t))return null;try{let o=pt.readFileSync(t,"utf8"),r=ki(),i=pt.existsSync(n)?pt.readFileSync(n,"utf8"):o;for(let a of Object.keys(r))i=Ni(i,a,r[a]);return pt.writeFileSync(n,i),r}catch(o){let r=o instanceof Error?o.message:String(o);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 Io(e){return At.find(t=>t.id===e)}var Ml=At.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Co(e,t,n="global"){let o=Io(t);if(!o)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${At.map(r=>r.id).join(", ")}`);if(o.id==="none"){z(e,"feature-flags");return}o.envVars.length>0&&oe(e,{category:"Feature Flags",name:o.name,envVars:o.envVars,docs:o.docs}),re(e,"FEATURE_FLAGS_PROVIDER",o.id)}import{execFileSync as To}from"child_process";import L from"fs";import Oi from"os";import ie from"path";import Li from"ignore";var Ui={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 Mi(){let e=process.env.SAILOR_TEMPLATE_LOCAL_DIR;if(!(!e||e.trim().length===0))return ie.resolve(e.trim())}var Di=new Set(["node_modules",".git","dist",".next",".turbo"]);function Fi(e,t){if(!L.statSync(e).isDirectory())throw new Error(`SAILOR_TEMPLATE_LOCAL_DIR is not a directory: ${e}`);L.cpSync(e,t,{recursive:!0,dereference:!0,filter:o=>{let r=ie.basename(o);return!Di.has(r)}})}function ji(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function Bi(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function No(e){return/^[0-9a-f]{7,40}$/i.test(e)}function Vi(e,t){let n=`https://github.com/${e}.git`,o=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of o)try{let s=To("git",["ls-remote",n,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!s)continue;let[i]=s.split(/\s+/);if(No(i))return i}catch{}return null}async function Ki(e,t){if(No(t))return t;let n=await fetch(`https://api.github.com/repos/${e}/commits/${encodeURIComponent(t)}`,{headers:{Accept:"application/vnd.github+json","User-Agent":"create-sailor"}});if(!n.ok){let r=Vi(e,t);if(r)return r;throw new Error(`Failed to resolve ${e}@${t} (GitHub API ${n.status})`)}let o=await n.json();if(typeof o.sha!="string"||o.sha.length===0)throw new Error(`GitHub API did not return a commit SHA for ${e}@${t}`);return o.sha}function Oo(e,t,n){let o=L.readdirSync(t,{withFileTypes:!0});for(let r of o){if(r.name==="node_modules"||r.name===".git")continue;let s=ie.join(t,r.name),i=ie.relative(e,s).split(ie.sep).join("/");r.isDirectory()?(n.push(i+"/"),Oo(e,s,n)):n.push(i)}}function xo(e){let t=ie.join(e,".templateignore");if(!L.existsSync(t))return;let n=L.readFileSync(t,"utf8"),o=Li().add(n),r=[];Oo(e,e,r);let s=r.map(c=>c.endsWith("/")?c.slice(0,-1):c),i=new Set(o.filter(s)),a=s.filter(c=>!i.has(c)).sort((c,p)=>p.split("/").length-c.split("/").length);for(let c of a){let p=ie.join(e,c);try{L.existsSync(p)&&L.rmSync(p,{recursive:!0,force:!0})}catch{}}try{L.existsSync(t)&&L.rmSync(t,{force:!0})}catch{}}async function Ro(e,t){let n=await fetch(e,{headers:{Accept:"application/octet-stream","User-Agent":"create-sailor"}});if(!n.ok)throw new Error(`Failed to download archive (${n.status})`);let o=Buffer.from(await n.arrayBuffer());if(o.byteLength<1024)throw new Error(`Downloaded archive is unexpectedly small (${o.byteLength} bytes)`);L.writeFileSync(t,o);let r=L.statSync(t);if(r.size!==o.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${o.byteLength})`);return r.size}function ko(e,t){To("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function cn(e){try{let t=L.readdirSync(e);for(let n of t)L.rmSync(ie.join(e,n),{recursive:!0,force:!0})}catch{}}async function $i(e,t){let n=L.mkdtempSync(ie.join(Oi.tmpdir(),"create-sailor-")),o=ie.join(n,"template.tar.gz");try{let r=await Ki(e.repo,e.ref);await Ro(Bi(e.repo,r),o),ko(o,t)}catch(r){if(!e.allowMutableFallback)throw r;cn(t),await Ro(ji(e.repo,e.ref),o),ko(o,t)}finally{L.rmSync(n,{recursive:!0,force:!0})}}async function Lo(e){L.mkdirSync(e,{recursive:!0});let t=Mi();if(t){if(!L.existsSync(t))throw new Error(`SAILOR_TEMPLATE_LOCAL_DIR does not exist: ${t}`);cn(e),Fi(t,e);try{xo(e)}catch(s){throw new Error(`Local template copied, but .templateignore processing failed: ${s instanceof Error?s.message:String(s)}`)}return}let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],r;for(let s of o){let i=Ui[s];try{if(await $i(i,e),i.applyIgnore)try{xo(e)}catch(a){throw new Error(`Template cloned, but .templateignore processing failed: ${a instanceof Error?a.message:String(a)}`)}return}catch(a){r=a instanceof Error?a:new Error(String(a)),cn(e)}}throw new Error(`Failed to download the template from any source. Last error: ${r?.message??"unknown"}
1652
1512
 
1653
1513
  Ensure you have internet access and 'tar' installed.
1654
- You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import{createHmac as Mi,randomBytes as Di}from"crypto";import J from"fs";import re from"path";import{fileURLToPath as Fi}from"url";var Ui=[{id:"v1",key:"nebutra-sailor:scaffold-marker:v1"}];function Io(){let e=Ui[0];if(!e)throw new Error("license-signing-keys: registry is empty \u2014 at least one key is required.");return e}var ji=Fi(import.meta.url),wo=re.dirname(ji),Ro="scaffold-meta.json",ko=".nebutra";function Vi(e){if(e)return e;let t=[re.join(wo,"..","templates"),re.join(wo,"..","..","templates")];for(let o of t)if(J.existsSync(o))return o;return t[0]}function Bi(e,t){let o=`${e.cliVersion}|${e.scaffoldedAt}|${e.projectName}|${e.nonce}`;return Mi("sha256",t).update(o).digest("hex")}function xo(e,t){let o=[],n=Vi(t.templatesRoot),r=re.join(e,"LICENSE");if(J.existsSync(r)){let C=J.readFileSync(r,"utf-8").slice(0,256);/GNU AFFERO GENERAL PUBLIC LICENSE/i.test(C)&&(J.renameSync(r,re.join(e,"LICENSE-AGPL-REFERENCE.md")),o.push("LICENSE-AGPL-REFERENCE.md (preserved upstream AGPL)"))}let s=re.join(n,"LICENSE-INDEPENDENT.md");if(!J.existsSync(s))throw new Error(`LICENSE-INDEPENDENT.md template missing at ${s}; cannot emit license.`);J.copyFileSync(s,re.join(e,"LICENSE")),o.push("LICENSE");let i=new Date().toISOString(),c=Di(12).toString("hex"),a=Io(),l=Bi({cliVersion:t.cliVersion,scaffoldedAt:i,projectName:t.projectName,nonce:c},a.key),u={schemaVersion:1,cliVersion:t.cliVersion,scaffoldedAt:i,projectName:t.projectName,nonce:c,signature:l,signingKeyId:a.id,purpose:"Marks this project as scaffolded by the official `create-sailor` CLI. The Independent Developer License in LICENSE applies as long as this file is present and the signature verifies.",license:{tier:"independent",file:"LICENSE",upgradeUrl:"https://nebutra.com/get-license"}},S=re.join(e,ko);J.mkdirSync(S,{recursive:!0}),J.writeFileSync(re.join(S,Ro),`${JSON.stringify(u,null,2)}
1655
- `),o.push(`${ko}/${Ro}`);let I=re.join(e,"README.md");if(J.existsSync(I)){let C=J.readFileSync(I,"utf-8");C.includes("Nebutra-Sailor Independent Developer License")||(J.writeFileSync(I,`> **License notice:** scaffolded by \`create-sailor\` under the
1514
+ You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import It from"fs";import pn from"path";var Yi="node scripts/governance/lint-no-raw-inputs.mjs",qi="node scripts/governance/lint-repository-seam.mjs",Gi="node scripts/governance/lint-brand-literals.mjs",Hi="node scripts/governance/lint-microcopy.mjs",Wi=/\bnode\s+scripts\/(governance\/)?lint-[\w-]+\.mjs/g,Xi=/\bnode\s+scripts\/lint-[\w-]+\.mjs/,zi={scanRoots:["apps"],primitivesImport:"@nebutra/ui/primitives",whitelist:["/storybook/src/stories/","/design-docs/src/components/previews/","/sailor-docs/src/components/previews/","\\.test\\.tsx?$","/__tests__/"]},Ji={coreDomains:["^packages/.*/(billing|license|metering|auth|audit|permissions|identity|tenant)/","^backends/gateway/src/routes/(billing|ai|admin|legal|integrations|webhooks)/","^apps/web/src/app/api/"],seamPaths:["^packages/platform/repositories/","^packages/platform/db/"],dbAccessors:["getTenantDb","getSystemDb"],allowlist:["apps/web/src/app/api/invitations/[invitationId]/accept/route.ts","apps/web/src/app/api/onboarding/invite-members/route.ts","apps/web/src/app/api/startup-os/projects/[projectId]/runs/[runId]/execute/route.ts","apps/web/src/app/api/cofounder/room/[profileId]/form-team/route.ts","apps/web/src/app/api/provider-keys/route.ts","backends/gateway/src/routes/admin/index.ts","backends/gateway/src/routes/ai/api-keys.ts","backends/gateway/src/routes/ai/usage.ts","backends/gateway/src/routes/billing/index.ts","backends/gateway/src/routes/integrations/index.ts","backends/gateway/src/routes/legal/consent.ts","backends/gateway/src/routes/webhooks/clerk.ts","backends/gateway/src/routes/webhooks/stripe.ts","packages/commerce/license/src/issue-license.ts","packages/commerce/license/src/validate-license.ts","packages/commerce/billing/src/credits/service.ts","packages/commerce/billing/src/usage/ledger.ts","packages/iam/audit/src/index.ts","packages/iam/auth/src/plugins/passkey-plugin.ts"]},Qi={scanRoots:["apps/web/src"],excludePaths:["/api/","\\.test\\.tsx?$","/__tests__/","/storybook/src/stories/","/design-docs/","/sailor-docs/"],bannedPatterns:[],allowlist:[]},Uo={governedPaths:["apps","packages/commerce","packages/integrations/email"],allowExpressions:["Nebutra","\u4E91\u6BD3\u667A\u80FD","\u4E91\u6BD3","nebutra\\.com","nebutra\\.ai","#0033FE","#0BF1C3"],knownExemptPatterns:["\\.stories\\.tsx?$","/__tests__/","\\.test\\.tsx?$","/previews/","^packages/design/brand/","^packages/design/tokens/","^packages/design/design-tokens/"],allowlist:[]},Zi=["apps/design-docs/mdx-components.tsx","apps/design-docs/next.config.ts","apps/design-docs/src/__registry__/index.tsx","apps/design-docs/src/app/[lang]/docs/[[...slug]]/page.tsx","apps/design-docs/src/app/[lang]/docs/layout.tsx","apps/design-docs/src/app/[lang]/layout.tsx","apps/design-docs/src/app/[lang]/registry/[name]/page.tsx","apps/design-docs/src/app/[lang]/registry/page.tsx","apps/design-docs/src/app/og/docs/[...slug]/route.tsx","apps/design-docs/src/components/brand-overview-visuals.tsx","apps/design-docs/src/components/color-usage.tsx","apps/design-docs/src/components/component-preview.tsx","apps/design-docs/src/components/gradient-demos.tsx","apps/design-docs/src/components/introduction-hero.tsx","apps/design-docs/src/components/motion-demos.tsx","apps/design-docs/src/components/pattern-demos.tsx","apps/design-docs/src/components/registry/registry-card.tsx","apps/design-docs/src/lib/github.ts","apps/design-docs/src/lib/registry-strings.ts","apps/design-docs/src/lib/registry.ts","apps/idp/src/app/layout.tsx","apps/idp/src/app/oauth/authorize/page.tsx","apps/idp/src/app/page.tsx","apps/idp/src/lib/oidc.ts","apps/landing-page/src/app/[lang]/layout.tsx","apps/landing-page/src/app/api/blog/comments/route.ts","apps/landing-page/src/app/api/blog/reactions/route.ts","apps/landing-page/src/app/api/og/route.ts","apps/landing-page/src/app/apple-icon.tsx","apps/landing-page/src/components/auth/google-one-tap.tsx","apps/landing-page/src/components/cookie-consent-banner.tsx","apps/landing-page/src/components/marketing/ProductHuntSection.tsx","apps/landing-page/src/components/marketing/TestimonialsSection.tsx","apps/landing-page/src/i18n/request.ts","apps/landing-page/src/lib/analytics/emit.ts","apps/landing-page/src/lib/blog-fallback.ts","apps/landing-page/src/lib/constants/playbook-data.ts","apps/landing-page/src/lib/constants/resources-data.ts","apps/landing-page/src/lib/constants/solutions-data.ts","apps/landing-page/src/lib/docs-links.ts","apps/landing-page/src/lib/env.ts","apps/landing-page/src/lib/landing-content.ts","apps/landing-page/src/lib/seo/metadata.ts","apps/landing-page/src/lib/seo/site-routes.ts","apps/landing-page/src/lib/status-checks.ts","apps/landing-page/src/proxy.ts","apps/mail-preview/scripts/export.ts","apps/mail-preview/scripts/render-react-templates.ts","apps/mail-preview/src/app/api/send-test/route.ts","apps/mail-preview/src/app/layout.tsx","apps/mail-preview/src/lib/fixtures.ts","apps/web/next.config.ts","apps/web/src/app/(app)/checkout-return/page.tsx","apps/web/src/app/(app)/choose-plan/page.tsx","apps/web/src/app/(app)/settings/api-keys/page.tsx","apps/web/src/app/(app)/settings/notifications/page.tsx","apps/web/src/app/(app)/settings/provider-keys/page.tsx","apps/web/src/app/(auth)/desktop-auth/complete/page.tsx","apps/web/src/app/(public)/page.tsx","apps/web/src/app/[locale]/welcome/page.tsx","apps/web/src/app/api/account/email-change/route.ts","apps/web/src/app/api/admin/access-invites/route.ts","apps/web/src/app/api/blog/comments/route.ts","apps/web/src/app/api/blog/reactions/route.ts","apps/web/src/app/api/me/public/route.ts","apps/web/src/app/api/organizations/[orgId]/members/route.ts","apps/web/src/app/global-error.tsx","apps/web/src/components/ErrorBoundary.tsx","apps/web/src/components/api-keys/create-api-key-dialog.tsx","apps/web/src/components/appearance/store.ts","apps/web/src/components/auth/auth-banner.tsx","apps/web/src/components/auth/desktop-auth-complete-handoff.tsx","apps/web/src/components/auth/sign-up-form.tsx","apps/web/src/components/billing/billing-self-service.tsx","apps/web/src/components/navigation/public-page-chrome.tsx","apps/web/src/components/notifications/inbox-bell.tsx","apps/web/src/components/notifications/notification-inbox-preview.tsx","apps/web/src/components/notifications/notification-preference-matrix.tsx","apps/web/src/components/notifications/notification-runtime-banner.tsx","apps/web/src/components/settings/security/security-capabilities.ts","apps/web/src/components/settings/security/security-settings-client.tsx","apps/web/src/components/theme-playground/design-md-import.tsx","apps/web/src/components/theme-playground/theme-playground-workbench.tsx","apps/web/src/components/theme-playground/theme-token-data.ts","apps/web/src/lib/api.ts","apps/web/src/lib/api/client.ts","apps/web/src/lib/env.ts","apps/web/src/lib/integrations/catalog.tsx","apps/web/src/lib/permissions.ts","apps/web/src/lib/public-url-defaults.ts","apps/web/src/lib/session-hint.ts","apps/web/src/lib/startup-os/company-context/generate.ts","apps/web/src/lib/startup-os/company-context/projection.ts","apps/web/src/lib/startup-os/conversation.ts","apps/web/src/lib/startup-os/execution.ts","apps/web/src/lib/startup-os/files.ts","apps/web/src/proxy.ts","packages/commerce/billing/src/index.ts","packages/commerce/contracts/src/identity.ts","packages/commerce/legal/src/components/CookieBanner.tsx","packages/commerce/legal/src/documents/config.ts","packages/commerce/legal/src/index.ts","packages/commerce/marketing/src/components/ProductHuntBadge.tsx","packages/commerce/marketing/src/config/index.ts","packages/commerce/marketing/src/index.ts","packages/integrations/email/src/index.ts","packages/integrations/email/src/templates/_layout.ts","packages/integrations/email/src/templates/invitation.tsx"];function ea(e,t){let n=(e??"").replace(Wi,"").split("&&").map(r=>r.trim()).filter(Boolean).join(" && ");return[n.length>0?n:"biome check .",...t].join(" && ")}function ta(e){let t=new RegExp(Uo.allowExpressions.join("|"));return Zi.filter(n=>{try{return t.test(It.readFileSync(pn.join(e,n),"utf8"))}catch{return!1}})}async function Mo(e,t){let n=t.database!=="none",o=[Yi];n&&o.push(qi),o.push(Gi),o.push(Hi);let r={...Uo,allowlist:ta(e)},s={rawInputs:zi,brandLiterals:r,microcopyRules:Qi};n&&(s.repositorySeam=Ji);let i=pn.join(e,"governance.config.json");It.writeFileSync(i,JSON.stringify(s,null,2)+`
1515
+ `);let a=pn.join(e,"package.json"),c;try{c=It.readFileSync(a,"utf8")}catch(p){if(p.code!=="ENOENT")throw p}if(c!==void 0){let p=JSON.parse(c);p.scripts=p.scripts??{};for(let[u,d]of Object.entries(p.scripts))u!=="lint"&&typeof d=="string"&&Xi.test(d)&&delete p.scripts[u];p.scripts.lint=ea(p.scripts.lint,o),It.writeFileSync(a,JSON.stringify(p,null,2)+`
1516
+ `)}return{lints:o,configWritten:!0}}import{createHmac as oa,randomBytes as ra}from"crypto";import Q from"fs";import ae from"path";import{fileURLToPath as sa}from"url";var na=[{id:"v1",key:"nebutra-sailor:scaffold-marker:v1"}];function Do(){let e=na[0];if(!e)throw new Error("license-signing-keys: registry is empty \u2014 at least one key is required.");return e}var ia=sa(import.meta.url),Fo=ae.dirname(ia),jo="scaffold-meta.json",Bo=".nebutra";function aa(e){if(e)return e;let t=[ae.join(Fo,"..","templates"),ae.join(Fo,"..","..","templates")];for(let n of t)if(Q.existsSync(n))return n;return t[0]}function ca(e,t){let n=`${e.cliVersion}|${e.scaffoldedAt}|${e.projectName}|${e.nonce}`;return oa("sha256",t).update(n).digest("hex")}function Vo(e,t){let n=[],o=aa(t.templatesRoot),r=ae.join(e,"LICENSE");if(Q.existsSync(r)){let h=Q.readFileSync(r,"utf-8").slice(0,256);/GNU AFFERO GENERAL PUBLIC LICENSE/i.test(h)&&(Q.renameSync(r,ae.join(e,"LICENSE-AGPL-REFERENCE.md")),n.push("LICENSE-AGPL-REFERENCE.md (preserved upstream AGPL)"))}let s=ae.join(o,"LICENSE-INDEPENDENT.md");if(!Q.existsSync(s))throw new Error(`LICENSE-INDEPENDENT.md template missing at ${s}; cannot emit license.`);Q.copyFileSync(s,ae.join(e,"LICENSE")),n.push("LICENSE");let i=new Date().toISOString(),a=ra(12).toString("hex"),c=Do(),p=ca({cliVersion:t.cliVersion,scaffoldedAt:i,projectName:t.projectName,nonce:a},c.key),u={schemaVersion:1,cliVersion:t.cliVersion,scaffoldedAt:i,projectName:t.projectName,nonce:a,signature:p,signingKeyId:c.id,purpose:"Marks this project as scaffolded by the official `create-sailor` CLI. The Independent Developer License in LICENSE applies as long as this file is present and the signature verifies.",license:{tier:"independent",file:"LICENSE",upgradeUrl:"https://nebutra.com/get-license"}},d=ae.join(e,Bo);Q.mkdirSync(d,{recursive:!0}),Q.writeFileSync(ae.join(d,jo),`${JSON.stringify(u,null,2)}
1517
+ `),n.push(`${Bo}/${jo}`);let _=ae.join(e,"README.md");if(Q.existsSync(_)){let h=Q.readFileSync(_,"utf-8");h.includes("Nebutra-Sailor Independent Developer License")||(Q.writeFileSync(_,`> **License notice:** scaffolded by \`create-sailor\` under the
1656
1518
  > [Nebutra-Sailor Independent Developer License](./LICENSE). Free for
1657
1519
  > individuals/OPC with \u2264 1 FTE and < $1M ARR; upgrade for larger teams at
1658
1520
  > https://nebutra.com/get-license. The upstream repository remains
1659
1521
  > AGPL-3.0 \u2014 see \`LICENSE-AGPL-REFERENCE.md\`.
1660
1522
 
1661
- `+C),o.push("README.md (prepended license notice)"))}return{wrote:o}}import Ue from"fs";import pn from"path";async function No(e,t){let o=pn.join(e,"packages","mcp");if(t==="off"){Ue.existsSync(o)&&Ue.rmSync(o,{recursive:!0,force:!0});let r=pn.join(e,"packages","cli","src","commands","mcp-server.ts");Ue.existsSync(r)&&Ue.rmSync(r,{force:!0});return}let n=pn.join(e,".env.example");if(Ue.existsSync(n)){let r=Ue.readFileSync(n,"utf-8"),s="# MCP Server (Agent-friendly API)";if(!r.includes(s)){let i=["","# =============================================",s,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
1662
- `);Ue.appendFileSync(n,i)}}}import At from"fs";import To from"path";async function Oo(e,t,o){let n=To.join(e,"packages","metering"),r;if(t==="auto"?r=o!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){At.existsSync(n)&&At.rmSync(n,{recursive:!0,force:!0});return}let s=To.join(e,".env.example");if(!At.existsSync(s))return;let i=At.readFileSync(s,"utf-8"),c="# Metering (usage-based billing)";if(!i.includes(c)){let a=["","# =============================================",c,"# Docs: see packages/commerce/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
1663
- `);At.appendFileSync(s,a)}}import ce from"fs";import F from"path";var Lo=[{id:"sentry",name:"Sentry",region:"both",envVars:["SENTRY_DSN","NEXT_PUBLIC_SENTRY_DSN"],docs:"https://docs.sentry.io",pkg:"@sentry/nextjs",instrumentationFile:"apps/web/instrumentation.ts"},{id:"datadog",name:"Datadog",region:"global",envVars:["DD_API_KEY","DD_APP_KEY","DD_SITE"],docs:"https://docs.datadoghq.com",pkg:"dd-trace",instrumentationFile:"apps/web/instrumentation.ts"},{id:"bugsnag",name:"Bugsnag",region:"global",envVars:["BUGSNAG_API_KEY","NEXT_PUBLIC_BUGSNAG_API_KEY"],docs:"https://docs.bugsnag.com",pkg:"@bugsnag/js",instrumentationFile:"apps/web/src/lib/monitoring/bugsnag.ts"},{id:"aliyun-arms",name:"\u963F\u91CC\u4E91 ARMS",region:"cn",envVars:["ALIYUN_ARMS_LICENSE_KEY","ALIYUN_ARMS_APP_NAME","NEXT_PUBLIC_ARMS_PID"],docs:"https://help.aliyun.com/product/34364.html",instrumentationFile:"apps/web/src/components/monitoring/ArmsScript.tsx"},{id:"tingyun",name:"\u542C\u4E91 TingYun",region:"cn",envVars:["TINGYUN_LICENSE_KEY","NEXT_PUBLIC_TINGYUN_APP_KEY"],docs:"https://www.tingyun.com/docs",instrumentationFile:"apps/web/src/components/monitoring/TingYunScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],Al=Lo.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Uo(e){return Lo.find(t=>t.id===e)}var ln={sentry:{"@sentry/nextjs":"^8.45.0"},datadog:{"dd-trace":"^5.32.0","@datadog/browser-rum":"^5.30.0"},bugsnag:{"@bugsnag/js":"^8.2.0","@bugsnag/plugin-react":"^8.2.0"}};function Ki(e){ce.mkdirSync(e,{recursive:!0})}function dn(e,t){let o=F.join(e,"package.json");if(!ce.existsSync(o))return;let n;try{n=JSON.parse(ce.readFileSync(o,"utf-8"))}catch(c){console.error(`Failed to parse ${o}:`,c);return}let s={...n.dependencies??{}};for(let[c,a]of Object.entries(t))s[c]||(s[c]=a);let i={...n,dependencies:s};ce.writeFileSync(o,JSON.stringify(i,null,2)+`
1664
- `)}function se(e,t){Ki(F.dirname(e)),ce.writeFileSync(e,t)}function Ct(e,t){let o=F.join(e,".env.example");ce.existsSync(o)?ce.appendFileSync(o,`
1665
- `+t):ce.writeFileSync(o,t)}function $i(e){let t=`import * as Sentry from "@sentry/nextjs";
1523
+ `+h),n.push("README.md (prepended license notice)"))}return{wrote:n}}import Me from"fs";import ln from"path";async function Ko(e,t){let n=ln.join(e,"packages","mcp");if(t==="off"){Me.existsSync(n)&&Me.rmSync(n,{recursive:!0,force:!0});let r=ln.join(e,"packages","cli","src","commands","mcp-server.ts");Me.existsSync(r)&&Me.rmSync(r,{force:!0});return}let o=ln.join(e,".env.example");if(Me.existsSync(o)){let r=Me.readFileSync(o,"utf-8"),s="# MCP Server (Agent-friendly API)";if(!r.includes(s)){let i=["","# =============================================",s,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
1524
+ `);Me.appendFileSync(o,i)}}}import lt from"fs";import $o from"path";async function Yo(e,t,n){let o=$o.join(e,"packages","metering"),r;if(t==="auto"?r=n!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){lt.existsSync(o)&&lt.rmSync(o,{recursive:!0,force:!0});return}let s=$o.join(e,".env.example");if(!lt.existsSync(s))return;let i=lt.readFileSync(s,"utf-8"),a="# Metering (usage-based billing)";if(!i.includes(a)){let c=["","# =============================================",a,"# Docs: see packages/commerce/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
1525
+ `);lt.appendFileSync(s,c)}}import de from"fs";import D from"path";var qo=[{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:""}],ld=qo.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Go(e){return qo.find(t=>t.id===e)}var dn={sentry:{"@sentry/nextjs":"^8.45.0"},datadog:{"dd-trace":"^5.32.0","@datadog/browser-rum":"^5.30.0"},bugsnag:{"@bugsnag/js":"^8.2.0","@bugsnag/plugin-react":"^8.2.0"}};function pa(e){de.mkdirSync(e,{recursive:!0})}function un(e,t){let n=D.join(e,"package.json");if(!de.existsSync(n))return;let o;try{o=JSON.parse(de.readFileSync(n,"utf-8"))}catch(a){console.error(`Failed to parse ${n}:`,a);return}let s={...o.dependencies??{}};for(let[a,c]of Object.entries(t))s[a]||(s[a]=c);let i={...o,dependencies:s};de.writeFileSync(n,JSON.stringify(i,null,2)+`
1526
+ `)}function ce(e,t){pa(D.dirname(e)),de.writeFileSync(e,t)}function dt(e,t){let n=D.join(e,".env.example");de.existsSync(n)?de.appendFileSync(n,`
1527
+ `+t):de.writeFileSync(n,t)}function la(e){let t=`import * as Sentry from "@sentry/nextjs";
1666
1528
 
1667
1529
  Sentry.init({
1668
1530
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
@@ -1677,14 +1539,14 @@ Sentry.init({
1677
1539
  ],
1678
1540
  environment: process.env.NODE_ENV,
1679
1541
  });
1680
- `,o=`import * as Sentry from "@sentry/nextjs";
1542
+ `,n=`import * as Sentry from "@sentry/nextjs";
1681
1543
 
1682
1544
  Sentry.init({
1683
1545
  dsn: process.env.SENTRY_DSN ?? process.env.NEXT_PUBLIC_SENTRY_DSN,
1684
1546
  tracesSampleRate: 1.0,
1685
1547
  environment: process.env.NODE_ENV,
1686
1548
  });
1687
- `,n=`import * as Sentry from "@sentry/nextjs";
1549
+ `,o=`import * as Sentry from "@sentry/nextjs";
1688
1550
 
1689
1551
  Sentry.init({
1690
1552
  dsn: process.env.SENTRY_DSN ?? process.env.NEXT_PUBLIC_SENTRY_DSN,
@@ -1705,14 +1567,14 @@ export async function register() {
1705
1567
  }
1706
1568
 
1707
1569
  export { captureRequestError as onRequestError } from "@sentry/nextjs";
1708
- `;se(F.join(e,"sentry.client.config.ts"),t),se(F.join(e,"sentry.server.config.ts"),o),se(F.join(e,"sentry.edge.config.ts"),n),se(F.join(e,"instrumentation.ts"),r)}function Yi(){return`# Sentry \u2014 error tracking + performance monitoring
1570
+ `;ce(D.join(e,"sentry.client.config.ts"),t),ce(D.join(e,"sentry.server.config.ts"),n),ce(D.join(e,"sentry.edge.config.ts"),o),ce(D.join(e,"instrumentation.ts"),r)}function da(){return`# Sentry \u2014 error tracking + performance monitoring
1709
1571
  # Get your DSN from https://sentry.io/settings/projects/<project>/keys/
1710
1572
  SENTRY_DSN=
1711
1573
  NEXT_PUBLIC_SENTRY_DSN=
1712
1574
  SENTRY_ORG=
1713
1575
  SENTRY_PROJECT=
1714
1576
  SENTRY_AUTH_TOKEN=
1715
- `}function qi(e){let t=`/**
1577
+ `}function ua(e){let t=`/**
1716
1578
  * Next.js instrumentation hook \u2014 wires Datadog APM (dd-trace) into Node runtime.
1717
1579
  * Edge runtime is not supported by dd-trace; only nodejs is initialized.
1718
1580
  */
@@ -1729,7 +1591,7 @@ export async function register() {
1729
1591
  });
1730
1592
  }
1731
1593
  }
1732
- `,o=`"use client";
1594
+ `,n=`"use client";
1733
1595
  /**
1734
1596
  * Datadog RUM (Real User Monitoring) \u2014 browser-side tracking.
1735
1597
  * Initialize once in your root layout via <DatadogRumProvider />.
@@ -1760,7 +1622,7 @@ export function initDatadogRum(): void {
1760
1622
  });
1761
1623
  initialized = true;
1762
1624
  }
1763
- `;se(F.join(e,"instrumentation.ts"),t),se(F.join(e,"src","lib","monitoring","datadog-rum.ts"),o)}function Gi(){return`# Datadog \u2014 APM + RUM
1625
+ `;ce(D.join(e,"instrumentation.ts"),t),ce(D.join(e,"src","lib","monitoring","datadog-rum.ts"),n)}function ma(){return`# Datadog \u2014 APM + RUM
1764
1626
  # Server APM (dd-trace)
1765
1627
  DD_API_KEY=
1766
1628
  DD_APP_KEY=
@@ -1775,7 +1637,7 @@ NEXT_PUBLIC_DD_SITE=datadoghq.com
1775
1637
  NEXT_PUBLIC_DD_SERVICE=sailor-web
1776
1638
  NEXT_PUBLIC_DD_ENV=production
1777
1639
  NEXT_PUBLIC_DD_VERSION=
1778
- `}function Hi(e){let t=`/**
1640
+ `}function ga(e){let t=`/**
1779
1641
  * Bugsnag server-side initialization.
1780
1642
  * Import this once at the top of your server entrypoint or a shared init module.
1781
1643
  */
@@ -1795,7 +1657,7 @@ export function startBugsnagServer(): void {
1795
1657
  });
1796
1658
  started = true;
1797
1659
  }
1798
- `,o=`"use client";
1660
+ `,n=`"use client";
1799
1661
  /**
1800
1662
  * Bugsnag browser initialization \u2014 wrap your app root with the returned provider.
1801
1663
  */
@@ -1824,11 +1686,11 @@ export function getBugsnagErrorBoundary() {
1824
1686
  errorBoundary = plugin.createErrorBoundary(React) as typeof errorBoundary;
1825
1687
  return errorBoundary;
1826
1688
  }
1827
- `;se(F.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),se(F.join(e,"src","lib","monitoring","bugsnag.client.tsx"),o)}function Wi(){return`# Bugsnag \u2014 error tracking
1689
+ `;ce(D.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),ce(D.join(e,"src","lib","monitoring","bugsnag.client.tsx"),n)}function fa(){return`# Bugsnag \u2014 error tracking
1828
1690
  BUGSNAG_API_KEY=
1829
1691
  NEXT_PUBLIC_BUGSNAG_API_KEY=
1830
1692
  APP_VERSION=
1831
- `}function Xi(e){se(F.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
1693
+ `}function ya(e){ce(D.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
1832
1694
  /**
1833
1695
  * \u963F\u91CC\u4E91 ARMS (Application Real-time Monitoring Service) browser agent.
1834
1696
  * Injects the official JS agent via next/script.
@@ -1849,11 +1711,11 @@ export function ArmsScript() {
1849
1711
  />
1850
1712
  );
1851
1713
  }
1852
- `)}function zi(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
1714
+ `)}function Sa(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
1853
1715
  ALIYUN_ARMS_LICENSE_KEY=
1854
1716
  ALIYUN_ARMS_APP_NAME=
1855
1717
  NEXT_PUBLIC_ARMS_PID=
1856
- `}function Ji(e){se(F.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
1718
+ `}function ha(e){ce(D.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
1857
1719
  /**
1858
1720
  * \u542C\u4E91 Browser Agent (\u524D\u7AEF\u6027\u80FD\u76D1\u63A7).
1859
1721
  * Docs: https://www.tingyun.com/docs
@@ -1871,12 +1733,12 @@ export function TingYunScript() {
1871
1733
  />
1872
1734
  );
1873
1735
  }
1874
- `)}function Qi(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
1736
+ `)}function Ea(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
1875
1737
  TINGYUN_LICENSE_KEY=
1876
1738
  NEXT_PUBLIC_TINGYUN_APP_KEY=
1877
- `}async function Mo(e,t,o="global"){let n=Uo(t);if(!n||n.id==="none")return;let r=F.join(e,"apps","web");if(!ce.existsSync(r))return;let s=n.id;try{switch(s){case"sentry":$i(r),dn(r,ln.sentry),Ct(e,Yi());return;case"datadog":qi(r),dn(r,ln.datadog),Ct(e,Gi());return;case"bugsnag":Hi(r),dn(r,ln.bugsnag),Ct(e,Wi());return;case"aliyun-arms":Xi(r),Ct(e,zi());return;case"tingyun":Ji(r),Ct(e,Qi());return;default:return}}catch(i){throw console.error(`Failed to apply monitoring selection "${t}":`,i),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Ht=[{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 Do(e){return Ht.find(t=>t.id===e)}var xl=Ht.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Fo(e,t,o="global"){let n=Do(t);if(!n)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Ht.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"notifications");return}n.envVars.length>0&&te(e,{category:"Notifications",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"NOTIFICATIONS_PROVIDER",n.id)}import un from"fs";import Zi from"path";async function jo(e,t){let o=Zi.join(e,"package.json");if(un.existsSync(o)){let n=un.readFileSync(o,"utf8"),r=JSON.parse(n);r.name=t,r.version="0.1.0",un.writeFileSync(o,JSON.stringify(r,null,2)+`
1878
- `)}}import Wt from"fs";import ct from"path";import{fileURLToPath as ea}from"url";var ta=ea(import.meta.url),Vo=ct.dirname(ta);function na(){let e=[ct.join(Vo,"..","templates","orm","drizzle"),ct.join(Vo,"..","..","templates","orm","drizzle")];for(let t of e)if(Wt.existsSync(t))return t;return null}function Bo(e,t){Wt.mkdirSync(t,{recursive:!0});for(let o of Wt.readdirSync(e,{withFileTypes:!0})){let n=ct.join(e,o.name),r=ct.join(t,o.name);o.isDirectory()?Bo(n,r):Wt.copyFileSync(n,r)}}async function Ko(e,t,o){if(t!=="drizzle")return{applied:!1};if(o!=="postgresql")return{applied:!1,reason:`Drizzle template currently targets Postgres only; --db=${o} keeps Prisma as sole ORM`};let n=na();if(!n)return{applied:!1,reason:"Drizzle template directory not found in package \u2014 bundling error"};let r=ct.join(e,"packages","platform","db-drizzle");return Bo(n,r),{applied:!0}}import pe from"fs";import It from"path";var oa=["stripe","lemonsqueezy","chinapay","polar"];function $o(e){pe.existsSync(e)&&pe.rmSync(e,{recursive:!0,force:!0})}function ra(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function sa(e,t){let o=It.join(e,".env.example");pe.existsSync(o)?pe.appendFileSync(o,`
1879
- `+t):pe.writeFileSync(o,t)}function ia(e){switch(e){case"stripe":return`# Stripe
1739
+ `}async function Ho(e,t,n="global"){let o=Go(t);if(!o||o.id==="none")return;let r=D.join(e,"apps","web");if(!de.existsSync(r))return;let s=o.id;try{switch(s){case"sentry":la(r),un(r,dn.sentry),dt(e,da());return;case"datadog":ua(r),un(r,dn.datadog),dt(e,ma());return;case"bugsnag":ga(r),un(r,dn.bugsnag),dt(e,fa());return;case"aliyun-arms":ya(r),dt(e,Sa());return;case"tingyun":ha(r),dt(e,Ea());return;default:return}}catch(i){throw console.error(`Failed to apply monitoring selection "${t}":`,i),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Ct=[{id:"novu",name:"Novu",region:"both",envVars:["NOVU_API_KEY","NOVU_APPLICATION_IDENTIFIER"],docs:"https://docs.novu.co",description:"Multi-channel notification infrastructure"},{id:"knock",name:"Knock",region:"global",envVars:["KNOCK_API_KEY","KNOCK_SIGNING_KEY","KNOCK_PUBLIC_API_KEY"],docs:"https://docs.knock.app",description:"Product notifications platform"},{id:"custom",name:"Custom (direct dispatchers)",region:"both",envVars:[],docs:"",description:"Use email + sms + push directly"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Wo(e){return Ct.find(t=>t.id===e)}var yd=Ct.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Xo(e,t,n="global"){let o=Wo(t);if(!o)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Ct.map(r=>r.id).join(", ")}`);if(o.id==="none"){z(e,"notifications");return}o.envVars.length>0&&oe(e,{category:"Notifications",name:o.name,envVars:o.envVars,docs:o.docs}),re(e,"NOTIFICATIONS_PROVIDER",o.id)}import mn from"fs";import va from"path";async function zo(e,t){let n=va.join(e,"package.json");if(mn.existsSync(n)){let o=mn.readFileSync(n,"utf8"),r=JSON.parse(o);r.name=t,r.version="0.1.0",mn.writeFileSync(n,JSON.stringify(r,null,2)+`
1740
+ `)}}import xt from"fs";import Qe from"path";import{fileURLToPath as ba}from"url";var _a=ba(import.meta.url),Jo=Qe.dirname(_a);function Pa(){let e=[Qe.join(Jo,"..","templates","orm","drizzle"),Qe.join(Jo,"..","..","templates","orm","drizzle")];for(let t of e)if(xt.existsSync(t))return t;return null}function Qo(e,t){xt.mkdirSync(t,{recursive:!0});for(let n of xt.readdirSync(e,{withFileTypes:!0})){let o=Qe.join(e,n.name),r=Qe.join(t,n.name);n.isDirectory()?Qo(o,r):xt.copyFileSync(o,r)}}async function Zo(e,t,n){if(t!=="drizzle")return{applied:!1};if(n!=="postgresql")return{applied:!1,reason:`Drizzle template currently targets Postgres only; --db=${n} keeps Prisma as sole ORM`};let o=Pa();if(!o)return{applied:!1,reason:"Drizzle template directory not found in package \u2014 bundling error"};let r=Qe.join(e,"packages","platform","db-drizzle");return Qo(o,r),{applied:!0}}import ue from"fs";import ut from"path";var wa=["stripe","lemonsqueezy","chinapay","polar"];function er(e){ue.existsSync(e)&&ue.rmSync(e,{recursive:!0,force:!0})}function Aa(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Ia(e,t){let n=ut.join(e,".env.example");ue.existsSync(n)?ue.appendFileSync(n,`
1741
+ `+t):ue.writeFileSync(n,t)}function Ca(e){switch(e){case"stripe":return`# Stripe
1880
1742
  STRIPE_SECRET_KEY=
1881
1743
  STRIPE_WEBHOOK_SECRET=
1882
1744
  `;case"lemon":return`# Lemon Squeezy
@@ -1891,14 +1753,14 @@ CHINAPAY_WECHAT_ENABLED=true
1891
1753
  CHINAPAY_APP_ID=
1892
1754
  CHINAPAY_APP_SECRET=
1893
1755
  CHINAPAY_ALIPAY_ENABLED=true
1894
- `}}async function Yo(e,t){let o=It.join(e,"packages","commerce","billing");if(!pe.existsSync(o))return;if(t==="none"){$o(o);return}let n=It.join(o,"src"),r=new Set(ra(t));for(let i of oa)r.has(i)||$o(It.join(n,i));let s=It.join(n,"checkout","types.ts");if(pe.existsSync(s)){let i=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",c=pe.readFileSync(s,"utf8"),a=c.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${i}";`);a!==c&&pe.writeFileSync(s,a)}sa(e,ia(t))}import ye from"fs";import pt from"path";var Ho=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),mn=/@sailor:([^\s*]+)/;function aa(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=>Ho.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 qo(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function Go(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function Wo(e,t){let o=e.split(`
1895
- `),n=[],r=e.includes("#"),s=0;for(;s<o.length;){let i=o[s],c=i.match(mn);if(!c){n.push(i),s++;continue}let{marker:a,keep:l}=aa(c[1],t);if(a==="registry-entries"){n.push(r?Go(i):qo(i)),s++;continue}if(l){let u=r?Go(i):qo(i);u.trim().length>0&&n.push(u);let S=s+1;for(;S<o.length&&o[S].trim()!==""&&!mn.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()!==""&&!mn.test(o[u]);)u++;u<o.length&&o[u].trim()===""&&u++,s=u}}return ca(n.join(`
1896
- `),t)}function ca(e,t){let{providerIds:o,customEndpoint:n}=t,r=new Set;for(let l of o)["openai","anthropic","google","mistral","xai"].includes(l)&&r.add(l),r.add(l.replace(/-/g,"_")),r.add(l);n&&r.add("custom");let s=/createProviderRegistry\(\{([\s\S]*?)\}\)/,i=e.match(s);if(!i)return e;let a=i[1].split(`
1897
- `).filter(l=>{let u=l.trim();if(u===""||u.startsWith("//"))return!0;let S=u.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return S?r.has(S[1]):!0}).join(`
1898
- `);return e.replace(s,`createProviderRegistry({${a}})`)}function pa(e,t){let o=pt.join(t,"registry.ts.template"),n=ye.readFileSync(o,"utf-8");return Wo(n,e)}function la(e,t){let o=pt.join(t,".env.example.template"),n=ye.readFileSync(o,"utf-8");return Wo(n,e)}async function Xo(e,t,o){let n=pa(t,o),r=la(t,o),s=pt.join(e,"packages/ai/agents/src");await ye.promises.mkdir(s,{recursive:!0}),await ye.promises.writeFile(pt.join(s,"registry.ts"),n),await ye.promises.appendFile(pt.join(e,".env.example"),`
1899
- `+r);let i={ai:"latest"},{providerIds:c,customEndpoint:a}=t;(c.includes("openai")||a||c.some(u=>Ho.has(u)))&&(i["@ai-sdk/openai"]="latest",i["@ai-sdk/openai-compatible"]="latest"),c.includes("anthropic")&&(i["@ai-sdk/anthropic"]="latest"),c.includes("google")&&(i["@ai-sdk/google"]="latest"),c.includes("mistral")&&(i["@ai-sdk/mistral"]="latest"),c.includes("xai")&&(i["@ai-sdk/openai"]="latest");let l=pt.join(e,"package.json");if(ye.existsSync(l)){let u=JSON.parse(await ye.promises.readFile(l,"utf-8"));u.dependencies||(u.dependencies={});for(let[S,I]of Object.entries(i))u.dependencies[S]=I;await ye.promises.writeFile(l,JSON.stringify(u,null,2)+`
1900
- `)}}import y from"fs";import d from"path";function zo(e,t){if(!y.existsSync(e))return;let o=y.readdirSync(e);for(let n of o){let r=d.join(e,n);y.statSync(r).isDirectory()?zo(r,t):t(r)}}async function Jo(e,t){let o=d.join(e,"package.json");if(!y.existsSync(o))return;let n=JSON.parse(y.readFileSync(o,"utf8"));if(t.orm!=="prisma"){let r=d.join(e,"packages","db");if(y.existsSync(r)){let s=d.join(r,"prisma");y.existsSync(s)&&y.rmSync(s,{recursive:!0,force:!0});let i=d.join(r,"package.json");if(y.existsSync(i)){let a=JSON.parse(y.readFileSync(i,"utf8"));a.dependencies&&delete a.dependencies["@prisma/client"],a.devDependencies&&delete a.devDependencies.prisma,y.writeFileSync(i,JSON.stringify(a,null,2)+`
1901
- `)}let c=d.join(r,"src","index.ts");y.existsSync(c)&&y.writeFileSync(c,`
1756
+ `}}async function tr(e,t){let n=ut.join(e,"packages","commerce","billing");if(!ue.existsSync(n))return;if(t==="none"){er(n);return}let o=ut.join(n,"src"),r=new Set(Aa(t));for(let i of wa)r.has(i)||er(ut.join(o,i));let s=ut.join(o,"checkout","types.ts");if(ue.existsSync(s)){let i=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",a=ue.readFileSync(s,"utf8"),c=a.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${i}";`);c!==a&&ue.writeFileSync(s,c)}Ia(e,Ca(t))}import _e from"fs";import Ze from"path";var rr=new Set(["siliconflow","volcengine-ark","bailian","moonshot"]),gn=/@sailor:([^\s*]+)/;function xa(e,t){let{providerIds:n,customEndpoint:o}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:n.includes(r)}}if(e==="cn-compatible"){let r=n.some(s=>rr.has(s));return{marker:e,keep:r||!!o}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:n.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!o}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function nr(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function or(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function sr(e,t){let n=e.split(`
1757
+ `),o=[],r=e.includes("#"),s=0;for(;s<n.length;){let i=n[s],a=i.match(gn);if(!a){o.push(i),s++;continue}let{marker:c,keep:p}=xa(a[1],t);if(c==="registry-entries"){o.push(r?or(i):nr(i)),s++;continue}if(p){let u=r?or(i):nr(i);u.trim().length>0&&o.push(u);let d=s+1;for(;d<n.length&&n[d].trim()!==""&&!gn.test(n[d]);)o.push(n[d]),d++;d<n.length&&n[d].trim()===""&&(o.push(n[d]),d++),s=d}else{let u=s+1;for(;u<n.length&&n[u].trim()!==""&&!gn.test(n[u]);)u++;u<n.length&&n[u].trim()===""&&u++,s=u}}return Ra(o.join(`
1758
+ `),t)}function Ra(e,t){let{providerIds:n,customEndpoint:o}=t,r=new Set;for(let p of n)["openai","anthropic","google","mistral","xai"].includes(p)&&r.add(p),r.add(p.replace(/-/g,"_")),r.add(p);o&&r.add("custom");let s=/createProviderRegistry\(\{([\s\S]*?)\}\)/,i=e.match(s);if(!i)return e;let c=i[1].split(`
1759
+ `).filter(p=>{let u=p.trim();if(u===""||u.startsWith("//"))return!0;let d=u.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return d?r.has(d[1]):!0}).join(`
1760
+ `);return e.replace(s,`createProviderRegistry({${c}})`)}function ka(e,t){let n=Ze.join(t,"registry.ts.template"),o=_e.readFileSync(n,"utf-8");return sr(o,e)}function Ta(e,t){let n=Ze.join(t,".env.example.template"),o=_e.readFileSync(n,"utf-8");return sr(o,e)}async function ir(e,t,n){let o=ka(t,n),r=Ta(t,n),s=Ze.join(e,"packages/ai/agents/src");await _e.promises.mkdir(s,{recursive:!0}),await _e.promises.writeFile(Ze.join(s,"registry.ts"),o),await _e.promises.appendFile(Ze.join(e,".env.example"),`
1761
+ `+r);let i={ai:"latest"},{providerIds:a,customEndpoint:c}=t;(a.includes("openai")||c||a.some(u=>rr.has(u)))&&(i["@ai-sdk/openai"]="latest",i["@ai-sdk/openai-compatible"]="latest"),a.includes("anthropic")&&(i["@ai-sdk/anthropic"]="latest"),a.includes("google")&&(i["@ai-sdk/google"]="latest"),a.includes("mistral")&&(i["@ai-sdk/mistral"]="latest"),a.includes("xai")&&(i["@ai-sdk/openai"]="latest");let p=Ze.join(e,"package.json");if(_e.existsSync(p)){let u=JSON.parse(await _e.promises.readFile(p,"utf-8"));u.dependencies||(u.dependencies={});for(let[d,_]of Object.entries(i))u.dependencies[d]=_;await _e.promises.writeFile(p,JSON.stringify(u,null,2)+`
1762
+ `)}}import y from"fs";import g from"path";function ar(e,t){if(!y.existsSync(e))return;let n=y.readdirSync(e);for(let o of n){let r=g.join(e,o);y.statSync(r).isDirectory()?ar(r,t):t(r)}}async function cr(e,t){let n=g.join(e,"package.json");if(!y.existsSync(n))return;let o=JSON.parse(y.readFileSync(n,"utf8"));if(t.orm!=="prisma"){let r=g.join(e,"packages","db");if(y.existsSync(r)){let s=g.join(r,"prisma");y.existsSync(s)&&y.rmSync(s,{recursive:!0,force:!0});let i=g.join(r,"package.json");if(y.existsSync(i)){let c=JSON.parse(y.readFileSync(i,"utf8"));c.dependencies&&delete c.dependencies["@prisma/client"],c.devDependencies&&delete c.devDependencies.prisma,y.writeFileSync(i,JSON.stringify(c,null,2)+`
1763
+ `)}let a=g.join(r,"src","index.ts");y.existsSync(a)&&y.writeFileSync(a,`
1902
1764
  export const prisma = {} as any;
1903
1765
  export const db = {} as any;
1904
1766
  export type PrismaClient = any;
@@ -1944,7 +1806,7 @@ export type UsageAggregate = any;
1944
1806
  export type UsageLedgerEntry = any;
1945
1807
  export type UsageType = any;
1946
1808
  export type UsageLedgerSource = any;
1947
- `)}n.scripts?.postinstall&&(n.scripts.postinstall=n.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=d.join(e,"apps");if(y.existsSync(r)){let s=y.readdirSync(r);for(let i of s){let c=d.join(r,i);if(!y.statSync(c).isDirectory())continue;let a=d.join(c,"src","app");if(!y.existsSync(a))continue;["[lang]","[locale]"].forEach(b=>{let m=d.join(a,b);if(y.existsSync(m)){let M=y.readdirSync(m);for(let xt of M)y.renameSync(d.join(m,xt),d.join(a,xt));y.rmdirSync(m)}}),["src/middleware.ts","middleware.ts"].forEach(b=>{let m=d.join(c,b);y.existsSync(m)&&y.rmSync(m)});let l=d.join(c,"src","lib");y.existsSync(l)||y.mkdirSync(l,{recursive:!0});let u=d.join(l,"mock-i18n.ts");y.writeFileSync(u,`
1809
+ `)}o.scripts?.postinstall&&(o.scripts.postinstall=o.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=g.join(e,"apps");if(y.existsSync(r)){let s=y.readdirSync(r);for(let i of s){let a=g.join(r,i);if(!y.statSync(a).isDirectory())continue;let c=g.join(a,"src","app");if(!y.existsSync(c))continue;["[lang]","[locale]"].forEach(S=>{let m=g.join(c,S);if(y.existsSync(m)){let P=y.readdirSync(m);for(let G of P)y.renameSync(g.join(m,G),g.join(c,G));y.rmdirSync(m)}}),["src/middleware.ts","middleware.ts"].forEach(S=>{let m=g.join(a,S);y.existsSync(m)&&y.rmSync(m)});let p=g.join(a,"src","lib");y.existsSync(p)||y.mkdirSync(p,{recursive:!0});let u=g.join(p,"mock-i18n.ts");y.writeFileSync(u,`
1948
1810
  import React from 'react';
1949
1811
  export function useTranslations(namespace?: string): any { return (key: string) => key; }
1950
1812
  export function useLocale() { return 'en'; }
@@ -1962,7 +1824,7 @@ export const useRouter = () => ({ push: (...args: any[]) => {}, replace: (...arg
1962
1824
  export default function createMiddleware(...args: any[]) { return (req: any) => req; }
1963
1825
  export function createNavigation(...args: any[]) { return { Link, redirect, usePathname, useRouter, getPathname: () => '/' }; }
1964
1826
  export function defineRouting<T>(config: T): T { return config; }
1965
- `);let I=d.join(l,"mock-i18n.d.ts");y.writeFileSync(I,`declare module '@/lib/mock-i18n' {
1827
+ `);let _=g.join(p,"mock-i18n.d.ts");y.writeFileSync(_,`declare module '@/lib/mock-i18n' {
1966
1828
  export function useTranslations(namespace?: string): any;
1967
1829
  export function useLocale(): string;
1968
1830
  export const NextIntlClientProvider: React.FC<any>;
@@ -1980,19 +1842,19 @@ export function defineRouting<T>(config: T): T { return config; }
1980
1842
  export function createNavigation(...args: any[]): any;
1981
1843
  export function defineRouting<T>(config: T): T;
1982
1844
  }
1983
- `),y.writeFileSync(d.join(l,"mock-i18n-index.ts"),`
1845
+ `),y.writeFileSync(g.join(p,"mock-i18n-index.ts"),`
1984
1846
  export * from './mock-i18n';
1985
1847
  export { default } from './mock-i18n';
1986
- `);let C=d.join(c,"tsconfig.json");if(y.existsSync(C))try{let b=y.readFileSync(C,"utf8");if(b.includes('"paths": {')){let m=b.replace(/"paths":\s*\{/,`"paths": {
1848
+ `);let h=g.join(a,"tsconfig.json");if(y.existsSync(h))try{let S=y.readFileSync(h,"utf8");if(S.includes('"paths": {')){let m=S.replace(/"paths":\s*\{/,`"paths": {
1987
1849
  "next-intl": ["./src/lib/mock-i18n"],
1988
- "next-intl/*": ["./src/lib/mock-i18n"],`);y.writeFileSync(C,m)}}catch{}let U=d.join(c,"src");y.existsSync(U)&&zo(U,b=>{if(!b.endsWith(".ts")&&!b.endsWith(".tsx"))return;let m=y.readFileSync(b,"utf8"),M=!1;b.endsWith("src/app/layout.tsx")&&m.includes("../providers")&&(m=m.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),M=!0),m=m.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),m=m.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),m.match(/locale\s*:\s*any/)&&(m=m.replace(/locale\s*:\s*any/g,"locale: string"),M=!0),m.match(/lang\s*:\s*any/)&&(m=m.replace(/lang\s*:\s*any/g,"lang: string"),M=!0),m.match(/requestLocale\s*:\s*any/)&&(m=m.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),M=!0),m.match(/\(locale\s*=\s*(.*)\)/)&&(m=m.replace(/\(locale\s*=\s*(.*)\)/g,"() "),M=!0),m.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(m=m.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),M=!0),(b.endsWith("src/app/layout.tsx")||b.endsWith("src/app/sitemap.ts")||b.endsWith("src/app/robots.ts")||b.endsWith("src/components/ui/locale-switcher.tsx")||b.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(m=m.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),m=m.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),m=m.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),m=m.replace(/\(l\)\s*=>/g,"(l: any) =>"),M=!0),b.endsWith("src/i18n/request.ts")&&(m=m.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),M=!0),(m.match(/locale\s*:/)||m.match(/lang\s*:/))&&(M=!0),M&&y.writeFileSync(b,m)});let ue=d.join(c,"package.json");if(y.existsSync(ue)){let b=JSON.parse(y.readFileSync(ue,"utf8"));b.dependencies&&delete b.dependencies["next-intl"],y.writeFileSync(ue,JSON.stringify(b,null,2)+`
1989
- `)}}}}y.writeFileSync(o,JSON.stringify(n,null,2)+`
1990
- `)}function v(e){try{y.rmSync(e,{recursive:!0,force:!0})}catch{}}function da(e,t){if(!y.existsSync(e))return;let o;try{o=JSON.parse(y.readFileSync(e,"utf8"))}catch{return}let n=!1;if(o.dependencies&&t in o.dependencies){let{[t]:r,...s}=o.dependencies;o={...o,dependencies:s},n=!0}if(o.devDependencies&&t in o.devDependencies){let{[t]:r,...s}=o.devDependencies;o={...o,devDependencies:s},n=!0}n&&y.writeFileSync(e,JSON.stringify(o,null,2)+`
1991
- `)}function Qo(e,t){t.cronJobs||(v(d.join(e,"apps/web/src/app/api/cron")),v(d.join(e,"packages/integrations/queue/src/scheduled"))),t.auditLog||(v(d.join(e,"apps/web/src/app/[locale]/(app)/settings/audit-log")),v(d.join(e,"apps/web/src/app/api/audit-logs")),v(d.join(e,"apps/web/src/components/audit"))),t.apiKeys||(v(d.join(e,"apps/web/src/app/[locale]/(app)/settings/api-keys")),v(d.join(e,"apps/web/src/app/api/api-keys")),v(d.join(e,"apps/web/src/components/api-keys"))),t.webhooks||(v(d.join(e,"apps/web/src/app/[locale]/(app)/settings/webhooks")),v(d.join(e,"apps/web/src/app/api/webhooks")),v(d.join(e,"apps/web/src/components/webhooks")),v(d.join(e,"packages/integrations/webhooks"))),t.commandPalette||(v(d.join(e,"apps/web/src/components/command-palette")),v(d.join(e,"apps/web/src/app/[locale]/providers/command-palette-mount.tsx"))),t.cookieConsent||(v(d.join(e,"apps/landing-page/src/components/cookie-consent-banner.tsx")),v(d.join(e,"apps/landing-page/src/components/__tests__/cookie-consent-banner.test.tsx")),v(d.join(e,"apps/landing-page/src/lib/cookie-consent.ts")),v(d.join(e,"apps/landing-page/src/lib/__tests__/cookie-consent.test.ts")),v(d.join(e,"apps/web/src/app/api/cookie-consent"))),t.legalPages||(v(d.join(e,"apps/landing-page/src/app/[lang]/(legal)/legal")),v(d.join(e,"apps/landing-page/src/lib/legal-documents.ts")),v(d.join(e,"apps/landing-page/src/lib/__tests__/legal-documents.test.ts"))),t.chinaCompliance||(v(d.join(e,"packages/ops/china-compliance")),v(d.join(e,"apps/landing-page/src/components/icp-footer.tsx")),v(d.join(e,"apps/landing-page/src/components/__tests__/icp-footer.test.tsx")),v(d.join(e,"apps/web/src/components/auth/wechat-login-button.tsx")),v(d.join(e,"apps/web/src/components/auth/__tests__/wechat-login-button.test.tsx")),da(d.join(e,"apps/web/package.json"),"@nebutra/china-compliance"))}import lt from"fs";import Zo from"path";var er=/^--\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/m;function ua(e){let t=er.exec(e);if(!t)return null;let[,o,n]=t,r=n.split("|").map(s=>s.trim()).filter(Boolean);return{flag:o,values:r}}function ma(e){return e.replace(er,"").replace(/^\n/,"")}function gn(e,t){let o={kept:[],removed:[],skipped:[]};if(!lt.existsSync(e))return o;let n=lt.readdirSync(e,{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,s)=>r.name.localeCompare(s.name));for(let r of n){let s=Zo.join(e,r.name),i=Zo.join(s,"migration.sql");if(!lt.existsSync(i)){o.skipped.push(r.name);continue}let c=lt.readFileSync(i,"utf8"),a=ua(c);if(!a){o.skipped.push(r.name);continue}let l=t[a.flag];if(l!==void 0&&a.values.includes(l)){lt.writeFileSync(i,ma(c)),o.kept.push(r.name);continue}lt.rmSync(s,{recursive:!0,force:!0}),o.removed.push(r.name)}return o}import{getSchema as ga,printSchema as fa}from"@mrleebo/prisma-ast";var ya=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function Sa(e){return e.type==="comment"&&e.text.trim().startsWith("//")}function ha(e){let t=ya.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 Ea(e,t){for(let o=t-1;o>=0;o--){let n=e[o];if(n.type==="comment"){let r=ha(n.text);if(r)return{annIndex:o,parsed:r};continue}break}return null}function va(e){return e.type==="model"||e.type==="enum"}function fn(e,t){let o=ga(e),n=new Set;for(let c=0;c<o.list.length;c++){let a=o.list[c];if(!va(a))continue;let l=Ea(o.list,c);if(!l)continue;let u=t[l.parsed.flag];if(u!==void 0&&l.parsed.values.includes(u))n.add(l.annIndex);else{n.add(c);for(let C=c-1;C>=0;C--){let U=o.list[C];if(Sa(U)){n.add(C);continue}break}let I=o.list[c+1];I&&I.type==="break"&&n.add(c+1)}}let r=o.list.filter((c,a)=>!n.has(a)),s=[];for(let c of r){let a=s[s.length-1];c.type==="break"&&a&&a.type==="break"||s.push(c)}return fa({type:"schema",list:s})}import dt from"fs";import nr from"path";var Xt=[{id:"qstash",name:"Upstash QStash",region:"both",envVars:["QSTASH_TOKEN","QSTASH_CURRENT_SIGNING_KEY","QSTASH_NEXT_SIGNING_KEY"],docs:"https://upstash.com/docs/qstash",description:"Serverless HTTP-based queue"},{id:"bullmq",name:"BullMQ",region:"both",envVars:["REDIS_URL"],docs:"https://docs.bullmq.io",description:"Redis-backed job queue"},{id:"sqs",name:"AWS SQS",region:"global",envVars:["AWS_SQS_QUEUE_URL","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"],docs:"https://docs.aws.amazon.com/AWSSimpleQueueService/",description:"AWS managed queue"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip queue package"}];function tr(e){return Xt.find(t=>t.id===e)}var nd=Xt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function or(e){return dt.existsSync(e)?dt.readFileSync(e,"utf-8"):null}function _a(e,t){let o=nr.join(e,".env.example"),n=or(o);if(n===null)return;let r=`# Queue: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1992
- `);dt.appendFileSync(o,s)}function ba(e,t,o){let n=nr.join(e,".env.example"),r=or(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?dt.writeFileSync(n,r.replace(s,`${t}="${o}"`)):dt.appendFileSync(n,`${t}="${o}"
1993
- `)}async function rr(e,t,o){let n=Re(e,"queue");if(t==="none"){n&&dt.rmSync(n,{recursive:!0,force:!0});return}let r=tr(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${Xt.map(s=>s.id).join(", ")}`);n&&(_a(e,r),ba(e,"QUEUE_PROVIDER",t))}import le from"fs";import Se from"path";import{fileURLToPath as Pa}from"url";var Aa=Pa(import.meta.url),sr=Se.dirname(Aa),Ca=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|toml|py)$/,Ia=["backends/gateway","infra","e2e","tests"];function wa(){let e=[Se.join(sr,"..","templates"),Se.join(sr,"..","..","templates")];for(let t of e)if(le.existsSync(t))return t;return e[0]}async function ir(e,t){let o=wa(),n=[],r=[],s=[...Ia,...t.withWorkflows?["workflows"]:[],...t.withPythonBackend?["backends/python"]:[]];for(let i of s){let c=Se.join(o,i);if(!le.existsSync(c)){r.push(i);continue}let a=Se.join(e,i);ar(c,a),cr(a,{"{PRODUCT_NAME}":t.projectName}),n.push(i)}return{applied:n,skipped:r}}function ar(e,t){le.mkdirSync(t,{recursive:!0});for(let o of le.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name),r=Se.join(t,o.name);o.isDirectory()?ar(n,r):le.existsSync(r)||le.copyFileSync(n,r)}}function cr(e,t){for(let o of le.readdirSync(e,{withFileTypes:!0})){let n=Se.join(e,o.name);if(o.isDirectory()){cr(n,t);continue}if(!Ca.test(o.name))continue;let r=le.readFileSync(n,"utf-8"),s=!1;for(let[i,c]of Object.entries(t))r.includes(i)&&(r=r.split(i).join(c),s=!0);s&&le.writeFileSync(n,r)}}import ut from"fs";import lr from"path";var zt=[{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 pr(e){return zt.find(t=>t.id===e)}var md=zt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function dr(e){return ut.existsSync(e)?ut.readFileSync(e,"utf-8"):null}function Ra(e,t){let o=lr.join(e,".env.example"),n=dr(o);if(n===null)return;let r=`# Search: ${t.name}`;if(n.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1994
- `);ut.appendFileSync(o,s)}function ka(e,t,o){let n=lr.join(e,".env.example"),r=dr(n);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?ut.writeFileSync(n,r.replace(s,`${t}="${o}"`)):ut.appendFileSync(n,`${t}="${o}"
1995
- `)}async function ur(e,t,o){let n=Re(e,"search");if(t==="none"){n&&ut.rmSync(n,{recursive:!0,force:!0});return}let r=pr(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${zt.map(s=>s.id).join(", ")}`);n&&(Ra(e,r),ka(e,"SEARCH_PROVIDER",t))}import he from"fs";import Me from"path";function xa(e){let t=[Me.join(e,"packages","db"),Me.join(e,"apps","web")];for(let o of t){let n=Me.join(o,"prisma","schema.prisma");if(he.existsSync(n))return{packageDir:o,seedPath:Me.join(o,"prisma","seed.ts"),packageJsonPath:Me.join(o,"package.json")}}return null}function Na(e){try{let t=he.readFileSync(e,"utf8"),o=new Set,n=/^\s*model\s+(\w+)\s*\{/gm,r=n.exec(t);for(;r;)o.add(r[1]),r=n.exec(t);return o}catch{return new Set}}function Ta(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1850
+ "next-intl/*": ["./src/lib/mock-i18n"],`);y.writeFileSync(h,m)}}catch{}let f=g.join(a,"src");y.existsSync(f)&&ar(f,S=>{if(!S.endsWith(".ts")&&!S.endsWith(".tsx"))return;let m=y.readFileSync(S,"utf8"),P=!1;S.endsWith("src/app/layout.tsx")&&m.includes("../providers")&&(m=m.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),P=!0),m=m.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),m=m.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),m.match(/locale\s*:\s*any/)&&(m=m.replace(/locale\s*:\s*any/g,"locale: string"),P=!0),m.match(/lang\s*:\s*any/)&&(m=m.replace(/lang\s*:\s*any/g,"lang: string"),P=!0),m.match(/requestLocale\s*:\s*any/)&&(m=m.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),P=!0),m.match(/\(locale\s*=\s*(.*)\)/)&&(m=m.replace(/\(locale\s*=\s*(.*)\)/g,"() "),P=!0),m.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(m=m.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),P=!0),(S.endsWith("src/app/layout.tsx")||S.endsWith("src/app/sitemap.ts")||S.endsWith("src/app/robots.ts")||S.endsWith("src/components/ui/locale-switcher.tsx")||S.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(m=m.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),m=m.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),m=m.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),m=m.replace(/\(l\)\s*=>/g,"(l: any) =>"),P=!0),S.endsWith("src/i18n/request.ts")&&(m=m.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),P=!0),(m.match(/locale\s*:/)||m.match(/lang\s*:/))&&(P=!0),P&&y.writeFileSync(S,m)});let E=g.join(a,"package.json");if(y.existsSync(E)){let S=JSON.parse(y.readFileSync(E,"utf8"));S.dependencies&&delete S.dependencies["next-intl"],y.writeFileSync(E,JSON.stringify(S,null,2)+`
1851
+ `)}}}}y.writeFileSync(n,JSON.stringify(o,null,2)+`
1852
+ `)}function b(e){try{y.rmSync(e,{recursive:!0,force:!0})}catch{}}function Na(e,t){if(!y.existsSync(e))return;let n;try{n=JSON.parse(y.readFileSync(e,"utf8"))}catch{return}let o=!1;if(n.dependencies&&t in n.dependencies){let{[t]:r,...s}=n.dependencies;n={...n,dependencies:s},o=!0}if(n.devDependencies&&t in n.devDependencies){let{[t]:r,...s}=n.devDependencies;n={...n,devDependencies:s},o=!0}o&&y.writeFileSync(e,JSON.stringify(n,null,2)+`
1853
+ `)}function pr(e,t){t.cronJobs||(b(g.join(e,"apps/web/src/app/api/cron")),b(g.join(e,"packages/integrations/queue/src/scheduled"))),t.auditLog||(b(g.join(e,"apps/web/src/app/[locale]/(app)/settings/audit-log")),b(g.join(e,"apps/web/src/app/api/audit-logs")),b(g.join(e,"apps/web/src/components/audit"))),t.apiKeys||(b(g.join(e,"apps/web/src/app/[locale]/(app)/settings/api-keys")),b(g.join(e,"apps/web/src/app/api/api-keys")),b(g.join(e,"apps/web/src/components/api-keys"))),t.webhooks||(b(g.join(e,"apps/web/src/app/[locale]/(app)/settings/webhooks")),b(g.join(e,"apps/web/src/app/api/webhooks")),b(g.join(e,"apps/web/src/components/webhooks")),b(g.join(e,"packages/integrations/webhooks"))),t.commandPalette||(b(g.join(e,"apps/web/src/components/command-palette")),b(g.join(e,"apps/web/src/app/[locale]/providers/command-palette-mount.tsx"))),t.cookieConsent||(b(g.join(e,"apps/landing-page/src/components/cookie-consent-banner.tsx")),b(g.join(e,"apps/landing-page/src/components/__tests__/cookie-consent-banner.test.tsx")),b(g.join(e,"apps/landing-page/src/lib/cookie-consent.ts")),b(g.join(e,"apps/landing-page/src/lib/__tests__/cookie-consent.test.ts")),b(g.join(e,"apps/web/src/app/api/cookie-consent"))),t.legalPages||(b(g.join(e,"apps/landing-page/src/app/[lang]/(legal)/legal")),b(g.join(e,"apps/landing-page/src/lib/legal-documents.ts")),b(g.join(e,"apps/landing-page/src/lib/__tests__/legal-documents.test.ts"))),t.chinaCompliance||(b(g.join(e,"packages/ops/china-compliance")),b(g.join(e,"apps/landing-page/src/components/icp-footer.tsx")),b(g.join(e,"apps/landing-page/src/components/__tests__/icp-footer.test.tsx")),b(g.join(e,"apps/web/src/components/auth/wechat-login-button.tsx")),b(g.join(e,"apps/web/src/components/auth/__tests__/wechat-login-button.test.tsx")),Na(g.join(e,"apps/web/package.json"),"@nebutra/china-compliance"))}import et from"fs";import lr from"path";var dr=/^--\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/m;function Oa(e){let t=dr.exec(e);if(!t)return null;let[,n,o]=t,r=o.split("|").map(s=>s.trim()).filter(Boolean);return{flag:n,values:r}}function La(e){return e.replace(dr,"").replace(/^\n/,"")}function fn(e,t){let n={kept:[],removed:[],skipped:[]};if(!et.existsSync(e))return n;let o=et.readdirSync(e,{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,s)=>r.name.localeCompare(s.name));for(let r of o){let s=lr.join(e,r.name),i=lr.join(s,"migration.sql");if(!et.existsSync(i)){n.skipped.push(r.name);continue}let a=et.readFileSync(i,"utf8"),c=Oa(a);if(!c){n.skipped.push(r.name);continue}let p=t[c.flag];if(p!==void 0&&c.values.includes(p)){et.writeFileSync(i,La(a)),n.kept.push(r.name);continue}et.rmSync(s,{recursive:!0,force:!0}),n.removed.push(r.name)}return n}import{getSchema as Ua,printSchema as Ma}from"@mrleebo/prisma-ast";var Da=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function Fa(e){return e.type==="comment"&&e.text.trim().startsWith("//")}function ja(e){let t=Da.exec(e.trim());if(!t)return null;let[,n,o]=t,r=o.split("|").map(s=>s.trim()).filter(s=>s.length>0);return{flag:n,values:r}}function Ba(e,t){for(let n=t-1;n>=0;n--){let o=e[n];if(o.type==="comment"){let r=ja(o.text);if(r)return{annIndex:n,parsed:r};continue}break}return null}function Va(e){return e.type==="model"||e.type==="enum"}function yn(e,t){let n=Ua(e),o=new Set;for(let a=0;a<n.list.length;a++){let c=n.list[a];if(!Va(c))continue;let p=Ba(n.list,a);if(!p)continue;let u=t[p.parsed.flag];if(u!==void 0&&p.parsed.values.includes(u))o.add(p.annIndex);else{o.add(a);for(let h=a-1;h>=0;h--){let f=n.list[h];if(Fa(f)){o.add(h);continue}break}let _=n.list[a+1];_&&_.type==="break"&&o.add(a+1)}}let r=n.list.filter((a,c)=>!o.has(c)),s=[];for(let a of r){let c=s[s.length-1];a.type==="break"&&c&&c.type==="break"||s.push(a)}return Ma({type:"schema",list:s})}import tt from"fs";import mr 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:"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 ur(e){return Rt.find(t=>t.id===e)}var Kd=Rt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function gr(e){return tt.existsSync(e)?tt.readFileSync(e,"utf-8"):null}function Ka(e,t){let n=mr.join(e,".env.example"),o=gr(n);if(o===null)return;let r=`# Queue: ${t.name}`;if(o.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1854
+ `);tt.appendFileSync(n,s)}function $a(e,t,n){let o=mr.join(e,".env.example"),r=gr(o);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?tt.writeFileSync(o,r.replace(s,`${t}="${n}"`)):tt.appendFileSync(o,`${t}="${n}"
1855
+ `)}async function fr(e,t,n){let o=Re(e,"queue");if(t==="none"){o&&tt.rmSync(o,{recursive:!0,force:!0});return}let r=ur(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${Rt.map(s=>s.id).join(", ")}`);o&&(Ka(e,r),$a(e,"QUEUE_PROVIDER",t))}import me from"fs";import Pe from"path";import{fileURLToPath as Ya}from"url";var qa=Ya(import.meta.url),yr=Pe.dirname(qa),Ga=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|toml|py)$/,Ha=["backends/gateway","infra","e2e","tests"];function Wa(){let e=[Pe.join(yr,"..","templates"),Pe.join(yr,"..","..","templates")];for(let t of e)if(me.existsSync(t))return t;return e[0]}async function Sr(e,t){let n=Wa(),o=[],r=[],s=[...Ha,...t.withWorkflows?["workflows"]:[],...t.withPythonBackend?["backends/python"]:[]];for(let i of s){let a=Pe.join(n,i);if(!me.existsSync(a)){r.push(i);continue}let c=Pe.join(e,i);hr(a,c),Er(c,{"{PRODUCT_NAME}":t.projectName}),o.push(i)}return{applied:o,skipped:r}}function hr(e,t){me.mkdirSync(t,{recursive:!0});for(let n of me.readdirSync(e,{withFileTypes:!0})){let o=Pe.join(e,n.name),r=Pe.join(t,n.name);n.isDirectory()?hr(o,r):me.existsSync(r)||me.copyFileSync(o,r)}}function Er(e,t){for(let n of me.readdirSync(e,{withFileTypes:!0})){let o=Pe.join(e,n.name);if(n.isDirectory()){Er(o,t);continue}if(!Ga.test(n.name))continue;let r=me.readFileSync(o,"utf-8"),s=!1;for(let[i,a]of Object.entries(t))r.includes(i)&&(r=r.split(i).join(a),s=!0);s&&me.writeFileSync(o,r)}}import nt from"fs";import br from"path";var kt=[{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 vr(e){return kt.find(t=>t.id===e)}var Zd=kt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function _r(e){return nt.existsSync(e)?nt.readFileSync(e,"utf-8"):null}function Xa(e,t){let n=br.join(e,".env.example"),o=_r(n);if(o===null)return;let r=`# Search: ${t.name}`;if(o.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1856
+ `);nt.appendFileSync(n,s)}function za(e,t,n){let o=br.join(e,".env.example"),r=_r(o);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?nt.writeFileSync(o,r.replace(s,`${t}="${n}"`)):nt.appendFileSync(o,`${t}="${n}"
1857
+ `)}async function Pr(e,t,n){let o=Re(e,"search");if(t==="none"){o&&nt.rmSync(o,{recursive:!0,force:!0});return}let r=vr(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${kt.map(s=>s.id).join(", ")}`);o&&(Xa(e,r),za(e,"SEARCH_PROVIDER",t))}import we from"fs";import De from"path";function Ja(e){let t=[De.join(e,"packages","db"),De.join(e,"apps","web")];for(let n of t){let o=De.join(n,"prisma","schema.prisma");if(we.existsSync(o))return{packageDir:n,seedPath:De.join(n,"prisma","seed.ts"),packageJsonPath:De.join(n,"package.json")}}return null}function Qa(e){try{let t=we.readFileSync(e,"utf8"),n=new Set,o=/^\s*model\s+(\w+)\s*\{/gm,r=o.exec(t);for(;r;)n.add(r[1]),r=o.exec(t);return n}catch{return new Set}}function Za(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1996
1858
  const admin = await prisma.user.create({
1997
1859
  data: {
1998
1860
  clerkId: "user_mock_admin",
@@ -2023,7 +1885,7 @@ export { default } from './mock-i18n';
2023
1885
  console.log("\\u2713 Created admin user:", admin.email);
2024
1886
  } catch (err) {
2025
1887
  console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
2026
- }`}function Oa(e,t){let o=t.has("Tenant"),n=t.has("User"),r=t.has("Project"),s=Ta(e,n),i=o?` let tenants: Array<{ id: string; name: string }> = [];
1888
+ }`}function ec(e,t){let n=t.has("Tenant"),o=t.has("User"),r=t.has("Project"),s=Za(e,o),i=n?` let tenants: Array<{ id: string; name: string }> = [];
2027
1889
  try {
2028
1890
  tenants = await Promise.all([
2029
1891
  prisma.tenant.create({
@@ -2040,7 +1902,7 @@ export { default } from './mock-i18n';
2040
1902
  } catch (err) {
2041
1903
  console.warn("\\u26A0 Tenant creation skipped:", (err as Error).message);
2042
1904
  }`:` const tenants: Array<{ id: string; name: string }> = [];
2043
- console.log("\\u2139 No Tenant model in schema \u2014 skipping tenant seed.");`,c=r&&o?` for (const tenant of tenants) {
1905
+ console.log("\\u2139 No Tenant model in schema \u2014 skipping tenant seed.");`,a=r&&n?` for (const tenant of tenants) {
2044
1906
  try {
2045
1907
  await prisma.project.createMany({
2046
1908
  data: [
@@ -2079,7 +1941,7 @@ ${i}
2079
1941
  ${s}
2080
1942
 
2081
1943
  // --- Sample projects per tenant --------------------------------------
2082
- ${c}
1944
+ ${a}
2083
1945
 
2084
1946
  console.log("\\u2713 Seed complete");
2085
1947
  }
@@ -2092,12 +1954,12 @@ main()
2092
1954
  .finally(async () => {
2093
1955
  await prisma.$disconnect();
2094
1956
  });
2095
- `}function La(e){if(he.existsSync(e))try{let t=he.readFileSync(e,"utf8"),o=JSON.parse(t),n=o.scripts??{},r=!1;n["db:seed"]||(n["db:seed"]="prisma db seed",r=!0);let s=o.prisma??{};if(s.seed||(s.seed="tsx prisma/seed.ts",r=!0),!r)return;let i={...o,scripts:n,prisma:s};he.writeFileSync(e,JSON.stringify(i,null,2)+`
2096
- `)}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 mr(e,t){let o=xa(e);if(o)try{let n=Me.join(o.packageDir,"prisma","schema.prisma"),r=Na(n),s=Oa(t,r),i=Me.dirname(o.seedPath);he.existsSync(i)||he.mkdirSync(i,{recursive:!0}),he.writeFileSync(o.seedPath,s),La(o.packageJsonPath)}catch(n){let r=n instanceof Error?n.message:String(n);throw console.error(`[create-sailor] Failed to generate seed data: ${r}`),new Error(`Unable to write prisma/seed.ts: ${r}`)}}import Ee from"fs";import De from"path";var Jt=[{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:""}],Pd=Jt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function gr(e){return Jt.find(t=>t.id===e)}var Ua="@nebutra/sms",Ma={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 yn(e,t){Ee.mkdirSync(De.dirname(e),{recursive:!0}),Ee.writeFileSync(e,t)}function Da(e,t){let o=De.join(e,".env.example");Ee.existsSync(o)?Ee.appendFileSync(o,`
2097
- `+t):Ee.writeFileSync(o,t)}function Fa(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
1957
+ `}function tc(e){if(we.existsSync(e))try{let t=we.readFileSync(e,"utf8"),n=JSON.parse(t),o=n.scripts??{},r=!1;o["db:seed"]||(o["db:seed"]="prisma db seed",r=!0);let s=n.prisma??{};if(s.seed||(s.seed="tsx prisma/seed.ts",r=!0),!r)return;let i={...n,scripts:o,prisma:s};we.writeFileSync(e,JSON.stringify(i,null,2)+`
1958
+ `)}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(`[create-sailor] Failed to patch seed scripts in ${e}: ${n}`)}}async function wr(e,t){let n=Ja(e);if(n)try{let o=De.join(n.packageDir,"prisma","schema.prisma"),r=Qa(o),s=ec(t,r),i=De.dirname(n.seedPath);we.existsSync(i)||we.mkdirSync(i,{recursive:!0}),we.writeFileSync(n.seedPath,s),tc(n.packageJsonPath)}catch(o){let r=o instanceof Error?o.message:String(o);throw console.error(`[create-sailor] Failed to generate seed data: ${r}`),new Error(`Unable to write prisma/seed.ts: ${r}`)}}import Ae from"fs";import Fe from"path";var Tt=[{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:""}],pu=Tt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Ar(e){return Tt.find(t=>t.id===e)}var nc="@nebutra/sms",oc={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 Sn(e,t){Ae.mkdirSync(Fe.dirname(e),{recursive:!0}),Ae.writeFileSync(e,t)}function rc(e,t){let n=Fe.join(e,".env.example");Ae.existsSync(n)?Ae.appendFileSync(n,`
1959
+ `+t):Ae.writeFileSync(n,t)}function sc(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,n=e.envVars.map(o=>`${o}=`).join(`
2098
1960
  `);return`${t}
2099
- ${o}
2100
- `}var ja=`/**
1961
+ ${n}
1962
+ `}var ic=`/**
2101
1963
  * Inputs for the \`sendSms\` wrapper. Keep this surface portable across
2102
1964
  * providers \u2014 provider-specific options belong in the wrapper itself.
2103
1965
  */
@@ -2117,7 +1979,7 @@ export interface SendSmsResult {
2117
1979
  provider: string;
2118
1980
  raw?: unknown;
2119
1981
  }
2120
- `;function Va(){return`import twilio from "twilio";
1982
+ `;function ac(){return`import twilio from "twilio";
2121
1983
  import type { SendSmsInput, SendSmsResult } from "./types";
2122
1984
 
2123
1985
  let client: ReturnType<typeof twilio> | null = null;
@@ -2152,7 +2014,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2152
2014
  }
2153
2015
 
2154
2016
  export type { SendSmsInput, SendSmsResult } from "./types";
2155
- `}function Ba(){return`import messagebird from "messagebird";
2017
+ `}function cc(){return`import messagebird from "messagebird";
2156
2018
  import type { SendSmsInput, SendSmsResult } from "./types";
2157
2019
 
2158
2020
  let client: ReturnType<typeof messagebird> | null = null;
@@ -2190,7 +2052,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2190
2052
  }
2191
2053
 
2192
2054
  export type { SendSmsInput, SendSmsResult } from "./types";
2193
- `}function Ka(){return`import plivo from "plivo";
2055
+ `}function pc(){return`import plivo from "plivo";
2194
2056
  import type { SendSmsInput, SendSmsResult } from "./types";
2195
2057
 
2196
2058
  let client: InstanceType<typeof plivo.Client> | null = null;
@@ -2229,7 +2091,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2229
2091
  }
2230
2092
 
2231
2093
  export type { SendSmsInput, SendSmsResult } from "./types";
2232
- `}function $a(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
2094
+ `}function lc(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
2233
2095
  import * as $OpenApi from "@alicloud/openapi-client";
2234
2096
  import type { SendSmsInput, SendSmsResult } from "./types";
2235
2097
 
@@ -2278,7 +2140,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2278
2140
  }
2279
2141
 
2280
2142
  export type { SendSmsInput, SendSmsResult } from "./types";
2281
- `}function Ya(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
2143
+ `}function dc(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
2282
2144
  import type { SendSmsInput, SendSmsResult } from "./types";
2283
2145
 
2284
2146
  const SmsClient = tencentcloud.sms.v20210111.Client;
@@ -2343,7 +2205,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2343
2205
  }
2344
2206
 
2345
2207
  export type { SendSmsInput, SendSmsResult } from "./types";
2346
- `}function qa(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
2208
+ `}function uc(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
2347
2209
  import Yunpian from "yunpian-nodejs-sdk";
2348
2210
  import type { SendSmsInput, SendSmsResult } from "./types";
2349
2211
 
@@ -2395,13 +2257,13 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2395
2257
  }
2396
2258
 
2397
2259
  export type { SendSmsInput, SendSmsResult } from "./types";
2398
- `}function Ga(e){switch(e){case"twilio":return Va();case"messagebird":return Ba();case"plivo":return Ka();case"aliyun-sms":return $a();case"tencent-sms":return Ya();case"yunpian":return qa();case"none":return`export {};
2399
- `}}function Ha(e){let t={};for(let n of e.pkgs??[]){let r=Ma[n];r&&(t[n]=r)}let o={name:Ua,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)+`
2400
- `}async function fr(e,t,o="global"){if(t==="none")return;let n=gr(t);if(!n)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${Jt.map(i=>i.id).join(", ")}`);let r=De.join(e,"packages","sms");if(!Ee.existsSync(r))return;let s=De.join(r,"src");Ee.existsSync(s)&&Ee.rmSync(s,{recursive:!0,force:!0});try{yn(De.join(r,"package.json"),Ha(n)),yn(De.join(s,"types.ts"),ja),yn(De.join(s,"index.ts"),Ga(n.id)),Da(e,Fa(n))}catch(i){throw console.error(`Failed to apply SMS selection "${t}":`,i),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import je from"fs";import Fe from"path";var wt=[{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 Sn(e){let t=e==="supabase"?"supabase-storage":e;return wt.some(o=>o.id===t)?t:void 0}function yr(e){let t=Sn(e);return t?wt.find(o=>o.id===t):void 0}var kd=wt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var Ve="@nebutra/storage";function hn(e,t){je.mkdirSync(Fe.dirname(e),{recursive:!0}),je.writeFileSync(e,t)}function Wa(e,t){let o=Fe.join(e,".env.example");je.existsSync(o)?je.appendFileSync(o,`
2401
- `+t):je.writeFileSync(o,t)}function Xa(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,o=e.envVars.map(n=>`${n}=`).join(`
2260
+ `}function mc(e){switch(e){case"twilio":return ac();case"messagebird":return cc();case"plivo":return pc();case"aliyun-sms":return lc();case"tencent-sms":return dc();case"yunpian":return uc();case"none":return`export {};
2261
+ `}}function gc(e){let t={};for(let o of e.pkgs??[]){let r=oc[o];r&&(t[o]=r)}let n={name:nc,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(n,null,2)+`
2262
+ `}async function Ir(e,t,n="global"){if(t==="none")return;let o=Ar(t);if(!o)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${Tt.map(i=>i.id).join(", ")}`);let r=Fe.join(e,"packages","sms");if(!Ae.existsSync(r))return;let s=Fe.join(r,"src");Ae.existsSync(s)&&Ae.rmSync(s,{recursive:!0,force:!0});try{Sn(Fe.join(r,"package.json"),gc(o)),Sn(Fe.join(s,"types.ts"),ic),Sn(Fe.join(s,"index.ts"),mc(o.id)),rc(e,sc(o))}catch(i){throw console.error(`Failed to apply SMS selection "${t}":`,i),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import Be from"fs";import je from"path";var Ve="@nebutra/storage";function hn(e,t){Be.mkdirSync(je.dirname(e),{recursive:!0}),Be.writeFileSync(e,t)}function fc(e,t){let n=je.join(e,".env.example");Be.existsSync(n)?Be.appendFileSync(n,`
2263
+ `+t):Be.writeFileSync(n,t)}function yc(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,n=e.envVars.map(o=>`${o}=`).join(`
2402
2264
  `);return`${t}
2403
- ${o}
2404
- `}var za=`/**
2265
+ ${n}
2266
+ `}var Sc=`/**
2405
2267
  * Inputs for the \`uploadFile\` wrapper. Keep this surface portable across
2406
2268
  * providers \u2014 provider-specific options belong in the wrapper itself.
2407
2269
  */
@@ -2427,7 +2289,7 @@ export interface SignedUrlOptions {
2427
2289
  operation?: "get" | "put";
2428
2290
  contentType?: string;
2429
2291
  }
2430
- `;function Ja(){return`/**
2292
+ `;function hc(){return`/**
2431
2293
  * @${Ve.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
2432
2294
  *
2433
2295
  * Docs: https://developers.cloudflare.com/r2/api/s3/api/
@@ -2491,7 +2353,7 @@ export async function getSignedUrl(
2491
2353
  }
2492
2354
 
2493
2355
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2494
- `}function Qa(){return`/**
2356
+ `}function Ec(){return`/**
2495
2357
  * @${Ve.slice(1)} \u2014 AWS S3 wrapper.
2496
2358
  *
2497
2359
  * Docs: https://docs.aws.amazon.com/s3/
@@ -2556,7 +2418,7 @@ export async function getSignedUrl(
2556
2418
  }
2557
2419
 
2558
2420
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2559
- `}function Za(){return`/**
2421
+ `}function vc(){return`/**
2560
2422
  * @${Ve.slice(1)} \u2014 Supabase Storage wrapper.
2561
2423
  *
2562
2424
  * Docs: https://supabase.com/docs/guides/storage
@@ -2619,7 +2481,7 @@ export async function getSignedUrl(
2619
2481
  }
2620
2482
 
2621
2483
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2622
- `}function ec(){return`/**
2484
+ `}function bc(){return`/**
2623
2485
  * @${Ve.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
2624
2486
  *
2625
2487
  * Docs: https://help.aliyun.com/product/31815.html
@@ -2666,7 +2528,7 @@ export async function getSignedUrl(
2666
2528
  }
2667
2529
 
2668
2530
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2669
- `}function tc(){return`/**
2531
+ `}function _c(){return`/**
2670
2532
  * @${Ve.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
2671
2533
  *
2672
2534
  * Docs: https://cloud.tencent.com/document/product/436
@@ -2721,7 +2583,7 @@ export async function getSignedUrl(
2721
2583
  }
2722
2584
 
2723
2585
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2724
- `}function nc(){return`/**
2586
+ `}function Pc(){return`/**
2725
2587
  * @${Ve.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
2726
2588
  *
2727
2589
  * Docs: https://developer.qiniu.com/kodo
@@ -2789,9 +2651,10 @@ export async function getSignedUrl(
2789
2651
  }
2790
2652
 
2791
2653
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2792
- `}function oc(e){switch(e){case"r2":return Ja();case"s3":return Qa();case"supabase-storage":return Za();case"aliyun-oss":return ec();case"tencent-cos":return tc();case"qiniu":return nc();case"none":return`export {};
2793
- `}}function rc(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),(e.id==="r2"||e.id==="s3")&&(t["@aws-sdk/s3-request-presigner"]="^3.658.0");let o={name:Ve,version:"0.1.0",private:!0,description:`Object storage via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(o,null,2)+`
2794
- `}async function Sr(e,t,o){if(t==="none")return;let n=yr(t);if(!n)throw new Error(`Unknown storage provider "${t}". Valid ids: ${wt.map(i=>i.id).join(", ")}`);let r=Fe.join(e,"packages","storage"),s=Fe.join(r,"src");je.existsSync(s)&&je.rmSync(s,{recursive:!0,force:!0}),hn(Fe.join(r,"package.json"),rc(n)),hn(Fe.join(s,"types.ts"),za),hn(Fe.join(s,"index.ts"),oc(n.id)),Wa(e,Xa(n))}function ve(e,t){if(e===void 0)return t;let o=String(e).trim().toLowerCase();return o==="true"||o==="1"||o==="yes"||o==="on"?!0:o==="false"||o==="0"||o==="no"||o==="off"?!1:t}function hr(e,t){let o=t==="cn";return{cronJobs:ve(e.cronJobs,!0),auditLog:ve(e.auditLog,!1),apiKeys:ve(e.apiKeys,!0),webhooks:ve(e.webhooks,!0),commandPalette:ve(e.commandPalette,!0),cookieConsent:ve(e.cookieConsent,!0),legalPages:ve(e.legalPages,!0),chinaCompliance:ve(e.chinaCompliance,o)}}var Qt=[{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 Er(e){return Qt.find(t=>t.id===e)}var Md=Qt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function vr(e,t,o="global"){let n=Er(t);if(!n)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Qt.map(r=>r.id).join(", ")}`);if(n.id==="none"){X(e,"webhooks");return}n.envVars.length>0&&te(e,{category:"Webhooks",name:n.name,envVars:n.envVars,docs:n.docs}),ne(e,"WEBHOOKS_PROVIDER",n.id)}import Be from"fs";import Rt from"path";function sc(e){return`import Link from "next/link";
2654
+ `}function wc(e){switch(e){case"r2":return hc();case"s3":return Ec();case"supabase-storage":return vc();case"aliyun-oss":return bc();case"tencent-cos":return _c();case"qiniu":return Pc();case"none":return`export {};
2655
+ `}}function Ac(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 n={name:Ve,version:"0.1.0",private:!0,description:`Object storage via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(n,null,2)+`
2656
+ `}async function Cr(e,t,n){if(t==="none")return;let o=Rn(t);if(!o)throw new Error(`Unknown storage provider "${t}". Valid ids: ${it.map(i=>i.id).join(", ")}`);let r=je.join(e,"packages","storage"),s=je.join(r,"src");Be.existsSync(s)&&Be.rmSync(s,{recursive:!0,force:!0}),hn(je.join(r,"package.json"),Ac(o)),hn(je.join(s,"types.ts"),Sc),hn(je.join(s,"index.ts"),wc(o.id)),fc(e,yc(o))}var Nt=[{id:"svix",name:"Svix",region:"global",envVars:["SVIX_API_TOKEN"],docs:"https://docs.svix.com",description:"Managed webhooks platform"},{id:"custom",name:"Custom (self-hosted)",region:"both",envVars:["WEBHOOK_SIGNING_SECRET"],docs:"",description:"Custom implementation with built-in package"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function xr(e){return Nt.find(t=>t.id===e)}var Eu=Nt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Rr(e,t,n="global"){let o=xr(t);if(!o)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Nt.map(r=>r.id).join(", ")}`);if(o.id==="none"){z(e,"webhooks");return}o.envVars.length>0&&oe(e,{category:"Webhooks",name:o.name,envVars:o.envVars,docs:o.docs}),re(e,"WEBHOOKS_PROVIDER",o.id)}import Ke from"fs";import mt from"path";function Ic(e){return`import { brand } from "@nebutra/brand/metadata";
2657
+ import Link from "next/link";
2795
2658
 
2796
2659
  export default function WelcomePage() {
2797
2660
  const projectName = ${JSON.stringify(e)};
@@ -2856,7 +2719,7 @@ export default function WelcomePage() {
2856
2719
  </li>
2857
2720
  <li>
2858
2721
  <a
2859
- href="https://nebutra.com/get-license"
2722
+ href={\`https://\${brand.domains.landing}/get-license\`}
2860
2723
  className="underline"
2861
2724
  >
2862
2725
  Get free license (Individual/OPC)
@@ -2900,21 +2763,21 @@ function Step({
2900
2763
  </li>
2901
2764
  );
2902
2765
  }
2903
- `}function ic(e={}){return`
2766
+ `}function Cc(e={}){return`
2904
2767
  ## What you can do next
2905
2768
 
2906
2769
  ${[e.apiKeys===!1?"- Manage API keys at `/settings/api-keys` (disabled \u2014 re-enable with `--api-keys=true`)":"- Manage API keys at `/settings/api-keys`",e.auditLog===!1?"- View audit log at `/settings/audit-log` (disabled \u2014 re-enable with `--audit-log=true`)":"- View audit log at `/settings/audit-log`","- Configure webhooks at `/settings/webhooks`",e.commandPalette===!1?"- Press \u2318K to open the command palette (disabled \u2014 re-enable with `--command-palette=true`)":"- Press \u2318K to open the command palette","- Edit notification preferences at `/settings/notifications`","- Export your data at `/settings/account/export`","- For China deployments, see `packages/ops/china-compliance/README.md`"].join(`
2907
2770
  `)}
2908
- `}function ac(e=[]){return e.length===0?"":`
2771
+ `}function xc(e=[]){return e.length===0?"":`
2909
2772
  ## Production readiness holds
2910
2773
 
2911
- Do not enable these in production until you replace stubs, add provider credentials, and verify the integration contract:
2774
+ Do not enable these in production until provider credentials, adapter wiring, and the integration contract are verified:
2912
2775
 
2913
- ${e.map(o=>{let n=rt(o.status);return`- ${o.flag}=${o.provider} ${n} \u2014 ${me(o.status)}`}).join(`
2776
+ ${e.map(n=>{let o=Xe(n.status);return`- ${n.flag}=${n.provider} ${o} \u2014 ${he(n.status)}`}).join(`
2914
2777
  `)}
2915
2778
 
2916
2779
  Review the package readiness matrix before handoff: [docs/package-status.md](docs/package-status.md)
2917
- `}function cc(e,t,o=[],n={}){return`# Next steps \u2014 ${e}
2780
+ `}function Rc(e,t,n=[],o={}){return`# Next steps \u2014 ${e}
2918
2781
 
2919
2782
  Region: ${t}
2920
2783
 
@@ -2940,44 +2803,119 @@ Your AI-native SaaS scaffold is ready. Complete these four steps to go from temp
2940
2803
  \`\`\`
2941
2804
 
2942
2805
  After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
2943
- ${ic(n)}${ac(o)}
2806
+ ${Cc(o)}${xc(n)}
2944
2807
 
2945
2808
  ## Resources
2946
2809
 
2947
2810
  - [Documentation](/docs)
2948
2811
  - [GitHub](https://github.com/nebutra/nebutra-sailor)
2949
2812
  - [Get free license (Individual/OPC)](https://nebutra.com/get-license)
2950
- `}async function _r(e,t){let{projectName:o,region:n,previewSelections:r=[],waveFeatures:s={}}=t;try{let i=Rt.join(e,".sailor");Be.existsSync(i)||Be.mkdirSync(i,{recursive:!0}),Be.writeFileSync(Rt.join(i,"next-steps.md"),cc(o,n,r,s))}catch(i){let c=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${c}`)}try{let i=Rt.join(e,"apps","web");if(!Be.existsSync(i))return;let c=Rt.join(i,"src","app","[locale]","welcome");Be.existsSync(c)||Be.mkdirSync(c,{recursive:!0}),Be.writeFileSync(Rt.join(c,"page.tsx"),sc(o))}catch(i){let c=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write welcome page: ${c}`)}}var br="create-sailor";function p(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2951
- `)}function dc(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function Pr(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 Ar(e,t,o){let n=e?.trim().toLowerCase()??Hn(t),r=$t(n);if(!r){let i=an.map(c=>c.id).join(", ");throw new Error(`Unknown --db-host="${n}". Valid: ${i}`)}let s=o;return r.forcedEngine&&s!=="none"&&s!==r.forcedEngine&&(s=r.forcedEngine),{hostId:r.id,engine:s}}function Cr(e){return e==="drizzle"?"drizzle":"prisma"}function Ir(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function wr(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 Rr(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="nextauth"||t==="next-auth"||t==="authjs"||t==="auth.js"?"nextauth":t==="supabase"||t==="supabase-auth"?"supabase":t==="none"?"none":"clerk"}var uc=new Set(["gateway","direct","custom","none"]);function Ur(e){if(!e)return!1;let t=e.trim().toLowerCase();return uc.has(t)}function kr(e){if(!e)return["openai"];if(Ur(e))return[];let t=e.split(",").map(o=>o.trim().toLowerCase());return t.includes("none")?[]:t}function mc(e,t){let o=e??t;return Sn(o)??o}var xr={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function Nr(e,t){if(!e)return"fumadocs";let o=e.toLowerCase();if(o==="fumadocs"||o==="none")return o;if(o in xr){let n=xr[o];return t?p(!0,{event:"notice",kind:"docs-fallback",requested:o,effective:"fumadocs"}):process.stdout.write(A.yellow(`\u26A0 ${n} support is coming in v1.2. Falling back to fumadocs.
2952
- `)+A.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
2953
- `)),"fumadocs"}return"fumadocs"}function Tr(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 Or(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function gc(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:"none",mcp:"on",metering:"auto",billingMode:"usage",idp:"clerk",accessGate:"none"}}function Lr(e){return e==="cn"?"wechat":"stripe"}async function fc(){let e=new pc;e.name(br).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(ae,"-v, --version").helpOption(!1).argument("[name]","project directory",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--region <id>","global | cn | hybrid").option("--orm <id>","prisma (default, primary) | drizzle (dual-ORM: adds db-drizzle alongside Prisma \u2014 Postgres only)").option("--db <id>","postgres | mysql | sqlite | none \u2014 engine (Prisma provider)").option("--db-host <id>","local | supabase | neon | vercel-postgres | planetscale | railway | aliyun-rds | tencent-cdb | none \u2014 managed-provider (region default: supabase global, local cn)").option("--auth <id>","clerk | betterauth | nextauth | supabase | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <mode-or-ids>","topology shorthand (gateway | direct | custom | none) OR comma-separated provider ids (e.g. openai,anthropic)").option("--deploy <target>","vercel | railway | cloudflare | selfhost").option("--docs <id>","fumadocs | mintlify | docusaurus | nextra | vitepress | none").option("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | none").option("--queue <id>","qstash | bullmq | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").option("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").option("--access-gate <mode>","none | invite (default: none)").option("--cron-jobs <bool>","true | false \u2014 scaffold scheduled cron handlers (default: true)").option("--audit-log <bool>","true | false \u2014 enable /settings/audit-log + arch test (default: false \u2014 @nebutra/audit is WIP)").option("--api-keys <bool>","true | false \u2014 enable /settings/api-keys page (default: true)").option("--command-palette <bool>","true | false \u2014 enable \u2318K command palette (default: true)").option("--cookie-consent <bool>","true | false \u2014 enable GDPR/CCPA cookie banner (default: true)").option("--legal-pages <bool>","true | false \u2014 enable dynamic /legal/[slug] route (default: true)").option("--china-compliance <bool>","true | false \u2014 enable @nebutra/china-compliance + ICP footer (default: true when --region=cn, otherwise false)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--with-workflows","scaffold workflows/ (inngest + n8n + pusher stubs)").option("--with-python-backend","scaffold backends/python/ (FastAPI stub \u2014 only when TS-by-Default ADR exception applies)").option("--no-install","skip package install").option("--no-git","skip git init").option("-y, --yes","accept all defaults (non-interactive)").option("--dry-run","preview actions without writing files").option("--json","machine-readable output").option("--no-color","disable color output").option("-h, --help","show help"),e.parse(process.argv);let t=e.opts(),[o]=e.args;t.help&&(Cn(),process.exit(0));let n=!!t.json,r=!!t.dryRun,s=!!t.yes,i=s||!process.stdin.isTTY;if(n||(ho(),bn()),p(n,{event:"start",version:ae}),!t.pm)try{kt("pnpm --version",{stdio:"ignore"})}catch{n||process.stderr.write(`
2954
- ${A.red("\u2718")} ${A.bold("pnpm is required")} but was not found on PATH.
2813
+ `}async function kr(e,t){let{projectName:n,region:o,previewSelections:r=[],waveFeatures:s={}}=t;try{let i=mt.join(e,".sailor");Ke.existsSync(i)||Ke.mkdirSync(i,{recursive:!0}),Ke.writeFileSync(mt.join(i,"next-steps.md"),Rc(n,o,r,s))}catch(i){let a=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${a}`)}try{let i=mt.join(e,"apps","web");if(!Ke.existsSync(i))return;let a=mt.join(i,"src","app","[locale]","welcome");Ke.existsSync(a)||Ke.mkdirSync(a,{recursive:!0}),Ke.writeFileSync(mt.join(a,"page.tsx"),Ic(n))}catch(i){let a=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write welcome page: ${a}`)}}function l(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2814
+ `)}function Tr(e){return e!==null&&typeof e=="object"&&"code"in e&&e.code==="ENOENT"}function Tc(e,t){for(let n of t)if(e)l(!0,{event:"warn",step:n.flag,provider:n.provider,packageStatus:n.status,message:he(n.status)});else{let o=Xe(n.status);process.stdout.write(gt.yellow(`\u26A0 ${n.flag}=${n.provider} ${o} \u2014 ${he(n.status)}
2815
+ `))}}function Nc(e,t,n){let o=$e.join(t,"packages/platform/db/prisma/schema.prisma"),r;try{r=Lt.readFileSync(o,"utf8")}catch(s){if(Tr(s)){l(e,{event:"step",step:"schema-prune",status:"skip"});return}let i=s instanceof Error?s.message:String(s);l(e,{event:"step",step:"schema-prune",status:"error",error:i});return}l(e,{event:"step",step:"schema-prune",status:"start"});try{let s=yn(r,n);Lt.writeFileSync(o,s),fn($e.join($e.dirname(o),"migrations"),n),l(e,{event:"step",step:"schema-prune",status:"ok"})}catch(s){let i=s instanceof Error?s.message:String(s);l(e,{event:"step",step:"schema-prune",status:"error",error:i})}}async function Nr(e){let{resolvedTarget:t,projectName:n,resolvedPm:o,opts:r,useJson:s,resolved:i,startedAt:a}=e,{region:c,orm:p,database:u,databaseHost:d,payment:_,paymentChoice:h,auth:f,socialLoginIds:E,aiProviders:S,deployTarget:m,docs:P,metering:G,billingMode:M,idp:ge,accessGate:pe,mcp:Z,waveToggles:j,previewSelections:K,config:C}=i,H={auth:f,payment:h,"billing-mode":M,idp:ge,template:"saas","access-gate":pe};l(s,{event:"step",step:"clone",status:"start"}),await Lo(t),l(s,{event:"step",step:"clone",status:"ok"}),l(s,{event:"step",step:"package",status:"start"}),await zo(t,n),l(s,{event:"step",step:"package",status:"ok"}),l(s,{event:"step",step:"config",status:"start"}),await co(t,C),l(s,{event:"step",step:"config",status:"ok"}),l(s,{event:"step",step:"governance-lints",status:"start"});let le=await Mo(t,C);l(s,{event:"step",step:"governance-lints",status:"ok",lints:le.lints}),l(s,{event:"step",step:"prune",status:"start"}),await cr(t,C),l(s,{event:"step",step:"prune",status:"ok"});{let v=$e.join(t,"packages/platform/db/prisma/schema.prisma"),k;try{k=Lt.readFileSync(v,"utf-8")}catch(I){if(Tr(I))l(s,{event:"step",step:"schema-prune",status:"skip"});else{let x=I instanceof Error?I.message:String(I);l(s,{event:"step",step:"schema-prune",status:"error",error:x})}}if(k!==void 0){l(s,{event:"step",step:"schema-prune",status:"start"});try{let I=yn(k,H);Lt.writeFileSync(v,I),fn($e.join($e.dirname(v),"migrations"),H),l(s,{event:"step",step:"schema-prune",status:"ok"})}catch(I){let x=I instanceof Error?I.message:String(I);l(s,{event:"step",step:"schema-prune",status:"error",error:x})}}}if(l(s,{event:"step",step:"auth",choice:f,status:"start"}),await zn(t,f),l(s,{event:"step",step:"auth",choice:f,status:"ok"}),E.length>0?(l(s,{event:"step",step:"social-login",providers:E,status:"start"}),await Qn(t,E,f),l(s,{event:"step",step:"social-login",providers:E,status:"ok"})):l(s,{event:"step",step:"social-login",status:"skip"}),l(s,{event:"step",step:"db",choice:u,status:"start"}),await uo(t,u,n),u!=="none"){let v=st(d);v&&(await mo(t,v,n),l(s,{event:"step",step:"db-host",choice:d,status:"ok"}))}if(l(s,{event:"step",step:"db",choice:u,status:"ok"}),p==="drizzle"){l(s,{event:"step",step:"orm",choice:"drizzle",status:"start"});let v=await Zo(t,"drizzle",u);l(s,{event:"step",step:"orm",choice:"drizzle",status:v.applied?"ok":"skip",...v.reason?{reason:v.reason}:{}})}if(l(s,{event:"step",step:"payment",choice:h,status:"start"}),await tr(t,h),l(s,{event:"step",step:"payment",choice:h,status:"ok"}),await vo(t,i.email,c),s&&l(!0,{event:"step",step:"email",choice:i.email,status:"ok"}),await Cr(t,i.storage,c),s&&l(!0,{event:"step",step:"storage",choice:i.storage,status:"ok"}),await Ho(t,i.monitoring,c),s&&l(!0,{event:"step",step:"monitoring",choice:i.monitoring,status:"ok"}),await Wn(t,i.analytics,c),s&&l(!0,{event:"step",step:"analytics",choice:i.analytics,status:"ok"}),await Ir(t,i.sms,c),s&&l(!0,{event:"step",step:"sms",choice:i.sms,status:"ok"}),await fr(t,i.queue,c),s&&l(!0,{event:"step",step:"queue",choice:i.queue,status:"ok"}),await Pr(t,i.search,c),s&&l(!0,{event:"step",step:"search",choice:i.search,status:"ok"}),await no(t,i.cache,c),s&&l(!0,{event:"step",step:"cache",choice:i.cache,status:"ok"}),await Xo(t,i.notifications,c),s&&l(!0,{event:"step",step:"notifications",choice:i.notifications,status:"ok"}),await Rr(t,i.webhooks,c),s&&l(!0,{event:"step",step:"webhooks",choice:i.webhooks,status:"ok"}),await io(t,i.cms,c),s&&l(!0,{event:"step",step:"cms",choice:i.cms,status:"ok"}),await Co(t,i.featureFlags,c),s&&l(!0,{event:"step",step:"feature-flags",choice:i.featureFlags,status:"ok"}),await ro(t,i.captcha,c),s&&l(!0,{event:"step",step:"captcha",choice:i.captcha,status:"ok"}),await Ko(t,Z),s&&l(!0,{event:"step",step:"mcp",mode:Z,status:"ok"}),await Yo(t,G,_),s&&l(!0,{event:"step",step:"metering",mode:G,status:"ok"}),l(s,{event:"step",step:"prune-wave-features",status:"start"}),pr(t,j),l(s,{event:"step",step:"prune-wave-features",status:"ok",toggles:j}),C.orm==="prisma"&&C.database!=="none"?Nc(s,t,H):l(s,{event:"step",step:"schema-prune",status:"skip"}),l(s,{event:"step",step:"billing-mode",choice:M,status:"ok"}),l(s,{event:"step",step:"idp",choice:ge,status:"ok"}),await ao(t,c),s&&l(!0,{event:"step",step:"compliance",region:c,status:"ok"}),await Ao(t),await wr(t,f),await kr(t,{projectName:n,region:c,previewSelections:K,waveFeatures:j}),C.aiMode!=="none"){l(s,{event:"step",step:"ai-providers",status:"start"});let v={providerIds:C.aiProviders,customEndpoint:C.customAiEndpoint},k=$e.join(t,"packages/ai/ai-providers/templates");await ir(t,v,k),l(s,{event:"step",step:"ai-providers",status:"ok"})}else l(s,{event:"step",step:"ai-providers",status:"skip"});l(s,{event:"step",step:"docs",status:"start"}),P!=="none"?(await yo(t,{framework:P,projectName:n}),l(s,{event:"step",step:"docs",framework:"fumadocs",requested:P,status:"ok"})):l(s,{event:"step",step:"docs",status:"skip"}),l(s,{event:"step",step:"deploy-target",status:"start"}),m!=="none"&&await Vn(t,m),await Bn(t,C.deployTargets),l(s,{event:"step",step:"deploy-target",status:"ok",targets:C.deployTargets});let w={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""};l(s,{event:"step",step:"env",status:"start"}),await _o(t,w),l(s,{event:"step",step:"env",status:"ok"}),l(s,{event:"step",step:"scaffold-extras",status:"start"});let fe=await Sr(t,{projectName:n,withWorkflows:!!r.withWorkflows,withPythonBackend:!!r.withPythonBackend});l(s,{event:"step",step:"scaffold-extras",status:"ok",applied:fe.applied,skipped:fe.skipped}),l(s,{event:"step",step:"license",status:"start"});try{let v=Vo(t,{projectName:n,cliVersion:X});l(s,{event:"step",step:"license",status:"ok",tier:"independent",wrote:v.wrote}),s||process.stdout.write(gt.dim(` License: Nebutra-Sailor Independent Developer License (free for \u2264 1 FTE, < $1M ARR).
2816
+ Upstream AGPL preserved as LICENSE-AGPL-REFERENCE.md.
2817
+ `))}catch(v){l(s,{event:"step",step:"license",status:"warn",message:v instanceof Error?v.message:String(v)})}if(r.install!==!1){let v=o==="bun"?"bun":o,k=["install"];s?l(!0,{event:"step",step:"install",pm:o,status:"start"}):process.stdout.write(gt.dim(` Installing dependencies with ${o}\u2026
2818
+ `));try{Ot(v,k,{cwd:t,stdio:s?"ignore":"inherit"}),l(s,{event:"step",step:"install",status:"ok"})}catch(I){let x=I instanceof Error?I.message:String(I);s?l(!0,{event:"step",step:"install",status:"error",error:x}):process.stdout.write(gt.yellow(` \u26A0 install failed \u2014 run '${o} install' manually.
2819
+ `))}}else l(s,{event:"step",step:"install",status:"skip"});if(r.git!==!1){s&&l(!0,{event:"step",step:"git-init",status:"start"});try{Ot("git",["init","-q"],{cwd:t,stdio:"ignore"}),Ot("git",["add","-A"],{cwd:t,stdio:"ignore"}),Ot("git",["-c","user.email=you@example.com","-c","user.name=You","commit","-q","-m","chore: initial scaffold from create-sailor"],{cwd:t,stdio:"ignore"}),l(s,{event:"step",step:"git-init",status:"ok"})}catch(v){let k=v instanceof Error?v.message:String(v);s?l(!0,{event:"step",step:"git-init",status:"error",error:k}):process.stdout.write(gt.yellow(` \u26A0 git init skipped \u2014 not fatal.
2820
+ `))}}else l(s,{event:"step",step:"git-init",status:"skip"});let ye=Math.max(1,Math.round((Date.now()-a)/1e3));Xn({template_version:X,package_manager:o,region:c,auth:f,payment:h,ai_providers:S,deploy_target:m,duration_ms:Date.now()-a}),K.length>0&&Tc(s,K),s?l(!0,{event:"done",status:"ok",elapsedSec:ye,targetDir:t,previewSelections:K,waveFeatures:j}):qn({elapsedSec:ye,targetDir:t,skippedInstall:r.install===!1,previewSelections:K,waveFeatures:j});try{kc({pkg:{name:"create-sailor",version:X},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}}import Oc from"cfonts";import Lc from"picocolors";function Or(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${X}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
2821
+ `));return}Oc.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(Lc.dim(` AI-Native SaaS Template \xB7 v${X} \xB7 nebutra.com
2955
2822
 
2956
- The scaffold uses pnpm workspaces + Turborepo. Install pnpm first:
2957
- ${A.cyan("npm i -g pnpm@10")}
2958
-
2959
- Then retry: ${A.cyan("pnpm dlx create-sailor@latest")}
2960
- (or pass ${A.dim("--pm=npm")} if you know workspace:* won't resolve in your setup)
2961
-
2962
- `),p(n,{event:"error",code:"PNPM_MISSING"}),process.exit(1)}let c=o??(s?"./my-saas-app":void 0),a;if(c)a=c;else if(i)a="./my-saas-app";else{let g=await O.group({name:()=>O.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:h=>{if(h.length===0)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(A.red(`\u2718 Cancelled
2963
- `)),process.exit(130)}});a=String(g.name)}let l=de.basename(de.resolve(a)),u=t.pm??dc(),S=!!t.region,I=!!t.auth,C=!!t.payment,U=!!t.ai,ue=!!t.email,b=!!t.storage,m=!!t.monitoring,M=!!t.analytics,xt=!!t.sms,En=t.i18n!==void 0,E,Ke,G,Nt="local",mt,H,j,Q=Ln(t.socialLogin),gt,Zt,be,$e,ie,W,Tt;if(i){E=Or(t.region),Ke=Cr(t.orm);{let Ae=Pr(t.db),V=Ar(t.dbHost,E,Ae);G=V.engine,Nt=V.hostId}let g=C?t.payment:Lr(E);mt=Ir(g),H=wr(g),j=Rr(t.auth);let h="gateway";if(U){let Ae=t.ai?.trim().toLowerCase()??"";Ur(Ae)?h=Ae:h="direct"}let L=on({mode:h,providerIds:U?kr(t.ai):void 0});gt=L.mode,Zt=L.routing,be=L.providerIds,ie=Tr(t.deploy),W=Nr(t.docs,n),Tt=En?!!t.i18n:!0}else{let g={};S||(g.region=()=>O.select({message:"Target region?",options:[{value:"global",label:"global \u2014 \u6D77\u5916\u4F18\u5148"},{value:"cn",label:"cn \u2014 \u56FD\u5185\u4F18\u5148"},{value:"hybrid",label:"hybrid \u2014 \u53CC\u8F68\uFF08\u56FD\u5185+\u51FA\u6D77\uFF09"}],initialValue:"global"})),I||(g.auth=()=>O.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk",hint:"managed, fastest setup"},{value:"betterauth",label:"Better Auth",hint:"self-hosted, modern (2FA / passkeys / RBAC)"},{value:"nextauth",label:"NextAuth (Auth.js v5)",hint:"self-hosted, mature, large ecosystem"},{value:"supabase",label:"Supabase Auth",hint:"managed auth with Supabase storage/realtime ecosystem"},{value:"none",label:"None"}],initialValue:"clerk"})),U||(g.aiMode=()=>O.select({message:"AI topology?",options:[{value:"gateway",label:"Multi-provider AI Gateway / router",hint:"recommended"},{value:"direct",label:"Direct SDK/provider adapters"},{value:"custom",label:"OpenAI-compatible endpoint"},{value:"none",label:"Skip AI"}],initialValue:"gateway"}),g.aiProviders=({results:f})=>{if(f.aiMode!=="direct")return Promise.resolve([]);let _=nn.map(Y=>({value:Y.id,label:`[${Y.category}] ${Y.name}`}));return O.multiselect({message:"Select direct AI provider adapters (expert path)",options:_,initialValues:["openai"],required:!1})},g.customAiName=({results:f})=>f.aiMode==="custom"?O.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),g.customAiBaseUrl=({results:f})=>f.aiMode==="custom"?O.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:_=>{if(_.length===0)return"Base URL is required."}}):Promise.resolve(void 0),g.customAiApiKeyEnv=({results:f})=>f.aiMode==="custom"?O.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0));let h=Object.keys(g).length>0?await O.group(g,{onCancel:()=>{process.stdout.write(A.red(`\u2718 Cancelled
2964
- `)),process.exit(130)}}):{};E=Or(S?t.region:h.region),Ke=Cr(t.orm);{let f=Pr(t.db),_=Ar(t.dbHost,E,f);G=_.engine,Nt=_.hostId}let L=C?t.payment:Lr(E);mt=Ir(L),H=wr(L),j=Rr(I?t.auth:h.auth);let Ae=h.aiMode==="custom"?{name:h.customAiName??"custom",baseURL:h.customAiBaseUrl??"",apiKeyEnvName:h.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,V=on({mode:U?t.ai?.trim().toLowerCase()==="none"?"none":"direct":h.aiMode??"gateway",providerIds:U?kr(t.ai):h.aiProviders,customEndpoint:Ae});gt=V.mode,Zt=V.routing,be=V.providerIds,V.customEndpoint&&($e={name:V.customEndpoint.name,baseURL:V.customEndpoint.baseURL,apiKeyEnvName:V.customEndpoint.apiKeyEnvName}),ie=Tr(t.deploy),W=Nr(t.docs,n),Tt=En?!!t.i18n:!0}let k=gc(E),Ye=ue?t.email:k.email,qe=mc(b?t.storage:void 0,k.storage),Ge=m?t.monitoring:k.monitoring,He=M?t.analytics:k.analytics,We=xt?t.sms:k.sms,Xe=t.queue??k.queue,ze=t.search??k.search,ft=t.cache??k.cache,Je=t.notifications??k.notifications,Qe=t.webhooks??k.webhooks,yt=t.cms??k.cms,Ze=t.featureFlags??k.featureFlags,et=t.captcha??k.captcha,Ot=t.mcp??k.mcp,St=t.metering??k.metering,tt=t.billingMode??k.billingMode,nt=t.idp??k.idp,ht=t.accessGate==="invite"?"invite":k.accessGate,w=hr({cronJobs:t.cronJobs,auditLog:t.auditLog,apiKeys:t.apiKeys,commandPalette:t.commandPalette,cookieConsent:t.cookieConsent,legalPages:t.legalPages,chinaCompliance:t.chinaCompliance},E),ot=Pn([{flag:"queue",provider:Xe},{flag:"search",provider:ze},{flag:"notifications",provider:Je},{flag:"webhooks",provider:Qe},{flag:"feature-flags",provider:Ze},{flag:"captcha",provider:et},{flag:"access-gate",provider:ht}]);function en(){for(let g of ot)if(n)p(!0,{event:"warn",step:g.flag,provider:g.provider,packageStatus:g.status,message:me(g.status)});else{let h=rt(g.status);process.stdout.write(A.yellow(`\u26A0 ${g.flag}=${g.provider} ${h} \u2014 ${me(g.status)}
2965
- `))}}let Pe={region:E,orm:Ke,database:G,payment:mt,aiMode:gt,aiRouting:Zt,aiProviders:be,customAiEndpoint:$e,deployTarget:ie,docs:W,i18n:Tt,email:Ye,storage:qe,monitoring:Ge,analytics:He,sms:We,queue:Xe,search:ze,cache:ft,notifications:Je,webhooks:Qe,cms:yt,featureFlags:Ze,captcha:et,mcp:Ot,metering:St,billingMode:tt,idp:nt,accessGate:ht,cronJobs:w.cronJobs,auditLog:w.auditLog,apiKeys:w.apiKeys,commandPalette:w.commandPalette,cookieConsent:w.cookieConsent,legalPages:w.legalPages,chinaCompliance:w.chinaCompliance},Lt=[["Project name",l],["Region",E],["Auth",j],["Social login",Q.length>0?Q.map(g=>Et.find(h=>h.id===g)?.name??g).join(", "):"none"],["ORM",Ke],["Database",G],["Payment",H],["AI topology",`${gt}${be.length>0?` (${be.join(", ")} seed)`:""}${$e?" + custom endpoint":""}`],["Email",Ye],["Storage",qe],["Monitoring",Ge],["Analytics",He],["SMS",We],["Deploy Target",ie],["Docs Framework",W],["Access gate",ht]];n?Lt.forEach(([g,h],L)=>{p(!0,{event:"step",step:g,value:h,index:L+1,total:Lt.length})}):Lt.forEach(([g,h],L)=>{wn({index:L+1,total:Lt.length,label:g,value:h})});let Mr={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""},vn=Date.now();if(r){let g=be.length,h=[`clone template \u2192 ${a}`,"write nebutra.config.json",`prune template (orm=${Ke}, i18n=${Tt})`,`region \u2192 ${E}`,`auth \u2192 ${j==="none"?"skip (remove packages/auth)":`configure ${j}`}`,...Q.length>0?[`social-login \u2192 generate ${Q.length} callback route${Q.length===1?"":"s"} + SocialLoginButtons.tsx (${Q.join(", ")})`]:[],`db \u2192 ${G==="none"?"skip (remove packages/db)":`configure Prisma for ${G}`}`,`payment \u2192 ${H==="none"?"skip (remove packages/billing)":`configure ${H}`}`,...W!=="none"?[`docs \u2192 scaffold apps/docs (${W==="fumadocs"?"fumadocs":`${W} \u2192 fumadocs fallback`})`]:[],...g>0||$e?[`ai-providers \u2192 generate ${gt} registry seed + env (${g}${$e?" + custom":""} provider${g===1&&!$e?"":"s"})`]:[],...Ye!=="none"?[`email \u2192 configure ${Ye}`]:[],...qe!=="none"?[`storage \u2192 configure ${qe}`]:[],...Ge!=="none"?[`monitoring \u2192 configure ${Ge}`]:[],...He!=="none"?[`analytics \u2192 configure ${He}`]:[],...We!=="none"?[`sms \u2192 configure ${We}`]:[],...Xe!=="none"?[`queue \u2192 configure ${Xe}`]:[],...ze!=="none"?[`search \u2192 configure ${ze}`]:[],...ft!=="none"?[`cache \u2192 configure ${ft}`]:[],...Je!=="none"?[`notifications \u2192 configure ${Je}`]:[],...Qe!=="none"?[`webhooks \u2192 configure ${Qe}`]:[],...yt!=="none"?[`cms \u2192 configure ${yt}`]:[],...Ze!=="none"?[`feature-flags \u2192 configure ${Ze}`]:[],...et!=="none"?[`captcha \u2192 configure ${et}`]:[],`mcp \u2192 ${Ot==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${St==="off"?"disabled":St==="auto"?mt!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...tt!=="usage"?[`billing-mode \u2192 ${tt}`]:[],...nt!=="clerk"?[`idp \u2192 ${nt}`]:[],`cron-jobs \u2192 ${w.cronJobs?"enabled":"disabled"}`,`audit-log \u2192 ${w.auditLog?"enabled":"disabled"}`,`api-keys \u2192 ${w.apiKeys?"enabled":"disabled"}`,`command-palette \u2192 ${w.commandPalette?"enabled":"disabled"}`,`cookie-consent \u2192 ${w.cookieConsent?"enabled":"disabled"}`,`legal-pages \u2192 ${w.legalPages?"enabled":"disabled"}`,`china-compliance \u2192 ${w.chinaCompliance?"enabled (@nebutra/china-compliance + ICP footer)":"disabled"}`,`compliance \u2192 inject ${E} boilerplate (ICP/Cookie/AIGC/Privacy)`,"welcome \u2192 generate dev welcome page","env \u2192 generate random secrets (AUTH_SECRET, JWT_SECRET)","seed \u2192 generate prisma/seed.ts (1 admin + 3 tenants)",...ie!=="none"?[`deploy \u2192 inject ${ie} config`]:[],"inject .env.local",t.install===!1?"skip install":`run ${u} install`,t.git===!1?"skip git init":"run git init"];if(n){for(let L of h)p(!0,{event:"plan",action:L});en(),p(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
2966
- `+A.bold(`Dry run \u2014 planned actions:
2967
- `));for(let L of h)process.stdout.write(` \u2022 ${L}
2968
- `);ot.length>0&&(process.stdout.write(`
2969
- `+A.bold(A.yellow(`Preview-status providers selected:
2970
- `))),en()),process.stdout.write(A.dim(`
2823
+ `))}var Uc=`Usage: create-sailor [name] [options]
2824
+
2825
+ Arguments:
2826
+ name project directory (default: ./my-saas-app)
2827
+
2828
+ Core options:
2829
+ -p, --pm <id> npm | pnpm | yarn | bun (auto-detected)
2830
+ --region <id> global | cn | hybrid (default: global)
2831
+ --auth <id> clerk | betterauth | nextauth | supabase | none
2832
+ --ai <ids> expert/non-interactive provider seed (e.g. openai,anthropic)
2833
+
2834
+ Interactive AI topology:
2835
+ Default first-run asks for topology, not individual provider enablement:
2836
+ gateway Multi-provider AI Gateway / router (recommended)
2837
+ direct Direct SDK/provider adapters
2838
+ custom OpenAI-compatible endpoint
2839
+ none Skip AI
2840
+
2841
+ Stack flags (region-based smart defaults):
2842
+ --orm <id> prisma | drizzle | none (default: prisma)
2843
+ --db <id> postgres | mysql | sqlite | none (default: postgres)
2844
+ --payment <id> stripe | lemon | wechat | alipay | none (default: region-based)
2845
+ --deploy <target> vercel | railway | cloudflare | selfhost (default: vercel)
2846
+ also writes per-service DEPLOY_TARGET_* selectors
2847
+ --docs <id> fumadocs | mintlify | docusaurus | nextra | vitepress | none
2848
+
2849
+ Feature flags (region-based smart defaults):
2850
+ --email <id> resend | postmark | ses | aliyun-dm | tencent-ses | netease | none
2851
+ --storage <id> r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none
2852
+ --monitoring <id> sentry | datadog | aliyun-arms | tingyun | none
2853
+ --analytics <id> posthog | plausible | umami | baidu | sensors | none
2854
+ --sms <id> twilio | aliyun-sms | tencent-sms | yunpian | none
2855
+ --queue <id> qstash | bullmq | upstash | sqs | none [Foundation]
2856
+ --search <id> meilisearch | typesense | algolia | pgvector | none [Foundation]
2857
+ --cache <id> upstash-redis | vercel-kv | redis | dragonfly | none
2858
+ --notifications <id> novu | knock | custom | none
2859
+ --webhooks <id> svix | custom | none
2860
+ --cms <id> sanity | contentful | strapi | none
2861
+ --feature-flags <id> vercel-flags | growthbook | configcat | none [Foundation]
2862
+ --captcha <id> turnstile | hcaptcha | aliyun-slide | none [WIP]
2863
+ --billing-mode <mode> usage | seat | credits (default: usage)
2864
+ --idp <id> clerk | oauth-server (default: clerk)
2865
+ --access-gate <mode> none | invite (default: none)
2866
+
2867
+ Preview statuses:
2868
+ [Foundation] \u2014 core path works; provider credentials, adapter wiring, or integration verification still required
2869
+ [WIP] \u2014 actively being built; do not use in production
2870
+ See: https://github.com/Nebutra/Nebutra-Sailor/blob/main/docs/package-status.md
2871
+
2872
+ Sailor features:
2873
+ --mcp <mode> on | off (default: on \u2014 Agent-friendly MCP server)
2874
+ --metering <mode> auto | on | off (default: auto)
2875
+
2876
+ Toggles:
2877
+ --i18n enable i18n (default: true)
2878
+ --no-i18n disable
2879
+ --no-install skip package install
2880
+ --no-git skip git init
2881
+ -y, --yes accept all defaults (non-interactive)
2882
+ --dry-run preview actions without writing files
2883
+ --json machine-readable output
2884
+ --no-color disable color output
2885
+ -h, --help show this help
2886
+ -v, --version show version
2887
+
2888
+ Examples:
2889
+ $ npx create-sailor@latest
2890
+ $ npx create-sailor@latest my-app -y
2891
+ $ npx create-sailor@latest my-app --region=cn --auth=clerk
2892
+ $ npx create-sailor@latest my-app --region=hybrid --ai=openai,deepseek
2893
+ $ npm create sailor@latest --dry-run --region=cn
2894
+ `;function Lr(){process.stdout.write(Uc)}import Ut from"picocolors";function Ur(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function Mc(e){let t=Ur()?"\u25B8":"->",n=`[${e.index}/${e.total}]`,o=e.label.padEnd(18," ");return Ur()?`${Ut.dim(n)} ${Ut.bold(o)} ${Ut.dim(t)} ${Ut.cyan(e.value)}`:`${n} ${o} ${t} ${e.value}`}function Mr(e){process.stdout.write(Mc(e)+`
2895
+ `)}import{existsSync as Dc,mkdirSync as Dr,writeFileSync as Fr}from"fs";import{homedir as jr,platform as Fc}from"os";import{join as ft}from"path";function jc(){if(Fc()==="win32"){let t=process.env.LOCALAPPDATA||ft(jr(),"AppData","Local");return ft(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?ft(e,"nebutra"):ft(jr(),".config","nebutra")}function Bc(){let e=process.env.NEBUTRA_TELEMETRY;return e==="0"||e==="false"||e==="no"}function Br(){if(!process.stderr.isTTY||!process.stdin.isTTY||process.env.CI)return;let e=jc(),t=ft(e,"first-run-acked");try{if(Dc(t))return}catch{return}if(Bc()){try{Dr(e,{recursive:!0}),Fr(t,"")}catch{}return}let n=["[36m\u2139[0m Nebutra collects anonymous usage analytics to improve the scaffolder."," Opt out at any time: export NEBUTRA_TELEMETRY=0"," Privacy policy: https://nebutra.com/legal/cli-analytics",""];try{process.stderr.write(n.join(`
2896
+ `))}catch{}try{Dr(e,{recursive:!0}),Fr(t,"")}catch{}}function Ye(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2897
+ `)}function Kc(e,t,n,o,r){let{region:s,orm:i,database:a,paymentChoice:c,docs:p,socialLoginIds:u,aiMode:d,aiProviders:_,customAiEndpoint:h,deployTarget:f,metering:E,payment:S,billingMode:m,idp:P,mcp:G,waveToggles:M,previewSelections:ge}=t,{email:pe,storage:Z,monitoring:j,analytics:K,sms:C,queue:H,search:le,cache:w,notifications:fe,webhooks:qe,cms:Ge,featureFlags:ye,captcha:v}=t,k=_.length,I=[`clone template \u2192 ${n}`,"write nebutra.config.json",`governance-lints \u2192 write governance.config.json + wire pnpm lint (no-raw-inputs${a!=="none"?" + repository-seam":""})`,`prune template (orm=${i}, i18n=${t.i18n})`,`region \u2192 ${s}`,`auth \u2192 ${t.auth==="none"?"skip (remove packages/auth)":`configure ${t.auth}`}`,...u.length>0?[`social-login \u2192 generate ${u.length} callback route${u.length===1?"":"s"} + SocialLoginButtons.tsx (${u.join(", ")})`]:[],`db \u2192 ${a==="none"?"skip (remove packages/db)":`configure Prisma for ${a}`}`,...a!=="none"?[`db-host \u2192 configure ${t.databaseHost}`]:[],`payment \u2192 ${c==="none"?"skip (remove packages/billing)":`configure ${c}`}`,...p!=="none"?[`docs \u2192 scaffold apps/docs (${p==="fumadocs"?"fumadocs":`${p} \u2192 fumadocs fallback`})`]:[],...k>0||h?[`ai-providers \u2192 generate ${d} registry seed + env (${k}${h?" + custom":""} provider${k===1&&!h?"":"s"})`]:[],...pe!=="none"?[`email \u2192 configure ${pe}`]:[],...Z!=="none"?[`storage \u2192 configure ${Z}`]:[],...j!=="none"?[`monitoring \u2192 configure ${j}`]:[],...K!=="none"?[`analytics \u2192 configure ${K}`]:[],...C!=="none"?[`sms \u2192 configure ${C}`]:[],...H!=="none"?[`queue \u2192 configure ${H}`]:[],...le!=="none"?[`search \u2192 configure ${le}`]:[],...w!=="none"?[`cache \u2192 configure ${w}`]:[],...fe!=="none"?[`notifications \u2192 configure ${fe}`]:[],...qe!=="none"?[`webhooks \u2192 configure ${qe}`]:[],...Ge!=="none"?[`cms \u2192 configure ${Ge}`]:[],...ye!=="none"?[`feature-flags \u2192 configure ${ye}`]:[],...v!=="none"?[`captcha \u2192 configure ${v}`]:[],`mcp \u2192 ${G==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${E==="off"?"disabled":E==="auto"?S!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...m!=="usage"?[`billing-mode \u2192 ${m}`]:[],...P!=="clerk"?[`idp \u2192 ${P}`]:[],`cron-jobs \u2192 ${M.cronJobs?"enabled":"disabled"}`,`audit-log \u2192 ${M.auditLog?"enabled":"disabled"}`,`api-keys \u2192 ${M.apiKeys?"enabled":"disabled"}`,`command-palette \u2192 ${M.commandPalette?"enabled":"disabled"}`,`cookie-consent \u2192 ${M.cookieConsent?"enabled":"disabled"}`,`legal-pages \u2192 ${M.legalPages?"enabled":"disabled"}`,`china-compliance \u2192 ${M.chinaCompliance?"enabled (@nebutra/china-compliance + ICP footer)":"disabled"}`,`compliance \u2192 inject ${s} 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)",...f!=="none"?[`deploy \u2192 inject ${f} config`]:[],"inject .env.local",r.install===!1?"skip install":`run ${o} install`,r.git===!1?"skip git init":"run git init"];if(e){for(let x of I)Ye(!0,{event:"plan",action:x});for(let x of ge)Ye(!0,{event:"warn",step:x.flag,provider:x.provider,packageStatus:x.status});Ye(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
2898
+ `+F.bold(`Dry run \u2014 planned actions:
2899
+ `));for(let x of I)process.stdout.write(` \u2022 ${x}
2900
+ `);if(ge.length>0){process.stdout.write(`
2901
+ `+F.bold(F.yellow(`Preview-status providers selected:
2902
+ `)));for(let x of ge)process.stdout.write(F.yellow(`\u26A0 ${x.flag}=${x.provider}
2903
+ `))}process.stdout.write(F.dim(`
2971
2904
  No files were written.
2972
- `))}process.exit(0)}let Dr=async()=>{process.stdout.write(`
2973
- `+A.red(`\u2718 Cancelled
2974
- `)),_e.existsSync(a)&&await O.confirm({message:`Cleanup partial install at ${a}?`,initialValue:!0})===!0&&(_e.rmSync(a,{recursive:!0,force:!0}),process.stdout.write(A.dim(` \u2713 Removed ${a}
2975
- `))),process.exit(130)};process.on("SIGINT",Dr);try{p(n,{event:"step",step:"clone",status:"start"}),await Co(a),p(n,{event:"step",step:"clone",status:"ok"}),p(n,{event:"step",step:"package",status:"start"}),await jo(a,l),p(n,{event:"step",step:"package",status:"ok"}),p(n,{event:"step",step:"config",status:"start"}),await Gn(a,Pe),p(n,{event:"step",step:"config",status:"ok"}),p(n,{event:"step",step:"prune",status:"start"}),await Jo(a,Pe),p(n,{event:"step",step:"prune",status:"ok"});let g=de.join(a,"packages/platform/db/prisma/schema.prisma");if(_e.existsSync(g)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let f=_e.readFileSync(g,"utf-8"),_={auth:j,payment:H,"billing-mode":tt,idp:nt,template:"saas","access-gate":ht},Y=fn(f,_);_e.writeFileSync(g,Y),gn(de.join(de.dirname(g),"migrations"),_),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(f){let _=f instanceof Error?f.message:String(f);p(n,{event:"step",step:"schema-prune",status:"error",error:_})}}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"auth",choice:j,status:"start"}),await Tn(a,j),p(n,{event:"step",step:"auth",choice:j,status:"ok"}),Q.length>0?(p(n,{event:"step",step:"social-login",providers:Q,status:"start"}),await Mn(a,Q,j),p(n,{event:"step",step:"social-login",providers:Q,status:"ok"})):p(n,{event:"step",step:"social-login",status:"skip"}),p(n,{event:"step",step:"db",choice:G,status:"start"}),await zn(a,G,l),G!=="none"){let f=$t(Nt);f&&(await Jn(a,f,l),p(n,{event:"step",step:"db-host",choice:Nt,status:"ok"}))}if(p(n,{event:"step",step:"db",choice:G,status:"ok"}),Ke==="drizzle"){p(n,{event:"step",step:"orm",choice:"drizzle",status:"start"});let f=await Ko(a,"drizzle",G);p(n,{event:"step",step:"orm",choice:"drizzle",status:f.applied?"ok":"skip",...f.reason?{reason:f.reason}:{}})}if(p(n,{event:"step",step:"payment",choice:H,status:"start"}),await Yo(a,H),p(n,{event:"step",step:"payment",choice:H,status:"ok"}),await io(a,Ye,E),n&&p(!0,{event:"step",step:"email",choice:Ye,status:"ok"}),await Sr(a,qe,E),n&&p(!0,{event:"step",step:"storage",choice:qe,status:"ok"}),await Mo(a,Ge,E),n&&p(!0,{event:"step",step:"monitoring",choice:Ge,status:"ok"}),await xn(a,He,E),n&&p(!0,{event:"step",step:"analytics",choice:He,status:"ok"}),await fr(a,We,E),n&&p(!0,{event:"step",step:"sms",choice:We,status:"ok"}),await rr(a,Xe,E),n&&p(!0,{event:"step",step:"queue",choice:Xe,status:"ok"}),await ur(a,ze,E),n&&p(!0,{event:"step",step:"search",choice:ze,status:"ok"}),await Vn(a,ft,E),n&&p(!0,{event:"step",step:"cache",choice:ft,status:"ok"}),await Fo(a,Je,E),n&&p(!0,{event:"step",step:"notifications",choice:Je,status:"ok"}),await vr(a,Qe,E),n&&p(!0,{event:"step",step:"webhooks",choice:Qe,status:"ok"}),await Yn(a,yt,E),n&&p(!0,{event:"step",step:"cms",choice:yt,status:"ok"}),await go(a,Ze,E),n&&p(!0,{event:"step",step:"feature-flags",choice:Ze,status:"ok"}),await Kn(a,et,E),n&&p(!0,{event:"step",step:"captcha",choice:et,status:"ok"}),await No(a,Ot),n&&p(!0,{event:"step",step:"mcp",mode:Ot,status:"ok"}),await Oo(a,St,mt),n&&p(!0,{event:"step",step:"metering",mode:St,status:"ok"}),p(n,{event:"step",step:"prune-wave-features",status:"start"}),Qo(a,w),p(n,{event:"step",step:"prune-wave-features",status:"ok",toggles:w}),Pe.orm==="prisma"&&Pe.database!=="none"){let f=de.join(a,"packages/platform/db/prisma/schema.prisma");if(_e.existsSync(f)){p(n,{event:"step",step:"schema-prune",status:"start"});try{let _=_e.readFileSync(f,"utf8"),Y={auth:j,payment:H,"billing-mode":tt,idp:nt,template:"saas","access-gate":ht},Fr=fn(_,Y);_e.writeFileSync(f,Fr),gn(de.join(de.dirname(f),"migrations"),Y),p(n,{event:"step",step:"schema-prune",status:"ok"})}catch(_){let Y=_ instanceof Error?_.message:String(_);p(n,{event:"step",step:"schema-prune",status:"error",error:Y})}}else p(n,{event:"step",step:"schema-prune",status:"skip"})}else p(n,{event:"step",step:"schema-prune",status:"skip"});if(p(n,{event:"step",step:"billing-mode",choice:tt,status:"ok"}),p(n,{event:"step",step:"idp",choice:nt,status:"ok"}),await qn(a,E),n&&p(!0,{event:"step",step:"compliance",region:E,status:"ok"}),await uo(a),await mr(a,j),await _r(a,{projectName:l,region:E,previewSelections:ot,waveFeatures:w}),Pe.aiMode!=="none"){p(n,{event:"step",step:"ai-providers",status:"start"});let f={providerIds:Pe.aiProviders,customEndpoint:Pe.customAiEndpoint},_=de.join(a,"packages/ai/ai-providers/templates");await Xo(a,f,_),p(n,{event:"step",step:"ai-providers",status:"ok"})}else p(n,{event:"step",step:"ai-providers",status:"skip"});p(n,{event:"step",step:"docs",status:"start"}),W!=="none"?(await no(a,{framework:W,projectName:l}),p(n,{event:"step",step:"docs",framework:"fumadocs",requested:W,status:"ok"})):p(n,{event:"step",step:"docs",status:"skip"}),p(n,{event:"step",step:"deploy-target",status:"start"}),ie!=="none"&&await Zn(a,ie),p(n,{event:"step",step:"deploy-target",status:"ok"}),p(n,{event:"step",step:"env",status:"start"}),await co(a,Mr),p(n,{event:"step",step:"env",status:"ok"}),p(n,{event:"step",step:"scaffold-extras",status:"start"});let h=await ir(a,{projectName:l,withWorkflows:!!t.withWorkflows,withPythonBackend:!!t.withPythonBackend});p(n,{event:"step",step:"scaffold-extras",status:"ok",applied:h.applied,skipped:h.skipped}),p(n,{event:"step",step:"license",status:"start"});try{let f=xo(a,{projectName:l,cliVersion:ae});p(n,{event:"step",step:"license",status:"ok",tier:"independent",wrote:f.wrote}),n||process.stdout.write(A.dim(` License: Nebutra-Sailor Independent Developer License (free for \u2264 1 FTE, < $1M ARR).
2976
- Upstream AGPL preserved as LICENSE-AGPL-REFERENCE.md.
2977
- `))}catch(f){p(n,{event:"step",step:"license",status:"warn",message:f instanceof Error?f.message:String(f)})}if(t.install!==!1){let f=u==="bun"?"bun install":`${u} install`;n?p(!0,{event:"step",step:"install",pm:u,status:"start"}):process.stdout.write(A.dim(` Installing dependencies with ${u}\u2026
2978
- `));try{kt(f,{cwd:a,stdio:n?"ignore":"inherit"}),p(n,{event:"step",step:"install",status:"ok"})}catch(_){let Y=_ instanceof Error?_.message:String(_);n?p(!0,{event:"step",step:"install",status:"error",error:Y}):process.stdout.write(A.yellow(` \u26A0 install failed \u2014 run '${f}' manually.
2979
- `))}}else p(n,{event:"step",step:"install",status:"skip"});if(t.git!==!1){n&&p(!0,{event:"step",step:"git-init",status:"start"});try{kt("git init -q",{cwd:a,stdio:"ignore"}),kt("git add -A",{cwd:a,stdio:"ignore"}),kt('git -c user.email=you@example.com -c user.name="You" commit -q -m "chore: initial scaffold from create-sailor"',{cwd:a,stdio:"ignore"}),p(n,{event:"step",step:"git-init",status:"ok"})}catch(f){let _=f instanceof Error?f.message:String(f);n?p(!0,{event:"step",step:"git-init",status:"error",error:_}):process.stdout.write(A.yellow(` \u26A0 git init skipped \u2014 not fatal.
2980
- `))}}else p(n,{event:"step",step:"git-init",status:"skip"});let V=Math.max(1,Math.round((Date.now()-vn)/1e3));Nn({template_version:ae,package_manager:u,region:E,auth:j,payment:H,ai_providers:be,deploy_target:ie,duration_ms:Date.now()-vn}),ot.length>0&&en(),n?p(!0,{event:"done",status:"ok",elapsedSec:V,targetDir:a,previewSelections:ot,waveFeatures:w}):An({elapsedSec:V,targetDir:a,skippedInstall:t.install===!1,previewSelections:ot,waveFeatures:w});try{lc({pkg:{name:br,version:ae},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}process.exit(0)}catch(g){let h=g instanceof Error?g.message:String(g);n?p(!0,{event:"error",message:h}):process.stdout.write(A.red(`
2981
- \u2718 Failed: ${h}
2982
- `)),process.exit(1)}}fc().catch(e=>{process.stderr.write(String(e)+`
2905
+ `))}}async function $c(){let e=Cn();e.parse(process.argv);let t=e.opts(),[n]=e.args;t.help&&(Lr(),process.exit(0));let o=!!t.json,r=!!t.dryRun,s=!!t.yes,i=s||!process.stdin.isTTY;if(o||(Br(),Or()),Ye(o,{event:"start",version:X}),!t.pm)try{Vc("pnpm --version",{stdio:"ignore"})}catch{o||process.stderr.write(`
2906
+ ${F.red("\u2718")} ${F.bold("pnpm is required")} but was not found on PATH.
2907
+
2908
+ The scaffold uses pnpm workspaces + Turborepo. Install pnpm first:
2909
+ ${F.cyan("npm i -g pnpm@10")}
2910
+
2911
+ Then retry: ${F.cyan("pnpm dlx create-sailor@latest")}
2912
+ (or pass ${F.dim("--pm=npm")} if you know workspace:* won't resolve in your setup)
2913
+
2914
+ `),Ye(o,{event:"error",code:"PNPM_MISSING"}),process.exit(1)}let a=n??(s?"./my-saas-app":void 0),c;if(a)c=a;else if(i)c="./my-saas-app";else{let f=await ot.group({name:()=>ot.text({message:"Where should we create your project?",placeholder:"./my-saas-app",defaultValue:"./my-saas-app",validate:E=>{if(!E?.length)return"Please enter a path."}})},{onCancel:()=>{process.stdout.write(F.red(`\u2718 Cancelled
2915
+ `)),process.exit(130)}});c=String(f.name)}let p=Kr.basename(Kr.resolve(c)),u=t.pm??Nn(),d=await Yn(t,o),_=[["Project name",p],["Region",d.region],["Auth",d.auth],["Social login",d.socialLoginIds.length>0?d.socialLoginIds.map(f=>We.find(E=>E.id===f)?.name??f).join(", "):"none"],["ORM",d.orm],["Database",d.database],["Database Host",d.databaseHost],["Payment",d.paymentChoice],["AI topology",`${d.aiMode}${d.aiProviders.length>0?` (${d.aiProviders.join(", ")} seed)`:""}${d.customAiEndpoint?" + custom endpoint":""}`],["Email",d.email],["Storage",d.storage],["Monitoring",d.monitoring],["Analytics",d.analytics],["SMS",d.sms],["Deploy Target",d.deployTarget],["Docs Framework",d.docs],["Access gate",d.accessGate]];o?_.forEach(([f,E],S)=>{Ye(!0,{event:"step",step:f,value:E,index:S+1,total:_.length})}):_.forEach(([f,E],S)=>{Mr({index:S+1,total:_.length,label:f,value:E})}),r&&(Kc(o,d,c,u,t),process.exit(0));let h=async()=>{process.stdout.write(`
2916
+ `+F.red(`\u2718 Cancelled
2917
+ `)),Vr.existsSync(c)&&await ot.confirm({message:`Cleanup partial install at ${c}?`,initialValue:!0})===!0&&(Vr.rmSync(c,{recursive:!0,force:!0}),process.stdout.write(F.dim(` \u2713 Removed ${c}
2918
+ `))),process.exit(130)};process.on("SIGINT",h);try{await Nr({resolvedTarget:c,projectName:p,resolvedPm:u,opts:t,useJson:o,resolved:d,startedAt:Date.now()}),process.exit(0)}catch(f){let E=f instanceof Error?f.message:String(f);o?Ye(!0,{event:"error",message:E}):process.stdout.write(F.red(`
2919
+ \u2718 Failed: ${E}
2920
+ `)),process.exit(1)}}$c().catch(e=>{process.stderr.write(String(e)+`
2983
2921
  `),process.exit(1)});