@amalgm/channels 0.1.1 → 0.1.3
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/PURPOSE.md +48 -13
- package/README.md +64 -6
- package/dist/host/auth.js +7 -3
- package/dist/host/auth.js.map +1 -1
- package/dist/host/config.d.ts +3 -1
- package/dist/host/config.js +3 -1
- package/dist/host/config.js.map +1 -1
- package/dist/host/inbox-repository.d.ts +10 -0
- package/dist/host/inbox-repository.js +57 -0
- package/dist/host/inbox-repository.js.map +1 -0
- package/dist/host/index.d.ts +4 -0
- package/dist/host/index.js +4 -0
- package/dist/host/index.js.map +1 -1
- package/dist/host/ingress-repository.d.ts +10 -0
- package/dist/host/ingress-repository.js +61 -0
- package/dist/host/ingress-repository.js.map +1 -0
- package/dist/host/main.js +32 -3
- package/dist/host/main.js.map +1 -1
- package/dist/host/repository.d.ts +4 -3
- package/dist/host/repository.js +23 -3
- package/dist/host/repository.js.map +1 -1
- package/dist/host/resend-webhook.d.ts +14 -0
- package/dist/host/resend-webhook.js +172 -0
- package/dist/host/resend-webhook.js.map +1 -0
- package/dist/host/resend.js +4 -0
- package/dist/host/resend.js.map +1 -1
- package/dist/host/server.d.ts +2 -1
- package/dist/host/server.js +85 -17
- package/dist/host/server.js.map +1 -1
- package/dist/host/wakeups.d.ts +22 -0
- package/dist/host/wakeups.js +30 -0
- package/dist/host/wakeups.js.map +1 -0
- package/dist/src/api-error.d.ts +2 -0
- package/dist/src/api-error.js +13 -0
- package/dist/src/api-error.js.map +1 -0
- package/dist/src/cli/arguments.d.ts +20 -0
- package/dist/src/cli/arguments.js +46 -0
- package/dist/src/cli/arguments.js.map +1 -0
- package/dist/src/cli/input.d.ts +6 -0
- package/dist/src/cli/input.js +38 -0
- package/dist/src/cli/input.js.map +1 -0
- package/dist/src/cli/main.d.ts +7 -0
- package/dist/src/cli/main.js +27 -0
- package/dist/src/cli/main.js.map +1 -0
- package/dist/src/cli/run.d.ts +13 -0
- package/dist/src/cli/run.js +47 -0
- package/dist/src/cli/run.js.map +1 -0
- package/dist/src/cli/shell-runtime.d.ts +9 -0
- package/dist/src/cli/shell-runtime.js +106 -0
- package/dist/src/cli/shell-runtime.js.map +1 -0
- package/dist/src/cli-main.d.ts +2 -0
- package/dist/src/cli-main.js +4 -0
- package/dist/src/cli-main.js.map +1 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.js +4 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/client.js +5 -4
- package/dist/src/client.js.map +1 -1
- package/dist/src/command-surface.d.ts +23 -0
- package/dist/src/command-surface.js +53 -0
- package/dist/src/command-surface.js.map +1 -0
- package/dist/src/contract.d.ts +33 -7
- package/dist/src/email/blocks.d.ts +7 -0
- package/dist/src/email/blocks.js +43 -0
- package/dist/src/email/blocks.js.map +1 -0
- package/dist/src/email/escape.d.ts +3 -0
- package/dist/src/email/escape.js +19 -0
- package/dist/src/email/escape.js.map +1 -0
- package/dist/src/email/inbound.d.ts +83 -0
- package/dist/src/email/inbound.js +162 -0
- package/dist/src/email/inbound.js.map +1 -0
- package/dist/src/email/inline.d.ts +1 -0
- package/dist/src/email/inline.js +31 -0
- package/dist/src/email/inline.js.map +1 -0
- package/dist/src/email/markdown.d.ts +1 -0
- package/dist/src/email/markdown.js +117 -0
- package/dist/src/email/markdown.js.map +1 -0
- package/dist/src/email/notification.d.ts +2 -0
- package/dist/src/email/notification.js +18 -0
- package/dist/src/email/notification.js.map +1 -0
- package/dist/src/email/styles.d.ts +33 -0
- package/dist/src/email/styles.js +34 -0
- package/dist/src/email/styles.js.map +1 -0
- package/dist/src/email/system.d.ts +13 -0
- package/dist/src/email/system.js +31 -0
- package/dist/src/email/system.js.map +1 -0
- package/dist/src/email/thread-token.d.ts +8 -0
- package/dist/src/email/thread-token.js +70 -0
- package/dist/src/email/thread-token.js.map +1 -0
- package/dist/src/errors.d.ts +3 -2
- package/dist/src/errors.js +3 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/http.d.ts +2 -0
- package/dist/src/http.js +84 -3
- package/dist/src/http.js.map +1 -1
- package/dist/src/inbox/client.d.ts +7 -0
- package/dist/src/inbox/client.js +79 -0
- package/dist/src/inbox/client.js.map +1 -0
- package/dist/src/inbox/contract.d.ts +37 -0
- package/dist/src/inbox/contract.js +2 -0
- package/dist/src/inbox/contract.js.map +1 -0
- package/dist/src/inbox/events.d.ts +7 -0
- package/dist/src/inbox/events.js +46 -0
- package/dist/src/inbox/events.js.map +1 -0
- package/dist/src/inbox/runner.d.ts +14 -0
- package/dist/src/inbox/runner.js +93 -0
- package/dist/src/inbox/runner.js.map +1 -0
- package/dist/src/inbox/service.d.ts +9 -0
- package/dist/src/inbox/service.js +56 -0
- package/dist/src/inbox/service.js.map +1 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp.js +20 -52
- package/dist/src/mcp.js.map +1 -1
- package/dist/src/service.js +7 -3
- package/dist/src/service.js.map +1 -1
- package/dist/src/validation.d.ts +2 -2
- package/dist/src/validation.js +2 -2
- package/dist/src/validation.js.map +1 -1
- package/dist/src/worker.d.ts +4 -1
- package/dist/src/worker.js +27 -5
- package/dist/src/worker.js.map +1 -1
- package/package.json +12 -5
- package/skills/channels/SKILL.md +14 -14
- package/supabase/migrations/20260903000000_bidirectional_email.sql +630 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { EmailThreadAddressing } from './thread-token.js';
|
|
2
|
+
export interface ReceivedEmail {
|
|
3
|
+
readonly providerEventId: string;
|
|
4
|
+
readonly providerEmailId: string;
|
|
5
|
+
readonly providerMessageId: string;
|
|
6
|
+
readonly from: string;
|
|
7
|
+
readonly to: readonly string[];
|
|
8
|
+
readonly subject: string;
|
|
9
|
+
readonly text?: string | null;
|
|
10
|
+
readonly html?: string | null;
|
|
11
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
12
|
+
readonly receivedAt: string;
|
|
13
|
+
}
|
|
14
|
+
export interface NormalizedReceivedEmail {
|
|
15
|
+
readonly providerEventId: string;
|
|
16
|
+
readonly providerEmailId: string;
|
|
17
|
+
readonly providerMessageId: string;
|
|
18
|
+
readonly senderEmail: string;
|
|
19
|
+
readonly subject: string;
|
|
20
|
+
readonly message: string;
|
|
21
|
+
readonly threadHintId?: string;
|
|
22
|
+
readonly replyMessageIds: readonly string[];
|
|
23
|
+
readonly receivedAt: string;
|
|
24
|
+
}
|
|
25
|
+
export type InboundAdmission = Readonly<{
|
|
26
|
+
kind: 'accepted';
|
|
27
|
+
userId: string;
|
|
28
|
+
messageId: string;
|
|
29
|
+
threadId: string;
|
|
30
|
+
sessionId: string;
|
|
31
|
+
targetComputerId: string;
|
|
32
|
+
targetComputerName: string;
|
|
33
|
+
targetOnline: boolean;
|
|
34
|
+
senderEmail: string;
|
|
35
|
+
subject: string;
|
|
36
|
+
providerMessageId: string;
|
|
37
|
+
references: readonly string[];
|
|
38
|
+
}> | Readonly<{
|
|
39
|
+
kind: 'unknown_sender';
|
|
40
|
+
recordId: string;
|
|
41
|
+
senderEmail: string;
|
|
42
|
+
subject: string;
|
|
43
|
+
providerMessageId: string;
|
|
44
|
+
references: readonly string[];
|
|
45
|
+
}> | Readonly<{
|
|
46
|
+
kind: 'no_computer';
|
|
47
|
+
recordId: string;
|
|
48
|
+
senderEmail: string;
|
|
49
|
+
subject: string;
|
|
50
|
+
providerMessageId: string;
|
|
51
|
+
references: readonly string[];
|
|
52
|
+
}> | Readonly<{
|
|
53
|
+
kind: 'duplicate';
|
|
54
|
+
recordId: string;
|
|
55
|
+
}> | Readonly<{
|
|
56
|
+
kind: 'ignored';
|
|
57
|
+
reason: string;
|
|
58
|
+
}>;
|
|
59
|
+
export interface EmailIngressRepository {
|
|
60
|
+
admit(input: NormalizedReceivedEmail): Promise<InboundAdmission>;
|
|
61
|
+
recordNotice(recordId: string, providerId: string, now: Date): Promise<boolean>;
|
|
62
|
+
applyProviderEvent(input: ProviderEmailEvent): Promise<boolean>;
|
|
63
|
+
}
|
|
64
|
+
export interface ProviderEmailEvent {
|
|
65
|
+
readonly providerEventId: string;
|
|
66
|
+
readonly providerEmailId: string;
|
|
67
|
+
readonly type: 'sent' | 'delivered' | 'failed';
|
|
68
|
+
readonly providerMessageId?: string;
|
|
69
|
+
readonly error?: string;
|
|
70
|
+
readonly occurredAt: string;
|
|
71
|
+
}
|
|
72
|
+
export declare class EmailIngress {
|
|
73
|
+
private readonly repository;
|
|
74
|
+
private readonly addressing;
|
|
75
|
+
constructor(repository: EmailIngressRepository, addressing: EmailThreadAddressing);
|
|
76
|
+
receive(input: ReceivedEmail): Promise<InboundAdmission>;
|
|
77
|
+
providerEvent(input: ProviderEmailEvent): Promise<boolean>;
|
|
78
|
+
repositoryNotice(recordId: string, providerId: string, now: Date): Promise<boolean>;
|
|
79
|
+
}
|
|
80
|
+
/** Only the receiver's aligned DMARC verdict can authorize a visible From address. */
|
|
81
|
+
export declare function authenticatedSender(headers: Readonly<Record<string, string>>, senderEmail: string): boolean;
|
|
82
|
+
/** Reduce provider plaintext to the newly authored reply, never the quoted transcript. */
|
|
83
|
+
export declare function visibleReply(value: string): string;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { ChannelsError } from '../errors.js';
|
|
2
|
+
export class EmailIngress {
|
|
3
|
+
repository;
|
|
4
|
+
addressing;
|
|
5
|
+
constructor(repository, addressing) {
|
|
6
|
+
this.repository = repository;
|
|
7
|
+
this.addressing = addressing;
|
|
8
|
+
}
|
|
9
|
+
async receive(input) {
|
|
10
|
+
const headers = lowerHeaders(input.headers);
|
|
11
|
+
const ignored = ignoredReason(headers);
|
|
12
|
+
if (ignored)
|
|
13
|
+
return Object.freeze({ kind: 'ignored', reason: ignored });
|
|
14
|
+
const senderEmail = sender(input.from);
|
|
15
|
+
if (!authenticatedSender(headers, senderEmail)) {
|
|
16
|
+
return Object.freeze({ kind: 'ignored', reason: 'unauthenticated_sender' });
|
|
17
|
+
}
|
|
18
|
+
const message = emailBody(input.text, input.html);
|
|
19
|
+
const threadHintId = await this.addressing.threadHint(input.to);
|
|
20
|
+
return this.repository.admit(Object.freeze({
|
|
21
|
+
providerEventId: bounded(input.providerEventId, 'providerEventId', 1, 200),
|
|
22
|
+
providerEmailId: bounded(input.providerEmailId, 'providerEmailId', 1, 200),
|
|
23
|
+
providerMessageId: messageId(input.providerMessageId, 'providerMessageId'),
|
|
24
|
+
senderEmail,
|
|
25
|
+
subject: subject(input.subject),
|
|
26
|
+
message,
|
|
27
|
+
...(threadHintId ? { threadHintId } : {}),
|
|
28
|
+
replyMessageIds: Object.freeze(replyIds(headers)),
|
|
29
|
+
receivedAt: timestamp(input.receivedAt, 'receivedAt'),
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
providerEvent(input) {
|
|
33
|
+
return this.repository.applyProviderEvent(Object.freeze({
|
|
34
|
+
providerEventId: bounded(input.providerEventId, 'providerEventId', 1, 200),
|
|
35
|
+
providerEmailId: bounded(input.providerEmailId, 'providerEmailId', 1, 200),
|
|
36
|
+
type: input.type,
|
|
37
|
+
...(input.providerMessageId
|
|
38
|
+
? { providerMessageId: messageId(input.providerMessageId, 'providerMessageId') }
|
|
39
|
+
: {}),
|
|
40
|
+
...(input.error ? { error: bounded(input.error, 'error', 1, 500) } : {}),
|
|
41
|
+
occurredAt: timestamp(input.occurredAt, 'occurredAt'),
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
repositoryNotice(recordId, providerId, now) {
|
|
45
|
+
return this.repository.recordNotice(recordId, providerId, now);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function lowerHeaders(value) {
|
|
49
|
+
return Object.fromEntries(Object.entries(value).map(([name, content]) => [name.toLowerCase(), String(content)]));
|
|
50
|
+
}
|
|
51
|
+
function ignoredReason(headers) {
|
|
52
|
+
const autoSubmitted = headers['auto-submitted']?.toLowerCase();
|
|
53
|
+
if (autoSubmitted && autoSubmitted !== 'no')
|
|
54
|
+
return 'auto_submitted';
|
|
55
|
+
if (/bulk|junk|list/i.test(headers['precedence'] ?? ''))
|
|
56
|
+
return 'bulk_message';
|
|
57
|
+
if (headers['x-autoreply'] || headers['x-autorespond'])
|
|
58
|
+
return 'auto_reply';
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
/** Only the receiver's aligned DMARC verdict can authorize a visible From address. */
|
|
62
|
+
export function authenticatedSender(headers, senderEmail) {
|
|
63
|
+
const fromDomain = senderEmail.slice(senderEmail.lastIndexOf('@') + 1).toLowerCase();
|
|
64
|
+
const results = headers['authentication-results'] ?? '';
|
|
65
|
+
const verdicts = [...results.matchAll(/(?:^|;)\s*dmarc\s*=\s*([a-z_]+)([^;]*)/gi)]
|
|
66
|
+
.map((match) => Object.freeze({
|
|
67
|
+
verdict: match[1]?.toLowerCase() ?? '',
|
|
68
|
+
domain: match[2]?.match(/\bheader\.from\s*=\s*([^\s;()]+)/i)?.[1]
|
|
69
|
+
?.replace(/^['"]|['"]$/g, '').toLowerCase() ?? '',
|
|
70
|
+
}))
|
|
71
|
+
.filter(({ domain }) => domain === fromDomain);
|
|
72
|
+
return verdicts.length > 0
|
|
73
|
+
&& verdicts.every(({ verdict }) => verdict === 'pass');
|
|
74
|
+
}
|
|
75
|
+
function replyIds(headers) {
|
|
76
|
+
const values = `${headers['in-reply-to'] ?? ''} ${headers.references ?? ''}`;
|
|
77
|
+
return [...new Set(values.match(/<[^<>\r\n]{1,500}>/g) ?? [])].slice(-50);
|
|
78
|
+
}
|
|
79
|
+
function emailBody(text, html) {
|
|
80
|
+
const plain = typeof text === 'string' ? text.replaceAll('\r\n', '\n').trim() : '';
|
|
81
|
+
const fallback = visibleReply(plain || htmlText(html ?? ''));
|
|
82
|
+
return bounded(fallback, 'message', 1, 32_000);
|
|
83
|
+
}
|
|
84
|
+
function htmlText(value) {
|
|
85
|
+
return value
|
|
86
|
+
.replace(/<(script|style)[^>]*>[\s\S]*?<\/\1>/gi, ' ')
|
|
87
|
+
.replace(/<blockquote[^>]*>[\s\S]*?<\/blockquote>/gi, ' ')
|
|
88
|
+
.replace(/<div[^>]*class=["'][^"']*gmail_quote[^"']*["'][^>]*>[\s\S]*?<\/div>/gi, ' ')
|
|
89
|
+
.replace(/<br\s*\/?>/gi, '\n')
|
|
90
|
+
.replace(/<\/p\s*>/gi, '\n\n')
|
|
91
|
+
.replace(/<[^>]+>/g, ' ')
|
|
92
|
+
.replace(/ /gi, ' ')
|
|
93
|
+
.replace(/&/gi, '&')
|
|
94
|
+
.replace(/</gi, '<')
|
|
95
|
+
.replace(/>/gi, '>')
|
|
96
|
+
.replace(/"/gi, '"')
|
|
97
|
+
.replace(/'/gi, "'")
|
|
98
|
+
.replace(/[ \t]+/g, ' ')
|
|
99
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
100
|
+
.trim();
|
|
101
|
+
}
|
|
102
|
+
/** Reduce provider plaintext to the newly authored reply, never the quoted transcript. */
|
|
103
|
+
export function visibleReply(value) {
|
|
104
|
+
const lines = value.replaceAll('\r\n', '\n').replaceAll('\r', '\n').split('\n');
|
|
105
|
+
let boundary = lines.length;
|
|
106
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
107
|
+
const line = lines[index]?.trim() ?? '';
|
|
108
|
+
const gmailBoundary = [1, 2, 3, 4].some((count) => /^On\s.{1,500}\bwrote:\s*$/i.test(lines.slice(index, Math.min(lines.length, index + count)).join(' ').replace(/\s+/g, ' ').trim()));
|
|
109
|
+
if (gmailBoundary
|
|
110
|
+
|| /^-{5,}\s*Original Message\s*-{5,}$/i.test(line)
|
|
111
|
+
|| (/^_{5,}$/.test(line) && outlookHeaders(lines, index + 1))
|
|
112
|
+
|| (index > 0 && /^From:\s+\S/i.test(line) && outlookHeaders(lines, index))) {
|
|
113
|
+
boundary = index;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
if (index > 0 && /^>/.test(line) && lines.slice(index).filter((item) => item.trim()).every((item) => /^>/.test(item.trim()))) {
|
|
117
|
+
boundary = index;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const visible = lines.slice(0, boundary).join('\n').trim();
|
|
122
|
+
return visible || value.trim();
|
|
123
|
+
}
|
|
124
|
+
function outlookHeaders(lines, start) {
|
|
125
|
+
const headers = lines.slice(start, Math.min(lines.length, start + 8))
|
|
126
|
+
.map((line) => line.trim().toLowerCase());
|
|
127
|
+
return headers.some((line) => line.startsWith('from:'))
|
|
128
|
+
&& headers.some((line) => line.startsWith('to:') || line.startsWith('sent:') || line.startsWith('date:'))
|
|
129
|
+
&& headers.some((line) => line.startsWith('subject:'));
|
|
130
|
+
}
|
|
131
|
+
function sender(value) {
|
|
132
|
+
const match = String(value).trim().toLowerCase().match(/<?([^<>\s]+@[^<>\s]+)>?$/);
|
|
133
|
+
if (!match?.[1] || match[1].length > 320)
|
|
134
|
+
throw new ChannelsError('validation', 'Sender email is invalid');
|
|
135
|
+
return match[1];
|
|
136
|
+
}
|
|
137
|
+
function subject(value) {
|
|
138
|
+
const clean = String(value ?? '').replace(/[\r\n]+/g, ' ').trim();
|
|
139
|
+
return (clean || '(no subject)').slice(0, 500);
|
|
140
|
+
}
|
|
141
|
+
function messageId(value, name) {
|
|
142
|
+
const clean = bounded(value, name, 3, 500);
|
|
143
|
+
if (!/^<[^<>\r\n]+>$/.test(clean))
|
|
144
|
+
throw new ChannelsError('validation', `${name} is invalid`);
|
|
145
|
+
return clean;
|
|
146
|
+
}
|
|
147
|
+
function timestamp(value, name) {
|
|
148
|
+
const date = new Date(value);
|
|
149
|
+
if (!Number.isFinite(date.getTime()))
|
|
150
|
+
throw new ChannelsError('validation', `${name} is invalid`);
|
|
151
|
+
return date.toISOString();
|
|
152
|
+
}
|
|
153
|
+
function bounded(value, name, minimum, maximum) {
|
|
154
|
+
if (typeof value !== 'string')
|
|
155
|
+
throw new ChannelsError('validation', `${name} must be a string`);
|
|
156
|
+
const clean = value.trim();
|
|
157
|
+
if (clean.length < minimum || clean.length > maximum) {
|
|
158
|
+
throw new ChannelsError('validation', `${name} must be ${minimum}-${maximum} characters`);
|
|
159
|
+
}
|
|
160
|
+
return clean;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=inbound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbound.js","sourceRoot":"","sources":["../../../src/email/inbound.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function renderInline(source: string): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { escapeAttribute, escapeText, safeLink } from './escape.js';
|
|
2
|
+
import { EMAIL } from './styles.js';
|
|
3
|
+
const marker = (index) => `\u0000${index}\u0000`;
|
|
4
|
+
export function renderInline(source) {
|
|
5
|
+
const tokens = [];
|
|
6
|
+
let text = source;
|
|
7
|
+
text = text.replace(/`([^`\n]+)`/g, (_match, code) => keep(tokens, inlineCode(code)));
|
|
8
|
+
text = text.replace(/\[([^\]\n]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g, (_match, label, href) => keep(tokens, link(label, href)));
|
|
9
|
+
text = escapeText(text)
|
|
10
|
+
.replace(/\*\*\*([^*\n]+)\*\*\*/g, '<strong style="color:#ffffff;font-weight:600"><em>$1</em></strong>')
|
|
11
|
+
.replace(/___([^_\n]+)___/g, '<strong style="color:#ffffff;font-weight:600"><em>$1</em></strong>')
|
|
12
|
+
.replace(/\*\*([^*\n]+)\*\*/g, '<strong style="color:#ffffff;font-weight:600">$1</strong>')
|
|
13
|
+
.replace(/__([^_\n]+)__/g, '<strong style="color:#ffffff;font-weight:600">$1</strong>')
|
|
14
|
+
.replace(/(^|\s)\*([^*\n]+)\*(?=\s|[.,!?;:]|$)/g, '$1<em>$2</em>')
|
|
15
|
+
.replace(/(^|\s)_([^_\n]+)_(?=\s|[.,!?;:]|$)/g, '$1<em>$2</em>');
|
|
16
|
+
return text.replace(/\u0000(\d+)\u0000/g, (_match, index) => tokens[Number(index)] ?? '');
|
|
17
|
+
}
|
|
18
|
+
function keep(tokens, html) {
|
|
19
|
+
tokens.push(html);
|
|
20
|
+
return marker(tokens.length - 1);
|
|
21
|
+
}
|
|
22
|
+
function inlineCode(code) {
|
|
23
|
+
return `<code style="background:${EMAIL.color.inset};border:1px solid ${EMAIL.color.border};padding:1.875px 7.5px;border-radius:5.625px;font-size:12px;line-height:1.2;font-family:${EMAIL.font.mono};color:#f5f5f4">${escapeText(code)}</code>`;
|
|
24
|
+
}
|
|
25
|
+
function link(label, rawHref) {
|
|
26
|
+
const href = safeLink(rawHref);
|
|
27
|
+
if (!href)
|
|
28
|
+
return escapeText(label);
|
|
29
|
+
return `<a href="${escapeAttribute(href)}" target="_blank" rel="noreferrer" style="color:${EMAIL.color.link};text-decoration:none">${escapeText(label)}</a>`;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=inline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline.js","sourceRoot":"","sources":["../../../src/email/inline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,MAAM,MAAM,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,SAAS,KAAK,QAAQ,CAAC;AAEjE,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,IAAI,GAAG,MAAM,CAAC;IAElB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9F,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,6CAA6C,EAAE,CACjE,MAAM,EACN,KAAa,EACb,IAAY,EACZ,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAEtC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC;SACpB,OAAO,CAAC,wBAAwB,EAAE,oEAAoE,CAAC;SACvG,OAAO,CAAC,kBAAkB,EAAE,oEAAoE,CAAC;SACjG,OAAO,CAAC,oBAAoB,EAAE,2DAA2D,CAAC;SAC1F,OAAO,CAAC,gBAAgB,EAAE,2DAA2D,CAAC;SACtF,OAAO,CAAC,uCAAuC,EAAE,eAAe,CAAC;SACjE,OAAO,CAAC,qCAAqC,EAAE,eAAe,CAAC,CAAC;IAEnE,OAAO,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AACpG,CAAC;AAED,SAAS,IAAI,CAAC,MAAgB,EAAE,IAAY;IAC1C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClB,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,2BAA2B,KAAK,CAAC,KAAK,CAAC,KAAK,qBAAqB,KAAK,CAAC,KAAK,CAAC,MAAM,2FAA2F,KAAK,CAAC,IAAI,CAAC,IAAI,mBAAmB,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;AACnP,CAAC;AAED,SAAS,IAAI,CAAC,KAAa,EAAE,OAAe;IAC1C,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI;QAAE,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,YAAY,eAAe,CAAC,IAAI,CAAC,mDAAmD,KAAK,CAAC,KAAK,CAAC,IAAI,0BAA0B,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC;AAC/J,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function renderEmailMarkdown(markdown: string): string;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { codeBlock, divider, heading, list, paragraph, quote, table } from './blocks.js';
|
|
2
|
+
import { EMAIL } from './styles.js';
|
|
3
|
+
export function renderEmailMarkdown(markdown) {
|
|
4
|
+
const lines = markdown.replaceAll('\r\n', '\n').replaceAll('\r', '\n').split('\n');
|
|
5
|
+
const blocks = [];
|
|
6
|
+
for (let index = 0; index < lines.length;) {
|
|
7
|
+
const line = lines[index] ?? '';
|
|
8
|
+
const trimmed = line.trim();
|
|
9
|
+
if (!trimmed) {
|
|
10
|
+
index += 1;
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
const fence = trimmed.match(/^```([\w+-]*)\s*$/);
|
|
14
|
+
if (fence) {
|
|
15
|
+
const code = [];
|
|
16
|
+
index += 1;
|
|
17
|
+
while (index < lines.length && !/^```\s*$/.test((lines[index] ?? '').trim())) {
|
|
18
|
+
code.push(lines[index] ?? '');
|
|
19
|
+
index += 1;
|
|
20
|
+
}
|
|
21
|
+
if (index < lines.length)
|
|
22
|
+
index += 1;
|
|
23
|
+
blocks.push(codeBlock(fence[1] ?? '', code.join('\n')));
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const headingMatch = trimmed.match(/^(#{1,6})\s+(.+)$/);
|
|
27
|
+
if (headingMatch) {
|
|
28
|
+
blocks.push(heading(headingMatch[1]?.length ?? 1, headingMatch[2] ?? ''));
|
|
29
|
+
index += 1;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (/^(?:---+|___+|\*\*\*+)\s*$/.test(trimmed)) {
|
|
33
|
+
blocks.push(divider());
|
|
34
|
+
index += 1;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const tableRows = readTable(lines, index);
|
|
38
|
+
if (tableRows) {
|
|
39
|
+
blocks.push(table(tableRows.rows));
|
|
40
|
+
index = tableRows.next;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (/^>\s?/.test(trimmed)) {
|
|
44
|
+
const result = collect(lines, index, (value) => {
|
|
45
|
+
const match = value.trim().match(/^>\s?(.*)$/);
|
|
46
|
+
return match?.[1] ?? null;
|
|
47
|
+
});
|
|
48
|
+
blocks.push(quote(result.values));
|
|
49
|
+
index = result.next;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const unordered = trimmed.match(/^[-*]\s+(.+)$/);
|
|
53
|
+
const ordered = trimmed.match(/^\d+\.\s+(.+)$/);
|
|
54
|
+
if (unordered || ordered) {
|
|
55
|
+
const isOrdered = Boolean(ordered);
|
|
56
|
+
const result = collect(lines, index, (value) => {
|
|
57
|
+
const pattern = isOrdered ? /^\d+\.\s+(.+)$/ : /^[-*]\s+(.+)$/;
|
|
58
|
+
return value.trim().match(pattern)?.[1] ?? null;
|
|
59
|
+
});
|
|
60
|
+
blocks.push(list(isOrdered, result.values));
|
|
61
|
+
index = result.next;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const prose = [];
|
|
65
|
+
while (index < lines.length && !startsBlock(lines, index)) {
|
|
66
|
+
prose.push((lines[index] ?? '').trim());
|
|
67
|
+
index += 1;
|
|
68
|
+
}
|
|
69
|
+
blocks.push(paragraph(prose));
|
|
70
|
+
}
|
|
71
|
+
return blocks.map((block, index) => index === 0
|
|
72
|
+
? block
|
|
73
|
+
: `<div style="margin:${EMAIL.blockGap}px 0 0">${block}</div>`).join('\n');
|
|
74
|
+
}
|
|
75
|
+
function startsBlock(lines, index) {
|
|
76
|
+
const value = (lines[index] ?? '').trim();
|
|
77
|
+
if (!value)
|
|
78
|
+
return true;
|
|
79
|
+
if (/^(?:```|#{1,6}\s|>\s?|[-*]\s+|\d+\.\s+|---+$|___+$|\*\*\*+$)/.test(value))
|
|
80
|
+
return true;
|
|
81
|
+
return readTable(lines, index) !== null;
|
|
82
|
+
}
|
|
83
|
+
function collect(lines, start, parse) {
|
|
84
|
+
const values = [];
|
|
85
|
+
let next = start;
|
|
86
|
+
while (next < lines.length) {
|
|
87
|
+
const value = parse(lines[next] ?? '');
|
|
88
|
+
if (value === null)
|
|
89
|
+
break;
|
|
90
|
+
values.push(value);
|
|
91
|
+
next += 1;
|
|
92
|
+
}
|
|
93
|
+
return { values, next };
|
|
94
|
+
}
|
|
95
|
+
function readTable(lines, start) {
|
|
96
|
+
const header = tableRow(lines[start] ?? '');
|
|
97
|
+
const separator = tableRow(lines[start + 1] ?? '');
|
|
98
|
+
if (!header || !separator || !separator.every((cell) => /^:?-{3,}:?$/.test(cell)))
|
|
99
|
+
return null;
|
|
100
|
+
const rows = [header];
|
|
101
|
+
let next = start + 2;
|
|
102
|
+
while (next < lines.length) {
|
|
103
|
+
const row = tableRow(lines[next] ?? '');
|
|
104
|
+
if (!row)
|
|
105
|
+
break;
|
|
106
|
+
rows.push(row);
|
|
107
|
+
next += 1;
|
|
108
|
+
}
|
|
109
|
+
return { rows, next };
|
|
110
|
+
}
|
|
111
|
+
function tableRow(value) {
|
|
112
|
+
const trimmed = value.trim();
|
|
113
|
+
if (!trimmed.startsWith('|') || !trimmed.endsWith('|'))
|
|
114
|
+
return null;
|
|
115
|
+
return trimmed.slice(1, -1).split('|').map((cell) => cell.trim());
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/email/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { renderEmailMarkdown } from './markdown.js';
|
|
2
|
+
import { EMAIL } from './styles.js';
|
|
3
|
+
/** The approved Engine notification presentation, now owned by Channels. */
|
|
4
|
+
export function renderNotificationEmail(message) {
|
|
5
|
+
const body = renderEmailMarkdown(message);
|
|
6
|
+
return `<!DOCTYPE html>
|
|
7
|
+
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"></head>
|
|
8
|
+
<body style="margin:0;padding:0;background:${EMAIL.color.background};font-family:${EMAIL.font.text}">
|
|
9
|
+
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:${EMAIL.color.background}"><tr><td align="center" style="padding:0">
|
|
10
|
+
<table role="presentation" width="520" cellpadding="0" cellspacing="0" style="max-width:520px;width:100%"><tr><td style="padding:40px 28px 48px">
|
|
11
|
+
<div style="font-size:${EMAIL.bodySize}px;color:${EMAIL.color.text}">${body}</div>
|
|
12
|
+
|
|
13
|
+
<p style="margin:48px 0 0;font-size:12px;color:${EMAIL.color.text}">amalgm.ai</p>
|
|
14
|
+
</td></tr></table>
|
|
15
|
+
</td></tr></table>
|
|
16
|
+
</body></html>`;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=notification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification.js","sourceRoot":"","sources":["../../../src/email/notification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,4EAA4E;AAC5E,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,MAAM,IAAI,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC1C,OAAO;;6CAEoC,KAAK,CAAC,KAAK,CAAC,UAAU,gBAAgB,KAAK,CAAC,IAAI,CAAC,IAAI;4FACN,KAAK,CAAC,KAAK,CAAC,UAAU;;4BAEtF,KAAK,CAAC,QAAQ,YAAY,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI;;qDAE1B,KAAK,CAAC,KAAK,CAAC,IAAI;;;eAGtD,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare const EMAIL: Readonly<{
|
|
2
|
+
font: Readonly<{
|
|
3
|
+
text: "\"SF Pro Text\", \"SF Pro Display\", -apple-system, BlinkMacSystemFont, system-ui, sans-serif";
|
|
4
|
+
mono: "'JetBrains Mono', 'SFMono-Regular', Menlo, monospace";
|
|
5
|
+
}>;
|
|
6
|
+
color: Readonly<{
|
|
7
|
+
background: "#000000";
|
|
8
|
+
text: "#ffffff";
|
|
9
|
+
secondary: "#d6d3d1";
|
|
10
|
+
muted: "#a8a29e";
|
|
11
|
+
border: "#1c1917";
|
|
12
|
+
grid: "#292524";
|
|
13
|
+
inset: "#0a0a0a";
|
|
14
|
+
link: "#60a5fa";
|
|
15
|
+
}>;
|
|
16
|
+
bodySize: 14;
|
|
17
|
+
blockGap: 15;
|
|
18
|
+
}>;
|
|
19
|
+
export declare const BLOCK: Readonly<{
|
|
20
|
+
headingSizes: readonly number[];
|
|
21
|
+
headingLineHeight: 1.35;
|
|
22
|
+
headingWeight: 650;
|
|
23
|
+
paragraphLineHeight: 1.75;
|
|
24
|
+
listPaddingLeft: 24;
|
|
25
|
+
listItemPaddingY: 3.75;
|
|
26
|
+
listItemLineHeight: 1.5;
|
|
27
|
+
quotePaddingLeft: 16;
|
|
28
|
+
codeRadius: 12;
|
|
29
|
+
codePadding: 15;
|
|
30
|
+
tableRadius: 12;
|
|
31
|
+
tableCellPaddingX: 11.25;
|
|
32
|
+
tableCellPaddingY: 5.625;
|
|
33
|
+
}>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const EMAIL = Object.freeze({
|
|
2
|
+
font: Object.freeze({
|
|
3
|
+
text: '"SF Pro Text", "SF Pro Display", -apple-system, BlinkMacSystemFont, system-ui, sans-serif',
|
|
4
|
+
mono: "'JetBrains Mono', 'SFMono-Regular', Menlo, monospace",
|
|
5
|
+
}),
|
|
6
|
+
color: Object.freeze({
|
|
7
|
+
background: '#000000',
|
|
8
|
+
text: '#ffffff',
|
|
9
|
+
secondary: '#d6d3d1',
|
|
10
|
+
muted: '#a8a29e',
|
|
11
|
+
border: '#1c1917',
|
|
12
|
+
grid: '#292524',
|
|
13
|
+
inset: '#0a0a0a',
|
|
14
|
+
link: '#60a5fa',
|
|
15
|
+
}),
|
|
16
|
+
bodySize: 14,
|
|
17
|
+
blockGap: 15,
|
|
18
|
+
});
|
|
19
|
+
export const BLOCK = Object.freeze({
|
|
20
|
+
headingSizes: Object.freeze([18, 16, 15, 14, 14, 14]),
|
|
21
|
+
headingLineHeight: 1.35,
|
|
22
|
+
headingWeight: 650,
|
|
23
|
+
paragraphLineHeight: 1.75,
|
|
24
|
+
listPaddingLeft: 24,
|
|
25
|
+
listItemPaddingY: 3.75,
|
|
26
|
+
listItemLineHeight: 1.5,
|
|
27
|
+
quotePaddingLeft: 16,
|
|
28
|
+
codeRadius: 12,
|
|
29
|
+
codePadding: 15,
|
|
30
|
+
tableRadius: 12,
|
|
31
|
+
tableCellPaddingX: 11.25,
|
|
32
|
+
tableCellPaddingY: 5.625,
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/email/styles.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC;QAClB,IAAI,EAAE,2FAA2F;QACjG,IAAI,EAAE,sDAAsD;KAC7D,CAAC;IACF,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC;QACnB,UAAU,EAAE,SAAS;QACrB,IAAI,EAAE,SAAS;QACf,SAAS,EAAE,SAAS;QACpB,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,SAAS;QACjB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE,SAAS;KAChB,CAAC;IACF,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE;CACb,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACrD,iBAAiB,EAAE,IAAI;IACvB,aAAa,EAAE,GAAG;IAClB,mBAAmB,EAAE,IAAI;IACzB,eAAe,EAAE,EAAE;IACnB,gBAAgB,EAAE,IAAI;IACtB,kBAAkB,EAAE,GAAG;IACvB,gBAAgB,EAAE,EAAE;IACpB,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,EAAE;IACf,WAAW,EAAE,EAAE;IACf,iBAAiB,EAAE,KAAK;IACxB,iBAAiB,EAAE,KAAK;CACzB,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type InboundSystemNotice = Readonly<{
|
|
2
|
+
kind: 'unknown_sender';
|
|
3
|
+
}> | Readonly<{
|
|
4
|
+
kind: 'no_computer';
|
|
5
|
+
}> | Readonly<{
|
|
6
|
+
kind: 'computer_offline';
|
|
7
|
+
computerName: string;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function inboundSystemNotice(notice: InboundSystemNotice): Readonly<{
|
|
10
|
+
subjectPrefix: string;
|
|
11
|
+
text: string;
|
|
12
|
+
html: string;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { renderNotificationEmail } from './notification.js';
|
|
2
|
+
export function inboundSystemNotice(notice) {
|
|
3
|
+
const text = noticeText(notice);
|
|
4
|
+
return Object.freeze({ subjectPrefix: 'Re:', text, html: renderNotificationEmail(text) });
|
|
5
|
+
}
|
|
6
|
+
function noticeText(notice) {
|
|
7
|
+
if (notice.kind === 'unknown_sender') {
|
|
8
|
+
return [
|
|
9
|
+
'## We couldn’t find your Amalgm account',
|
|
10
|
+
'',
|
|
11
|
+
'This email address is not attached to an Amalgm account. Send your message again from the email address you use to sign in.',
|
|
12
|
+
'',
|
|
13
|
+
'[Open Amalgm](https://amalgm.ai)',
|
|
14
|
+
].join('\n');
|
|
15
|
+
}
|
|
16
|
+
if (notice.kind === 'no_computer') {
|
|
17
|
+
return [
|
|
18
|
+
'## No Amalgm computer is available',
|
|
19
|
+
'',
|
|
20
|
+
'Your account does not have a computer that can run this message yet. Open Amalgm on a computer, then send your message again.',
|
|
21
|
+
'',
|
|
22
|
+
'[Open Amalgm](https://amalgm.ai)',
|
|
23
|
+
].join('\n');
|
|
24
|
+
}
|
|
25
|
+
return [
|
|
26
|
+
'## Your message is waiting',
|
|
27
|
+
'',
|
|
28
|
+
`**${notice.computerName}** is offline. We saved your message and will give it to your agent when that computer reconnects. You do not need to resend it.`,
|
|
29
|
+
].join('\n');
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.js","sourceRoot":"","sources":["../../../src/email/system.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAO5D,MAAM,UAAU,mBAAmB,CAAC,MAA2B;IAK7D,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAChC,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC5F,CAAC;AAED,SAAS,UAAU,CAAC,MAA2B;IAC7C,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;QACrC,OAAO;YACL,yCAAyC;YACzC,EAAE;YACF,6HAA6H;YAC7H,EAAE;YACF,kCAAkC;SACnC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QAClC,OAAO;YACL,oCAAoC;YACpC,EAAE;YACF,+HAA+H;YAC/H,EAAE;YACF,kCAAkC;SACnC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IACD,OAAO;QACL,4BAA4B;QAC5B,EAAE;QACF,KAAK,MAAM,CAAC,YAAY,kIAAkI;KAC3J,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Opaque reply addresses route a response without exposing a user or session id. */
|
|
2
|
+
export declare class EmailThreadAddressing {
|
|
3
|
+
#private;
|
|
4
|
+
readonly inboxAddress: string;
|
|
5
|
+
constructor(secret: string, inboxAddress: string);
|
|
6
|
+
replyAddress(threadId: string): Promise<string>;
|
|
7
|
+
threadHint(recipients: readonly string[]): Promise<string | null>;
|
|
8
|
+
}
|