@shipfox/api-integration-jira 12.3.0 → 12.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  $ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
2
- Successfully compiled: 35 files with swc (436.44ms)
3
- 2026-08-07T08:46:34.151Z [INFO] asset workflow-bundle-0005de700a374d33c72a.js 3.17 MiB [emitted] [immutable] (name: main)
2
+ Successfully compiled: 35 files with swc (445.27ms)
3
+ 2026-08-08T09:16:49.166Z [INFO] asset workflow-bundle-0005de700a374d33c72a.js 3.17 MiB [emitted] [immutable] (name: main)
4
4
  orphan modules 33.5 KiB [orphan] 21 modules
5
5
  runtime modules 1.13 KiB 5 modules
6
6
  modules by path ../../../../node_modules/.pnpm/ 970 KiB 196 modules
@@ -13,6 +13,6 @@ optional modules 30 bytes [optional]
13
13
  __temporal_custom_payload_converter (ignored) 15 bytes [optional] [built] [code generated]
14
14
  __temporal_custom_failure_converter (ignored) 15 bytes [optional] [built] [code generated]
15
15
  ../../../shared/node/temporal/dist/workflow-error-interceptor.js 1.21 KiB [built] [code generated]
16
- webpack 5.107.2 compiled successfully in 7008 ms
17
- 2026-08-07T08:46:34.170Z [INFO] Workflow bundle created { size: '3.17MB' }
16
+ webpack 5.107.2 compiled successfully in 8668 ms
17
+ 2026-08-08T09:16:49.200Z [INFO] Workflow bundle created { size: '3.17MB' }
18
18
  /home/runner/work/shipfox/shipfox/libs/api/integration/jira/dist/temporal/workflows/index.js: 3327328 bytes
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @shipfox/api-integration-jira
2
2
 
3
+ ## 12.4.0
4
+
5
+ ### Patch Changes
6
+
7
+ - a566809: Registers Jira dynamic webhooks with a non-empty all-issues JQL filter.
8
+
3
9
  ## 12.3.0
4
10
 
5
11
  ### Minor Changes
@@ -1,5 +1,5 @@
1
1
  export declare const JIRA_DYNAMIC_WEBHOOK_EVENTS: readonly ["jira:issue_created", "jira:issue_updated", "jira:issue_deleted", "comment_created", "comment_updated", "comment_deleted"];
2
- export declare const JIRA_DYNAMIC_WEBHOOK_JQL = "";
2
+ export declare const JIRA_DYNAMIC_WEBHOOK_JQL = "project != null";
3
3
  export interface JiraAuthorization {
4
4
  accessToken: string;
5
5
  refreshToken?: string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,2BAA2B,sIAAwB,CAAC;AACjE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IAC7B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,8BAA8B;IAC7C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,uBAAuB,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7D,MAAM,MAAM,uBAAuB,GAC/B,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAC5B,SAAS,CAAC;AAEd,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,uBAAuB,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,GAAG,SAAS,CAAC;IAC5D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACtE;AAED,MAAM,WAAW,aAAa;IAC5B,yBAAyB,CAAC,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC7E,kBAAkB,CAAC,KAAK,EAAE;QAAC,YAAY,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC9E,sBAAsB,CAAC,KAAK,EAAE;QAAC,WAAW,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAAC;IACxF,SAAS,CAAC,KAAK,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAChF,sBAAsB,CAAC,KAAK,EAAE;QAC5B,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;KACb,GAAG,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC5C,sBAAsB,CAAC,KAAK,EAAE;QAC5B,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;IAC9B,qBAAqB,CAAC,KAAK,EAAE;QAC3B,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,oBAAoB,CAAC,KAAK,EAAE;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AA0BD,wBAAgB,mBAAmB,IAAI,aAAa,CAoInD;AAED,wBAAgB,0BAA0B,IAAI,oBAAoB,CAEjE;AA4KD,wBAAsB,YAAY,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAyC9F"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,8 @@ const JIRA_API_TIMEOUT_MS = 10_000;
7
7
  const SCOPE_SEPARATOR_RE = /[,\s]+/;
8
8
  const TRAILING_SLASHES_RE = /\/+$/;
9
9
  export const JIRA_DYNAMIC_WEBHOOK_EVENTS = jiraWebhookEventNames;
10
- export const JIRA_DYNAMIC_WEBHOOK_JQL = '';
10
+ // Jira rejects an empty dynamic-webhook filter; every issue belongs to a project.
11
+ export const JIRA_DYNAMIC_WEBHOOK_JQL = 'project != null';
11
12
  const JIRA_REFRESH_TOKEN_TERMINAL_ERROR_CODES = new Set([
12
13
  'invalid_grant',
13
14
  'unauthorized_client'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/api/client.ts"],"sourcesContent":["import {jiraWebhookEventNames} from '@shipfox/api-integration-jira-dto';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport ky, {HTTPError, TimeoutError} from 'ky';\nimport {config} from '#config.js';\nimport {JiraIntegrationProviderError} from '#core/errors.js';\n\nconst JIRA_API_TIMEOUT_MS = 10_000;\nconst SCOPE_SEPARATOR_RE = /[,\\s]+/;\nconst TRAILING_SLASHES_RE = /\\/+$/;\nexport const JIRA_DYNAMIC_WEBHOOK_EVENTS = jiraWebhookEventNames;\nexport const JIRA_DYNAMIC_WEBHOOK_JQL = '';\n\nexport interface JiraAuthorization {\n accessToken: string;\n refreshToken?: string | undefined;\n expiresAt?: Date | undefined;\n scopes: string[];\n}\n\nexport interface JiraAccessibleResource {\n cloudId: string;\n name: string;\n url: string;\n scopes: string[];\n}\n\nexport interface JiraIdentity {\n accountId: string;\n}\n\nexport interface JiraDynamicWebhookRegistration {\n webhookId: number;\n}\n\nexport type JiraAgentToolHttpMethod = 'GET' | 'POST' | 'PUT';\n\nexport type JiraAgentToolQueryValue =\n | string\n | number\n | boolean\n | readonly (string | number)[]\n | undefined;\n\nexport interface JiraAgentToolRequest {\n accessToken: string;\n cloudId: string;\n method: JiraAgentToolHttpMethod;\n path: string;\n query?: Record<string, JiraAgentToolQueryValue> | undefined;\n body?: unknown;\n operation?: string | undefined;\n}\n\nexport interface JiraAgentToolResponse {\n status: number;\n body: unknown;\n}\n\nexport interface JiraAgentToolsClient {\n request(input: JiraAgentToolRequest): Promise<JiraAgentToolResponse>;\n}\n\nexport interface JiraApiClient {\n exchangeAuthorizationCode(input: {code: string}): Promise<JiraAuthorization>;\n refreshAccessToken(input: {refreshToken: string}): Promise<JiraAuthorization>;\n getAccessibleResources(input: {accessToken: string}): Promise<JiraAccessibleResource[]>;\n getMyself(input: {accessToken: string; cloudId: string}): Promise<JiraIdentity>;\n registerDynamicWebhook(input: {\n accessToken: string;\n cloudId: string;\n url: string;\n }): Promise<JiraDynamicWebhookRegistration>;\n refreshDynamicWebhooks(input: {\n accessToken: string;\n cloudId: string;\n webhookIds: number[];\n }): Promise<Date | undefined>;\n deleteDynamicWebhooks(input: {\n accessToken: string;\n cloudId: string;\n webhookIds: number[];\n }): Promise<void>;\n deleteDynamicWebhook(input: {\n accessToken: string;\n cloudId: string;\n webhookId: number;\n }): Promise<void>;\n}\n\ninterface JiraTokenResponse {\n access_token?: unknown;\n refresh_token?: unknown;\n expires_in?: unknown;\n scope?: unknown;\n}\n\ninterface JiraResourceResponse {\n id?: unknown;\n name?: unknown;\n url?: unknown;\n scopes?: unknown;\n}\n\ninterface JiraMyselfResponse {\n accountId?: unknown;\n}\n\ninterface JiraDynamicWebhookRegistrationResponse {\n webhookRegistrationResult?: unknown;\n}\n\nconst JIRA_REFRESH_TOKEN_TERMINAL_ERROR_CODES = new Set(['invalid_grant', 'unauthorized_client']);\n\nexport function createJiraApiClient(): JiraApiClient {\n const deleteDynamicWebhooks: JiraApiClient['deleteDynamicWebhooks'] = async (input) => {\n await mapJiraError('delete-dynamic-webhooks', () =>\n ky.delete(`${config.JIRA_API_BASE_URL}/ex/jira/${input.cloudId}/rest/api/3/webhook`, {\n headers: {authorization: `Bearer ${input.accessToken}`},\n json: {webhookIds: input.webhookIds},\n timeout: JIRA_API_TIMEOUT_MS,\n }),\n );\n };\n\n return {\n async exchangeAuthorizationCode(input) {\n const body = await mapJiraError('exchange-authorization-code', () =>\n ky\n .post(`${config.JIRA_AUTH_BASE_URL}/oauth/token`, {\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: config.JIRA_OAUTH_CLIENT_ID,\n client_secret: config.JIRA_OAUTH_CLIENT_SECRET,\n code: input.code,\n redirect_uri: config.JIRA_OAUTH_REDIRECT_URL,\n }),\n timeout: JIRA_API_TIMEOUT_MS,\n })\n .json<JiraTokenResponse>(),\n );\n return parseAuthorization(body);\n },\n\n async refreshAccessToken(input) {\n const body = await mapJiraError('refresh-access-token', () =>\n ky\n .post(`${config.JIRA_AUTH_BASE_URL}/oauth/token`, {\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: config.JIRA_OAUTH_CLIENT_ID,\n client_secret: config.JIRA_OAUTH_CLIENT_SECRET,\n refresh_token: input.refreshToken,\n }),\n timeout: JIRA_API_TIMEOUT_MS,\n })\n .json<JiraTokenResponse>(),\n );\n return parseAuthorization(body);\n },\n\n async getAccessibleResources(input) {\n const body = await mapJiraError('get-accessible-resources', () =>\n ky\n .get(`${config.JIRA_API_BASE_URL}/oauth/token/accessible-resources`, {\n headers: {authorization: `Bearer ${input.accessToken}`},\n timeout: JIRA_API_TIMEOUT_MS,\n })\n .json<unknown>(),\n );\n if (!Array.isArray(body)) {\n throw malformed('Jira accessible-resources response was not an array');\n }\n return body.map(parseAccessibleResource);\n },\n\n async getMyself(input) {\n const body = await mapJiraError('get-myself', () =>\n ky\n .get(`${config.JIRA_API_BASE_URL}/ex/jira/${input.cloudId}/rest/api/3/myself`, {\n headers: {authorization: `Bearer ${input.accessToken}`},\n timeout: JIRA_API_TIMEOUT_MS,\n })\n .json<JiraMyselfResponse>(),\n );\n if (typeof body.accountId !== 'string' || body.accountId.length === 0) {\n throw malformed('Jira identity response did not include an accountId');\n }\n return {accountId: body.accountId};\n },\n\n async registerDynamicWebhook(input) {\n const body = await mapJiraError('register-dynamic-webhook', () =>\n ky\n .post(`${config.JIRA_API_BASE_URL}/ex/jira/${input.cloudId}/rest/api/3/webhook`, {\n headers: {authorization: `Bearer ${input.accessToken}`},\n json: {\n url: input.url,\n webhooks: [\n {\n events: JIRA_DYNAMIC_WEBHOOK_EVENTS,\n jqlFilter: JIRA_DYNAMIC_WEBHOOK_JQL,\n },\n ],\n },\n timeout: JIRA_API_TIMEOUT_MS,\n })\n .json<JiraDynamicWebhookRegistrationResponse>(),\n );\n return parseDynamicWebhookRegistration(body);\n },\n\n async refreshDynamicWebhooks(input) {\n const response = await mapJiraError('refresh-dynamic-webhooks', async () => {\n try {\n return await ky.put(\n `${config.JIRA_API_BASE_URL}/ex/jira/${input.cloudId}/rest/api/3/webhook/refresh`,\n {\n headers: {authorization: `Bearer ${input.accessToken}`},\n json: {webhookIds: input.webhookIds},\n timeout: JIRA_API_TIMEOUT_MS,\n },\n );\n } catch (error) {\n if (\n error instanceof HTTPError &&\n (error.response.status === 400 || error.response.status === 404)\n )\n return undefined;\n throw error;\n }\n });\n if (!response) return undefined;\n return parseDynamicWebhookExpiration(await readJiraResponseBody(response));\n },\n\n deleteDynamicWebhooks,\n\n async deleteDynamicWebhook(input) {\n await deleteDynamicWebhooks({\n accessToken: input.accessToken,\n cloudId: input.cloudId,\n webhookIds: [input.webhookId],\n });\n },\n };\n}\n\nexport function createJiraAgentToolsClient(): JiraAgentToolsClient {\n return {request: requestJiraRest};\n}\n\nasync function requestJiraRest(input: JiraAgentToolRequest): Promise<JiraAgentToolResponse> {\n return await mapJiraError(input.operation ?? 'agent-tool', async () => {\n try {\n const response = await ky(jiraRestUrl(input.cloudId, input.path), {\n method: input.method,\n headers: {authorization: `Bearer ${input.accessToken}`},\n ...(input.query === undefined ? {} : {searchParams: jiraQueryParams(input.query)}),\n ...(input.body === undefined ? {} : {json: input.body}),\n timeout: JIRA_API_TIMEOUT_MS,\n });\n return {status: response.status, body: await readJiraResponseBody(response)};\n } catch (error) {\n if (\n error instanceof HTTPError &&\n (error.response.status === 400 || error.response.status === 404)\n ) {\n return {\n status: error.response.status,\n body: await readJiraResponseBody(error.response),\n };\n }\n throw error;\n }\n });\n}\n\nfunction jiraRestUrl(cloudId: string, path: string): string {\n const baseUrl = config.JIRA_API_BASE_URL.replace(TRAILING_SLASHES_RE, '');\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n return `${baseUrl}/ex/jira/${encodeURIComponent(cloudId)}/rest/api/3${normalizedPath}`;\n}\n\nfunction jiraQueryParams(\n query: Record<string, JiraAgentToolQueryValue>,\n): URLSearchParams | undefined {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const item of value) params.append(key, String(item));\n continue;\n }\n params.set(key, String(value));\n }\n return params.size > 0 ? params : undefined;\n}\n\nasync function readJiraResponseBody(response: Response): Promise<unknown> {\n const text = await response.text();\n if (text.length === 0) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction parseDynamicWebhookRegistration(\n body: JiraDynamicWebhookRegistrationResponse,\n): JiraDynamicWebhookRegistration {\n if (\n !body ||\n typeof body !== 'object' ||\n !Array.isArray(body.webhookRegistrationResult) ||\n body.webhookRegistrationResult.length !== 1\n ) {\n throw malformed('Jira webhook registration response did not contain exactly one result');\n }\n\n const result = body.webhookRegistrationResult[0];\n if (!result || typeof result !== 'object') {\n throw malformed('Jira webhook registration result was malformed');\n }\n const {createdWebhookId, errors} = result as {\n createdWebhookId?: unknown;\n errors?: unknown;\n };\n if (errors !== undefined && !Array.isArray(errors)) {\n throw malformed('Jira webhook registration returned errors');\n }\n if (Array.isArray(errors) && errors.length > 0) {\n logger().warn(\n {\n operation: 'register-dynamic-webhook',\n providerErrors: errors\n .filter((error): error is string => typeof error === 'string')\n .slice(0, 5)\n .map((error) => error.slice(0, 500)),\n providerErrorCount: errors.length,\n },\n 'Jira dynamic webhook registration rejected',\n );\n throw malformed('Jira webhook registration returned errors');\n }\n if (\n typeof createdWebhookId !== 'number' ||\n !Number.isSafeInteger(createdWebhookId) ||\n createdWebhookId <= 0\n ) {\n throw malformed('Jira webhook registration did not return a created webhook id');\n }\n return {webhookId: createdWebhookId};\n}\n\nfunction parseDynamicWebhookExpiration(body: unknown): Date | undefined {\n if (body === undefined || body === null) return undefined;\n if (typeof body !== 'object' || Array.isArray(body)) {\n throw malformed('Jira webhook refresh response was malformed');\n }\n const expirationDate = (body as {expirationDate?: unknown}).expirationDate;\n if (expirationDate === undefined) return undefined;\n if (typeof expirationDate !== 'string') {\n throw malformed('Jira webhook refresh response included a malformed expiration date');\n }\n const parsed = new Date(expirationDate);\n if (Number.isNaN(parsed.getTime())) {\n throw malformed('Jira webhook refresh response included a malformed expiration date');\n }\n return parsed;\n}\n\nfunction parseAuthorization(body: JiraTokenResponse): JiraAuthorization {\n if (typeof body.access_token !== 'string' || body.access_token.length === 0) {\n throw malformed('Jira authorization response did not include an access token');\n }\n return {\n accessToken: body.access_token,\n refreshToken: typeof body.refresh_token === 'string' ? body.refresh_token : undefined,\n expiresAt: parseExpiresAt(body.expires_in),\n scopes: parseScopes(body.scope),\n };\n}\n\nfunction parseAccessibleResource(value: unknown): JiraAccessibleResource {\n if (!value || typeof value !== 'object') throw malformed('Jira site response was malformed');\n const {id, name, url, scopes} = value as JiraResourceResponse;\n if (\n typeof id !== 'string' ||\n id.length === 0 ||\n typeof name !== 'string' ||\n name.length === 0 ||\n typeof url !== 'string' ||\n url.length === 0 ||\n !Array.isArray(scopes) ||\n !scopes.every((scope) => typeof scope === 'string')\n ) {\n throw malformed('Jira site response did not include a valid cloud id, name, URL, and scopes');\n }\n return {cloudId: id, name, url, scopes};\n}\n\nfunction parseScopes(scope: unknown): string[] {\n if (typeof scope === 'string')\n return scope\n .split(SCOPE_SEPARATOR_RE)\n .map((value) => value.trim())\n .filter(Boolean);\n if (Array.isArray(scope) && scope.every((value) => typeof value === 'string')) return scope;\n if (scope === undefined) return [];\n throw malformed('Jira authorization response included malformed scopes');\n}\n\nfunction parseExpiresAt(expiresIn: unknown): Date | undefined {\n if (expiresIn === undefined) return undefined;\n if (typeof expiresIn !== 'number' || !Number.isFinite(expiresIn) || expiresIn <= 0) {\n throw malformed('Jira authorization response included a malformed expiry');\n }\n return new Date(Date.now() + expiresIn * 1000);\n}\n\nexport async function mapJiraError<T>(operation: string, request: () => Promise<T>): Promise<T> {\n try {\n return await request();\n } catch (error) {\n if (error instanceof JiraIntegrationProviderError) throw error;\n if (error instanceof HTTPError) {\n const {status, statusText, headers} = error.response;\n logger().warn({operation, status, statusText}, 'Jira API request rejected');\n if (status === 429) {\n throw new JiraIntegrationProviderError(\n 'rate-limited',\n 'Jira request was rate limited',\n retryAfterSeconds(headers),\n );\n }\n if (status >= 500)\n throw new JiraIntegrationProviderError('provider-unavailable', 'Jira request failed');\n if (status === 401 || status === 403) {\n throw new JiraIntegrationProviderError('access-denied', 'Jira request was rejected');\n }\n if (status === 400 && operation === 'refresh-access-token') {\n const errorCode = readJiraOAuthErrorCode(error.data);\n if (errorCode && JIRA_REFRESH_TOKEN_TERMINAL_ERROR_CODES.has(errorCode)) {\n throw new JiraIntegrationProviderError(\n 'access-denied',\n 'Jira refresh token was rejected; reconnect is required',\n );\n }\n }\n throw malformed('Jira request was rejected');\n }\n if (error instanceof TimeoutError) {\n logger().warn({operation}, 'Jira API request timed out');\n throw new JiraIntegrationProviderError('timeout', 'Jira request timed out');\n }\n logger().warn(\n {operation, errName: error instanceof Error ? error.name : typeof error},\n 'Jira API request failed',\n );\n throw new JiraIntegrationProviderError('provider-unavailable', 'Jira request failed');\n }\n}\n\nfunction malformed(message: string): JiraIntegrationProviderError {\n return new JiraIntegrationProviderError('malformed-provider-response', message);\n}\n\nfunction readJiraOAuthErrorCode(data: unknown): string | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const errorCode = (data as {error?: unknown}).error;\n return typeof errorCode === 'string' ? errorCode : undefined;\n}\n\nfunction retryAfterSeconds(headers: Headers): number | undefined {\n const value = headers.get('retry-after');\n if (!value) return undefined;\n const parsed = Number.parseInt(value, 10);\n return Number.isNaN(parsed) ? undefined : parsed;\n}\n"],"names":["jiraWebhookEventNames","logger","ky","HTTPError","TimeoutError","config","JiraIntegrationProviderError","JIRA_API_TIMEOUT_MS","SCOPE_SEPARATOR_RE","TRAILING_SLASHES_RE","JIRA_DYNAMIC_WEBHOOK_EVENTS","JIRA_DYNAMIC_WEBHOOK_JQL","JIRA_REFRESH_TOKEN_TERMINAL_ERROR_CODES","Set","createJiraApiClient","deleteDynamicWebhooks","input","mapJiraError","delete","JIRA_API_BASE_URL","cloudId","headers","authorization","accessToken","json","webhookIds","timeout","exchangeAuthorizationCode","body","post","JIRA_AUTH_BASE_URL","URLSearchParams","grant_type","client_id","JIRA_OAUTH_CLIENT_ID","client_secret","JIRA_OAUTH_CLIENT_SECRET","code","redirect_uri","JIRA_OAUTH_REDIRECT_URL","parseAuthorization","refreshAccessToken","refresh_token","refreshToken","getAccessibleResources","get","Array","isArray","malformed","map","parseAccessibleResource","getMyself","accountId","length","registerDynamicWebhook","url","webhooks","events","jqlFilter","parseDynamicWebhookRegistration","refreshDynamicWebhooks","response","put","error","status","undefined","parseDynamicWebhookExpiration","readJiraResponseBody","deleteDynamicWebhook","webhookId","createJiraAgentToolsClient","request","requestJiraRest","operation","jiraRestUrl","path","method","query","searchParams","jiraQueryParams","baseUrl","replace","normalizedPath","startsWith","encodeURIComponent","params","key","value","Object","entries","item","append","String","set","size","text","JSON","parse","webhookRegistrationResult","result","createdWebhookId","errors","warn","providerErrors","filter","slice","providerErrorCount","Number","isSafeInteger","expirationDate","parsed","Date","isNaN","getTime","access_token","expiresAt","parseExpiresAt","expires_in","scopes","parseScopes","scope","id","name","every","split","trim","Boolean","expiresIn","isFinite","now","statusText","retryAfterSeconds","errorCode","readJiraOAuthErrorCode","data","has","errName","Error","message","parseInt"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/api/client.ts"],"sourcesContent":["import {jiraWebhookEventNames} from '@shipfox/api-integration-jira-dto';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport ky, {HTTPError, TimeoutError} from 'ky';\nimport {config} from '#config.js';\nimport {JiraIntegrationProviderError} from '#core/errors.js';\n\nconst JIRA_API_TIMEOUT_MS = 10_000;\nconst SCOPE_SEPARATOR_RE = /[,\\s]+/;\nconst TRAILING_SLASHES_RE = /\\/+$/;\nexport const JIRA_DYNAMIC_WEBHOOK_EVENTS = jiraWebhookEventNames;\n// Jira rejects an empty dynamic-webhook filter; every issue belongs to a project.\nexport const JIRA_DYNAMIC_WEBHOOK_JQL = 'project != null';\n\nexport interface JiraAuthorization {\n accessToken: string;\n refreshToken?: string | undefined;\n expiresAt?: Date | undefined;\n scopes: string[];\n}\n\nexport interface JiraAccessibleResource {\n cloudId: string;\n name: string;\n url: string;\n scopes: string[];\n}\n\nexport interface JiraIdentity {\n accountId: string;\n}\n\nexport interface JiraDynamicWebhookRegistration {\n webhookId: number;\n}\n\nexport type JiraAgentToolHttpMethod = 'GET' | 'POST' | 'PUT';\n\nexport type JiraAgentToolQueryValue =\n | string\n | number\n | boolean\n | readonly (string | number)[]\n | undefined;\n\nexport interface JiraAgentToolRequest {\n accessToken: string;\n cloudId: string;\n method: JiraAgentToolHttpMethod;\n path: string;\n query?: Record<string, JiraAgentToolQueryValue> | undefined;\n body?: unknown;\n operation?: string | undefined;\n}\n\nexport interface JiraAgentToolResponse {\n status: number;\n body: unknown;\n}\n\nexport interface JiraAgentToolsClient {\n request(input: JiraAgentToolRequest): Promise<JiraAgentToolResponse>;\n}\n\nexport interface JiraApiClient {\n exchangeAuthorizationCode(input: {code: string}): Promise<JiraAuthorization>;\n refreshAccessToken(input: {refreshToken: string}): Promise<JiraAuthorization>;\n getAccessibleResources(input: {accessToken: string}): Promise<JiraAccessibleResource[]>;\n getMyself(input: {accessToken: string; cloudId: string}): Promise<JiraIdentity>;\n registerDynamicWebhook(input: {\n accessToken: string;\n cloudId: string;\n url: string;\n }): Promise<JiraDynamicWebhookRegistration>;\n refreshDynamicWebhooks(input: {\n accessToken: string;\n cloudId: string;\n webhookIds: number[];\n }): Promise<Date | undefined>;\n deleteDynamicWebhooks(input: {\n accessToken: string;\n cloudId: string;\n webhookIds: number[];\n }): Promise<void>;\n deleteDynamicWebhook(input: {\n accessToken: string;\n cloudId: string;\n webhookId: number;\n }): Promise<void>;\n}\n\ninterface JiraTokenResponse {\n access_token?: unknown;\n refresh_token?: unknown;\n expires_in?: unknown;\n scope?: unknown;\n}\n\ninterface JiraResourceResponse {\n id?: unknown;\n name?: unknown;\n url?: unknown;\n scopes?: unknown;\n}\n\ninterface JiraMyselfResponse {\n accountId?: unknown;\n}\n\ninterface JiraDynamicWebhookRegistrationResponse {\n webhookRegistrationResult?: unknown;\n}\n\nconst JIRA_REFRESH_TOKEN_TERMINAL_ERROR_CODES = new Set(['invalid_grant', 'unauthorized_client']);\n\nexport function createJiraApiClient(): JiraApiClient {\n const deleteDynamicWebhooks: JiraApiClient['deleteDynamicWebhooks'] = async (input) => {\n await mapJiraError('delete-dynamic-webhooks', () =>\n ky.delete(`${config.JIRA_API_BASE_URL}/ex/jira/${input.cloudId}/rest/api/3/webhook`, {\n headers: {authorization: `Bearer ${input.accessToken}`},\n json: {webhookIds: input.webhookIds},\n timeout: JIRA_API_TIMEOUT_MS,\n }),\n );\n };\n\n return {\n async exchangeAuthorizationCode(input) {\n const body = await mapJiraError('exchange-authorization-code', () =>\n ky\n .post(`${config.JIRA_AUTH_BASE_URL}/oauth/token`, {\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: config.JIRA_OAUTH_CLIENT_ID,\n client_secret: config.JIRA_OAUTH_CLIENT_SECRET,\n code: input.code,\n redirect_uri: config.JIRA_OAUTH_REDIRECT_URL,\n }),\n timeout: JIRA_API_TIMEOUT_MS,\n })\n .json<JiraTokenResponse>(),\n );\n return parseAuthorization(body);\n },\n\n async refreshAccessToken(input) {\n const body = await mapJiraError('refresh-access-token', () =>\n ky\n .post(`${config.JIRA_AUTH_BASE_URL}/oauth/token`, {\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: config.JIRA_OAUTH_CLIENT_ID,\n client_secret: config.JIRA_OAUTH_CLIENT_SECRET,\n refresh_token: input.refreshToken,\n }),\n timeout: JIRA_API_TIMEOUT_MS,\n })\n .json<JiraTokenResponse>(),\n );\n return parseAuthorization(body);\n },\n\n async getAccessibleResources(input) {\n const body = await mapJiraError('get-accessible-resources', () =>\n ky\n .get(`${config.JIRA_API_BASE_URL}/oauth/token/accessible-resources`, {\n headers: {authorization: `Bearer ${input.accessToken}`},\n timeout: JIRA_API_TIMEOUT_MS,\n })\n .json<unknown>(),\n );\n if (!Array.isArray(body)) {\n throw malformed('Jira accessible-resources response was not an array');\n }\n return body.map(parseAccessibleResource);\n },\n\n async getMyself(input) {\n const body = await mapJiraError('get-myself', () =>\n ky\n .get(`${config.JIRA_API_BASE_URL}/ex/jira/${input.cloudId}/rest/api/3/myself`, {\n headers: {authorization: `Bearer ${input.accessToken}`},\n timeout: JIRA_API_TIMEOUT_MS,\n })\n .json<JiraMyselfResponse>(),\n );\n if (typeof body.accountId !== 'string' || body.accountId.length === 0) {\n throw malformed('Jira identity response did not include an accountId');\n }\n return {accountId: body.accountId};\n },\n\n async registerDynamicWebhook(input) {\n const body = await mapJiraError('register-dynamic-webhook', () =>\n ky\n .post(`${config.JIRA_API_BASE_URL}/ex/jira/${input.cloudId}/rest/api/3/webhook`, {\n headers: {authorization: `Bearer ${input.accessToken}`},\n json: {\n url: input.url,\n webhooks: [\n {\n events: JIRA_DYNAMIC_WEBHOOK_EVENTS,\n jqlFilter: JIRA_DYNAMIC_WEBHOOK_JQL,\n },\n ],\n },\n timeout: JIRA_API_TIMEOUT_MS,\n })\n .json<JiraDynamicWebhookRegistrationResponse>(),\n );\n return parseDynamicWebhookRegistration(body);\n },\n\n async refreshDynamicWebhooks(input) {\n const response = await mapJiraError('refresh-dynamic-webhooks', async () => {\n try {\n return await ky.put(\n `${config.JIRA_API_BASE_URL}/ex/jira/${input.cloudId}/rest/api/3/webhook/refresh`,\n {\n headers: {authorization: `Bearer ${input.accessToken}`},\n json: {webhookIds: input.webhookIds},\n timeout: JIRA_API_TIMEOUT_MS,\n },\n );\n } catch (error) {\n if (\n error instanceof HTTPError &&\n (error.response.status === 400 || error.response.status === 404)\n )\n return undefined;\n throw error;\n }\n });\n if (!response) return undefined;\n return parseDynamicWebhookExpiration(await readJiraResponseBody(response));\n },\n\n deleteDynamicWebhooks,\n\n async deleteDynamicWebhook(input) {\n await deleteDynamicWebhooks({\n accessToken: input.accessToken,\n cloudId: input.cloudId,\n webhookIds: [input.webhookId],\n });\n },\n };\n}\n\nexport function createJiraAgentToolsClient(): JiraAgentToolsClient {\n return {request: requestJiraRest};\n}\n\nasync function requestJiraRest(input: JiraAgentToolRequest): Promise<JiraAgentToolResponse> {\n return await mapJiraError(input.operation ?? 'agent-tool', async () => {\n try {\n const response = await ky(jiraRestUrl(input.cloudId, input.path), {\n method: input.method,\n headers: {authorization: `Bearer ${input.accessToken}`},\n ...(input.query === undefined ? {} : {searchParams: jiraQueryParams(input.query)}),\n ...(input.body === undefined ? {} : {json: input.body}),\n timeout: JIRA_API_TIMEOUT_MS,\n });\n return {status: response.status, body: await readJiraResponseBody(response)};\n } catch (error) {\n if (\n error instanceof HTTPError &&\n (error.response.status === 400 || error.response.status === 404)\n ) {\n return {\n status: error.response.status,\n body: await readJiraResponseBody(error.response),\n };\n }\n throw error;\n }\n });\n}\n\nfunction jiraRestUrl(cloudId: string, path: string): string {\n const baseUrl = config.JIRA_API_BASE_URL.replace(TRAILING_SLASHES_RE, '');\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n return `${baseUrl}/ex/jira/${encodeURIComponent(cloudId)}/rest/api/3${normalizedPath}`;\n}\n\nfunction jiraQueryParams(\n query: Record<string, JiraAgentToolQueryValue>,\n): URLSearchParams | undefined {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const item of value) params.append(key, String(item));\n continue;\n }\n params.set(key, String(value));\n }\n return params.size > 0 ? params : undefined;\n}\n\nasync function readJiraResponseBody(response: Response): Promise<unknown> {\n const text = await response.text();\n if (text.length === 0) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction parseDynamicWebhookRegistration(\n body: JiraDynamicWebhookRegistrationResponse,\n): JiraDynamicWebhookRegistration {\n if (\n !body ||\n typeof body !== 'object' ||\n !Array.isArray(body.webhookRegistrationResult) ||\n body.webhookRegistrationResult.length !== 1\n ) {\n throw malformed('Jira webhook registration response did not contain exactly one result');\n }\n\n const result = body.webhookRegistrationResult[0];\n if (!result || typeof result !== 'object') {\n throw malformed('Jira webhook registration result was malformed');\n }\n const {createdWebhookId, errors} = result as {\n createdWebhookId?: unknown;\n errors?: unknown;\n };\n if (errors !== undefined && !Array.isArray(errors)) {\n throw malformed('Jira webhook registration returned errors');\n }\n if (Array.isArray(errors) && errors.length > 0) {\n logger().warn(\n {\n operation: 'register-dynamic-webhook',\n providerErrors: errors\n .filter((error): error is string => typeof error === 'string')\n .slice(0, 5)\n .map((error) => error.slice(0, 500)),\n providerErrorCount: errors.length,\n },\n 'Jira dynamic webhook registration rejected',\n );\n throw malformed('Jira webhook registration returned errors');\n }\n if (\n typeof createdWebhookId !== 'number' ||\n !Number.isSafeInteger(createdWebhookId) ||\n createdWebhookId <= 0\n ) {\n throw malformed('Jira webhook registration did not return a created webhook id');\n }\n return {webhookId: createdWebhookId};\n}\n\nfunction parseDynamicWebhookExpiration(body: unknown): Date | undefined {\n if (body === undefined || body === null) return undefined;\n if (typeof body !== 'object' || Array.isArray(body)) {\n throw malformed('Jira webhook refresh response was malformed');\n }\n const expirationDate = (body as {expirationDate?: unknown}).expirationDate;\n if (expirationDate === undefined) return undefined;\n if (typeof expirationDate !== 'string') {\n throw malformed('Jira webhook refresh response included a malformed expiration date');\n }\n const parsed = new Date(expirationDate);\n if (Number.isNaN(parsed.getTime())) {\n throw malformed('Jira webhook refresh response included a malformed expiration date');\n }\n return parsed;\n}\n\nfunction parseAuthorization(body: JiraTokenResponse): JiraAuthorization {\n if (typeof body.access_token !== 'string' || body.access_token.length === 0) {\n throw malformed('Jira authorization response did not include an access token');\n }\n return {\n accessToken: body.access_token,\n refreshToken: typeof body.refresh_token === 'string' ? body.refresh_token : undefined,\n expiresAt: parseExpiresAt(body.expires_in),\n scopes: parseScopes(body.scope),\n };\n}\n\nfunction parseAccessibleResource(value: unknown): JiraAccessibleResource {\n if (!value || typeof value !== 'object') throw malformed('Jira site response was malformed');\n const {id, name, url, scopes} = value as JiraResourceResponse;\n if (\n typeof id !== 'string' ||\n id.length === 0 ||\n typeof name !== 'string' ||\n name.length === 0 ||\n typeof url !== 'string' ||\n url.length === 0 ||\n !Array.isArray(scopes) ||\n !scopes.every((scope) => typeof scope === 'string')\n ) {\n throw malformed('Jira site response did not include a valid cloud id, name, URL, and scopes');\n }\n return {cloudId: id, name, url, scopes};\n}\n\nfunction parseScopes(scope: unknown): string[] {\n if (typeof scope === 'string')\n return scope\n .split(SCOPE_SEPARATOR_RE)\n .map((value) => value.trim())\n .filter(Boolean);\n if (Array.isArray(scope) && scope.every((value) => typeof value === 'string')) return scope;\n if (scope === undefined) return [];\n throw malformed('Jira authorization response included malformed scopes');\n}\n\nfunction parseExpiresAt(expiresIn: unknown): Date | undefined {\n if (expiresIn === undefined) return undefined;\n if (typeof expiresIn !== 'number' || !Number.isFinite(expiresIn) || expiresIn <= 0) {\n throw malformed('Jira authorization response included a malformed expiry');\n }\n return new Date(Date.now() + expiresIn * 1000);\n}\n\nexport async function mapJiraError<T>(operation: string, request: () => Promise<T>): Promise<T> {\n try {\n return await request();\n } catch (error) {\n if (error instanceof JiraIntegrationProviderError) throw error;\n if (error instanceof HTTPError) {\n const {status, statusText, headers} = error.response;\n logger().warn({operation, status, statusText}, 'Jira API request rejected');\n if (status === 429) {\n throw new JiraIntegrationProviderError(\n 'rate-limited',\n 'Jira request was rate limited',\n retryAfterSeconds(headers),\n );\n }\n if (status >= 500)\n throw new JiraIntegrationProviderError('provider-unavailable', 'Jira request failed');\n if (status === 401 || status === 403) {\n throw new JiraIntegrationProviderError('access-denied', 'Jira request was rejected');\n }\n if (status === 400 && operation === 'refresh-access-token') {\n const errorCode = readJiraOAuthErrorCode(error.data);\n if (errorCode && JIRA_REFRESH_TOKEN_TERMINAL_ERROR_CODES.has(errorCode)) {\n throw new JiraIntegrationProviderError(\n 'access-denied',\n 'Jira refresh token was rejected; reconnect is required',\n );\n }\n }\n throw malformed('Jira request was rejected');\n }\n if (error instanceof TimeoutError) {\n logger().warn({operation}, 'Jira API request timed out');\n throw new JiraIntegrationProviderError('timeout', 'Jira request timed out');\n }\n logger().warn(\n {operation, errName: error instanceof Error ? error.name : typeof error},\n 'Jira API request failed',\n );\n throw new JiraIntegrationProviderError('provider-unavailable', 'Jira request failed');\n }\n}\n\nfunction malformed(message: string): JiraIntegrationProviderError {\n return new JiraIntegrationProviderError('malformed-provider-response', message);\n}\n\nfunction readJiraOAuthErrorCode(data: unknown): string | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const errorCode = (data as {error?: unknown}).error;\n return typeof errorCode === 'string' ? errorCode : undefined;\n}\n\nfunction retryAfterSeconds(headers: Headers): number | undefined {\n const value = headers.get('retry-after');\n if (!value) return undefined;\n const parsed = Number.parseInt(value, 10);\n return Number.isNaN(parsed) ? undefined : parsed;\n}\n"],"names":["jiraWebhookEventNames","logger","ky","HTTPError","TimeoutError","config","JiraIntegrationProviderError","JIRA_API_TIMEOUT_MS","SCOPE_SEPARATOR_RE","TRAILING_SLASHES_RE","JIRA_DYNAMIC_WEBHOOK_EVENTS","JIRA_DYNAMIC_WEBHOOK_JQL","JIRA_REFRESH_TOKEN_TERMINAL_ERROR_CODES","Set","createJiraApiClient","deleteDynamicWebhooks","input","mapJiraError","delete","JIRA_API_BASE_URL","cloudId","headers","authorization","accessToken","json","webhookIds","timeout","exchangeAuthorizationCode","body","post","JIRA_AUTH_BASE_URL","URLSearchParams","grant_type","client_id","JIRA_OAUTH_CLIENT_ID","client_secret","JIRA_OAUTH_CLIENT_SECRET","code","redirect_uri","JIRA_OAUTH_REDIRECT_URL","parseAuthorization","refreshAccessToken","refresh_token","refreshToken","getAccessibleResources","get","Array","isArray","malformed","map","parseAccessibleResource","getMyself","accountId","length","registerDynamicWebhook","url","webhooks","events","jqlFilter","parseDynamicWebhookRegistration","refreshDynamicWebhooks","response","put","error","status","undefined","parseDynamicWebhookExpiration","readJiraResponseBody","deleteDynamicWebhook","webhookId","createJiraAgentToolsClient","request","requestJiraRest","operation","jiraRestUrl","path","method","query","searchParams","jiraQueryParams","baseUrl","replace","normalizedPath","startsWith","encodeURIComponent","params","key","value","Object","entries","item","append","String","set","size","text","JSON","parse","webhookRegistrationResult","result","createdWebhookId","errors","warn","providerErrors","filter","slice","providerErrorCount","Number","isSafeInteger","expirationDate","parsed","Date","isNaN","getTime","access_token","expiresAt","parseExpiresAt","expires_in","scopes","parseScopes","scope","id","name","every","split","trim","Boolean","expiresIn","isFinite","now","statusText","retryAfterSeconds","errorCode","readJiraOAuthErrorCode","data","has","errName","Error","message","parseInt"],"mappings":"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"}