@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,286 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { z } from "zod";
3
+ import { beforeDeadline } from "./deadline.js";
4
+ import { feedbackConversationSchema } from "./index.js";
5
+ import { bearerHeaders, providerRequestInit, requestJson } from "./http.js";
6
+ const ticketSchema = z.object({
7
+ id: z.number().int().positive(),
8
+ subject: z.string().nullable(),
9
+ description: z.string().nullable(),
10
+ status: z.string().min(1),
11
+ created_at: z.string(),
12
+ updated_at: z.string(),
13
+ tags: z.array(z.string()).default([]),
14
+ });
15
+ const commentSchema = z.object({
16
+ id: z.number().int().positive(),
17
+ body: z.string(),
18
+ public: z.boolean(),
19
+ created_at: z.string(),
20
+ });
21
+ const ticketResponseSchema = z.object({ ticket: ticketSchema });
22
+ const commentsResponseSchema = z.object({ comments: z.array(commentSchema) });
23
+ const searchResponseSchema = z.object({ results: z.array(ticketSchema) });
24
+ const USER_MARKER = "[emseepea-feedback:user]";
25
+ const RECEIPT_MARKER = "[emseepea-feedback:offered:";
26
+ export function createZendeskFeedbackBackend(options) {
27
+ const fetcher = options.fetch ?? fetch;
28
+ const base = options.baseUrl ?? zendeskUrl(options.subdomain);
29
+ assertProviderUrl(base);
30
+ async function call(path, context, init = {}, expected = [200]) {
31
+ const token = typeof options.token === "function" ? await options.token() : options.token;
32
+ return beforeDeadline(requestJson(fetcher, new URL(path, base), providerRequestInit(context, {
33
+ ...init,
34
+ headers: { ...bearerHeaders(token), ...init.headers },
35
+ }), expected), context);
36
+ }
37
+ return {
38
+ async createThread({ subject, message }, context) {
39
+ const requesterId = await resolveRequesterId(options, context.scope);
40
+ const response = await call("api/v2/tickets.json", context, {
41
+ method: "POST",
42
+ body: JSON.stringify({
43
+ ticket: {
44
+ subject,
45
+ ...(requesterId ? { requester_id: requesterId } : {}),
46
+ comment: {
47
+ body: `${USER_MARKER}\n${message}`,
48
+ public: true,
49
+ ...(requesterId ? { author_id: requesterId } : {}),
50
+ },
51
+ tags: [...(options.tags ?? []), zendeskScopeTag(context.scope)],
52
+ },
53
+ }),
54
+ }, [201]);
55
+ const ticket = ticketResponseSchema.parse(response.value).ticket;
56
+ const conversation = await readConversation(call, ticket, context);
57
+ const initial = conversation.messages[0];
58
+ return {
59
+ conversation,
60
+ events: [
61
+ event("feedback.thread.created", conversation.id, undefined, "user", ticket.created_at),
62
+ event("feedback.message.added", conversation.id, initial.id, "user", initial.createdAt),
63
+ ],
64
+ };
65
+ },
66
+ async appendMessage({ threadId, message }, context) {
67
+ const id = ticketId(threadId);
68
+ await scopedTicket(call, id, context);
69
+ const requesterId = await resolveRequesterId(options, context.scope);
70
+ const correlation = randomUUID();
71
+ await call(`api/v2/tickets/${id}.json`, context, {
72
+ method: "PUT",
73
+ body: JSON.stringify({
74
+ ticket: {
75
+ comment: {
76
+ body: `${USER_MARKER}:${correlation}\n${message}`,
77
+ public: true,
78
+ ...(requesterId ? { author_id: requesterId } : {}),
79
+ },
80
+ },
81
+ }),
82
+ });
83
+ const allComments = await ticketComments(call, id, context);
84
+ const comment = allComments.find(({ body }) => body.startsWith(`${USER_MARKER}:${correlation}\n`));
85
+ if (!comment)
86
+ throw new Error("Zendesk did not return the appended feedback message");
87
+ const visible = allComments.filter((item) => item.public);
88
+ const mapped = zendeskMessage(threadId, comment, visible.findIndex(({ id }) => id === comment.id) + 1);
89
+ return {
90
+ message: mapped,
91
+ events: [event("feedback.message.added", threadId, mapped.id, "user", mapped.createdAt)],
92
+ };
93
+ },
94
+ async listThreads({ cursor, limit }, context) {
95
+ const page = parsePage(cursor);
96
+ const query = encodeURIComponent(`type:ticket tags:${zendeskScopeTag(context.scope)}`);
97
+ const response = await call(`api/v2/search.json?query=${query}&per_page=${limit}&page=${page}`, context);
98
+ const tickets = searchResponseSchema.parse(response.value).results;
99
+ return {
100
+ page: {
101
+ threads: tickets.map(zendeskThread),
102
+ nextCursor: tickets.length === limit ? String(page + 1) : undefined,
103
+ },
104
+ };
105
+ },
106
+ async getThread({ threadId }, context) {
107
+ const id = ticketId(threadId);
108
+ const ticket = await scopedTicket(call, id, context);
109
+ const before = await ticketComments(call, id, context);
110
+ const existingReceipts = new Map();
111
+ for (const comment of before) {
112
+ const receipt = receiptDetails(comment);
113
+ if (receipt)
114
+ existingReceipts.set(receipt.messageId, comment.created_at);
115
+ }
116
+ const conversation = mapConversation(ticket, before, existingReceipts);
117
+ feedbackConversationSchema.parse(conversation);
118
+ const newReceiptIds = new Set();
119
+ for (const comment of before) {
120
+ if (!comment.public || comment.body.startsWith(USER_MARKER) || existingReceipts.has(comment.id))
121
+ continue;
122
+ try {
123
+ await call(`api/v2/tickets/${id}.json`, context, {
124
+ method: "PUT",
125
+ body: JSON.stringify({
126
+ ticket: {
127
+ comment: {
128
+ body: `${RECEIPT_MARKER}${comment.id}] Offered to the MCP client.`,
129
+ public: false,
130
+ },
131
+ },
132
+ }),
133
+ });
134
+ newReceiptIds.add(comment.id);
135
+ }
136
+ catch {
137
+ // The validated support reply is still returned when its receipt fails.
138
+ }
139
+ }
140
+ let after = before;
141
+ if (newReceiptIds.size > 0) {
142
+ try {
143
+ after = await ticketComments(call, id, context);
144
+ }
145
+ catch {
146
+ return { conversation, events: [] };
147
+ }
148
+ }
149
+ const newlyOffered = new Map();
150
+ for (const comment of after) {
151
+ const receipt = receiptDetails(comment);
152
+ if (receipt && newReceiptIds.has(receipt.messageId)) {
153
+ newlyOffered.set(receipt.messageId, comment.created_at);
154
+ }
155
+ }
156
+ const allReceipts = new Map([...existingReceipts, ...newlyOffered]);
157
+ const offeredConversation = mapConversation(ticket, before, allReceipts);
158
+ const events = [...newlyOffered].map(([messageId, offeredAt]) => event("feedback.message.offered-to-client", threadId, `zendesk-comment-${messageId}`, "team", offeredAt));
159
+ return { conversation: offeredConversation, events };
160
+ },
161
+ };
162
+ }
163
+ export function createZendeskFeedbackSubmissionBackend(options) {
164
+ const backend = createZendeskFeedbackBackend(options);
165
+ return {
166
+ async submit(command, context) {
167
+ const result = await backend.createThread({
168
+ subject: `Feedback: ${command.observation.replaceAll("_", " ")}`,
169
+ message: command.detail,
170
+ }, context);
171
+ return {
172
+ id: result.conversation.id,
173
+ recordedAt: result.conversation.createdAt,
174
+ events: result.events,
175
+ };
176
+ },
177
+ };
178
+ }
179
+ async function scopedTicket(call, id, context) {
180
+ const response = await call(`api/v2/tickets/${id}.json`, context);
181
+ const ticket = ticketResponseSchema.parse(response.value).ticket;
182
+ if (!ticket.tags.includes(zendeskScopeTag(context.scope)))
183
+ throw new Error("Feedback thread not found");
184
+ return ticket;
185
+ }
186
+ async function ticketComments(call, id, context) {
187
+ const response = await call(`api/v2/tickets/${id}/comments.json?sort_order=asc&per_page=100&page=1`, context);
188
+ const values = commentsResponseSchema.parse(response.value).comments;
189
+ if (values.length === 100) {
190
+ const overflow = await call(`api/v2/tickets/${id}/comments.json?sort_order=asc&per_page=1&page=101`, context);
191
+ if (commentsResponseSchema.parse(overflow.value).comments.length > 0) {
192
+ throw new Error("Zendesk feedback thread exceeded the 100-comment limit");
193
+ }
194
+ }
195
+ return values;
196
+ }
197
+ async function readConversation(call, ticket, context) {
198
+ const comments = await ticketComments(call, ticket.id, context);
199
+ return mapConversation(ticket, comments, new Map());
200
+ }
201
+ function mapConversation(ticket, comments, receipts) {
202
+ const threadId = `zendesk-ticket-${ticket.id}`;
203
+ const visible = comments.filter((item) => item.public);
204
+ return {
205
+ ...zendeskThread(ticket),
206
+ messages: visible.map((comment, index) => ({
207
+ ...zendeskMessage(threadId, comment, index + 1),
208
+ offeredToClientAt: receipts.get(comment.id),
209
+ })),
210
+ };
211
+ }
212
+ function zendeskThread(ticket) {
213
+ return {
214
+ id: `zendesk-ticket-${ticket.id}`,
215
+ subject: ticket.subject ?? "Feedback",
216
+ status: ticket.status,
217
+ createdAt: ticket.created_at,
218
+ updatedAt: ticket.updated_at,
219
+ };
220
+ }
221
+ function zendeskMessage(threadId, comment, sequence) {
222
+ const user = comment.body.startsWith(USER_MARKER);
223
+ return {
224
+ id: `zendesk-comment-${comment.id}`,
225
+ threadId,
226
+ sequence,
227
+ author: user ? "user" : "team",
228
+ kind: "comment",
229
+ body: stripMarker(comment.body),
230
+ createdAt: comment.created_at,
231
+ };
232
+ }
233
+ function receiptDetails(comment) {
234
+ if (comment.public)
235
+ return undefined;
236
+ const match = /^\[emseepea-feedback:offered:(\d+)\]/.exec(comment.body);
237
+ return match ? { messageId: Number.parseInt(match[1], 10) } : undefined;
238
+ }
239
+ function stripMarker(value) {
240
+ return value.replace(/^\[emseepea-feedback:user\](?::[^\n]+)?\n?/, "").trim();
241
+ }
242
+ function ticketId(threadId) {
243
+ const match = /^zendesk-ticket-(\d+)$/.exec(threadId);
244
+ if (!match)
245
+ throw new Error("Invalid Zendesk feedback thread identifier");
246
+ return Number.parseInt(match[1], 10);
247
+ }
248
+ function zendeskScopeTag(scope) {
249
+ return `emseepea_${createHash("sha256").update(scope).digest("hex").slice(0, 24)}`;
250
+ }
251
+ function zendeskUrl(subdomain) {
252
+ if (!subdomain || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(subdomain)) {
253
+ throw new Error("A valid Zendesk subdomain is required");
254
+ }
255
+ return new URL(`https://${subdomain}.zendesk.com/`);
256
+ }
257
+ async function resolveRequesterId(options, scope) {
258
+ if (!options.requesterId)
259
+ return undefined;
260
+ return z.number().int().positive().parse(await options.requesterId(scope));
261
+ }
262
+ function assertProviderUrl(value) {
263
+ if (value.protocol !== "https:" || value.username || value.password || value.hash) {
264
+ throw new Error("Zendesk API URL must be HTTPS without credentials or a fragment");
265
+ }
266
+ }
267
+ function parsePage(cursor) {
268
+ if (cursor === undefined)
269
+ return 1;
270
+ const page = Number.parseInt(cursor, 10);
271
+ if (!Number.isSafeInteger(page) || page < 1 || String(page) !== cursor) {
272
+ throw new Error("Invalid Zendesk feedback cursor");
273
+ }
274
+ return page;
275
+ }
276
+ function event(type, threadId, messageId, author, occurredAt) {
277
+ return {
278
+ id: messageId ? `${type}:${messageId}` : `${type}:${threadId}:${occurredAt}`,
279
+ type,
280
+ occurredAt,
281
+ threadId,
282
+ messageId,
283
+ author,
284
+ };
285
+ }
286
+ //# sourceMappingURL=zendesk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zendesk.js","sourceRoot":"","sources":["../src/zendesk.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@emseepea/feedback",
3
+ "version": "0.2.0",
4
+ "description": "Optional detailed feedback and support conversations for Em See Pea servers",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/emseepea/emseepea.git",
9
+ "directory": "packages/feedback"
10
+ },
11
+ "homepage": "https://emseepea.github.io/emseepea/feedback/",
12
+ "bugs": "https://github.com/emseepea/emseepea/issues",
13
+ "publishConfig": {
14
+ "access": "public",
15
+ "provenance": true
16
+ },
17
+ "type": "module",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ },
23
+ "./postgres": {
24
+ "types": "./dist/postgres.d.ts",
25
+ "import": "./dist/postgres.js"
26
+ },
27
+ "./firestore": {
28
+ "types": "./dist/firestore.d.ts",
29
+ "import": "./dist/firestore.js"
30
+ },
31
+ "./github": {
32
+ "types": "./dist/github.d.ts",
33
+ "import": "./dist/github.js"
34
+ },
35
+ "./zendesk": {
36
+ "types": "./dist/zendesk.d.ts",
37
+ "import": "./dist/zendesk.js"
38
+ },
39
+ "./webhooks": {
40
+ "types": "./dist/webhooks.d.ts",
41
+ "import": "./dist/webhooks.js"
42
+ },
43
+ "./testing-server": "./dist/testing-server.js"
44
+ },
45
+ "files": [
46
+ "dist",
47
+ "LICENSE",
48
+ "README.md"
49
+ ],
50
+ "scripts": {
51
+ "build": "tsc -p tsconfig.json && tsc -p tsconfig.type-tests.json",
52
+ "prepack": "npm run build",
53
+ "test": "npm run build && npm run test:built",
54
+ "test:built": "node --test test/*.test.mjs",
55
+ "test:postgres": "cd ../../examples/multi-instance-postgres-server && node test/with-postgres.mjs node --test ../../packages/feedback/test/postgres.integration.mjs",
56
+ "test:llm": "npm run build && npm run test:llm:built",
57
+ "test:llm:built": "emseepea-test eval",
58
+ "lint": "oxlint src test eval"
59
+ },
60
+ "dependencies": {
61
+ "@emseepea/server": "0.6.1",
62
+ "zod": "4.4.3"
63
+ },
64
+ "devDependencies": {
65
+ "@emseepea/testing": "0.9.3",
66
+ "pg": "8.23.0"
67
+ },
68
+ "engines": {
69
+ "node": ">=22"
70
+ }
71
+ }