refactor(jira): group attachment modules with concrete owner imports (#31683)

This commit is contained in:
Neil
2026-10-21 16:19:40 -07:00
committed by GitHub
parent fcac5cf0f0
commit 926decd2f1
25 changed files with 143 additions and 113 deletions
+14 -8
View File
@@ -21,6 +21,18 @@ const {
vi.mock('./request-queue', () => ({ acquire: acquireMock, release: releaseMock }))
const { JiraApiError: JiraApiErrorMock } = vi.hoisted(() => ({
JiraApiError: class JiraApiError extends Error {
status: number | null
constructor(message: string, status: number | null = null) {
super(message)
this.status = status
}
}
}))
vi.mock('./jira-api-error', () => ({ JiraApiError: JiraApiErrorMock }))
vi.mock('./authenticated-request', () => ({
apiBasePath: (site: { authType?: string }) =>
site.authType === 'server' ? '/rest/api/2' : '/rest/api/3',
@@ -29,13 +41,7 @@ vi.mock('./authenticated-request', () => ({
isAuthError: (...args: unknown[]) => isAuthErrorMock(...args),
jiraRequest: (...args: unknown[]) => jiraRequestMock(...args),
jiraRequestBinary: (...args: unknown[]) => jiraRequestBinaryMock(...args),
JiraApiError: class JiraApiError extends Error {
status: number | null
constructor(message: string, status: number | null = null) {
super(message)
this.status = status
}
}
JiraApiError: JiraApiErrorMock
}))
vi.mock('./client', () => ({
@@ -80,7 +86,7 @@ describe('Jira ADF link mark mapping', () => {
releaseMock.mockImplementation(() => {})
jiraRequestBinaryMock.mockReset()
jiraRequestMock.mockReset()
const { _resetAttachmentImageCache } = await import('./attachment-image-cache')
const { _resetAttachmentImageCache } = await import('./attachments/image-cache')
_resetAttachmentImageCache()
})
@@ -1,7 +1,7 @@
import type { JiraSite } from '../../shared/jira-types'
import { apiBasePath } from './authenticated-request'
import { isJiraGatewayBaseUrl } from './gateway-base-url'
import type { AttachmentMeta } from './attachment-meta'
import type { JiraSite } from '../../../shared/jira-types'
import { apiBasePath } from '../authenticated-request'
import { isJiraGatewayBaseUrl } from '../gateway-base-url'
import type { AttachmentMeta } from './meta'
export function attachmentContentUrl(site: JiraSite, meta: AttachmentMeta): URL | null {
if (!meta.contentUrl && site.authType === 'server') {
@@ -1,5 +1,5 @@
import type { JiraAdfMediaAttrs } from './adf-markdown'
import { MAX_IMAGES, parseImageAttachmentMetas } from './attachment-meta'
import type { JiraAdfMediaAttrs } from '../adf-markdown'
import { MAX_IMAGES, parseImageAttachmentMetas } from './meta'
/**
* Pull attachment content IDs from Jira rendered HTML in document order.
@@ -1,20 +1,20 @@
import { jiraRequestBinary, type JiraClientForSite } from './authenticated-request'
import type { AttachmentMeta } from './attachment-meta'
import { attachmentContentUrl } from './attachment-content-url'
import { jiraRequestBinary, type JiraClientForSite } from '../authenticated-request'
import type { AttachmentMeta } from './meta'
import { attachmentContentUrl } from './content-url'
import {
loadAttachmentBytesWithCache,
type AttachmentImageBytes,
attachmentImagesEpoch,
getCachedAttachmentBytes
} from './attachment-image-cache'
} from './image-cache'
import {
JIRA_IMAGE_MAX_BYTES,
JIRA_IMAGE_MAX_PENDING_READS,
isJiraImageMimeType
} from '../../shared/jira-attachment-image'
import { withJiraDeadline } from './jira-read-failure'
import { PrioritySemaphore } from '../../shared/priority-semaphore'
import { waitForPromiseWithSignal } from '../../shared/abort-signal-reason'
} from '../../../shared/jira-attachment-image'
import { withJiraDeadline } from '../jira-read-failure'
import { PrioritySemaphore } from '../../../shared/priority-semaphore'
import { waitForPromiseWithSignal } from '../../../shared/abort-signal-reason'
const downloads = new PrioritySemaphore(3)
const interests = new Map<string, { controller: AbortController; readers: number }>()
@@ -4,7 +4,7 @@ import {
clearAttachmentImagesForSite,
getCachedAttachmentDataUrl,
loadAttachmentDataUrlWithCache
} from './attachment-image-cache'
} from './image-cache'
type Image = { dataUrl: string; byteSize: number } | null
function deferredImage() {
@@ -1,5 +1,5 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { MAX_TIMER_DELAY_MS } from '../../shared/timer-delay'
import { MAX_TIMER_DELAY_MS } from '../../../shared/timer-delay'
import {
_getAttachmentImageCacheSize,
_resetAttachmentImageCache,
@@ -7,7 +7,7 @@ import {
getCachedAttachmentDataUrl,
loadAttachmentDataUrlWithCache,
setCachedAttachmentDataUrl
} from './attachment-image-cache'
} from './image-cache'
describe('attachment image cache', () => {
beforeEach(() => {
@@ -1,6 +1,6 @@
// Description, comments, and lazy image reads share one bounded cache.
import { MAX_TIMER_DELAY_MS } from '../../shared/timer-delay'
import { MAX_TIMER_DELAY_MS } from '../../../shared/timer-delay'
const CACHE_TTL_MS = 30 * 60_000
const MAX_CACHE_ENTRIES = 96
@@ -1,8 +1,8 @@
import { randomUUID } from 'node:crypto'
import { JIRA_IMAGE_SCHEME } from '../../shared/jira-attachment-image'
import { attachmentImagesEpoch } from './attachment-image-cache'
import type { JiraClientForSite } from './authenticated-request'
import type { AttachmentMeta } from './attachment-meta'
import { JIRA_IMAGE_SCHEME } from '../../../shared/jira-attachment-image'
import { attachmentImagesEpoch } from './image-cache'
import type { JiraClientForSite } from '../authenticated-request'
import type { AttachmentMeta } from './meta'
const GRANT_TTL_MS = 30 * 60_000
const MAX_GRANTS = 2048
@@ -1,6 +1,6 @@
import { protocol } from 'electron'
import { JIRA_IMAGE_SCHEME, jiraImageReference } from '../../shared/jira-attachment-image'
import { readGrantedAttachmentImage } from './attachment-image-read'
import { JIRA_IMAGE_SCHEME, jiraImageReference } from '../../../shared/jira-attachment-image'
import { readGrantedAttachmentImage } from './image-read'
export const JIRA_IMAGE_CUSTOM_SCHEME: Electron.CustomScheme = {
scheme: JIRA_IMAGE_SCHEME,
@@ -1,22 +1,22 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { JiraClientForSite } from './authenticated-request'
import { JIRA_IMAGE_MAX_PENDING_READS } from '../../shared/jira-attachment-image'
import { readAttachmentImageBytes } from './attachment-image-bytes'
import type { JiraClientForSite } from '../authenticated-request'
import { JIRA_IMAGE_MAX_PENDING_READS } from '../../../shared/jira-attachment-image'
import { readAttachmentImageBytes } from './image-bytes'
import {
registerAttachmentImageGrant,
attachmentImageGrant,
resetAttachmentImageGrantsForTest
} from './attachment-image-grants'
import { readGrantedAttachmentImage } from './attachment-image-read'
import { handleJiraImageRequest } from './attachment-image-protocol'
import { clearAttachmentImagesForSite, _resetAttachmentImageCache } from './attachment-image-cache'
} from './image-grants'
import { readGrantedAttachmentImage } from './image-read'
import { handleJiraImageRequest } from './image-protocol'
import { clearAttachmentImagesForSite, _resetAttachmentImageCache } from './image-cache'
const { binary, clients } = vi.hoisted(() => ({ binary: vi.fn(), clients: vi.fn() }))
vi.mock('./authenticated-request', () => ({
vi.mock('../authenticated-request', () => ({
apiBasePath: () => '/rest/api/3',
jiraRequestBinary: binary
}))
vi.mock('./client', () => ({ getClients: clients }))
vi.mock('../client', () => ({ getClients: clients }))
vi.mock('electron', () => ({ protocol: { handle: vi.fn() } }))
const client: JiraClientForSite = {
site: { id: 'site', siteUrl: 'https://jira.test', email: '', accountId: '', displayName: '' },
@@ -1,7 +1,7 @@
import { getClients } from './client'
import { attachmentImageGrant, isAttachmentImageGrantCurrent } from './attachment-image-grants'
import { readAttachmentImageBytes } from './attachment-image-bytes'
import type { AttachmentImageBytes } from './attachment-image-cache'
import { getClients } from '../client'
import { attachmentImageGrant, isAttachmentImageGrantCurrent } from './image-grants'
import { readAttachmentImageBytes } from './image-bytes'
import type { AttachmentImageBytes } from './image-cache'
export async function readGrantedAttachmentImage(
reference: string,
@@ -1,14 +1,20 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { JIRA_IMAGE_MAX_BYTES } from '../../shared/jira-attachment-image'
import { loadIssueImageAttachments, createMediaMarkdownResolver } from './attachment-images'
import { attachmentImageGrant, resetAttachmentImageGrantsForTest } from './attachment-image-grants'
import { clearAttachmentImagesForSite, _resetAttachmentImageCache } from './attachment-image-cache'
import type { JiraClientForSite } from './authenticated-request'
import { JIRA_IMAGE_MAX_BYTES } from '../../../shared/jira-attachment-image'
import { loadIssueImageAttachments, createMediaMarkdownResolver } from './images'
import { attachmentImageGrant, resetAttachmentImageGrantsForTest } from './image-grants'
import { clearAttachmentImagesForSite, _resetAttachmentImageCache } from './image-cache'
import type { JiraClientForSite } from '../authenticated-request'
vi.mock('./authenticated-request', () => ({
const { JiraApiError: JiraApiErrorMock } = vi.hoisted(() => ({
JiraApiError: class extends Error {}
}))
vi.mock('../jira-api-error', () => ({ JiraApiError: JiraApiErrorMock }))
vi.mock('../authenticated-request', () => ({
apiBasePath: () => '/rest/api/3',
jiraRequestBinary: vi.fn(),
JiraApiError: class extends Error {}
JiraApiError: JiraApiErrorMock
}))
const client: JiraClientForSite = {
site: {
@@ -37,7 +43,7 @@ describe('lazy Jira image references', () => {
vi.clearAllMocks()
})
it('keeps image bytes out of Markdown without downloading the attachment', async () => {
const { jiraRequestBinary } = await import('./authenticated-request')
const { jiraRequestBinary } = await import('../authenticated-request')
const images = await loadIssueImageAttachments(client, metadata, ['1'], 'reference')
const markdown = createMediaMarkdownResolver(images, ['1'])({ id: 'media-id', alt: 'shot.png' })
expect(markdown).toMatch(/^!\[shot.png\]\(orca-jira-image:\/\/attachment\/[0-9a-f-]+\)$/)
@@ -64,7 +70,7 @@ describe('lazy Jira image references', () => {
})
it('discovers larger images by filename when rendered HTML has no attachment IDs', async () => {
const { collectIssueMediaRequest } = await import('./jira-issue-media')
const { collectIssueMediaRequest } = await import('../jira-issue-media')
const raw = {
key: 'JIRA-1',
fields: {
@@ -85,7 +91,7 @@ it('discovers larger images by filename when rendered HTML has no attachment IDs
})
it('keeps the old per-image cap when an old client reuses a newer byte-cache entry', async () => {
const { loadAttachmentBytesWithCache } = await import('./attachment-image-cache')
const { loadAttachmentBytesWithCache } = await import('./image-cache')
_resetAttachmentImageCache()
await loadAttachmentBytesWithCache({
siteId: client.site.id,
@@ -1,14 +1,11 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { JiraClientForSite } from './authenticated-request'
import type { JiraClientForSite } from '../authenticated-request'
const { jiraRequestBinaryMock } = vi.hoisted(() => ({
jiraRequestBinaryMock: vi.fn()
}))
vi.mock('./authenticated-request', () => ({
jiraRequestBinary: (...args: unknown[]) => jiraRequestBinaryMock(...args),
apiBasePath: (site: { authType?: string }) =>
site.authType === 'server' ? '/rest/api/2' : '/rest/api/3',
const { JiraApiError: JiraApiErrorMock } = vi.hoisted(() => ({
JiraApiError: class JiraApiError extends Error {
status: number | null
constructor(message: string, status: number | null = null) {
@@ -18,6 +15,15 @@ vi.mock('./authenticated-request', () => ({
}
}))
vi.mock('../jira-api-error', () => ({ JiraApiError: JiraApiErrorMock }))
vi.mock('../authenticated-request', () => ({
jiraRequestBinary: (...args: unknown[]) => jiraRequestBinaryMock(...args),
apiBasePath: (site: { authType?: string }) =>
site.authType === 'server' ? '/rest/api/2' : '/rest/api/3',
JiraApiError: JiraApiErrorMock
}))
function makeEntry(): JiraClientForSite {
return {
site: {
@@ -34,12 +40,12 @@ function makeEntry(): JiraClientForSite {
describe('attachment image helpers', () => {
beforeEach(async () => {
jiraRequestBinaryMock.mockReset()
const { _resetAttachmentImageCache } = await import('./attachment-image-cache')
const { _resetAttachmentImageCache } = await import('./image-cache')
_resetAttachmentImageCache()
})
it('extracts attachment content ids from rendered HTML in order', async () => {
const { extractAttachmentContentIdsFromHtml } = await import('./attachment-discovery')
const { extractAttachmentContentIdsFromHtml } = await import('./discovery')
const ids = extractAttachmentContentIdsFromHtml(`
<p>intro</p>
<img src="https://example.atlassian.net/rest/api/3/attachment/content/101" />
@@ -50,7 +56,7 @@ describe('attachment image helpers', () => {
})
it('extracts thumbnail attachment ids', async () => {
const { extractAttachmentContentIdsFromHtml } = await import('./attachment-discovery')
const { extractAttachmentContentIdsFromHtml } = await import('./discovery')
expect(
extractAttachmentContentIdsFromHtml(
'<img src="https://example.atlassian.net/secure/thumbnail/10001/shot.png" />'
@@ -70,8 +76,7 @@ describe('attachment image helpers', () => {
contentType: 'image/png'
})
const { createMediaMarkdownResolver, loadIssueImageAttachments } =
await import('./attachment-images')
const { createMediaMarkdownResolver, loadIssueImageAttachments } = await import('./images')
const images = await loadIssueImageAttachments(
makeEntry(),
@@ -108,7 +113,7 @@ describe('attachment image helpers', () => {
})
it('pairs shared alt filenames to distinct attachments then falls through', async () => {
const { createMediaMarkdownResolver } = await import('./attachment-images')
const { createMediaMarkdownResolver } = await import('./images')
const images = [
{
id: '1',
@@ -132,7 +137,7 @@ describe('attachment image helpers', () => {
})
it('does not re-emit an already consumed attachment for a third shared-alt node', async () => {
const { createMediaMarkdownResolver } = await import('./attachment-images')
const { createMediaMarkdownResolver } = await import('./images')
const images = [
{
id: '1',
@@ -156,7 +161,7 @@ describe('attachment image helpers', () => {
})
it('escapes hostile external media URLs instead of injecting markdown', async () => {
const { createMediaMarkdownResolver } = await import('./attachment-images')
const { createMediaMarkdownResolver } = await import('./images')
const resolve = createMediaMarkdownResolver([], [])
const hostile = 'https://evil.example/x?a=1)![z](javascript:alert(1))'
const out = resolve({ url: hostile, alt: 'Image' })
@@ -168,14 +173,14 @@ describe('attachment image helpers', () => {
})
it('returns placeholder for external URLs that remain hostile after encode', async () => {
const { createMediaMarkdownResolver } = await import('./attachment-images')
const { createMediaMarkdownResolver } = await import('./images')
const resolve = createMediaMarkdownResolver([], [])
// non-http rejected
expect(resolve({ url: 'javascript:alert(1)', alt: 'x' })).toBe('*[x]*')
})
it('selects preferred ids via Option A filename fallback without sweeping all attachments', async () => {
const { selectPreferredAttachmentIds } = await import('./attachment-discovery')
const { selectPreferredAttachmentIds } = await import('./discovery')
const attachments = [
{ id: '1', filename: 'a.png', mimeType: 'image/png', size: 1 },
{ id: '2', filename: 'b.png', mimeType: 'image/png', size: 1 },
@@ -200,7 +205,7 @@ describe('attachment image helpers', () => {
})
it('Option A unions multiple same-filename attachments for repeated alts', async () => {
const { selectPreferredAttachmentIds } = await import('./attachment-discovery')
const { selectPreferredAttachmentIds } = await import('./discovery')
const attachments = [
{ id: '1', filename: 'image.png', mimeType: 'image/png', size: 1 },
{ id: '2', filename: 'image.png', mimeType: 'image/png', size: 1 }
@@ -226,7 +231,7 @@ describe('attachment image helpers', () => {
data: Uint8Array.from([1]).buffer,
contentType: 'image/png'
})
const { loadIssueImageAttachments } = await import('./attachment-images')
const { loadIssueImageAttachments } = await import('./images')
const attachments = Array.from({ length: 13 }, (_, index) => ({
id: String(index + 1),
filename: `${index + 1}.png`,
@@ -245,7 +250,7 @@ describe('attachment image helpers', () => {
})
it('does not download attachments when rendered content references none', async () => {
const { loadIssueImageAttachments } = await import('./attachment-images')
const { loadIssueImageAttachments } = await import('./images')
await expect(
loadIssueImageAttachments(
@@ -268,7 +273,7 @@ describe('attachment image helpers', () => {
siteUrl: 'https://jira.example.com/jira',
authType: 'server'
}
const { loadIssueImageAttachments } = await import('./attachment-images')
const { loadIssueImageAttachments } = await import('./images')
await loadIssueImageAttachments(
entry,
@@ -291,7 +296,7 @@ describe('attachment image helpers', () => {
})
it('skips oversized and non-image attachments', async () => {
const { parseImageAttachmentMetas } = await import('./attachment-meta')
const { parseImageAttachmentMetas } = await import('./meta')
expect(
parseImageAttachmentMetas([
{ id: '1', filename: 'big.png', mimeType: 'image/png', size: 20 * 1024 * 1024 },
@@ -306,7 +311,7 @@ describe('attachment image helpers', () => {
data: Uint8Array.from([1, 2, 3]).buffer,
contentType: 'image/png'
})
const { loadIssueImageAttachments } = await import('./attachment-images')
const { loadIssueImageAttachments } = await import('./images')
const entry = makeEntry()
const field = [{ id: '9', filename: 'c.png', mimeType: 'image/png', size: 3 }]
await loadIssueImageAttachments(entry, field, ['9'])
@@ -322,7 +327,7 @@ describe('attachment image helpers', () => {
resolveDownload = resolve
})
)
const { loadIssueImageAttachments } = await import('./attachment-images')
const { loadIssueImageAttachments } = await import('./images')
const entry = makeEntry()
const field = [{ id: '7', filename: 's.png', mimeType: 'image/png', size: 1 }]
const p1 = loadIssueImageAttachments(entry, field, ['7'])
@@ -336,7 +341,7 @@ describe('attachment image helpers', () => {
it('warns when media resolution is incomplete', async () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
const { warnIfMediaResolutionIncomplete } = await import('./attachment-discovery')
const { warnIfMediaResolutionIncomplete } = await import('./discovery')
warnIfMediaResolutionIncomplete({
siteId: 's',
issueKey: 'ABC-1',
@@ -1,10 +1,11 @@
import type { JiraClientForSite } from './authenticated-request'
import { attachmentContentUrl } from './attachment-content-url'
import { JiraApiError, jiraRequestBinary } from './authenticated-request'
import type { JiraAdfMediaAttrs, JiraAdfMediaResolver } from './adf-markdown'
import { escapeMarkdownAlt, unresolvedMediaPlaceholder } from './adf-markdown'
import { escapeMarkdownLinkDestination } from './adf-media-destination'
import { loadAttachmentDataUrlWithCache } from './attachment-image-cache'
import type { JiraClientForSite } from '../authenticated-request'
import { attachmentContentUrl } from './content-url'
import { jiraRequestBinary } from '../authenticated-request'
import { JiraApiError } from '../jira-api-error'
import type { JiraAdfMediaAttrs, JiraAdfMediaResolver } from '../adf-markdown'
import { escapeMarkdownAlt, unresolvedMediaPlaceholder } from '../adf-markdown'
import { escapeMarkdownLinkDestination } from '../adf-media-destination'
import { loadAttachmentDataUrlWithCache } from './image-cache'
import {
MAX_IMAGE_BYTES,
MAX_IMAGES,
@@ -12,14 +13,14 @@ import {
parseImageAttachmentMetas,
isImageMimeType,
type AttachmentMeta
} from './attachment-meta'
import { mapWithConcurrency } from '../../shared/map-with-concurrency'
} from './meta'
import { mapWithConcurrency } from '../../../shared/map-with-concurrency'
import {
JIRA_IMAGE_MAX_BYTES,
JIRA_IMAGE_MAX_REFERENCES,
type JiraMediaFormat
} from '../../shared/jira-attachment-image'
import { registerAttachmentImageGrant } from './attachment-image-grants'
} from '../../../shared/jira-attachment-image'
import { registerAttachmentImageGrant } from './image-grants'
const DOWNLOAD_CONCURRENCY = 3
@@ -1,14 +1,20 @@
import { afterEach, beforeEach, expect, it, vi } from 'vitest'
import { readAttachmentImageBytes } from './attachment-image-bytes'
import { loadIssueImageAttachments, type JiraImageAttachment } from './attachment-images'
import * as cache from './attachment-image-cache'
import type { JiraClientForSite } from './authenticated-request'
import { readAttachmentImageBytes } from './image-bytes'
import { loadIssueImageAttachments, type JiraImageAttachment } from './images'
import * as cache from './image-cache'
import type { JiraClientForSite } from '../authenticated-request'
const { binary } = vi.hoisted(() => ({ binary: vi.fn() }))
vi.mock('./authenticated-request', () => ({
const { JiraApiError: JiraApiErrorMock } = vi.hoisted(() => ({
JiraApiError: class extends Error {}
}))
vi.mock('../jira-api-error', () => ({ JiraApiError: JiraApiErrorMock }))
vi.mock('../authenticated-request', () => ({
apiBasePath: () => '/rest/api/3',
jiraRequestBinary: binary,
JiraApiError: class extends Error {}
JiraApiError: JiraApiErrorMock
}))
const client: JiraClientForSite = {
+1 -1
View File
@@ -91,7 +91,7 @@ describe('scoped Jira Cloud tokens over HTTP', () => {
if (!client) {
throw new Error('Expected connected Jira client')
}
const cache = await import('./attachment-image-cache')
const cache = await import('./attachments/image-cache')
cache.setCachedAttachmentDataUrl({
siteId: client.site.id,
attachmentId: 'image',
+1 -1
View File
@@ -7,7 +7,7 @@ import type {
JiraSiteSelection,
JiraViewer
} from '../../shared/jira-types'
import { clearAttachmentImagesForSite } from './attachment-image-cache'
import { clearAttachmentImagesForSite } from './attachments/image-cache'
import { acquire, release } from './request-queue'
import {
getCredentialError,
+12 -6
View File
@@ -28,11 +28,7 @@ vi.mock('./jira-agile-fields', () => ({
vi.mock('./request-queue', () => ({ acquire: acquireMock, release: releaseMock }))
vi.mock('./authenticated-request', () => ({
apiBasePath: (site: { authType?: string }) =>
site.authType === 'server' ? '/rest/api/2' : '/rest/api/3',
jiraRequest: (...args: unknown[]) => jiraRequestMock(...args),
jiraRequestBinary: (...args: unknown[]) => jiraRequestBinaryMock(...args),
const { JiraApiError: JiraApiErrorMock } = vi.hoisted(() => ({
JiraApiError: class JiraApiError extends Error {
status: number | null
constructor(message: string, status: number | null = null) {
@@ -42,6 +38,16 @@ vi.mock('./authenticated-request', () => ({
}
}))
vi.mock('./jira-api-error', () => ({ JiraApiError: JiraApiErrorMock }))
vi.mock('./authenticated-request', () => ({
apiBasePath: (site: { authType?: string }) =>
site.authType === 'server' ? '/rest/api/2' : '/rest/api/3',
jiraRequest: (...args: unknown[]) => jiraRequestMock(...args),
jiraRequestBinary: (...args: unknown[]) => jiraRequestBinaryMock(...args),
JiraApiError: JiraApiErrorMock
}))
vi.mock('./client', () => ({
clearToken: (...args: unknown[]) => clearTokenMock(...args),
getClients: (...args: unknown[]) => getClientsMock(...args),
@@ -84,7 +90,7 @@ describe('Jira issue operations', () => {
releaseMock.mockImplementation(() => {})
jiraRequestBinaryMock.mockReset()
jiraRequestMock.mockReset()
const { _resetAttachmentImageCache } = await import('./attachment-image-cache')
const { _resetAttachmentImageCache } = await import('./attachments/image-cache')
_resetAttachmentImageCache()
})
+1 -1
View File
@@ -17,7 +17,7 @@ import {
import {
extractAttachmentContentIdsFromHtml,
selectPreferredAttachmentIds
} from './attachment-discovery'
} from './attachments/discovery'
import { mapUser } from './jira-issue-mapping'
import {
flushMediaResolutionWarn,
+2 -2
View File
@@ -3,12 +3,12 @@ import {
extractAttachmentContentIdsFromHtml,
selectPreferredAttachmentIds,
warnIfMediaResolutionIncomplete
} from './attachment-discovery'
} from './attachments/discovery'
import {
createMediaMarkdownResolver,
loadIssueImageAttachments,
type MediaResolutionStats
} from './attachment-images'
} from './attachments/images'
import type { JiraClientForSite } from './authenticated-request'
import { asRecord, asString, type JiraRecord } from './jira-record-pages'
import {
@@ -6,15 +6,15 @@ import { JIRA_ATTACHMENT_IMAGE_METHODS } from './jira-attachment-image'
import {
registerAttachmentImageGrant,
resetAttachmentImageGrantsForTest
} from '../../../jira/attachment-image-grants'
} from '../../../jira/attachments/image-grants'
import {
clearAttachmentImagesForSite,
_resetAttachmentImageCache
} from '../../../jira/attachment-image-cache'
} from '../../../jira/attachments/image-cache'
import { decodeJiraImageFrame } from '../../../../shared/jira-image-stream-frame'
const { read } = vi.hoisted(() => ({ read: vi.fn() }))
vi.mock('../../../jira/attachment-image-read', () => ({ readGrantedAttachmentImage: read }))
vi.mock('../../../jira/attachments/image-read', () => ({ readGrantedAttachmentImage: read }))
const transferId = '12345678-1234-4234-8234-123456789012'
const runtime = { getRuntimeId: () => 'runtime' }
const dispatcher = new RpcDispatcher({
@@ -5,8 +5,8 @@ import { throwIfSignalAborted } from '../../../../shared/abort-signal-reason'
import {
attachmentImageGrant,
isAttachmentImageGrantCurrent
} from '../../../jira/attachment-image-grants'
import { readGrantedAttachmentImage } from '../../../jira/attachment-image-read'
} from '../../../jira/attachments/image-grants'
import { readGrantedAttachmentImage } from '../../../jira/attachments/image-read'
import { AttachmentImage } from '../../../../shared/rpc-contract/jira-params'
import { defineStreamingMethod } from '../core'
+1 -1
View File
@@ -86,7 +86,7 @@ import { initOpenCodeUsagePath } from '../opencode-usage/store'
import { initMuseUsagePath } from '../muse-usage/store'
import { registerDocPreviewSchemePrivileges } from '../browser/doc-preview-protocol'
import { MEDIA_PREVIEW_CUSTOM_SCHEME } from '../media/media-preview-protocol'
import { JIRA_IMAGE_CUSTOM_SCHEME } from '../jira/attachment-image-protocol'
import { JIRA_IMAGE_CUSTOM_SCHEME } from '../jira/attachments/image-protocol'
import { startCrashpadCapture } from '../crash-reporting/crashpad-capture'
import { CrashReportStore } from '../crash-reporting/crash-report-store'
import { recordCrashBreadcrumb } from '../crash-reporting/crash-breadcrumb-store'
@@ -38,7 +38,7 @@ import {
} from '../browser/browser-session-proxy'
import { installDocPreviewProtocolHandler } from '../browser/doc-preview-protocol'
import { installMediaPreviewProtocolHandler } from '../media/media-preview-protocol'
import { installJiraImageProtocolHandler } from '../jira/attachment-image-protocol'
import { installJiraImageProtocolHandler } from '../jira/attachments/image-protocol'
import { registerDocPreviewGrantHandlers } from '../ipc/doc-preview-grant-ipc'
import { initializeBrowserSessionsForApp } from '../browser/browser-session-startup'
import { browserSessionRegistry } from '../browser/browser-session-registry'