@shipfox/api-integration-jira 11.0.0 → 12.1.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.
- package/.turbo/turbo-build.log +17 -2
- package/CHANGELOG.md +36 -0
- package/README.md +58 -2
- package/dist/api/client.d.ts +34 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +131 -0
- package/dist/api/client.js.map +1 -1
- package/dist/config.d.ts +0 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -4
- package/dist/config.js.map +1 -1
- package/dist/core/agent-tools-provider.d.ts +26 -0
- package/dist/core/agent-tools-provider.d.ts.map +1 -0
- package/dist/core/agent-tools-provider.js +130 -0
- package/dist/core/agent-tools-provider.js.map +1 -0
- package/dist/core/agent-tools.d.ts +16 -0
- package/dist/core/agent-tools.d.ts.map +1 -0
- package/dist/core/agent-tools.js +441 -0
- package/dist/core/agent-tools.js.map +1 -0
- package/dist/core/install.d.ts +22 -0
- package/dist/core/install.d.ts.map +1 -1
- package/dist/core/install.js +68 -20
- package/dist/core/install.js.map +1 -1
- package/dist/core/tokens.d.ts +2 -0
- package/dist/core/tokens.d.ts.map +1 -1
- package/dist/core/tokens.js +129 -37
- package/dist/core/tokens.js.map +1 -1
- package/dist/core/webhook-processor.d.ts +15 -0
- package/dist/core/webhook-processor.d.ts.map +1 -0
- package/dist/core/webhook-processor.js +137 -0
- package/dist/core/webhook-processor.js.map +1 -0
- package/dist/core/webhook-registration.d.ts +26 -0
- package/dist/core/webhook-registration.d.ts.map +1 -0
- package/dist/core/webhook-registration.js +165 -0
- package/dist/core/webhook-registration.js.map +1 -0
- package/dist/core/webhook.d.ts +18 -0
- package/dist/core/webhook.d.ts.map +1 -0
- package/dist/core/webhook.js +38 -0
- package/dist/core/webhook.js.map +1 -0
- package/dist/db/db.d.ts +68 -0
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/installations.d.ts +33 -6
- package/dist/db/installations.d.ts.map +1 -1
- package/dist/db/installations.js +79 -7
- package/dist/db/installations.js.map +1 -1
- package/dist/db/schema/installations.d.ts +34 -0
- package/dist/db/schema/installations.d.ts.map +1 -1
- package/dist/db/schema/installations.js +12 -2
- package/dist/db/schema/installations.js.map +1 -1
- package/dist/index.d.ts +34 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +76 -8
- package/dist/index.js.map +1 -1
- package/dist/presentation/routes/install.d.ts +22 -0
- package/dist/presentation/routes/install.d.ts.map +1 -1
- package/dist/presentation/routes/install.js.map +1 -1
- package/dist/presentation/routes/webhooks.d.ts +8 -0
- package/dist/presentation/routes/webhooks.d.ts.map +1 -0
- package/dist/presentation/routes/webhooks.js +108 -0
- package/dist/presentation/routes/webhooks.js.map +1 -0
- package/dist/temporal/activities/index.d.ts +2 -0
- package/dist/temporal/activities/index.d.ts.map +1 -0
- package/dist/temporal/activities/index.js +3 -0
- package/dist/temporal/activities/index.js.map +1 -0
- package/dist/temporal/activities/refresh-jira-tokens.d.ts +20 -0
- package/dist/temporal/activities/refresh-jira-tokens.d.ts.map +1 -0
- package/dist/temporal/activities/refresh-jira-tokens.js +58 -0
- package/dist/temporal/activities/refresh-jira-tokens.js.map +1 -0
- package/dist/temporal/constants.d.ts +6 -0
- package/dist/temporal/constants.d.ts.map +1 -0
- package/dist/temporal/constants.js +8 -0
- package/dist/temporal/constants.js.map +1 -0
- package/dist/temporal/worker.d.ts +9 -0
- package/dist/temporal/worker.d.ts.map +1 -0
- package/dist/temporal/worker.js +26 -0
- package/dist/temporal/worker.js.map +1 -0
- package/dist/temporal/workflows/index.bundle.js +25225 -0
- package/dist/temporal/workflows/index.bundle.meta.json +1 -0
- package/dist/temporal/workflows/index.d.ts +2 -0
- package/dist/temporal/workflows/index.d.ts.map +1 -0
- package/dist/temporal/workflows/index.js +3 -0
- package/dist/temporal/workflows/index.js.map +1 -0
- package/dist/temporal/workflows/refresh-jira-tokens-cron.d.ts +2 -0
- package/dist/temporal/workflows/refresh-jira-tokens-cron.d.ts.map +1 -0
- package/dist/temporal/workflows/refresh-jira-tokens-cron.js +20 -0
- package/dist/temporal/workflows/refresh-jira-tokens-cron.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0001_jira-token-refresh-state.sql +12 -0
- package/drizzle/meta/0001_snapshot.json +245 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +17 -8
- package/src/api/client.test.ts +236 -9
- package/src/api/client.ts +192 -0
- package/src/config.test.ts +0 -1
- package/src/config.ts +1 -4
- package/src/core/agent-tools-provider.test.ts +299 -0
- package/src/core/agent-tools-provider.ts +175 -0
- package/src/core/agent-tools.ts +450 -0
- package/src/core/install.test.ts +179 -0
- package/src/core/install.ts +85 -19
- package/src/core/tokens-refresh.test.ts +223 -4
- package/src/core/tokens.test.ts +1 -1
- package/src/core/tokens.ts +153 -33
- package/src/core/webhook-processor.test.ts +418 -0
- package/src/core/webhook-processor.ts +166 -0
- package/src/core/webhook-registration.test.ts +375 -0
- package/src/core/webhook-registration.ts +216 -0
- package/src/core/webhook.ts +69 -0
- package/src/db/installations.test.ts +148 -2
- package/src/db/installations.ts +133 -7
- package/src/db/schema/installations.ts +21 -1
- package/src/index.test.ts +42 -0
- package/src/index.ts +148 -5
- package/src/presentation/routes/install.ts +12 -0
- package/src/presentation/routes/webhooks.test.ts +132 -0
- package/src/presentation/routes/webhooks.ts +115 -0
- package/src/temporal/activities/index.ts +5 -0
- package/src/temporal/activities/refresh-jira-tokens.test.ts +156 -0
- package/src/temporal/activities/refresh-jira-tokens.ts +88 -0
- package/src/temporal/constants.ts +8 -0
- package/src/temporal/worker.ts +39 -0
- package/src/temporal/workflows/index.ts +1 -0
- package/src/temporal/workflows/refresh-jira-tokens-cron.ts +19 -0
- package/test/env.ts +0 -1
- package/test/factories/jira-installation.ts +4 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { JIRA_PROVIDER } from '@shipfox/api-integration-jira-dto';
|
|
2
|
-
import { createJiraApiClient } from '#api/client.js';
|
|
2
|
+
import { createJiraAgentToolsClient, createJiraApiClient } from '#api/client.js';
|
|
3
3
|
import { config } from '#config.js';
|
|
4
|
+
import { JiraAgentToolsProvider } from '#core/agent-tools-provider.js';
|
|
5
|
+
import { createJiraWebhookProcessor } from '#core/webhook-processor.js';
|
|
6
|
+
import { registerJiraWebhook } from '#core/webhook-registration.js';
|
|
4
7
|
import { closeDb, db } from '#db/db.js';
|
|
5
8
|
import { getJiraInstallationByConnectionId } from '#db/installations.js';
|
|
6
9
|
import { migrationsPath } from '#db/migrations.js';
|
|
7
10
|
import { createJiraIntegrationRoutes } from '#presentation/routes/install.js';
|
|
8
|
-
|
|
11
|
+
import { createJiraWebhookRoutes, JIRA_WEBHOOK_ROUTE_PREFIX } from '#presentation/routes/webhooks.js';
|
|
12
|
+
const TRAILING_SLASHES_RE = /\/+$/;
|
|
13
|
+
export { createJiraAgentToolsClient, createJiraApiClient, JIRA_DYNAMIC_WEBHOOK_EVENTS, JIRA_DYNAMIC_WEBHOOK_JQL, mapJiraError } from '#api/client.js';
|
|
14
|
+
export { jiraAgentToolCatalog, jiraAgentToolSelectionCatalog, jiraPlainTextToAdf } from '#core/agent-tools.js';
|
|
15
|
+
export { JiraAgentToolsProvider } from '#core/agent-tools-provider.js';
|
|
9
16
|
export { disconnectJiraInstallation } from '#core/disconnect.js';
|
|
10
17
|
export { JiraAccessTokenMissingError, JiraAuthorizationScopeMismatchError, JiraConnectionAlreadyLinkedError, JiraConnectionNotFoundError, JiraInstallationAlreadyLinkedError, JiraInstallationSiteMismatchError, JiraInstallStateActorMismatchError, JiraInstallStateError, JiraIntegrationProviderError, JiraOAuthCallbackError, JiraOfflineAccessNotGrantedError, JiraPendingSelectionNotFoundError, JiraSiteSelectionMismatchError, JiraTokenUnrefreshableError } from '#core/errors.js';
|
|
11
18
|
export { handleJiraCallback, handleJiraOAuthCallbackError, handleJiraSiteSelection } from '#core/install.js';
|
|
@@ -13,26 +20,87 @@ export { createJiraPendingSelectionStore, jiraPendingSecretsNamespace } from '#c
|
|
|
13
20
|
export { assertJiraAuthorizationScopes, formatJiraOAuthScopes, JIRA_OAUTH_SCOPES } from '#core/scopes.js';
|
|
14
21
|
export { signJiraInstallState, verifyJiraInstallState } from '#core/state.js';
|
|
15
22
|
export { createJiraTokenStore, jiraSecretsNamespace } from '#core/tokens.js';
|
|
16
|
-
export {
|
|
23
|
+
export { createJiraWebhookProcessor } from '#core/webhook-processor.js';
|
|
24
|
+
export { JIRA_WEBHOOK_TTL_MS, registerJiraWebhook } from '#core/webhook-registration.js';
|
|
25
|
+
export { deleteJiraInstallationByConnectionId, getJiraInstallationByCloudId, getJiraInstallationByConnectionId, getJiraInstallationByWebhookId, listJiraInstallationsDueForTokenRefresh, markJiraInstallationRevoked, updateJiraInstallationTokenExpiry, updateJiraInstallationWebhook, upsertJiraInstallation, withJiraRefreshLock, withJiraWebhookRegistrationLock } from '#db/installations.js';
|
|
26
|
+
export { createJiraWebhookRoutes } from '#presentation/routes/webhooks.js';
|
|
27
|
+
export { createJiraMaintenanceWorker } from '#temporal/worker.js';
|
|
17
28
|
export { closeDb, config, db, migrationsPath };
|
|
18
29
|
export function createJiraIntegrationProvider(options = {}) {
|
|
19
30
|
const jira = options.jira ?? createJiraApiClient();
|
|
20
31
|
const getInstallationByConnectionId = options.getJiraInstallationByConnectionId ?? getJiraInstallationByConnectionId;
|
|
32
|
+
const adapters = options.agentTools ? {
|
|
33
|
+
agent_tools: new JiraAgentToolsProvider({
|
|
34
|
+
jira: options.agentTools.jira ?? createJiraAgentToolsClient(),
|
|
35
|
+
tokenStore: options.agentTools.tokenStore
|
|
36
|
+
})
|
|
37
|
+
} : {};
|
|
38
|
+
const webhookOptions = toJiraWebhookOptions(options.routes);
|
|
39
|
+
const webhookProcessor = webhookOptions ? createJiraWebhookProcessor(webhookOptions) : undefined;
|
|
40
|
+
const webhookRoutes = webhookOptions ? [
|
|
41
|
+
createJiraWebhookRoutes({
|
|
42
|
+
coreDb: webhookOptions.coreDb,
|
|
43
|
+
publishIntegrationEventReceived: webhookOptions.publishIntegrationEventReceived,
|
|
44
|
+
recordDeliveryOnly: webhookOptions.recordDeliveryOnly,
|
|
45
|
+
getIntegrationConnectionById: webhookOptions.getIntegrationConnectionById,
|
|
46
|
+
processor: webhookProcessor
|
|
47
|
+
})
|
|
48
|
+
] : [];
|
|
21
49
|
const routes = options.routes ? [
|
|
22
50
|
createJiraIntegrationRoutes({
|
|
23
51
|
jira,
|
|
24
|
-
connectionCapabilities: [
|
|
25
|
-
|
|
26
|
-
|
|
52
|
+
connectionCapabilities: adapters.agent_tools ? [
|
|
53
|
+
'agent_tools'
|
|
54
|
+
] : [],
|
|
55
|
+
...options.routes,
|
|
56
|
+
registerJiraWebhook: (input)=>registerJiraWebhook({
|
|
57
|
+
jira,
|
|
58
|
+
connectionId: input.connectionId,
|
|
59
|
+
cloudId: input.cloudId,
|
|
60
|
+
accessToken: input.accessToken,
|
|
61
|
+
webhookUrl: jiraWebhookUrl(input.connectionId),
|
|
62
|
+
...input.withRegistrationLock ? {
|
|
63
|
+
withRegistrationLock: input.withRegistrationLock
|
|
64
|
+
} : {},
|
|
65
|
+
...input.onRegistrationSuccess ? {
|
|
66
|
+
onRegistrationSuccess: input.onRegistrationSuccess
|
|
67
|
+
} : {},
|
|
68
|
+
...input.onRegistrationFailure ? {
|
|
69
|
+
onRegistrationFailure: input.onRegistrationFailure
|
|
70
|
+
} : {}
|
|
71
|
+
}).then(()=>undefined)
|
|
72
|
+
}),
|
|
73
|
+
...webhookRoutes
|
|
27
74
|
] : [];
|
|
28
75
|
return {
|
|
29
76
|
provider: JIRA_PROVIDER,
|
|
30
77
|
displayName: 'Jira',
|
|
31
|
-
adapters
|
|
78
|
+
adapters,
|
|
32
79
|
async connectionExternalUrl (connection) {
|
|
33
80
|
return (await getInstallationByConnectionId(connection.id))?.siteUrl;
|
|
34
81
|
},
|
|
35
|
-
routes
|
|
82
|
+
routes,
|
|
83
|
+
webhookProcessors: webhookProcessor ? [
|
|
84
|
+
{
|
|
85
|
+
routeIds: [
|
|
86
|
+
'jira'
|
|
87
|
+
],
|
|
88
|
+
processor: webhookProcessor
|
|
89
|
+
}
|
|
90
|
+
] : undefined
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function jiraWebhookUrl(connectionId) {
|
|
94
|
+
return `${config.JIRA_WEBHOOK_BASE_URL.replace(TRAILING_SLASHES_RE, '')}${JIRA_WEBHOOK_ROUTE_PREFIX}/${connectionId}`;
|
|
95
|
+
}
|
|
96
|
+
function toJiraWebhookOptions(routes) {
|
|
97
|
+
if (!routes) return undefined;
|
|
98
|
+
if (routes.coreDb === undefined || routes.publishIntegrationEventReceived === undefined || routes.recordDeliveryOnly === undefined || routes.getIntegrationConnectionById === undefined) throw new Error('Jira integration provider requires all webhook receiver dependencies: coreDb, publishIntegrationEventReceived, recordDeliveryOnly, and getIntegrationConnectionById');
|
|
99
|
+
return {
|
|
100
|
+
coreDb: routes.coreDb,
|
|
101
|
+
publishIntegrationEventReceived: routes.publishIntegrationEventReceived,
|
|
102
|
+
recordDeliveryOnly: routes.recordDeliveryOnly,
|
|
103
|
+
getIntegrationConnectionById: routes.getIntegrationConnectionById
|
|
36
104
|
};
|
|
37
105
|
}
|
|
38
106
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {JIRA_PROVIDER} from '@shipfox/api-integration-jira-dto';\nimport {createJiraApiClient, type JiraApiClient} from '#api/client.js';\nimport {config} from '#config.js';\nimport {closeDb, db} from '#db/db.js';\nimport {getJiraInstallationByConnectionId} from '#db/installations.js';\nimport {migrationsPath} from '#db/migrations.js';\nimport {\n type CreateJiraIntegrationRoutesOptions,\n createJiraIntegrationRoutes,\n} from '#presentation/routes/install.js';\n\nexport type {JiraProvider} from '@shipfox/api-integration-jira-dto';\nexport type {\n JiraAccessibleResource,\n JiraApiClient,\n JiraAuthorization,\n JiraIdentity,\n} from '#api/client.js';\nexport {createJiraApiClient, mapJiraError} from '#api/client.js';\nexport type {DisconnectJiraInstallationParams} from '#core/disconnect.js';\nexport {disconnectJiraInstallation} from '#core/disconnect.js';\nexport {\n JiraAccessTokenMissingError,\n JiraAuthorizationScopeMismatchError,\n JiraConnectionAlreadyLinkedError,\n JiraConnectionNotFoundError,\n JiraInstallationAlreadyLinkedError,\n JiraInstallationSiteMismatchError,\n JiraInstallStateActorMismatchError,\n JiraInstallStateError,\n JiraIntegrationProviderError,\n JiraOAuthCallbackError,\n JiraOfflineAccessNotGrantedError,\n JiraPendingSelectionNotFoundError,\n JiraSiteSelectionMismatchError,\n JiraTokenUnrefreshableError,\n} from '#core/errors.js';\nexport type {ConnectJiraInstallationInput, HandleJiraCallbackParams} from '#core/install.js';\nexport {\n handleJiraCallback,\n handleJiraOAuthCallbackError,\n handleJiraSiteSelection,\n} from '#core/install.js';\nexport type {JiraPendingSelectionSecretsStore, JiraPendingSelectionStore} from '#core/pending.js';\nexport {createJiraPendingSelectionStore, jiraPendingSecretsNamespace} from '#core/pending.js';\nexport {\n assertJiraAuthorizationScopes,\n formatJiraOAuthScopes,\n JIRA_OAUTH_SCOPES,\n} from '#core/scopes.js';\nexport {signJiraInstallState, verifyJiraInstallState} from '#core/state.js';\nexport type {\n CreateJiraTokenStoreParams,\n GetJiraAccessTokenParams,\n JiraConnectionResolverResult,\n JiraSecretsStore,\n JiraTokenStore,\n StoreJiraTokensParams,\n} from '#core/tokens.js';\nexport {createJiraTokenStore, jiraSecretsNamespace} from '#core/tokens.js';\nexport type {\n JiraInstallation,\n JiraInstallationStatus,\n UpsertJiraInstallationParams,\n} from '#db/installations.js';\nexport {\n deleteJiraInstallationByConnectionId,\n getJiraInstallationByCloudId,\n getJiraInstallationByConnectionId,\n getJiraInstallationByWebhookId,\n markJiraInstallationRevoked,\n updateJiraInstallationTokenExpiry,\n upsertJiraInstallation,\n withJiraRefreshLock,\n} from '#db/installations.js';\nexport {closeDb, config, db, migrationsPath};\n\nexport interface CreateJiraIntegrationProviderOptions {\n jira?: JiraApiClient | undefined;\n getJiraInstallationByConnectionId?: typeof getJiraInstallationByConnectionId | undefined;\n routes?: Omit<CreateJiraIntegrationRoutesOptions, 'jira' | 'connectionCapabilities'> | undefined;\n}\n\nexport function createJiraIntegrationProvider(options: CreateJiraIntegrationProviderOptions = {}) {\n const jira = options.jira ?? createJiraApiClient();\n const getInstallationByConnectionId =\n options.getJiraInstallationByConnectionId ?? getJiraInstallationByConnectionId;\n const routes = options.routes\n ? [createJiraIntegrationRoutes({jira, connectionCapabilities: [], ...options.routes})]\n : [];\n return {\n provider: JIRA_PROVIDER,\n displayName: 'Jira',\n adapters: {},\n async connectionExternalUrl(connection: {id: string}): Promise<string | undefined> {\n return (await getInstallationByConnectionId(connection.id))?.siteUrl;\n },\n routes,\n };\n}\n"],"names":["JIRA_PROVIDER","createJiraApiClient","config","closeDb","db","getJiraInstallationByConnectionId","migrationsPath","createJiraIntegrationRoutes","mapJiraError","disconnectJiraInstallation","JiraAccessTokenMissingError","JiraAuthorizationScopeMismatchError","JiraConnectionAlreadyLinkedError","JiraConnectionNotFoundError","JiraInstallationAlreadyLinkedError","JiraInstallationSiteMismatchError","JiraInstallStateActorMismatchError","JiraInstallStateError","JiraIntegrationProviderError","JiraOAuthCallbackError","JiraOfflineAccessNotGrantedError","JiraPendingSelectionNotFoundError","JiraSiteSelectionMismatchError","JiraTokenUnrefreshableError","handleJiraCallback","handleJiraOAuthCallbackError","handleJiraSiteSelection","createJiraPendingSelectionStore","jiraPendingSecretsNamespace","assertJiraAuthorizationScopes","formatJiraOAuthScopes","JIRA_OAUTH_SCOPES","signJiraInstallState","verifyJiraInstallState","createJiraTokenStore","jiraSecretsNamespace","deleteJiraInstallationByConnectionId","getJiraInstallationByCloudId","getJiraInstallationByWebhookId","markJiraInstallationRevoked","updateJiraInstallationTokenExpiry","upsertJiraInstallation","withJiraRefreshLock","createJiraIntegrationProvider","options","jira","getInstallationByConnectionId","routes","connectionCapabilities","provider","displayName","adapters","connectionExternalUrl","connection","id","siteUrl"],"mappings":"AAAA,SAAQA,aAAa,QAAO,oCAAoC;AAChE,SAAQC,mBAAmB,QAA2B,iBAAiB;AACvE,SAAQC,MAAM,QAAO,aAAa;AAClC,SAAQC,OAAO,EAAEC,EAAE,QAAO,YAAY;AACtC,SAAQC,iCAAiC,QAAO,uBAAuB;AACvE,SAAQC,cAAc,QAAO,oBAAoB;AACjD,SAEEC,2BAA2B,QACtB,kCAAkC;AASzC,SAAQN,mBAAmB,EAAEO,YAAY,QAAO,iBAAiB;AAEjE,SAAQC,0BAA0B,QAAO,sBAAsB;AAC/D,SACEC,2BAA2B,EAC3BC,mCAAmC,EACnCC,gCAAgC,EAChCC,2BAA2B,EAC3BC,kCAAkC,EAClCC,iCAAiC,EACjCC,kCAAkC,EAClCC,qBAAqB,EACrBC,4BAA4B,EAC5BC,sBAAsB,EACtBC,gCAAgC,EAChCC,iCAAiC,EACjCC,8BAA8B,EAC9BC,2BAA2B,QACtB,kBAAkB;AAEzB,SACEC,kBAAkB,EAClBC,4BAA4B,EAC5BC,uBAAuB,QAClB,mBAAmB;AAE1B,SAAQC,+BAA+B,EAAEC,2BAA2B,QAAO,mBAAmB;AAC9F,SACEC,6BAA6B,EAC7BC,qBAAqB,EACrBC,iBAAiB,QACZ,kBAAkB;AACzB,SAAQC,oBAAoB,EAAEC,sBAAsB,QAAO,iBAAiB;AAS5E,SAAQC,oBAAoB,EAAEC,oBAAoB,QAAO,kBAAkB;AAM3E,SACEC,oCAAoC,EACpCC,4BAA4B,EAC5BhC,iCAAiC,EACjCiC,8BAA8B,EAC9BC,2BAA2B,EAC3BC,iCAAiC,EACjCC,sBAAsB,EACtBC,mBAAmB,QACd,uBAAuB;AAC9B,SAAQvC,OAAO,EAAED,MAAM,EAAEE,EAAE,EAAEE,cAAc,GAAE;AAQ7C,OAAO,SAASqC,8BAA8BC,UAAgD,CAAC,CAAC;IAC9F,MAAMC,OAAOD,QAAQC,IAAI,IAAI5C;IAC7B,MAAM6C,gCACJF,QAAQvC,iCAAiC,IAAIA;IAC/C,MAAM0C,SAASH,QAAQG,MAAM,GACzB;QAACxC,4BAA4B;YAACsC;YAAMG,wBAAwB,EAAE;YAAE,GAAGJ,QAAQG,MAAM;QAAA;KAAG,GACpF,EAAE;IACN,OAAO;QACLE,UAAUjD;QACVkD,aAAa;QACbC,UAAU,CAAC;QACX,MAAMC,uBAAsBC,UAAwB;YAClD,OAAQ,CAAA,MAAMP,8BAA8BO,WAAWC,EAAE,CAAA,GAAIC;QAC/D;QACAR;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {JIRA_PROVIDER} from '@shipfox/api-integration-jira-dto';\nimport {\n createJiraAgentToolsClient,\n createJiraApiClient,\n type JiraAgentToolsClient,\n type JiraApiClient,\n} from '#api/client.js';\nimport {config} from '#config.js';\nimport {JiraAgentToolsProvider} from '#core/agent-tools-provider.js';\nimport type {JiraTokenStore} from '#core/tokens.js';\nimport {createJiraWebhookProcessor} from '#core/webhook-processor.js';\nimport {registerJiraWebhook} from '#core/webhook-registration.js';\nimport {closeDb, db} from '#db/db.js';\nimport {getJiraInstallationByConnectionId} from '#db/installations.js';\nimport {migrationsPath} from '#db/migrations.js';\nimport {\n type CreateJiraIntegrationRoutesOptions,\n createJiraIntegrationRoutes,\n} from '#presentation/routes/install.js';\nimport {\n type CreateJiraWebhookRoutesOptions,\n createJiraWebhookRoutes,\n JIRA_WEBHOOK_ROUTE_PREFIX,\n} from '#presentation/routes/webhooks.js';\n\nconst TRAILING_SLASHES_RE = /\\/+$/;\n\nexport type {JiraProvider} from '@shipfox/api-integration-jira-dto';\nexport type {\n JiraAccessibleResource,\n JiraAgentToolHttpMethod,\n JiraAgentToolQueryValue,\n JiraAgentToolRequest,\n JiraAgentToolResponse,\n JiraAgentToolsClient,\n JiraApiClient,\n JiraAuthorization,\n JiraDynamicWebhookRegistration,\n JiraIdentity,\n} from '#api/client.js';\nexport {\n createJiraAgentToolsClient,\n createJiraApiClient,\n JIRA_DYNAMIC_WEBHOOK_EVENTS,\n JIRA_DYNAMIC_WEBHOOK_JQL,\n mapJiraError,\n} from '#api/client.js';\nexport type {\n JiraAgentToolCatalogEntry,\n JiraAgentToolId,\n JiraAgentToolRequiredScope,\n} from '#core/agent-tools.js';\nexport {\n jiraAgentToolCatalog,\n jiraAgentToolSelectionCatalog,\n jiraPlainTextToAdf,\n} from '#core/agent-tools.js';\nexport type {\n JiraAgentToolsProviderOptions,\n JiraToolCallResult,\n} from '#core/agent-tools-provider.js';\nexport {JiraAgentToolsProvider} from '#core/agent-tools-provider.js';\nexport type {DisconnectJiraInstallationParams} from '#core/disconnect.js';\nexport {disconnectJiraInstallation} from '#core/disconnect.js';\nexport {\n JiraAccessTokenMissingError,\n JiraAuthorizationScopeMismatchError,\n JiraConnectionAlreadyLinkedError,\n JiraConnectionNotFoundError,\n JiraInstallationAlreadyLinkedError,\n JiraInstallationSiteMismatchError,\n JiraInstallStateActorMismatchError,\n JiraInstallStateError,\n JiraIntegrationProviderError,\n JiraOAuthCallbackError,\n JiraOfflineAccessNotGrantedError,\n JiraPendingSelectionNotFoundError,\n JiraSiteSelectionMismatchError,\n JiraTokenUnrefreshableError,\n} from '#core/errors.js';\nexport type {ConnectJiraInstallationInput, HandleJiraCallbackParams} from '#core/install.js';\nexport {\n handleJiraCallback,\n handleJiraOAuthCallbackError,\n handleJiraSiteSelection,\n} from '#core/install.js';\nexport type {JiraPendingSelectionSecretsStore, JiraPendingSelectionStore} from '#core/pending.js';\nexport {createJiraPendingSelectionStore, jiraPendingSecretsNamespace} from '#core/pending.js';\nexport {\n assertJiraAuthorizationScopes,\n formatJiraOAuthScopes,\n JIRA_OAUTH_SCOPES,\n} from '#core/scopes.js';\nexport {signJiraInstallState, verifyJiraInstallState} from '#core/state.js';\nexport type {\n CreateJiraTokenStoreParams,\n GetJiraAccessTokenParams,\n JiraConnectionResolverResult,\n JiraSecretsStore,\n JiraTokenStore,\n StoreJiraTokensParams,\n} from '#core/tokens.js';\nexport {createJiraTokenStore, jiraSecretsNamespace} from '#core/tokens.js';\nexport type {\n CreateJiraWebhookProcessorOptions,\n JiraWebhookProcessor,\n} from '#core/webhook-processor.js';\nexport {createJiraWebhookProcessor} from '#core/webhook-processor.js';\nexport type {RegisterJiraWebhookParams} from '#core/webhook-registration.js';\nexport {JIRA_WEBHOOK_TTL_MS, registerJiraWebhook} from '#core/webhook-registration.js';\nexport type {\n JiraInstallation,\n JiraInstallationLock,\n JiraInstallationStatus,\n UpdateJiraInstallationWebhookParams,\n UpsertJiraInstallationParams,\n} from '#db/installations.js';\nexport {\n deleteJiraInstallationByConnectionId,\n getJiraInstallationByCloudId,\n getJiraInstallationByConnectionId,\n getJiraInstallationByWebhookId,\n listJiraInstallationsDueForTokenRefresh,\n markJiraInstallationRevoked,\n updateJiraInstallationTokenExpiry,\n updateJiraInstallationWebhook,\n upsertJiraInstallation,\n withJiraRefreshLock,\n withJiraWebhookRegistrationLock,\n} from '#db/installations.js';\nexport type {CreateJiraWebhookRoutesOptions} from '#presentation/routes/webhooks.js';\nexport {createJiraWebhookRoutes} from '#presentation/routes/webhooks.js';\nexport {createJiraMaintenanceWorker} from '#temporal/worker.js';\nexport {closeDb, config, db, migrationsPath};\n\nexport interface CreateJiraIntegrationProviderOptions {\n jira?: JiraApiClient | undefined;\n agentTools?:\n | {\n tokenStore: Pick<JiraTokenStore, 'getAccessToken'>;\n jira?: JiraAgentToolsClient | undefined;\n }\n | undefined;\n getJiraInstallationByConnectionId?: typeof getJiraInstallationByConnectionId | undefined;\n routes?: JiraIntegrationProviderRoutesOptions | undefined;\n}\n\ntype JiraIntegrationProviderRoutesOptions = Omit<\n CreateJiraIntegrationRoutesOptions,\n 'jira' | 'connectionCapabilities' | 'registerJiraWebhook'\n> &\n Omit<CreateJiraWebhookRoutesOptions, 'processor'>;\n\nexport function createJiraIntegrationProvider(options: CreateJiraIntegrationProviderOptions = {}) {\n const jira = options.jira ?? createJiraApiClient();\n const getInstallationByConnectionId =\n options.getJiraInstallationByConnectionId ?? getJiraInstallationByConnectionId;\n const adapters = options.agentTools\n ? {\n agent_tools: new JiraAgentToolsProvider({\n jira: options.agentTools.jira ?? createJiraAgentToolsClient(),\n tokenStore: options.agentTools.tokenStore,\n }),\n }\n : {};\n const webhookOptions = toJiraWebhookOptions(options.routes);\n const webhookProcessor = webhookOptions ? createJiraWebhookProcessor(webhookOptions) : undefined;\n const webhookRoutes = webhookOptions\n ? [\n createJiraWebhookRoutes({\n coreDb: webhookOptions.coreDb,\n publishIntegrationEventReceived: webhookOptions.publishIntegrationEventReceived,\n recordDeliveryOnly: webhookOptions.recordDeliveryOnly,\n getIntegrationConnectionById: webhookOptions.getIntegrationConnectionById,\n processor: webhookProcessor,\n }),\n ]\n : [];\n const routes = options.routes\n ? [\n createJiraIntegrationRoutes({\n jira,\n connectionCapabilities: adapters.agent_tools ? ['agent_tools'] : [],\n ...options.routes,\n registerJiraWebhook: (input) =>\n registerJiraWebhook({\n jira,\n connectionId: input.connectionId,\n cloudId: input.cloudId,\n accessToken: input.accessToken,\n webhookUrl: jiraWebhookUrl(input.connectionId),\n ...(input.withRegistrationLock\n ? {withRegistrationLock: input.withRegistrationLock}\n : {}),\n ...(input.onRegistrationSuccess\n ? {onRegistrationSuccess: input.onRegistrationSuccess}\n : {}),\n ...(input.onRegistrationFailure\n ? {onRegistrationFailure: input.onRegistrationFailure}\n : {}),\n }).then(() => undefined),\n }),\n ...webhookRoutes,\n ]\n : [];\n return {\n provider: JIRA_PROVIDER,\n displayName: 'Jira',\n adapters,\n async connectionExternalUrl(connection: {id: string}): Promise<string | undefined> {\n return (await getInstallationByConnectionId(connection.id))?.siteUrl;\n },\n routes,\n webhookProcessors: webhookProcessor\n ? [{routeIds: ['jira'] as const, processor: webhookProcessor}]\n : undefined,\n };\n}\n\nfunction jiraWebhookUrl(connectionId: string): string {\n return `${config.JIRA_WEBHOOK_BASE_URL.replace(TRAILING_SLASHES_RE, '')}${JIRA_WEBHOOK_ROUTE_PREFIX}/${connectionId}`;\n}\n\nfunction toJiraWebhookOptions(\n routes: CreateJiraIntegrationProviderOptions['routes'],\n): CreateJiraWebhookRoutesOptions | undefined {\n if (!routes) return undefined;\n if (\n routes.coreDb === undefined ||\n routes.publishIntegrationEventReceived === undefined ||\n routes.recordDeliveryOnly === undefined ||\n routes.getIntegrationConnectionById === undefined\n )\n throw new Error(\n 'Jira integration provider requires all webhook receiver dependencies: coreDb, publishIntegrationEventReceived, recordDeliveryOnly, and getIntegrationConnectionById',\n );\n return {\n coreDb: routes.coreDb,\n publishIntegrationEventReceived: routes.publishIntegrationEventReceived,\n recordDeliveryOnly: routes.recordDeliveryOnly,\n getIntegrationConnectionById: routes.getIntegrationConnectionById,\n };\n}\n"],"names":["JIRA_PROVIDER","createJiraAgentToolsClient","createJiraApiClient","config","JiraAgentToolsProvider","createJiraWebhookProcessor","registerJiraWebhook","closeDb","db","getJiraInstallationByConnectionId","migrationsPath","createJiraIntegrationRoutes","createJiraWebhookRoutes","JIRA_WEBHOOK_ROUTE_PREFIX","TRAILING_SLASHES_RE","JIRA_DYNAMIC_WEBHOOK_EVENTS","JIRA_DYNAMIC_WEBHOOK_JQL","mapJiraError","jiraAgentToolCatalog","jiraAgentToolSelectionCatalog","jiraPlainTextToAdf","disconnectJiraInstallation","JiraAccessTokenMissingError","JiraAuthorizationScopeMismatchError","JiraConnectionAlreadyLinkedError","JiraConnectionNotFoundError","JiraInstallationAlreadyLinkedError","JiraInstallationSiteMismatchError","JiraInstallStateActorMismatchError","JiraInstallStateError","JiraIntegrationProviderError","JiraOAuthCallbackError","JiraOfflineAccessNotGrantedError","JiraPendingSelectionNotFoundError","JiraSiteSelectionMismatchError","JiraTokenUnrefreshableError","handleJiraCallback","handleJiraOAuthCallbackError","handleJiraSiteSelection","createJiraPendingSelectionStore","jiraPendingSecretsNamespace","assertJiraAuthorizationScopes","formatJiraOAuthScopes","JIRA_OAUTH_SCOPES","signJiraInstallState","verifyJiraInstallState","createJiraTokenStore","jiraSecretsNamespace","JIRA_WEBHOOK_TTL_MS","deleteJiraInstallationByConnectionId","getJiraInstallationByCloudId","getJiraInstallationByWebhookId","listJiraInstallationsDueForTokenRefresh","markJiraInstallationRevoked","updateJiraInstallationTokenExpiry","updateJiraInstallationWebhook","upsertJiraInstallation","withJiraRefreshLock","withJiraWebhookRegistrationLock","createJiraMaintenanceWorker","createJiraIntegrationProvider","options","jira","getInstallationByConnectionId","adapters","agentTools","agent_tools","tokenStore","webhookOptions","toJiraWebhookOptions","routes","webhookProcessor","undefined","webhookRoutes","coreDb","publishIntegrationEventReceived","recordDeliveryOnly","getIntegrationConnectionById","processor","connectionCapabilities","input","connectionId","cloudId","accessToken","webhookUrl","jiraWebhookUrl","withRegistrationLock","onRegistrationSuccess","onRegistrationFailure","then","provider","displayName","connectionExternalUrl","connection","id","siteUrl","webhookProcessors","routeIds","JIRA_WEBHOOK_BASE_URL","replace","Error"],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ import type { JiraApiClient } from '#api/client.js';
|
|
|
4
4
|
import { type ConnectJiraInstallationInput } from '#core/install.js';
|
|
5
5
|
import type { JiraPendingSelectionStore } from '#core/pending.js';
|
|
6
6
|
import type { JiraTokenStore } from '#core/tokens.js';
|
|
7
|
+
import type { JiraInstallationLock } from '#db/installations.js';
|
|
7
8
|
export interface CreateJiraIntegrationRoutesOptions {
|
|
8
9
|
jira: JiraApiClient;
|
|
9
10
|
tokenStore: Pick<JiraTokenStore, 'storeTokens'>;
|
|
@@ -12,6 +13,27 @@ export interface CreateJiraIntegrationRoutesOptions {
|
|
|
12
13
|
cloudId: string;
|
|
13
14
|
}): Promise<IntegrationConnection<'jira'> | undefined>;
|
|
14
15
|
connectJiraInstallation(input: ConnectJiraInstallationInput): Promise<IntegrationConnection<'jira'>>;
|
|
16
|
+
registerJiraWebhook(input: {
|
|
17
|
+
connectionId: string;
|
|
18
|
+
cloudId: string;
|
|
19
|
+
accessToken: string;
|
|
20
|
+
withRegistrationLock?: JiraInstallationLock;
|
|
21
|
+
onRegistrationSuccess: (input: {
|
|
22
|
+
tx?: unknown;
|
|
23
|
+
}) => Promise<void>;
|
|
24
|
+
onRegistrationFailure: (input: {
|
|
25
|
+
tx?: unknown;
|
|
26
|
+
}) => Promise<void>;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
withJiraInstallationLock?: JiraInstallationLock;
|
|
29
|
+
markConnectionActive(input: {
|
|
30
|
+
connectionId: string;
|
|
31
|
+
tx?: unknown;
|
|
32
|
+
}): Promise<void>;
|
|
33
|
+
markConnectionError(input: {
|
|
34
|
+
connectionId: string;
|
|
35
|
+
tx?: unknown;
|
|
36
|
+
}): Promise<void>;
|
|
15
37
|
disconnectJiraInstallation(input: {
|
|
16
38
|
connectionId: string;
|
|
17
39
|
}): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/install.ts"],"names":[],"mappings":"AASA,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAE3B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAc,KAAK,UAAU,EAAC,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAElD,OAAO,EACL,KAAK,4BAA4B,EAIlC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,kBAAkB,CAAC;AAGhE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/install.ts"],"names":[],"mappings":"AASA,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAE3B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAc,KAAK,UAAU,EAAC,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAElD,OAAO,EACL,KAAK,4BAA4B,EAIlC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,kBAAkB,CAAC;AAGhE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,sBAAsB,CAAC;AAI/D,MAAM,WAAW,kCAAkC;IACjD,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,IAAI,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;IAChD,YAAY,EAAE,IAAI,CAAC,yBAAyB,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACzE,yBAAyB,CAAC,KAAK,EAAE;QAC/B,OAAO,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,qBAAqB,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;IACvD,uBAAuB,CACrB,KAAK,EAAE,4BAA4B,GAClC,OAAO,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1C,mBAAmB,CAAC,KAAK,EAAE;QACzB,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;QAC5C,qBAAqB,EAAE,CAAC,KAAK,EAAE;YAAC,EAAE,CAAC,EAAE,OAAO,CAAA;SAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAChE,qBAAqB,EAAE,CAAC,KAAK,EAAE;YAAC,EAAE,CAAC,EAAE,OAAO,CAAA;SAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACjE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,wBAAwB,CAAC,EAAE,oBAAoB,CAAC;IAChD,oBAAoB,CAAC,KAAK,EAAE;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,OAAO,CAAA;KAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjF,mBAAmB,CAAC,KAAK,EAAE;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,OAAO,CAAA;KAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,0BAA0B,CAAC,KAAK,EAAE;QAAC,YAAY,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,sBAAsB,EAAE,qBAAqB,EAAE,CAAC;IAChD,gCAAgC,CAAC,EAAE,CAAC,KAAK,EAAE;QACzC,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,aAAa,CAAC,OAAO,2BAA2B,EAAE,qBAAqB,CAAC,CAAC;KACvF,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACxB;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,kCAAkC,GAC1C,UAAU,CA6FZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/presentation/routes/install.ts"],"sourcesContent":["import {AUTH_USER, requireUserContext, requireWorkspaceAccess} from '@shipfox/api-auth-context';\nimport {\n completeJiraSiteSelectionBodySchema,\n createJiraInstallBodySchema,\n createJiraInstallResponseSchema,\n type JiraCallbackQueryDto,\n jiraCallbackQuerySchema,\n jiraCallbackResponseSchema,\n} from '@shipfox/api-integration-jira-dto';\nimport {\n type IntegrationCapability,\n type IntegrationConnection,\n integrationConnectionDtoSchema,\n} from '@shipfox/api-integration-spi';\nimport {defineRoute, type RouteGroup} from '@shipfox/node-fastify';\nimport type {JiraApiClient} from '#api/client.js';\nimport {config} from '#config.js';\nimport {\n type ConnectJiraInstallationInput,\n handleJiraCallback,\n handleJiraOAuthCallbackError,\n handleJiraSiteSelection,\n} from '#core/install.js';\nimport type {JiraPendingSelectionStore} from '#core/pending.js';\nimport {formatJiraOAuthScopes} from '#core/scopes.js';\nimport {signJiraInstallState} from '#core/state.js';\nimport type {JiraTokenStore} from '#core/tokens.js';\nimport {toIntegrationConnectionDto} from '#presentation/dto/integrations.js';\nimport {jiraRouteErrorHandler} from './errors.js';\n\nexport interface CreateJiraIntegrationRoutesOptions {\n jira: JiraApiClient;\n tokenStore: Pick<JiraTokenStore, 'storeTokens'>;\n pendingStore: Pick<JiraPendingSelectionStore, 'save' | 'load' | 'clear'>;\n getExistingJiraConnection(input: {\n cloudId: string;\n }): Promise<IntegrationConnection<'jira'> | undefined>;\n connectJiraInstallation(\n input: ConnectJiraInstallationInput,\n ): Promise<IntegrationConnection<'jira'>>;\n disconnectJiraInstallation(input: {connectionId: string}): Promise<void>;\n connectionCapabilities: IntegrationCapability[];\n requireActiveWorkspaceMembership?: (input: {\n workspaceId: string;\n userId: string;\n memberships: ReadonlyArray<import('@shipfox/api-auth-context').UserContextMembership>;\n }) => Promise<unknown>;\n}\n\nexport function createJiraIntegrationRoutes(\n options: CreateJiraIntegrationRoutesOptions,\n): RouteGroup {\n const requireMembership =\n options.requireActiveWorkspaceMembership ?? unavailableWorkspaceMembershipCheck;\n const installRoute = defineRoute({\n method: 'POST',\n path: '/install',\n auth: AUTH_USER,\n description: 'Create a Jira OAuth authorization URL for a workspace.',\n schema: {body: createJiraInstallBodySchema, response: {200: createJiraInstallResponseSchema}},\n handler: (request) => {\n const {workspace_id: workspaceId} = request.body;\n const actor = requireUserContext(request);\n requireWorkspaceAccess({request, workspaceId});\n const installUrl = new URL(`${config.JIRA_AUTH_BASE_URL}/authorize`);\n installUrl.searchParams.set('audience', 'api.atlassian.com');\n installUrl.searchParams.set('client_id', config.JIRA_OAUTH_CLIENT_ID);\n installUrl.searchParams.set('scope', formatJiraOAuthScopes());\n installUrl.searchParams.set('redirect_uri', config.JIRA_OAUTH_REDIRECT_URL);\n installUrl.searchParams.set(\n 'state',\n signJiraInstallState({workspaceId, userId: actor.userId}),\n );\n installUrl.searchParams.set('response_type', 'code');\n installUrl.searchParams.set('prompt', 'consent');\n return {install_url: installUrl.toString()};\n },\n });\n const callbackApiRoute = defineRoute({\n method: 'GET',\n path: '/callback/api',\n auth: AUTH_USER,\n description: 'Handle the Jira OAuth callback.',\n schema: {querystring: jiraCallbackQuerySchema, response: {200: jiraCallbackResponseSchema}},\n errorHandler: jiraRouteErrorHandler,\n handler: async (request) => {\n const actor = requireUserContext(request);\n const query = request.query;\n if (isJiraOAuthErrorCallback(query))\n return await handleJiraOAuthCallbackError({\n state: query.state,\n error: query.error,\n errorDescription: query.error_description,\n sessionUserId: actor.userId,\n sessionMemberships: actor.memberships,\n requireWorkspaceMembership: requireMembership,\n });\n const result = await handleJiraCallback({\n ...options,\n code: query.code,\n state: query.state,\n sessionUserId: actor.userId,\n sessionMemberships: actor.memberships,\n requireWorkspaceMembership: requireMembership,\n });\n return 'sites' in result\n ? {\n sites: result.sites.map((site) => ({\n cloud_id: site.cloudId,\n name: site.name,\n url: site.url,\n scopes: site.scopes,\n })),\n }\n : toIntegrationConnectionDto(result, {capabilities: options.connectionCapabilities});\n },\n });\n const siteSelectionRoute = defineRoute({\n method: 'POST',\n path: '/callback/site',\n auth: AUTH_USER,\n description: 'Complete Jira OAuth site selection.',\n schema: {\n body: completeJiraSiteSelectionBodySchema,\n response: {200: integrationConnectionDtoSchema},\n },\n errorHandler: jiraRouteErrorHandler,\n handler: async (request) => {\n const actor = requireUserContext(request);\n const connection = await handleJiraSiteSelection({\n ...options,\n cloudId: request.body.cloud_id,\n state: request.body.state,\n sessionUserId: actor.userId,\n sessionMemberships: actor.memberships,\n requireWorkspaceMembership: requireMembership,\n });\n return toIntegrationConnectionDto(connection, {capabilities: options.connectionCapabilities});\n },\n });\n return {\n prefix: '/integrations/jira',\n routes: [installRoute, callbackApiRoute, siteSelectionRoute],\n };\n}\n\nfunction unavailableWorkspaceMembershipCheck(_input: {\n workspaceId: string;\n userId: string;\n memberships: ReadonlyArray<import('@shipfox/api-auth-context').UserContextMembership>;\n}): Promise<never> {\n return Promise.reject(new Error('Workspaces inter-module client is not configured'));\n}\n\nfunction isJiraOAuthErrorCallback(query: JiraCallbackQueryDto): query is JiraCallbackQueryDto & {\n error: string;\n error_description?: string | undefined;\n state: string;\n} {\n return 'error' in query && typeof query.error === 'string';\n}\n"],"names":["AUTH_USER","requireUserContext","requireWorkspaceAccess","completeJiraSiteSelectionBodySchema","createJiraInstallBodySchema","createJiraInstallResponseSchema","jiraCallbackQuerySchema","jiraCallbackResponseSchema","integrationConnectionDtoSchema","defineRoute","config","handleJiraCallback","handleJiraOAuthCallbackError","handleJiraSiteSelection","formatJiraOAuthScopes","signJiraInstallState","toIntegrationConnectionDto","jiraRouteErrorHandler","createJiraIntegrationRoutes","options","requireMembership","requireActiveWorkspaceMembership","unavailableWorkspaceMembershipCheck","installRoute","method","path","auth","description","schema","body","response","handler","request","workspace_id","workspaceId","actor","installUrl","URL","JIRA_AUTH_BASE_URL","searchParams","set","JIRA_OAUTH_CLIENT_ID","JIRA_OAUTH_REDIRECT_URL","userId","install_url","toString","callbackApiRoute","querystring","errorHandler","query","isJiraOAuthErrorCallback","state","error","errorDescription","error_description","sessionUserId","sessionMemberships","memberships","requireWorkspaceMembership","result","code","sites","map","site","cloud_id","cloudId","name","url","scopes","capabilities","connectionCapabilities","siteSelectionRoute","connection","prefix","routes","_input","Promise","reject","Error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/presentation/routes/install.ts"],"sourcesContent":["import {AUTH_USER, requireUserContext, requireWorkspaceAccess} from '@shipfox/api-auth-context';\nimport {\n completeJiraSiteSelectionBodySchema,\n createJiraInstallBodySchema,\n createJiraInstallResponseSchema,\n type JiraCallbackQueryDto,\n jiraCallbackQuerySchema,\n jiraCallbackResponseSchema,\n} from '@shipfox/api-integration-jira-dto';\nimport {\n type IntegrationCapability,\n type IntegrationConnection,\n integrationConnectionDtoSchema,\n} from '@shipfox/api-integration-spi';\nimport {defineRoute, type RouteGroup} from '@shipfox/node-fastify';\nimport type {JiraApiClient} from '#api/client.js';\nimport {config} from '#config.js';\nimport {\n type ConnectJiraInstallationInput,\n handleJiraCallback,\n handleJiraOAuthCallbackError,\n handleJiraSiteSelection,\n} from '#core/install.js';\nimport type {JiraPendingSelectionStore} from '#core/pending.js';\nimport {formatJiraOAuthScopes} from '#core/scopes.js';\nimport {signJiraInstallState} from '#core/state.js';\nimport type {JiraTokenStore} from '#core/tokens.js';\nimport type {JiraInstallationLock} from '#db/installations.js';\nimport {toIntegrationConnectionDto} from '#presentation/dto/integrations.js';\nimport {jiraRouteErrorHandler} from './errors.js';\n\nexport interface CreateJiraIntegrationRoutesOptions {\n jira: JiraApiClient;\n tokenStore: Pick<JiraTokenStore, 'storeTokens'>;\n pendingStore: Pick<JiraPendingSelectionStore, 'save' | 'load' | 'clear'>;\n getExistingJiraConnection(input: {\n cloudId: string;\n }): Promise<IntegrationConnection<'jira'> | undefined>;\n connectJiraInstallation(\n input: ConnectJiraInstallationInput,\n ): Promise<IntegrationConnection<'jira'>>;\n registerJiraWebhook(input: {\n connectionId: string;\n cloudId: string;\n accessToken: string;\n withRegistrationLock?: JiraInstallationLock;\n onRegistrationSuccess: (input: {tx?: unknown}) => Promise<void>;\n onRegistrationFailure: (input: {tx?: unknown}) => Promise<void>;\n }): Promise<void>;\n withJiraInstallationLock?: JiraInstallationLock;\n markConnectionActive(input: {connectionId: string; tx?: unknown}): Promise<void>;\n markConnectionError(input: {connectionId: string; tx?: unknown}): Promise<void>;\n disconnectJiraInstallation(input: {connectionId: string}): Promise<void>;\n connectionCapabilities: IntegrationCapability[];\n requireActiveWorkspaceMembership?: (input: {\n workspaceId: string;\n userId: string;\n memberships: ReadonlyArray<import('@shipfox/api-auth-context').UserContextMembership>;\n }) => Promise<unknown>;\n}\n\nexport function createJiraIntegrationRoutes(\n options: CreateJiraIntegrationRoutesOptions,\n): RouteGroup {\n const requireMembership =\n options.requireActiveWorkspaceMembership ?? unavailableWorkspaceMembershipCheck;\n const installRoute = defineRoute({\n method: 'POST',\n path: '/install',\n auth: AUTH_USER,\n description: 'Create a Jira OAuth authorization URL for a workspace.',\n schema: {body: createJiraInstallBodySchema, response: {200: createJiraInstallResponseSchema}},\n handler: (request) => {\n const {workspace_id: workspaceId} = request.body;\n const actor = requireUserContext(request);\n requireWorkspaceAccess({request, workspaceId});\n const installUrl = new URL(`${config.JIRA_AUTH_BASE_URL}/authorize`);\n installUrl.searchParams.set('audience', 'api.atlassian.com');\n installUrl.searchParams.set('client_id', config.JIRA_OAUTH_CLIENT_ID);\n installUrl.searchParams.set('scope', formatJiraOAuthScopes());\n installUrl.searchParams.set('redirect_uri', config.JIRA_OAUTH_REDIRECT_URL);\n installUrl.searchParams.set(\n 'state',\n signJiraInstallState({workspaceId, userId: actor.userId}),\n );\n installUrl.searchParams.set('response_type', 'code');\n installUrl.searchParams.set('prompt', 'consent');\n return {install_url: installUrl.toString()};\n },\n });\n const callbackApiRoute = defineRoute({\n method: 'GET',\n path: '/callback/api',\n auth: AUTH_USER,\n description: 'Handle the Jira OAuth callback.',\n schema: {querystring: jiraCallbackQuerySchema, response: {200: jiraCallbackResponseSchema}},\n errorHandler: jiraRouteErrorHandler,\n handler: async (request) => {\n const actor = requireUserContext(request);\n const query = request.query;\n if (isJiraOAuthErrorCallback(query))\n return await handleJiraOAuthCallbackError({\n state: query.state,\n error: query.error,\n errorDescription: query.error_description,\n sessionUserId: actor.userId,\n sessionMemberships: actor.memberships,\n requireWorkspaceMembership: requireMembership,\n });\n const result = await handleJiraCallback({\n ...options,\n code: query.code,\n state: query.state,\n sessionUserId: actor.userId,\n sessionMemberships: actor.memberships,\n requireWorkspaceMembership: requireMembership,\n });\n return 'sites' in result\n ? {\n sites: result.sites.map((site) => ({\n cloud_id: site.cloudId,\n name: site.name,\n url: site.url,\n scopes: site.scopes,\n })),\n }\n : toIntegrationConnectionDto(result, {capabilities: options.connectionCapabilities});\n },\n });\n const siteSelectionRoute = defineRoute({\n method: 'POST',\n path: '/callback/site',\n auth: AUTH_USER,\n description: 'Complete Jira OAuth site selection.',\n schema: {\n body: completeJiraSiteSelectionBodySchema,\n response: {200: integrationConnectionDtoSchema},\n },\n errorHandler: jiraRouteErrorHandler,\n handler: async (request) => {\n const actor = requireUserContext(request);\n const connection = await handleJiraSiteSelection({\n ...options,\n cloudId: request.body.cloud_id,\n state: request.body.state,\n sessionUserId: actor.userId,\n sessionMemberships: actor.memberships,\n requireWorkspaceMembership: requireMembership,\n });\n return toIntegrationConnectionDto(connection, {capabilities: options.connectionCapabilities});\n },\n });\n return {\n prefix: '/integrations/jira',\n routes: [installRoute, callbackApiRoute, siteSelectionRoute],\n };\n}\n\nfunction unavailableWorkspaceMembershipCheck(_input: {\n workspaceId: string;\n userId: string;\n memberships: ReadonlyArray<import('@shipfox/api-auth-context').UserContextMembership>;\n}): Promise<never> {\n return Promise.reject(new Error('Workspaces inter-module client is not configured'));\n}\n\nfunction isJiraOAuthErrorCallback(query: JiraCallbackQueryDto): query is JiraCallbackQueryDto & {\n error: string;\n error_description?: string | undefined;\n state: string;\n} {\n return 'error' in query && typeof query.error === 'string';\n}\n"],"names":["AUTH_USER","requireUserContext","requireWorkspaceAccess","completeJiraSiteSelectionBodySchema","createJiraInstallBodySchema","createJiraInstallResponseSchema","jiraCallbackQuerySchema","jiraCallbackResponseSchema","integrationConnectionDtoSchema","defineRoute","config","handleJiraCallback","handleJiraOAuthCallbackError","handleJiraSiteSelection","formatJiraOAuthScopes","signJiraInstallState","toIntegrationConnectionDto","jiraRouteErrorHandler","createJiraIntegrationRoutes","options","requireMembership","requireActiveWorkspaceMembership","unavailableWorkspaceMembershipCheck","installRoute","method","path","auth","description","schema","body","response","handler","request","workspace_id","workspaceId","actor","installUrl","URL","JIRA_AUTH_BASE_URL","searchParams","set","JIRA_OAUTH_CLIENT_ID","JIRA_OAUTH_REDIRECT_URL","userId","install_url","toString","callbackApiRoute","querystring","errorHandler","query","isJiraOAuthErrorCallback","state","error","errorDescription","error_description","sessionUserId","sessionMemberships","memberships","requireWorkspaceMembership","result","code","sites","map","site","cloud_id","cloudId","name","url","scopes","capabilities","connectionCapabilities","siteSelectionRoute","connection","prefix","routes","_input","Promise","reject","Error"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type RouteGroup } from '@shipfox/node-fastify';
|
|
2
|
+
import { type CreateJiraWebhookProcessorOptions, type JiraWebhookProcessor } from '#core/webhook-processor.js';
|
|
3
|
+
export declare const JIRA_WEBHOOK_ROUTE_PREFIX = "/webhooks/integrations/jira";
|
|
4
|
+
export interface CreateJiraWebhookRoutesOptions extends Omit<CreateJiraWebhookProcessorOptions, 'getJiraInstallationByConnectionId'> {
|
|
5
|
+
processor?: JiraWebhookProcessor | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare function createJiraWebhookRoutes(options: CreateJiraWebhookRoutesOptions): RouteGroup;
|
|
8
|
+
//# sourceMappingURL=webhooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/webhooks.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,UAAU,EAGhB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,KAAK,iCAAiC,EAEtC,KAAK,oBAAoB,EAC1B,MAAM,4BAA4B,CAAC;AAGpC,eAAO,MAAM,yBAAyB,gCAAgC,CAAC;AAEvE,MAAM,WAAW,8BACf,SAAQ,IAAI,CAAC,iCAAiC,EAAE,mCAAmC,CAAC;IACpF,SAAS,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC9C;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,8BAA8B,GAAG,UAAU,CAgC3F"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { createStoredWebhookRequest, WEBHOOK_MAX_RAW_BODY_BYTES } from '@shipfox/api-integration-spi';
|
|
3
|
+
import { ClientError, defineRoute, rawBodyPlugin, WEBHOOK_BODY_LIMIT } from '@shipfox/node-fastify';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { createJiraWebhookProcessor } from '#core/webhook-processor.js';
|
|
6
|
+
const jiraWebhookParamsSchema = z.object({
|
|
7
|
+
connectionId: z.string().uuid()
|
|
8
|
+
});
|
|
9
|
+
export const JIRA_WEBHOOK_ROUTE_PREFIX = '/webhooks/integrations/jira';
|
|
10
|
+
export function createJiraWebhookRoutes(options) {
|
|
11
|
+
const processor = options.processor ?? createJiraWebhookProcessor(options);
|
|
12
|
+
const route = defineRoute({
|
|
13
|
+
method: 'POST',
|
|
14
|
+
path: '/:connectionId',
|
|
15
|
+
auth: [],
|
|
16
|
+
description: 'Jira dynamic webhook receiver.',
|
|
17
|
+
options: {
|
|
18
|
+
bodyLimit: WEBHOOK_BODY_LIMIT
|
|
19
|
+
},
|
|
20
|
+
schema: {
|
|
21
|
+
params: jiraWebhookParamsSchema
|
|
22
|
+
},
|
|
23
|
+
handler: async (request, reply)=>{
|
|
24
|
+
const body = request.body;
|
|
25
|
+
if (!(body instanceof Uint8Array)) {
|
|
26
|
+
throw new ClientError('Expected raw JSON body', 'invalid-webhook-request', {
|
|
27
|
+
status: 400
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const result = await processor.process(createJiraStoredWebhookRequest({
|
|
31
|
+
body,
|
|
32
|
+
connectionId: request.params.connectionId,
|
|
33
|
+
headers: request.headers,
|
|
34
|
+
rawQueryString: request.raw.url?.split('?')[1] ?? ''
|
|
35
|
+
}));
|
|
36
|
+
return sendJiraWebhookResponse(reply, result);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
prefix: JIRA_WEBHOOK_ROUTE_PREFIX,
|
|
41
|
+
auth: [],
|
|
42
|
+
plugins: [
|
|
43
|
+
rawBodyPlugin
|
|
44
|
+
],
|
|
45
|
+
routes: [
|
|
46
|
+
route
|
|
47
|
+
]
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function createJiraStoredWebhookRequest(input) {
|
|
51
|
+
if (input.body.byteLength > WEBHOOK_MAX_RAW_BODY_BYTES) {
|
|
52
|
+
throw new ClientError('Webhook request body is too large', 'body-too-large', {
|
|
53
|
+
status: 413
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
return createStoredWebhookRequest({
|
|
58
|
+
requestId: randomUUID(),
|
|
59
|
+
routeId: 'jira',
|
|
60
|
+
receivedAt: new Date().toISOString(),
|
|
61
|
+
rawQueryString: input.rawQueryString,
|
|
62
|
+
headers: jiraWebhookHeaders(input.headers),
|
|
63
|
+
body: input.body,
|
|
64
|
+
connectionId: input.connectionId
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
throw new ClientError('Webhook request metadata is invalid', 'invalid-webhook-request', {
|
|
68
|
+
cause: error
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function jiraWebhookHeaders(headers) {
|
|
73
|
+
return Object.fromEntries([
|
|
74
|
+
'authorization',
|
|
75
|
+
'content-type',
|
|
76
|
+
'x-atlassian-webhook-identifier'
|
|
77
|
+
].flatMap((name)=>{
|
|
78
|
+
const value = headers[name];
|
|
79
|
+
return typeof value === 'string' ? [
|
|
80
|
+
[
|
|
81
|
+
name,
|
|
82
|
+
value
|
|
83
|
+
]
|
|
84
|
+
] : [];
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
function sendJiraWebhookResponse(reply, result) {
|
|
88
|
+
if (result.outcome !== 'discarded') {
|
|
89
|
+
reply.code(200);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
if (result.reason === 'invalid_signature' || result.reason === 'missing_required_input') {
|
|
93
|
+
reply.code(401);
|
|
94
|
+
return {
|
|
95
|
+
error: 'invalid authorization'
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (result.reason === 'malformed_payload') {
|
|
99
|
+
reply.code(400);
|
|
100
|
+
return {
|
|
101
|
+
error: 'malformed JSON'
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
reply.code(200);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=webhooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/presentation/routes/webhooks.ts"],"sourcesContent":["import {randomUUID} from 'node:crypto';\nimport type {StoredWebhookRequest, WebhookProcessingResult} from '@shipfox/api-integration-spi';\nimport {createStoredWebhookRequest, WEBHOOK_MAX_RAW_BODY_BYTES} from '@shipfox/api-integration-spi';\nimport {\n ClientError,\n defineRoute,\n type RouteGroup,\n rawBodyPlugin,\n WEBHOOK_BODY_LIMIT,\n} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport {\n type CreateJiraWebhookProcessorOptions,\n createJiraWebhookProcessor,\n type JiraWebhookProcessor,\n} from '#core/webhook-processor.js';\n\nconst jiraWebhookParamsSchema = z.object({connectionId: z.string().uuid()});\nexport const JIRA_WEBHOOK_ROUTE_PREFIX = '/webhooks/integrations/jira';\n\nexport interface CreateJiraWebhookRoutesOptions\n extends Omit<CreateJiraWebhookProcessorOptions, 'getJiraInstallationByConnectionId'> {\n processor?: JiraWebhookProcessor | undefined;\n}\n\nexport function createJiraWebhookRoutes(options: CreateJiraWebhookRoutesOptions): RouteGroup {\n const processor = options.processor ?? createJiraWebhookProcessor(options);\n const route = defineRoute({\n method: 'POST',\n path: '/:connectionId',\n auth: [],\n description: 'Jira dynamic webhook receiver.',\n options: {bodyLimit: WEBHOOK_BODY_LIMIT},\n schema: {params: jiraWebhookParamsSchema},\n handler: async (request, reply) => {\n const body = request.body;\n if (!(body instanceof Uint8Array)) {\n throw new ClientError('Expected raw JSON body', 'invalid-webhook-request', {status: 400});\n }\n const result = await processor.process(\n createJiraStoredWebhookRequest({\n body,\n connectionId: request.params.connectionId,\n headers: request.headers,\n rawQueryString: request.raw.url?.split('?')[1] ?? '',\n }),\n );\n return sendJiraWebhookResponse(reply, result);\n },\n });\n\n return {\n prefix: JIRA_WEBHOOK_ROUTE_PREFIX,\n auth: [],\n plugins: [rawBodyPlugin],\n routes: [route],\n };\n}\n\nfunction createJiraStoredWebhookRequest(input: {\n body: Uint8Array;\n connectionId: string;\n headers: Record<string, string | string[] | undefined>;\n rawQueryString: string;\n}): StoredWebhookRequest {\n if (input.body.byteLength > WEBHOOK_MAX_RAW_BODY_BYTES) {\n throw new ClientError('Webhook request body is too large', 'body-too-large', {status: 413});\n }\n try {\n return createStoredWebhookRequest({\n requestId: randomUUID(),\n routeId: 'jira',\n receivedAt: new Date().toISOString(),\n rawQueryString: input.rawQueryString,\n headers: jiraWebhookHeaders(input.headers),\n body: input.body,\n connectionId: input.connectionId,\n });\n } catch (error) {\n throw new ClientError('Webhook request metadata is invalid', 'invalid-webhook-request', {\n cause: error,\n });\n }\n}\n\nfunction jiraWebhookHeaders(\n headers: Record<string, string | string[] | undefined>,\n): Record<string, string> {\n return Object.fromEntries(\n ['authorization', 'content-type', 'x-atlassian-webhook-identifier'].flatMap((name) => {\n const value = headers[name];\n return typeof value === 'string' ? [[name, value]] : [];\n }),\n );\n}\n\nfunction sendJiraWebhookResponse(\n reply: {code(statusCode: number): void},\n result: WebhookProcessingResult,\n) {\n if (result.outcome !== 'discarded') {\n reply.code(200);\n return null;\n }\n if (result.reason === 'invalid_signature' || result.reason === 'missing_required_input') {\n reply.code(401);\n return {error: 'invalid authorization'};\n }\n if (result.reason === 'malformed_payload') {\n reply.code(400);\n return {error: 'malformed JSON'};\n }\n reply.code(200);\n return null;\n}\n"],"names":["randomUUID","createStoredWebhookRequest","WEBHOOK_MAX_RAW_BODY_BYTES","ClientError","defineRoute","rawBodyPlugin","WEBHOOK_BODY_LIMIT","z","createJiraWebhookProcessor","jiraWebhookParamsSchema","object","connectionId","string","uuid","JIRA_WEBHOOK_ROUTE_PREFIX","createJiraWebhookRoutes","options","processor","route","method","path","auth","description","bodyLimit","schema","params","handler","request","reply","body","Uint8Array","status","result","process","createJiraStoredWebhookRequest","headers","rawQueryString","raw","url","split","sendJiraWebhookResponse","prefix","plugins","routes","input","byteLength","requestId","routeId","receivedAt","Date","toISOString","jiraWebhookHeaders","error","cause","Object","fromEntries","flatMap","name","value","outcome","code","reason"],"mappings":"AAAA,SAAQA,UAAU,QAAO,cAAc;AAEvC,SAAQC,0BAA0B,EAAEC,0BAA0B,QAAO,+BAA+B;AACpG,SACEC,WAAW,EACXC,WAAW,EAEXC,aAAa,EACbC,kBAAkB,QACb,wBAAwB;AAC/B,SAAQC,CAAC,QAAO,MAAM;AACtB,SAEEC,0BAA0B,QAErB,6BAA6B;AAEpC,MAAMC,0BAA0BF,EAAEG,MAAM,CAAC;IAACC,cAAcJ,EAAEK,MAAM,GAAGC,IAAI;AAAE;AACzE,OAAO,MAAMC,4BAA4B,8BAA8B;AAOvE,OAAO,SAASC,wBAAwBC,OAAuC;IAC7E,MAAMC,YAAYD,QAAQC,SAAS,IAAIT,2BAA2BQ;IAClE,MAAME,QAAQd,YAAY;QACxBe,QAAQ;QACRC,MAAM;QACNC,MAAM,EAAE;QACRC,aAAa;QACbN,SAAS;YAACO,WAAWjB;QAAkB;QACvCkB,QAAQ;YAACC,QAAQhB;QAAuB;QACxCiB,SAAS,OAAOC,SAASC;YACvB,MAAMC,OAAOF,QAAQE,IAAI;YACzB,IAAI,CAAEA,CAAAA,gBAAgBC,UAAS,GAAI;gBACjC,MAAM,IAAI3B,YAAY,0BAA0B,2BAA2B;oBAAC4B,QAAQ;gBAAG;YACzF;YACA,MAAMC,SAAS,MAAMf,UAAUgB,OAAO,CACpCC,+BAA+B;gBAC7BL;gBACAlB,cAAcgB,QAAQF,MAAM,CAACd,YAAY;gBACzCwB,SAASR,QAAQQ,OAAO;gBACxBC,gBAAgBT,QAAQU,GAAG,CAACC,GAAG,EAAEC,MAAM,IAAI,CAAC,EAAE,IAAI;YACpD;YAEF,OAAOC,wBAAwBZ,OAAOI;QACxC;IACF;IAEA,OAAO;QACLS,QAAQ3B;QACRO,MAAM,EAAE;QACRqB,SAAS;YAACrC;SAAc;QACxBsC,QAAQ;YAACzB;SAAM;IACjB;AACF;AAEA,SAASgB,+BAA+BU,KAKvC;IACC,IAAIA,MAAMf,IAAI,CAACgB,UAAU,GAAG3C,4BAA4B;QACtD,MAAM,IAAIC,YAAY,qCAAqC,kBAAkB;YAAC4B,QAAQ;QAAG;IAC3F;IACA,IAAI;QACF,OAAO9B,2BAA2B;YAChC6C,WAAW9C;YACX+C,SAAS;YACTC,YAAY,IAAIC,OAAOC,WAAW;YAClCd,gBAAgBQ,MAAMR,cAAc;YACpCD,SAASgB,mBAAmBP,MAAMT,OAAO;YACzCN,MAAMe,MAAMf,IAAI;YAChBlB,cAAciC,MAAMjC,YAAY;QAClC;IACF,EAAE,OAAOyC,OAAO;QACd,MAAM,IAAIjD,YAAY,uCAAuC,2BAA2B;YACtFkD,OAAOD;QACT;IACF;AACF;AAEA,SAASD,mBACPhB,OAAsD;IAEtD,OAAOmB,OAAOC,WAAW,CACvB;QAAC;QAAiB;QAAgB;KAAiC,CAACC,OAAO,CAAC,CAACC;QAC3E,MAAMC,QAAQvB,OAAO,CAACsB,KAAK;QAC3B,OAAO,OAAOC,UAAU,WAAW;YAAC;gBAACD;gBAAMC;aAAM;SAAC,GAAG,EAAE;IACzD;AAEJ;AAEA,SAASlB,wBACPZ,KAAuC,EACvCI,MAA+B;IAE/B,IAAIA,OAAO2B,OAAO,KAAK,aAAa;QAClC/B,MAAMgC,IAAI,CAAC;QACX,OAAO;IACT;IACA,IAAI5B,OAAO6B,MAAM,KAAK,uBAAuB7B,OAAO6B,MAAM,KAAK,0BAA0B;QACvFjC,MAAMgC,IAAI,CAAC;QACX,OAAO;YAACR,OAAO;QAAuB;IACxC;IACA,IAAIpB,OAAO6B,MAAM,KAAK,qBAAqB;QACzCjC,MAAMgC,IAAI,CAAC;QACX,OAAO;YAACR,OAAO;QAAgB;IACjC;IACAxB,MAAMgC,IAAI,CAAC;IACX,OAAO;AACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/temporal/activities/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,sCAAsC,EAC3C,+BAA+B,EAC/B,KAAK,8BAA8B,GACpC,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/temporal/activities/index.ts"],"sourcesContent":["export {\n type CreateJiraMaintenanceActivitiesOptions,\n createJiraMaintenanceActivities,\n type JiraTokenRefreshActivityResult,\n} from './refresh-jira-tokens.js';\n"],"names":["createJiraMaintenanceActivities"],"mappings":"AAAA,SAEEA,+BAA+B,QAE1B,2BAA2B"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IntegrationConnection } from '@shipfox/api-integration-spi';
|
|
2
|
+
import type { JiraTokenStore } from '#core/tokens.js';
|
|
3
|
+
import { listJiraInstallationsDueForTokenRefresh, markJiraInstallationTokenRefreshAttempt } from '#db/installations.js';
|
|
4
|
+
export interface JiraTokenRefreshActivityResult {
|
|
5
|
+
refreshed: number;
|
|
6
|
+
skipped: number;
|
|
7
|
+
failed: number;
|
|
8
|
+
}
|
|
9
|
+
export interface CreateJiraMaintenanceActivitiesOptions {
|
|
10
|
+
tokenStore: Pick<JiraTokenStore, 'getAccessToken'>;
|
|
11
|
+
resolveConnection(connectionId: string): Promise<Pick<IntegrationConnection, 'lifecycleStatus'> | undefined>;
|
|
12
|
+
listInstallations?: typeof listJiraInstallationsDueForTokenRefresh | undefined;
|
|
13
|
+
markAttempted?: typeof markJiraInstallationTokenRefreshAttempt | undefined;
|
|
14
|
+
now?: (() => Date) | undefined;
|
|
15
|
+
heartbeat?: (() => void) | undefined;
|
|
16
|
+
}
|
|
17
|
+
export declare function createJiraMaintenanceActivities(options: CreateJiraMaintenanceActivitiesOptions): {
|
|
18
|
+
refreshJiraTokensActivity(): Promise<JiraTokenRefreshActivityResult>;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=refresh-jira-tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh-jira-tokens.d.ts","sourceRoot":"","sources":["../../../src/temporal/activities/refresh-jira-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,8BAA8B,CAAC;AAExE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAEL,uCAAuC,EACvC,uCAAuC,EACxC,MAAM,sBAAsB,CAAC;AAQ9B,MAAM,WAAW,8BAA8B;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sCAAsC;IACrD,UAAU,EAAE,IAAI,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;IACnD,iBAAiB,CACf,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,GAAG,SAAS,CAAC,CAAC;IACvE,iBAAiB,CAAC,EAAE,OAAO,uCAAuC,GAAG,SAAS,CAAC;IAC/E,aAAa,CAAC,EAAE,OAAO,uCAAuC,GAAG,SAAS,CAAC;IAC3E,GAAG,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACtC;AAED,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,sCAAsC;iCAOxD,OAAO,CAAC,8BAA8B,CAAC;EAsC7E"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { logger } from '@shipfox/node-opentelemetry';
|
|
2
|
+
import { listJiraInstallationsDueForTokenRefresh, markJiraInstallationTokenRefreshAttempt } from '#db/installations.js';
|
|
3
|
+
import { JIRA_REFRESH_TOKEN_PROACTIVE_REFRESH_AFTER_MS, JIRA_REFRESH_TOKEN_SWEEP_BATCH_SIZE } from '#temporal/constants.js';
|
|
4
|
+
const JIRA_REFRESH_TOKEN_HEARTBEAT_INTERVAL_MS = 15_000;
|
|
5
|
+
export function createJiraMaintenanceActivities(options) {
|
|
6
|
+
const listInstallations = options.listInstallations ?? listJiraInstallationsDueForTokenRefresh;
|
|
7
|
+
const markAttempted = options.markAttempted ?? markJiraInstallationTokenRefreshAttempt;
|
|
8
|
+
const now = options.now ?? (()=>new Date());
|
|
9
|
+
const heartbeat = options.heartbeat ?? (()=>undefined);
|
|
10
|
+
return {
|
|
11
|
+
async refreshJiraTokensActivity () {
|
|
12
|
+
const before = new Date(now().getTime() - JIRA_REFRESH_TOKEN_PROACTIVE_REFRESH_AFTER_MS);
|
|
13
|
+
const installations = await listInstallations({
|
|
14
|
+
before,
|
|
15
|
+
limit: JIRA_REFRESH_TOKEN_SWEEP_BATCH_SIZE
|
|
16
|
+
});
|
|
17
|
+
let refreshed = 0;
|
|
18
|
+
let skipped = 0;
|
|
19
|
+
let failed = 0;
|
|
20
|
+
for (const installation of installations){
|
|
21
|
+
const heartbeatInterval = setInterval(heartbeat, JIRA_REFRESH_TOKEN_HEARTBEAT_INTERVAL_MS);
|
|
22
|
+
try {
|
|
23
|
+
heartbeat();
|
|
24
|
+
await markAttempted(installation.connectionId);
|
|
25
|
+
const connection = await options.resolveConnection(installation.connectionId);
|
|
26
|
+
if (connection?.lifecycleStatus !== 'active') {
|
|
27
|
+
skipped += 1;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
await options.tokenStore.getAccessToken({
|
|
31
|
+
connectionId: installation.connectionId,
|
|
32
|
+
forceRefresh: true
|
|
33
|
+
});
|
|
34
|
+
refreshed += 1;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
failed += 1;
|
|
37
|
+
logRefreshFailure(installation, error);
|
|
38
|
+
} finally{
|
|
39
|
+
clearInterval(heartbeatInterval);
|
|
40
|
+
heartbeat();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
refreshed,
|
|
45
|
+
skipped,
|
|
46
|
+
failed
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function logRefreshFailure(installation, error) {
|
|
52
|
+
logger().warn({
|
|
53
|
+
connectionId: installation.connectionId,
|
|
54
|
+
err: error
|
|
55
|
+
}, 'Jira proactive token refresh failed');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=refresh-jira-tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/temporal/activities/refresh-jira-tokens.ts"],"sourcesContent":["import type {IntegrationConnection} from '@shipfox/api-integration-spi';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport type {JiraTokenStore} from '#core/tokens.js';\nimport {\n type JiraInstallation,\n listJiraInstallationsDueForTokenRefresh,\n markJiraInstallationTokenRefreshAttempt,\n} from '#db/installations.js';\nimport {\n JIRA_REFRESH_TOKEN_PROACTIVE_REFRESH_AFTER_MS,\n JIRA_REFRESH_TOKEN_SWEEP_BATCH_SIZE,\n} from '#temporal/constants.js';\n\nconst JIRA_REFRESH_TOKEN_HEARTBEAT_INTERVAL_MS = 15_000;\n\nexport interface JiraTokenRefreshActivityResult {\n refreshed: number;\n skipped: number;\n failed: number;\n}\n\nexport interface CreateJiraMaintenanceActivitiesOptions {\n tokenStore: Pick<JiraTokenStore, 'getAccessToken'>;\n resolveConnection(\n connectionId: string,\n ): Promise<Pick<IntegrationConnection, 'lifecycleStatus'> | undefined>;\n listInstallations?: typeof listJiraInstallationsDueForTokenRefresh | undefined;\n markAttempted?: typeof markJiraInstallationTokenRefreshAttempt | undefined;\n now?: (() => Date) | undefined;\n heartbeat?: (() => void) | undefined;\n}\n\nexport function createJiraMaintenanceActivities(options: CreateJiraMaintenanceActivitiesOptions) {\n const listInstallations = options.listInstallations ?? listJiraInstallationsDueForTokenRefresh;\n const markAttempted = options.markAttempted ?? markJiraInstallationTokenRefreshAttempt;\n const now = options.now ?? (() => new Date());\n const heartbeat = options.heartbeat ?? (() => undefined);\n\n return {\n async refreshJiraTokensActivity(): Promise<JiraTokenRefreshActivityResult> {\n const before = new Date(now().getTime() - JIRA_REFRESH_TOKEN_PROACTIVE_REFRESH_AFTER_MS);\n const installations = await listInstallations({\n before,\n limit: JIRA_REFRESH_TOKEN_SWEEP_BATCH_SIZE,\n });\n let refreshed = 0;\n let skipped = 0;\n let failed = 0;\n\n for (const installation of installations) {\n const heartbeatInterval = setInterval(heartbeat, JIRA_REFRESH_TOKEN_HEARTBEAT_INTERVAL_MS);\n try {\n heartbeat();\n await markAttempted(installation.connectionId);\n const connection = await options.resolveConnection(installation.connectionId);\n if (connection?.lifecycleStatus !== 'active') {\n skipped += 1;\n continue;\n }\n\n await options.tokenStore.getAccessToken({\n connectionId: installation.connectionId,\n forceRefresh: true,\n });\n refreshed += 1;\n } catch (error) {\n failed += 1;\n logRefreshFailure(installation, error);\n } finally {\n clearInterval(heartbeatInterval);\n heartbeat();\n }\n }\n\n return {refreshed, skipped, failed};\n },\n };\n}\n\nfunction logRefreshFailure(installation: JiraInstallation, error: unknown): void {\n logger().warn(\n {\n connectionId: installation.connectionId,\n err: error,\n },\n 'Jira proactive token refresh failed',\n );\n}\n"],"names":["logger","listJiraInstallationsDueForTokenRefresh","markJiraInstallationTokenRefreshAttempt","JIRA_REFRESH_TOKEN_PROACTIVE_REFRESH_AFTER_MS","JIRA_REFRESH_TOKEN_SWEEP_BATCH_SIZE","JIRA_REFRESH_TOKEN_HEARTBEAT_INTERVAL_MS","createJiraMaintenanceActivities","options","listInstallations","markAttempted","now","Date","heartbeat","undefined","refreshJiraTokensActivity","before","getTime","installations","limit","refreshed","skipped","failed","installation","heartbeatInterval","setInterval","connectionId","connection","resolveConnection","lifecycleStatus","tokenStore","getAccessToken","forceRefresh","error","logRefreshFailure","clearInterval","warn","err"],"mappings":"AACA,SAAQA,MAAM,QAAO,8BAA8B;AAEnD,SAEEC,uCAAuC,EACvCC,uCAAuC,QAClC,uBAAuB;AAC9B,SACEC,6CAA6C,EAC7CC,mCAAmC,QAC9B,yBAAyB;AAEhC,MAAMC,2CAA2C;AAmBjD,OAAO,SAASC,gCAAgCC,OAA+C;IAC7F,MAAMC,oBAAoBD,QAAQC,iBAAiB,IAAIP;IACvD,MAAMQ,gBAAgBF,QAAQE,aAAa,IAAIP;IAC/C,MAAMQ,MAAMH,QAAQG,GAAG,IAAK,CAAA,IAAM,IAAIC,MAAK;IAC3C,MAAMC,YAAYL,QAAQK,SAAS,IAAK,CAAA,IAAMC,SAAQ;IAEtD,OAAO;QACL,MAAMC;YACJ,MAAMC,SAAS,IAAIJ,KAAKD,MAAMM,OAAO,KAAKb;YAC1C,MAAMc,gBAAgB,MAAMT,kBAAkB;gBAC5CO;gBACAG,OAAOd;YACT;YACA,IAAIe,YAAY;YAChB,IAAIC,UAAU;YACd,IAAIC,SAAS;YAEb,KAAK,MAAMC,gBAAgBL,cAAe;gBACxC,MAAMM,oBAAoBC,YAAYZ,WAAWP;gBACjD,IAAI;oBACFO;oBACA,MAAMH,cAAca,aAAaG,YAAY;oBAC7C,MAAMC,aAAa,MAAMnB,QAAQoB,iBAAiB,CAACL,aAAaG,YAAY;oBAC5E,IAAIC,YAAYE,oBAAoB,UAAU;wBAC5CR,WAAW;wBACX;oBACF;oBAEA,MAAMb,QAAQsB,UAAU,CAACC,cAAc,CAAC;wBACtCL,cAAcH,aAAaG,YAAY;wBACvCM,cAAc;oBAChB;oBACAZ,aAAa;gBACf,EAAE,OAAOa,OAAO;oBACdX,UAAU;oBACVY,kBAAkBX,cAAcU;gBAClC,SAAU;oBACRE,cAAcX;oBACdX;gBACF;YACF;YAEA,OAAO;gBAACO;gBAAWC;gBAASC;YAAM;QACpC;IACF;AACF;AAEA,SAASY,kBAAkBX,YAA8B,EAAEU,KAAc;IACvEhC,SAASmC,IAAI,CACX;QACEV,cAAcH,aAAaG,YAAY;QACvCW,KAAKJ;IACP,GACA;AAEJ"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const JIRA_REFRESH_TOKEN_IDLE_WINDOW_MS: number;
|
|
2
|
+
export declare const JIRA_REFRESH_TOKEN_REFRESH_LEAD_TIME_MS: number;
|
|
3
|
+
export declare const JIRA_REFRESH_TOKEN_PROACTIVE_REFRESH_AFTER_MS: number;
|
|
4
|
+
export declare const JIRA_REFRESH_TOKEN_SWEEP_BATCH_SIZE = 20;
|
|
5
|
+
export declare const JIRA_MAINTENANCE_TASK_QUEUE = "integrations-jira-maintenance";
|
|
6
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/temporal/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iCAAiC,QAAkB,CAAC;AACjE,eAAO,MAAM,uCAAuC,QAAkB,CAAC;AACvE,eAAO,MAAM,6CAA6C,QACmB,CAAC;AAC9E,eAAO,MAAM,mCAAmC,KAAK,CAAC;AACtD,eAAO,MAAM,2BAA2B,kCAAkC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
2
|
+
export const JIRA_REFRESH_TOKEN_IDLE_WINDOW_MS = 90 * MS_PER_DAY;
|
|
3
|
+
export const JIRA_REFRESH_TOKEN_REFRESH_LEAD_TIME_MS = 14 * MS_PER_DAY;
|
|
4
|
+
export const JIRA_REFRESH_TOKEN_PROACTIVE_REFRESH_AFTER_MS = JIRA_REFRESH_TOKEN_IDLE_WINDOW_MS - JIRA_REFRESH_TOKEN_REFRESH_LEAD_TIME_MS;
|
|
5
|
+
export const JIRA_REFRESH_TOKEN_SWEEP_BATCH_SIZE = 20;
|
|
6
|
+
export const JIRA_MAINTENANCE_TASK_QUEUE = 'integrations-jira-maintenance';
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/temporal/constants.ts"],"sourcesContent":["const MS_PER_DAY = 24 * 60 * 60 * 1000;\n\nexport const JIRA_REFRESH_TOKEN_IDLE_WINDOW_MS = 90 * MS_PER_DAY;\nexport const JIRA_REFRESH_TOKEN_REFRESH_LEAD_TIME_MS = 14 * MS_PER_DAY;\nexport const JIRA_REFRESH_TOKEN_PROACTIVE_REFRESH_AFTER_MS =\n JIRA_REFRESH_TOKEN_IDLE_WINDOW_MS - JIRA_REFRESH_TOKEN_REFRESH_LEAD_TIME_MS;\nexport const JIRA_REFRESH_TOKEN_SWEEP_BATCH_SIZE = 20;\nexport const JIRA_MAINTENANCE_TASK_QUEUE = 'integrations-jira-maintenance';\n"],"names":["MS_PER_DAY","JIRA_REFRESH_TOKEN_IDLE_WINDOW_MS","JIRA_REFRESH_TOKEN_REFRESH_LEAD_TIME_MS","JIRA_REFRESH_TOKEN_PROACTIVE_REFRESH_AFTER_MS","JIRA_REFRESH_TOKEN_SWEEP_BATCH_SIZE","JIRA_MAINTENANCE_TASK_QUEUE"],"mappings":"AAAA,MAAMA,aAAa,KAAK,KAAK,KAAK;AAElC,OAAO,MAAMC,oCAAoC,KAAKD,WAAW;AACjE,OAAO,MAAME,0CAA0C,KAAKF,WAAW;AACvE,OAAO,MAAMG,gDACXF,oCAAoCC,wCAAwC;AAC9E,OAAO,MAAME,sCAAsC,GAAG;AACtD,OAAO,MAAMC,8BAA8B,gCAAgC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { IntegrationConnection } from '@shipfox/api-integration-spi';
|
|
2
|
+
import type { ModuleWorker } from '@shipfox/node-module';
|
|
3
|
+
import type { JiraTokenStore } from '#core/tokens.js';
|
|
4
|
+
export interface CreateJiraMaintenanceWorkerOptions {
|
|
5
|
+
tokenStore: Pick<JiraTokenStore, 'getAccessToken'>;
|
|
6
|
+
resolveConnection(connectionId: string): Promise<Pick<IntegrationConnection, 'lifecycleStatus'> | undefined>;
|
|
7
|
+
}
|
|
8
|
+
export declare function createJiraMaintenanceWorker(options: CreateJiraMaintenanceWorkerOptions): ModuleWorker;
|
|
9
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/temporal/worker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAOpD,MAAM,WAAW,kCAAkC;IACjD,UAAU,EAAE,IAAI,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;IACnD,iBAAiB,CACf,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,GAAG,SAAS,CAAC,CAAC;CACxE;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,kCAAkC,GAC1C,YAAY,CAiBd"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { dirname, resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { Context } from '@temporalio/activity';
|
|
4
|
+
import { createJiraMaintenanceActivities } from '#temporal/activities/index.js';
|
|
5
|
+
import { JIRA_MAINTENANCE_TASK_QUEUE } from '#temporal/constants.js';
|
|
6
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
|
|
7
|
+
const workflowsPath = resolve(packageRoot, 'dist/temporal/workflows/index.js');
|
|
8
|
+
export function createJiraMaintenanceWorker(options) {
|
|
9
|
+
return {
|
|
10
|
+
taskQueue: JIRA_MAINTENANCE_TASK_QUEUE,
|
|
11
|
+
workflowsPath,
|
|
12
|
+
activities: ()=>createJiraMaintenanceActivities({
|
|
13
|
+
...options,
|
|
14
|
+
heartbeat: ()=>Context.current().heartbeat()
|
|
15
|
+
}),
|
|
16
|
+
workflows: [
|
|
17
|
+
{
|
|
18
|
+
name: 'refreshJiraTokensCron',
|
|
19
|
+
id: 'jira-refresh-tokens',
|
|
20
|
+
cronSchedule: '0 */6 * * *'
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/temporal/worker.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport type {IntegrationConnection} from '@shipfox/api-integration-spi';\nimport type {ModuleWorker} from '@shipfox/node-module';\nimport {Context} from '@temporalio/activity';\nimport type {JiraTokenStore} from '#core/tokens.js';\nimport {createJiraMaintenanceActivities} from '#temporal/activities/index.js';\nimport {JIRA_MAINTENANCE_TASK_QUEUE} from '#temporal/constants.js';\n\nconst packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..');\nconst workflowsPath = resolve(packageRoot, 'dist/temporal/workflows/index.js');\n\nexport interface CreateJiraMaintenanceWorkerOptions {\n tokenStore: Pick<JiraTokenStore, 'getAccessToken'>;\n resolveConnection(\n connectionId: string,\n ): Promise<Pick<IntegrationConnection, 'lifecycleStatus'> | undefined>;\n}\n\nexport function createJiraMaintenanceWorker(\n options: CreateJiraMaintenanceWorkerOptions,\n): ModuleWorker {\n return {\n taskQueue: JIRA_MAINTENANCE_TASK_QUEUE,\n workflowsPath,\n activities: () =>\n createJiraMaintenanceActivities({\n ...options,\n heartbeat: () => Context.current().heartbeat(),\n }),\n workflows: [\n {\n name: 'refreshJiraTokensCron',\n id: 'jira-refresh-tokens',\n cronSchedule: '0 */6 * * *',\n },\n ],\n };\n}\n"],"names":["dirname","resolve","fileURLToPath","Context","createJiraMaintenanceActivities","JIRA_MAINTENANCE_TASK_QUEUE","packageRoot","url","workflowsPath","createJiraMaintenanceWorker","options","taskQueue","activities","heartbeat","current","workflows","name","id","cronSchedule"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AAGvC,SAAQC,OAAO,QAAO,uBAAuB;AAE7C,SAAQC,+BAA+B,QAAO,gCAAgC;AAC9E,SAAQC,2BAA2B,QAAO,yBAAyB;AAEnE,MAAMC,cAAcL,QAAQD,QAAQE,cAAc,YAAYK,GAAG,IAAI;AACrE,MAAMC,gBAAgBP,QAAQK,aAAa;AAS3C,OAAO,SAASG,4BACdC,OAA2C;IAE3C,OAAO;QACLC,WAAWN;QACXG;QACAI,YAAY,IACVR,gCAAgC;gBAC9B,GAAGM,OAAO;gBACVG,WAAW,IAAMV,QAAQW,OAAO,GAAGD,SAAS;YAC9C;QACFE,WAAW;YACT;gBACEC,MAAM;gBACNC,IAAI;gBACJC,cAAc;YAChB;SACD;IACH;AACF"}
|