npm.io
0.3.40 • Published 3d ago

@wzyjs/middle-sdk

Licence
Version
0.3.40
Deps
2
Size
36 kB
Vulns
0
Weekly
0

@wzyjs/middle-sdk

Login

业务项目通过 @wzyjs/middle-sdk/login 接入中台登录。

创建 NextAuth 配置

import { createMiddleNextAuthOptions } from '@wzyjs/middle-sdk/login'

export const authOptions = createMiddleNextAuthOptions({
  cookiePrefix: 'my-app',
  clientId: process.env.MIDDLE_OIDC_CLIENT_ID!,
  clientSecret: process.env.MIDDLE_OIDC_CLIENT_SECRET!,
  issuer: process.env.MIDDLE_OIDC_ISSUER!,
  secret: process.env.NEXTAUTH_SECRET!,
  pages: {
    signIn: '/auth/signin',
    error: '/auth/error',
  },
})
配置参数
interface CreateMiddleNextAuthOptions {
  // 中台 OAuth client id。
  clientId: string
  // 中台 OAuth client secret。
  clientSecret: string
  // 中台站点地址,例如 https://middle.example.com。
  issuer: string
  // NextAuth secret。
  secret: string
  // Cookie 名称前缀,用来避免多个业务系统的 NextAuth cookie 冲突。
  cookiePrefix?: string
  // 是否开启 NextAuth debug 日志。
  debug?: boolean
  // NextAuth 登录页、错误页等页面配置。
  pages?: NextAuthOptions['pages']
  // 是否给 NextAuth cookie 添加 secure 标记。
  secureCookies?: boolean
}
Session 参数

登录成功后,业务项目可以从 session 里读取这些参数:

session.middleAccessToken
session.app
session.pages
session.permissions
session.roles
补充 Session 类型

NextAuth 默认的 Session 类型不知道 SDK 增加的中台字段。 业务项目如果要在 TypeScript 里安全访问 session.middleAccessTokensession.appsession.pages 等字段,需要补充一次类型声明。

import type { DefaultSession } from 'next-auth'
import type { MiddleNextAuthSessionFields } from '@wzyjs/middle-sdk/login'

declare module 'next-auth' {
  interface Session extends MiddleNextAuthSessionFields {
    user?: DefaultSession['user'] & {
      id?: string
    }
  }
}
手动刷新权限资料

业务项目需要重新读取中台应用、页面、角色、权限时,可以调用:

import { createMiddleAccessProfileRefreshUpdate } from '@wzyjs/middle-sdk/login'
import { useSession } from 'next-auth/react'

const { update } = useSession()

await update(createMiddleAccessProfileRefreshUpdate())

Page

业务项目通过 @wzyjs/middle-sdk/page 处理中台页面配置。

模块功能
  • session.pages 里的页面配置解析成菜单可直接使用的数据。
  • 自动区分站内路由、iframe 外链、新开窗口外链。
  • 提供中台 iframe 承载页组件。
解析菜单页面
import { resolveMiddleMenuPages } from '@wzyjs/middle-sdk/page'

const pathname = usePathname()

const menuItems = resolveMiddleMenuPages(session.pages, {
  // iframe 承载页自己的路由地址。
  // 当中台页面是外链但不走新开窗口时,SDK 会把它解析成 `/middle?url=...` 这种地址。
  iframePagePath: '/middle',
  // 当前页面 pathname,用来判断菜单是否处于激活状态。
  // 站内路由菜单会拿它和 page.path 对比。
  pathname,
  // 当前 iframe 承载页里实际打开的外链地址。
  // 当 pathname 是 `/middle` 时,SDK 会继续用这个值判断当前激活的是哪个 iframe 菜单。
  iframeUrl: searchParams.get('url'),
})

返回结果里的每一项都会带这些字段:

interface MiddleResolvedPage {
  href: string
  isActive: boolean
  isBlank: boolean
  isExternal: boolean
  isIframe: boolean
  isRoute: boolean
  page: MiddlePage
  rel?: 'noreferrer'
  target?: '_blank'
  type: 'route' | 'iframe' | 'blank'
}
挂载 iframe 页面
import { Suspense } from 'react'
import { MiddleIframeRoutePage } from '@wzyjs/middle-sdk/page'

export default function MiddlePage() {
  return (
    <Suspense>
      <MiddleIframeRoutePage />
    </Suspense>
  )
}

默认会从当前地址的 url query 参数读取 iframe 地址,例如 /middle?url=https://example.com

类型
interface MiddlePage {
  icon: string | null
  isMenu: boolean
  name: string
  openMode: 'iframe' | 'blank' | null
  path: string
  permissions: string[]
}

Proxy

业务项目通过 @wzyjs/middle-sdk/proxy 生成中台代理地址。

生成代理地址
import { createMiddleProxyUrlFactory } from '@wzyjs/middle-sdk/proxy'

const createAppProxyUrl = createMiddleProxyUrlFactory({
  appid: 'ertyuertyu',
  baseUrl: 'https://middle.example.com',
})

const proxyUrl = createAppProxyUrl('https://example.com/path?a=1')

// https://middle.example.com/api/proxy/my-app?url=https%3A%2F%2Fexample.com%2Fpath%3Fa%3D1
参数
interface CreateMiddleProxyUrlParams {
  url: string
  appid: string
  baseUrl: string
}

interface CreateMiddleProxyUrlFactoryParams {
  appid: string
  baseUrl: string
}
规则
  • 只会代理 httphttps 地址。
  • 已经是 /api/proxy/... 的地址会原样返回,不会重复包装。
  • appid 为空时会直接抛错。
  • baseUrl 为空时会直接抛错。
  • 返回值始终是带中台域名的完整代理地址。

业务项目通过 @wzyjs/middle-sdk/search 调用中台搜索能力。

import { createMiddleSearchFactory } from '@wzyjs/middle-sdk/search'

const searchMiddle = createMiddleSearchFactory({
  baseUrl: 'https://middle.example.com',
  accessToken: async () => session.middleAccessToken!,
})

const results = await searchMiddle({
  query: 'OpenAI 最新动态',
  source: 'serper',
})

source 支持 serperminimaxgooglesearxngzhihuweibobaidu,不传时默认使用 serper。搜索接口需要中台登录态。

Upload

业务项目通过 @wzyjs/middle-sdk/upload 上传文件到中台。

JS 上传二进制文件
import { createMiddleUploadFileFactory } from '@wzyjs/middle-sdk/upload'

const uploadMiddleFile = createMiddleUploadFileFactory({
  baseUrl: 'https://middle.example.com',
  accessToken: 'your-access-token',
})

const result = await uploadMiddleFile({
  file: fileInput.files![0],
  fileName: 'avatar.png',
  mimeType: 'image/png',
  business: 'avatar',
})
JS 上传 URL 文件源
import { createMiddleUploadFileFactory } from '@wzyjs/middle-sdk/upload'

const uploadMiddleFile = createMiddleUploadFileFactory({
  baseUrl: 'https://middle.example.com',
  accessToken: async () => session.middleAccessToken!,
})

const result = await uploadMiddleFile({
  type: 'url',
  file: 'https://example.com/image.png',
  business: 'avatar',
})
给上传组件使用
import { createMiddleUploadPropsFactory } from '@wzyjs/middle-sdk/upload'

const createUploadProps = createMiddleUploadPropsFactory({
  baseUrl: 'https://middle.example.com',
  accessToken: session.middleAccessToken,
})

<FileUploader
  immediateUpload
  trigger='button'
  showUploadList={false}
  {...createUploadProps({ business: 'file' })}
/>
参数
interface CreateMiddleUploadFileFactoryParams {
  baseUrl: string
  accessToken: string | (() => Promise<string> | string)
}

interface CreateMiddleUploadPropsFactoryParams {
  baseUrl: string
  accessToken?: string | null
}

interface CreateMiddleUploadPropsParams {
  business?: string
}

type MiddleUploadFileInput =
  | {
      type?: 'file'
      file: Blob | ArrayBuffer | Uint8Array
      business?: string
      fileName?: string
      mimeType?: string
    }
  | {
      type: 'url'
      file: string
      business?: string
      fileName?: string
      mimeType?: string
    }
返回值
interface MiddleUploadedFile {
  id: string
  name: string
  mimeType: string
  ext: string
  size: number
  hash: string
  objectKey: string
  provider: string
  status: string
  business: string | null
  applicationId: string
  creatorId: string
  url: string
  createdAt: string | Date
  updatedAt: string | Date
  isDeleted: boolean
}