{"version":3,"file":"index.mjs","sources":["../src/config.ts","../src/shared/hash.ts","../src/shared/util.ts","../src/error.ts","../src/http/assert.ts","../src/http/simple.ts","../src/auth/session.ts","../src/resource.ts","../src/resources/card/instances.ts","../src/resources/card/card.ts","../src/resources/downloader.ts","../src/resources/uploader.ts","../src/robots/interfaces/outgoing.ts","../src/robots/interfaces/incoming.ts","../src/robots/webhooks/customize.ts","../src/robots/webhooks/session.ts","../src/robots/message/sayable.ts","../src/robots/message/robot.ts","../src/robots/message/room.ts","../src/robots/message/talker.ts","../src/robots/message/message.ts","../src/stream/subscription.ts","../src/stream/client.ts","../src/index.ts"],"sourcesContent":["export const CLIENT_ID = process.env.DINGTALK_CLIENT_ID;\n\nexport const SECRET_KEY = process.env.DINGTALK_SECRET_KEY;\n\n/**\n * API 网关地址\n */\nexport const API_GATEWAY_URL = 'https://api.dingtalk.com/v1.0';\n\n/**\n * 企业内部应用网关地址\n */\nexport const OPEN_API_GATEWAY_URL = 'https://oapi.dingtalk.com/v1.0';\n\n/**\n * 配置\n */\nexport type Configuration = {\n  /**\n   * 应用的唯一标识\n   */\n  clientId?: string | undefined;\n\n  /**\n   * 应用的密钥\n   */\n  clientSecret?: string | undefined;\n\n  // 允许动态属性\n  [key: string]: any;\n};\n\nexport const defaultConfig: Configuration = {\n  clientId: CLIENT_ID,\n  clientSecret: SECRET_KEY,\n};\n","import {\n  type BinaryLike,\n  type BinaryToTextEncoding,\n  createHmac,\n  type KeyObject,\n} from 'node:crypto';\n\nexport function sha256(\n  data: BinaryLike,\n  key: BinaryLike | KeyObject,\n  encoding: BinaryToTextEncoding = 'base64',\n) {\n  return createHmac('sha256', key).update(data).digest(encoding);\n}\n","import { createHmac } from 'node:crypto';\n\nexport const castToError = (err: any): Error => {\n  if (err instanceof Error) return err;\n  return new Error(err);\n};\n\nexport const safeJSON = (text: string) => {\n  try {\n    return JSON.parse(text);\n  } catch (err) {\n    return undefined;\n  }\n};\n\nexport function md5(str: string): string {\n  return createHmac('md5', str).digest('hex');\n}\n","import { castToError } from './shared';\n\nexport class DingtalkError extends Error {}\n\nexport class InvalidArgumentError extends DingtalkError {}\n\nexport class InvalidResultError extends DingtalkError {}\n\nexport class APIError extends DingtalkError {\n  readonly status: number | undefined;\n  readonly headers: Headers | undefined;\n  readonly error: NonNullable<unknown> | undefined;\n\n  readonly code: string | null | undefined;\n\n  constructor(\n    status: number | undefined,\n    error: NonNullable<unknown> | undefined,\n    message: string | undefined,\n    headers: Headers | undefined,\n  ) {\n    super(`${APIError.makeMessage(status, error, message)}`);\n    this.status = status;\n    this.headers = headers;\n\n    const data = error as Record<string, any>;\n    this.error = data;\n    this.code = data?.['code'];\n  }\n\n  private static makeMessage(\n    status: number | undefined,\n    error: any,\n    message: string | undefined,\n  ) {\n    const msg = error?.message\n      ? typeof error.message === 'string'\n        ? error.message\n        : JSON.stringify(error.message)\n      : error\n        ? JSON.stringify(error)\n        : message;\n\n    if (status && msg) {\n      return `${status} ${msg}`;\n    }\n    if (status) {\n      return `${status} status code (no body)`;\n    }\n    if (msg) {\n      return msg;\n    }\n    return '(no status code or body)';\n  }\n\n  static generate(\n    status: number | undefined,\n    errorResponse: NonNullable<unknown> | undefined,\n    message?: string | undefined,\n    headers?: Headers | undefined,\n  ) {\n    if (!status) {\n      return new APIConnectionError({ cause: castToError(errorResponse) });\n    }\n\n    const error =\n      (errorResponse as Record<string, any>)?.['errmsg'] || errorResponse;\n\n    if (status === 400) {\n      return new BadRequestError(status, error, message, headers);\n    }\n\n    if (status === 401) {\n      return new AuthenticationError(status, error, message, headers);\n    }\n\n    if (status === 403) {\n      return new PermissionDeniedError(status, error, message, headers);\n    }\n\n    if (status === 404) {\n      return new NotFoundError(status, error, message, headers);\n    }\n\n    if (status === 409) {\n      return new ConflictError(status, error, message, headers);\n    }\n\n    if (status === 422) {\n      return new UnprocessableEntityError(status, error, message, headers);\n    }\n\n    if (status >= 500) {\n      return new InternalServerError(status, error, message, headers);\n    }\n\n    return new APIError(status, error, message, headers);\n  }\n}\n\nexport class APIUserAbortError extends APIError {\n  override readonly status: undefined = undefined;\n\n  constructor({ message }: { message?: string } = {}) {\n    super(undefined, undefined, message || 'Request was aborted.', undefined);\n  }\n}\n\nexport class APIConnectionError extends APIError {\n  override readonly status: undefined = undefined;\n\n  constructor({\n    message,\n    cause,\n  }: {\n    message?: string;\n    cause?: Error | undefined;\n  }) {\n    super(undefined, undefined, message || 'Connection error.', undefined);\n    // in some environments the \"cause\" property is already declared\n\n    if (cause) this.cause = cause;\n  }\n}\n\nexport class APIConnectionTimeoutError extends APIConnectionError {\n  constructor({ message }: { message?: string } = {}) {\n    super({ message: message ?? 'Request timed out.' });\n  }\n}\n\nexport class BadRequestError extends APIError {\n  override readonly status = 400;\n}\n\nexport class AuthenticationError extends APIError {\n  override readonly status = 401;\n}\n\nexport class PermissionDeniedError extends APIError {\n  override readonly status = 403;\n}\n\nexport class NotFoundError extends APIError {\n  override readonly status = 404;\n}\n\nexport class ConflictError extends APIError {\n  override readonly status = 409;\n}\n\nexport class UnprocessableEntityError extends APIError {\n  override readonly status = 422;\n}\n\nexport class InternalServerError extends APIError {}\n","import { APIError, InvalidResultError } from '../error';\nimport { castToError, safeJSON } from '../shared';\n\nexport type DingtalkResult = Record<string, any>;\n\nexport async function assertJsonFromResponse(\n  responseInit: Response | Promise<Response>,\n): Promise<void> {\n  const response = await responseInit;\n\n  await assertResponse(response);\n  assertResultSync(await response.json());\n}\n\nexport function assertResultSync(result: DingtalkResult): void {\n  if (typeof result.errcode === 'undefined' || result.errcode === 0) return;\n\n  throw new InvalidResultError(result.errmsg);\n}\n\nexport async function assertResponse(response: Response): Promise<void> {\n  if (response.ok) return;\n\n  const errText = await response.text().catch(e => castToError(e).message);\n  const errJSON = safeJSON(errText);\n  const errMessage = errJSON ? undefined : errText;\n\n  throw APIError.generate(\n    response.status,\n    errJSON,\n    errMessage,\n    response.headers as unknown as globalThis.Headers,\n  );\n}\n","import {\n  assertResponse,\n  assertResultSync,\n  type DingtalkResult,\n} from './assert';\n\nexport type SimpleRequestInit = {\n  method: string;\n  headers: Record<string, string>;\n  body?: RequestInit['body'];\n  signal?: AbortSignal;\n};\n\nexport function simple_post_json<R = DingtalkResult>(\n  input: RequestInfo | URL,\n  body?: RequestInit['body'] | undefined,\n  init?: Omit<SimpleRequestInit, 'method' | 'body'>,\n): Promise<R> {\n  const request = new Request(input, {\n    method: 'POST',\n    headers: {\n      Accept: 'application/json',\n      'Content-Type': 'application/json',\n    },\n    body: body,\n  });\n\n  return simple_json(request, init);\n}\n\nexport async function simple_json<R = DingtalkResult>(\n  input: RequestInfo | URL,\n  init?: RequestInit | undefined,\n): Promise<R> {\n  const response = await fetch(input, init);\n\n  await assertResponse(response);\n\n  const result = await response.json();\n\n  assertResultSync(result);\n\n  return result;\n}\n","import { OPEN_API_GATEWAY_URL } from '../config';\nimport { assertResponse, assertResultSync } from '../http';\nimport { type Credentials } from './credentials';\n\ntype TokenResponse = {\n  errcode: number;\n  errmsg: string;\n  access_token: string;\n  expires_in: number; // 7200s\n};\n\n/**\n * 获取企业内部应用的身份凭证\n *\n * @see https://open.dingtalk.com/document/orgapp/obtain-the-access_token-of-an-internal-app\n */\nexport class SessionCredentials {\n  #cache?: TokenResponse;\n  #expiredAt?: number;\n  #promise?: Promise<TokenResponse>;\n\n  constructor(protected credentials: Credentials) {}\n\n  getAccessToken(): Promise<string> {\n    return this.process().then(res => res.access_token);\n  }\n\n  protected process() {\n    const promise = this.#promise;\n    if (promise) return promise;\n\n    if (this.#cache && this.#expiredAt && this.#expiredAt > Date.now()) {\n      return Promise.resolve(this.#cache);\n    }\n\n    this.#promise = this.request().then(res => {\n      this.#cache = res;\n      this.#expiredAt = Date.now() + (res.expires_in - 120) * 1000;\n      return res;\n    });\n\n    this.#promise.finally(() => {\n      this.#promise = undefined;\n    });\n\n    return this.#promise;\n  }\n\n  protected async request(): Promise<TokenResponse> {\n    const { clientId, clientSecret } = this.credentials;\n\n    // cSpell: ignore appkey appsecret gettoken\n    const url = new URL('/gettoken', OPEN_API_GATEWAY_URL);\n\n    const { searchParams } = url;\n\n    searchParams.set('appkey', clientId);\n    searchParams.set('appsecret', clientSecret);\n\n    const response = await fetch(url, {\n      method: 'GET',\n      headers: {\n        Accept: 'application/json',\n        'Content-Type': 'application/json',\n      },\n    });\n\n    await assertResponse(response);\n\n    const result = await response.json();\n\n    assertResultSync(result);\n\n    return result as TokenResponse;\n  }\n}\n","import type { DingtalkClient } from './index';\n\nexport class APIResource {\n  protected client: DingtalkClient;\n\n  protected post: DingtalkClient['post'];\n\n  constructor(client: DingtalkClient) {\n    this.client = client;\n    this.post = client.post.bind(client);\n  }\n}\n","import { APIError } from '../../error';\nimport { APIResource } from '../../resource';\n\nexport type MaybePromise<T> = T | Promise<T>;\n\n/**\n * 互动卡片\n */\nexport class Instances extends APIResource {\n  /**\n   * 创建卡片\n   *\n   * @param params -\n   * @returns\n   */\n  async create(params: CardInstancesCreateParams): Promise<string> {\n    return this.afterResponse<string>(\n      this.post('/card/instances', JSON.stringify(params)),\n    );\n  }\n\n  /**\n   * 投放卡片\n   *\n   * @param params -\n   */\n  async deliver(params: CardInstancesDeliverParams) {\n    return this.afterResponse<unknown[]>(\n      this.post('/card/instances/deliver', JSON.stringify(params)),\n    );\n  }\n\n  /**\n   * 发送卡片\n   *\n   * @param params -\n   * @returns\n   */\n  async send(params: CardInstancesSendParams) {\n    // 私聊发送 chatBotId 和 robotCode 会报错\n    if (params.conversationType === 0) {\n      delete params.chatBotId\n      delete params.robotCode\n    }\n\n    return this.afterResponse<{ processQueryKey: string }>(\n      this.post('/im/interactiveCards/send', JSON.stringify(params)),\n    );\n  }\n\n  protected async afterResponse<T>(\n    resultInit: MaybePromise<CardInstanceResponse<T> | CardInstanceError>,\n  ): Promise<T> {\n    const result = await resultInit;\n\n    if ('success' in result && result.success) {\n      return result.result;\n    }\n\n    throw APIError.generate(\n      400,\n      undefined,\n      (result as CardInstanceError).message,\n    );\n  }\n}\n\n/**\n * 创建互动卡片实例\n *\n * @see https://open.dingtalk.com/document/orgapp/interface-for-creating-a-card-instance\n */\nexport interface CardInstancesCreateParams {\n  /**\n   * 卡片创建者的用户 ID\n   */\n  userId?: string;\n\n  /**\n   * 用户 ID 类型\n   *\n   * 1 userId\n   * 2 unionId\n   */\n  userIdType?: number;\n\n  /**\n   * 卡片内容模板ID\n   *\n   * @see https://open-dev.dingtalk.com/fe/card\n   */\n  cardTemplateId: string;\n\n  /**\n   * 外部卡片实例Id\n   */\n  outTrackId: string;\n\n  /**\n   * 卡片回调的类型\n   *\n   * - STREAM\n   * - HTTP\n   *\n   * 注意参数均为大写\n   */\n  callbackType?: 'STREAM' | 'HTTP';\n\n  /**\n   * 卡片回调HTTP模式时的路由 Key，用于查询注册的 callbackUrl\n   */\n  callbackRouteKey?: string;\n\n  /**\n   * 卡片数据\n   */\n  cardData: CardData;\n  /**\n   * 私有数据\n   *\n   * key 是用户 ID\n   */\n  privateData?: Record<string, CardData>;\n\n  /**\n   * 动态数据源配置\n   */\n  openDynamicDataConfig?: {\n    /**\n     * 动态数据源配置列表\n     */\n    dynamicDataSourceConfigs?: OpenDynamicDataConfig.SourceConfig[];\n  };\n  /**\n   * \tIM 群聊场域信息\n   */\n  imGroupOpenSpaceModel?: OpenSpaceModel;\n\n  /**\n   * IM 单聊场域信息\n   */\n  imRobotOpenSpaceModel?: OpenSpaceModel;\n\n  /**\n   * 协作场域信息\n   */\n  coFeedOpenSpaceModel?: {\n    /**\n     * 卡片标题\n     */\n    title?: string;\n\n    /**\n     * 吊顶场域属性，通过增加spaeType使卡片支持吊顶场域\n     */\n    topOpenSpaceModel?: {\n      spaceType: string;\n    };\n  };\n}\n\n/**\n * 卡片模板内容替换参数\n */\nexport type CardParamMap = Record<string, string>;\n\nexport type CardData = {\n  cardParamMap?: CardParamMap & { sys_full_json_obj?: string };\n};\n\nexport namespace OpenDynamicDataConfig {\n  export enum PullStrategy {\n    /**\n     * 不拉取，无动态数据\n     */\n    None = 'NONE',\n    /**\n     * 间隔拉取\n     */\n    Interval = 'INTERVAL',\n    /**\n     * 拉取一次\n     */\n    Once = 'ONCE',\n  }\n\n  export enum TimeUnit {\n    Seconds = 'SECONDS',\n    Minutes = 'MINUTES',\n    Hours = 'HOURS',\n    Days = 'DAYS',\n  }\n\n  export type SourceConfig = {\n    /**\n     * 数据源的唯一 ID, 调用方指定\n     */\n    dynamicDataSourceId?: string;\n    /**\n     * 回调数据源时回传的固定参数\n     */\n    constParams?: Record<string, string>;\n    /**\n     * 数据源拉取配置\n     */\n    pullConfig?: {\n      /**\n       * 拉取策略\n       */\n      pullStrategy?: PullStrategy;\n      /**\n       * 拉取的间隔时间\n       *\n       * - 只在将pullStrategy设置为INTERVAL的时候生效。\n       * - 最小拉取间隔时间3s。\n       */\n      interval?: number;\n      /**\n       * 拉取的间隔时间的单位\n       */\n      timeUnit?: TimeUnit;\n    };\n  };\n}\n\nexport type OpenSpaceModel = {\n  /**\n   * 是否支持转发\n   */\n  supportForward: boolean;\n\n  /**\n   * 支持国际化的LastMessage，目前支持的语言枚举值：\n   *\n   * ZH_CN：简体中文\n   * ZH_TW：繁体中文:\n   * EN_US：英文\n   * JA_JP：日语\n   * VI_VN：越南语\n   */\n  lastMessageI18n?: Map<I18n.Language, string>;\n\n  /**\n   * 支持卡片消息可被搜索字段\n   */\n  searchSupport?: {\n    /**\n     * 类型的icon，供搜索展示使用。\n     */\n    searchIcon?: string;\n    /**\n     * 卡片类型名\n     */\n    searchTypeName?: string;\n\n    /**\n     * 供消息展示与搜索的字段\n     */\n    searchDesc?: string;\n  };\n\n  /**\n   * 通知信息\n   */\n  notification?: {\n    /**\n     * 通知内容\n     *\n     * @defaultValue 如你收到 1 条新消息\n     */\n    alertContent?: string;\n\n    /**\n     * 是否关闭推送通知\n     */\n    notificationOff?: boolean;\n  };\n};\n\nexport namespace I18n {\n  export enum Language {\n    /**\n     * 简体中文\n     */\n    ZH_CN = 'ZH_CN',\n    /**\n     * 繁体中文\n     */\n    ZH_TW = 'ZH_TW',\n    /**\n     * 英文\n     */\n    EN_US = 'EN_US',\n    /**\n     * 日语\n     */\n    JA_JP = 'JA_JP',\n    /**\n     * 越南语\n     */\n    VI_VN = 'VI_VN',\n  }\n}\n\nexport type CardInstanceResponse<T> = {\n  success: boolean;\n  result: T;\n};\n\nexport type CardInstanceError = {\n  code: string;\n  requestId: string;\n  message: string;\n};\n\nexport type CardInstancesDeliverParams = {\n  /**\n   * 外部卡片实例 ID\n   */\n  outTrackId: string;\n\n  /**\n   * 卡片投放的场域\n   */\n  openSpaceId: string;\n\n  /**\n   * IM机器人单聊投放参数\n   */\n  imRobotOpenDeliverModel?: {\n    robotCode?: string;\n    spaceType?: string;\n    extension?: Record<string, string>;\n  };\n\n  /**\n   * 群聊投放参数\n   */\n  imGroupOpenDeliverModel?: {\n    robotCode?: string;\n    atUserIds: Record<string, string>;\n    recipients?: string[];\n    extension?: Record<string, string>;\n  };\n\n  /**\n   * 吊顶投放参数\n   */\n  topOpenDeliverModel?: {\n    expiredTimeMillis?: string;\n    userIds?: string[];\n    platforms: string[];\n  };\n\n  /**\n   * 协作投放参数\n   */\n  coFeedOpenDeliverModel?: {\n    /**\n     * 业务标识\n     */\n    bizTag?: string;\n    /**\n     * 协作场域下的排序时间\n     */\n    gmtTimeLine: string;\n  };\n\n  /**\n   * 文档投放参数\n   */\n  docOpenDeliverModel?: {\n    userId?: string;\n  };\n\n  userIdType?: number;\n};\n\n/**\n * 发送互动卡片\n *\n * @see https://open.dingtalk.com/document/orgapp-server/send-dingtalk-interactive-cards\n */\nexport type CardInstancesSendParams = {\n  /**\n   * 互动卡片的消息模板ID\n   */\n  cardTemplateId: string;\n\n  /**\n   * 唯一标示卡片的外部编码\n   */\n  outTrackId: string;\n\n  /**\n   * 机器人唯一编码\n   */\n  robotCode?: string;\n\n  /**\n   * 机器人ID\n   */\n  chatBotId?: string;\n\n  /**\n   * 群ID\n   */\n  openConversationId: string;\n\n  /**\n   * 会话类型\n   *\n   * - 0 单聊\n   * - 1 群聊\n   *\n   * @remarks 和消息的会话类型不同\n   */\n  conversationType: number;\n\n  /**\n   * 接收用户列表\n   */\n  receiverUserIdList: string[];\n\n  /**\n   * 消息提及的人\n   */\n  atOpenIds?: Record<string, string>;\n\n  /**\n   * 用户ID类型\n   */\n  userIdType?: number;\n\n  /**\n   * 卡片回调时的路由Key，用于查询注册的callbackUrl\n   */\n  callbackRouteKey?: string;\n\n  /**\n   * 卡片数据\n   */\n  cardData: CardData;\n\n  /**\n   * 卡片选项\n   */\n  cardOptions?: {\n    supportForward: boolean;\n  };\n\n  /**\n   * 私有数据\n   */\n  privateData?: Record<string, CardData>;\n\n  /**\n   * 拉取策略\n   *\n   * - true：开启卡片纯拉模式\n   * - false：不开启卡片纯拉模式\n   */\n  pullStrategy?: boolean;\n};\n","import { APIResource } from '../../resource'\n\nimport * as InstancesAPI from './instances'\n\nexport class Card extends APIResource {\n  instances: InstancesAPI.Instances = new InstancesAPI.Instances(this.client);\n}\n","import { createWriteStream } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport { finished } from 'node:stream/promises';\nimport { type ReadableStream as WebReadableStream } from 'node:stream/web';\n\nimport { API_GATEWAY_URL } from '../config';\nimport { InvalidResultError } from '../error';\nimport { APIResource } from '../resource';\n\ntype ExchangeCodeResult = {\n  // cSpell: ignore requestid\n  requestid: string;\n  message?: string;\n  code?: string;\n  /**\n   * 错误码\n   */\n  errcode: number;\n  /**\n   * 错误信息\n   */\n  errmsg: string;\n  /**\n   * 文件下载地址\n   */\n  downloadUrl: string;\n};\n\n/**\n * 临时下载码\n *\n * @see https://open.dingtalk.com/document/orgapp/download-the-file-content-of-the-robot-receiving-message\n */\nexport type DownloadCode = string;\n\nexport class Downloader extends APIResource {\n  endpoint = '/robot/messageFiles/download';\n\n  /**\n   * 使用下载码交换文件地址\n   *\n   * @param downloadCode - 下载码\n   * @param robotCode - 机器人Code\n   */\n  async exchangeCode(\n    downloadCode: DownloadCode,\n    robotCode?: string, // TODO 支持从全局配置的企业应用ID中获取\n  ): Promise<string> {\n    const { client } = this;\n    const url = new URL(`${API_GATEWAY_URL}${this.endpoint}`);\n\n    const response = await fetch(url, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'x-acs-dingtalk-access-token': await client.getAccessToken(),\n      },\n      body: JSON.stringify({\n        downloadCode: downloadCode,\n        robotCode: robotCode || client.clientId,\n      }),\n    });\n\n    const result: ExchangeCodeResult = await response.json();\n\n    if (result.downloadUrl) return result.downloadUrl;\n\n    throw new InvalidResultError(result.errmsg || result.message);\n  }\n\n  /**\n   * 下载文件到指定位置\n   *\n   * @param url - 下载地址\n   * @param filePath - 文件路径\n   * @returns 文件路径\n   */\n  downloadToPath(url: string, filePath: string): Promise<string> {\n    return this.fetchStream(url).then(stream => this.saveTo(stream, filePath));\n  }\n\n  /**\n   * 下载文件到临时目录\n   *\n   * @param url - 下载地址\n   * @param filename - 文件名\n   * @returns 临时文件路径\n   */\n  downloadToTmp(url: string, name?: string): Promise<string> {\n    return this.fetchStream(url).then(stream => {\n      const filename = name || resolveNameFromURl(url);\n      return this.saveTo(stream, path.join(os.tmpdir(), filename));\n    });\n  }\n\n  protected fetchStream(url: string): Promise<WebReadableStream> {\n    return fetch(url).then(res => {\n      const stream = res.body! as WebReadableStream;\n      if (stream) return stream;\n\n      throw new TypeError('No readable stream');\n    });\n  }\n\n  /**\n   * 保存数据流到文件\n   *\n   * @param stream - 数据流\n   * @param filePath - 绝对路径\n   * @returns 文件路径\n   */\n  protected saveTo(\n    stream: WebReadableStream,\n    filePath: string,\n  ): Promise<string> {\n    const writeStream = createWriteStream(filePath);\n\n    Readable.fromWeb(stream).pipe(writeStream);\n\n    return finished(writeStream).then(() => filePath);\n  }\n}\n\nfunction resolveNameFromURl(url: string) {\n  const { pathname } = new URL(url);\n  return path.basename(pathname);\n}\n","import { readFileSync } from 'node:fs';\n\nimport { OPEN_API_GATEWAY_URL } from '../config';\nimport { InvalidResultError } from '../error';\nimport { APIResource } from '../resource';\n\n/**\n * 媒体文件类型\n *\n * - image：图片，图片最大20MB。支持上传jpg、gif、png、bmp格式。\n * - voice：语音，语音文件最大2MB。支持上传amr、mp3、wav格式。\n * - video：视频，视频最大20MB。支持上传mp4格式。\n * - file：普通文件，最大20MB。支持上传doc、docx、xls、xlsx、ppt、pptx、zip、pdf、rar格式。\n */\nexport type MediaType = 'image' | 'voice' | 'file';\n\n/**\n * 上传结果\n */\nexport type UploadResult<T extends MediaType = MediaType> = {\n  /**\n   * 错误码\n   */\n  errcode: number;\n  /**\n   * 错误信息\n   */\n  errmsg: string;\n  /**\n   * 媒体文件类型\n   */\n  type: T;\n  /**\n   * 媒体文件上传后获取的唯一标识。\n   */\n  media_id: string;\n  /**\n   * 媒体文件上传时间戳。\n   */\n  created_at: number;\n};\n\nexport class Uploader extends APIResource {\n  endpoint = '/media/upload';\n\n  /**\n   * 从远程链接获取文件并上传\n   *\n   * @param type - 媒体文件类型\n   * @param url - 下载地址\n   * @param name - 文件名\n   * @returns 上传结果\n   */\n  async putFromURL<Type extends MediaType = MediaType>(\n    type: Type,\n    url: string,\n    name?: string,\n  ): Promise<UploadResult<Type>> {\n    const downloader = this.client.downloader;\n    const filePath = await downloader.downloadToTmp(url, name);\n\n    return this.putFromPath(type, filePath, name);\n  }\n\n  /**\n   * 从本地文件上传\n   *\n   * @param type - 上传文件类型\n   * @param path - 文件路径\n   * @param filename - 文件名\n   * @returns 上传结果\n   */\n  async putFromPath<Type extends MediaType = MediaType>(\n    type: Type,\n    path: string,\n    name?: string,\n  ): Promise<UploadResult<Type>> {\n    return this.putFromObject(type, readFileSync(path), name);\n  }\n\n  /**\n   * 从文件内容上传\n   *\n   * @see https://open.dingtalk.com/document/orgapp/upload-media-files\n   * @param type - 上传类型\n   * @param data - 文件内容\n   * @param filename - 文件名\n   * @returns 上传结果\n   */\n  async putFromObject<Type extends MediaType = MediaType>(\n    type: Type,\n    data: BlobPart,\n    filename?: string,\n  ): Promise<UploadResult<Type>> {\n    const { client } = this;\n    const url = new URL(this.endpoint, OPEN_API_GATEWAY_URL);\n\n    url.searchParams.set('access_token', await client.getAccessToken());\n\n    const form = new FormData();\n\n    form.append('type', type);\n    form.append('media', new Blob([data]), filename);\n\n    const response = await fetch(url, {\n      method: 'POST',\n      headers: {\n        Accept: 'application/json',\n      },\n      body: form,\n    });\n\n    const result: UploadResult<Type> = await response.json();\n\n    if (result.errcode === 0) return result;\n\n    throw new InvalidResultError(result.errmsg);\n  }\n}\n","export namespace Outgoing {\n  /**\n   * 空消息\n   *\n   * 当不想回复消息到群里时，可以使用空消息\n   */\n  export type EmptyMessage = {\n    msgtype: 'empty';\n  };\n\n  /**\n   * 文本消息\n   */\n  export type TextMessage = WithAt<{\n    msgtype: 'text';\n    text: {\n      content: string;\n    };\n  }>;\n\n  /**\n   * Markdown 消息\n   */\n  export type MarkdownMessage = WithAt<{\n    msgtype: 'markdown';\n    markdown: {\n      title: string;\n      text: string;\n    };\n  }>;\n\n  /**\n   * 链接消息\n   */\n  export type LinkMessage = {\n    msgtype: 'link';\n    link: {\n      text: string;\n      title: string;\n      picUrl: string;\n      messageUrl: string;\n    };\n  };\n\n  /**\n   * webhook 方式不支持\n   */\n  export type ImageMessage = {\n    msgtype: 'picture';\n    image: {\n      photoURL: string;\n    };\n  };\n\n  export type AudioMessage = {\n    msgtype: 'audio';\n    audio: {\n      mediaId: string;\n      duration: number;\n    };\n  };\n\n  export type VideoMessage = {\n    msgtype: 'video';\n    video: {\n      /**\n       * 视频封面图片媒体文件ID\n       *\n       * 通过上传媒体文件接口得到的 mediaId\n       */\n      picMediaId: string;\n      /**\n       * 视频媒体文件ID\n       *\n       * 通过上传媒体文件接口得到的 mediaId\n       */\n      videoMediaId: string;\n      /**\n       * 视频类型，支持mp4格式。\n       */\n      videoType: number;\n      /**\n       * 视频时长，单位：秒\n       */\n      duration: string;\n      /**\n       * 视频展示宽度，单位px\n       */\n      width?: string;\n      /**\n       * 视频展示高度，单位px\n       */\n      height?: string;\n    };\n  };\n\n  export type FileMessage = {\n    msgtype: 'file';\n    file: {\n      mediaId: string;\n      fileName: string;\n      fileType: string;\n    };\n  };\n\n  export type SingleButtonActionCard = {\n    /**\n     * 首屏会话透出的展示内容\n     */\n    title: string;\n    /**\n     * markdown 格式的消息\n     */\n    text: string;\n    /**\n     * 单个按钮的标题\n     */\n    singleTitle: string;\n    /**\n     * 点击 singleTitle 按钮触发的URL\n     */\n    singleURL: string;\n  };\n\n  export enum ActionCardButtonOrientation {\n    Vertical = '0',\n    Horizontal = '1',\n  }\n\n  export type ActionCardButtonStyle = {\n    /**\n     * 按钮标题\n     */\n    title: string;\n    /**\n     * 点击按钮触发的URL\n     */\n    actionURL: string;\n  };\n\n  export type MultiButtonActionCard = {\n    /**\n     * 首屏会话透出的展示内容\n     */\n    title: string;\n    /**\n     * markdown 格式的消息\n     */\n    text: string;\n    /**\n     * 按钮排列顺序\n     *\n     * 0: 按钮竖直排列\n     * 1: 按钮横向排列\n     */\n    btnOrientation: ActionCardButtonOrientation;\n    /**\n     * 按钮列表\n     */\n    btns: ActionCardButtonStyle[];\n  };\n\n  /**\n   * ActionCard 消息\n   */\n  export type ActionCardMessage = {\n    msgtype: 'actionCard';\n    actionCard: SingleButtonActionCard | MultiButtonActionCard;\n  };\n\n  export type FeedLink = {\n    title: string;\n    messageURL: string;\n    picURL: string;\n  };\n\n  /**\n   * FeedCard 消息\n   *\n   * 接口方式不支持\n   */\n  export type FeedCardMessage = {\n    msgtype: 'feedCard';\n    feedCard: {\n      links: FeedLink[];\n    };\n  };\n\n  /**\n   * 机器人发送的消息类型\n   */\n  export enum ContentType {\n    Empty = 'empty',\n    Text = 'text',\n    Markdown = 'markdown',\n    Link = 'link',\n    Image = 'image',\n    Audio = 'audio',\n    Video = 'video',\n    File = 'file',\n    ActionCard = 'actionCard',\n    FeedCard = 'feedCard',\n  }\n\n  type At = {\n    atUserIds?: string[];\n    atMobiles?: string[];\n    isAtAll?: boolean;\n  };\n\n  type WithAt<T> = T & { at?: At };\n\n  type MessageMap = {\n    [ContentType.Empty]: EmptyMessage;\n    [ContentType.Text]: TextMessage;\n    [ContentType.Markdown]: MarkdownMessage;\n    [ContentType.Link]: LinkMessage;\n    [ContentType.Image]: ImageMessage;\n    [ContentType.Audio]: AudioMessage;\n    [ContentType.Video]: VideoMessage;\n    [ContentType.File]: FileMessage;\n    [ContentType.ActionCard]: ActionCardMessage;\n    [ContentType.FeedCard]: FeedCardMessage;\n  };\n\n  /**\n   * 机器人发送的消息类型\n   *\n   * https://open.dingtalk.com/document/orgapp/robot-message-types-and-data-format\n   */\n  export type Message = MessageMap[ContentType];\n}\n","import { Outgoing } from './outgoing';\n\nexport namespace Incoming {\n  /**\n   * 机器人发送的消息类型\n   */\n  export enum ContentType {\n    Text = 'text',\n    Audio = 'audio',\n    Video = 'video',\n    Image = 'picture',\n    RichText = 'richText',\n    File = 'file',\n  }\n\n  export namespace RichText {\n    export type TextSection = {\n      text: string;\n    };\n\n    export type ImageSection = {\n      type: 'picture';\n      downloadCode: string;\n      pictureDownloadCode: string;\n    };\n\n    export type Section = TextSection | ImageSection;\n  }\n\n  export type RichTextSection = RichText.Section;\n\n  export type RichTextMessage = {\n    msgtype: 'richText';\n    content: {\n      richText: RichTextSection[];\n    };\n  };\n\n  export type ImageMessage = {\n    msgtype: 'picture';\n    content: {\n      downloadCode: string;\n      pictureDownloadCode: string;\n    };\n  };\n\n  export type AudioMessage = {\n    msgtype: 'audio';\n    content: {\n      duration: number;\n      downloadCode: string;\n      recognition: string; // 语音识别结果\n    };\n  };\n\n  export type VideoMessage = {\n    msgtype: 'video';\n    content: {\n      duration: number;\n      downloadCode: string;\n      videoType: string;\n    };\n  };\n\n  export type FileMessage = {\n    msgtype: 'file';\n    content: {\n      spaceId: string;\n      field: string;\n      downloadCode: string;\n      fileName: string;\n    };\n  };\n\n  type MessageMap = {\n    [ContentType.Text]: Outgoing.TextMessage;\n    [ContentType.RichText]: RichTextMessage;\n    [ContentType.Image]: ImageMessage;\n    [ContentType.Audio]: AudioMessage;\n    [ContentType.Video]: VideoMessage;\n    [ContentType.File]: FileMessage;\n  };\n\n  export type Message = MessageMap[ContentType];\n}\n","import { debuglog } from 'node:util';\n\nimport { OPEN_API_GATEWAY_URL } from '../../config';\nimport { simple_post_json } from '../../http';\nimport { sha256 } from '../../shared/hash';\nimport { Outgoing } from '../interfaces/outgoing';\n\nconst debug = debuglog('dingtalk.robots.session-robot');\n\nexport type CustomizeWebhookSettings = {\n  /**\n   * 钉钉开放平台网关地址\n   *\n   * @defaultValue https://oapi.dingtalk.com\n   */\n  apiBaseUrl?: string;\n\n  /**\n   * 机器人接口地址\n   */\n  endpoint?: string;\n\n  /**\n   * 授权令牌\n   */\n  token: string;\n\n  /**\n   * 加密密钥\n   *\n   * see https://open.dingtalk.com/document/robots/customize-robot-security-settings\n   */\n  secret?: string;\n};\n\n/**\n * 自定义机器人接入\n *\n * @see https://open.dingtalk.com/document/isvapp/custom-bot-access-send-message\n */\nexport class CustomizeWebhook {\n  token: string;\n  secret?: string;\n\n  apiBaseUrl: string;\n  endpoint: string;\n\n  constructor(settings: CustomizeWebhookSettings) {\n    this.token = settings.token;\n    this.secret = settings.secret;\n\n    this.apiBaseUrl = settings.apiBaseUrl ?? OPEN_API_GATEWAY_URL;\n    this.endpoint = settings.endpoint ?? '/robot/send';\n  }\n\n  say(sayable: string | Outgoing.Message): Promise<void> {\n    if (typeof sayable === 'string') {\n      return this.send({\n        msgtype: 'text',\n        text: {\n          content: sayable,\n        },\n      });\n    }\n\n    return this.send(sayable);\n  }\n\n  async send(message: Outgoing.Message): Promise<void> {\n    await simple_post_json(this.buildURL(), JSON.stringify(message));\n  }\n\n  protected buildURL(): string {\n    const url = new URL(`${this.apiBaseUrl}${this.endpoint}`);\n\n    const { searchParams } = url;\n\n    searchParams.set('access_token', this.token);\n\n    if (this.secret) {\n      const timestamp = Date.now();\n      const stringToSign = `${timestamp}\\n${this.secret}`;\n      const signature = encodeURIComponent(sha256(stringToSign, this.secret));\n\n      searchParams.set('timestamp', timestamp.toString());\n      searchParams.set('sign', signature);\n    }\n\n    debug('url: %s', url.toString());\n\n    return url.toString();\n  }\n}\n","import { debuglog } from 'node:util';\n\nimport { simple_post_json } from '../../http';\nimport { Outgoing } from '../interfaces/outgoing';\n\nconst debug = debuglog('dingtalk.robots.session-robot');\n\nexport type SessionWebhookSettings = {\n  /**\n   * 当前会话的 Webhook 地址\n   */\n  sessionWebhook: string;\n\n  /**\n   * 当前会话的 Webhook 地址过期时间\n   */\n  sessionWebhookExpiredTime: number;\n};\n\n/**\n * see https://open.dingtalk.com/document/orgapp/receive-message\n */\nexport class SessionWebhook {\n  sessionWebhook: string;\n  sessionWebhookExpiredTime: number;\n\n  constructor(settings: SessionWebhookSettings) {\n    this.sessionWebhook = settings.sessionWebhook;\n    this.sessionWebhookExpiredTime = settings.sessionWebhookExpiredTime;\n  }\n\n  is_expired(): boolean {\n    return this.sessionWebhookExpiredTime < Date.now();\n  }\n\n  async send(message: Outgoing.Message): Promise<void> {\n    // 忽略过期的 Webhook\n    if (this.is_expired()) {\n      debug('[SessionRobot] %s Webhook 过期，已忽略发送的消息');\n      return;\n    }\n\n    await simple_post_json(this.sessionWebhook, JSON.stringify(message));\n  }\n}\n","import { Outgoing } from '../interfaces';\n\nexport type Sayable = string | Outgoing.Message;\n\nexport abstract class SayableSayer {\n  async say(sayable: Sayable): Promise<any>;\n  async say(sayable: Sayable, atAll: true): Promise<any>;\n  async say(sayable: Sayable, mentionList: string[]): Promise<any>;\n  async say(sayable: Sayable, mentionList?: true | string[]): Promise<any> {\n    const message = await this.resolve(sayable);\n\n    if (!mentionList) return this.send(message);\n\n    return this.send(this.mention(message, mentionList as string[]));\n  }\n\n  protected abstract send(message: Outgoing.Message): Promise<void>;\n\n  protected mention(message: Outgoing.Message): Outgoing.Message;\n  protected mention(message: Outgoing.Message, atAll: true): Outgoing.Message;\n  protected mention(\n    message: Outgoing.Message,\n    mentionList: string[],\n  ): Outgoing.Message;\n  protected mention(\n    message: Outgoing.Message,\n    mentionList?: true | string[],\n  ): Outgoing.Message {\n    if (!mentionList) return message;\n\n    if (mentionList === true) {\n      message = this.atAll(message);\n    } else {\n      message = this.atUserIds(message, mentionList);\n    }\n\n    return message;\n  }\n\n  protected atAll(message: Outgoing.Message): Outgoing.Message {\n    if (\n      message.msgtype === Outgoing.ContentType.Text ||\n      message.msgtype === Outgoing.ContentType.Markdown\n    ) {\n      message.at = { isAtAll: true };\n    }\n\n    return message;\n  }\n\n  protected atUserIds(\n    message: Outgoing.Message,\n    userIds: string[],\n  ): Outgoing.Message {\n    if (\n      userIds.length === 0 ||\n      !(\n        Outgoing.ContentType.Text === message.msgtype ||\n        Outgoing.ContentType.Markdown === message.msgtype\n      )\n    ) {\n      return message;\n    }\n\n    if (userIds.length === 0) return message;\n\n    if (message.msgtype === Outgoing.ContentType.Text) {\n      message.text.content += ` ${userIds.map(id => `@${id}`).join(' ')}`;\n    } else if (message.msgtype === Outgoing.ContentType.Markdown) {\n      message.markdown.text += ` \\n\\n------\\n\\n ###### 此消息通知对象: ${userIds\n        .map(userId => `@${userId}`)\n        .join(' ')}`;\n    }\n\n    message.at = {\n      atUserIds: userIds,\n    };\n\n    return message;\n  }\n\n  // TODO 支持媒体消息，并且自动上传\n  protected async resolve(sayable: Sayable): Promise<Outgoing.Message> {\n    if (typeof sayable === 'string') {\n      return {\n        msgtype: Outgoing.ContentType.Text,\n        text: {\n          content: sayable,\n        },\n      };\n    }\n\n    return sayable;\n  }\n}\n","import { Outgoing, type RobotProperties } from '../interfaces';\nimport { SessionWebhook } from '../webhooks/session';\nimport { type IncomingMessage } from './message';\nimport { SayableSayer } from './sayable';\n\nexport class Robot extends SayableSayer {\n  id: string;\n\n  code: string;\n\n  corpId: string;\n\n  webhook: SessionWebhook;\n\n  constructor(\n    public incoming: IncomingMessage, // TODO 暂定，用于调用其他 API\n    {\n      chatbotUserId,\n      robotCode,\n      chatbotCorpId,\n      sessionWebhook,\n      sessionWebhookExpiredTime,\n    }: RobotProperties,\n  ) {\n    super();\n\n    this.id = chatbotUserId;\n    this.code = robotCode;\n    this.corpId = chatbotCorpId;\n\n    this.webhook = new SessionWebhook({\n      sessionWebhook,\n      sessionWebhookExpiredTime,\n    });\n  }\n\n  protected send(message: Outgoing.Message): Promise<void> {\n    return this.webhook.send(message);\n  }\n}\n","import { type ConversationProperties } from '../interfaces/conversation';\nimport { type IncomingMessage } from './message';\nimport { type Sayable } from './sayable';\n\nexport class Room {\n  id: string;\n\n  name: string;\n\n  constructor(\n    protected incoming: IncomingMessage,\n    properties: ConversationProperties,\n  ) {\n    this.id = properties.conversationId;\n    this.name = properties.conversationTitle!;\n  }\n\n  // 快捷方式\n  async say(sayable: Sayable): Promise<any>;\n  async say(sayable: Sayable, atAll: true): Promise<any>;\n  async say(sayable: Sayable, mentionList: string[]): Promise<any>;\n  async say(sayable: Sayable, mentionList?: true | string[]): Promise<any> {\n    return this.incoming.say(sayable, mentionList as string[]);\n  }\n\n  async reply(sayable: Sayable) {\n    return this.incoming.reply(sayable);\n  }\n}\n","import { type TalkerProperties } from '../interfaces';\nimport { type IncomingMessage } from './message';\nimport { type Sayable } from './sayable';\n\nexport class Talker {\n  /**\n   * 用户ID\n   *\n   */\n  id: string;\n  /**\n   * 企业ID\n   */\n  corpId: string;\n  /**\n   * 员工ID\n   */\n  staffId: string;\n  /**\n   * 昵称\n   */\n  name: string;\n  /**\n   * 是否管理员\n   */\n  isAdmin: boolean;\n\n  constructor(\n    protected incoming: IncomingMessage,\n    properties: TalkerProperties,\n  ) {\n    this.id = properties.senderId;\n    this.corpId = properties.senderCorpId;\n    this.staffId = properties.senderStaffId;\n    this.name = properties.senderNick;\n    this.isAdmin = properties.isAdmin;\n  }\n\n  reply(sayable: Sayable): Promise<void> {\n    return this.incoming.reply(sayable);\n  }\n}\n","import DingtalkClient from '../../index';\nimport { type Conversation, Incoming } from '../interfaces';\nimport { SessionWebhook } from '../webhooks/session';\nimport { Robot } from './robot';\nimport { Room } from './room';\nimport { type Sayable } from './sayable';\nimport { Talker } from './talker';\n\n// TODO 支持获取引用的消息\n// TODO 支持消息转文件\nexport class IncomingMessage {\n  Type = Incoming.ContentType;\n\n  conversationId: string;\n  conversationType: '2' | '1';\n\n  id: string;\n  type: Incoming.ContentType;\n  text: string;\n  age: number;\n  createAt: number;\n\n  room?: Room | undefined;\n\n  robot: Robot;\n\n  talker: Talker;\n\n  webhook: SessionWebhook;\n\n  constructor(\n    protected client: DingtalkClient,\n    public properties: Conversation,\n  ) {\n    const {\n      // 会话\n      conversationId,\n      conversationType,\n      // 消息\n      msgId,\n      msgtype,\n      createAt,\n      // Webhook\n      sessionWebhook,\n      sessionWebhookExpiredTime,\n    } = properties;\n\n    this.conversationId = conversationId;\n    this.conversationType = conversationType;\n\n    this.id = msgId;\n    this.type = msgtype as Incoming.ContentType;\n    this.age = Date.now() - createAt;\n    this.createAt = createAt;\n\n    this.webhook = new SessionWebhook({\n      sessionWebhook,\n      sessionWebhookExpiredTime,\n    });\n\n    if (conversationType === '2') {\n      this.room = new Room(this, properties);\n    }\n\n    this.robot = new Robot(this, properties);\n    this.talker = new Talker(this, properties);\n\n    // 从支持的消息类型中获取文本内容\n    this.text = resolveTextContent(properties);\n  }\n\n  /**\n   * 获取富文本内容\n   *\n   * @returns 富文本节点\n   */\n  richText(): Incoming.RichTextSection[] | void {\n    const { properties } = this;\n\n    if (properties.msgtype === Incoming.ContentType.RichText) {\n      return properties.content.richText;\n    }\n  }\n\n  /**\n   * 直接回复消息给发送者\n   *\n   * @param sayable - 消息内容\n   * @returns\n   */\n  reply(sayable: Sayable) {\n    return this.say(sayable, [this.talker.staffId]);\n  }\n\n  /**\n   * 可以发送给任何消息给有权限的人\n   *\n   * @param sayable - 消息内容\n   */\n  async say(sayable: Sayable): Promise<void>;\n  async say(sayable: Sayable, atAll: true): Promise<void>;\n  async say(sayable: Sayable, mentionList: string[]): Promise<void>;\n  async say(sayable: Sayable, mentionList?: true | string[]): Promise<void> {\n    if (this.conversationType === '1') {\n      return this.robot.say(sayable);\n    }\n\n    return this.robot.say(sayable, mentionList as string[]);\n  }\n\n  async unstable__getFileURL(): Promise<string | void> {\n    const {\n      properties,\n      client: { downloader },\n    } = this;\n\n    if (properties.msgtype === Incoming.ContentType.Image) {\n      return downloader.exchangeCode(properties.content.downloadCode);\n    }\n\n    if (properties.msgtype === Incoming.ContentType.File) {\n      return downloader.exchangeCode(properties.content.downloadCode);\n    }\n  }\n\n  /**\n   * 保存文件到临时目录中\n   *\n   * @param filename - 临时文件名\n   * @returns 文件路径\n   */\n  async unstable__saveFileToTmpdir(\n    filename?: string,\n  ): Promise<string | undefined> {\n    const url = await this.unstable__getFileURL();\n    if (!url) return;\n\n    const {\n      properties,\n      client: { downloader },\n    } = this;\n\n    // 修复文件名丢失的问题，如修复：`xxxx.file` 的文件名\n    if (properties.msgtype === Incoming.ContentType.File) {\n      filename = properties.content.fileName;\n    }\n\n    return downloader.downloadToTmp(url, filename);\n  }\n\n  /**\n   * 获取消息包含的文件名称\n   *\n   * @returns 文件名称\n   */\n  unstable__filenameSync(): string | void {\n    const { properties } = this;\n    if (properties.msgtype === Incoming.ContentType.File) {\n      return properties.content.fileName;\n    }\n  }\n}\n\nfunction resolveTextContent(message: Incoming.Message) {\n  const { msgtype } = message;\n\n  if (msgtype === Incoming.ContentType.Text) {\n    return message.text.content;\n  }\n\n  if (msgtype === Incoming.ContentType.RichText) {\n    const data = message.content.richText.map(item => {\n      return 'text' in item ? item.text : '';\n    });\n\n    return data.filter(Boolean).join('\\n');\n  }\n\n  if (msgtype === Incoming.ContentType.Audio) {\n    return message.content.recognition;\n  }\n\n  return '';\n}\n","export enum SubscriptionType {\n  ImMessage = 'im.message',\n}\n\nexport type SubscriptionItem = {\n  type: (string & NonNullable<unknown>) | 'EVENT' | 'CALLBACK';\n  topic: string;\n};\n\nexport type SubscriptionData = {\n  specVersion: string;\n  type: string;\n  headers: {\n    appId: string;\n    connectionId: string;\n    IncomingType: string;\n    messageId: string;\n    time: string;\n    topic: string;\n    eventType?: string;\n    eventBornTime?: string;\n    eventId?: string;\n    eventCorpId?: string;\n    eventUnifiedAppId?: string;\n  };\n  data: string;\n};\n\nexport const Subscriptions = {\n  AllEvent: {\n    type: 'EVENT',\n    topic: '*',\n  } as SubscriptionItem,\n  ImMessage: {\n    type: 'CALLBACK',\n    topic: '/v1.0/im/bot/messages/get',\n  } as SubscriptionItem,\n} as const;\n\n// TODO 将订阅功能从客户端分离出来，解耦 事件 和 回调 的处理\nexport class SubscriptionManager {\n  // pass\n}\n","import { EventEmitter } from 'node:events';\n\nimport WebSocket from 'ws';\n\nimport { API_GATEWAY_URL } from '../config';\nimport { InvalidResultError } from '../error';\nimport { DingtalkClient } from '../index';\nimport { IncomingMessage } from '../robots';\nimport {\n  type SubscriptionData,\n  type SubscriptionItem,\n  Subscriptions,\n  SubscriptionType,\n} from './subscription';\n\nconst DEFAULT_PING_INTERVAL_IN_MS = 8 * 1000;\n\nexport interface StreamClientOptions {\n  /**\n   * 订阅的事件\n   */\n  subscriptions?: SubscriptionItem[];\n\n  /**\n   * ping 服务器的默认间隔\n   *\n   * @defaultValue 8 * 1000\n   */\n  keepAliveIntervalInMilliseconds?: number;\n}\n\nexport class StreamClient extends EventEmitter {\n  #subscriptions: SubscriptionItem[];\n\n  #socket?: WebSocket;\n  #connected: boolean = false;\n\n  #living = false;\n  #keepAliveTimerId?: NodeJS.Timeout;\n  #keepAliveIntervalInMilliseconds: number;\n\n  constructor(\n    protected client: DingtalkClient,\n    options?: StreamClientOptions,\n  ) {\n    super();\n\n    const {\n      keepAliveIntervalInMilliseconds = DEFAULT_PING_INTERVAL_IN_MS,\n      subscriptions = [Subscriptions.AllEvent, Subscriptions.ImMessage],\n    } = options || {};\n\n    this.#subscriptions = subscriptions;\n    this.#keepAliveIntervalInMilliseconds = keepAliveIntervalInMilliseconds;\n  }\n\n  async connect(): Promise<void> {\n    if (this.#connected) return;\n\n    const { endpoint, ticket } = await this.getEndpoint();\n    const connection = new WebSocket(`${endpoint}?ticket=${ticket}`, {\n      rejectUnauthorized: true,\n    });\n\n    connection.on('open', () => {\n      this.#connected = true;\n      console.info('[' + new Date().toISOString() + '] connect success');\n\n      this.enableHeartbeat();\n    });\n\n    connection.on('message', (data: string) => {\n      const event = JSON.parse(data) as SubscriptionData;\n\n      switch (event.type) {\n        case 'SYSTEM':\n          this.handleSystem(event);\n          break;\n        case 'CALLBACK':\n          this.handleCallback(event);\n          break;\n        case 'EVENT':\n          this.handleEvent(event);\n          break;\n      }\n    });\n\n    connection.on('close', () => {\n      this.#socket = undefined;\n      this.#connected = false;\n      this.disableHeartbeat();\n      this.emit('close');\n    });\n\n    connection.on('error', error => {\n      this.#socket = undefined;\n      this.#connected = false;\n      this.disableHeartbeat();\n      this.emit('error', error);\n    });\n\n    this.#socket = connection;\n  }\n\n  isConnecting() {\n    return this.#connected;\n  }\n\n  disconnect() {\n    this.#connected = false;\n    this.#socket?.close();\n  }\n\n  sendGraphAPIResponse(messageId: string, value: GraphAPIResponse) {\n    if (!messageId) {\n      throw new Error('send: messageId must be defined');\n    }\n\n    const socket = this.#socket;\n    if (!socket) {\n      throw new Error('send: ws must be defined');\n    }\n\n    socket.send(\n      JSON.stringify({\n        code: 200,\n        headers: {\n          IncomingType: 'application/json',\n          messageId: messageId,\n        },\n        message: 'OK',\n        data: JSON.stringify(value),\n      }),\n    );\n  }\n\n  onImMessage(callback: (message: IncomingMessage) => void) {\n    this.on(SubscriptionType.ImMessage, callback);\n  }\n\n  protected handleSystem(message: SubscriptionData) {\n    switch (message.headers.topic) {\n      case 'REGISTERED': {\n        this.#connected = false;\n        break;\n      }\n\n      case 'disconnect': {\n        this.#connected = false;\n        break;\n      }\n\n      case 'KEEPALIVE': {\n        this.#living = true;\n        break;\n      }\n\n      case 'ping': {\n        this.#socket!.send(\n          JSON.stringify({\n            code: 200,\n            headers: message.headers,\n            message: 'OK',\n            data: message.data,\n          }),\n        );\n        break;\n      }\n    }\n  }\n\n  protected handleCallback(event: SubscriptionData) {\n    switch (event.headers.topic) {\n      case Subscriptions.ImMessage.topic: {\n        this.emit(\n          SubscriptionType.ImMessage,\n          new IncomingMessage(this.client, JSON.parse(event.data)),\n        );\n        break;\n      }\n      default:\n        this.emit(event.headers.topic, event);\n    }\n  }\n\n  protected handleEvent(event: SubscriptionData) {\n    this.emit('event', event);\n  }\n\n  protected async getEndpoint() {\n    const { client } = this;\n\n    const res = await fetch(`${API_GATEWAY_URL}/gateway/connections/open`, {\n      method: 'POST',\n      headers: await this.defaultHeaders(),\n      body: JSON.stringify({\n        clientId: client.clientId,\n        clientSecret: client.clientSecret,\n        subscriptions: this.#subscriptions,\n        ua: '',\n      }),\n    });\n\n    const data = await res.json();\n\n    if (!data.endpoint || !data.ticket) {\n      throw new InvalidResultError('endpoint or ticket is null');\n    }\n\n    return data;\n  }\n\n  protected enableHeartbeat() {\n    const socket = this.#socket;\n    if (!socket) return;\n\n    // clear previous heartbeat\n    this.disableHeartbeat();\n\n    socket.on('pong', () => {\n      this.#living = true;\n    });\n\n    this.#living = true;\n    this.#keepAliveTimerId = setInterval(() => {\n      // if ping-pong need to much time, longer than heartbeat, terminate socket connection\n      if (this.#living === false) {\n        console.error(\n          'TERMINATE SOCKET: Ping Pong does not transfer heartbeat within heartbeat interval',\n        );\n        return socket.terminate();\n      }\n\n      // if ping-pong ok, prepare next one\n      this.#living = false;\n      socket.ping('', true);\n    }, this.#keepAliveIntervalInMilliseconds);\n  }\n\n  protected disableHeartbeat() {\n    if (this.#keepAliveTimerId) {\n      clearInterval(this.#keepAliveTimerId);\n    }\n  }\n\n  async authHeaders() {\n    return {\n      'access-token': await this.client.getAccessToken(),\n    }\n  }\n\n  protected async defaultHeaders() {\n    return {\n      Accept: 'application/json',\n      'Content-Type': 'application/json',\n      ...(await this.authHeaders()),\n    };\n  }\n}\n\nexport interface GraphAPIResponse {\n  response: {\n    statusLine: {\n      code?: number;\n      reasonPhrase?: string;\n    };\n    headers: {\n      [key: string]: string;\n    };\n    body: string;\n  };\n}\n","import { type Credentials, SessionCredentials } from './auth';\nimport { API_GATEWAY_URL, type Configuration, defaultConfig } from './config';\nimport * as Errors from './error';\nimport * as API from './resources';\nimport * as Robots from './robots';\nimport * as EventBus from './stream';\n\nexport class DingtalkClient {\n  clientId: string;\n\n  clientSecret: string;\n\n  baseUrl = API_GATEWAY_URL;\n\n  config: Configuration;\n\n  constructor(options: Configuration = {}) {\n    const config = Object.assign({}, defaultConfig, options);\n\n    if (!(config.clientId && config.clientSecret)) {\n      throw new Errors.InvalidArgumentError(\n        'Missing Access token or Secret key',\n      );\n    }\n\n    this.config = config;\n\n    this.clientId = config.clientId;\n    this.clientSecret = config.clientSecret;\n  }\n\n  session = new SessionCredentials(this);\n\n  uploader = new API.Uploader(this);\n\n  downloader = new API.Downloader(this);\n\n  card = new API.Card(this);\n\n  async post<T>(\n    url: string,\n    body?: BodyInit,\n    options?: Omit<RequestInit, 'body'>,\n  ): Promise<T> {\n    const headers = await this.defaultHeaders();\n\n    const resource = await fetch(`${this.baseUrl}${url}`, {\n      ...options,\n      method: 'POST',\n      headers: {\n        ...options?.headers,\n        ...headers,\n      },\n      body,\n    });\n\n    return await resource.json();\n  }\n\n  /**\n   * 获取临时授权码\n   *\n   * @returns 临时授权码\n   */\n  getAccessToken(): Promise<string> {\n    return this.session.getAccessToken();\n  }\n\n  /**\n   * 授权请求头\n   *\n   * @returns 授权请求头\n   */\n  async authHeaders(): Promise<Record<string, string>> {\n    const token = await this.getAccessToken();\n    console.log(token)\n\n    return {\n      'x-acs-dingtalk-access-token': token,\n    };\n  }\n\n  /**\n   * 默认请求头\n   *\n   * @returns 默认请求头\n   */\n  async defaultHeaders(): Promise<Record<string, string>> {\n    const authHeaders = await this.authHeaders();\n\n    return {\n      'Content-Type': 'application/json',\n      ...authHeaders,\n    };\n  }\n\n  static config = defaultConfig;\n\n  static SubscriptionType = EventBus.SubscriptionType;\n  static Subscriptions = EventBus.Subscriptions;\n\n  static SessionWebhook = Robots.SessionWebhook;\n  static CustomizeWebhook = Robots.CustomizeWebhook;\n\n  static IncomingType = Robots.Incoming.ContentType;\n  static OutgoingType = Robots.Outgoing.ContentType;\n}\n\nexport const {\n  DingtalkError,\n  InvalidArgumentError,\n  APIError,\n  APIUserAbortError,\n  APIConnectionError,\n  APIConnectionTimeoutError,\n  BadRequestError,\n  AuthenticationError,\n  PermissionDeniedError,\n  NotFoundError,\n  ConflictError,\n  UnprocessableEntityError,\n  InternalServerError,\n} = Errors;\n\nexport const { StreamClient, SubscriptionType } = EventBus;\n\nexport const { SessionWebhook, CustomizeWebhook } = Robots;\n\nexport const { Downloader, Uploader } = API;\n\nexport { SessionCredentials, type Credentials };\n\nexport type RichTextSectionImage = Robots.Incoming.RichText.ImageSection;\n\nexport namespace DingtalkClient {\n  export type MediaType = API.MediaType;\n\n  export type Uploader = API.Uploader;\n  export type UploadResult = API.UploadResult;\n\n  export type Downloader = API.Downloader;\n\n  export type SubscriptionType = EventBus.SubscriptionType;\n  export type SubscriptionItem = EventBus.SubscriptionItem;\n\n  export type IncomingMessage = Robots.IncomingMessage;\n\n  export type RichTextSectionImage = Robots.Incoming.RichText.ImageSection;\n}\n\nexport default DingtalkClient;\n"],"names":["CLIENT_ID","SECRET_KEY","API_GATEWAY_URL","OPEN_API_GATEWAY_URL","defaultConfig","sha256","data","key","encoding","createHmac","castToError","err","safeJSON","text","DingtalkError","InvalidResultError","APIError","status","error","message","headers","msg","errorResponse","APIConnectionError","BadRequestError","AuthenticationError","PermissionDeniedError","NotFoundError","ConflictError","UnprocessableEntityError","InternalServerError","cause","assertResultSync","result","assertResponse","response","errText","e","errJSON","errMessage","simple_post_json","input","body","init","request","simple_json","SessionCredentials","credentials","#cache","#expiredAt","#promise","res","promise","clientId","clientSecret","url","searchParams","APIResource","client","Instances","params","resultInit","OpenDynamicDataConfig","PullStrategy","TimeUnit","I18n","Language","Card","InstancesAPI.Instances","downloadCode","robotCode","filePath","stream","name","filename","resolveNameFromURl","path","os","writeStream","createWriteStream","Readable","finished","pathname","type","readFileSync","form","Outgoing","ActionCardButtonOrientation","ContentType","Incoming","debug","debuglog","CustomizeWebhook$1","settings","sayable","timestamp","stringToSign","signature","SessionWebhook$1","SayableSayer","mentionList","userIds","id","userId","Robot","incoming","chatbotUserId","chatbotCorpId","sessionWebhook","sessionWebhookExpiredTime","SessionWebhook","Room","properties","Talker","IncomingMessage","conversationId","conversationType","msgId","msgtype","createAt","resolveTextContent","downloader","item","SubscriptionType","Subscriptions","SubscriptionManager","DEFAULT_PING_INTERVAL_IN_MS","EventEmitter","options","keepAliveIntervalInMilliseconds","subscriptions","#subscriptions","#keepAliveIntervalInMilliseconds","#socket","#connected","#living","#keepAliveTimerId","endpoint","ticket","connection","WebSocket","event","messageId","value","socket","callback","DingtalkClient","config","Errors.InvalidArgumentError","API.Uploader","API.Downloader","API.Card","token","EventBus.SubscriptionType","EventBus.Subscriptions","Robots.SessionWebhook","Robots.CustomizeWebhook","Robots.Incoming","Robots.Outgoing","InvalidArgumentError","APIUserAbortError","APIConnectionTimeoutError","Errors","StreamClient","EventBus","CustomizeWebhook","Robots","Downloader","Uploader","API"],"mappings":"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"}