@noodleseed/one 0.96.3 → 0.98.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.
Files changed (173) hide show
  1. package/README.md +2 -1
  2. package/dist/commands/author-loop.d.ts.map +1 -1
  3. package/dist/commands/author-loop.js +7 -1
  4. package/dist/commands/author-loop.js.map +1 -1
  5. package/dist/commands/catalog-data-local-authoring.d.ts.map +1 -1
  6. package/dist/commands/catalog-data-local-authoring.js +2 -2
  7. package/dist/commands/catalog-data-local-authoring.js.map +1 -1
  8. package/dist/deploy.d.ts +5 -0
  9. package/dist/deploy.d.ts.map +1 -1
  10. package/dist/deploy.js +1 -1
  11. package/dist/deploy.js.map +1 -1
  12. package/dist/dev.d.ts +13 -0
  13. package/dist/dev.d.ts.map +1 -1
  14. package/dist/dev.js +116 -7
  15. package/dist/dev.js.map +1 -1
  16. package/dist/devtools-auth-routes.d.ts +4 -0
  17. package/dist/devtools-auth-routes.d.ts.map +1 -0
  18. package/dist/devtools-auth-routes.js +205 -0
  19. package/dist/devtools-auth-routes.js.map +1 -0
  20. package/dist/devtools-auth-session-helpers.d.ts +6 -0
  21. package/dist/devtools-auth-session-helpers.d.ts.map +1 -0
  22. package/dist/devtools-auth-session-helpers.js +19 -0
  23. package/dist/devtools-auth-session-helpers.js.map +1 -0
  24. package/dist/devtools-auth-session.d.ts +35 -0
  25. package/dist/devtools-auth-session.d.ts.map +1 -0
  26. package/dist/devtools-auth-session.js +433 -0
  27. package/dist/devtools-auth-session.js.map +1 -0
  28. package/dist/devtools-auth-types.d.ts +51 -0
  29. package/dist/devtools-auth-types.d.ts.map +1 -0
  30. package/dist/devtools-auth-types.js +16 -0
  31. package/dist/devtools-auth-types.js.map +1 -0
  32. package/dist/devtools-auth-ui.d.ts +6 -0
  33. package/dist/devtools-auth-ui.d.ts.map +1 -0
  34. package/dist/devtools-auth-ui.js +127 -0
  35. package/dist/devtools-auth-ui.js.map +1 -0
  36. package/dist/devtools-delegated-credential.d.ts +10 -0
  37. package/dist/devtools-delegated-credential.d.ts.map +1 -0
  38. package/dist/devtools-delegated-credential.js +32 -0
  39. package/dist/devtools-delegated-credential.js.map +1 -0
  40. package/dist/devtools-firebase-auth.d.ts +55 -0
  41. package/dist/devtools-firebase-auth.d.ts.map +1 -0
  42. package/dist/devtools-firebase-auth.js +237 -0
  43. package/dist/devtools-firebase-auth.js.map +1 -0
  44. package/dist/devtools-harness.d.ts +5 -0
  45. package/dist/devtools-harness.d.ts.map +1 -1
  46. package/dist/devtools-harness.js +60 -21
  47. package/dist/devtools-harness.js.map +1 -1
  48. package/dist/devtools-microsoft-auth.d.ts +42 -0
  49. package/dist/devtools-microsoft-auth.d.ts.map +1 -0
  50. package/dist/devtools-microsoft-auth.js +362 -0
  51. package/dist/devtools-microsoft-auth.js.map +1 -0
  52. package/dist/devtools-microsoft-errors.d.ts +7 -0
  53. package/dist/devtools-microsoft-errors.d.ts.map +1 -0
  54. package/dist/devtools-microsoft-errors.js +60 -0
  55. package/dist/devtools-microsoft-errors.js.map +1 -0
  56. package/dist/devtools-preview.d.ts +15 -13
  57. package/dist/devtools-preview.d.ts.map +1 -1
  58. package/dist/devtools-preview.js +101 -179
  59. package/dist/devtools-preview.js.map +1 -1
  60. package/dist/devtools-rpc-forwarder.d.ts +37 -0
  61. package/dist/devtools-rpc-forwarder.d.ts.map +1 -0
  62. package/dist/devtools-rpc-forwarder.js +251 -0
  63. package/dist/devtools-rpc-forwarder.js.map +1 -0
  64. package/dist/devtools-tool-safety.d.ts +20 -0
  65. package/dist/devtools-tool-safety.d.ts.map +1 -0
  66. package/dist/devtools-tool-safety.js +43 -0
  67. package/dist/devtools-tool-safety.js.map +1 -0
  68. package/dist/preview-session.d.ts.map +1 -1
  69. package/dist/preview-session.js +5 -0
  70. package/dist/preview-session.js.map +1 -1
  71. package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
  72. package/node_modules/@noodle-borg/auth/dist/index.d.ts +1 -0
  73. package/node_modules/@noodle-borg/auth/dist/index.d.ts.map +1 -1
  74. package/node_modules/@noodle-borg/auth/dist/index.js +1 -0
  75. package/node_modules/@noodle-borg/auth/dist/index.js.map +1 -1
  76. package/node_modules/@noodle-borg/auth/dist/mcp-oauth-client.d.ts +56 -0
  77. package/node_modules/@noodle-borg/auth/dist/mcp-oauth-client.d.ts.map +1 -0
  78. package/node_modules/@noodle-borg/auth/dist/mcp-oauth-client.js +367 -0
  79. package/node_modules/@noodle-borg/auth/dist/mcp-oauth-client.js.map +1 -0
  80. package/node_modules/@noodle-borg/service/dist/customer-verifier-boundaries.d.ts +13 -0
  81. package/node_modules/@noodle-borg/service/dist/customer-verifier-boundaries.d.ts.map +1 -0
  82. package/node_modules/@noodle-borg/service/dist/customer-verifier-boundaries.js +71 -0
  83. package/node_modules/@noodle-borg/service/dist/customer-verifier-boundaries.js.map +1 -0
  84. package/node_modules/@noodle-borg/service/dist/customer-verifier.d.ts +1 -1
  85. package/node_modules/@noodle-borg/service/dist/customer-verifier.d.ts.map +1 -1
  86. package/node_modules/@noodle-borg/service/dist/customer-verifier.js +43 -31
  87. package/node_modules/@noodle-borg/service/dist/customer-verifier.js.map +1 -1
  88. package/node_modules/@noodle-borg/service/dist/feedback-operations/bootstrap.d.ts +7 -0
  89. package/node_modules/@noodle-borg/service/dist/feedback-operations/bootstrap.d.ts.map +1 -0
  90. package/node_modules/@noodle-borg/service/dist/feedback-operations/bootstrap.js +23 -0
  91. package/node_modules/@noodle-borg/service/dist/feedback-operations/bootstrap.js.map +1 -0
  92. package/node_modules/@noodle-borg/service/dist/feedback-operations/config.d.ts +12 -0
  93. package/node_modules/@noodle-borg/service/dist/feedback-operations/config.d.ts.map +1 -0
  94. package/node_modules/@noodle-borg/service/dist/feedback-operations/config.js +47 -0
  95. package/node_modules/@noodle-borg/service/dist/feedback-operations/config.js.map +1 -0
  96. package/node_modules/@noodle-borg/service/dist/feedback-operations/contracts.d.ts +24 -0
  97. package/node_modules/@noodle-borg/service/dist/feedback-operations/contracts.d.ts.map +1 -0
  98. package/node_modules/@noodle-borg/service/dist/feedback-operations/contracts.js +2 -0
  99. package/node_modules/@noodle-borg/service/dist/feedback-operations/contracts.js.map +1 -0
  100. package/node_modules/@noodle-borg/service/dist/feedback-operations/delivery-worker.d.ts +29 -0
  101. package/node_modules/@noodle-borg/service/dist/feedback-operations/delivery-worker.d.ts.map +1 -0
  102. package/node_modules/@noodle-borg/service/dist/feedback-operations/delivery-worker.js +256 -0
  103. package/node_modules/@noodle-borg/service/dist/feedback-operations/delivery-worker.js.map +1 -0
  104. package/node_modules/@noodle-borg/service/dist/feedback-operations/linear-client.d.ts +39 -0
  105. package/node_modules/@noodle-borg/service/dist/feedback-operations/linear-client.d.ts.map +1 -0
  106. package/node_modules/@noodle-borg/service/dist/feedback-operations/linear-client.js +142 -0
  107. package/node_modules/@noodle-borg/service/dist/feedback-operations/linear-client.js.map +1 -0
  108. package/node_modules/@noodle-borg/service/dist/feedback-operations/reporter-email.d.ts +33 -0
  109. package/node_modules/@noodle-borg/service/dist/feedback-operations/reporter-email.d.ts.map +1 -0
  110. package/node_modules/@noodle-borg/service/dist/feedback-operations/reporter-email.js +142 -0
  111. package/node_modules/@noodle-borg/service/dist/feedback-operations/reporter-email.js.map +1 -0
  112. package/node_modules/@noodle-borg/service/dist/feedback-operations/slack-card.d.ts +138 -0
  113. package/node_modules/@noodle-borg/service/dist/feedback-operations/slack-card.d.ts.map +1 -0
  114. package/node_modules/@noodle-borg/service/dist/feedback-operations/slack-card.js +199 -0
  115. package/node_modules/@noodle-borg/service/dist/feedback-operations/slack-card.js.map +1 -0
  116. package/node_modules/@noodle-borg/service/dist/feedback-operations/slack-client.d.ts +44 -0
  117. package/node_modules/@noodle-borg/service/dist/feedback-operations/slack-client.d.ts.map +1 -0
  118. package/node_modules/@noodle-borg/service/dist/feedback-operations/slack-client.js +95 -0
  119. package/node_modules/@noodle-borg/service/dist/feedback-operations/slack-client.js.map +1 -0
  120. package/node_modules/@noodle-borg/service/dist/index.d.ts +3 -1
  121. package/node_modules/@noodle-borg/service/dist/index.d.ts.map +1 -1
  122. package/node_modules/@noodle-borg/service/dist/index.js +1 -0
  123. package/node_modules/@noodle-borg/service/dist/index.js.map +1 -1
  124. package/node_modules/@noodle-borg/service/dist/local-devtools-delegated-credentials.d.ts +20 -0
  125. package/node_modules/@noodle-borg/service/dist/local-devtools-delegated-credentials.d.ts.map +1 -0
  126. package/node_modules/@noodle-borg/service/dist/local-devtools-delegated-credentials.js +107 -0
  127. package/node_modules/@noodle-borg/service/dist/local-devtools-delegated-credentials.js.map +1 -0
  128. package/node_modules/@noodle-borg/service/dist/main.js +38 -3
  129. package/node_modules/@noodle-borg/service/dist/main.js.map +1 -1
  130. package/node_modules/@noodle-borg/service/dist/oauth/microsoft.d.ts +5 -0
  131. package/node_modules/@noodle-borg/service/dist/oauth/microsoft.d.ts.map +1 -1
  132. package/node_modules/@noodle-borg/service/dist/oauth/microsoft.js +48 -28
  133. package/node_modules/@noodle-borg/service/dist/oauth/microsoft.js.map +1 -1
  134. package/node_modules/@noodle-borg/service/dist/options.d.ts +14 -0
  135. package/node_modules/@noodle-borg/service/dist/options.d.ts.map +1 -1
  136. package/node_modules/@noodle-borg/service/dist/routes/feedback-operations-dispatch.d.ts +9 -0
  137. package/node_modules/@noodle-borg/service/dist/routes/feedback-operations-dispatch.d.ts.map +1 -0
  138. package/node_modules/@noodle-borg/service/dist/routes/feedback-operations-dispatch.js +53 -0
  139. package/node_modules/@noodle-borg/service/dist/routes/feedback-operations-dispatch.js.map +1 -0
  140. package/node_modules/@noodle-borg/service/dist/routes/feedback.d.ts +2 -0
  141. package/node_modules/@noodle-borg/service/dist/routes/feedback.d.ts.map +1 -1
  142. package/node_modules/@noodle-borg/service/dist/routes/feedback.js +22 -0
  143. package/node_modules/@noodle-borg/service/dist/routes/feedback.js.map +1 -1
  144. package/node_modules/@noodle-borg/service/dist/routes/linear-feedback-webhook.d.ts +17 -0
  145. package/node_modules/@noodle-borg/service/dist/routes/linear-feedback-webhook.d.ts.map +1 -0
  146. package/node_modules/@noodle-borg/service/dist/routes/linear-feedback-webhook.js +141 -0
  147. package/node_modules/@noodle-borg/service/dist/routes/linear-feedback-webhook.js.map +1 -0
  148. package/node_modules/@noodle-borg/service/dist/routes/slack-feedback-actions.d.ts +13 -0
  149. package/node_modules/@noodle-borg/service/dist/routes/slack-feedback-actions.d.ts.map +1 -0
  150. package/node_modules/@noodle-borg/service/dist/routes/slack-feedback-actions.js +99 -0
  151. package/node_modules/@noodle-borg/service/dist/routes/slack-feedback-actions.js.map +1 -0
  152. package/node_modules/@noodle-borg/service/dist/serve-options.d.ts +13 -0
  153. package/node_modules/@noodle-borg/service/dist/serve-options.d.ts.map +1 -1
  154. package/node_modules/@noodle-borg/service/dist/serve.d.ts +3 -0
  155. package/node_modules/@noodle-borg/service/dist/serve.d.ts.map +1 -1
  156. package/node_modules/@noodle-borg/service/dist/serve.js +72 -18
  157. package/node_modules/@noodle-borg/service/dist/serve.js.map +1 -1
  158. package/node_modules/@noodle-borg/service/dist/service-resource-cleanup.d.ts +1 -0
  159. package/node_modules/@noodle-borg/service/dist/service-resource-cleanup.d.ts.map +1 -1
  160. package/node_modules/@noodle-borg/service/dist/service-resource-cleanup.js +2 -0
  161. package/node_modules/@noodle-borg/service/dist/service-resource-cleanup.js.map +1 -1
  162. package/node_modules/@noodle-borg/service/dist/service.d.ts.map +1 -1
  163. package/node_modules/@noodle-borg/service/dist/service.js +6 -0
  164. package/node_modules/@noodle-borg/service/dist/service.js.map +1 -1
  165. package/node_modules/@noodle-borg/service/dist/store/feedback-operations.d.ts +186 -0
  166. package/node_modules/@noodle-borg/service/dist/store/feedback-operations.d.ts.map +1 -0
  167. package/node_modules/@noodle-borg/service/dist/store/feedback-operations.js +483 -0
  168. package/node_modules/@noodle-borg/service/dist/store/feedback-operations.js.map +1 -0
  169. package/node_modules/@noodle-borg/service/dist/store/postgres-feedback-operations.d.ts +35 -0
  170. package/node_modules/@noodle-borg/service/dist/store/postgres-feedback-operations.d.ts.map +1 -0
  171. package/node_modules/@noodle-borg/service/dist/store/postgres-feedback-operations.js +172 -0
  172. package/node_modules/@noodle-borg/service/dist/store/postgres-feedback-operations.js.map +1 -0
  173. package/package.json +1 -1
@@ -0,0 +1,142 @@
1
+ import { z } from 'zod';
2
+ const LINEAR_GRAPHQL_ENDPOINT = 'https://api.linear.app/graphql';
3
+ const REQUEST_TIMEOUT_MS = 10_000;
4
+ const MAX_RESPONSE_BYTES = 512_000;
5
+ const LinearIssueResponseSchema = z.object({
6
+ data: z.object({
7
+ issue: z
8
+ .object({
9
+ id: z.string().min(1),
10
+ identifier: z.string().min(1),
11
+ url: z.url(),
12
+ title: z.string(),
13
+ description: z.string().nullable(),
14
+ team: z.object({ id: z.string().min(1) }),
15
+ state: z.object({
16
+ id: z.string().min(1),
17
+ name: z.string(),
18
+ type: z.enum(['backlog', 'unstarted', 'started', 'completed', 'canceled']),
19
+ }),
20
+ assignee: z.object({ name: z.string() }).nullable(),
21
+ labels: z.object({ nodes: z.array(z.object({ name: z.string() })) }),
22
+ attachments: z.object({ nodes: z.array(z.object({ url: z.url() })) }),
23
+ })
24
+ .nullable(),
25
+ }),
26
+ });
27
+ export class LinearGraphqlFeedbackClient {
28
+ #apiToken;
29
+ #fetch;
30
+ constructor(options) {
31
+ if (options.apiToken.trim() === '')
32
+ throw new Error('Linear API token is required');
33
+ this.#apiToken = options.apiToken;
34
+ this.#fetch = options.fetch ?? globalThis.fetch;
35
+ }
36
+ async getIssue(id, options = {}) {
37
+ const data = await this.#request(`query FeedbackIssue($id: String!) {
38
+ issue(id: $id) {
39
+ id identifier url title description
40
+ team { id }
41
+ state { id name type }
42
+ assignee { name }
43
+ labels { nodes { name } }
44
+ attachments { nodes { url } }
45
+ }
46
+ }`, { id }, options);
47
+ const parsed = LinearIssueResponseSchema.safeParse(data);
48
+ if (!parsed.success)
49
+ throw new Error('Linear returned a malformed issue response');
50
+ const issue = parsed.data.data.issue;
51
+ if (issue === null)
52
+ return undefined;
53
+ return {
54
+ id: issue.id,
55
+ identifier: issue.identifier,
56
+ url: issue.url,
57
+ title: issue.title,
58
+ description: issue.description ?? '',
59
+ teamId: issue.team.id,
60
+ status: issue.state,
61
+ ...(issue.assignee !== null ? { assigneeName: issue.assignee.name } : {}),
62
+ labels: issue.labels.nodes.map((label) => label.name),
63
+ attachments: issue.attachments.nodes.map((attachment) => attachment.url),
64
+ };
65
+ }
66
+ async moveIssueToState(issueId, stateId, options = {}) {
67
+ const response = await this.#request(`mutation StartFeedbackWork($issueId: String!, $stateId: String!) {
68
+ issueUpdate(id: $issueId, input: { stateId: $stateId }) { success }
69
+ }`, { issueId, stateId }, options);
70
+ const success = z
71
+ .object({ data: z.object({ issueUpdate: z.object({ success: z.literal(true) }) }) })
72
+ .safeParse(response);
73
+ if (!success.success)
74
+ throw new Error('Linear rejected the feedback state transition');
75
+ }
76
+ async #request(query, variables, options = {}) {
77
+ const response = await this.#fetch(LINEAR_GRAPHQL_ENDPOINT, {
78
+ method: 'POST',
79
+ redirect: 'error',
80
+ signal: boundedSignal(options.signal),
81
+ headers: {
82
+ authorization: this.#apiToken,
83
+ 'content-type': 'application/json',
84
+ },
85
+ body: JSON.stringify({ query, variables }),
86
+ });
87
+ if (!response.ok)
88
+ throw new Error(`Linear request failed with status ${response.status}`);
89
+ const length = Number(response.headers.get('content-length') ?? '0');
90
+ if (Number.isFinite(length) && length > MAX_RESPONSE_BYTES) {
91
+ throw new Error('Linear response exceeded the size limit');
92
+ }
93
+ const text = await readBoundedText(response, MAX_RESPONSE_BYTES);
94
+ let parsed;
95
+ try {
96
+ parsed = JSON.parse(text);
97
+ }
98
+ catch {
99
+ throw new Error('Linear returned invalid JSON');
100
+ }
101
+ const errors = typeof parsed === 'object' && parsed !== null ? Reflect.get(parsed, 'errors') : undefined;
102
+ if (Array.isArray(errors) && errors.length > 0) {
103
+ throw new Error('Linear GraphQL request failed');
104
+ }
105
+ return parsed;
106
+ }
107
+ }
108
+ function boundedSignal(signal) {
109
+ const timeout = AbortSignal.timeout(REQUEST_TIMEOUT_MS);
110
+ return signal === undefined ? timeout : AbortSignal.any([signal, timeout]);
111
+ }
112
+ async function readBoundedText(response, maxBytes) {
113
+ if (response.body === null)
114
+ return '';
115
+ const reader = response.body.getReader();
116
+ const chunks = [];
117
+ let total = 0;
118
+ try {
119
+ while (true) {
120
+ const { done, value } = await reader.read();
121
+ if (done)
122
+ break;
123
+ total += value.byteLength;
124
+ if (total > maxBytes) {
125
+ await reader.cancel().catch(() => undefined);
126
+ throw new Error('Linear response exceeded the size limit');
127
+ }
128
+ chunks.push(value);
129
+ }
130
+ }
131
+ finally {
132
+ reader.releaseLock();
133
+ }
134
+ const body = new Uint8Array(total);
135
+ let offset = 0;
136
+ for (const chunk of chunks) {
137
+ body.set(chunk, offset);
138
+ offset += chunk.byteLength;
139
+ }
140
+ return new TextDecoder().decode(body);
141
+ }
142
+ //# sourceMappingURL=linear-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-client.js","sourceRoot":"","sources":["../../src/feedback-operations/linear-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { RenderedFeedbackEmail } from './contracts.js';
2
+ export interface FeedbackReporterEmailInput {
3
+ readonly githubIssueNumber: number;
4
+ readonly recipient: string;
5
+ readonly title: string;
6
+ readonly message: string;
7
+ }
8
+ export interface FeedbackReporterEmailSender {
9
+ send(input: FeedbackReporterEmailInput, options?: {
10
+ readonly signal?: AbortSignal;
11
+ }): Promise<{
12
+ readonly providerMessageId: string;
13
+ }>;
14
+ }
15
+ export declare class ResendFeedbackReporterEmailSender implements FeedbackReporterEmailSender {
16
+ #private;
17
+ constructor(options: {
18
+ apiKey: string;
19
+ from: string;
20
+ replyTo: string;
21
+ fetch?: typeof fetch;
22
+ });
23
+ send(input: FeedbackReporterEmailInput, options?: {
24
+ readonly signal?: AbortSignal;
25
+ }): Promise<{
26
+ readonly providerMessageId: string;
27
+ }>;
28
+ }
29
+ export declare function renderFeedbackAcceptedEmail(input: {
30
+ readonly title: string;
31
+ readonly message: string;
32
+ }): RenderedFeedbackEmail;
33
+ //# sourceMappingURL=reporter-email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter-email.d.ts","sourceRoot":"","sources":["../../src/feedback-operations/reporter-email.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAS5D,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,2BAA2B;IAC1C,IAAI,CACF,KAAK,EAAE,0BAA0B,EACjC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAC1C,OAAO,CAAC;QAAE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAED,qBAAa,iCAAkC,YAAW,2BAA2B;;gBAMvE,OAAO,EAAE;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;KACtB;IAOK,IAAI,CACR,KAAK,EAAE,0BAA0B,EACjC,OAAO,GAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GAC9C,OAAO,CAAC;QAAE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,CAAC;CA+BnD;AAOD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,GAAG,qBAAqB,CAkCxB"}
@@ -0,0 +1,142 @@
1
+ import { z } from 'zod';
2
+ import { sanitizedFeedbackText } from './slack-card.js';
3
+ const SUBJECT = "We're looking into your Noodle Seed feedback";
4
+ const RESEND_ENDPOINT = 'https://api.resend.com/emails';
5
+ const DELIVERY_TIMEOUT_MS = 10_000;
6
+ const MAX_PROVIDER_RESPONSE_BYTES = 64_000;
7
+ const ProviderResponseSchema = z.object({ id: z.string().trim().min(1) });
8
+ export class ResendFeedbackReporterEmailSender {
9
+ #apiKey;
10
+ #from;
11
+ #replyTo;
12
+ #fetch;
13
+ constructor(options) {
14
+ this.#apiKey = options.apiKey;
15
+ this.#from = options.from;
16
+ this.#replyTo = options.replyTo;
17
+ this.#fetch = options.fetch ?? globalThis.fetch;
18
+ }
19
+ async send(input, options = {}) {
20
+ const response = await this.#fetch(RESEND_ENDPOINT, {
21
+ method: 'POST',
22
+ redirect: 'error',
23
+ signal: boundedSignal(options.signal),
24
+ headers: {
25
+ authorization: `Bearer ${this.#apiKey}`,
26
+ 'content-type': 'application/json',
27
+ 'idempotency-key': `feedback-accepted/${input.githubIssueNumber}`,
28
+ },
29
+ body: JSON.stringify({
30
+ from: this.#from,
31
+ to: [input.recipient],
32
+ reply_to: this.#replyTo,
33
+ ...renderFeedbackAcceptedEmail(input),
34
+ }),
35
+ });
36
+ if (!response.ok) {
37
+ throw new Error(`feedback email provider rejected request with status ${response.status}`);
38
+ }
39
+ let providerResponse;
40
+ try {
41
+ providerResponse = JSON.parse(await readBoundedText(response, MAX_PROVIDER_RESPONSE_BYTES));
42
+ }
43
+ catch {
44
+ throw new Error('feedback email provider returned an invalid response');
45
+ }
46
+ const parsed = zProviderResponse(providerResponse);
47
+ return { providerMessageId: parsed };
48
+ }
49
+ }
50
+ function boundedSignal(signal) {
51
+ const timeout = AbortSignal.timeout(DELIVERY_TIMEOUT_MS);
52
+ return signal === undefined ? timeout : AbortSignal.any([signal, timeout]);
53
+ }
54
+ export function renderFeedbackAcceptedEmail(input) {
55
+ const title = clean(sanitizedFeedbackText(input.title, 200), 200);
56
+ const message = sanitizedFeedbackText(input.message, 4_000);
57
+ const text = `Hi,
58
+
59
+ Thanks for sharing this feedback with Noodle Seed. I wanted to let you know that our engineering team is now looking into:
60
+
61
+ ${title}
62
+
63
+ ${message}
64
+
65
+ If you'd like to discuss it directly, just reply to this email.
66
+
67
+ — Asad`;
68
+ const html = `<!doctype html>
69
+ <html lang="en">
70
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(SUBJECT)}</title></head>
71
+ <body style="margin:0;background:#f4f2ed;color:#171714;font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;">
72
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="background:#f4f2ed;padding:32px 16px;"><tr><td align="center">
73
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="max-width:600px;background:#fff;border:1px solid #dedbd3;border-radius:16px;">
74
+ <tr><td style="padding:40px;">
75
+ <h1 style="margin:0 0 24px;font-size:28px;line-height:1.2;">We're looking into your feedback</h1>
76
+ <p style="margin:0 0 18px;font-size:16px;line-height:1.65;">Hi,</p>
77
+ <p style="margin:0 0 18px;font-size:16px;line-height:1.65;">Thanks for sharing this feedback with Noodle Seed. I wanted to let you know that our engineering team is now looking into:</p>
78
+ <p style="margin:0 0 10px;font-size:18px;line-height:1.5;"><strong>${escapeHtml(title)}</strong></p>
79
+ <p style="margin:0 0 24px;font-size:16px;line-height:1.65;white-space:pre-wrap;">${escapeHtml(message)}</p>
80
+ <p style="margin:0 0 18px;font-size:16px;line-height:1.65;">If you'd like to discuss it directly, just reply to this email.</p>
81
+ <p style="margin:0;font-size:16px;line-height:1.65;">— Asad</p>
82
+ </td></tr>
83
+ </table>
84
+ </td></tr></table>
85
+ </body>
86
+ </html>`;
87
+ return { subject: SUBJECT, text, html };
88
+ }
89
+ function clean(value, length) {
90
+ return value
91
+ .replace(/[\r\n]+/g, ' ')
92
+ .trim()
93
+ .slice(0, length);
94
+ }
95
+ function escapeHtml(value) {
96
+ return value
97
+ .replaceAll('&', '&amp;')
98
+ .replaceAll('<', '&lt;')
99
+ .replaceAll('>', '&gt;')
100
+ .replaceAll('"', '&quot;')
101
+ .replaceAll("'", '&#039;');
102
+ }
103
+ function zProviderResponse(value) {
104
+ const parsed = ProviderResponseSchema.safeParse(value);
105
+ if (!parsed.success) {
106
+ throw new Error('feedback email provider returned an invalid response');
107
+ }
108
+ return parsed.data.id;
109
+ }
110
+ async function readBoundedText(response, maxBytes) {
111
+ const declaredLength = Number(response.headers.get('content-length'));
112
+ if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
113
+ throw new Error('response exceeds byte limit');
114
+ }
115
+ if (response.body === null)
116
+ return '';
117
+ const reader = response.body.getReader();
118
+ const chunks = [];
119
+ let total = 0;
120
+ try {
121
+ while (true) {
122
+ const { done, value } = await reader.read();
123
+ if (done)
124
+ break;
125
+ total += value.byteLength;
126
+ if (total > maxBytes)
127
+ throw new Error('response exceeds byte limit');
128
+ chunks.push(value);
129
+ }
130
+ }
131
+ finally {
132
+ await reader.cancel().catch(() => undefined);
133
+ }
134
+ const bytes = new Uint8Array(total);
135
+ let offset = 0;
136
+ for (const chunk of chunks) {
137
+ bytes.set(chunk, offset);
138
+ offset += chunk.byteLength;
139
+ }
140
+ return new TextDecoder().decode(bytes);
141
+ }
142
+ //# sourceMappingURL=reporter-email.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter-email.js","sourceRoot":"","sources":["../../src/feedback-operations/reporter-email.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,138 @@
1
+ import { z } from 'zod';
2
+ import type { SlackFeedbackCardInput } from './contracts.js';
3
+ export declare const SlackFeedbackCardSchema: z.ZodObject<{
4
+ text: z.ZodString;
5
+ blocks: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
6
+ type: z.ZodLiteral<"header">;
7
+ text: z.ZodObject<{
8
+ type: z.ZodLiteral<"plain_text">;
9
+ text: z.ZodString;
10
+ emoji: z.ZodOptional<z.ZodBoolean>;
11
+ }, z.core.$strict>;
12
+ }, z.core.$strict>, z.ZodObject<{
13
+ type: z.ZodLiteral<"section">;
14
+ text: z.ZodObject<{
15
+ type: z.ZodLiteral<"mrkdwn">;
16
+ text: z.ZodString;
17
+ }, z.core.$strict>;
18
+ }, z.core.$strict>, z.ZodObject<{
19
+ type: z.ZodLiteral<"context">;
20
+ elements: z.ZodArray<z.ZodObject<{
21
+ type: z.ZodLiteral<"mrkdwn">;
22
+ text: z.ZodString;
23
+ }, z.core.$strict>>;
24
+ }, z.core.$strict>, z.ZodObject<{
25
+ type: z.ZodLiteral<"actions">;
26
+ elements: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
27
+ type: z.ZodLiteral<"button">;
28
+ text: z.ZodObject<{
29
+ type: z.ZodLiteral<"plain_text">;
30
+ text: z.ZodString;
31
+ emoji: z.ZodOptional<z.ZodBoolean>;
32
+ }, z.core.$strict>;
33
+ url: z.ZodURL;
34
+ action_id: z.ZodLiteral<"feedback_open_linear">;
35
+ }, z.core.$strict>, z.ZodObject<{
36
+ type: z.ZodLiteral<"button">;
37
+ text: z.ZodObject<{
38
+ type: z.ZodLiteral<"plain_text">;
39
+ text: z.ZodString;
40
+ emoji: z.ZodOptional<z.ZodBoolean>;
41
+ }, z.core.$strict>;
42
+ style: z.ZodLiteral<"primary">;
43
+ action_id: z.ZodLiteral<"feedback_start_work">;
44
+ value: z.ZodString;
45
+ confirm: z.ZodObject<{
46
+ title: z.ZodObject<{
47
+ type: z.ZodLiteral<"plain_text">;
48
+ text: z.ZodString;
49
+ emoji: z.ZodOptional<z.ZodBoolean>;
50
+ }, z.core.$strict>;
51
+ text: z.ZodObject<{
52
+ type: z.ZodLiteral<"mrkdwn">;
53
+ text: z.ZodString;
54
+ }, z.core.$strict>;
55
+ confirm: z.ZodObject<{
56
+ type: z.ZodLiteral<"plain_text">;
57
+ text: z.ZodString;
58
+ emoji: z.ZodOptional<z.ZodBoolean>;
59
+ }, z.core.$strict>;
60
+ deny: z.ZodObject<{
61
+ type: z.ZodLiteral<"plain_text">;
62
+ text: z.ZodString;
63
+ emoji: z.ZodOptional<z.ZodBoolean>;
64
+ }, z.core.$strict>;
65
+ }, z.core.$strict>;
66
+ }, z.core.$strict>]>>;
67
+ }, z.core.$strict>]>>;
68
+ }, z.core.$strict>;
69
+ export type SlackFeedbackCard = z.infer<typeof SlackFeedbackCardSchema>;
70
+ export declare const SlackFeedbackCardJsonSchema: z.core.ZodStandardJSONSchemaPayload<z.ZodObject<{
71
+ text: z.ZodString;
72
+ blocks: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
73
+ type: z.ZodLiteral<"header">;
74
+ text: z.ZodObject<{
75
+ type: z.ZodLiteral<"plain_text">;
76
+ text: z.ZodString;
77
+ emoji: z.ZodOptional<z.ZodBoolean>;
78
+ }, z.core.$strict>;
79
+ }, z.core.$strict>, z.ZodObject<{
80
+ type: z.ZodLiteral<"section">;
81
+ text: z.ZodObject<{
82
+ type: z.ZodLiteral<"mrkdwn">;
83
+ text: z.ZodString;
84
+ }, z.core.$strict>;
85
+ }, z.core.$strict>, z.ZodObject<{
86
+ type: z.ZodLiteral<"context">;
87
+ elements: z.ZodArray<z.ZodObject<{
88
+ type: z.ZodLiteral<"mrkdwn">;
89
+ text: z.ZodString;
90
+ }, z.core.$strict>>;
91
+ }, z.core.$strict>, z.ZodObject<{
92
+ type: z.ZodLiteral<"actions">;
93
+ elements: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
94
+ type: z.ZodLiteral<"button">;
95
+ text: z.ZodObject<{
96
+ type: z.ZodLiteral<"plain_text">;
97
+ text: z.ZodString;
98
+ emoji: z.ZodOptional<z.ZodBoolean>;
99
+ }, z.core.$strict>;
100
+ url: z.ZodURL;
101
+ action_id: z.ZodLiteral<"feedback_open_linear">;
102
+ }, z.core.$strict>, z.ZodObject<{
103
+ type: z.ZodLiteral<"button">;
104
+ text: z.ZodObject<{
105
+ type: z.ZodLiteral<"plain_text">;
106
+ text: z.ZodString;
107
+ emoji: z.ZodOptional<z.ZodBoolean>;
108
+ }, z.core.$strict>;
109
+ style: z.ZodLiteral<"primary">;
110
+ action_id: z.ZodLiteral<"feedback_start_work">;
111
+ value: z.ZodString;
112
+ confirm: z.ZodObject<{
113
+ title: z.ZodObject<{
114
+ type: z.ZodLiteral<"plain_text">;
115
+ text: z.ZodString;
116
+ emoji: z.ZodOptional<z.ZodBoolean>;
117
+ }, z.core.$strict>;
118
+ text: z.ZodObject<{
119
+ type: z.ZodLiteral<"mrkdwn">;
120
+ text: z.ZodString;
121
+ }, z.core.$strict>;
122
+ confirm: z.ZodObject<{
123
+ type: z.ZodLiteral<"plain_text">;
124
+ text: z.ZodString;
125
+ emoji: z.ZodOptional<z.ZodBoolean>;
126
+ }, z.core.$strict>;
127
+ deny: z.ZodObject<{
128
+ type: z.ZodLiteral<"plain_text">;
129
+ text: z.ZodString;
130
+ emoji: z.ZodOptional<z.ZodBoolean>;
131
+ }, z.core.$strict>;
132
+ }, z.core.$strict>;
133
+ }, z.core.$strict>]>>;
134
+ }, z.core.$strict>]>>;
135
+ }, z.core.$strict>>;
136
+ export declare function renderSlackFeedbackCard(input: SlackFeedbackCardInput): SlackFeedbackCard;
137
+ export declare function sanitizedFeedbackText(value: string, maxLength?: number): string;
138
+ //# sourceMappingURL=slack-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack-card.d.ts","sourceRoot":"","sources":["../../src/feedback-operations/slack-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAyD7D,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAUzB,CAAC;AAEZ,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAEtC,CAAC;AAEH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,sBAAsB,GAAG,iBAAiB,CA8DxF;AAoBD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,SAAqB,GAAG,MAAM,CAE3F"}