pipework 0.71.0 → 0.72.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/CHANGELOG.md +11 -0
- package/REFERENCE.md +54 -0
- package/dist/core/config/discover.d.ts +2 -1
- package/dist/core/config/discover.d.ts.map +1 -1
- package/dist/core/config/discover.js +2 -56
- package/dist/core/config/discover.js.map +1 -1
- package/dist/core/config/namespace.d.ts +1 -0
- package/dist/core/config/namespace.d.ts.map +1 -1
- package/dist/core/config/schema.d.ts +1 -0
- package/dist/core/config/schema.d.ts.map +1 -1
- package/dist/core/config/schema.js +2 -0
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/config/ts-inline-hooks.d.ts +3 -0
- package/dist/core/config/ts-inline-hooks.d.ts.map +1 -0
- package/dist/core/config/ts-inline-hooks.js +65 -0
- package/dist/core/config/ts-inline-hooks.js.map +1 -0
- package/dist/core/config/ts-register.js +2 -0
- package/dist/core/config/ts-register.js.map +1 -1
- package/dist/core/config/ts-resolve-hooks.d.ts.map +1 -1
- package/dist/core/config/ts-resolve-hooks.js +2 -0
- package/dist/core/config/ts-resolve-hooks.js.map +1 -1
- package/dist/data/migrate/internal-definitions.d.ts.map +1 -1
- package/dist/data/migrate/internal-definitions.js +7 -0
- package/dist/data/migrate/internal-definitions.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/infra/alerts/handle.d.ts.map +1 -1
- package/dist/infra/alerts/handle.js +12 -76
- package/dist/infra/alerts/handle.js.map +1 -1
- package/dist/infra/alerts/sinks.d.ts +17 -21
- package/dist/infra/alerts/sinks.d.ts.map +1 -1
- package/dist/infra/alerts/sinks.js +0 -1
- package/dist/infra/alerts/sinks.js.map +1 -1
- package/dist/infra/outbox/core.d.ts +52 -0
- package/dist/infra/outbox/core.d.ts.map +1 -0
- package/dist/infra/outbox/core.js +91 -0
- package/dist/infra/outbox/core.js.map +1 -0
- package/dist/infra/support/handle.d.ts +271 -0
- package/dist/infra/support/handle.d.ts.map +1 -0
- package/dist/infra/support/handle.js +548 -0
- package/dist/infra/support/handle.js.map +1 -0
- package/dist/infra/support/index.d.ts +3 -0
- package/dist/infra/support/index.d.ts.map +1 -0
- package/dist/infra/support/index.js +2 -0
- package/dist/infra/support/index.js.map +1 -0
- package/dist/infra/support/namespace.d.ts +19 -0
- package/dist/infra/support/namespace.d.ts.map +1 -0
- package/dist/infra/support/namespace.js +9 -0
- package/dist/infra/support/namespace.js.map +1 -0
- package/dist/infra/support/schema.d.ts +214 -0
- package/dist/infra/support/schema.d.ts.map +1 -0
- package/dist/infra/support/schema.js +91 -0
- package/dist/infra/support/schema.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { ConflictError } from '../../core/errors/index.js';
|
|
2
|
+
import type { Queue } from '../../async/jobs/queue.js';
|
|
3
|
+
import type { Handler } from '../../request/di/types.js';
|
|
4
|
+
import type { Mail } from '../email/mail.js';
|
|
5
|
+
import type { ReceivedEmail } from '../email/inbound.js';
|
|
6
|
+
import { type Sink, type SinkDelivery } from '../outbox/core.js';
|
|
7
|
+
import { TICKET_STATES } from './schema.js';
|
|
8
|
+
export type TicketState = typeof TICKET_STATES[number];
|
|
9
|
+
export type SupportEventKind = 'ticket.created' | 'ticket.customer-replied' | 'draft.awaiting-approval';
|
|
10
|
+
/** What a sink receives as `delivery.payload` for a support event. No message bodies. */
|
|
11
|
+
export interface SupportEventPayload {
|
|
12
|
+
readonly kind: SupportEventKind;
|
|
13
|
+
readonly ticketId: string;
|
|
14
|
+
readonly tenantId: string;
|
|
15
|
+
readonly subject: string;
|
|
16
|
+
readonly state: TicketState;
|
|
17
|
+
readonly category: string | null;
|
|
18
|
+
readonly at: string;
|
|
19
|
+
}
|
|
20
|
+
/** A place ticket events are sent: `send(delivery)` gets `delivery.payload` as a `SupportEventPayload`. `alerts.webhook()` and `alerts.memory()` fit where a `SupportSink` is expected. */
|
|
21
|
+
export type SupportSink = Sink<SupportEventPayload>;
|
|
22
|
+
export type SupportDelivery = SinkDelivery<SupportEventPayload>;
|
|
23
|
+
/** What `screen` decides for a received email: `accept` it, `separate` it (open a new ticket, never add to an existing one), or `drop` it. */
|
|
24
|
+
export type ScreenVerdict = 'accept' | 'separate' | 'drop';
|
|
25
|
+
export interface SupportConfig {
|
|
26
|
+
/** The app's mail interface; the only caller of its `send` is `approve`. Its templates must include `support.templates`. */
|
|
27
|
+
readonly mail: Pick<Mail<any>, 'send'>;
|
|
28
|
+
/**
|
|
29
|
+
* Where ticket events go: `alerts.webhook(...)`, `alerts.memory()` or your own `SupportSink`. A delivery's
|
|
30
|
+
* `kind` is the event kind, its `key` the ticket id and its `payload` a `SupportEventPayload`.
|
|
31
|
+
*/
|
|
32
|
+
readonly sinks: readonly SupportSink[];
|
|
33
|
+
/** The queue the events job runs on; its worker surface must run `support.job`. */
|
|
34
|
+
readonly queue: Pick<Queue, 'enqueue'>;
|
|
35
|
+
/**
|
|
36
|
+
* Whether `actorId` may approve replies for `tenantId`. Called by `approve` before anything is read or sent.
|
|
37
|
+
* With rbac: `({ actorId, tenantId }) => rbac.can(actorId, 'support:approve', { tenantId })`.
|
|
38
|
+
*/
|
|
39
|
+
readonly canApprove: (who: {
|
|
40
|
+
actorId: string;
|
|
41
|
+
tenantId: string;
|
|
42
|
+
}) => Promise<boolean>;
|
|
43
|
+
/** The author of a draft may not approve it. Default true. */
|
|
44
|
+
readonly distinctApprover?: boolean;
|
|
45
|
+
/** Template name `approve` sends with; default `'pipework.support.reply'`. The app's mail templates must define it (spread `support.templates`). */
|
|
46
|
+
readonly replyTemplate?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Decides what `receiveEmail` does with a message. Default: virus verdict `FAIL` drops it; DMARC `FAIL`, or SPF and
|
|
49
|
+
* DKIM both `FAIL`, separates it (the From address is probably forged, so it must not add text to a ticket an agent
|
|
50
|
+
* is reading: it always opens a new ticket); anything else, including no verdicts (the folder stand-in), is accepted.
|
|
51
|
+
*/
|
|
52
|
+
readonly screen?: (email: ReceivedEmail) => ScreenVerdict;
|
|
53
|
+
/** Job type of `support.job`; default `'pipework.support.events'`. */
|
|
54
|
+
readonly jobType?: string;
|
|
55
|
+
/** Delivery attempts before an event is given up on; default 10. */
|
|
56
|
+
readonly maxAttempts?: number;
|
|
57
|
+
/** First retry delay, doubling per attempt up to one hour; default 5000. */
|
|
58
|
+
readonly backoffMs?: number;
|
|
59
|
+
}
|
|
60
|
+
export interface Ticket {
|
|
61
|
+
readonly id: string;
|
|
62
|
+
readonly tenantId: string;
|
|
63
|
+
readonly state: TicketState;
|
|
64
|
+
readonly category: string | null;
|
|
65
|
+
readonly subject: string;
|
|
66
|
+
readonly contactEmail: string;
|
|
67
|
+
readonly contactName: string | null;
|
|
68
|
+
readonly userId: string | null;
|
|
69
|
+
/** The email conversation this ticket answers into, or `null` (chat, API, or a second sender in a conversation another ticket holds). */
|
|
70
|
+
readonly conversationId: string | null;
|
|
71
|
+
readonly createdAt: Date;
|
|
72
|
+
readonly updatedAt: Date;
|
|
73
|
+
readonly lastCustomerMessageAt: Date;
|
|
74
|
+
}
|
|
75
|
+
export interface TicketMessage {
|
|
76
|
+
readonly id: string;
|
|
77
|
+
readonly ticketId: string;
|
|
78
|
+
readonly kind: 'inbound' | 'note' | 'draft' | 'outbound';
|
|
79
|
+
readonly channel: 'email' | 'chat' | 'api';
|
|
80
|
+
readonly subject: string | null;
|
|
81
|
+
readonly text: string;
|
|
82
|
+
readonly html: string | null;
|
|
83
|
+
readonly fromAddress: string | null;
|
|
84
|
+
readonly inboundEmailId: string | null;
|
|
85
|
+
/** Stored file ids and names of an inbound email's attachments. */
|
|
86
|
+
readonly attachments: readonly {
|
|
87
|
+
id: string;
|
|
88
|
+
filename: string | null;
|
|
89
|
+
mediaType: string;
|
|
90
|
+
size: number;
|
|
91
|
+
}[] | null;
|
|
92
|
+
readonly draftStatus: 'draft' | 'approved' | 'discarded' | null;
|
|
93
|
+
/** Starts at 1; `editDraft` adds one. `approve` must be given the version the approver read. */
|
|
94
|
+
readonly version: number;
|
|
95
|
+
readonly approvedBy: string | null;
|
|
96
|
+
readonly approvedAt: Date | null;
|
|
97
|
+
/** The `pipework_email_messages` row an approved draft (and its outbound message) was sent as. */
|
|
98
|
+
readonly emailMessageId: string | null;
|
|
99
|
+
readonly createdBy: string | null;
|
|
100
|
+
readonly createdAt: Date;
|
|
101
|
+
}
|
|
102
|
+
export interface TicketLink {
|
|
103
|
+
readonly id: string;
|
|
104
|
+
readonly ticketId: string;
|
|
105
|
+
readonly kind: string;
|
|
106
|
+
readonly ref: string;
|
|
107
|
+
readonly label: string | null;
|
|
108
|
+
readonly createdAt: Date;
|
|
109
|
+
}
|
|
110
|
+
export interface TicketDetail {
|
|
111
|
+
readonly ticket: Ticket;
|
|
112
|
+
/** Oldest first. */
|
|
113
|
+
readonly messages: readonly TicketMessage[];
|
|
114
|
+
readonly links: readonly TicketLink[];
|
|
115
|
+
}
|
|
116
|
+
export interface ListOptions {
|
|
117
|
+
readonly state?: TicketState;
|
|
118
|
+
readonly category?: string;
|
|
119
|
+
readonly limit?: number;
|
|
120
|
+
/** The `next` of a previous page. */
|
|
121
|
+
readonly cursor?: string;
|
|
122
|
+
}
|
|
123
|
+
export interface ListPage {
|
|
124
|
+
/** Newest first. */
|
|
125
|
+
readonly tickets: readonly Ticket[];
|
|
126
|
+
readonly next: string | null;
|
|
127
|
+
}
|
|
128
|
+
export interface DraftInput {
|
|
129
|
+
readonly text: string;
|
|
130
|
+
readonly html?: string;
|
|
131
|
+
/** Default `Re: <ticket subject>`. */
|
|
132
|
+
readonly subject?: string;
|
|
133
|
+
}
|
|
134
|
+
export type ReceiveResult = {
|
|
135
|
+
readonly status: 'received' | 'duplicate';
|
|
136
|
+
readonly ticketId: string;
|
|
137
|
+
readonly created: boolean;
|
|
138
|
+
} | {
|
|
139
|
+
readonly status: 'dropped' | 'no-tenant';
|
|
140
|
+
};
|
|
141
|
+
export interface ReceiveInput {
|
|
142
|
+
readonly channel: 'chat' | 'api';
|
|
143
|
+
readonly contact: {
|
|
144
|
+
readonly email: string;
|
|
145
|
+
readonly name?: string;
|
|
146
|
+
readonly userId?: string;
|
|
147
|
+
};
|
|
148
|
+
readonly text: string;
|
|
149
|
+
readonly html?: string;
|
|
150
|
+
/** Subject of a new ticket; default the first line of `text`. */
|
|
151
|
+
readonly subject?: string;
|
|
152
|
+
/** Adds to this ticket (the contact must be the ticket's) instead of opening one. */
|
|
153
|
+
readonly ticketId?: string;
|
|
154
|
+
}
|
|
155
|
+
/** A draft could not be approved, edited or discarded: it is already approved, discarded, or changed since `expectedVersion`. */
|
|
156
|
+
export declare class DraftStateError extends ConflictError {
|
|
157
|
+
readonly reason: 'approved' | 'discarded' | 'changed' | 'not-awaiting-approval';
|
|
158
|
+
constructor(reason: 'approved' | 'discarded' | 'changed' | 'not-awaiting-approval', message: string);
|
|
159
|
+
}
|
|
160
|
+
/** The calls on one tenant's tickets. Each also exists as `<name>For(tenantId, ...)` for callers with no tenant in the Flow. */
|
|
161
|
+
export interface TicketApi {
|
|
162
|
+
get(ticketId: string): Promise<TicketDetail>;
|
|
163
|
+
list(options?: ListOptions): Promise<ListPage>;
|
|
164
|
+
/** `null` clears it. */
|
|
165
|
+
setCategory(ticketId: string, category: string | null): Promise<Ticket>;
|
|
166
|
+
/** Moves the ticket along the state machine; an illegal move throws `InvalidTransitionError`. `awaiting_approval` and `answered` are reached only by drafting and approving. */
|
|
167
|
+
transition(ticketId: string, to: TicketState): Promise<Ticket>;
|
|
168
|
+
/** An internal note: stored, audited, never sent. */
|
|
169
|
+
addNote(ticketId: string, text: string): Promise<TicketMessage>;
|
|
170
|
+
link(ticketId: string, link: {
|
|
171
|
+
kind: string;
|
|
172
|
+
ref: string;
|
|
173
|
+
label?: string;
|
|
174
|
+
}): Promise<TicketLink>;
|
|
175
|
+
/**
|
|
176
|
+
* Stores a draft reply and moves the ticket to `awaiting_approval` (from `open` through `triaged`).
|
|
177
|
+
* A ticket has one live draft: a new draft discards the previous. Nothing is sent.
|
|
178
|
+
*/
|
|
179
|
+
draftReply(ticketId: string, draft: DraftInput): Promise<{
|
|
180
|
+
draftId: string;
|
|
181
|
+
version: number;
|
|
182
|
+
}>;
|
|
183
|
+
/** Changes the live draft's content and adds one to its version; the editor becomes its author for `distinctApprover`. */
|
|
184
|
+
editDraft(draftId: string, draft: Partial<DraftInput>): Promise<{
|
|
185
|
+
draftId: string;
|
|
186
|
+
version: number;
|
|
187
|
+
}>;
|
|
188
|
+
/** Discards the live draft; the ticket goes back to `triaged`. */
|
|
189
|
+
discardDraft(draftId: string): Promise<void>;
|
|
190
|
+
/**
|
|
191
|
+
* Approves and sends a draft. The actor is the Flow's `auth.userId`. Refused (`ForbiddenError`) when `canApprove`
|
|
192
|
+
* says no or, with `distinctApprover`, when the actor wrote the draft. Refused with `DraftStateError` when the draft
|
|
193
|
+
* is approved, discarded or at another version than `expectedVersion`. In one transaction the draft is marked
|
|
194
|
+
* approved (approver and time recorded), exactly its text and html are handed to `mail.send` as a reply in the
|
|
195
|
+
* ticket's conversation, an outbound message is stored and the ticket becomes `answered`.
|
|
196
|
+
*/
|
|
197
|
+
approve(draftId: string, options: {
|
|
198
|
+
expectedVersion: number;
|
|
199
|
+
}): Promise<{
|
|
200
|
+
messageId: string;
|
|
201
|
+
emailMessageId: string;
|
|
202
|
+
}>;
|
|
203
|
+
}
|
|
204
|
+
type WithFor<T> = T & {
|
|
205
|
+
[K in keyof T & string as `${K}For`]: T[K] extends (...args: infer A) => infer R ? (tenantId: string, ...args: A) => R : never;
|
|
206
|
+
};
|
|
207
|
+
export interface Support extends WithFor<TicketApi> {
|
|
208
|
+
/**
|
|
209
|
+
* Hands a received email to the ticket system; call it from `mail.inbound`'s `onMessage`. It uses `email.tenantId`
|
|
210
|
+
* (none: logged, `{ status: 'no-tenant' }`) and is idempotent on `email.id`. A message `screen` drops (default: virus
|
|
211
|
+
* verdict `FAIL`) opens nothing and is audited; one it separates (default: DMARC `FAIL`, or SPF and DKIM both `FAIL`)
|
|
212
|
+
* always opens a new ticket and never adds to an existing one, because a forged From address must not add text to a
|
|
213
|
+
* ticket the agent is reading. A new conversation opens a ticket; a message in a conversation that
|
|
214
|
+
* has a ticket joins it only when its sender is the ticket's contact (threading is not authentication), and
|
|
215
|
+
* otherwise opens a new ticket, tied to the conversation if no ticket holds it yet. A customer message moves the
|
|
216
|
+
* ticket to `open` and discards a live draft.
|
|
217
|
+
*/
|
|
218
|
+
receiveEmail(email: ReceivedEmail): Promise<ReceiveResult>;
|
|
219
|
+
/** A customer message from another channel; same rules as `receiveEmail`. */
|
|
220
|
+
receive(tenantId: string, input: ReceiveInput): Promise<ReceiveResult>;
|
|
221
|
+
/** The job to add to a worker surface's `jobs`: delivers ticket events to the sinks. */
|
|
222
|
+
readonly job: Handler<Record<string, unknown>, unknown>;
|
|
223
|
+
/** What one run of `job` does; callable from a test. Needs a Flow. */
|
|
224
|
+
tick(): Promise<{
|
|
225
|
+
delivered: number;
|
|
226
|
+
retried: number;
|
|
227
|
+
failed: number;
|
|
228
|
+
}>;
|
|
229
|
+
/** Event deliveries, oldest first, for a ticket or all. */
|
|
230
|
+
deliveries(options?: {
|
|
231
|
+
ticketId?: string;
|
|
232
|
+
}): Promise<readonly {
|
|
233
|
+
id: string;
|
|
234
|
+
ticketId: string;
|
|
235
|
+
kind: SupportEventKind;
|
|
236
|
+
sink: string;
|
|
237
|
+
attempts: number;
|
|
238
|
+
deliveredAt: Date | null;
|
|
239
|
+
failedAt: Date | null;
|
|
240
|
+
lastError: string | null;
|
|
241
|
+
}[]>;
|
|
242
|
+
}
|
|
243
|
+
/** Mail templates for `mail.create({ templates: { ...support.templates, ... } })`: the reply is rendered verbatim from the approved draft, nothing added. */
|
|
244
|
+
export declare const supportTemplates: {
|
|
245
|
+
readonly 'pipework.support.reply': ({ subject, text, html }: {
|
|
246
|
+
subject: string;
|
|
247
|
+
text: string;
|
|
248
|
+
html?: string | null;
|
|
249
|
+
}) => {
|
|
250
|
+
subject: string;
|
|
251
|
+
text: string;
|
|
252
|
+
html?: string;
|
|
253
|
+
};
|
|
254
|
+
};
|
|
255
|
+
/**
|
|
256
|
+
* Creates the support handle: tickets for a tenant's customers, opened from received email, with replies
|
|
257
|
+
* sent only after an approval.
|
|
258
|
+
*
|
|
259
|
+
* Needs blueprint `support: {}` (tables `support_ticket`, `support_message`, `support_link` with forced
|
|
260
|
+
* row-level security, and the event outbox `support_event_delivery`) and, for email, `email: {}`.
|
|
261
|
+
* The app's mail templates must include `support.templates`, which render an approved draft verbatim.
|
|
262
|
+
*
|
|
263
|
+
* The only code path that sends a reply is `approve`: it needs an actor that `canApprove` accepts (and, by
|
|
264
|
+
* default, who is not the draft's author), and hands `mail.send` exactly the approved text and html in the
|
|
265
|
+
* ticket's conversation. Events (`ticket.created`, `ticket.customer-replied`, `draft.awaiting-approval`)
|
|
266
|
+
* go to the sinks through an outbox with retries, delivered by `job` or `tick()`. Every change is a
|
|
267
|
+
* `SupportTicket:<verb>` audit record under the Flow's open trace step.
|
|
268
|
+
*/
|
|
269
|
+
export declare function createSupport(config: SupportConfig): Support;
|
|
270
|
+
export {};
|
|
271
|
+
//# sourceMappingURL=handle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle.d.ts","sourceRoot":"","sources":["../../../src/infra/support/handle.ts"],"names":[],"mappings":"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"}
|