@team-plain/webhooks 0.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/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +12 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/parse.d.ts +5 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +102 -0
- package/dist/parse.js.map +1 -0
- package/dist/result.d.ts +12 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +4 -0
- package/dist/result.js.map +1 -0
- package/dist/verify.d.ts +14 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +65 -0
- package/dist/verify.js.map +1 -0
- package/dist/webhook-schema.d.ts +854 -0
- package/dist/webhook-schema.d.ts.map +1 -0
- package/dist/webhook-schema.js +8 -0
- package/dist/webhook-schema.js.map +1 -0
- package/dist/webhook-schema.json +3495 -0
- package/package.json +31 -0
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare abstract class PlainWebhookError extends Error {
|
|
2
|
+
}
|
|
3
|
+
export declare class PlainWebhookSignatureVerificationError extends PlainWebhookError {
|
|
4
|
+
}
|
|
5
|
+
export declare class PlainWebhookVersionMismatchError extends PlainWebhookError {
|
|
6
|
+
constructor(error: string, payloadVersion: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class PlainWebhookPayloadError extends PlainWebhookError {
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,8BAAsB,iBAAkB,SAAQ,KAAK;CAAG;AAExD,qBAAa,sCAAuC,SAAQ,iBAAiB;CAAG;AAEhF,qBAAa,gCAAiC,SAAQ,iBAAiB;gBACzD,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;CAKlD;AAED,qBAAa,wBAAyB,SAAQ,iBAAiB;CAAG"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export class PlainWebhookError extends Error {
|
|
2
|
+
}
|
|
3
|
+
export class PlainWebhookSignatureVerificationError extends PlainWebhookError {
|
|
4
|
+
}
|
|
5
|
+
export class PlainWebhookVersionMismatchError extends PlainWebhookError {
|
|
6
|
+
constructor(error, payloadVersion) {
|
|
7
|
+
super(`The webhook payload (version=${payloadVersion}) is incompatible with the current version of the SDK. Please upgrade both the SDK and the webhook target to the latest version. Refer to https://www.plain.com/docs/api-reference/webhooks/versions for more information. Original error: ${error}`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class PlainWebhookPayloadError extends PlainWebhookError {
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAgB,iBAAkB,SAAQ,KAAK;CAAG;AAExD,MAAM,OAAO,sCAAuC,SAAQ,iBAAiB;CAAG;AAEhF,MAAM,OAAO,gCAAiC,SAAQ,iBAAiB;IACrE,YAAY,KAAa,EAAE,cAAsB;QAC/C,KAAK,CACH,gCAAgC,cAAc,8OAA8O,KAAK,EAAE,CACpS,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,wBAAyB,SAAQ,iBAAiB;CAAG"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { parsePlainWebhook } from "./parse.js";
|
|
2
|
+
export { verifyPlainWebhook } from "./verify.js";
|
|
3
|
+
export { PlainWebhookError, PlainWebhookSignatureVerificationError, PlainWebhookVersionMismatchError, PlainWebhookPayloadError, } from "./errors.js";
|
|
4
|
+
export type { Result } from "./result.js";
|
|
5
|
+
export type { CustomerChangedPayload, CustomerCreatedPublicEventPayload, CustomerDeletedPublicEventPayload, CustomerGroupChangedPayload, CustomerGroupMembershipsChangedPayload, CustomerUpdatedPublicEventPayload, ThreadAssignmentTransitionedPublicEventPayload, ThreadChatSentPublicEventPayload, ThreadCreatedPublicEventPayload, ThreadEmailReceivedPublicEventPayload, ThreadEmailSentPublicEventPayload, ThreadFieldCreatedPublicEventPayload, ThreadFieldDeletedPublicEventPayload, ThreadFieldUpdatedPublicEventPayload, ThreadLabelsChangedPublicEventPayload, ThreadPriorityChangedPublicEventPayload, ThreadServiceLevelAgreementStatusTransitionedPayload, ThreadSlackMessageReceivedEventPayload, ThreadSlackMessageSentEventPayload, ThreadStatusTransitionedPublicEventPayload, TimelineEntryChangedPayload, WebhooksSchemaDefinition, } from "./webhook-schema.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EACL,iBAAiB,EACjB,sCAAsC,EACtC,gCAAgC,EAChC,wBAAwB,GACzB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,YAAY,EACV,sBAAsB,EACtB,iCAAiC,EACjC,iCAAiC,EACjC,2BAA2B,EAC3B,sCAAsC,EACtC,iCAAiC,EACjC,8CAA8C,EAC9C,gCAAgC,EAChC,+BAA+B,EAC/B,qCAAqC,EACrC,iCAAiC,EACjC,oCAAoC,EACpC,oCAAoC,EACpC,oCAAoC,EACpC,qCAAqC,EACrC,uCAAuC,EACvC,oDAAoD,EACpD,sCAAsC,EACtC,kCAAkC,EAClC,0CAA0C,EAC1C,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { parsePlainWebhook } from "./parse.js";
|
|
2
|
+
export { verifyPlainWebhook } from "./verify.js";
|
|
3
|
+
export { PlainWebhookError, PlainWebhookSignatureVerificationError, PlainWebhookVersionMismatchError, PlainWebhookPayloadError, } from "./errors.js";
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EACL,iBAAiB,EACjB,sCAAsC,EACtC,gCAAgC,EAChC,wBAAwB,GACzB,MAAM,aAAa,CAAC"}
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Result } from "./result.js";
|
|
2
|
+
import { PlainWebhookPayloadError } from "./errors.js";
|
|
3
|
+
import type { WebhooksSchemaDefinition } from "./webhook-schema.js";
|
|
4
|
+
export declare function parsePlainWebhook(unknownPayload: unknown): Result<WebhooksSchemaDefinition, PlainWebhookPayloadError>;
|
|
5
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,MAAM,EAAS,MAAM,aAAa,CAAC;AACjD,OAAO,EAEL,wBAAwB,EAEzB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAGpE,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,OAAO,GACtB,MAAM,CAAC,wBAAwB,EAAE,wBAAwB,CAAC,CAuC5D"}
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Ajv } from "ajv";
|
|
2
|
+
import _addFormats from "ajv-formats";
|
|
3
|
+
// ajv-formats is CJS — under nodenext the default import resolves to the module namespace
|
|
4
|
+
const addFormats = _addFormats;
|
|
5
|
+
import { isErr } from "./result.js";
|
|
6
|
+
import { PlainWebhookPayloadError, PlainWebhookVersionMismatchError, } from "./errors.js";
|
|
7
|
+
import webhookSchema from "./webhook-schema.json" with { type: "json" };
|
|
8
|
+
export function parsePlainWebhook(unknownPayload) {
|
|
9
|
+
const payloadResult = (() => {
|
|
10
|
+
if (typeof unknownPayload === "string") {
|
|
11
|
+
try {
|
|
12
|
+
return { data: JSON.parse(unknownPayload) };
|
|
13
|
+
}
|
|
14
|
+
catch (_e) {
|
|
15
|
+
return {
|
|
16
|
+
error: new PlainWebhookPayloadError("The webhook payload is not a valid JSON object."),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return { data: unknownPayload };
|
|
21
|
+
})();
|
|
22
|
+
if (isErr(payloadResult)) {
|
|
23
|
+
return payloadResult;
|
|
24
|
+
}
|
|
25
|
+
const payload = payloadResult.data;
|
|
26
|
+
const ajv = new Ajv({
|
|
27
|
+
unicodeRegExp: false,
|
|
28
|
+
});
|
|
29
|
+
addFormats(ajv);
|
|
30
|
+
if (ajv.validate(webhookSchema, payload)) {
|
|
31
|
+
return { data: payload };
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
return { error: getParseError(payload, ajv.errorsText()) };
|
|
35
|
+
}
|
|
36
|
+
catch (_e) {
|
|
37
|
+
return {
|
|
38
|
+
error: new PlainWebhookPayloadError(`Failed to parse the webhook payload: ${ajv.errorsText()}`),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function getParseError(payload, originalAjvError) {
|
|
43
|
+
const errorMessage = getErrorMessageForHumans(payload, originalAjvError);
|
|
44
|
+
if (isVersionMismatch(payload)) {
|
|
45
|
+
return new PlainWebhookVersionMismatchError(errorMessage, getPayloadVersion(payload) ?? "unknown");
|
|
46
|
+
}
|
|
47
|
+
return new PlainWebhookPayloadError(errorMessage);
|
|
48
|
+
}
|
|
49
|
+
function isVersionMismatch(payload) {
|
|
50
|
+
const schemaVersion = getSchemaVersion();
|
|
51
|
+
return typeof schemaVersion === "string" && schemaVersion !== getPayloadVersion(payload);
|
|
52
|
+
}
|
|
53
|
+
function getErrorMessageForHumans(payload, originalAjvError) {
|
|
54
|
+
try {
|
|
55
|
+
const eventType = payload.type;
|
|
56
|
+
if (typeof eventType !== "string") {
|
|
57
|
+
return originalAjvError;
|
|
58
|
+
}
|
|
59
|
+
const payloadDefinitionKey = (() => {
|
|
60
|
+
for (const [key, definition] of Object.entries(webhookSchema.definitions)) {
|
|
61
|
+
if (definition?.properties?.eventType?.const === eventType) {
|
|
62
|
+
return key;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
})();
|
|
67
|
+
if (payloadDefinitionKey === null) {
|
|
68
|
+
return originalAjvError;
|
|
69
|
+
}
|
|
70
|
+
const updatedSchema = {
|
|
71
|
+
...webhookSchema,
|
|
72
|
+
properties: {
|
|
73
|
+
...webhookSchema.properties,
|
|
74
|
+
payload: {
|
|
75
|
+
$ref: `#/definitions/${payloadDefinitionKey}`,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
const ajv = new Ajv({
|
|
80
|
+
unicodeRegExp: false,
|
|
81
|
+
});
|
|
82
|
+
addFormats(ajv);
|
|
83
|
+
if (ajv.validate(updatedSchema, payload)) {
|
|
84
|
+
return originalAjvError;
|
|
85
|
+
}
|
|
86
|
+
return ajv.errorsText();
|
|
87
|
+
}
|
|
88
|
+
catch (_e) {
|
|
89
|
+
return originalAjvError;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function getPayloadVersion(payload) {
|
|
93
|
+
const metadata = payload?.webhookMetadata;
|
|
94
|
+
const ret = metadata?.webhookTargetVersion;
|
|
95
|
+
return typeof ret === "string" ? ret : null;
|
|
96
|
+
}
|
|
97
|
+
function getSchemaVersion() {
|
|
98
|
+
const ret = webhookSchema?.definitions?.webhookMetadata?.properties?.webhookTargetVersion
|
|
99
|
+
?.const;
|
|
100
|
+
return typeof ret === "string" ? ret : null;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
|
package/dist/result.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type Data<T> = {
|
|
2
|
+
data: T;
|
|
3
|
+
error?: never;
|
|
4
|
+
};
|
|
5
|
+
type Err<U> = {
|
|
6
|
+
data?: never;
|
|
7
|
+
error: U;
|
|
8
|
+
};
|
|
9
|
+
export type Result<T, U> = NonNullable<Data<T> | Err<U>>;
|
|
10
|
+
export declare const isErr: <T, U>(result: Result<T, U>) => result is Err<U>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,KAAK,IAAI,CAAC,CAAC,IAAI;IACb,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAEF,KAAK,GAAG,CAAC,CAAC,IAAI;IACZ,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,CAAC,CAAC;CACV,CAAC;AAEF,MAAM,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzD,eAAO,MAAM,KAAK,GAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,KAAG,MAAM,IAAI,GAAG,CAAC,CAAC,CAEjE,CAAC"}
|
package/dist/result.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,KAAK,GAAG,CAAO,MAAoB,EAAoB,EAAE;IACpE,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;AACxB,CAAC,CAAC"}
|
package/dist/verify.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Result } from "./result.js";
|
|
2
|
+
import { type PlainWebhookError } from "./errors.js";
|
|
3
|
+
import type { WebhooksSchemaDefinition } from "./webhook-schema.js";
|
|
4
|
+
/**
|
|
5
|
+
* Verifies and validates a Plain webhook payload.
|
|
6
|
+
*
|
|
7
|
+
* @param payload - The raw request body.
|
|
8
|
+
* @param signature - The value of the 'Plain-Request-Signature' header.
|
|
9
|
+
* @param secret - Your Plain webhook signing secret.
|
|
10
|
+
* @param tolerance - (Optional) Maximum allowed difference in seconds between the timestamp and the current time. Defaults to 300 seconds. This is helpful to prevent replay attacks.
|
|
11
|
+
* @returns A Result object containing the validated payload or an error.
|
|
12
|
+
*/
|
|
13
|
+
export declare function verifyPlainWebhook(payloadRaw: string, signature: string, secret: string, tolerance?: number): Result<WebhooksSchemaDefinition, PlainWebhookError>;
|
|
14
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,MAAM,EAAS,MAAM,aAAa,CAAC;AACjD,OAAO,EACL,KAAK,iBAAiB,EAGvB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAEpE;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,SAAM,GACd,MAAM,CAAC,wBAAwB,EAAE,iBAAiB,CAAC,CAgCrD"}
|
package/dist/verify.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
|
+
import { isErr } from "./result.js";
|
|
3
|
+
import { PlainWebhookPayloadError, PlainWebhookSignatureVerificationError, } from "./errors.js";
|
|
4
|
+
import { parsePlainWebhook } from "./parse.js";
|
|
5
|
+
/**
|
|
6
|
+
* Verifies and validates a Plain webhook payload.
|
|
7
|
+
*
|
|
8
|
+
* @param payload - The raw request body.
|
|
9
|
+
* @param signature - The value of the 'Plain-Request-Signature' header.
|
|
10
|
+
* @param secret - Your Plain webhook signing secret.
|
|
11
|
+
* @param tolerance - (Optional) Maximum allowed difference in seconds between the timestamp and the current time. Defaults to 300 seconds. This is helpful to prevent replay attacks.
|
|
12
|
+
* @returns A Result object containing the validated payload or an error.
|
|
13
|
+
*/
|
|
14
|
+
export function verifyPlainWebhook(payloadRaw, signature, secret, tolerance = 300) {
|
|
15
|
+
const signatureVerificationResult = verifyWebhookSignature(payloadRaw, signature, secret);
|
|
16
|
+
if (isErr(signatureVerificationResult)) {
|
|
17
|
+
return signatureVerificationResult;
|
|
18
|
+
}
|
|
19
|
+
const payloadResult = parsePlainWebhook(payloadRaw);
|
|
20
|
+
if (isErr(payloadResult)) {
|
|
21
|
+
return payloadResult;
|
|
22
|
+
}
|
|
23
|
+
const payload = payloadResult.data;
|
|
24
|
+
const timestamp = Date.parse(payload.webhookMetadata.webhookDeliveryAttemptTimestamp);
|
|
25
|
+
if (Number.isNaN(timestamp)) {
|
|
26
|
+
return {
|
|
27
|
+
error: new PlainWebhookPayloadError(`Invalid timestamp provided in the webhook payload: ${timestamp}. This is likely a bug in the Plain API (eventId: ${payload.id}).`),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const currentTime = Date.now();
|
|
31
|
+
if (Math.abs(currentTime - timestamp) > tolerance * 1000) {
|
|
32
|
+
return {
|
|
33
|
+
error: new PlainWebhookSignatureVerificationError(`The timestamp provided in the webhook payload is too far in the past. The maximum allowed difference is ${tolerance} seconds.`),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return { data: payload };
|
|
37
|
+
}
|
|
38
|
+
function verifyWebhookSignature(payload, signature, secret) {
|
|
39
|
+
if (payload.length === 0) {
|
|
40
|
+
return {
|
|
41
|
+
error: new PlainWebhookSignatureVerificationError("No webhook payload was provided."),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (signature.length === 0) {
|
|
45
|
+
return {
|
|
46
|
+
error: new PlainWebhookSignatureVerificationError('No signature header value was provided. Please pass the value of the "Plain-Request-Signature" header.'),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (secret.length === 0) {
|
|
50
|
+
return {
|
|
51
|
+
error: new PlainWebhookSignatureVerificationError("No webhook secret was provided. You can find your webhook secret in your workspace settings."),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const expectedSignature = crypto
|
|
55
|
+
.createHmac("sha256", secret)
|
|
56
|
+
.update(payload, "utf8")
|
|
57
|
+
.digest("hex");
|
|
58
|
+
if (signature !== expectedSignature) {
|
|
59
|
+
return {
|
|
60
|
+
error: new PlainWebhookSignatureVerificationError("The signature provided is invalid."),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return { data: true };
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAe,KAAK,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAEL,wBAAwB,EACxB,sCAAsC,GACvC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAG/C;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,UAAkB,EAClB,SAAiB,EACjB,MAAc,EACd,SAAS,GAAG,GAAG;IAEf,MAAM,2BAA2B,GAAG,sBAAsB,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAC1F,IAAI,KAAK,CAAC,2BAA2B,CAAC,EAAE,CAAC;QACvC,OAAO,2BAA2B,CAAC;IACrC,CAAC;IAED,MAAM,aAAa,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACpD,IAAI,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;QACzB,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC;IACnC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,+BAA+B,CAAC,CAAC;IAEtF,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,KAAK,EAAE,IAAI,wBAAwB,CACjC,sDAAsD,SAAS,qDAAqD,OAAO,CAAC,EAAE,IAAI,CACnI;SACF,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC/B,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,CAAC;QACzD,OAAO;YACL,KAAK,EAAE,IAAI,sCAAsC,CAC/C,2GAA2G,SAAS,WAAW,CAChI;SACF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,sBAAsB,CAC7B,OAAe,EACf,SAAiB,EACjB,MAAc;IAEd,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,KAAK,EAAE,IAAI,sCAAsC,CAAC,kCAAkC,CAAC;SACtF,CAAC;IACJ,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO;YACL,KAAK,EAAE,IAAI,sCAAsC,CAC/C,wGAAwG,CACzG;SACF,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,KAAK,EAAE,IAAI,sCAAsC,CAC/C,8FAA8F,CAC/F;SACF,CAAC;IACJ,CAAC;IAED,MAAM,iBAAiB,GAAG,MAAM;SAC7B,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC;SAC5B,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC;SACvB,MAAM,CAAC,KAAK,CAAC,CAAC;IAEjB,IAAI,SAAS,KAAK,iBAAiB,EAAE,CAAC;QACpC,OAAO;YACL,KAAK,EAAE,IAAI,sCAAsC,CAAC,oCAAoC,CAAC;SACxF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC"}
|