@shipfox/api-integration-core-dto 9.0.2 → 12.2.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 +1 -1
- package/CHANGELOG.md +29 -0
- package/dist/events.d.ts +54 -3
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +28 -1
- package/dist/events.js.map +1 -1
- package/dist/inter-module.d.ts +81 -29
- package/dist/inter-module.d.ts.map +1 -1
- package/dist/inter-module.js +28 -5
- package/dist/inter-module.js.map +1 -1
- package/dist/schemas/integrations.d.ts +19 -19
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/dist/webhooks.d.ts +33 -10
- package/dist/webhooks.d.ts.map +1 -1
- package/dist/webhooks.js +9 -3
- package/dist/webhooks.js.map +1 -1
- package/package.json +2 -2
- package/src/events.test.ts +61 -1
- package/src/events.ts +41 -0
- package/src/inter-module.test.ts +42 -0
- package/src/inter-module.ts +17 -1
- package/src/webhooks.test.ts +18 -0
- package/src/webhooks.ts +25 -4
- package/tsconfig.build.tsbuildinfo +1 -1
package/dist/webhooks.d.ts
CHANGED
|
@@ -4,14 +4,15 @@ export declare const WEBHOOK_MAX_RAW_BODY_BYTES: number;
|
|
|
4
4
|
export declare const WEBHOOK_MAX_SERIALIZED_REQUEST_BYTES: number;
|
|
5
5
|
export declare const WEBHOOK_MAX_HEADER_BYTES: number;
|
|
6
6
|
export declare const WEBHOOK_MAX_RAW_QUERY_STRING_LENGTH: number;
|
|
7
|
-
export declare const webhookRouteIds: readonly ["github", "gitea", "linear", "sentry", "slack.event", "slack.command", "webhook.connection"];
|
|
7
|
+
export declare const webhookRouteIds: readonly ["github", "gitea", "linear", "sentry", "slack.event", "slack.command", "webhook.connection", "jira"];
|
|
8
8
|
export declare const webhookRouteIdSchema: z.ZodEnum<{
|
|
9
|
-
github: "github";
|
|
10
9
|
gitea: "gitea";
|
|
10
|
+
github: "github";
|
|
11
|
+
jira: "jira";
|
|
11
12
|
linear: "linear";
|
|
12
13
|
sentry: "sentry";
|
|
13
|
-
"slack.event": "slack.event";
|
|
14
14
|
"slack.command": "slack.command";
|
|
15
|
+
"slack.event": "slack.event";
|
|
15
16
|
"webhook.connection": "webhook.connection";
|
|
16
17
|
}>;
|
|
17
18
|
export type WebhookRouteId = z.infer<typeof webhookRouteIdSchema>;
|
|
@@ -31,12 +32,12 @@ export declare const storedWebhookRequestSchema: z.ZodDiscriminatedUnion<[z.ZodO
|
|
|
31
32
|
data: z.ZodString;
|
|
32
33
|
}, z.core.$strict>;
|
|
33
34
|
route_id: z.ZodEnum<{
|
|
34
|
-
github: "github";
|
|
35
35
|
gitea: "gitea";
|
|
36
|
+
github: "github";
|
|
36
37
|
linear: "linear";
|
|
37
38
|
sentry: "sentry";
|
|
38
|
-
"slack.event": "slack.event";
|
|
39
39
|
"slack.command": "slack.command";
|
|
40
|
+
"slack.event": "slack.event";
|
|
40
41
|
}>;
|
|
41
42
|
path_parameters: z.ZodObject<{}, z.core.$strict>;
|
|
42
43
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -54,6 +55,21 @@ export declare const storedWebhookRequestSchema: z.ZodDiscriminatedUnion<[z.ZodO
|
|
|
54
55
|
path_parameters: z.ZodObject<{
|
|
55
56
|
connection_id: z.ZodString;
|
|
56
57
|
}, z.core.$strict>;
|
|
58
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
59
|
+
schema_version: z.ZodLiteral<1>;
|
|
60
|
+
request_id: z.ZodString;
|
|
61
|
+
received_at: z.ZodString;
|
|
62
|
+
method: z.ZodLiteral<"POST">;
|
|
63
|
+
raw_query_string: z.ZodString;
|
|
64
|
+
headers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
65
|
+
body: z.ZodObject<{
|
|
66
|
+
encoding: z.ZodLiteral<"base64">;
|
|
67
|
+
data: z.ZodString;
|
|
68
|
+
}, z.core.$strict>;
|
|
69
|
+
route_id: z.ZodLiteral<"jira">;
|
|
70
|
+
path_parameters: z.ZodObject<{
|
|
71
|
+
connection_id: z.ZodString;
|
|
72
|
+
}, z.core.$strict>;
|
|
57
73
|
}, z.core.$strict>], "route_id">;
|
|
58
74
|
export type StoredWebhookRequest = z.infer<typeof storedWebhookRequestSchema>;
|
|
59
75
|
export declare const webhookProcessingResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -66,25 +82,32 @@ export declare const webhookProcessingResultSchema: z.ZodDiscriminatedUnion<[z.Z
|
|
|
66
82
|
}, z.core.$strict>, z.ZodObject<{
|
|
67
83
|
outcome: z.ZodLiteral<"discarded">;
|
|
68
84
|
reason: z.ZodEnum<{
|
|
69
|
-
|
|
85
|
+
connection_unavailable: "connection_unavailable";
|
|
70
86
|
invalid_signature: "invalid_signature";
|
|
71
|
-
stale_at_receipt: "stale_at_receipt";
|
|
72
87
|
malformed_payload: "malformed_payload";
|
|
88
|
+
missing_required_input: "missing_required_input";
|
|
89
|
+
stale_at_receipt: "stale_at_receipt";
|
|
73
90
|
unsupported_event: "unsupported_event";
|
|
74
|
-
connection_unavailable: "connection_unavailable";
|
|
75
91
|
}>;
|
|
76
92
|
deliveryId: z.ZodOptional<z.ZodString>;
|
|
77
93
|
}, z.core.$strict>], "outcome">;
|
|
78
94
|
export type WebhookProcessingResult = z.infer<typeof webhookProcessingResultSchema>;
|
|
79
|
-
|
|
95
|
+
interface CreateStoredWebhookRequestInputBase {
|
|
80
96
|
requestId: string;
|
|
81
97
|
routeId: WebhookRouteId;
|
|
82
98
|
receivedAt: string;
|
|
83
99
|
rawQueryString: string;
|
|
84
100
|
headers: Record<string, string>;
|
|
85
101
|
body: Uint8Array;
|
|
86
|
-
connectionId?: string | undefined;
|
|
87
102
|
}
|
|
103
|
+
type ConnectionScopedWebhookRouteId = 'webhook.connection' | 'jira';
|
|
104
|
+
export type CreateStoredWebhookRequestInput = (CreateStoredWebhookRequestInputBase & {
|
|
105
|
+
routeId: ConnectionScopedWebhookRouteId;
|
|
106
|
+
connectionId: string;
|
|
107
|
+
}) | (CreateStoredWebhookRequestInputBase & {
|
|
108
|
+
routeId: Exclude<WebhookRouteId, ConnectionScopedWebhookRouteId>;
|
|
109
|
+
connectionId?: never;
|
|
110
|
+
});
|
|
88
111
|
export declare function encodeWebhookBody(body: Uint8Array): string;
|
|
89
112
|
export declare function decodeWebhookBody(body: z.infer<typeof webhookBodySchema>): Uint8Array;
|
|
90
113
|
export declare function createStoredWebhookRequest(input: CreateStoredWebhookRequestInput): StoredWebhookRequest;
|
package/dist/webhooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../src/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,eAAO,MAAM,8BAA8B,EAAG,CAAU,CAAC;AACzD,eAAO,MAAM,0BAA0B,QAAa,CAAC;AACrD,eAAO,MAAM,oCAAoC,QAAc,CAAC;AAChE,eAAO,MAAM,wBAAwB,QAAY,CAAC;AAClD,eAAO,MAAM,mCAAmC,QAAW,CAAC;AAW5D,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../src/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,eAAO,MAAM,8BAA8B,EAAG,CAAU,CAAC;AACzD,eAAO,MAAM,0BAA0B,QAAa,CAAC;AACrD,eAAO,MAAM,oCAAoC,QAAc,CAAC;AAChE,eAAO,MAAM,wBAAwB,QAAY,CAAC;AAClD,eAAO,MAAM,mCAAmC,QAAW,CAAC;AAW5D,eAAO,MAAM,eAAe,gHAAsE,CAAC;AAEnG,eAAO,MAAM,oBAAoB;;;;;;;;;EAA0B,CAAC;AAC5D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AA4BlE,QAAA,MAAM,iBAAiB;;;kBAYpB,CAAC;AAoCJ,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAIrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;+BAuBxC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF,UAAU,mCAAmC;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,KAAK,8BAA8B,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAEpE,MAAM,MAAM,+BAA+B,GACvC,CAAC,mCAAmC,GAAG;IACrC,OAAO,EAAE,8BAA8B,CAAC;IACxC,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC,GACF,CAAC,mCAAmC,GAAG;IACrC,OAAO,EAAE,OAAO,CAAC,cAAc,EAAE,8BAA8B,CAAC,CAAC;IACjE,YAAY,CAAC,EAAE,KAAK,CAAC;CACtB,CAAC,CAAC;AAEP,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CA0B1D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,GAAG,UAAU,CAyBrF;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,+BAA+B,GACrC,oBAAoB,CAiBtB"}
|
package/dist/webhooks.js
CHANGED
|
@@ -14,7 +14,8 @@ const standardWebhookRouteIds = [
|
|
|
14
14
|
];
|
|
15
15
|
export const webhookRouteIds = [
|
|
16
16
|
...standardWebhookRouteIds,
|
|
17
|
-
'webhook.connection'
|
|
17
|
+
'webhook.connection',
|
|
18
|
+
'jira'
|
|
18
19
|
];
|
|
19
20
|
export const webhookRouteIdSchema = z.enum(webhookRouteIds);
|
|
20
21
|
const base64Pattern = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
@@ -53,9 +54,14 @@ const genericWebhookRouteRequestSchema = storedWebhookRequestBaseSchema.extend({
|
|
|
53
54
|
route_id: z.literal('webhook.connection'),
|
|
54
55
|
path_parameters: connectionPathParametersSchema
|
|
55
56
|
}).strict();
|
|
57
|
+
const jiraWebhookRouteRequestSchema = storedWebhookRequestBaseSchema.extend({
|
|
58
|
+
route_id: z.literal('jira'),
|
|
59
|
+
path_parameters: connectionPathParametersSchema
|
|
60
|
+
}).strict();
|
|
56
61
|
export const storedWebhookRequestSchema = z.discriminatedUnion('route_id', [
|
|
57
62
|
standardWebhookRouteRequestSchema,
|
|
58
|
-
genericWebhookRouteRequestSchema
|
|
63
|
+
genericWebhookRouteRequestSchema,
|
|
64
|
+
jiraWebhookRouteRequestSchema
|
|
59
65
|
]);
|
|
60
66
|
export const webhookProcessingResultSchema = z.discriminatedUnion('outcome', [
|
|
61
67
|
z.object({
|
|
@@ -112,7 +118,7 @@ export function decodeWebhookBody(body) {
|
|
|
112
118
|
return output;
|
|
113
119
|
}
|
|
114
120
|
export function createStoredWebhookRequest(input) {
|
|
115
|
-
const pathParameters = input.routeId === 'webhook.connection' ? {
|
|
121
|
+
const pathParameters = input.routeId === 'webhook.connection' || input.routeId === 'jira' ? {
|
|
116
122
|
connection_id: input.connectionId
|
|
117
123
|
} : {};
|
|
118
124
|
return storedWebhookRequestSchema.parse({
|
package/dist/webhooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/webhooks.ts"],"sourcesContent":["import {z} from 'zod';\n\nexport const WEBHOOK_REQUEST_SCHEMA_VERSION = 1 as const;\nexport const WEBHOOK_MAX_RAW_BODY_BYTES = 512 * 1024;\nexport const WEBHOOK_MAX_SERIALIZED_REQUEST_BYTES = 1024 * 1024;\nexport const WEBHOOK_MAX_HEADER_BYTES = 64 * 1024;\nexport const WEBHOOK_MAX_RAW_QUERY_STRING_LENGTH = 8 * 1024;\n\nconst standardWebhookRouteIds = [\n 'github',\n 'gitea',\n 'linear',\n 'sentry',\n 'slack.event',\n 'slack.command',\n] as const;\n\nexport const webhookRouteIds = [...standardWebhookRouteIds, 'webhook.connection'] as const;\n\nexport const webhookRouteIdSchema = z.enum(webhookRouteIds);\nexport type WebhookRouteId = z.infer<typeof webhookRouteIdSchema>;\n\nconst base64Pattern = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;\n\nfunction decodedBase64Length(value: string): number {\n const paddingLength = value.endsWith('==') ? 2 : value.endsWith('=') ? 1 : 0;\n\n return (value.length / 4) * 3 - paddingLength;\n}\n\nfunction headersByteLength(headers: Record<string, string>): number {\n return new TextEncoder().encode(JSON.stringify(headers)).byteLength;\n}\n\nconst webhookHeadersSchema = z\n .record(z.string(), z.string().max(8 * 1024))\n .refine(\n (headers) =>\n Object.keys(headers).every(\n (name) => name === name.toLowerCase() && name.length > 0 && name.length <= 128,\n ),\n 'Webhook header names must be lowercase and at most 128 characters',\n )\n .refine(\n (headers) => headersByteLength(headers) <= WEBHOOK_MAX_HEADER_BYTES,\n `Webhook headers must serialize to at most ${WEBHOOK_MAX_HEADER_BYTES} bytes`,\n );\n\nconst webhookBodySchema = z\n .object({\n encoding: z.literal('base64'),\n data: z\n .string()\n .max(Math.ceil(WEBHOOK_MAX_RAW_BODY_BYTES / 3) * 4)\n .regex(base64Pattern),\n })\n .strict()\n .refine(\n (body) => decodedBase64Length(body.data) <= WEBHOOK_MAX_RAW_BODY_BYTES,\n `Webhook bodies must decode to at most ${WEBHOOK_MAX_RAW_BODY_BYTES} bytes`,\n );\n\nconst storedWebhookRequestBaseSchema = z.object({\n schema_version: z.literal(WEBHOOK_REQUEST_SCHEMA_VERSION),\n request_id: z.string().uuid(),\n received_at: z.string().datetime({offset: true}),\n method: z.literal('POST'),\n raw_query_string: z.string().max(WEBHOOK_MAX_RAW_QUERY_STRING_LENGTH),\n headers: webhookHeadersSchema,\n body: webhookBodySchema,\n});\n\nconst emptyPathParametersSchema = z.object({}).strict();\nconst connectionPathParametersSchema = z.object({connection_id: z.string().uuid()}).strict();\n\nconst standardWebhookRouteRequestSchema = storedWebhookRequestBaseSchema\n .extend({\n route_id: z.enum(standardWebhookRouteIds),\n path_parameters: emptyPathParametersSchema,\n })\n .strict();\n\nconst genericWebhookRouteRequestSchema = storedWebhookRequestBaseSchema\n .extend({\n route_id: z.literal('webhook.connection'),\n path_parameters: connectionPathParametersSchema,\n })\n .strict();\n\nexport const storedWebhookRequestSchema = z.discriminatedUnion('route_id', [\n standardWebhookRouteRequestSchema,\n genericWebhookRouteRequestSchema,\n]);\nexport type StoredWebhookRequest = z.infer<typeof storedWebhookRequestSchema>;\n\nexport const webhookProcessingResultSchema = z.discriminatedUnion('outcome', [\n z\n .object({\n outcome: z.literal('processed'),\n deliveryId: z.string().min(1).optional(),\n challenge: z.string().min(1).optional(),\n })\n .strict(),\n z.object({outcome: z.literal('duplicate'), deliveryId: z.string().min(1)}).strict(),\n z\n .object({\n outcome: z.literal('discarded'),\n reason: z.enum([\n 'missing_required_input',\n 'invalid_signature',\n 'stale_at_receipt',\n 'malformed_payload',\n 'unsupported_event',\n 'connection_unavailable',\n ]),\n deliveryId: z.string().min(1).optional(),\n })\n .strict(),\n]);\nexport type WebhookProcessingResult = z.infer<typeof webhookProcessingResultSchema>;\n\nexport interface CreateStoredWebhookRequestInput {\n requestId: string;\n routeId: WebhookRouteId;\n receivedAt: string;\n rawQueryString: string;\n headers: Record<string, string>;\n body: Uint8Array;\n connectionId?: string | undefined;\n}\n\nexport function encodeWebhookBody(body: Uint8Array): string {\n let encoded = '';\n\n for (let index = 0; index < body.length; index += 3) {\n const first = body[index] ?? 0;\n const second = body[index + 1];\n const third = body[index + 2];\n const combined = (first << 16) | ((second ?? 0) << 8) | (third ?? 0);\n\n encoded += 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'[\n (combined >> 18) & 63\n ];\n encoded += 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'[\n (combined >> 12) & 63\n ];\n encoded +=\n second === undefined\n ? '='\n : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'[(combined >> 6) & 63];\n encoded +=\n third === undefined\n ? '='\n : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'[combined & 63];\n }\n\n return encoded;\n}\n\nexport function decodeWebhookBody(body: z.infer<typeof webhookBodySchema>): Uint8Array {\n const output = new Uint8Array(decodedBase64Length(body.data));\n let outputIndex = 0;\n\n for (let index = 0; index < body.data.length; index += 4) {\n const chunk = body.data.slice(index, index + 4);\n const values = chunk\n .split('')\n .map((character) =>\n character === '='\n ? 0\n : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.indexOf(character),\n );\n const first = values[0] ?? 0;\n const second = values[1] ?? 0;\n const third = values[2] ?? 0;\n const fourth = values[3] ?? 0;\n const combined = (first << 18) | (second << 12) | (third << 6) | fourth;\n\n output[outputIndex++] = (combined >> 16) & 255;\n if (chunk[2] !== '=') output[outputIndex++] = (combined >> 8) & 255;\n if (chunk[3] !== '=') output[outputIndex++] = combined & 255;\n }\n\n return output;\n}\n\nexport function createStoredWebhookRequest(\n input: CreateStoredWebhookRequestInput,\n): StoredWebhookRequest {\n const pathParameters =\n input.routeId === 'webhook.connection' ? {connection_id: input.connectionId} : {};\n\n return storedWebhookRequestSchema.parse({\n schema_version: WEBHOOK_REQUEST_SCHEMA_VERSION,\n request_id: input.requestId,\n route_id: input.routeId,\n received_at: input.receivedAt,\n method: 'POST',\n path_parameters: pathParameters,\n raw_query_string: input.rawQueryString,\n headers: input.headers,\n body: {encoding: 'base64', data: encodeWebhookBody(input.body)},\n });\n}\n"],"names":["z","WEBHOOK_REQUEST_SCHEMA_VERSION","WEBHOOK_MAX_RAW_BODY_BYTES","WEBHOOK_MAX_SERIALIZED_REQUEST_BYTES","WEBHOOK_MAX_HEADER_BYTES","WEBHOOK_MAX_RAW_QUERY_STRING_LENGTH","standardWebhookRouteIds","webhookRouteIds","webhookRouteIdSchema","enum","base64Pattern","decodedBase64Length","value","paddingLength","endsWith","length","headersByteLength","headers","TextEncoder","encode","JSON","stringify","byteLength","webhookHeadersSchema","record","string","max","refine","Object","keys","every","name","toLowerCase","webhookBodySchema","object","encoding","literal","data","Math","ceil","regex","strict","body","storedWebhookRequestBaseSchema","schema_version","request_id","uuid","received_at","datetime","offset","method","raw_query_string","emptyPathParametersSchema","connectionPathParametersSchema","connection_id","standardWebhookRouteRequestSchema","extend","route_id","path_parameters","genericWebhookRouteRequestSchema","storedWebhookRequestSchema","discriminatedUnion","webhookProcessingResultSchema","outcome","deliveryId","min","optional","challenge","reason","encodeWebhookBody","encoded","index","first","second","third","combined","undefined","decodeWebhookBody","output","Uint8Array","outputIndex","chunk","slice","values","split","map","character","indexOf","fourth","createStoredWebhookRequest","input","pathParameters","routeId","connectionId","parse","requestId","receivedAt","rawQueryString"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/webhooks.ts"],"sourcesContent":["import {z} from 'zod';\n\nexport const WEBHOOK_REQUEST_SCHEMA_VERSION = 1 as const;\nexport const WEBHOOK_MAX_RAW_BODY_BYTES = 512 * 1024;\nexport const WEBHOOK_MAX_SERIALIZED_REQUEST_BYTES = 1024 * 1024;\nexport const WEBHOOK_MAX_HEADER_BYTES = 64 * 1024;\nexport const WEBHOOK_MAX_RAW_QUERY_STRING_LENGTH = 8 * 1024;\n\nconst standardWebhookRouteIds = [\n 'github',\n 'gitea',\n 'linear',\n 'sentry',\n 'slack.event',\n 'slack.command',\n] as const;\n\nexport const webhookRouteIds = [...standardWebhookRouteIds, 'webhook.connection', 'jira'] as const;\n\nexport const webhookRouteIdSchema = z.enum(webhookRouteIds);\nexport type WebhookRouteId = z.infer<typeof webhookRouteIdSchema>;\n\nconst base64Pattern = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;\n\nfunction decodedBase64Length(value: string): number {\n const paddingLength = value.endsWith('==') ? 2 : value.endsWith('=') ? 1 : 0;\n\n return (value.length / 4) * 3 - paddingLength;\n}\n\nfunction headersByteLength(headers: Record<string, string>): number {\n return new TextEncoder().encode(JSON.stringify(headers)).byteLength;\n}\n\nconst webhookHeadersSchema = z\n .record(z.string(), z.string().max(8 * 1024))\n .refine(\n (headers) =>\n Object.keys(headers).every(\n (name) => name === name.toLowerCase() && name.length > 0 && name.length <= 128,\n ),\n 'Webhook header names must be lowercase and at most 128 characters',\n )\n .refine(\n (headers) => headersByteLength(headers) <= WEBHOOK_MAX_HEADER_BYTES,\n `Webhook headers must serialize to at most ${WEBHOOK_MAX_HEADER_BYTES} bytes`,\n );\n\nconst webhookBodySchema = z\n .object({\n encoding: z.literal('base64'),\n data: z\n .string()\n .max(Math.ceil(WEBHOOK_MAX_RAW_BODY_BYTES / 3) * 4)\n .regex(base64Pattern),\n })\n .strict()\n .refine(\n (body) => decodedBase64Length(body.data) <= WEBHOOK_MAX_RAW_BODY_BYTES,\n `Webhook bodies must decode to at most ${WEBHOOK_MAX_RAW_BODY_BYTES} bytes`,\n );\n\nconst storedWebhookRequestBaseSchema = z.object({\n schema_version: z.literal(WEBHOOK_REQUEST_SCHEMA_VERSION),\n request_id: z.string().uuid(),\n received_at: z.string().datetime({offset: true}),\n method: z.literal('POST'),\n raw_query_string: z.string().max(WEBHOOK_MAX_RAW_QUERY_STRING_LENGTH),\n headers: webhookHeadersSchema,\n body: webhookBodySchema,\n});\n\nconst emptyPathParametersSchema = z.object({}).strict();\nconst connectionPathParametersSchema = z.object({connection_id: z.string().uuid()}).strict();\n\nconst standardWebhookRouteRequestSchema = storedWebhookRequestBaseSchema\n .extend({\n route_id: z.enum(standardWebhookRouteIds),\n path_parameters: emptyPathParametersSchema,\n })\n .strict();\n\nconst genericWebhookRouteRequestSchema = storedWebhookRequestBaseSchema\n .extend({\n route_id: z.literal('webhook.connection'),\n path_parameters: connectionPathParametersSchema,\n })\n .strict();\n\nconst jiraWebhookRouteRequestSchema = storedWebhookRequestBaseSchema\n .extend({\n route_id: z.literal('jira'),\n path_parameters: connectionPathParametersSchema,\n })\n .strict();\n\nexport const storedWebhookRequestSchema = z.discriminatedUnion('route_id', [\n standardWebhookRouteRequestSchema,\n genericWebhookRouteRequestSchema,\n jiraWebhookRouteRequestSchema,\n]);\nexport type StoredWebhookRequest = z.infer<typeof storedWebhookRequestSchema>;\n\nexport const webhookProcessingResultSchema = z.discriminatedUnion('outcome', [\n z\n .object({\n outcome: z.literal('processed'),\n deliveryId: z.string().min(1).optional(),\n challenge: z.string().min(1).optional(),\n })\n .strict(),\n z.object({outcome: z.literal('duplicate'), deliveryId: z.string().min(1)}).strict(),\n z\n .object({\n outcome: z.literal('discarded'),\n reason: z.enum([\n 'missing_required_input',\n 'invalid_signature',\n 'stale_at_receipt',\n 'malformed_payload',\n 'unsupported_event',\n 'connection_unavailable',\n ]),\n deliveryId: z.string().min(1).optional(),\n })\n .strict(),\n]);\nexport type WebhookProcessingResult = z.infer<typeof webhookProcessingResultSchema>;\n\ninterface CreateStoredWebhookRequestInputBase {\n requestId: string;\n routeId: WebhookRouteId;\n receivedAt: string;\n rawQueryString: string;\n headers: Record<string, string>;\n body: Uint8Array;\n}\n\ntype ConnectionScopedWebhookRouteId = 'webhook.connection' | 'jira';\n\nexport type CreateStoredWebhookRequestInput =\n | (CreateStoredWebhookRequestInputBase & {\n routeId: ConnectionScopedWebhookRouteId;\n connectionId: string;\n })\n | (CreateStoredWebhookRequestInputBase & {\n routeId: Exclude<WebhookRouteId, ConnectionScopedWebhookRouteId>;\n connectionId?: never;\n });\n\nexport function encodeWebhookBody(body: Uint8Array): string {\n let encoded = '';\n\n for (let index = 0; index < body.length; index += 3) {\n const first = body[index] ?? 0;\n const second = body[index + 1];\n const third = body[index + 2];\n const combined = (first << 16) | ((second ?? 0) << 8) | (third ?? 0);\n\n encoded += 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'[\n (combined >> 18) & 63\n ];\n encoded += 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'[\n (combined >> 12) & 63\n ];\n encoded +=\n second === undefined\n ? '='\n : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'[(combined >> 6) & 63];\n encoded +=\n third === undefined\n ? '='\n : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'[combined & 63];\n }\n\n return encoded;\n}\n\nexport function decodeWebhookBody(body: z.infer<typeof webhookBodySchema>): Uint8Array {\n const output = new Uint8Array(decodedBase64Length(body.data));\n let outputIndex = 0;\n\n for (let index = 0; index < body.data.length; index += 4) {\n const chunk = body.data.slice(index, index + 4);\n const values = chunk\n .split('')\n .map((character) =>\n character === '='\n ? 0\n : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.indexOf(character),\n );\n const first = values[0] ?? 0;\n const second = values[1] ?? 0;\n const third = values[2] ?? 0;\n const fourth = values[3] ?? 0;\n const combined = (first << 18) | (second << 12) | (third << 6) | fourth;\n\n output[outputIndex++] = (combined >> 16) & 255;\n if (chunk[2] !== '=') output[outputIndex++] = (combined >> 8) & 255;\n if (chunk[3] !== '=') output[outputIndex++] = combined & 255;\n }\n\n return output;\n}\n\nexport function createStoredWebhookRequest(\n input: CreateStoredWebhookRequestInput,\n): StoredWebhookRequest {\n const pathParameters =\n input.routeId === 'webhook.connection' || input.routeId === 'jira'\n ? {connection_id: input.connectionId}\n : {};\n\n return storedWebhookRequestSchema.parse({\n schema_version: WEBHOOK_REQUEST_SCHEMA_VERSION,\n request_id: input.requestId,\n route_id: input.routeId,\n received_at: input.receivedAt,\n method: 'POST',\n path_parameters: pathParameters,\n raw_query_string: input.rawQueryString,\n headers: input.headers,\n body: {encoding: 'base64', data: encodeWebhookBody(input.body)},\n });\n}\n"],"names":["z","WEBHOOK_REQUEST_SCHEMA_VERSION","WEBHOOK_MAX_RAW_BODY_BYTES","WEBHOOK_MAX_SERIALIZED_REQUEST_BYTES","WEBHOOK_MAX_HEADER_BYTES","WEBHOOK_MAX_RAW_QUERY_STRING_LENGTH","standardWebhookRouteIds","webhookRouteIds","webhookRouteIdSchema","enum","base64Pattern","decodedBase64Length","value","paddingLength","endsWith","length","headersByteLength","headers","TextEncoder","encode","JSON","stringify","byteLength","webhookHeadersSchema","record","string","max","refine","Object","keys","every","name","toLowerCase","webhookBodySchema","object","encoding","literal","data","Math","ceil","regex","strict","body","storedWebhookRequestBaseSchema","schema_version","request_id","uuid","received_at","datetime","offset","method","raw_query_string","emptyPathParametersSchema","connectionPathParametersSchema","connection_id","standardWebhookRouteRequestSchema","extend","route_id","path_parameters","genericWebhookRouteRequestSchema","jiraWebhookRouteRequestSchema","storedWebhookRequestSchema","discriminatedUnion","webhookProcessingResultSchema","outcome","deliveryId","min","optional","challenge","reason","encodeWebhookBody","encoded","index","first","second","third","combined","undefined","decodeWebhookBody","output","Uint8Array","outputIndex","chunk","slice","values","split","map","character","indexOf","fourth","createStoredWebhookRequest","input","pathParameters","routeId","connectionId","parse","requestId","receivedAt","rawQueryString"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipfox/api-integration-core-dto",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "12.2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/ShipfoxHQ/shipfox.git",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"zod": "^4.4.3",
|
|
26
|
-
"@shipfox/inter-module": "0.2.
|
|
26
|
+
"@shipfox/inter-module": "0.2.3"
|
|
27
27
|
},
|
|
28
28
|
"imports": {
|
|
29
29
|
"#*": "./dist/*"
|
package/src/events.test.ts
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
+
INTEGRATION_CONNECTION_AVAILABLE,
|
|
2
3
|
INTEGRATION_EVENT_RECEIVED,
|
|
3
4
|
INTEGRATION_SOURCE_COMMIT_PUSHED,
|
|
5
|
+
INTEGRATION_SOURCE_REPOSITORY_UPDATED,
|
|
6
|
+
integrationConnectionAvailableSchema,
|
|
4
7
|
integrationEventReceivedSchema,
|
|
5
8
|
integrationSourceCommitPushedSchema,
|
|
9
|
+
integrationSourceRepositoryUpdatedSchema,
|
|
6
10
|
integrationsEventSchemas,
|
|
7
11
|
} from './events.js';
|
|
8
12
|
|
|
13
|
+
const validConnectionAvailable = {
|
|
14
|
+
provider: 'linear',
|
|
15
|
+
workspaceId: 'ws-1',
|
|
16
|
+
connectionId: 'conn-1',
|
|
17
|
+
slug: 'linear_shipfox',
|
|
18
|
+
};
|
|
19
|
+
|
|
9
20
|
const validEventReceived = {
|
|
10
21
|
provider: 'github',
|
|
11
22
|
source: 'github',
|
|
@@ -33,6 +44,34 @@ const validCommitPushed = {
|
|
|
33
44
|
},
|
|
34
45
|
};
|
|
35
46
|
|
|
47
|
+
const validRepositoryUpdated = {
|
|
48
|
+
provider: 'github',
|
|
49
|
+
workspaceId: 'ws-1',
|
|
50
|
+
connectionId: 'conn-1',
|
|
51
|
+
deliveryId: 'delivery-1',
|
|
52
|
+
receivedAt: '2026-06-21T00:00:00.000Z',
|
|
53
|
+
repository: {
|
|
54
|
+
externalRepositoryId: 'github:42',
|
|
55
|
+
owner: 'acme',
|
|
56
|
+
name: 'platform-renamed',
|
|
57
|
+
defaultBranch: 'main',
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
describe('integrationConnectionAvailableSchema', () => {
|
|
62
|
+
it('parses a valid connection-available payload unchanged', () => {
|
|
63
|
+
expect(integrationConnectionAvailableSchema.parse(validConnectionAvailable)).toEqual(
|
|
64
|
+
validConnectionAvailable,
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('rejects a payload without a connection slug', () => {
|
|
69
|
+
const {slug: _slug, ...withoutSlug} = validConnectionAvailable;
|
|
70
|
+
|
|
71
|
+
expect(() => integrationConnectionAvailableSchema.parse(withoutSlug)).toThrow();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
36
75
|
describe('integrationSourceCommitPushedSchema', () => {
|
|
37
76
|
it('parses a valid commit-pushed payload unchanged', () => {
|
|
38
77
|
const result = integrationSourceCommitPushedSchema.parse(validCommitPushed);
|
|
@@ -98,12 +137,33 @@ describe('integrationEventReceivedSchema', () => {
|
|
|
98
137
|
});
|
|
99
138
|
});
|
|
100
139
|
|
|
140
|
+
describe('integrationSourceRepositoryUpdatedSchema', () => {
|
|
141
|
+
it('parses a valid repository identity update unchanged', () => {
|
|
142
|
+
const result = integrationSourceRepositoryUpdatedSchema.parse(validRepositoryUpdated);
|
|
143
|
+
|
|
144
|
+
expect(result).toEqual(validRepositoryUpdated);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('rejects a payload missing repository identity', () => {
|
|
148
|
+
const {repository: _repository, ...withoutRepository} = validRepositoryUpdated;
|
|
149
|
+
|
|
150
|
+
const parse = () => integrationSourceRepositoryUpdatedSchema.parse(withoutRepository);
|
|
151
|
+
|
|
152
|
+
expect(parse).toThrow();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
101
156
|
describe('integrationsEventSchemas', () => {
|
|
102
157
|
it('registers every integration publisher event type', () => {
|
|
103
158
|
const registeredTypes = Object.keys(integrationsEventSchemas).sort();
|
|
104
159
|
|
|
105
160
|
expect(registeredTypes).toEqual(
|
|
106
|
-
[
|
|
161
|
+
[
|
|
162
|
+
INTEGRATION_CONNECTION_AVAILABLE,
|
|
163
|
+
INTEGRATION_EVENT_RECEIVED,
|
|
164
|
+
INTEGRATION_SOURCE_COMMIT_PUSHED,
|
|
165
|
+
INTEGRATION_SOURCE_REPOSITORY_UPDATED,
|
|
166
|
+
].sort(),
|
|
107
167
|
);
|
|
108
168
|
});
|
|
109
169
|
});
|
package/src/events.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {z} from 'zod';
|
|
2
2
|
|
|
3
3
|
export const INTEGRATION_EVENT_RECEIVED = 'integrations.event.received' as const;
|
|
4
|
+
export const INTEGRATION_CONNECTION_AVAILABLE = 'integrations.connection.available' as const;
|
|
4
5
|
|
|
5
6
|
const nonEmptyStringSchema = z.string().nonempty();
|
|
6
7
|
const isoDateTimeSchema = z.string().datetime();
|
|
@@ -22,6 +23,16 @@ export const integrationEventReceivedSchema = z.object({
|
|
|
22
23
|
});
|
|
23
24
|
export type IntegrationEventReceivedEvent = z.infer<typeof integrationEventReceivedSchema>;
|
|
24
25
|
|
|
26
|
+
export const integrationConnectionAvailableSchema = z.object({
|
|
27
|
+
provider: nonEmptyStringSchema,
|
|
28
|
+
workspaceId: nonEmptyStringSchema,
|
|
29
|
+
connectionId: nonEmptyStringSchema,
|
|
30
|
+
slug: nonEmptyStringSchema,
|
|
31
|
+
});
|
|
32
|
+
export type IntegrationConnectionAvailableEvent = z.infer<
|
|
33
|
+
typeof integrationConnectionAvailableSchema
|
|
34
|
+
>;
|
|
35
|
+
|
|
25
36
|
// A source-control push, normalized by the producing provider and carried by
|
|
26
37
|
// `INTEGRATION_SOURCE_COMMIT_PUSHED` for domain consumers.
|
|
27
38
|
export const sourcePushSchema = z.object({
|
|
@@ -51,6 +62,32 @@ export type IntegrationSourceCommitPushedEvent = z.infer<
|
|
|
51
62
|
typeof integrationSourceCommitPushedSchema
|
|
52
63
|
>;
|
|
53
64
|
|
|
65
|
+
export const sourceRepositoryIdentitySchema = z.object({
|
|
66
|
+
externalRepositoryId: nonEmptyStringSchema,
|
|
67
|
+
owner: nonEmptyStringSchema,
|
|
68
|
+
name: nonEmptyStringSchema,
|
|
69
|
+
defaultBranch: nonEmptyStringSchema,
|
|
70
|
+
});
|
|
71
|
+
export type SourceRepositoryIdentity = z.infer<typeof sourceRepositoryIdentitySchema>;
|
|
72
|
+
|
|
73
|
+
export const INTEGRATION_SOURCE_REPOSITORY_UPDATED =
|
|
74
|
+
'integrations.source_control.repository_updated' as const;
|
|
75
|
+
|
|
76
|
+
// Typed, provider-agnostic source-control event. The producing provider owns the
|
|
77
|
+
// translation from its raw webhook into this shape, so domain consumers never decode
|
|
78
|
+
// provider payloads.
|
|
79
|
+
export const integrationSourceRepositoryUpdatedSchema = z.object({
|
|
80
|
+
provider: nonEmptyStringSchema,
|
|
81
|
+
workspaceId: nonEmptyStringSchema,
|
|
82
|
+
connectionId: nonEmptyStringSchema,
|
|
83
|
+
deliveryId: nonEmptyStringSchema,
|
|
84
|
+
receivedAt: isoDateTimeSchema,
|
|
85
|
+
repository: sourceRepositoryIdentitySchema,
|
|
86
|
+
});
|
|
87
|
+
export type IntegrationSourceRepositoryUpdatedEvent = z.infer<
|
|
88
|
+
typeof integrationSourceRepositoryUpdatedSchema
|
|
89
|
+
>;
|
|
90
|
+
|
|
54
91
|
export interface SentryIssuePayload {
|
|
55
92
|
action: SentryIssueAction;
|
|
56
93
|
issueId: string;
|
|
@@ -81,11 +118,15 @@ export const SENTRY_ISSUE_ACTIONS = [
|
|
|
81
118
|
export type SentryIssueAction = (typeof SENTRY_ISSUE_ACTIONS)[number];
|
|
82
119
|
|
|
83
120
|
export interface IntegrationsEventMap {
|
|
121
|
+
[INTEGRATION_CONNECTION_AVAILABLE]: IntegrationConnectionAvailableEvent;
|
|
84
122
|
[INTEGRATION_EVENT_RECEIVED]: IntegrationEventReceivedEvent;
|
|
85
123
|
[INTEGRATION_SOURCE_COMMIT_PUSHED]: IntegrationSourceCommitPushedEvent;
|
|
124
|
+
[INTEGRATION_SOURCE_REPOSITORY_UPDATED]: IntegrationSourceRepositoryUpdatedEvent;
|
|
86
125
|
}
|
|
87
126
|
|
|
88
127
|
export const integrationsEventSchemas = {
|
|
128
|
+
[INTEGRATION_CONNECTION_AVAILABLE]: integrationConnectionAvailableSchema,
|
|
89
129
|
[INTEGRATION_EVENT_RECEIVED]: integrationEventReceivedSchema,
|
|
90
130
|
[INTEGRATION_SOURCE_COMMIT_PUSHED]: integrationSourceCommitPushedSchema,
|
|
131
|
+
[INTEGRATION_SOURCE_REPOSITORY_UPDATED]: integrationSourceRepositoryUpdatedSchema,
|
|
91
132
|
} satisfies Record<keyof IntegrationsEventMap, z.ZodType>;
|
package/src/inter-module.test.ts
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
import {integrationsInterModuleContract} from './inter-module.js';
|
|
2
2
|
|
|
3
3
|
describe('integrationsInterModuleContract', () => {
|
|
4
|
+
test('accepts a nullable normalized trigger reference', () => {
|
|
5
|
+
const result = integrationsInterModuleContract.methods.resolveTriggerReference.output.parse({
|
|
6
|
+
externalRepositoryId: 'github:42',
|
|
7
|
+
ref: 'refs/heads/main',
|
|
8
|
+
commit: 'a'.repeat(40),
|
|
9
|
+
actor: 'octocat',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
expect(result?.externalRepositoryId).toBe('github:42');
|
|
13
|
+
expect(result?.actor).toBe('octocat');
|
|
14
|
+
expect(
|
|
15
|
+
integrationsInterModuleContract.methods.resolveTriggerReference.output.parse(null),
|
|
16
|
+
).toBeNull();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('accepts a reference from a payload that named no actor', () => {
|
|
20
|
+
const result = integrationsInterModuleContract.methods.resolveTriggerReference.output.parse({
|
|
21
|
+
externalRepositoryId: 'github:42',
|
|
22
|
+
ref: 'refs/heads/main',
|
|
23
|
+
commit: 'a'.repeat(40),
|
|
24
|
+
actor: null,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
expect(result?.actor).toBeNull();
|
|
28
|
+
});
|
|
29
|
+
|
|
4
30
|
test('accepts a source repository lookup through the producer contract', () => {
|
|
5
31
|
const result = integrationsInterModuleContract.methods.resolveSourceRepository.output.parse({
|
|
6
32
|
connection: {
|
|
@@ -23,6 +49,22 @@ describe('integrationsInterModuleContract', () => {
|
|
|
23
49
|
expect(result.repository.fullName).toBe('shipfox/project');
|
|
24
50
|
});
|
|
25
51
|
|
|
52
|
+
test('accepts a workspace-scoped connection lookup through the producer contract', () => {
|
|
53
|
+
const input = integrationsInterModuleContract.methods.resolveConnection.input.parse({
|
|
54
|
+
workspaceId: '00000000-0000-4000-8000-000000000001',
|
|
55
|
+
slug: 'github-main',
|
|
56
|
+
});
|
|
57
|
+
const output = integrationsInterModuleContract.methods.resolveConnection.output.parse({
|
|
58
|
+
id: '00000000-0000-4000-8000-000000000002',
|
|
59
|
+
provider: 'github',
|
|
60
|
+
slug: 'github-main',
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
expect(input.slug).toBe('github-main');
|
|
64
|
+
expect(output?.id).toBe('00000000-0000-4000-8000-000000000002');
|
|
65
|
+
expect(integrationsInterModuleContract.methods.resolveConnection.output.parse(null)).toBeNull();
|
|
66
|
+
});
|
|
67
|
+
|
|
26
68
|
test.each([
|
|
27
69
|
['connection-not-found', {connectionId: '00000000-0000-4000-8000-000000000001'}],
|
|
28
70
|
['provider-unavailable', {provider: 'github'}],
|
package/src/inter-module.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {z} from 'zod';
|
|
|
4
4
|
const id = z.string().uuid();
|
|
5
5
|
const provider = z.string().min(1);
|
|
6
6
|
const capability = z.enum(['source_control', 'agent_tools']);
|
|
7
|
+
const connection = z.object({id, provider, slug: z.string().min(1)});
|
|
7
8
|
const repository = z.object({
|
|
8
9
|
externalRepositoryId: z.string(),
|
|
9
10
|
owner: z.string(),
|
|
@@ -14,6 +15,12 @@ const repository = z.object({
|
|
|
14
15
|
cloneUrl: z.string(),
|
|
15
16
|
htmlUrl: z.string(),
|
|
16
17
|
});
|
|
18
|
+
const triggerReference = z.object({
|
|
19
|
+
externalRepositoryId: z.string(),
|
|
20
|
+
ref: z.string(),
|
|
21
|
+
commit: z.string(),
|
|
22
|
+
actor: z.string().nullable(),
|
|
23
|
+
});
|
|
17
24
|
const sourceInput = z.object({workspaceId: id, connectionId: id, externalRepositoryId: z.string()});
|
|
18
25
|
const providerError = z.object({
|
|
19
26
|
reason: z.string(),
|
|
@@ -35,7 +42,16 @@ export const integrationsInterModuleContract = defineInterModuleContract({
|
|
|
35
42
|
methods: {
|
|
36
43
|
resolveSourceRepository: {
|
|
37
44
|
input: sourceInput,
|
|
38
|
-
output: z.object({connection
|
|
45
|
+
output: z.object({connection, repository}),
|
|
46
|
+
errors: sourceErrors,
|
|
47
|
+
},
|
|
48
|
+
resolveConnection: {
|
|
49
|
+
input: z.object({workspaceId: id, slug: z.string().min(1)}),
|
|
50
|
+
output: connection.nullable(),
|
|
51
|
+
},
|
|
52
|
+
resolveTriggerReference: {
|
|
53
|
+
input: z.object({workspaceId: id, connectionId: id, payload: z.unknown()}),
|
|
54
|
+
output: triggerReference.nullable(),
|
|
39
55
|
errors: sourceErrors,
|
|
40
56
|
},
|
|
41
57
|
listSourceFiles: {
|
package/src/webhooks.test.ts
CHANGED
|
@@ -90,6 +90,24 @@ describe('storedWebhookRequestSchema', () => {
|
|
|
90
90
|
expect(storedWebhookRequestSchema.safeParse(withoutConnectionId).success).toBe(false);
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
+
it('requires and round-trips a connection identifier for Jira requests', () => {
|
|
94
|
+
const request = createStoredWebhookRequest({
|
|
95
|
+
requestId,
|
|
96
|
+
routeId: 'jira',
|
|
97
|
+
receivedAt,
|
|
98
|
+
rawQueryString: '',
|
|
99
|
+
headers: {authorization: 'Bearer token'},
|
|
100
|
+
body: new Uint8Array([1, 2, 3]),
|
|
101
|
+
connectionId: 'c0a8012e-0b6d-4d8f-8d5c-6d74102602b0',
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(request.path_parameters.connection_id).toBe('c0a8012e-0b6d-4d8f-8d5c-6d74102602b0');
|
|
105
|
+
expect(storedWebhookRequestSchema.parse(JSON.parse(JSON.stringify(request)))).toEqual(request);
|
|
106
|
+
expect(storedWebhookRequestSchema.safeParse({...request, path_parameters: {}}).success).toBe(
|
|
107
|
+
false,
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
|
|
93
111
|
it('keeps the maximum-size fixture below the SQS message limit', () => {
|
|
94
112
|
const fixture = createMaximumSizeStoredWebhookRequestFixture();
|
|
95
113
|
const serializedSize = new TextEncoder().encode(JSON.stringify(fixture)).byteLength;
|
package/src/webhooks.ts
CHANGED
|
@@ -15,7 +15,7 @@ const standardWebhookRouteIds = [
|
|
|
15
15
|
'slack.command',
|
|
16
16
|
] as const;
|
|
17
17
|
|
|
18
|
-
export const webhookRouteIds = [...standardWebhookRouteIds, 'webhook.connection'] as const;
|
|
18
|
+
export const webhookRouteIds = [...standardWebhookRouteIds, 'webhook.connection', 'jira'] as const;
|
|
19
19
|
|
|
20
20
|
export const webhookRouteIdSchema = z.enum(webhookRouteIds);
|
|
21
21
|
export type WebhookRouteId = z.infer<typeof webhookRouteIdSchema>;
|
|
@@ -87,9 +87,17 @@ const genericWebhookRouteRequestSchema = storedWebhookRequestBaseSchema
|
|
|
87
87
|
})
|
|
88
88
|
.strict();
|
|
89
89
|
|
|
90
|
+
const jiraWebhookRouteRequestSchema = storedWebhookRequestBaseSchema
|
|
91
|
+
.extend({
|
|
92
|
+
route_id: z.literal('jira'),
|
|
93
|
+
path_parameters: connectionPathParametersSchema,
|
|
94
|
+
})
|
|
95
|
+
.strict();
|
|
96
|
+
|
|
90
97
|
export const storedWebhookRequestSchema = z.discriminatedUnion('route_id', [
|
|
91
98
|
standardWebhookRouteRequestSchema,
|
|
92
99
|
genericWebhookRouteRequestSchema,
|
|
100
|
+
jiraWebhookRouteRequestSchema,
|
|
93
101
|
]);
|
|
94
102
|
export type StoredWebhookRequest = z.infer<typeof storedWebhookRequestSchema>;
|
|
95
103
|
|
|
@@ -119,16 +127,27 @@ export const webhookProcessingResultSchema = z.discriminatedUnion('outcome', [
|
|
|
119
127
|
]);
|
|
120
128
|
export type WebhookProcessingResult = z.infer<typeof webhookProcessingResultSchema>;
|
|
121
129
|
|
|
122
|
-
|
|
130
|
+
interface CreateStoredWebhookRequestInputBase {
|
|
123
131
|
requestId: string;
|
|
124
132
|
routeId: WebhookRouteId;
|
|
125
133
|
receivedAt: string;
|
|
126
134
|
rawQueryString: string;
|
|
127
135
|
headers: Record<string, string>;
|
|
128
136
|
body: Uint8Array;
|
|
129
|
-
connectionId?: string | undefined;
|
|
130
137
|
}
|
|
131
138
|
|
|
139
|
+
type ConnectionScopedWebhookRouteId = 'webhook.connection' | 'jira';
|
|
140
|
+
|
|
141
|
+
export type CreateStoredWebhookRequestInput =
|
|
142
|
+
| (CreateStoredWebhookRequestInputBase & {
|
|
143
|
+
routeId: ConnectionScopedWebhookRouteId;
|
|
144
|
+
connectionId: string;
|
|
145
|
+
})
|
|
146
|
+
| (CreateStoredWebhookRequestInputBase & {
|
|
147
|
+
routeId: Exclude<WebhookRouteId, ConnectionScopedWebhookRouteId>;
|
|
148
|
+
connectionId?: never;
|
|
149
|
+
});
|
|
150
|
+
|
|
132
151
|
export function encodeWebhookBody(body: Uint8Array): string {
|
|
133
152
|
let encoded = '';
|
|
134
153
|
|
|
@@ -188,7 +207,9 @@ export function createStoredWebhookRequest(
|
|
|
188
207
|
input: CreateStoredWebhookRequestInput,
|
|
189
208
|
): StoredWebhookRequest {
|
|
190
209
|
const pathParameters =
|
|
191
|
-
input.routeId === 'webhook.connection'
|
|
210
|
+
input.routeId === 'webhook.connection' || input.routeId === 'jira'
|
|
211
|
+
? {connection_id: input.connectionId}
|
|
212
|
+
: {};
|
|
192
213
|
|
|
193
214
|
return storedWebhookRequestSchema.parse({
|
|
194
215
|
schema_version: WEBHOOK_REQUEST_SCHEMA_VERSION,
|