{"version":3,"file":"jira.cjs","names":["Document","BaseDocumentLoader"],"sources":["../../../src/document_loaders/web/jira.ts"],"sourcesContent":["import { Document } from \"@langchain/core/documents\";\nimport { BaseDocumentLoader } from \"@langchain/core/document_loaders/base\";\n\nexport type JiraStatusCategory = {\n  self: string;\n  id: number;\n  key: string;\n  colorName: string;\n  name: string;\n};\n\nexport type JiraStatus = {\n  self: string;\n  description: string;\n  iconUrl: string;\n  name: string;\n  id: string;\n  statusCategory: JiraStatusCategory;\n};\n\nexport type JiraUser = {\n  accountId: string;\n  accountType: string;\n  active: boolean;\n  avatarUrls: {\n    \"16x16\": string;\n    \"24x24\": string;\n    \"32x32\": string;\n    \"48x48\": string;\n  };\n  displayName: string;\n  emailAddress: string;\n  self: string;\n  timeZone: string;\n};\n\nexport type JiraIssueType = {\n  avatarId: number;\n  description: string;\n  entityId: string;\n  hierarchyLevel: number;\n  iconUrl: string;\n  id: string;\n  name: string;\n  self: string;\n  subtask: boolean;\n};\n\nexport type JiraPriority = {\n  iconUrl: string;\n  id: string;\n  name: string;\n  self: string;\n};\n\nexport type JiraProgress = {\n  progress: number;\n  total: number;\n  percent?: number;\n};\n\nexport type JiraProject = {\n  avatarUrls: {\n    \"16x16\": string;\n    \"24x24\": string;\n    \"32x32\": string;\n    \"48x48\": string;\n  };\n  id: string;\n  key: string;\n  name: string;\n  projectTypeKey: string;\n  self: string;\n  simplified: boolean;\n};\n\nexport type JiraSubTask = {\n  id: string;\n  key: string;\n  self: string;\n  fields: {\n    issuetype: JiraIssueType;\n    priority: JiraPriority;\n    status: JiraStatus;\n    summary: string;\n  };\n};\n\nexport type JiraIssueLinkType = {\n  id: string;\n  name: string;\n  inward: string;\n  outward: string;\n  self: string;\n};\n\nexport type JiraBriefIssue = {\n  id: string;\n  key: string;\n  self: string;\n  fields: {\n    summary: string;\n    status: JiraStatus;\n    priority: JiraPriority;\n    issuetype: JiraIssueType;\n  };\n};\n\nexport type JiraIssueLink = {\n  id: string;\n  self: string;\n  type: JiraIssueLinkType;\n  inwardIssue?: JiraBriefIssue;\n  outwardIssue?: JiraBriefIssue;\n};\n\nexport type JiraIssue = {\n  expand: string;\n  id: string;\n  self: string;\n  key: string;\n  fields: {\n    assignee?: JiraUser;\n    created: string;\n    description: ADFNode;\n    issuelinks: JiraIssueLink[];\n    issuetype: JiraIssueType;\n    labels?: string[];\n    priority: JiraPriority;\n    progress: JiraProgress;\n    project: JiraProject;\n    reporter?: JiraUser;\n    creator: JiraUser;\n    resolutiondate?: string;\n    status: JiraStatus;\n    subtasks: JiraSubTask[];\n    summary: string;\n    timeestimate?: number;\n    timespent?: number;\n    updated: string;\n    duedate?: string;\n    parent?: JiraBriefIssue;\n  };\n};\n\nexport type JiraDescriptionFormatter = (\n  content: ADFNode | null | undefined,\n  issue?: JiraIssue\n) => string | ADFNode | null;\n\nexport type JiraAPIResponse = {\n  expand?: string;\n  startAt?: number;\n  maxResults?: number;\n  total?: number;\n  issues: JiraIssue[];\n  isLast?: boolean;\n  nextPageToken?: string;\n};\n\nexport interface ADFNode {\n  type: string;\n  text?: string;\n  content?: ADFNode[];\n  attrs?: Record<string, unknown>;\n}\n\nexport interface ADFDocument extends ADFNode {\n  type: \"doc\";\n  version: number;\n  content: ADFNode[];\n}\n\nexport function adfToText(adf: ADFNode | null | undefined): string {\n  if (!adf || !adf.content) return \"\";\n  const recur = (node: ADFNode): string => {\n    if (node.text) return node.text;\n    if (node.content) return node.content.map(recur).join(\"\");\n    return \"\";\n  };\n  return recur(adf).trim();\n}\n\nexport const formatJiraDescriptionAsJSON: JiraDescriptionFormatter = (\n  adfContent: ADFNode | null | undefined\n): ADFNode | null => {\n  if (!adfContent) return null;\n\n  const traverseNode = (node: ADFNode): ADFNode => {\n    if (typeof node === \"string\") return { type: \"text\", text: node };\n\n    const result: ADFNode = { type: node.type || \"unknown\" };\n    if (node.text) result.text = node.text;\n    if (node.attrs) result.attrs = node.attrs;\n    if (node.content) result.content = node.content.map(traverseNode);\n    return result;\n  };\n\n  return traverseNode(adfContent);\n};\n\nexport const formatJiraDescriptionAsText: JiraDescriptionFormatter = (\n  adfContent: ADFNode | null | undefined\n): string => {\n  if (!adfContent) return \"\";\n\n  const traverseNode = (node: ADFNode): string => {\n    if (node.text) return node.text;\n    if (node.content) return node.content.map(traverseNode).join(\"\");\n    return \"\";\n  };\n\n  return traverseNode(adfContent).trim();\n};\n\n/**\n * Interface representing the parameters for configuring the\n * JiraDocumentConverter.\n */\nexport interface JiraDocumentConverterParams {\n  host: string;\n  projectKey: string;\n  formatter?: JiraDescriptionFormatter;\n}\n\n/**\n * Class responsible for converting Jira issues to Document objects\n */\nexport class JiraDocumentConverter {\n  public readonly host: string;\n\n  public readonly projectKey: string;\n\n  private readonly formatter: JiraDescriptionFormatter;\n\n  constructor({ host, projectKey, formatter }: JiraDocumentConverterParams) {\n    this.host = host;\n    this.projectKey = projectKey;\n    this.formatter = formatter ?? formatJiraDescriptionAsText;\n  }\n\n  public convertToDocuments(issues: JiraIssue[]): Document[] {\n    return issues.map((issue) => this.documentFromIssue(issue));\n  }\n\n  private documentFromIssue(issue: JiraIssue): Document {\n    return new Document({\n      pageContent: this.formatIssueInfo({ issue, host: this.host }),\n      metadata: {\n        id: issue.id,\n        host: this.host,\n        projectKey: this.projectKey,\n        created: issue.fields.created,\n      },\n    });\n  }\n\n  private formatIssueInfo({\n    issue,\n    host,\n  }: {\n    issue: JiraIssue;\n    host: string;\n  }): string {\n    let text = `Issue: ${this.formatMainIssueInfoText({ issue, host })}\\n`;\n    text += `Project: ${issue.fields.project.name} (${issue.fields.project.key}, ID ${issue.fields.project.id})\\n`;\n    text += `Status: ${issue.fields.status.name}\\n`;\n    text += `Priority: ${issue.fields.priority.name}\\n`;\n    text += `Type: ${issue.fields.issuetype.name}\\n`;\n    text += `Creator: ${issue.fields.creator?.displayName}\\n`;\n\n    if (issue.fields.labels && issue.fields.labels.length > 0) {\n      text += `Labels: ${issue.fields.labels.join(\", \")}\\n`;\n    }\n\n    text += `Created: ${issue.fields.created}\\n`;\n    text += `Updated: ${issue.fields.updated}\\n`;\n\n    if (issue.fields.reporter) {\n      text += `Reporter: ${issue.fields.reporter.displayName}\\n`;\n    }\n\n    text += `Assignee: ${issue.fields.assignee?.displayName ?? \"Unassigned\"}\\n`;\n\n    if (issue.fields.duedate) {\n      text += `Due Date: ${issue.fields.duedate}\\n`;\n    }\n\n    if (issue.fields.timeestimate) {\n      text += `Time Estimate: ${issue.fields.timeestimate}\\n`;\n    }\n\n    if (issue.fields.timespent) {\n      text += `Time Spent: ${issue.fields.timespent}\\n`;\n    }\n\n    if (issue.fields.resolutiondate) {\n      text += `Resolution Date: ${issue.fields.resolutiondate}\\n`;\n    }\n\n    if (issue.fields.description) {\n      const formattedDescription = this.formatter(\n        issue.fields.description,\n        issue\n      );\n      const descText =\n        typeof formattedDescription === \"string\"\n          ? formattedDescription\n          : JSON.stringify(formattedDescription, null, 2);\n\n      text += `Description: ${descText}\\n`;\n    }\n\n    if (issue.fields.progress?.percent) {\n      text += `Progress: ${issue.fields.progress.percent}%\\n`;\n    }\n\n    if (issue.fields.parent) {\n      text += `Parent Issue: ${this.formatMainIssueInfoText({\n        issue: issue.fields.parent,\n        host,\n      })}\\n`;\n    }\n\n    if (issue.fields.subtasks?.length > 0) {\n      text += `Subtasks:\\n`;\n      issue.fields.subtasks.forEach((subtask) => {\n        text += `  - ${this.formatMainIssueInfoText({\n          issue: subtask,\n          host,\n        })}\\n`;\n      });\n    }\n\n    if (issue.fields.issuelinks?.length > 0) {\n      text += `Issue Links:\\n`;\n      issue.fields.issuelinks.forEach((link) => {\n        text += `  - ${link.type.name}\\n`;\n        if (link.inwardIssue) {\n          text += `    - ${this.formatMainIssueInfoText({\n            issue: link.inwardIssue,\n            host,\n          })}\\n`;\n        }\n        if (link.outwardIssue) {\n          text += `    - ${this.formatMainIssueInfoText({\n            issue: link.outwardIssue,\n            host,\n          })}\\n`;\n        }\n      });\n    }\n\n    return text;\n  }\n\n  private getLinkToIssue({\n    issueKey,\n    host,\n  }: {\n    issueKey: string;\n    host: string;\n  }): string {\n    return `${host}/browse/${issueKey}`;\n  }\n\n  private formatMainIssueInfoText({\n    issue,\n    host,\n  }: {\n    issue: JiraIssue | JiraBriefIssue;\n    host: string;\n  }): string {\n    const link = this.getLinkToIssue({\n      issueKey: issue.key,\n      host,\n    });\n\n    const text = `${issue.key} (ID ${issue.id}) - ${issue.fields.summary} (${link})`;\n\n    return text;\n  }\n}\n\n/**\n * Interface representing the parameters for configuring the\n * JiraProjectLoader.\n */\nexport interface JiraProjectLoaderParams {\n  host: string;\n  projectKey: string;\n  username?: string;\n  accessToken?: string;\n  personalAccessToken?: string;\n  limitPerRequest?: number;\n  createdAfter?: Date;\n  filterFn?: (issue: JiraIssue) => boolean;\n  descriptionFormatter?: JiraDescriptionFormatter;\n\n  /**\n   * Optional custom JQL query. When provided, this replaces the\n   * auto-generated `project = <projectKey>` query entirely, giving\n   * full control over filtering, sorting, and scoping.\n   *\n   * Examples:\n   *   \"project = AC AND status = 'In Progress'\"\n   *   \"project = AC AND sprint in openSprints() ORDER BY priority DESC\"\n   *   \"assignee = currentUser() AND updated >= -7d\"\n   *\n   * Note: `createdAfter` is ignored when `jql` is provided — include\n   * any date filters directly in your JQL string.\n   */\n  jql?: string;\n\n  /**\n   * Maximum total number of issues to fetch across all pages.\n   * When set, pagination stops early once this limit is reached.\n   * Without this, the loader fetches every issue matching the query.\n   *\n   * Note: `limitPerRequest` controls the page size (how many issues\n   * per API call), while `maxTotal` controls the overall cap.\n   */\n  maxTotal?: number;\n}\n\n/**\n * Class representing a document loader for loading issues from Jira.\n */\nexport class JiraProjectLoader extends BaseDocumentLoader {\n  private readonly accessToken?: string;\n\n  public readonly host: string;\n\n  public readonly projectKey: string;\n\n  public readonly username?: string;\n\n  public readonly limitPerRequest: number;\n\n  private readonly createdAfter?: Date;\n\n  private readonly filterFn?: (issue: JiraIssue) => boolean;\n\n  private readonly documentConverter: JiraDocumentConverter;\n\n  private readonly personalAccessToken?: string;\n\n  private readonly jql?: string;\n\n  private readonly maxTotal?: number;\n\n  constructor({\n    host,\n    projectKey,\n    username,\n    accessToken,\n    limitPerRequest = 100,\n    createdAfter,\n    personalAccessToken,\n    filterFn,\n    descriptionFormatter: formatter,\n    jql,\n    maxTotal,\n  }: JiraProjectLoaderParams) {\n    super();\n    this.host = host;\n    this.projectKey = projectKey;\n    this.username = username;\n    this.accessToken = accessToken;\n    this.limitPerRequest = limitPerRequest;\n    this.createdAfter = createdAfter;\n    this.documentConverter = new JiraDocumentConverter({\n      host,\n      projectKey,\n      formatter,\n    });\n    this.personalAccessToken = personalAccessToken;\n    this.filterFn = filterFn;\n    this.jql = jql;\n    this.maxTotal = maxTotal;\n  }\n\n  private buildAuthorizationHeader(): string {\n    if (this.personalAccessToken) {\n      return `Bearer ${this.personalAccessToken}`;\n    }\n    return `Basic ${Buffer.from(\n      `${this.username}:${this.accessToken}`\n    ).toString(\"base64\")}`;\n  }\n\n  public async load(): Promise<Document[]> {\n    const allJiraIssues = await this.loadAsIssues();\n    const filtered = allJiraIssues.filter((issue) => {\n      if (this.filterFn) {\n        return this.filterFn(issue);\n      }\n      return true;\n    });\n    return this.documentConverter.convertToDocuments(filtered);\n  }\n\n  public async loadAsIssues(): Promise<JiraIssue[]> {\n    const allIssues: JiraIssue[] = [];\n\n    for await (const issues of this.fetchIssues()) {\n      allIssues.push(...issues);\n      if (this.maxTotal && allIssues.length >= this.maxTotal) {\n        return allIssues.slice(0, this.maxTotal);\n      }\n    }\n\n    return allIssues;\n  }\n\n  protected toJiraDateString(date: Date | undefined): string | undefined {\n    if (!date) {\n      return undefined;\n    }\n    const year = date.getUTCFullYear();\n    const month = String(date.getUTCMonth() + 1).padStart(2, \"0\");\n    const dayOfMonth = String(date.getUTCDate()).padStart(2, \"0\");\n    return `${year}-${month}-${dayOfMonth}`;\n  }\n\n  private buildJql(): string {\n    // If custom JQL is provided, use it directly\n    if (this.jql) {\n      return this.jql;\n    }\n\n    // Otherwise, build JQL from projectKey and createdAfter\n    const createdAfterAsString = this.toJiraDateString(this.createdAfter);\n    const jqlParts = [\n      `project = ${this.projectKey}`,\n      ...(createdAfterAsString ? [`created >= \"${createdAfterAsString}\"`] : []),\n    ];\n    return `${jqlParts.join(\" AND \")} ORDER BY created ASC, key ASC`;\n  }\n\n  protected async *fetchIssues(): AsyncIterable<JiraIssue[]> {\n    const authorizationHeader = this.buildAuthorizationHeader();\n    const url = `${this.host}/rest/api/3/search/jql`;\n    const jql = this.buildJql();\n\n    let nextPageToken: string | undefined;\n    let totalFetched = 0;\n\n    while (true) {\n      // If maxTotal is set, don't request more than we need\n      let pageSize = this.limitPerRequest;\n      if (this.maxTotal) {\n        const remaining = this.maxTotal - totalFetched;\n        if (remaining <= 0) break;\n        pageSize = Math.min(pageSize, remaining);\n      }\n\n      const body: Record<string, unknown> = {\n        jql,\n        maxResults: pageSize,\n        fields: [\"*all\"],\n      };\n\n      if (nextPageToken) {\n        body.nextPageToken = nextPageToken;\n      }\n\n      const response = await fetch(url, {\n        method: \"POST\",\n        headers: {\n          Authorization: authorizationHeader,\n          Accept: \"application/json\",\n          \"Content-Type\": \"application/json\",\n        },\n        body: JSON.stringify(body),\n      });\n\n      const data = await response.json();\n\n      if (!response.ok) {\n        throw new Error(\n          `Jira API request failed with status ${response.status}: ${JSON.stringify(data)}`\n        );\n      }\n\n      if (data.issues?.length) {\n        yield data.issues;\n        totalFetched += data.issues.length;\n      }\n\n      if (data.isLast === true) break;\n\n      if (!data.nextPageToken) {\n        throw new Error(\"Expected nextPageToken but none returned\");\n      }\n\n      nextPageToken = data.nextPageToken;\n    }\n  }\n}\n"],"mappings":"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"}