PageSourceSearch

https://devcodex-labs.github.io/vextjs/static/js/async/route-2781b4deec6f.8e81953e91.js

js devcodex-labs.github.io collected 2026-10-03 08:59:22 UTC 170,433 bytes, 1 lines download raw bytes

1"use strict";(self.rspackChunkvext_website=self.rspackChunkvext_website||[]).push([[2577],{8725(s,n,e){e.r(n);var r=e(4848),i=e(8453);function o(s){let n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...s.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(n.h1,{id:"服务层",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#服务层",children:"#"}),"服务层"]}),"\n",(0,r.jsxs)(n.p,{children:["VextJS 采用 ",(0,r.jsx)(n.strong,{children:"分层架构"}),",将业务逻辑集中在服务层(Service Layer)。服务文件放在 ",(0,r.jsx)(n.code,{children:"src/services/"})," 目录下,由框架自动扫描、实例化并注入到 ",(0,r.jsx)(n.code,{children:"app.services"}),",路由 handler 中通过 ",(0,r.jsx)(n.code,{children:"app.services.xxx"})," 访问。"]}),"\n",(0,r.jsxs)(n.h2,{id:"设计理念",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#设计理念",children:"#"}),"设计理念"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"txt",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"路由层 (routes)    ← 参数提取 + 响应返回(薄层)"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"   ↓"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"服务层 (services)  ← 业务逻辑(核心)"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"   ↓"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"数据层 (models)    ← 数据访问(通过插件提供)"})})]})})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"路由 handler"})," 只负责从请求中提取参数、调用 service、返回响应"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"服务层"})," 承载所有业务逻辑,不感知 HTTP 协议(不访问 ",(0,r.jsx)(n.code,{children:"req"})," / ",(0,r.jsx)(n.code,{children:"res"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"数据层"})," 由插件提供(如数据库 ORM),通过 ",(0,r.jsx)(n.code,{children:"app"})," 对象访问"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"这种分层使得:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"业务逻辑可以在不同路由间复用"}),"\n",(0,r.jsx)(n.li,{children:"服务层可以独立进行单元测试(不依赖 HTTP)"}),"\n",(0,r.jsx)(n.li,{children:"切换底层 Adapter 不影响业务代码"}),"\n"]}),"\n",(0,r.jsxs)(n.h2,{id:"基本写法",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#基本写法",children:"#"}),"基本写法"]}),"\n",(0,r.jsxs)(n.h3,{id:"服务类",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#服务类",children:"#"}),"服务类"]}),"\n",(0,r.jsxs)(n.p,{children:["每个服务文件导出一个 ",(0,r.jsx)(n.strong,{children:"class"}),",构造函数接收 ",(0,r.jsx)(n.code,{children:"app"})," 参数:"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// src/services/user.ts"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" type"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { VextApp } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "vextjs"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" class"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" UserService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  constructor"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".app "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app;"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" findAll"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(options"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"?:"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { page"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"?:"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"; limit"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"?:"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" }) {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"page"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" 1"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" limit"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" 20"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" options "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"??"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {};"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 业务逻辑..."})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      items"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" []"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      total"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" 0"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      page"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      limit"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    };"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" findById"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 业务逻辑..."})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" name"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "Alice"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" email"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "[email protected]"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" };"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" user;"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" create"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(data"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { name"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"; email"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" }) {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"logger"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".info"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"({ data }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "Creating user"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 业务逻辑..."})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" crypto"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".randomUUID"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"}
1,children:"()"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ..."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"data };"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" update"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" data"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" Partial"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"<{ name"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"; email"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" }>) {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"logger"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".info"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"({ id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" data }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "Updating user"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ..."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"data };"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" delete"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"logger"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".info"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"({ id }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "Deleting user"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsxs)(n.h3,{id:"在路由中使用",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#在路由中使用",children:"#"}),"在路由中使用"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// src/routes/users.ts"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { defineRoutes } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "vextjs"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" defineRoutes"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"((app) "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"  app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".get"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'"/"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" (_req"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" res) "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 通过 app.services 访问已注入的服务实例"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" users"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"services"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".findAll"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"}
1,children:"();"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    res"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".json"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(users);"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  });"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"  app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".get"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'    "/:id"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    {"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      validate"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { param"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "string!"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" } }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" (req"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" res) "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"      const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" req"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".valid"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'"param"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"      const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"services"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".findById"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(id);"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"      if"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" ("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"!"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"user) "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".throw"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"404"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "user.not_found"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"      res"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".json"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(user);"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  );"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"  app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".post"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'    "/"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    {"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      validate"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"        body"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { name"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "string:1-50!"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" email"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "email!"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      middlewares"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" ["}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'"auth"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"]"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      auth"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { required"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" true"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" security"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "bearerAuth"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" (req"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" res) "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"      const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" data"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" req"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".valid"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'"body"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"      const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"services"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".create"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(data);"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"      res"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".json"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" 201"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  );"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"});"})})]})})}),"\n",(0,r.jsxs)(n.h2,{id:"文件命名与映射",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#文件命名与映射",children:"#"}),"文件命名与映射"]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"service-loader"})," 按文件路径自动将服务实例挂载到 ",(0,r.jsx)(n.code,{children:"app.services"})," 的对应属性上。"]}),"\n",(0,r.jsxs)(n.h3,{id:"映射规则",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#映射规则",children:"#"}),"映射规则"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"文件路径"}),(0,r.jsx)(n.th,{children:"访问方式"}),(0,r.jsx)(n.th,{children:"说明"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"services/user.ts"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"app.services.user"})}),(0,r.jsx)(n.td,{children:"扁平命名"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"services/order.ts"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"app.services.order"})}),(0,r.jsx)(n.td,{children:"扁平命名"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"services/user-profile.ts"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"app.services.userProfile"})}),(0,r.jsx)(n.td,{children:"kebab-case → camelCase"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"services/payment/stripe.ts"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"app.services.payment.stripe"})}),(0,r.jsx)(n.td,{children:"嵌套命名空间"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"services/payment/alipay.ts"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"app.services.payment.alipay"})}),(0,r.jsx)(n.td,{children:"嵌套命名空间"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"services/admin/user-manage.ts"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"app.services.admin.userManage"})}),(0,r.jsx)(n.td,{children:"嵌套 + 驼峰转换"})]})]})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"转换
1规则:"})}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["文件路径相对于 ",(0,r.jsx)(n.code,{children:"services/"})," 目录,去除扩展名"]}),"\n",(0,r.jsxs)(n.li,{children:["文件名自动从 ",(0,r.jsx)(n.code,{children:"kebab-case"})," 转换为 ",(0,r.jsx)(n.code,{children:"camelCase"})]}),"\n",(0,r.jsx)(n.li,{children:"子目录映射为嵌套对象"}),"\n"]}),"\n",(0,r.jsxs)(n.h3,{id:"嵌套服务示例",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#嵌套服务示例",children:"#"}),"嵌套服务示例"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"txt",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"src/services/"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"├── user.ts                    → app.services.user"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"├── order.ts                   → app.services.order"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"└── payment/"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"    ├── stripe.ts              → app.services.payment.stripe"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"    └── wechat-pay.ts          → app.services.payment.wechatPay"})})]})})}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// src/services/payment/stripe.ts"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" type"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { VextApp } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "vextjs"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" class"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" StripeService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  constructor"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".app "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app;"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" createPayment"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(amount"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" currency"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"logger"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".info"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"({ amount"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" currency }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "Creating Stripe payment"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // Stripe API 调用..."})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { paymentId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "pi_xxx"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" status"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "pending"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" };"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" refund"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(paymentId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"logger"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".info"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"({ paymentId }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "Refunding Stripe payment"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { refundId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "re_xxx"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" status"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "refunded"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" };"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// 在路由中使用嵌套服务"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".post"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'"/pay"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" (req"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" res) "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" result"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"services"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"payment"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"stripe"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".createPayment"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"100"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "usd"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"  res"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".json"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(result);"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"});"})})]})})}),"\n",(0,r.jsxs)(n.h2,{id:"service-hooks",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#service-hooks",children:"#"}),"Service Hooks"]}),"\n",(0,r.jsxs)(n.p,{children:["Vext 会为加载到 ",(0,r.jsx)(n.code,{children:"app.services"})," 的实例方法安装轻量 wrapper。当没有注册 service hook 时,调用会直接走原方法;注册 hook 后,可观察调用前后和错误:"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// src/plugins/service-observer.ts"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { definePlugin } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "vextjs"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" definePlugin"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"({"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  name"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "service-observer"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"  setup"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(app) {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"hooks"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".on"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'"service:beforeCall"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" ({ service"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" method 
1}) "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"      app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"logger"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".debug"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"({ service"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" method }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "service call start"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    });"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"hooks"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".on"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'"service:error"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" ({ service"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" method"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" error }) "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"      app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"logger"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".error"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"({ service"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" method"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" err"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" error }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "service call failed"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    });"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"});"})})]})})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"service:beforeCall"}),"、",(0,r.jsx)(n.code,{children:"service:afterCall"})," 和 ",(0,r.jsx)(n.code,{children:"service:error"})," 都是同步 hook。不要在这些 handler 中返回 Promise;如需异步上报,建议放入队列或使用不阻塞主调用的日志传输。"]}),"\n",(0,r.jsxs)(n.h2,{id:"服务间调用",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#服务间调用",children:"#"}),"服务间调用"]}),"\n",(0,r.jsxs)(n.p,{children:["服务之间可以相互调用。推荐通过 ",(0,r.jsx)(n.code,{children:"this.app.services"})," 在",(0,r.jsx)(n.strong,{children:"方法中"}),"按需访问(延迟访问),而非在构造函数中直接引用:"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// src/services/order.ts"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" type"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { VextApp } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "vextjs"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" class"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" OrderService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  constructor"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".app "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app;"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" createOrder"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    userId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    items"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" Array"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"<{ productId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"; quantity"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" }>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  ) {"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 调用其他 service — 通过 this.app.services 延迟访问"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"services"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".findById"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(userId);"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    if"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" ("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"!"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"user) {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"      this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".throw"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"404"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "user.not_found"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 计算价格"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" total"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".calculateTotal"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(items);"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 调用支付服务"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" payment"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"services"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"payment"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"stripe"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".createPayment"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      total"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'      "usd"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    );"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      orderId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" crypto"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".randomUUID"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"}
1,children:"()"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      userId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      items"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      total"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      paymentId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" payment"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".paymentId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      status"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "created"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    };"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" calculateTotal"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    items"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" Array"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"<{ productId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"; quantity"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" }>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  ) {"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 业务逻辑..."})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" items"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".reduce"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"((sum"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" item) "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" sum "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"+"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" item"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".quantity "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"*"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" 10"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" 0"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsxs)(n.p,{children:["::::warning 避免循环依赖\n",(0,r.jsx)(n.code,{children:"service-loader"})," 内置循环依赖检测。如果 ",(0,r.jsx)(n.code,{children:"ServiceA"})," 和 ",(0,r.jsx)(n.code,{children:"ServiceB"})," 相互依赖,框架会在启动时报错。"]}
1),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"✅ 正确做法"})," — 在方法中延迟访问:"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" class"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" OrderService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  constructor"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {}"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" createOrder"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"() {"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // ✅ 方法调用时 user service 已经初始化完成"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"services"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".findById"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'"123"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"❌ 错误做法"})," — 在构造函数中直接引用:"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" class"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" OrderService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" userService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" UserService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  constructor"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // ❌ 构造函数执行时 user service 可能尚未初始化"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".userService "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"services"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".user;"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsx)(n.p,{children:"::::"}),"\n",(0,r.jsxs)(n.h2,{id:"使用插件提供的能力",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#使用插件提供的能力",children:"#"}),"使用插件提供的能力"]}),"\n",(0,r.jsxs)(n.p,{children:["插件通过 ",(0,r.jsx)(n.code,{children:"app.extend()"})," 注入的能力,在服务中通过 ",(0,r.jsx)(n.code,{children:"this.app"})," 访问:"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// 假设 redis 插件已通过 app.extend('redis', redis) 注入"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// src/services/user.ts"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" type"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { VextApp } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "vextjs"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" class"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" UserService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  constructor"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".app "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app;"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" findById"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 先查缓存"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" cached"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" ("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".app "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"as"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" any"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:")."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"redis"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".get"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:"`user:"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"${"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"}"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:"`"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    if"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" (cached) "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" cached;"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 缓存未命中,查数据库"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".queryDatabase"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(id);"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 写入缓存"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    if"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" (user) {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"      await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" ("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".app "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"as"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" any"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:")."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"redis"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".set"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:"`user:"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"${"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"}"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:"`"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" JSON"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".stringify"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(user));"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" user;"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"}
1,children:" queryDatabase"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 数据库查询逻辑..."})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" name"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "Alice"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" };"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsxs)(n.p,{children:["::::tip 类型提示\n使用 ",(0,r.jsx)(n.code,{children:"declare module"})," 扩展 ",(0,r.jsx)(n.code,{children:"VextApp"})," 接口可获得完整的类型提示:"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// src/types/extensions.d.ts"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"declare"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" module"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "vextjs"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  interface"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    redis"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"      get"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(key"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:")"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" Promise"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"<"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" |"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" null"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:">;"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"      set"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(key"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" value"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" ttl"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"?:"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:")"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" Promise"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"<"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"void"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:">;"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    };"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsxs)(n.p,{children:["扩展后 ",(0,r.jsx)(n.code,{children:"this.app.redis"}
1)," 即可获得 IDE 自动补全。\n::::"]}),"\n",(0,r.jsxs)(n.h2,{id:"使用-appthrow-抛出错误",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#使用-appthrow-抛出错误",children:"#"}),"使用 ",(0,r.jsx)(n.code,{children:"app.throw()"})," 抛出错误"]}),"\n",(0,r.jsxs)(n.p,{children:["服务层中可以通过 ",(0,r.jsx)(n.code,{children:"this.app.throw()"})," 抛出 HTTP 错误。框架会自动捕获并转化为统一的错误响应,无需在路由层手动 try-catch:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["需要主动返回 ",(0,r.jsx)(n.code,{children:"404"}),"、",(0,r.jsx)(n.code,{children:"409"}),"、",(0,r.jsx)(n.code,{children:"401"})," 等明确 HTTP 语义时,使用 ",(0,r.jsx)(n.code,{children:"this.app.throw(...)"})]}),"\n",(0,r.jsxs)(n.li,{children:["需要返回字段级校验详情时,抛出 ",(0,r.jsx)(n.code,{children:"VextValidationError"})]}),"\n",(0,r.jsxs)(n.li,{children:["发生未预期异常时,可以直接 ",(0,r.jsx)(n.code,{children:'throw new Error("...")'}),",框架会统一转成 500"]}),"\n"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" class"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" UserService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  constructor"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {}"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" findById"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".queryDatabase"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(id);"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    if"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" ("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"!"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"user) {"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"      // 直接在 service 中抛出,框架统一处理"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"      this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".throw"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"404"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "user.not_found"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    }"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" user;"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" create"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(data"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { name"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"; email"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" }) {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" existing"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".findByEmail"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"data"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".email);"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    if"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" (existing) {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"      this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".throw"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"409"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "邮箱已注册"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" 10001"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 创建逻辑..."})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" crypto"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".randomUUID"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"}
1,children:"()"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ..."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"data };"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" queryDatabase"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" null"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"; "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// 模拟"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" findByEmail"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(email"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" null"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"; "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// 模拟"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsxs)(n.p,{children:["如果 service 内部直接 ",(0,r.jsx)(n.code,{children:'throw new Error("...")'}),",框架也会捕获它;这条路径表示未知运行时异常,而不是主动设计好的 HTTP 错误响应。默认情况下客户端会收到安全的 ",(0,r.jsx)(n.code,{children:"500 Internal Server Error"}),",开发环境下可通过 ",(0,r.jsx)(n.code,{children:"response.hideInternalErrors = false"})," 额外暴露 ",(0,r.jsx)(n.code,{children:"stack"})," 便于排查。"]}),"\n",(0,r.jsxs)(n.h2,{id:"在服务中校验非-http-输入",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#在服务中校验非-http-输入",children:"#"}),"在服务中校验非 HTTP 输入"]}),"\n",(0,r.jsxs)(n.p,{children:["路由入口参数优先通过 ",(0,r.jsx)(n.code,{children:"RouteOptions.validate"})," 声明,并在 handler 中使用 ",(0,r.jsx)(n.code,{children:"req.valid()"})," 读取校验后的数据。对于 service 直接处理的非 HTTP 输入,例如定时任务、消息队列、外部回调或其他 service 调用,可以通过 ",(0,r.jsx)(n.code,{children:"this.app.getValidator()"})," 复用当前全局校验引擎。"]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"getValidator()"})," 默认返回基于 schema-dsl 的 validator;如果插件通过 ",(0,r.jsx)(n.code,{children:"app.setValidator()"})," 替换为 Zod、Yup 等实现,service 中获取到的也是替换后的 validator。"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { VextValidationError"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" type"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" type"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" VextValidator } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "vextjs"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" createUserSchema"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  name"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "string:1-50!"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  email"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "email!"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"};"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" class"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" UserService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" validateCreateUser"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" ReturnType"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"<"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"VextValidator"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"["}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'"compile"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"]>;"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  constructor"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" validator"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".getValidator"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"}
1,children:"();"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".validateCreateUser "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" validator"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".compile"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(createUserSchema);"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" createFromJob"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(input"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" unknown"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" result"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".validateCreateUser"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(input);"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    if"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" ("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"!"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"result"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".valid) {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"      throw"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" new"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextValidationError"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"result"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".errors "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"??"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" []);"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" data"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" result"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".data "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"as"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { name"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"; email"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" };"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".create"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(data);"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" create"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(data"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { name"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"; email"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" }) {"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"    // 创建逻辑..."})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { id"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" crypto"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".randomUUID"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"}
1,children:"()"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ..."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"data };"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsx)(n.p,{children:"::::tip"}),"\n",(0,r.jsxs)(n.p,{children:["不要在 service 中直接 ",(0,r.jsx)(n.code,{children:'import "schema-dsl"'}),"。直接引用 schema-dsl 会绕过 ",(0,r.jsx)(n.code,{children:"app.setValidator()"})," 的全局替换能力,导致 service 校验与路由校验使用不同引擎。"]}),"\n",(0,r.jsx)(n.p,{children:"::::"}),"\n",(0,r.jsxs)(n.h2,{id:"使用-applogger-记录日志",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#使用-applogger-记录日志",children:"#"}),"使用 ",(0,r.jsx)(n.code,{children:"app.logger"})," 记录日志"]}),"\n",(0,r.jsxs)(n.p,{children:["服务层推荐通过 ",(0,r.jsx)(n.code,{children:"this.app.logger"})," 记录结构化日志。日志自动携带 requestId(通过 AsyncLocalStorage 上下文传播):"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" class"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" PaymentService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  constructor"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {}"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" processPayment"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(orderId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" amount"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"logger"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".info"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"({ orderId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" amount }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "Processing payment"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    try"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"      // 调用外部支付 API..."})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"      const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" result"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { transactionId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "txn_xxx"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" };"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"      this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"logger"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".info"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"        { orderId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" transactionId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" result"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".transactionId }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'        "Payment successful"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      );"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"      return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" result;"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"catch"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" (err) {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"      this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"logger"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".error"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"({ orderId"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" err }"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "Payment failed"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"      this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".throw"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"500"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "payment.failed"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:");"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsxs)(n.h2,{id:"加载顺序与生命周期",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#加载顺序与生命周期",children:"#"}),"加载顺序与生命周期"]}),"\n",(0,r.jsxs)(n.h3,{id:"加载时机",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#加载时机",children:"#"}),"加载时机"]}),"\n",(0,r.jsxs)(n.p,{children:["在 ",(0,r.jsx)(n.code,{children:"bootstrap"})," 启动流程中,",(0,r.jsx)(n.code,{children:"service-loader"})," 在以下阶段执行:"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"txt",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"1. config    → 加载配置"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"2. locales   → 加载语言包"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"3. plugins   → 执行插件 setup()"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"4. middlewares → 扫描中间件"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"5. services  → ⭐ 实例化服务(此处)"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"6. routes    → 注册路由(handler 中可安全访问 app.services)"})})]})})}),"\n",(0,r.jsx)(n.p,{children:"这意味着:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["✅ 服务构造函数中可以访问 ",(0,r.jsx)(n.code,{children:"app.config"}),"(已加载)"]}),"\n",(0,r.jsxs)(n.li,{children:["✅ 服务构造函数中可以访问 ",(0,r.jsx)(n.code,{children:"app.logger"}),"(已初始化)"]}),"\n",(0,r.jsx)(n.li,{children:"✅ 服务构造函数中可以访问插件注入的能力(插件已 setup)"}),"\n",(0,r.jsxs)(n.li,{children:["⚠️ 服务构造函数中访问 ",(0,r.jsx)(n.code,{children:"app.services"})," 需注意顺序(见循环依赖章节)"]}),"\n",(0,r.jsxs)(n.li,{children:["✅ 路由 handler 中可以安全访问所有 ",(0,r.jsx)(n.code,{children:"app.services"}),"(已全部注入完成)"]}),"\n"]}),"\n",(0,r.jsxs)(n.h3,{id:"实例化过程",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#实例化过程",children:"#"}),"实例化过程"]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"扫描"})," — 递归扫描 ",(0,r.jsx)(n.code,{children:"src/services/"})," 目录下所有 ",(0,r.jsx)(n.code,{children:".ts"})," / ",(0,r.jsx)(n.code,{children:".js"})," 文件"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"排序"})," — 按文件路径字母序排序(确保加载顺序确定性)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"实例化"})," — 逐个 ",(0,r.jsx)(n.code,{children:"new ServiceClass(app)"})," 创建实例"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"挂载"})," — 将实例挂载到 ",(0,r.jsx)(n.code,{children:"app.services"})," 的对应属性"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"检测"})," — 执行循环依赖检测(可选,默认开启)"]}),"\n"]}),"\n",(0,r.jsxs)(n.h3,{id:"排除规则",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#排除规则",children:"#"}),"排除规则"]}),"\n",(0,r.jsx)(n.p,{children:"以下文件会被自动跳过:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["测试文件:",(0,r.jsx)(n.code,{children:"*.test.ts"}),"、",(0,r.jsx)(n.code,{children:"*.spec.ts"})]}),"\n",(0,r.jsxs)(n.li,{children:["以 ",(0,r.jsx)(n.code,{children:"_"})," 或 ",(0,r.jsx)(n.code,{children:"."})," 开头的文件/目录"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"node_modules"})," 目录"]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["可以利用 ",(0,r.jsx)(n.code,{children:"_"})," 前缀创建服务共享的工具模块:"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"txt",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"src/services/"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"├── _base.ts          # 基类,不会被当作服务加载"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"├── _types.ts         # 共享类型"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"├── user.ts"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"└── order.ts"})})]})})}),"\n",(0,r.jsxs)(n.h2,{id:"服务层最佳实践",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#服务层最佳实践",children:"#"}),"服务层最佳实践"]}),"\n",(0,r.jsxs)(n.h3,{id:"1-保持服务层的-http-无关性",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#1-保持服务层的-http-无关性",children:"#"}),"1. 保持服务层的 HTTP 无关性"]}),"\n",(0,r.jsxs)(n.p,{children:["服务层不应直接操作 ",(0,r.jsx)(n.code,{children:"req"})," / ",(0,r.jsx)(n.code,{children:"res"}
1)," 对象。如果需要请求上下文信息(如当前用户),作为参数传入:"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// ✅ 正确 — 参数传入"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"async "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"createOrder"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(userId: string"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" items: OrderItem[]) {"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"  // ..."})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// ❌ 错误 — 直接操作请求对象"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"async "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"createOrder"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(req: VextRequest"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" res: VextResponse) {"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"  // service 不应感知 HTTP"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsxs)(n.h3,{id:"2-单一职责",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#2-单一职责",children:"#"}),"2. 单一职责"]}),"\n",(0,r.jsx)(n.p,{children:"每个服务对应一个业务领域。避免将不同领域的逻辑放在同一个服务中:"}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"txt",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"services/"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"├── user.ts           # 用户管理"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"├── order.ts          # 订单管理"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"├── notification.ts   # 通知服务"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"└── payment/"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"    ├── stripe.ts     # Stripe 支付"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{children:"    └── wechat-pay.ts # 微信支付"})})]})})}),"\n",(0,r.jsxs)(n.h3,{id:"3-使用基类共享通用逻辑",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#3-使用基类共享通用逻辑",children:"#"}),"3. 使用基类共享通用逻辑"]}),"\n",(0,r.jsxs)(n.p,{children:["对于有共同行为的服务,可以创建基类(以 ",(0,r.jsx)(n.code,{children:"_"})," 前缀防止被当作服务加载):"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// src/services/_base.ts(不会被自动加载)"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" type"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { VextApp } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "vextjs"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" abstract"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" class"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" BaseService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  protected"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  constructor"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(app"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextApp"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"    this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:".app "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" app;"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  protected"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" paginate"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"<"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"T"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:">("})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"    queryFn"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" (offset"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" limit"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" Promise"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"<"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"T"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"[]>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"    countFn"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" () "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" Promise"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"<"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:">"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    page"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    limit"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  ) {"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" offset"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" ="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" (page "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"-"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" 1"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"*"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" limit;"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    const"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" ["}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:"items"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" total"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"] "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" await"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" Promise"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".all"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(["})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"      queryFn"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(offset"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" limit)"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"      countFn"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"}
1,children:"()"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    ]);"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { items"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" total"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" page"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" limit"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" pages"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" Math"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".ceil"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(total "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"/"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" limit) };"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// src/services/user.ts"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" { BaseService } "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "./_base.js"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"export"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" class"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" UserService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" extends"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" BaseService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" findAll"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(page "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" 1"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" limit "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"="}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" 20"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".paginate"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      (offset"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" limit) "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".queryUsers"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(offset"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" limit)"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      () "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"=>"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" this"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:".countUsers"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"}
1,children:"()"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      page"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      limit"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    );"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" queryUsers"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"(offset"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-punctuation)"},children:","}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" limit"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" number"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:") {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" []; "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// 数据库查询"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  private"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" async"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" countUsers"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"() {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"    return"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-constant)"},children:" 0"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"; "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// 计数查询"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsxs)(n.h3,{id:"4-typescript-类型声明",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#4-typescript-类型声明",children:"#"}),"4. TypeScript 类型声明"]}),"\n",(0,r.jsxs)(n.p,{children:["为 ",(0,r.jsx)(n.code,{children:"app.services"})," 添加类型声明,获得完整的 IDE 支持:"]}),"\n",(0,r.jsx)(n.p,{children:"推荐优先使用框架提供的生成命令:"}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"bash",children:(0,r.jsx)(n.code,{children:(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"vext"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string)"},children:" typegen"})]})})})}),"\n",(0,r.jsxs)(n.p,{children:["该命令会在 ",(0,r.jsx)(n.code,{children:".vext/types/services.generated.d.ts"})," 中自动生成 ",(0,r.jsx)(n.code,{children:"VextServices"})," 扩展声明,并通过 ",(0,r.jsx)(n.code,{children:"src/types/generated/index.d.ts"})," 接入 TypeScript 项目,同时执行一轮 tooling 层 service 依赖检查。"]}),"\n",(0,r.jsxs)(n.p,{children:["从 ",(0,r.jsx)(n.code,{children:"0.3.7"})," 起,",(0,r.jsx)(n.code,{children:"vext dev"})," 也会在 preflight 中自动执行这一步的基础版本,用于保证开发态的 generated 声明与当前 ",(0,r.jsx)(n.code,{children:"services"})," / ",(0,r.jsx)(n.code,{children:"plugins"})," 定义保持同步;如果你需要 ",(0,r.jsx)(n.code,{children:"--check"}),"、",(0,r.jsx)(n.code,{children:"--write-manifest"})," 或独立 CI 控制,仍应显式运行 ",(0,r.jsx)(n.code,{children:"vext typegen"}),"。"]}),"\n",(0,r.jsxs)(n.p,{children:["如果你还想把 service 索引、",(0,r.jsx)(n.code,{children:"app.extend()"})," 聚合结果与依赖图摘要提供给编辑器、CI 或其他工具链消费,可以额外执行:"]}),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"bash",children:(0,r.jsx)(n.code,{children:(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"vext"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string)"},children:" typegen"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string)"},children:" --write-manifest"})]})})})}),"\n",(0,r.jsxs)(n.p,{children:["对应产物会写入:",(0,r.jsx)(n.code,{children:".vext/manifest/services.json"}),"。"]}),"\n",(0,r.jsxs)(n.p,{children:["如果你需要手写或补充少量高级声明,仍可保留自定义 ",(0,r.jsx)(n.code,{children:".d.ts"})," 文件;generated 文件与手写文件是隔离的,不会互相覆盖。"]}
1),"\n",(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.pre,{className:"shiki css-variables",style:{backgroundColor:"var(--shiki-background)",color:"var(--shiki-foreground)"},tabIndex:"0",lang:"typescript",children:(0,r.jsxs)(n.code,{children:[(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-comment)"},children:"// src/types/services.d.ts"})}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" type"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" UserService "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "../services/user.js"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" type"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" OrderService "}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"from"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "../services/order.js"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line"}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"declare"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" module"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:' "vextjs"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:"  interface"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" VextServices"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    user"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" UserService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    order"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:" OrderService"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    payment"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:" {"})]}),"\n",(0,r.jsxs)(n.span,{className:"line",children:[(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"      stripe"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:":"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-keyword)"},children:" import"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"("}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-string-expression)"},children:'"../services/payment/stripe.js"'}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:")."}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-token-function)"},children:"default"}),(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:";"})]}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"    };"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"  }"})}),"\n",(0,r.jsx)(n.span,{className:"line",children:(0,r.jsx)(n.span,{style:{color:"var(--shiki-foreground)"},children:"}"})})]})})}),"\n",(0,r.jsxs)(n.p,{children:["添加后,",(0,r.jsx)(n.code,{children:"app.services.user.findById()"})," 等调用将获得完整的方法签名提示和类型检查。"]}),"\n",(0,r.jsxs)(n.h2,{id:"下一步",children:[(0,r.jsx)(n.a,{className:"rp-header-anchor","aria-hidden":"true",href:"#下一步",children:"#"}),"下一步"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["了解 ",(0,r.jsx)(n.a,{href:"/zh/guide/middleware.html",children:"中间件"})," 如何拦截和处理请求"]}),"\n",(0,r.jsxs)(n.li,{children:["学习 ",(0,r.jsx)(n.a,{href:"/zh/guide/plugins.html",children:"插件"})," 如何扩展框架能力"]}),"\n",(0,r.jsxs)(n.li,{children:["查看 ",(0,r.jsx)(n.a,{href:"/zh/guide/testing.html",children:"测试"})," 如何对服务层进行单元测试"]}),"\n"]})]})}function l(){let s=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},{wrapper:n}={...(0,i.R)(),...s.components};return n?(0,r.jsx)(n,{...s,children:(0,r.jsx)(o,{...s})}):o(s)}l.__RSPRESS_PAGE_META={},l.__RSPRESS_PAGE_META["zh%2Fguide%2Fservices.md"]={toc:[{id:"设计理念",text:"设计理念",depth:2},{id:"基本写法",text:"基本写法",depth:2},{id:"服务类",text:"服务类",depth:3},{id:"在路由中使用",text:"在路由中使用",depth:3},{id:"文件命名与映射",text:"文件命名与映射",depth:2},{id:"映射规则",text:"映射规则",depth:3},{id:"嵌套服务示例",text:"嵌套服务示例",depth:3},{id:"service-hooks",text:"Service Hooks",depth:2},{id:"服务间调用",text:"服务间调用",depth:2},{id:"使用插件提供的能力",text:"使用插件提供的能力",depth:2},{id:"使用-appthrow-抛出错误",text:"使用 `app.throw()` 抛出错误",depth:2},{id:"在服务中校验非-http-输入",text:"在服务中校验非 HTTP 输入",depth:2},{id:"使用-applogger-记录日志",text:"使用 `app.logger` 记录日志",depth:2},{id:"加载顺序与生命周期",text:"加载顺序与生命周期",depth:2},{id:"加载时机",text:"加载时机",depth:3},{id:"实例化过程",text:"实例化过程",depth:3},{id:"排除规则",text:"排除规则",depth:3},{id:"服务层最佳实践",text:"服务层最佳实践",depth:2},{id:"1-保持服务层的-http-无关性",text:"1. 保持服务层的 HTTP 无关性",depth:3},{id:"2-单一职责",text:"2. 单一职责",depth:3},{id:"3-使用基类共享通用逻辑",text:"3. 使用基类共享通用逻辑",depth:3},{id:"4-typescript-类型声明",text:"4. TypeScript 类型声明",depth:3},{id:"下一步",text:"下一步",depth:2}],title:"服务层",headingTitle:"服务层",frontmatter:{}},e.d(n,{default:()=>l})}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.