@emseepea/feedback 0.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.
@@ -0,0 +1,352 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { z } from "zod";
3
+ import { feedbackConversationSchema } from "./index.js";
4
+ import { beforeDeadline } from "./deadline.js";
5
+ export const postgresFeedbackSchema = `
6
+ CREATE TABLE IF NOT EXISTS emseepea_feedback_threads (
7
+ scope text NOT NULL,
8
+ id text NOT NULL,
9
+ subject text NOT NULL,
10
+ status text NOT NULL,
11
+ created_at timestamptz NOT NULL,
12
+ updated_at timestamptz NOT NULL,
13
+ PRIMARY KEY (scope, id)
14
+ );
15
+ CREATE TABLE IF NOT EXISTS emseepea_feedback_messages (
16
+ scope text NOT NULL,
17
+ thread_id text NOT NULL,
18
+ id text NOT NULL,
19
+ sequence integer NOT NULL CHECK (sequence > 0),
20
+ author text NOT NULL CHECK (author IN ('user', 'team', 'system')),
21
+ kind text NOT NULL CHECK (kind IN ('comment', 'question', 'status')),
22
+ body text NOT NULL,
23
+ created_at timestamptz NOT NULL,
24
+ offered_to_client_at timestamptz,
25
+ PRIMARY KEY (scope, id),
26
+ UNIQUE (scope, thread_id, sequence),
27
+ FOREIGN KEY (scope, thread_id) REFERENCES emseepea_feedback_threads(scope, id)
28
+ );
29
+ CREATE INDEX IF NOT EXISTS emseepea_feedback_threads_page
30
+ ON emseepea_feedback_threads(scope, updated_at DESC, id DESC);
31
+ CREATE TABLE IF NOT EXISTS emseepea_feedback_submissions (
32
+ scope text NOT NULL,
33
+ id text NOT NULL,
34
+ observation text NOT NULL,
35
+ detail text NOT NULL,
36
+ context jsonb,
37
+ recorded_at timestamptz NOT NULL,
38
+ PRIMARY KEY (scope, id)
39
+ );
40
+ CREATE TABLE IF NOT EXISTS emseepea_feedback_outbox (
41
+ event_id text PRIMARY KEY,
42
+ event_type text NOT NULL,
43
+ occurred_at timestamptz NOT NULL,
44
+ scope text NOT NULL,
45
+ thread_id text NOT NULL,
46
+ message_id text,
47
+ author text,
48
+ dispatched_at timestamptz
49
+ );`;
50
+ export async function migratePostgresFeedback(pool) {
51
+ await pool.query(postgresFeedbackSchema);
52
+ }
53
+ export function createPostgresFeedbackSubmissionBackend(options) {
54
+ return {
55
+ submit: (command, context) => transaction(options.pool, async (client) => {
56
+ const id = randomUUID();
57
+ const result = await client.query(`
58
+ INSERT INTO emseepea_feedback_submissions
59
+ (scope, id, observation, detail, context, recorded_at)
60
+ VALUES ($1, $2, $3, $4, $5::jsonb, clock_timestamp())
61
+ RETURNING recorded_at
62
+ `, [context.scope, id, command.observation, command.detail, JSON.stringify(command.context)]);
63
+ const recordedAt = iso(result.rows[0]?.recorded_at);
64
+ const events = [event("feedback.message.added", id, id, "user", recordedAt)];
65
+ if (options.outbox)
66
+ await writeOutbox(client, context.scope, events);
67
+ return { id, recordedAt, events };
68
+ }, context),
69
+ };
70
+ }
71
+ export function createPostgresFeedbackBackend(options) {
72
+ return {
73
+ createThread: (command, context) => transaction(options.pool, async (client) => {
74
+ const threadId = randomUUID();
75
+ const messageId = randomUUID();
76
+ const inserted = await client.query(`
77
+ INSERT INTO emseepea_feedback_threads
78
+ (scope, id, subject, status, created_at, updated_at)
79
+ VALUES ($1, $2, $3, 'open', clock_timestamp(), clock_timestamp())
80
+ RETURNING *
81
+ `, [context.scope, threadId, command.subject]);
82
+ const message = await insertMessage(client, context.scope, threadId, messageId, 1, "user", "comment", command.message);
83
+ const thread = threadRow.parse(inserted.rows[0]);
84
+ const events = [
85
+ event("feedback.thread.created", threadId, undefined, "user", iso(thread.created_at)),
86
+ event("feedback.message.added", threadId, messageId, "user", iso(message.created_at)),
87
+ ];
88
+ if (options.outbox)
89
+ await writeOutbox(client, context.scope, events);
90
+ return { conversation: conversation(thread, [message]), events };
91
+ }, context),
92
+ appendMessage: (command, context) => transaction(options.pool, async (client) => {
93
+ const thread = await lockThread(client, context.scope, command.threadId);
94
+ const sequenceResult = await client.query(`
95
+ SELECT COALESCE(MAX(sequence), 0) + 1 AS sequence
96
+ FROM emseepea_feedback_messages
97
+ WHERE scope = $1 AND thread_id = $2
98
+ `, [context.scope, command.threadId]);
99
+ const sequence = z.coerce.number().int().positive().parse(sequenceResult.rows[0]?.sequence);
100
+ const message = await insertMessage(client, context.scope, command.threadId, randomUUID(), sequence, "user", "comment", command.message);
101
+ await client.query(`
102
+ UPDATE emseepea_feedback_threads SET updated_at = $3
103
+ WHERE scope = $1 AND id = $2
104
+ `, [context.scope, command.threadId, message.created_at]);
105
+ const mapped = messageValue(message);
106
+ const events = [event("feedback.message.added", command.threadId, mapped.id, "user", mapped.createdAt)];
107
+ if (options.outbox)
108
+ await writeOutbox(client, context.scope, events);
109
+ void thread;
110
+ return { message: mapped, events };
111
+ }, context),
112
+ listThreads: ({ cursor, limit }, context) => transaction(options.pool, async (client) => {
113
+ const position = decodeCursor(cursor);
114
+ const values = [context.scope, limit + 1];
115
+ const condition = position
116
+ ? "AND (updated_at, id) < ($3::timestamptz, $4)"
117
+ : "";
118
+ if (position)
119
+ values.push(position.updatedAt, position.id);
120
+ const result = await client.query(`
121
+ SELECT * FROM emseepea_feedback_threads
122
+ WHERE scope = $1 ${condition}
123
+ ORDER BY updated_at DESC, id DESC
124
+ LIMIT $2
125
+ `, values);
126
+ const rows = result.rows.map((row) => threadRow.parse(row));
127
+ const visible = rows.slice(0, limit);
128
+ const last = visible.at(-1);
129
+ return {
130
+ page: {
131
+ threads: visible.map(threadValue),
132
+ nextCursor: rows.length > limit && last
133
+ ? encodeCursor(iso(last.updated_at), last.id)
134
+ : undefined,
135
+ },
136
+ };
137
+ }, context),
138
+ async getThread(query, context) {
139
+ const base = await transaction(options.pool, async (client) => {
140
+ const thread = await lockThread(client, context.scope, query.threadId);
141
+ const messages = await client.query(`
142
+ SELECT * FROM emseepea_feedback_messages
143
+ WHERE scope = $1 AND thread_id = $2
144
+ ORDER BY sequence
145
+ LIMIT 200
146
+ `, [context.scope, query.threadId]);
147
+ return conversation(thread, messages.rows.map((row) => messageRow.parse(row)));
148
+ }, context);
149
+ feedbackConversationSchema.parse(base);
150
+ try {
151
+ const offered = await transaction(options.pool, async (client) => {
152
+ const result = await client.query(`
153
+ UPDATE emseepea_feedback_messages
154
+ SET offered_to_client_at = clock_timestamp()
155
+ WHERE scope = $1 AND thread_id = $2
156
+ AND author = 'team' AND offered_to_client_at IS NULL
157
+ RETURNING *
158
+ `, [context.scope, query.threadId]);
159
+ const rows = result.rows.map((row) => messageRow.parse(row));
160
+ const events = rows.map((message) => event("feedback.message.offered-to-client", query.threadId, message.id, "team", iso(message.offered_to_client_at)));
161
+ if (options.outbox)
162
+ await writeOutbox(client, context.scope, events);
163
+ return { rows, events };
164
+ }, context);
165
+ const receipts = new Map(offered.rows.map((message) => [message.id, iso(message.offered_to_client_at)]));
166
+ return {
167
+ conversation: {
168
+ ...base,
169
+ messages: base.messages.map((message) => receipts.has(message.id)
170
+ ? { ...message, offeredToClientAt: receipts.get(message.id) }
171
+ : message),
172
+ },
173
+ events: offered.events,
174
+ };
175
+ }
176
+ catch {
177
+ return { conversation: base, events: [] };
178
+ }
179
+ },
180
+ };
181
+ }
182
+ export async function appendPostgresTeamReply(options, command, context) {
183
+ const scope = z.string().min(1).max(240).parse(command.scope);
184
+ const messageBody = z.string().min(1).max(4_000).parse(command.message);
185
+ await transaction(options.pool, async (client) => {
186
+ await lockThread(client, scope, command.threadId);
187
+ const next = await client.query(`
188
+ SELECT COALESCE(MAX(sequence), 0) + 1 AS sequence
189
+ FROM emseepea_feedback_messages
190
+ WHERE scope = $1 AND thread_id = $2
191
+ `, [scope, command.threadId]);
192
+ const message = await insertMessage(client, scope, command.threadId, randomUUID(), z.coerce.number().int().positive().parse(next.rows[0]?.sequence), "team", "comment", messageBody);
193
+ const status = command.status === undefined
194
+ ? undefined
195
+ : z.string().min(1).max(80).parse(command.status);
196
+ await client.query(`
197
+ UPDATE emseepea_feedback_threads
198
+ SET updated_at = $3, status = COALESCE($4, status)
199
+ WHERE scope = $1 AND id = $2
200
+ `, [scope, command.threadId, message.created_at, status]);
201
+ if (options.outbox) {
202
+ const events = [event("feedback.message.added", command.threadId, message.id, "team", iso(message.created_at))];
203
+ if (status)
204
+ events.push(event("feedback.status.changed", command.threadId, undefined, "team", iso(message.created_at)));
205
+ await writeOutbox(client, scope, events);
206
+ }
207
+ }, { ...context, scope });
208
+ }
209
+ const threadRow = z.object({
210
+ id: z.string(),
211
+ subject: z.string(),
212
+ status: z.string(),
213
+ created_at: z.union([z.date(), z.string()]),
214
+ updated_at: z.union([z.date(), z.string()]),
215
+ });
216
+ const messageRow = z.object({
217
+ id: z.string(),
218
+ thread_id: z.string(),
219
+ sequence: z.coerce.number().int().positive(),
220
+ author: z.enum(["user", "team", "system"]),
221
+ kind: z.enum(["comment", "question", "status"]),
222
+ body: z.string(),
223
+ created_at: z.union([z.date(), z.string()]),
224
+ offered_to_client_at: z.union([z.date(), z.string()]).nullable(),
225
+ });
226
+ async function transaction(pool, work, context) {
227
+ context.signal.throwIfAborted();
228
+ let abandoned = false;
229
+ const pendingClient = pool.connect();
230
+ pendingClient.then((client) => {
231
+ if (abandoned)
232
+ client.release();
233
+ }).catch(() => undefined);
234
+ let client;
235
+ try {
236
+ client = await beforeDeadline(pendingClient, context);
237
+ }
238
+ catch (error) {
239
+ abandoned = true;
240
+ throw error;
241
+ }
242
+ try {
243
+ await client.query("BEGIN");
244
+ const remainingMs = Math.max(1, context.deadlineMs - Date.now());
245
+ await client.query("SELECT set_config('statement_timeout', $1, true)", [String(remainingMs)]);
246
+ context.signal.throwIfAborted();
247
+ const result = await work(client);
248
+ context.signal.throwIfAborted();
249
+ await client.query("COMMIT");
250
+ return result;
251
+ }
252
+ catch (error) {
253
+ await client.query("ROLLBACK").catch(() => undefined);
254
+ throw error;
255
+ }
256
+ finally {
257
+ client.release();
258
+ }
259
+ }
260
+ async function lockThread(client, scope, id) {
261
+ const result = await client.query(`
262
+ SELECT * FROM emseepea_feedback_threads
263
+ WHERE scope = $1 AND id = $2
264
+ FOR UPDATE
265
+ `, [scope, id]);
266
+ if (result.rows.length !== 1)
267
+ throw new Error("Feedback thread not found");
268
+ return threadRow.parse(result.rows[0]);
269
+ }
270
+ async function insertMessage(client, scope, threadId, id, sequence, author, kind, value) {
271
+ const result = await client.query(`
272
+ INSERT INTO emseepea_feedback_messages
273
+ (scope, thread_id, id, sequence, author, kind, body, created_at)
274
+ VALUES ($1, $2, $3, $4, $5, $6, $7, clock_timestamp())
275
+ RETURNING *
276
+ `, [scope, threadId, id, sequence, author, kind, value]);
277
+ return messageRow.parse(result.rows[0]);
278
+ }
279
+ async function writeOutbox(client, scope, events) {
280
+ if (events.length === 0)
281
+ return;
282
+ await client.query(`
283
+ INSERT INTO emseepea_feedback_outbox
284
+ (event_id, event_type, occurred_at, scope, thread_id, message_id, author)
285
+ SELECT id, type, "occurredAt"::timestamptz, $2, "threadId", "messageId", author
286
+ FROM jsonb_to_recordset($1::jsonb)
287
+ AS event(id text, type text, "occurredAt" text, "threadId" text, "messageId" text, author text)
288
+ ON CONFLICT (event_id) DO NOTHING
289
+ `, [JSON.stringify(events), scope]);
290
+ }
291
+ function conversation(thread, messages) {
292
+ return {
293
+ ...threadValue(thread),
294
+ messages: messages.map(messageValue),
295
+ };
296
+ }
297
+ function threadValue(thread) {
298
+ return {
299
+ id: thread.id,
300
+ subject: thread.subject,
301
+ status: thread.status,
302
+ createdAt: iso(thread.created_at),
303
+ updatedAt: iso(thread.updated_at),
304
+ };
305
+ }
306
+ function messageValue(message) {
307
+ return {
308
+ id: message.id,
309
+ threadId: message.thread_id,
310
+ sequence: message.sequence,
311
+ author: message.author,
312
+ kind: message.kind,
313
+ body: message.body,
314
+ createdAt: iso(message.created_at),
315
+ offeredToClientAt: message.offered_to_client_at
316
+ ? iso(message.offered_to_client_at)
317
+ : undefined,
318
+ };
319
+ }
320
+ function iso(value) {
321
+ if (value === null || value === undefined)
322
+ throw new Error("PostgreSQL feedback timestamp missing");
323
+ const date = value instanceof Date ? value : new Date(value);
324
+ if (Number.isNaN(date.valueOf()))
325
+ throw new Error("PostgreSQL feedback timestamp invalid");
326
+ return date.toISOString();
327
+ }
328
+ function event(type, threadId, messageId, author, occurredAt) {
329
+ return {
330
+ id: messageId ? `${type}:${messageId}` : `${type}:${threadId}:${occurredAt}`,
331
+ type,
332
+ occurredAt,
333
+ threadId,
334
+ messageId,
335
+ author,
336
+ };
337
+ }
338
+ function encodeCursor(updatedAt, id) {
339
+ return Buffer.from(JSON.stringify({ updatedAt, id })).toString("base64url");
340
+ }
341
+ function decodeCursor(cursor) {
342
+ if (cursor === undefined)
343
+ return undefined;
344
+ try {
345
+ return z.strictObject({ updatedAt: z.iso.datetime(), id: z.string().min(1).max(240) })
346
+ .parse(JSON.parse(Buffer.from(cursor, "base64url").toString("utf8")));
347
+ }
348
+ catch {
349
+ throw new Error("Invalid PostgreSQL feedback cursor");
350
+ }
351
+ }
352
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=testing-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing-server.d.ts","sourceRoot":"","sources":["../src/testing-server.ts"],"names":[],"mappings":""}
@@ -0,0 +1,46 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { serveEmseepea } from "@emseepea/server";
3
+ import { defineFeedbackSubmission } from "./index.js";
4
+ const appModule = process.env.EMSEEPEA_EVAL_APP_MODULE;
5
+ const factoryName = process.env.EMSEEPEA_EVAL_APP_FACTORY;
6
+ const kind = process.env.EMSEEPEA_EVAL_APP_KIND ?? "options";
7
+ if (!appModule || !factoryName)
8
+ throw new Error("Example eval app factory is required");
9
+ const factory = (await import(appModule))[factoryName];
10
+ if (typeof factory !== "function")
11
+ throw new Error("Example eval app factory was not exported");
12
+ const feedback = defineFeedbackSubmission({
13
+ access: "public",
14
+ backend: {
15
+ submit: () => ({ id: randomUUID(), recordedAt: new Date().toISOString() }),
16
+ },
17
+ });
18
+ const extensions = { additionalTools: [feedback] };
19
+ const created = kind === "postgres"
20
+ ? await factory({ databaseUrl: process.env.DATABASE_URL, ...extensions })
21
+ : kind === "mongodb"
22
+ ? await factory({ uri: process.env.MONGODB_URL, ...extensions })
23
+ : kind === "soap"
24
+ ? await factory(process.env.PEA_SOAP_URL, extensions)
25
+ : await factory(extensions);
26
+ if (!created || typeof created !== "object")
27
+ throw new Error("Example eval app factory returned no app");
28
+ const app = "app" in created ? created.app : created;
29
+ const closeProvider = "closeProvider" in created && typeof created.closeProvider === "function"
30
+ ? created.closeProvider.bind(created)
31
+ : undefined;
32
+ const running = await serveEmseepea(app, {
33
+ port: Number.parseInt(process.env.PORT ?? "3000", 10),
34
+ });
35
+ console.log(`Feedback-enabled example eval server listening at ${running.url}`);
36
+ async function shutdown() {
37
+ try {
38
+ await running.close();
39
+ }
40
+ finally {
41
+ await closeProvider?.();
42
+ }
43
+ }
44
+ process.once("SIGINT", () => void shutdown());
45
+ process.once("SIGTERM", () => void shutdown());
46
+ //# sourceMappingURL=testing-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing-server.js","sourceRoot":"","sources":["../src/testing-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { FeedbackAdapterContext, FeedbackEvent } from "./index.js";
2
+ export interface FeedbackWebhookStore {
3
+ claim(eventId: string, context: FeedbackAdapterContext): boolean | Promise<boolean>;
4
+ resolveScope(scopeHash: string, context: FeedbackAdapterContext): string | undefined | Promise<string | undefined>;
5
+ }
6
+ interface WebhookInput {
7
+ readonly body: Uint8Array;
8
+ readonly headers: Readonly<Record<string, string | undefined>>;
9
+ }
10
+ export declare function ingestGitHubFeedbackWebhook(input: WebhookInput, options: Readonly<{
11
+ secret: string;
12
+ owner: string;
13
+ repository: string;
14
+ store: FeedbackWebhookStore;
15
+ }>, context: FeedbackAdapterContext): Promise<readonly FeedbackEvent[]>;
16
+ export declare function ingestZendeskFeedbackWebhook(input: WebhookInput, options: Readonly<{
17
+ secret: string;
18
+ subdomain: string;
19
+ store: FeedbackWebhookStore;
20
+ }>, context: FeedbackAdapterContext): Promise<readonly FeedbackEvent[]>;
21
+ export {};
22
+ //# sourceMappingURL=webhooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../src/webhooks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkCxE,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACpH;AAED,UAAU,YAAY;IACpB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;CAChE;AAED,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,oBAAoB,CAAC;CAC7B,CAAC,EACF,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAgBnC;AAED,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,oBAAoB,CAAC;CAC7B,CAAC,EACF,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CA2BnC"}
@@ -0,0 +1,142 @@
1
+ import { createHmac, timingSafeEqual } from "node:crypto";
2
+ import { z } from "zod";
3
+ import { beforeDeadline } from "./deadline.js";
4
+ import { feedbackEventSchema } from "./index.js";
5
+ const maximumWebhookBytes = 64 * 1024;
6
+ const timestamp = z.iso.datetime({ offset: true });
7
+ const githubPayloadSchema = z.object({
8
+ action: z.string().min(1),
9
+ repository: z.object({ full_name: z.string().min(3) }),
10
+ issue: z.object({
11
+ number: z.number().int().positive(),
12
+ updated_at: timestamp,
13
+ labels: z.array(z.object({ name: z.string() })),
14
+ }),
15
+ comment: z.object({
16
+ id: z.number().int().positive(),
17
+ body: z.string(),
18
+ created_at: timestamp,
19
+ }).optional(),
20
+ });
21
+ const zendeskPayloadSchema = z.strictObject({
22
+ eventId: z.string().min(1).max(240),
23
+ subdomain: z.string().min(1).max(63),
24
+ ticketId: z.number().int().positive(),
25
+ scopeTag: z.string().regex(/^emseepea_[a-f0-9]{24}$/),
26
+ occurredAt: timestamp,
27
+ change: z.discriminatedUnion("type", [
28
+ z.strictObject({
29
+ type: z.literal("public_comment"),
30
+ commentId: z.number().int().positive(),
31
+ author: z.enum(["user", "team"]),
32
+ }),
33
+ z.strictObject({ type: z.literal("status_changed") }),
34
+ ]),
35
+ });
36
+ export async function ingestGitHubFeedbackWebhook(input, options, context) {
37
+ const body = checkedBody(input.body);
38
+ verifyHexSignature(input.headers["x-hub-signature-256"], checkedSecret(options.secret), body);
39
+ const delivery = requiredHeader(input.headers, "x-github-delivery");
40
+ const kind = requiredHeader(input.headers, "x-github-event");
41
+ const payload = githubPayloadSchema.parse(JSON.parse(new TextDecoder().decode(body)));
42
+ if (payload.repository.full_name !== `${options.owner}/${options.repository}`) {
43
+ throw new Error("GitHub feedback webhook targeted the wrong repository");
44
+ }
45
+ const labels = payload.issue.labels.filter(({ name }) => name.startsWith("emseepea-"));
46
+ if (labels.length !== 1)
47
+ throw new Error("GitHub feedback webhook must have exactly one feedback scope");
48
+ const label = labels[0];
49
+ const scope = await resolveScope(options.store, label.name.slice("emseepea-".length), context);
50
+ const event = githubEvent(kind, delivery, payload, scope);
51
+ if (!await beforeDeadline(Promise.resolve(options.store.claim(`github:${delivery}`, context)), context))
52
+ return [];
53
+ return Object.freeze([Object.freeze(feedbackEventSchema.parse(event))]);
54
+ }
55
+ export async function ingestZendeskFeedbackWebhook(input, options, context) {
56
+ const body = checkedBody(input.body);
57
+ const sentAt = requiredHeader(input.headers, "x-zendesk-webhook-signature-timestamp");
58
+ verifyBase64Signature(input.headers["x-zendesk-webhook-signature"], checkedSecret(options.secret), new TextEncoder().encode(`${sentAt}${new TextDecoder().decode(body)}`));
59
+ const payload = zendeskPayloadSchema.parse(JSON.parse(new TextDecoder().decode(body)));
60
+ if (payload.subdomain !== options.subdomain) {
61
+ throw new Error("Zendesk feedback webhook targeted the wrong account");
62
+ }
63
+ const scope = await resolveScope(options.store, payload.scopeTag.slice("emseepea_".length), context);
64
+ if (!await beforeDeadline(Promise.resolve(options.store.claim(`zendesk:${payload.eventId}`, context)), context))
65
+ return [];
66
+ const threadId = `zendesk-ticket-${payload.ticketId}`;
67
+ const change = payload.change;
68
+ return Object.freeze([Object.freeze(feedbackEventSchema.parse({
69
+ id: `zendesk:${payload.eventId}`,
70
+ type: change.type === "status_changed" ? "feedback.status.changed" : "feedback.message.added",
71
+ occurredAt: payload.occurredAt,
72
+ scope,
73
+ threadId,
74
+ ...(change.type === "public_comment" ? {
75
+ messageId: `zendesk-comment-${change.commentId}`,
76
+ author: change.author,
77
+ } : {}),
78
+ }))]);
79
+ }
80
+ function githubEvent(kind, delivery, payload, scope) {
81
+ const threadId = `github-issue-${payload.issue.number}`;
82
+ if (kind === "issue_comment" && payload.action === "created" && payload.comment) {
83
+ return Object.freeze({
84
+ id: `github:${delivery}`,
85
+ type: "feedback.message.added",
86
+ occurredAt: payload.comment.created_at,
87
+ scope,
88
+ threadId,
89
+ messageId: `github-comment-${payload.comment.id}`,
90
+ author: payload.comment.body.startsWith("<!-- emseepea-feedback:user -->") ? "user" : "team",
91
+ });
92
+ }
93
+ if (kind === "issues" && ["assigned", "closed", "labeled", "milestoned", "reopened", "unassigned", "unlabeled"].includes(payload.action)) {
94
+ return Object.freeze({
95
+ id: `github:${delivery}`,
96
+ type: "feedback.status.changed",
97
+ occurredAt: payload.issue.updated_at,
98
+ scope,
99
+ threadId,
100
+ });
101
+ }
102
+ throw new Error("Unsupported GitHub feedback webhook event");
103
+ }
104
+ async function resolveScope(store, hash, context) {
105
+ const scope = await beforeDeadline(Promise.resolve(store.resolveScope(hash, context)), context);
106
+ return z.string().min(1).max(240).parse(scope);
107
+ }
108
+ function checkedBody(body) {
109
+ if (body.byteLength === 0 || body.byteLength > maximumWebhookBytes) {
110
+ throw new Error("Feedback webhook body is empty or exceeded 64 KiB");
111
+ }
112
+ return body;
113
+ }
114
+ function checkedSecret(secret) {
115
+ if (Buffer.byteLength(secret, "utf8") < 32) {
116
+ throw new Error("Feedback webhook secret must be at least 32 bytes");
117
+ }
118
+ return secret;
119
+ }
120
+ function requiredHeader(headers, name) {
121
+ const value = headers[name];
122
+ if (!value)
123
+ throw new Error(`Feedback webhook is missing ${name}`);
124
+ return value;
125
+ }
126
+ function verifyHexSignature(value, secret, body) {
127
+ const expected = `sha256=${createHmac("sha256", secret).update(body).digest("hex")}`;
128
+ verifySignature(value, expected);
129
+ }
130
+ function verifyBase64Signature(value, secret, body) {
131
+ verifySignature(value, createHmac("sha256", secret).update(body).digest("base64"));
132
+ }
133
+ function verifySignature(value, expected) {
134
+ if (!value)
135
+ throw new Error("Feedback webhook signature is missing");
136
+ const actualBytes = Buffer.from(value);
137
+ const expectedBytes = Buffer.from(expected);
138
+ if (actualBytes.length !== expectedBytes.length || !timingSafeEqual(actualBytes, expectedBytes)) {
139
+ throw new Error("Feedback webhook signature is invalid");
140
+ }
141
+ }
142
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../src/webhooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { FeedbackConversationBackend, FeedbackSubmissionBackend } from "./index.js";
2
+ export interface ZendeskFeedbackOptions {
3
+ readonly subdomain?: string;
4
+ readonly baseUrl?: URL;
5
+ readonly token: string | (() => string | Promise<string>);
6
+ readonly requesterId?: (scope: string) => number | Promise<number>;
7
+ readonly tags?: readonly string[];
8
+ readonly fetch?: typeof fetch;
9
+ }
10
+ export declare function createZendeskFeedbackBackend(options: ZendeskFeedbackOptions): FeedbackConversationBackend;
11
+ export declare function createZendeskFeedbackSubmissionBackend(options: ZendeskFeedbackOptions): FeedbackSubmissionBackend;
12
+ //# sourceMappingURL=zendesk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zendesk.d.ts","sourceRoot":"","sources":["../src/zendesk.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,2BAA2B,EAE3B,yBAAyB,EAE1B,MAAM,YAAY,CAAC;AAyBpB,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CAC/B;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,sBAAsB,GAC9B,2BAA2B,CAsJ7B;AAED,wBAAgB,sCAAsC,CACpD,OAAO,EAAE,sBAAsB,GAC9B,yBAAyB,CAe3B"}