@team-plain/webhooks 1.0.0 → 1.0.1
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/cjs/errors.js +47 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.js +41 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/parse.js +141 -0
- package/dist/cjs/parse.js.map +1 -0
- package/dist/cjs/result.js +31 -0
- package/dist/cjs/result.js.map +1 -0
- package/dist/cjs/verify.js +98 -0
- package/dist/cjs/verify.js.map +1 -0
- package/dist/cjs/webhook-schema.js +17 -0
- package/dist/cjs/webhook-schema.js.map +1 -0
- package/dist/cjs/webhook-schema.json +3498 -0
- package/package.json +33 -7
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var errors_exports = {};
|
|
20
|
+
__export(errors_exports, {
|
|
21
|
+
PlainWebhookError: () => PlainWebhookError,
|
|
22
|
+
PlainWebhookPayloadError: () => PlainWebhookPayloadError,
|
|
23
|
+
PlainWebhookSignatureVerificationError: () => PlainWebhookSignatureVerificationError,
|
|
24
|
+
PlainWebhookVersionMismatchError: () => PlainWebhookVersionMismatchError
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(errors_exports);
|
|
27
|
+
class PlainWebhookError extends Error {
|
|
28
|
+
}
|
|
29
|
+
class PlainWebhookSignatureVerificationError extends PlainWebhookError {
|
|
30
|
+
}
|
|
31
|
+
class PlainWebhookVersionMismatchError extends PlainWebhookError {
|
|
32
|
+
constructor(error, payloadVersion) {
|
|
33
|
+
super(
|
|
34
|
+
`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}`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
class PlainWebhookPayloadError extends PlainWebhookError {
|
|
39
|
+
}
|
|
40
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
41
|
+
0 && (module.exports = {
|
|
42
|
+
PlainWebhookError,
|
|
43
|
+
PlainWebhookPayloadError,
|
|
44
|
+
PlainWebhookSignatureVerificationError,
|
|
45
|
+
PlainWebhookVersionMismatchError
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/errors.ts"],"sourcesContent":["export abstract class PlainWebhookError extends Error {}\n\nexport class PlainWebhookSignatureVerificationError extends PlainWebhookError {}\n\nexport class PlainWebhookVersionMismatchError extends PlainWebhookError {\n constructor(error: string, payloadVersion: string) {\n super(\n `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}`,\n );\n }\n}\n\nexport class PlainWebhookPayloadError extends PlainWebhookError {}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAe,0BAA0B,MAAM;AAAC;AAEhD,MAAM,+CAA+C,kBAAkB;AAAC;AAExE,MAAM,yCAAyC,kBAAkB;AAAA,EACtE,YAAY,OAAe,gBAAwB;AACjD;AAAA,MACE,gCAAgC,cAAc,8OAA8O,KAAK;AAAA,IACnS;AAAA,EACF;AACF;AAEO,MAAM,iCAAiC,kBAAkB;AAAC;","names":[]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var index_exports = {};
|
|
20
|
+
__export(index_exports, {
|
|
21
|
+
PlainWebhookError: () => import_errors.PlainWebhookError,
|
|
22
|
+
PlainWebhookPayloadError: () => import_errors.PlainWebhookPayloadError,
|
|
23
|
+
PlainWebhookSignatureVerificationError: () => import_errors.PlainWebhookSignatureVerificationError,
|
|
24
|
+
PlainWebhookVersionMismatchError: () => import_errors.PlainWebhookVersionMismatchError,
|
|
25
|
+
parsePlainWebhook: () => import_parse.parsePlainWebhook,
|
|
26
|
+
verifyPlainWebhook: () => import_verify.verifyPlainWebhook
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
var import_errors = require("./errors.js");
|
|
30
|
+
var import_parse = require("./parse.js");
|
|
31
|
+
var import_verify = require("./verify.js");
|
|
32
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
33
|
+
0 && (module.exports = {
|
|
34
|
+
PlainWebhookError,
|
|
35
|
+
PlainWebhookPayloadError,
|
|
36
|
+
PlainWebhookSignatureVerificationError,
|
|
37
|
+
PlainWebhookVersionMismatchError,
|
|
38
|
+
parsePlainWebhook,
|
|
39
|
+
verifyPlainWebhook
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export {\n PlainWebhookError,\n PlainWebhookPayloadError,\n PlainWebhookSignatureVerificationError,\n PlainWebhookVersionMismatchError,\n} from \"./errors.js\";\nexport { parsePlainWebhook } from \"./parse.js\";\nexport type { Result } from \"./result.js\";\nexport { verifyPlainWebhook } from \"./verify.js\";\n\nexport type {\n CustomerChangedPayload,\n CustomerCreatedPublicEventPayload,\n CustomerDeletedPublicEventPayload,\n CustomerGroupChangedPayload,\n CustomerGroupMembershipsChangedPayload,\n CustomerUpdatedPublicEventPayload,\n ThreadAssignmentTransitionedPublicEventPayload,\n ThreadChatSentPublicEventPayload,\n ThreadCreatedPublicEventPayload,\n ThreadEmailReceivedPublicEventPayload,\n ThreadEmailSentPublicEventPayload,\n ThreadFieldCreatedPublicEventPayload,\n ThreadFieldDeletedPublicEventPayload,\n ThreadFieldUpdatedPublicEventPayload,\n ThreadLabelsChangedPublicEventPayload,\n ThreadPriorityChangedPublicEventPayload,\n ThreadServiceLevelAgreementStatusTransitionedPayload,\n ThreadSlackMessageReceivedEventPayload,\n ThreadSlackMessageSentEventPayload,\n ThreadStatusTransitionedPublicEventPayload,\n TimelineEntryChangedPayload,\n WebhooksSchemaDefinition,\n} from \"./webhook-schema.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAKO;AACP,mBAAkC;AAElC,oBAAmC;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var parse_exports = {};
|
|
30
|
+
__export(parse_exports, {
|
|
31
|
+
parsePlainWebhook: () => parsePlainWebhook
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(parse_exports);
|
|
34
|
+
var import_ajv = require("ajv");
|
|
35
|
+
var import_ajv_formats = __toESM(require("ajv-formats"), 1);
|
|
36
|
+
var import_errors = require("./errors.js");
|
|
37
|
+
var import_result = require("./result.js");
|
|
38
|
+
var import_webhook_schema = __toESM(require("./webhook-schema.json"), 1);
|
|
39
|
+
const addFormats = import_ajv_formats.default;
|
|
40
|
+
function parsePlainWebhook(unknownPayload) {
|
|
41
|
+
const payloadResult = (() => {
|
|
42
|
+
if (typeof unknownPayload === "string") {
|
|
43
|
+
try {
|
|
44
|
+
return { data: JSON.parse(unknownPayload) };
|
|
45
|
+
} catch (_e) {
|
|
46
|
+
return {
|
|
47
|
+
error: new import_errors.PlainWebhookPayloadError("The webhook payload is not a valid JSON object.")
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { data: unknownPayload };
|
|
52
|
+
})();
|
|
53
|
+
if ((0, import_result.isErr)(payloadResult)) {
|
|
54
|
+
return payloadResult;
|
|
55
|
+
}
|
|
56
|
+
const payload = payloadResult.data;
|
|
57
|
+
const ajv = new import_ajv.Ajv({
|
|
58
|
+
unicodeRegExp: false
|
|
59
|
+
});
|
|
60
|
+
addFormats(ajv);
|
|
61
|
+
if (ajv.validate(import_webhook_schema.default, payload)) {
|
|
62
|
+
return { data: payload };
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
return { error: getParseError(payload, ajv.errorsText()) };
|
|
66
|
+
} catch (_e) {
|
|
67
|
+
return {
|
|
68
|
+
error: new import_errors.PlainWebhookPayloadError(
|
|
69
|
+
`Failed to parse the webhook payload: ${ajv.errorsText()}`
|
|
70
|
+
)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function getParseError(payload, originalAjvError) {
|
|
75
|
+
const errorMessage = getErrorMessageForHumans(payload, originalAjvError);
|
|
76
|
+
if (isVersionMismatch(payload)) {
|
|
77
|
+
return new import_errors.PlainWebhookVersionMismatchError(
|
|
78
|
+
errorMessage,
|
|
79
|
+
getPayloadVersion(payload) ?? "unknown"
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return new import_errors.PlainWebhookPayloadError(errorMessage);
|
|
83
|
+
}
|
|
84
|
+
function isVersionMismatch(payload) {
|
|
85
|
+
const schemaVersion = getSchemaVersion();
|
|
86
|
+
return typeof schemaVersion === "string" && schemaVersion !== getPayloadVersion(payload);
|
|
87
|
+
}
|
|
88
|
+
function getErrorMessageForHumans(payload, originalAjvError) {
|
|
89
|
+
try {
|
|
90
|
+
const eventType = payload.type;
|
|
91
|
+
if (typeof eventType !== "string") {
|
|
92
|
+
return originalAjvError;
|
|
93
|
+
}
|
|
94
|
+
const payloadDefinitionKey = (() => {
|
|
95
|
+
for (const [key, definition] of Object.entries(
|
|
96
|
+
import_webhook_schema.default.definitions
|
|
97
|
+
)) {
|
|
98
|
+
if (definition?.properties?.eventType?.const === eventType) {
|
|
99
|
+
return key;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
})();
|
|
104
|
+
if (payloadDefinitionKey === null) {
|
|
105
|
+
return originalAjvError;
|
|
106
|
+
}
|
|
107
|
+
const updatedSchema = {
|
|
108
|
+
...import_webhook_schema.default,
|
|
109
|
+
properties: {
|
|
110
|
+
...import_webhook_schema.default.properties,
|
|
111
|
+
payload: {
|
|
112
|
+
$ref: `#/definitions/${payloadDefinitionKey}`
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const ajv = new import_ajv.Ajv({
|
|
117
|
+
unicodeRegExp: false
|
|
118
|
+
});
|
|
119
|
+
addFormats(ajv);
|
|
120
|
+
if (ajv.validate(updatedSchema, payload)) {
|
|
121
|
+
return originalAjvError;
|
|
122
|
+
}
|
|
123
|
+
return ajv.errorsText();
|
|
124
|
+
} catch (_e) {
|
|
125
|
+
return originalAjvError;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function getPayloadVersion(payload) {
|
|
129
|
+
const metadata = payload?.webhookMetadata;
|
|
130
|
+
const ret = metadata?.webhookTargetVersion;
|
|
131
|
+
return typeof ret === "string" ? ret : null;
|
|
132
|
+
}
|
|
133
|
+
function getSchemaVersion() {
|
|
134
|
+
const ret = import_webhook_schema.default?.definitions?.webhookMetadata?.properties?.webhookTargetVersion?.const;
|
|
135
|
+
return typeof ret === "string" ? ret : null;
|
|
136
|
+
}
|
|
137
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
138
|
+
0 && (module.exports = {
|
|
139
|
+
parsePlainWebhook
|
|
140
|
+
});
|
|
141
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/parse.ts"],"sourcesContent":["import { Ajv } from \"ajv\";\nimport _addFormats from \"ajv-formats\";\n\n// ajv-formats is CJS — under nodenext the default import resolves to the module namespace\nconst addFormats = _addFormats as unknown as typeof _addFormats.default;\n\nimport {\n type PlainWebhookError,\n PlainWebhookPayloadError,\n PlainWebhookVersionMismatchError,\n} from \"./errors.js\";\nimport { isErr, type Result } from \"./result.js\";\nimport type { WebhooksSchemaDefinition } from \"./webhook-schema.js\";\nimport webhookSchema from \"./webhook-schema.json\" with { type: \"json\" };\n\nexport function parsePlainWebhook(\n unknownPayload: unknown,\n): Result<WebhooksSchemaDefinition, PlainWebhookPayloadError> {\n const payloadResult = (() => {\n if (typeof unknownPayload === \"string\") {\n try {\n return { data: JSON.parse(unknownPayload) };\n } catch (_e) {\n return {\n error: new PlainWebhookPayloadError(\"The webhook payload is not a valid JSON object.\"),\n };\n }\n }\n\n return { data: unknownPayload };\n })();\n\n if (isErr(payloadResult)) {\n return payloadResult;\n }\n\n const payload = payloadResult.data;\n\n const ajv = new Ajv({\n unicodeRegExp: false,\n });\n addFormats(ajv);\n\n if (ajv.validate<WebhooksSchemaDefinition>(webhookSchema, payload)) {\n return { data: payload };\n }\n\n try {\n return { error: getParseError(payload, ajv.errorsText()) };\n } catch (_e) {\n return {\n error: new PlainWebhookPayloadError(\n `Failed to parse the webhook payload: ${ajv.errorsText()}`,\n ),\n };\n }\n}\n\nfunction getParseError(\n payload: Record<string, unknown>,\n originalAjvError: string,\n): PlainWebhookError {\n const errorMessage = getErrorMessageForHumans(payload, originalAjvError);\n\n if (isVersionMismatch(payload)) {\n return new PlainWebhookVersionMismatchError(\n errorMessage,\n getPayloadVersion(payload) ?? \"unknown\",\n );\n }\n\n return new PlainWebhookPayloadError(errorMessage);\n}\n\nfunction isVersionMismatch(payload: Record<string, unknown>): boolean {\n const schemaVersion = getSchemaVersion();\n return typeof schemaVersion === \"string\" && schemaVersion !== getPayloadVersion(payload);\n}\n\nfunction getErrorMessageForHumans(\n payload: Record<string, unknown>,\n originalAjvError: string,\n): string {\n try {\n const eventType = payload.type;\n if (typeof eventType !== \"string\") {\n return originalAjvError;\n }\n\n const payloadDefinitionKey = (() => {\n for (const [key, definition] of Object.entries(\n (webhookSchema as Record<string, any>).definitions,\n )) {\n if ((definition as any)?.properties?.eventType?.const === eventType) {\n return key;\n }\n }\n return null;\n })();\n\n if (payloadDefinitionKey === null) {\n return originalAjvError;\n }\n\n const updatedSchema = {\n ...webhookSchema,\n properties: {\n ...(webhookSchema as Record<string, any>).properties,\n payload: {\n $ref: `#/definitions/${payloadDefinitionKey}`,\n },\n },\n };\n\n const ajv = new Ajv({\n unicodeRegExp: false,\n });\n addFormats(ajv);\n\n if (ajv.validate(updatedSchema, payload)) {\n return originalAjvError;\n }\n\n return ajv.errorsText();\n } catch (_e) {\n return originalAjvError;\n }\n}\n\nfunction getPayloadVersion(payload: Record<string, unknown>): string | null {\n const metadata = (payload as any)?.webhookMetadata;\n const ret = metadata?.webhookTargetVersion;\n return typeof ret === \"string\" ? ret : null;\n}\n\nfunction getSchemaVersion(): string | null {\n const ret = (webhookSchema as any)?.definitions?.webhookMetadata?.properties?.webhookTargetVersion\n ?.const;\n return typeof ret === \"string\" ? ret : null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoB;AACpB,yBAAwB;AAKxB,oBAIO;AACP,oBAAmC;AAEnC,4BAA0B;AAT1B,MAAM,aAAa,mBAAAA;AAWZ,SAAS,kBACd,gBAC4D;AAC5D,QAAM,iBAAiB,MAAM;AAC3B,QAAI,OAAO,mBAAmB,UAAU;AACtC,UAAI;AACF,eAAO,EAAE,MAAM,KAAK,MAAM,cAAc,EAAE;AAAA,MAC5C,SAAS,IAAI;AACX,eAAO;AAAA,UACL,OAAO,IAAI,uCAAyB,iDAAiD;AAAA,QACvF;AAAA,MACF;AAAA,IACF;AAEA,WAAO,EAAE,MAAM,eAAe;AAAA,EAChC,GAAG;AAEH,UAAI,qBAAM,aAAa,GAAG;AACxB,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,cAAc;AAE9B,QAAM,MAAM,IAAI,eAAI;AAAA,IAClB,eAAe;AAAA,EACjB,CAAC;AACD,aAAW,GAAG;AAEd,MAAI,IAAI,SAAmC,sBAAAC,SAAe,OAAO,GAAG;AAClE,WAAO,EAAE,MAAM,QAAQ;AAAA,EACzB;AAEA,MAAI;AACF,WAAO,EAAE,OAAO,cAAc,SAAS,IAAI,WAAW,CAAC,EAAE;AAAA,EAC3D,SAAS,IAAI;AACX,WAAO;AAAA,MACL,OAAO,IAAI;AAAA,QACT,wCAAwC,IAAI,WAAW,CAAC;AAAA,MAC1D;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,cACP,SACA,kBACmB;AACnB,QAAM,eAAe,yBAAyB,SAAS,gBAAgB;AAEvE,MAAI,kBAAkB,OAAO,GAAG;AAC9B,WAAO,IAAI;AAAA,MACT;AAAA,MACA,kBAAkB,OAAO,KAAK;AAAA,IAChC;AAAA,EACF;AAEA,SAAO,IAAI,uCAAyB,YAAY;AAClD;AAEA,SAAS,kBAAkB,SAA2C;AACpE,QAAM,gBAAgB,iBAAiB;AACvC,SAAO,OAAO,kBAAkB,YAAY,kBAAkB,kBAAkB,OAAO;AACzF;AAEA,SAAS,yBACP,SACA,kBACQ;AACR,MAAI;AACF,UAAM,YAAY,QAAQ;AAC1B,QAAI,OAAO,cAAc,UAAU;AACjC,aAAO;AAAA,IACT;AAEA,UAAM,wBAAwB,MAAM;AAClC,iBAAW,CAAC,KAAK,UAAU,KAAK,OAAO;AAAA,QACpC,sBAAAA,QAAsC;AAAA,MACzC,GAAG;AACD,YAAK,YAAoB,YAAY,WAAW,UAAU,WAAW;AACnE,iBAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO;AAAA,IACT,GAAG;AAEH,QAAI,yBAAyB,MAAM;AACjC,aAAO;AAAA,IACT;AAEA,UAAM,gBAAgB;AAAA,MACpB,GAAG,sBAAAA;AAAA,MACH,YAAY;AAAA,QACV,GAAI,sBAAAA,QAAsC;AAAA,QAC1C,SAAS;AAAA,UACP,MAAM,iBAAiB,oBAAoB;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM,IAAI,eAAI;AAAA,MAClB,eAAe;AAAA,IACjB,CAAC;AACD,eAAW,GAAG;AAEd,QAAI,IAAI,SAAS,eAAe,OAAO,GAAG;AACxC,aAAO;AAAA,IACT;AAEA,WAAO,IAAI,WAAW;AAAA,EACxB,SAAS,IAAI;AACX,WAAO;AAAA,EACT;AACF;AAEA,SAAS,kBAAkB,SAAiD;AAC1E,QAAM,WAAY,SAAiB;AACnC,QAAM,MAAM,UAAU;AACtB,SAAO,OAAO,QAAQ,WAAW,MAAM;AACzC;AAEA,SAAS,mBAAkC;AACzC,QAAM,MAAO,sBAAAA,SAAuB,aAAa,iBAAiB,YAAY,sBAC1E;AACJ,SAAO,OAAO,QAAQ,WAAW,MAAM;AACzC;","names":["_addFormats","webhookSchema"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var result_exports = {};
|
|
20
|
+
__export(result_exports, {
|
|
21
|
+
isErr: () => isErr
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(result_exports);
|
|
24
|
+
const isErr = (result) => {
|
|
25
|
+
return !!result.error;
|
|
26
|
+
};
|
|
27
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
28
|
+
0 && (module.exports = {
|
|
29
|
+
isErr
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/result.ts"],"sourcesContent":["type Data<T> = {\n data: T;\n error?: never;\n};\n\ntype Err<U> = {\n data?: never;\n error: U;\n};\n\nexport type Result<T, U> = NonNullable<Data<T> | Err<U>>;\n\nexport const isErr = <T, U>(result: Result<T, U>): result is Err<U> => {\n return !!result.error;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAYO,MAAM,QAAQ,CAAO,WAA2C;AACrE,SAAO,CAAC,CAAC,OAAO;AAClB;","names":[]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var verify_exports = {};
|
|
30
|
+
__export(verify_exports, {
|
|
31
|
+
verifyPlainWebhook: () => verifyPlainWebhook
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(verify_exports);
|
|
34
|
+
var crypto = __toESM(require("node:crypto"), 1);
|
|
35
|
+
var import_errors = require("./errors.js");
|
|
36
|
+
var import_parse = require("./parse.js");
|
|
37
|
+
var import_result = require("./result.js");
|
|
38
|
+
function verifyPlainWebhook(payloadRaw, signature, secret, tolerance = 300) {
|
|
39
|
+
const signatureVerificationResult = verifyWebhookSignature(payloadRaw, signature, secret);
|
|
40
|
+
if ((0, import_result.isErr)(signatureVerificationResult)) {
|
|
41
|
+
return signatureVerificationResult;
|
|
42
|
+
}
|
|
43
|
+
const payloadResult = (0, import_parse.parsePlainWebhook)(payloadRaw);
|
|
44
|
+
if ((0, import_result.isErr)(payloadResult)) {
|
|
45
|
+
return payloadResult;
|
|
46
|
+
}
|
|
47
|
+
const payload = payloadResult.data;
|
|
48
|
+
const timestamp = Date.parse(payload.webhookMetadata.webhookDeliveryAttemptTimestamp);
|
|
49
|
+
if (Number.isNaN(timestamp)) {
|
|
50
|
+
return {
|
|
51
|
+
error: new import_errors.PlainWebhookPayloadError(
|
|
52
|
+
`Invalid timestamp provided in the webhook payload: ${timestamp}. This is likely a bug in the Plain API (eventId: ${payload.id}).`
|
|
53
|
+
)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const currentTime = Date.now();
|
|
57
|
+
if (Math.abs(currentTime - timestamp) > tolerance * 1e3) {
|
|
58
|
+
return {
|
|
59
|
+
error: new import_errors.PlainWebhookSignatureVerificationError(
|
|
60
|
+
`The timestamp provided in the webhook payload is too far in the past. The maximum allowed difference is ${tolerance} seconds.`
|
|
61
|
+
)
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return { data: payload };
|
|
65
|
+
}
|
|
66
|
+
function verifyWebhookSignature(payload, signature, secret) {
|
|
67
|
+
if (payload.length === 0) {
|
|
68
|
+
return {
|
|
69
|
+
error: new import_errors.PlainWebhookSignatureVerificationError("No webhook payload was provided.")
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (signature.length === 0) {
|
|
73
|
+
return {
|
|
74
|
+
error: new import_errors.PlainWebhookSignatureVerificationError(
|
|
75
|
+
'No signature header value was provided. Please pass the value of the "Plain-Request-Signature" header.'
|
|
76
|
+
)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (secret.length === 0) {
|
|
80
|
+
return {
|
|
81
|
+
error: new import_errors.PlainWebhookSignatureVerificationError(
|
|
82
|
+
"No webhook secret was provided. You can find your webhook secret in your workspace settings."
|
|
83
|
+
)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const expectedSignature = crypto.createHmac("sha256", secret).update(payload, "utf8").digest("hex");
|
|
87
|
+
if (signature !== expectedSignature) {
|
|
88
|
+
return {
|
|
89
|
+
error: new import_errors.PlainWebhookSignatureVerificationError("The signature provided is invalid.")
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return { data: true };
|
|
93
|
+
}
|
|
94
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
95
|
+
0 && (module.exports = {
|
|
96
|
+
verifyPlainWebhook
|
|
97
|
+
});
|
|
98
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/verify.ts"],"sourcesContent":["import * as crypto from \"node:crypto\";\nimport {\n type PlainWebhookError,\n PlainWebhookPayloadError,\n PlainWebhookSignatureVerificationError,\n} from \"./errors.js\";\nimport { parsePlainWebhook } from \"./parse.js\";\nimport { isErr, type Result } from \"./result.js\";\nimport type { WebhooksSchemaDefinition } from \"./webhook-schema.js\";\n\n/**\n * Verifies and validates a Plain webhook payload.\n *\n * @param payload - The raw request body.\n * @param signature - The value of the 'Plain-Request-Signature' header.\n * @param secret - Your Plain webhook signing secret.\n * @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.\n * @returns A Result object containing the validated payload or an error.\n */\nexport function verifyPlainWebhook(\n payloadRaw: string,\n signature: string,\n secret: string,\n tolerance = 300, // 5 minutes\n): Result<WebhooksSchemaDefinition, PlainWebhookError> {\n const signatureVerificationResult = verifyWebhookSignature(payloadRaw, signature, secret);\n if (isErr(signatureVerificationResult)) {\n return signatureVerificationResult;\n }\n\n const payloadResult = parsePlainWebhook(payloadRaw);\n if (isErr(payloadResult)) {\n return payloadResult;\n }\n\n const payload = payloadResult.data;\n const timestamp = Date.parse(payload.webhookMetadata.webhookDeliveryAttemptTimestamp);\n\n if (Number.isNaN(timestamp)) {\n return {\n error: new PlainWebhookPayloadError(\n `Invalid timestamp provided in the webhook payload: ${timestamp}. This is likely a bug in the Plain API (eventId: ${payload.id}).`,\n ),\n };\n }\n\n const currentTime = Date.now();\n if (Math.abs(currentTime - timestamp) > tolerance * 1000) {\n return {\n error: new PlainWebhookSignatureVerificationError(\n `The timestamp provided in the webhook payload is too far in the past. The maximum allowed difference is ${tolerance} seconds.`,\n ),\n };\n }\n\n return { data: payload };\n}\n\nfunction verifyWebhookSignature(\n payload: string,\n signature: string,\n secret: string,\n): Result<true, PlainWebhookSignatureVerificationError> {\n if (payload.length === 0) {\n return {\n error: new PlainWebhookSignatureVerificationError(\"No webhook payload was provided.\"),\n };\n }\n\n if (signature.length === 0) {\n return {\n error: new PlainWebhookSignatureVerificationError(\n 'No signature header value was provided. Please pass the value of the \"Plain-Request-Signature\" header.',\n ),\n };\n }\n\n if (secret.length === 0) {\n return {\n error: new PlainWebhookSignatureVerificationError(\n \"No webhook secret was provided. You can find your webhook secret in your workspace settings.\",\n ),\n };\n }\n\n const expectedSignature = crypto\n .createHmac(\"sha256\", secret)\n .update(payload, \"utf8\")\n .digest(\"hex\");\n\n if (signature !== expectedSignature) {\n return {\n error: new PlainWebhookSignatureVerificationError(\"The signature provided is invalid.\"),\n };\n }\n\n return { data: true };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAAwB;AACxB,oBAIO;AACP,mBAAkC;AAClC,oBAAmC;AAY5B,SAAS,mBACd,YACA,WACA,QACA,YAAY,KACyC;AACrD,QAAM,8BAA8B,uBAAuB,YAAY,WAAW,MAAM;AACxF,UAAI,qBAAM,2BAA2B,GAAG;AACtC,WAAO;AAAA,EACT;AAEA,QAAM,oBAAgB,gCAAkB,UAAU;AAClD,UAAI,qBAAM,aAAa,GAAG;AACxB,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,cAAc;AAC9B,QAAM,YAAY,KAAK,MAAM,QAAQ,gBAAgB,+BAA+B;AAEpF,MAAI,OAAO,MAAM,SAAS,GAAG;AAC3B,WAAO;AAAA,MACL,OAAO,IAAI;AAAA,QACT,sDAAsD,SAAS,qDAAqD,QAAQ,EAAE;AAAA,MAChI;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAc,KAAK,IAAI;AAC7B,MAAI,KAAK,IAAI,cAAc,SAAS,IAAI,YAAY,KAAM;AACxD,WAAO;AAAA,MACL,OAAO,IAAI;AAAA,QACT,2GAA2G,SAAS;AAAA,MACtH;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,QAAQ;AACzB;AAEA,SAAS,uBACP,SACA,WACA,QACsD;AACtD,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO;AAAA,MACL,OAAO,IAAI,qDAAuC,kCAAkC;AAAA,IACtF;AAAA,EACF;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO;AAAA,MACL,OAAO,IAAI;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,MACL,OAAO,IAAI;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,oBAAoB,OACvB,WAAW,UAAU,MAAM,EAC3B,OAAO,SAAS,MAAM,EACtB,OAAO,KAAK;AAEf,MAAI,cAAc,mBAAmB;AACnC,WAAO;AAAA,MACL,OAAO,IAAI,qDAAuC,oCAAoC;AAAA,IACxF;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,KAAK;AACtB;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
var webhook_schema_exports = {};
|
|
16
|
+
module.exports = __toCommonJS(webhook_schema_exports);
|
|
17
|
+
//# sourceMappingURL=webhook-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/webhook-schema.ts"],"sourcesContent":["/* eslint-disable */\n/**\n * This file was automatically generated by json-schema-to-typescript.\n * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,\n * and run json-schema-to-typescript to regenerate this file.\n */\n\nexport type Datetime = string;\nexport type Id = string;\nexport type EmailAddress = string;\nexport type InternalActor =\n | {\n actorType: \"UNKNOWN\";\n [k: string]: unknown;\n }\n | UserActor\n | MachineUserActor\n | SystemActor;\nexport type Actor =\n | {\n actorType: \"UNKNOWN\";\n [k: string]: unknown;\n }\n | UserActor\n | MachineUserActor\n | SystemActor\n | CustomerActor;\nexport type NullableString = string | null;\nexport type EmailActor =\n | {\n actorType: \"UNKNOWN\";\n [k: string]: unknown;\n }\n | UserActor\n | CustomerActor\n | {\n actorType: \"supportEmailAddress\";\n supportEmailAddress: string;\n [k: string]: unknown;\n }\n | {\n actorType: \"deletedCustomer\";\n customerId: Id;\n [k: string]: unknown;\n };\nexport type EmailAuthenticity = \"PASS\" | \"FAIL\" | \"UNKNOWN\" | \"UNKNOWN_EMAIL_AUTHENTICITY\";\nexport type Component =\n | {\n type: \"UNKNOWN\";\n [k: string]: unknown;\n }\n | ComponentText\n | ComponentPlainText\n | ComponentSpacer\n | ComponentDivider\n | ComponentLinkButton\n | ComponentWorkflowButton\n | ComponentBadge\n | ComponentCopyButton\n | ComponentRow\n | ComponentContainer;\nexport type ComponentTextSize = \"S\" | \"M\" | \"L\" | \"UNKNOWN_COMPONENT_TEXT_SIZE\";\nexport type ComponentTextColor =\n | \"NORMAL\"\n | \"MUTED\"\n | \"SUCCESS\"\n | \"WARNING\"\n | \"ERROR\"\n | \"UNKNOWN_COMPONENT_TEXT_COLOR\";\nexport type ComponentPlainTextSize = \"S\" | \"M\" | \"L\" | \"UNKNOWN_COMPONENT_PLAIN_TEXT_SIZE\";\nexport type ComponentPlainTextColor =\n | \"NORMAL\"\n | \"MUTED\"\n | \"SUCCESS\"\n | \"WARNING\"\n | \"ERROR\"\n | \"UNKNOWN_COMPONENT_PLAIN_TEXT_COLOR\";\nexport type ComponentSpacerSize = \"XS\" | \"S\" | \"M\" | \"L\" | \"XL\" | \"UNKNOWN_COMPONENT_SPACER_SIZE\";\nexport type ComponentDividerSpacingSize =\n | \"XS\"\n | \"S\"\n | \"M\"\n | \"L\"\n | \"XL\"\n | \"UNKNOWN_COMPONENT_DIVIDER_SPACING_SIZE\";\nexport type ComponentBadgeColor =\n | \"GREY\"\n | \"GREEN\"\n | \"YELLOW\"\n | \"RED\"\n | \"BLUE\"\n | \"UNKNOWN_COMPONENT_BADGE_COLOR\";\nexport type ComponentRowContent =\n | {\n type: \"UNKNOWN\";\n [k: string]: unknown;\n }\n | ComponentText\n | ComponentPlainText\n | ComponentSpacer\n | ComponentDivider\n | ComponentLinkButton\n | ComponentWorkflowButton\n | ComponentBadge\n | ComponentCopyButton;\nexport type ComponentContainerContent =\n | {\n type: \"UNKNOWN\";\n [k: string]: unknown;\n }\n | ComponentText\n | ComponentPlainText\n | ComponentSpacer\n | ComponentDivider\n | ComponentLinkButton\n | ComponentWorkflowButton\n | ComponentBadge\n | ComponentCopyButton\n | ComponentRow;\nexport type CustomerGroupChangedPayload =\n | {\n changeType: \"ADDED\";\n eventType: \"customer.customer_group_changed\";\n customerGroup: CustomerGroup;\n [k: string]: unknown;\n }\n | {\n changeType: \"UPDATED\";\n eventType: \"customer.customer_group_changed\";\n customerGroup: CustomerGroup;\n previousCustomerGroup: CustomerGroup;\n [k: string]: unknown;\n }\n | {\n changeType: \"REMOVED\";\n eventType: \"customer.customer_group_changed\";\n previousCustomerGroup: CustomerGroup;\n [k: string]: unknown;\n };\nexport type ThreadPriority = number;\nexport type ThreadStatus = \"TODO\" | \"DONE\" | \"SNOOZED\" | \"UNKNOWN_THREAD_STATUS\";\nexport type ThreadStatusDetail =\n | {\n type: \"UNKNOWN\";\n [k: string]: unknown;\n }\n | {\n type: \"CREATED\";\n createdAt: Datetime;\n [k: string]: unknown;\n }\n | {\n type: \"NEW_REPLY\";\n [k: string]: unknown;\n }\n | {\n type: \"IN_PROGRESS\";\n [k: string]: unknown;\n }\n | {\n type: \"WAITING_FOR_CUSTOMER\";\n [k: string]: unknown;\n }\n | {\n type: \"WAITING_FOR_DURATION\";\n waitingUntil: Datetime;\n durationSeconds: number;\n [k: string]: unknown;\n }\n | {\n type: \"THREAD_LINK_UPDATED\";\n linear?: {\n issueId: string;\n [k: string]: unknown;\n };\n [k: string]: unknown;\n }\n | {\n type: \"DONE_MANUALLY_SET\";\n [k: string]: unknown;\n }\n | {\n type: \"IGNORED\";\n [k: string]: unknown;\n }\n | {\n type: \"DONE_AUTOMATICALLY_SET\";\n afterSeconds?: number;\n [k: string]: unknown;\n }\n | {\n type: \"THREAD_DISCUSSION_RESOLVED\";\n threadDiscussionId?: Id;\n [k: string]: unknown;\n };\nexport type ThreadAssignee =\n | {\n type: \"UNKNOWN\";\n [k: string]: unknown;\n }\n | User\n | MachineUser\n | {\n id: string;\n [k: string]: unknown;\n };\nexport type NullableDatetime = Datetime | null;\nexport type NullableInternalActor = InternalActor | null;\nexport type ServiceLevelAgreement =\n | {\n type: \"UNKNOWN\";\n [k: string]: unknown;\n }\n | {\n id: Id;\n tier: Tier;\n useBusinessHoursOnly: boolean;\n threadPriorityFilter: ThreadPriorityFilter;\n createdAt: Datetime;\n createdBy: InternalActor;\n updatedAt: Datetime;\n updatedBy: InternalActor;\n type: \"FIRST_RESPONSE_TIME\";\n firstResponseTimeMinutes: number;\n [k: string]: unknown;\n }\n | {\n id: Id;\n tier: Tier;\n useBusinessHoursOnly: boolean;\n threadPriorityFilter: ThreadPriorityFilter;\n createdAt: Datetime;\n createdBy: InternalActor;\n updatedAt: Datetime;\n updatedBy: InternalActor;\n type: \"NEXT_RESPONSE_TIME\";\n nextResponseTimeMinutes: number;\n [k: string]: unknown;\n };\n/**\n * @minItems 1\n */\nexport type ThreadPriorityFilter = [ThreadPriority, ...ThreadPriority[]];\nexport type ServiceLevelAgreementStatusDetail =\n | {\n status: \"UNKNOWN\";\n [k: string]: unknown;\n }\n | {\n breachTime: Datetime;\n status: \"PENDING\";\n [k: string]: unknown;\n }\n | {\n achievedAt: Datetime;\n status: \"ACHIEVED\";\n [k: string]: unknown;\n }\n | {\n breachTime: Datetime;\n status: \"IMMINENT_BREACH\";\n [k: string]: unknown;\n }\n | {\n breachedAt: Datetime;\n status: \"BREACHING\";\n [k: string]: unknown;\n }\n | {\n breachedAt: Datetime;\n completedAt: Datetime;\n status: \"BREACHED\";\n [k: string]: unknown;\n }\n | {\n cancelledAt: Datetime;\n status: \"CANCELLED\";\n [k: string]: unknown;\n };\n\n/**\n * Webhook request\n */\nexport interface WebhooksSchemaDefinition {\n timestamp: Datetime;\n workspaceId: Id;\n payload:\n | CustomerChangedPayload\n | CustomerGroupMembershipsChangedPayload\n | TimelineEntryChangedPayload\n | CustomerGroupChangedPayload\n | ThreadCreatedPublicEventPayload\n | ThreadStatusTransitionedPublicEventPayload\n | ThreadAssignmentTransitionedPublicEventPayload\n | ThreadEmailReceivedPublicEventPayload\n | ThreadEmailSentPublicEventPayload\n | ThreadSlackMessageReceivedEventPayload\n | ThreadSlackMessageSentEventPayload\n | ThreadMSTeamsMessageReceivedEventPayload\n | ThreadMSTeamsMessageSentEventPayload\n | ThreadLabelsChangedPublicEventPayload\n | ThreadPriorityChangedPublicEventPayload\n | ThreadFieldCreatedPublicEventPayload\n | ThreadFieldUpdatedPublicEventPayload\n | ThreadFieldDeletedPublicEventPayload\n | ThreadChatSentPublicEventPayload\n | ThreadServiceLevelAgreementStatusTransitionedPayload\n | CustomerCreatedPublicEventPayload\n | CustomerUpdatedPublicEventPayload\n | CustomerDeletedPublicEventPayload\n | ThreadNoteCreatedEventPayload\n | ThreadChatReceivedPublicEventPayload\n | ThreadSlackMessageUpdatedEventPayload\n | ThreadDiscordMessageReceivedEventPayload\n | ThreadDiscordMessageSentEventPayload\n | ThreadDiscordMessageUpdatedEventPayload;\n id: Id;\n type:\n | \"thread.thread_created\"\n | \"thread.thread_status_transitioned\"\n | \"thread.thread_assignment_transitioned\"\n | \"thread.email_received\"\n | \"thread.email_sent\"\n | \"thread.slack_message_received\"\n | \"thread.slack_message_sent\"\n | \"thread.slack_message_updated\"\n | \"thread.discord_message_received\"\n | \"thread.discord_message_sent\"\n | \"thread.discord_message_updated\"\n | \"thread.ms_teams_message_sent\"\n | \"thread.ms_teams_message_received\"\n | \"thread.chat_sent\"\n | \"thread.chat_received\"\n | \"thread.note_created\"\n | \"thread.thread_labels_changed\"\n | \"thread.thread_priority_changed\"\n | \"thread.thread_field_created\"\n | \"thread.thread_field_updated\"\n | \"thread.thread_field_deleted\"\n | \"thread.service_level_agreement_status_transitioned\"\n | \"thread.thread_tenant_updated\"\n | \"customer.customer_created\"\n | \"customer.customer_updated\"\n | \"customer.customer_deleted\"\n | \"customer.customer_changed\"\n | \"customer.customer_group_changed\"\n | \"customer.customer_group_memberships_changed\"\n | \"timeline.timeline_entry_changed\";\n webhookMetadata: WebhookMetadata;\n [k: string]: unknown;\n}\n/**\n * A customer has been created or updated\n */\nexport interface CustomerChangedPayload {\n changeType: \"ADDED\" | \"UPDATED\";\n eventType: \"customer.customer_changed\";\n customer: Customer;\n previousCustomer: Customer | null;\n [k: string]: unknown;\n}\nexport interface Customer {\n id: Id;\n email: {\n email: EmailAddress;\n isVerified: boolean;\n verifiedAt: Datetime | null;\n [k: string]: unknown;\n };\n externalId: string | null;\n fullName: string;\n shortName: string | null;\n markedAsSpamAt?: Datetime | null;\n markedAsSpamBy?: InternalActor | null;\n customerGroupMemberships: CustomerGroupMembership[];\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n [k: string]: unknown;\n}\nexport interface UserActor {\n actorType: \"user\";\n userId: Id;\n [k: string]: unknown;\n}\nexport interface MachineUserActor {\n actorType: \"machineUser\";\n machineUserId: Id;\n [k: string]: unknown;\n}\nexport interface SystemActor {\n actorType: \"system\";\n system: string;\n [k: string]: unknown;\n}\nexport interface CustomerGroupMembership {\n customerId: Id;\n customerGroupId: Id;\n workspaceId: Id;\n createdAt: Datetime;\n createdBy: InternalActor;\n updatedAt: Datetime;\n updatedBy: InternalActor;\n customerGroup: CustomerGroup;\n [k: string]: unknown;\n}\nexport interface CustomerGroup {\n id: Id;\n workspaceId: Id;\n name: string;\n key: string;\n color: string;\n createdAt: Datetime;\n createdBy: InternalActor;\n updatedAt: Datetime;\n updatedBy: InternalActor;\n [k: string]: unknown;\n}\nexport interface CustomerActor {\n actorType: \"customer\";\n customerId: Id;\n [k: string]: unknown;\n}\nexport interface CustomerGroupMembershipsChangedPayload {\n eventType: \"customer.customer_group_memberships_changed\";\n changeType: \"ADDED\" | \"REMOVED\";\n customer: Customer;\n previousCustomer: Customer;\n [k: string]: unknown;\n}\n/**\n * A timeline entry has been added, updated or removed\n */\nexport interface TimelineEntryChangedPayload {\n eventType: \"timeline.timeline_entry_changed\";\n /**\n * null if changeType=ADDED\n */\n previousTimelineEntry: TimelineEntry | null;\n /**\n * null if changeType=REMOVED\n */\n timelineEntry: TimelineEntry | null;\n changeType: \"ADDED\" | \"UPDATED\" | \"REMOVED\";\n [k: string]: unknown;\n}\nexport interface TimelineEntry {\n id: Id;\n customerId: Id;\n threadId?: Id | null;\n timestamp: Datetime;\n actor: Actor;\n entry:\n | {\n entryType: \"UNKNOWN\";\n [k: string]: unknown;\n }\n | NoteEntry\n | ChatEntry\n | EmailEntry\n | CustomEntry;\n [k: string]: unknown;\n}\nexport interface NoteEntry {\n entryType: \"note\";\n noteId: Id;\n text: string;\n markdown: string | null;\n [k: string]: unknown;\n}\nexport interface ChatEntry {\n entryType: \"chat\";\n chatId: Id;\n text: string | null;\n attachments: ChatEntryAttachment[];\n customerReadAt: Datetime | null;\n [k: string]: unknown;\n}\nexport interface ChatEntryAttachment {\n id: Id;\n fileName: string;\n fileSizeBytes: number;\n fileMimeType: string;\n fileExtension: NullableString;\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n type: \"CHAT\";\n [k: string]: unknown;\n}\nexport interface EmailEntry {\n entryType: \"email\";\n emailId: Id;\n to: EmailParticipant;\n from: EmailParticipant;\n additionalRecipients: EmailParticipant[];\n hiddenRecipients: EmailParticipant[];\n subject: string | null;\n textContent: string | null;\n hasMoreTextContent: boolean;\n markdownContent: string | null;\n hasMoreMarkdownContent: boolean;\n authenticity: EmailAuthenticity;\n sentAt: Datetime | null;\n receivedAt: Datetime | null;\n attachments: EmailEntryAttachment[];\n inReplyToEmailId: string | null;\n isStartOfThread: boolean;\n [k: string]: unknown;\n}\nexport interface EmailParticipant {\n email: string;\n name: string | null;\n emailActor: EmailActor | null;\n [k: string]: unknown;\n}\nexport interface EmailEntryAttachment {\n id: Id;\n fileName: string;\n fileSizeBytes: number;\n fileMimeType: string;\n fileExtension: NullableString;\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n type: \"EMAIL\";\n emailContentId: string;\n [k: string]: unknown;\n}\nexport interface CustomEntry {\n entryType: \"custom\";\n externalId: string | null;\n title: string;\n type: string | null;\n components: Component[];\n attachments: CustomEntryAttachment[];\n [k: string]: unknown;\n}\nexport interface ComponentText {\n type: \"text\";\n textSize: ComponentTextSize | null;\n textColor: ComponentTextColor | null;\n text: string;\n [k: string]: unknown;\n}\nexport interface ComponentPlainText {\n plainTextSize: ComponentPlainTextSize | null;\n plainTextColor: ComponentPlainTextColor | null;\n plainText: string;\n type: \"plainText\";\n [k: string]: unknown;\n}\nexport interface ComponentSpacer {\n spacerSize: ComponentSpacerSize;\n type: \"spacer\";\n [k: string]: unknown;\n}\nexport interface ComponentDivider {\n dividerSpacingSize: ComponentDividerSpacingSize | null;\n type: \"divider\";\n [k: string]: unknown;\n}\nexport interface ComponentLinkButton {\n linkButtonUrl: string;\n linkButtonLabel: string;\n type: \"linkButton\";\n [k: string]: unknown;\n}\nexport interface ComponentWorkflowButton {\n workflowButtonWorkflowIdentifier: {\n workflowId?: string;\n workflowKey?: string;\n [k: string]: unknown;\n };\n workflowButtonLabel: string;\n type: \"workflowButton\";\n [k: string]: unknown;\n}\nexport interface ComponentBadge {\n badgeLabel: string;\n badgeColor: ComponentBadgeColor | null;\n type: \"badge\";\n [k: string]: unknown;\n}\nexport interface ComponentCopyButton {\n copyButtonValue: string;\n copyButtonTooltipLabel: string | null;\n type: \"copyButton\";\n [k: string]: unknown;\n}\nexport interface ComponentRow {\n type: \"row\";\n rowMainContent: ComponentRowContent[];\n rowAsideContent: ComponentRowContent[];\n [k: string]: unknown;\n}\nexport interface ComponentContainer {\n type: \"container\";\n containerContent: ComponentContainerContent[];\n [k: string]: unknown;\n}\nexport interface CustomEntryAttachment {\n id: Id;\n fileName: string;\n fileSizeBytes: number;\n fileMimeType: string;\n fileExtension: NullableString;\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n type: \"CUSTOM_TIMELINE_ENTRY\";\n [k: string]: unknown;\n}\nexport interface ThreadCreatedPublicEventPayload {\n eventType: \"thread.thread_created\";\n thread: Thread;\n [k: string]: unknown;\n}\nexport interface Thread {\n id: Id;\n customer: Customer;\n title: string;\n previewText?: string | null;\n priority: ThreadPriority;\n externalId: string | null;\n status: ThreadStatus;\n statusChangedAt: Datetime;\n statusChangedBy?: Actor | null;\n statusDetail: ThreadStatusDetail | null;\n assignee: ThreadAssignee | null;\n assignedAt: Datetime | null;\n additionalAssignees?: ThreadAssignee[];\n labels: Label[];\n firstInboundMessageInfo: ThreadMessageInfo | null;\n firstOutboundMessageInfo: ThreadMessageInfo | null;\n lastInboundMessageInfo: ThreadMessageInfo | null;\n lastOutboundMessageInfo: ThreadMessageInfo | null;\n supportEmailAddresses: string[];\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n [k: string]: unknown;\n}\nexport interface User {\n id: Id;\n email: EmailAddress;\n fullName: string;\n publicName: string;\n status: \"ONLINE\" | \"OFFLINE\" | \"BREAK\" | \"AWAY\" | \"UNKNOWN_USER_STATUS\";\n statusChangedAt: Datetime;\n createdAt: Datetime;\n createdBy: InternalActor;\n updatedAt: Datetime;\n updatedBy: InternalActor;\n deletedAt: NullableDatetime;\n deletedBy: NullableInternalActor;\n [k: string]: unknown;\n}\nexport interface MachineUser {\n id: Id;\n fullName: string;\n publicName: string;\n description: string | null;\n createdAt: Datetime;\n createdBy: InternalActor;\n updatedAt: Datetime;\n updatedBy: InternalActor;\n deletedAt: NullableDatetime;\n deletedBy: NullableInternalActor;\n [k: string]: unknown;\n}\nexport interface Label {\n id: Id;\n labelType: LabelType;\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n [k: string]: unknown;\n}\nexport interface LabelType {\n id: Id;\n name: string;\n icon?: string | null;\n isArchived?: boolean;\n archivedAt: Datetime | null;\n archivedBy: InternalActor | null;\n externalId?: string | null;\n isExcludedFromAi?: boolean;\n createdAt: Datetime;\n createdBy: InternalActor;\n updatedAt: Datetime;\n updatedBy: InternalActor;\n [k: string]: unknown;\n}\nexport interface ThreadMessageInfo {\n timestamp: Datetime;\n messageSource:\n | \"CHAT\"\n | \"EMAIL\"\n | \"API\"\n | \"SLACK\"\n | \"MS_TEAMS\"\n | \"UNKNOWN_THREAD_MESSAGE_INFO_MESSAGE_SOURCE\";\n actorId?: string | null;\n actorType?: (\"user\" | \"machineUser\" | \"customer\" | \"system\") | null;\n [k: string]: unknown;\n}\nexport interface ThreadStatusTransitionedPublicEventPayload {\n eventType: \"thread.thread_status_transitioned\";\n previousThread: Thread;\n thread: Thread;\n [k: string]: unknown;\n}\nexport interface ThreadAssignmentTransitionedPublicEventPayload {\n eventType: \"thread.thread_assignment_transitioned\";\n previousThread: Thread;\n thread: Thread;\n [k: string]: unknown;\n}\nexport interface ThreadEmailReceivedPublicEventPayload {\n eventType: \"thread.email_received\";\n thread: Thread;\n email: Email;\n [k: string]: unknown;\n}\nexport interface Email {\n timelineEntryId: Id;\n id: Id;\n to: EmailParticipant;\n from: EmailParticipant;\n replyTo: string | null;\n additionalRecipients: EmailParticipant[];\n hiddenRecipients: EmailParticipant[];\n subject: string | null;\n textContent: string | null;\n markdownContent: string | null;\n authenticity: EmailAuthenticity;\n sentAt: Datetime | null;\n receivedAt: Datetime | null;\n attachments: Attachment[];\n inReplyToEmailId: string | null;\n isStartOfThread: boolean;\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n [k: string]: unknown;\n}\nexport interface Attachment {\n id: Id;\n fileName: string;\n fileSizeBytes: number;\n fileMimeType: string;\n fileExtension: NullableString;\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n [k: string]: unknown;\n}\nexport interface ThreadEmailSentPublicEventPayload {\n eventType: \"thread.email_sent\";\n thread: Thread;\n email: Email;\n [k: string]: unknown;\n}\nexport interface ThreadSlackMessageReceivedEventPayload {\n eventType: \"thread.slack_message_received\";\n thread: Thread;\n slackMessage: SlackMessage;\n [k: string]: unknown;\n}\nexport interface SlackMessage {\n timelineEntryId: Id;\n id: Id;\n text: string;\n resolvedText?: string;\n attachments: Attachment[];\n slackChannelId: string;\n slackChannelName: string;\n slackMessageLink: string;\n slackReactions?: {\n name: string;\n actors: {\n actorId: Id;\n actorType: \"user\" | \"machineUser\" | \"customer\" | \"system\";\n slackUserId: string;\n [k: string]: unknown;\n }[];\n imageUrl?: string | null;\n [k: string]: unknown;\n }[];\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n [k: string]: unknown;\n}\nexport interface ThreadSlackMessageSentEventPayload {\n eventType: \"thread.slack_message_sent\";\n thread: Thread;\n slackMessage: SlackMessage;\n [k: string]: unknown;\n}\nexport interface ThreadMSTeamsMessageReceivedEventPayload {\n eventType: \"thread.ms_teams_message_received\";\n thread: Thread;\n msTeamsMessage: MsTeamsMessage;\n [k: string]: unknown;\n}\nexport interface MsTeamsMessage {\n timelineEntryId: Id;\n threadId: Id;\n msTeamsMessageId: string;\n type: (\"INBOUND\" | \"OUTBOUND\" | \"UNKNOWN_MS_TEAMS_MESSAGE_TYPE\") | null;\n text: string;\n attachments: Attachment[];\n lastEditedOnMsTeamsAt: Datetime | null;\n deletedOnMsTeamsAt: Datetime | null;\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n [k: string]: unknown;\n}\nexport interface ThreadMSTeamsMessageSentEventPayload {\n eventType: \"thread.ms_teams_message_sent\";\n thread: Thread;\n msTeamsMessage: MsTeamsMessage;\n [k: string]: unknown;\n}\nexport interface ThreadLabelsChangedPublicEventPayload {\n eventType: \"thread.thread_labels_changed\";\n changeType: \"ADDED\" | \"REMOVED\";\n thread: Thread;\n previousThread: Thread;\n [k: string]: unknown;\n}\nexport interface ThreadPriorityChangedPublicEventPayload {\n eventType: \"thread.thread_priority_changed\";\n previousThread: Thread;\n thread: Thread;\n [k: string]: unknown;\n}\nexport interface ThreadFieldCreatedPublicEventPayload {\n eventType: \"thread.thread_field_created\";\n thread: Thread;\n threadField: ThreadField;\n [k: string]: unknown;\n}\nexport interface ThreadField {\n id: Id;\n threadId: Id;\n key: string;\n type:\n | \"STRING\"\n | \"BOOL\"\n | \"ENUM\"\n | \"NUMBER\"\n | \"CURRENCY\"\n | \"DATE\"\n | \"UNKNOWN_THREAD_FIELD_SCHEMA_TYPE\";\n stringValue: string | null;\n booleanValue: boolean | null;\n numberValue?: number | null;\n dateValue?: string | null;\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n [k: string]: unknown;\n}\nexport interface ThreadFieldUpdatedPublicEventPayload {\n eventType: \"thread.thread_field_updated\";\n thread: Thread;\n previousThreadField: ThreadField;\n threadField: ThreadField;\n [k: string]: unknown;\n}\nexport interface ThreadFieldDeletedPublicEventPayload {\n eventType: \"thread.thread_field_deleted\";\n thread: Thread;\n previousThreadField: ThreadField;\n [k: string]: unknown;\n}\nexport interface ThreadChatSentPublicEventPayload {\n eventType: \"thread.chat_sent\";\n chat: Chat;\n thread: Thread;\n [k: string]: unknown;\n}\nexport interface Chat {\n timelineEntryId: Id;\n id: Id;\n customerReadAt: Datetime | null;\n text?: string | null;\n attachments: Attachment[];\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n [k: string]: unknown;\n}\nexport interface ThreadServiceLevelAgreementStatusTransitionedPayload {\n eventType: \"thread.service_level_agreement_status_transitioned\";\n thread: Thread;\n serviceLevelAgreement: ServiceLevelAgreement;\n previousServiceLevelAgreementStatusDetail: ServiceLevelAgreementStatusDetail;\n serviceLevelAgreementStatusDetail: ServiceLevelAgreementStatusDetail;\n [k: string]: unknown;\n}\nexport interface Tier {\n id: Id;\n name: string;\n externalId: string | null;\n color: string;\n defaultThreadPriority?: number;\n isDefault: boolean;\n createdAt: Datetime;\n createdBy: InternalActor;\n updatedAt: Datetime;\n updatedBy: InternalActor;\n [k: string]: unknown;\n}\n/**\n * A customer has been created\n */\nexport interface CustomerCreatedPublicEventPayload {\n eventType: \"customer.customer_created\";\n customer: Customer;\n [k: string]: unknown;\n}\n/**\n * A customer has been updated\n */\nexport interface CustomerUpdatedPublicEventPayload {\n eventType: \"customer.customer_updated\";\n customer: Customer;\n previousCustomer: Customer;\n [k: string]: unknown;\n}\n/**\n * A customer has been deleted\n */\nexport interface CustomerDeletedPublicEventPayload {\n eventType: \"customer.customer_deleted\";\n previousCustomer: Customer;\n [k: string]: unknown;\n}\nexport interface ThreadNoteCreatedEventPayload {\n eventType: \"thread.note_created\";\n thread: Thread;\n note: {\n timelineEntryId: Id;\n id: Id;\n text: string;\n markdown: string | null;\n createdAt: Datetime;\n createdBy: InternalActor;\n updatedAt: Datetime;\n updatedBy: InternalActor;\n deletedAt: NullableDatetime;\n deletedBy: NullableInternalActor;\n [k: string]: unknown;\n };\n [k: string]: unknown;\n}\nexport interface ThreadChatReceivedPublicEventPayload {\n eventType: \"thread.chat_received\";\n chat: Chat;\n thread: Thread;\n [k: string]: unknown;\n}\nexport interface ThreadSlackMessageUpdatedEventPayload {\n eventType: \"thread.slack_message_updated\";\n changeType?:\n | \"MESSAGE_EDITED\"\n | \"MESSAGE_DELETED\"\n | \"REACTIONS_CHANGED\"\n | \"UNKNOWN_SLACK_MESSAGE_CHANGE_TYPE\";\n thread: Thread;\n slackMessage: SlackMessage;\n [k: string]: unknown;\n}\nexport interface ThreadDiscordMessageReceivedEventPayload {\n eventType: \"thread.discord_message_received\";\n thread: Thread;\n discordMessage: DiscordMessage;\n [k: string]: unknown;\n}\nexport interface DiscordMessage {\n timelineEntryId: Id;\n id: Id;\n discordGuildId: string;\n discordChannelId: string;\n discordThreadId: string;\n discordId: string;\n discordTimestamp: Datetime;\n textContent: string;\n attachments?: Attachment[];\n lastEditedOnDiscordAt?: Datetime | null;\n deletedOnDiscordAt?: Datetime | null;\n createdAt: Datetime;\n createdBy: Actor;\n updatedAt: Datetime;\n updatedBy: Actor;\n [k: string]: unknown;\n}\nexport interface ThreadDiscordMessageSentEventPayload {\n eventType: \"thread.discord_message_sent\";\n thread: Thread;\n discordMessage: DiscordMessage;\n [k: string]: unknown;\n}\nexport interface ThreadDiscordMessageUpdatedEventPayload {\n eventType: \"thread.discord_message_updated\";\n thread: Thread;\n discordMessage: DiscordMessage;\n [k: string]: unknown;\n}\nexport interface WebhookMetadata {\n webhookTargetId: Id;\n webhookTargetVersion: \"2026-03-13\";\n webhookDeliveryAttemptId: Id;\n webhookDeliveryAttemptNumber: number;\n webhookDeliveryAttemptTimestamp: Datetime;\n [k: string]: unknown;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|