automate.ax 0.3.1 → 0.4.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/README.md +58 -6
- package/dist/automation/account-planning.d.ts +17 -0
- package/dist/automation/account-planning.d.ts.map +1 -0
- package/dist/automation/account-planning.js +48 -0
- package/dist/automation/actions.d.ts +2 -1
- package/dist/automation/actions.d.ts.map +1 -1
- package/dist/automation/actions.js +3 -36
- package/dist/cli/commands/deploy.d.ts.map +1 -1
- package/dist/cli/commands/deploy.js +4 -4
- package/dist/cli/usage.d.ts +2 -1
- package/dist/cli/usage.d.ts.map +1 -1
- package/dist/cli/usage.js +2 -1
- package/dist/components/core/actions.d.ts +29 -0
- package/dist/components/core/actions.d.ts.map +1 -0
- package/dist/components/core/actions.js +57 -0
- package/dist/components/core/index.d.ts +3 -0
- package/dist/components/core/index.d.ts.map +1 -0
- package/dist/components/core/index.js +2 -0
- package/dist/components/core/triggers.d.ts +21 -0
- package/dist/components/core/triggers.d.ts.map +1 -0
- package/dist/components/core/triggers.js +9 -0
- package/dist/components/gmail/actions/add-label.d.ts +12 -0
- package/dist/components/gmail/actions/add-label.d.ts.map +1 -0
- package/dist/components/gmail/actions/add-label.js +33 -0
- package/dist/components/gmail/actions/archive.d.ts +9 -0
- package/dist/components/gmail/actions/archive.d.ts.map +1 -0
- package/dist/components/gmail/actions/archive.js +7 -0
- package/dist/components/gmail/actions/create-label.d.ts +43 -0
- package/dist/components/gmail/actions/create-label.d.ts.map +1 -0
- package/dist/components/gmail/actions/create-label.js +27 -0
- package/dist/components/gmail/actions/delete-draft.d.ts +6 -0
- package/dist/components/gmail/actions/delete-draft.d.ts.map +1 -0
- package/dist/components/gmail/actions/delete-draft.js +20 -0
- package/dist/components/gmail/actions/delete-label.d.ts +6 -0
- package/dist/components/gmail/actions/delete-label.d.ts.map +1 -0
- package/dist/components/gmail/actions/delete-label.js +22 -0
- package/dist/components/gmail/actions/draft-email.d.ts +66 -0
- package/dist/components/gmail/actions/draft-email.d.ts.map +1 -0
- package/dist/components/gmail/actions/draft-email.js +32 -0
- package/dist/components/gmail/actions/draft-reply.d.ts +67 -0
- package/dist/components/gmail/actions/draft-reply.d.ts.map +1 -0
- package/dist/components/gmail/actions/draft-reply.js +42 -0
- package/dist/components/gmail/actions/forward.d.ts +67 -0
- package/dist/components/gmail/actions/forward.d.ts.map +1 -0
- package/dist/components/gmail/actions/forward.js +130 -0
- package/dist/components/gmail/actions/get-draft.d.ts +66 -0
- package/dist/components/gmail/actions/get-draft.d.ts.map +1 -0
- package/dist/components/gmail/actions/get-draft.js +28 -0
- package/dist/components/gmail/actions/get-message.d.ts +68 -0
- package/dist/components/gmail/actions/get-message.d.ts.map +1 -0
- package/dist/components/gmail/actions/get-message.js +24 -0
- package/dist/components/gmail/actions/get-messages.d.ts +63 -0
- package/dist/components/gmail/actions/get-messages.d.ts.map +1 -0
- package/dist/components/gmail/actions/get-messages.js +23 -0
- package/dist/components/gmail/actions/get-profile.d.ts +8 -0
- package/dist/components/gmail/actions/get-profile.d.ts.map +1 -0
- package/dist/components/gmail/actions/get-profile.js +23 -0
- package/dist/components/gmail/actions/get-raw-message.d.ts +11 -0
- package/dist/components/gmail/actions/get-raw-message.d.ts.map +1 -0
- package/dist/components/gmail/actions/get-raw-message.js +28 -0
- package/dist/components/gmail/actions/get-thread.d.ts +67 -0
- package/dist/components/gmail/actions/get-thread.d.ts.map +1 -0
- package/dist/components/gmail/actions/get-thread.js +28 -0
- package/dist/components/gmail/actions/has-label.d.ts +7 -0
- package/dist/components/gmail/actions/has-label.d.ts.map +1 -0
- package/dist/components/gmail/actions/has-label.js +23 -0
- package/dist/components/gmail/actions/index.d.ts +42 -0
- package/dist/components/gmail/actions/index.d.ts.map +1 -0
- package/dist/components/gmail/actions/index.js +41 -0
- package/dist/components/gmail/actions/is-important.d.ts +5 -0
- package/dist/components/gmail/actions/is-important.d.ts.map +1 -0
- package/dist/components/gmail/actions/is-important.js +3 -0
- package/dist/components/gmail/actions/is-starred.d.ts +5 -0
- package/dist/components/gmail/actions/is-starred.d.ts.map +1 -0
- package/dist/components/gmail/actions/is-starred.js +3 -0
- package/dist/components/gmail/actions/is-unread.d.ts +5 -0
- package/dist/components/gmail/actions/is-unread.d.ts.map +1 -0
- package/dist/components/gmail/actions/is-unread.js +3 -0
- package/dist/components/gmail/actions/list-labels.d.ts +27 -0
- package/dist/components/gmail/actions/list-labels.d.ts.map +1 -0
- package/dist/components/gmail/actions/list-labels.js +15 -0
- package/dist/components/gmail/actions/mark-as-important.d.ts +5 -0
- package/dist/components/gmail/actions/mark-as-important.d.ts.map +1 -0
- package/dist/components/gmail/actions/mark-as-important.js +3 -0
- package/dist/components/gmail/actions/mark-as-not-spam.d.ts +5 -0
- package/dist/components/gmail/actions/mark-as-not-spam.d.ts.map +1 -0
- package/dist/components/gmail/actions/mark-as-not-spam.js +3 -0
- package/dist/components/gmail/actions/mark-as-read.d.ts +5 -0
- package/dist/components/gmail/actions/mark-as-read.d.ts.map +1 -0
- package/dist/components/gmail/actions/mark-as-read.js +3 -0
- package/dist/components/gmail/actions/mark-as-spam.d.ts +5 -0
- package/dist/components/gmail/actions/mark-as-spam.d.ts.map +1 -0
- package/dist/components/gmail/actions/mark-as-spam.js +3 -0
- package/dist/components/gmail/actions/mark-as-unread.d.ts +5 -0
- package/dist/components/gmail/actions/mark-as-unread.d.ts.map +1 -0
- package/dist/components/gmail/actions/mark-as-unread.js +3 -0
- package/dist/components/gmail/actions/modify-labels.d.ts +12 -0
- package/dist/components/gmail/actions/modify-labels.d.ts.map +1 -0
- package/dist/components/gmail/actions/modify-labels.js +41 -0
- package/dist/components/gmail/actions/move-to-inbox.d.ts +5 -0
- package/dist/components/gmail/actions/move-to-inbox.d.ts.map +1 -0
- package/dist/components/gmail/actions/move-to-inbox.js +3 -0
- package/dist/components/gmail/actions/remove-label.d.ts +12 -0
- package/dist/components/gmail/actions/remove-label.d.ts.map +1 -0
- package/dist/components/gmail/actions/remove-label.js +33 -0
- package/dist/components/gmail/actions/reply-thread.d.ts +65 -0
- package/dist/components/gmail/actions/reply-thread.d.ts.map +1 -0
- package/dist/components/gmail/actions/reply-thread.js +35 -0
- package/dist/components/gmail/actions/reply.d.ts +66 -0
- package/dist/components/gmail/actions/reply.d.ts.map +1 -0
- package/dist/components/gmail/actions/reply.js +23 -0
- package/dist/components/gmail/actions/search-drafts.d.ts +18 -0
- package/dist/components/gmail/actions/search-drafts.d.ts.map +1 -0
- package/dist/components/gmail/actions/search-drafts.js +50 -0
- package/dist/components/gmail/actions/search-messages.d.ts +16 -0
- package/dist/components/gmail/actions/search-messages.d.ts.map +1 -0
- package/dist/components/gmail/actions/search-messages.js +45 -0
- package/dist/components/gmail/actions/search-threads.d.ts +15 -0
- package/dist/components/gmail/actions/search-threads.d.ts.map +1 -0
- package/dist/components/gmail/actions/search-threads.js +43 -0
- package/dist/components/gmail/actions/send-draft.d.ts +11 -0
- package/dist/components/gmail/actions/send-draft.d.ts.map +1 -0
- package/dist/components/gmail/actions/send-draft.js +18 -0
- package/dist/components/gmail/actions/send-email.d.ts +65 -0
- package/dist/components/gmail/actions/send-email.d.ts.map +1 -0
- package/dist/components/gmail/actions/send-email.js +35 -0
- package/dist/components/gmail/actions/star.d.ts +5 -0
- package/dist/components/gmail/actions/star.d.ts.map +1 -0
- package/dist/components/gmail/actions/star.js +3 -0
- package/dist/components/gmail/actions/trash.d.ts +15 -0
- package/dist/components/gmail/actions/trash.d.ts.map +1 -0
- package/dist/components/gmail/actions/trash.js +26 -0
- package/dist/components/gmail/actions/unmark-as-important.d.ts +5 -0
- package/dist/components/gmail/actions/unmark-as-important.d.ts.map +1 -0
- package/dist/components/gmail/actions/unmark-as-important.js +3 -0
- package/dist/components/gmail/actions/unstar.d.ts +5 -0
- package/dist/components/gmail/actions/unstar.d.ts.map +1 -0
- package/dist/components/gmail/actions/unstar.js +3 -0
- package/dist/components/gmail/actions/untrash.d.ts +15 -0
- package/dist/components/gmail/actions/untrash.d.ts.map +1 -0
- package/dist/components/gmail/actions/untrash.js +26 -0
- package/dist/components/gmail/actions/update-draft.d.ts +67 -0
- package/dist/components/gmail/actions/update-draft.d.ts.map +1 -0
- package/dist/components/gmail/actions/update-draft.js +67 -0
- package/dist/components/gmail/actions/update-label.d.ts +44 -0
- package/dist/components/gmail/actions/update-label.d.ts.map +1 -0
- package/dist/components/gmail/actions/update-label.js +38 -0
- package/dist/components/gmail/index.d.ts +5 -0
- package/dist/components/gmail/index.d.ts.map +1 -0
- package/dist/components/gmail/index.js +4 -0
- package/dist/components/gmail/lib/action-factories.d.ts +27 -0
- package/dist/components/gmail/lib/action-factories.d.ts.map +1 -0
- package/dist/components/gmail/lib/action-factories.js +55 -0
- package/dist/components/gmail/lib/gmail.d.ts +178 -0
- package/dist/components/gmail/lib/gmail.d.ts.map +1 -0
- package/dist/components/gmail/lib/gmail.js +411 -0
- package/dist/components/gmail/lib/schemas.d.ts +380 -0
- package/dist/components/gmail/lib/schemas.d.ts.map +1 -0
- package/dist/components/gmail/lib/schemas.js +226 -0
- package/dist/components/gmail/lib/scopes.d.ts +10 -0
- package/dist/components/gmail/lib/scopes.d.ts.map +1 -0
- package/dist/components/gmail/lib/scopes.js +16 -0
- package/dist/components/gmail/triggers/index.d.ts +2 -0
- package/dist/components/gmail/triggers/index.d.ts.map +1 -0
- package/dist/components/gmail/triggers/index.js +1 -0
- package/dist/components/gmail/triggers/on-new-email.d.ts +75 -0
- package/dist/components/gmail/triggers/on-new-email.d.ts.map +1 -0
- package/dist/components/gmail/triggers/on-new-email.js +30 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/package.json +26 -6
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { type gmail_v1 } from "@googleapis/gmail";
|
|
2
|
+
import { type Address } from "postal-mime";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { ATTACHMENT_INPUT_SCHEMA, DRAFT_IDENTIFIER_SCHEMA, LABEL_SCHEMA, MESSAGE_METADATA_SCHEMA, MESSAGE_SCHEMA, RECIPIENT_SCHEMA, REPLY_OPTIONS_SCHEMA } from "./schemas.js";
|
|
5
|
+
/** Internal options for constructing one RFC 5322 message. */
|
|
6
|
+
export interface BuildMessageOptions {
|
|
7
|
+
/** Files and inline MIME parts attached to the message. */
|
|
8
|
+
attachments?: z.input<typeof ATTACHMENT_INPUT_SCHEMA>[];
|
|
9
|
+
/** Blind-copy recipients. */
|
|
10
|
+
bcc?: z.input<typeof RECIPIENT_SCHEMA> | z.input<typeof RECIPIENT_SCHEMA>[];
|
|
11
|
+
/** Carbon-copy recipients. */
|
|
12
|
+
cc?: z.input<typeof RECIPIENT_SCHEMA> | z.input<typeof RECIPIENT_SCHEMA>[];
|
|
13
|
+
/** Sender address or configured Gmail send-as alias. */
|
|
14
|
+
from?: z.input<typeof RECIPIENT_SCHEMA>;
|
|
15
|
+
/** Additional RFC 5322 headers. */
|
|
16
|
+
headers?: Record<string, string>;
|
|
17
|
+
/** HTML message body. */
|
|
18
|
+
html?: string;
|
|
19
|
+
/** RFC 5322 Message-ID this message replies to. */
|
|
20
|
+
inReplyTo?: string;
|
|
21
|
+
/** Importance priority encoded into standard message headers. */
|
|
22
|
+
priority?: "high" | "normal" | "low";
|
|
23
|
+
/** RFC 5322 Message-IDs in the conversation ancestry. */
|
|
24
|
+
references?: string[];
|
|
25
|
+
/** Addresses that should receive replies. */
|
|
26
|
+
replyTo?: z.input<typeof RECIPIENT_SCHEMA> | z.input<typeof RECIPIENT_SCHEMA>[];
|
|
27
|
+
/** Message subject line. */
|
|
28
|
+
subject?: string;
|
|
29
|
+
/** Plain-text message body. */
|
|
30
|
+
text?: string;
|
|
31
|
+
/** Primary recipients. */
|
|
32
|
+
to?: z.input<typeof RECIPIENT_SCHEMA> | z.input<typeof RECIPIENT_SCHEMA>[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates the official Gmail client from a resolved Google integration secret.
|
|
36
|
+
*
|
|
37
|
+
* @param secret - Refreshed Google integration secret.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getGmailApi(secret: Record<string, unknown>): gmail_v1.Gmail;
|
|
40
|
+
/**
|
|
41
|
+
* Builds the RFC 5322 message Gmail expects in its `raw` field.
|
|
42
|
+
*
|
|
43
|
+
* Missing plain text is derived from HTML.
|
|
44
|
+
*
|
|
45
|
+
* @param options - Message recipients, content, headers, and attachments.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildRawMessage(options: BuildMessageOptions): Promise<string>;
|
|
48
|
+
/**
|
|
49
|
+
* Resolves a Gmail label name or ID to its canonical ID.
|
|
50
|
+
*
|
|
51
|
+
* @param gmailApi - Authenticated Gmail client.
|
|
52
|
+
* @param labelSearch - Label display name or ID.
|
|
53
|
+
*/
|
|
54
|
+
export declare function findLabelId(gmailApi: gmail_v1.Gmail, labelSearch: string): Promise<string>;
|
|
55
|
+
/**
|
|
56
|
+
* Resolves Gmail label names or IDs with one label-list request.
|
|
57
|
+
*
|
|
58
|
+
* @param gmailApi - Authenticated Gmail client.
|
|
59
|
+
* @param labelSearches - Label display names or IDs.
|
|
60
|
+
*/
|
|
61
|
+
export declare function findLabelIds(gmailApi: gmail_v1.Gmail, labelSearches: string[]): Promise<string[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Normalizes a raw Gmail API message into the public message representation.
|
|
64
|
+
*
|
|
65
|
+
* @param rawMessage - Gmail message fetched with `format: "raw"`.
|
|
66
|
+
*/
|
|
67
|
+
export declare function getGmailMessage(rawMessage: gmail_v1.Schema$Message): Promise<z.output<typeof MESSAGE_SCHEMA>>;
|
|
68
|
+
/**
|
|
69
|
+
* Resolves the headers and recipients needed to create a reply.
|
|
70
|
+
*
|
|
71
|
+
* @param gmailApi - Authenticated Gmail client.
|
|
72
|
+
* @param message - Gmail message receiving the reply.
|
|
73
|
+
* @param replyAll - Whether to include the original To and Cc recipients.
|
|
74
|
+
*/
|
|
75
|
+
export declare function getReplyOptions(gmailApi: gmail_v1.Gmail, message: gmail_v1.Schema$Message, replyAll: boolean): Promise<{
|
|
76
|
+
cc: string[] | undefined;
|
|
77
|
+
inReplyTo: string;
|
|
78
|
+
references: string[];
|
|
79
|
+
subject: string;
|
|
80
|
+
threadId: string;
|
|
81
|
+
to: string;
|
|
82
|
+
}>;
|
|
83
|
+
/**
|
|
84
|
+
* Parses a raw Gmail message with MIME charset and attachment handling.
|
|
85
|
+
*
|
|
86
|
+
* @param raw - Base64url-encoded RFC 5322 message.
|
|
87
|
+
*/
|
|
88
|
+
export declare function parseRawMessage(raw: string): Promise<import("postal-mime").Email>;
|
|
89
|
+
/**
|
|
90
|
+
* Converts one or many message IDs to the array required by Gmail batch APIs.
|
|
91
|
+
*
|
|
92
|
+
* @param messageIds - One Gmail message ID or an existing array.
|
|
93
|
+
*/
|
|
94
|
+
export declare function normalizeMessageIds(messageIds: string | string[]): string[];
|
|
95
|
+
/**
|
|
96
|
+
* Converts optional singular or plural recipients to an array.
|
|
97
|
+
*
|
|
98
|
+
* @param recipients - One recipient, many recipients, or no recipients.
|
|
99
|
+
*/
|
|
100
|
+
export declare function normalizeRecipients(recipients: z.input<typeof RECIPIENT_SCHEMA> | z.input<typeof RECIPIENT_SCHEMA>[] | undefined): (string | {
|
|
101
|
+
address: string;
|
|
102
|
+
name?: string | undefined;
|
|
103
|
+
})[];
|
|
104
|
+
/**
|
|
105
|
+
* Fetches the metadata needed for message predicates and replies.
|
|
106
|
+
*
|
|
107
|
+
* @param gmailApi - Authenticated Gmail client.
|
|
108
|
+
* @param messageId - Immutable Gmail message ID.
|
|
109
|
+
*/
|
|
110
|
+
export declare function getMessageMetadata(gmailApi: gmail_v1.Gmail, messageId: string): Promise<gmail_v1.Schema$Message>;
|
|
111
|
+
/**
|
|
112
|
+
* Requires Gmail to identify a created or mutated message.
|
|
113
|
+
*
|
|
114
|
+
* @param message - Gmail message response.
|
|
115
|
+
* @param operation - Operation named in failure output.
|
|
116
|
+
* @throws When Gmail omits the message or thread ID.
|
|
117
|
+
*/
|
|
118
|
+
export declare function toMessageMetadata(message: gmail_v1.Schema$Message, operation: string): z.output<typeof MESSAGE_METADATA_SCHEMA>;
|
|
119
|
+
/**
|
|
120
|
+
* Builds and sends a reply for one resolved Gmail message.
|
|
121
|
+
*
|
|
122
|
+
* @param gmailApi - Authenticated Gmail client.
|
|
123
|
+
* @param original - Message receiving the reply.
|
|
124
|
+
* @param input - Reply body, recipients, headers, and attachments.
|
|
125
|
+
*/
|
|
126
|
+
export declare function sendReply(gmailApi: gmail_v1.Gmail, original: gmail_v1.Schema$Message, input: z.input<typeof REPLY_OPTIONS_SCHEMA>): Promise<{
|
|
127
|
+
messageId: string;
|
|
128
|
+
threadId: string;
|
|
129
|
+
labelIds: string[];
|
|
130
|
+
historyId?: string | undefined;
|
|
131
|
+
}>;
|
|
132
|
+
/**
|
|
133
|
+
* Combines derived reply headers with caller-supplied recipients.
|
|
134
|
+
*
|
|
135
|
+
* @param reply - Reply fields derived from the original message.
|
|
136
|
+
* @param input - Optional reply overrides and additional recipients.
|
|
137
|
+
*/
|
|
138
|
+
export declare function getReplyMessageOptions(reply: Awaited<ReturnType<typeof getReplyOptions>>, input: z.input<typeof REPLY_OPTIONS_SCHEMA>): {
|
|
139
|
+
attachments: (File | {
|
|
140
|
+
file: File;
|
|
141
|
+
contentId?: string | undefined;
|
|
142
|
+
disposition?: "attachment" | "inline" | undefined;
|
|
143
|
+
filename?: string | undefined;
|
|
144
|
+
})[] | undefined;
|
|
145
|
+
cc: (string | {
|
|
146
|
+
address: string;
|
|
147
|
+
name?: string | undefined;
|
|
148
|
+
})[];
|
|
149
|
+
inReplyTo: string;
|
|
150
|
+
references: string[];
|
|
151
|
+
subject: string;
|
|
152
|
+
to: (string | {
|
|
153
|
+
address: string;
|
|
154
|
+
name?: string | undefined;
|
|
155
|
+
})[];
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Requires Gmail to identify a created or updated draft and its message.
|
|
159
|
+
*
|
|
160
|
+
* @param draft - Gmail draft response.
|
|
161
|
+
* @param operation - Operation named in failure output.
|
|
162
|
+
* @throws When Gmail omits the draft, message, or thread identity.
|
|
163
|
+
*/
|
|
164
|
+
export declare function toDraftIdentifier(draft: gmail_v1.Schema$Draft, operation: string): z.output<typeof DRAFT_IDENTIFIER_SCHEMA>;
|
|
165
|
+
/**
|
|
166
|
+
* Converts a Gmail label resource to its documented public representation.
|
|
167
|
+
*
|
|
168
|
+
* @param label - Gmail label resource.
|
|
169
|
+
* @throws When Gmail omits required label fields or returns invalid metadata.
|
|
170
|
+
*/
|
|
171
|
+
export declare function toGmailLabel(label: gmail_v1.Schema$Label): z.output<typeof LABEL_SCHEMA>;
|
|
172
|
+
/**
|
|
173
|
+
* Formats one PostalMime address or group.
|
|
174
|
+
*
|
|
175
|
+
* @param address - Parsed address.
|
|
176
|
+
*/
|
|
177
|
+
export declare function formatAddress(address: Address): string;
|
|
178
|
+
//# sourceMappingURL=gmail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../../../../src/components/gmail/lib/gmail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import { auth, gmail } from "@googleapis/gmail";
|
|
2
|
+
import { compile } from "html-to-text";
|
|
3
|
+
import MailComposer from "nodemailer/lib/mail-composer";
|
|
4
|
+
import PostalMime, { addressParser, } from "postal-mime";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
const AUTOMATE_EMAIL_HEADERS = {
|
|
7
|
+
"X-Mailer": "Automate.ax",
|
|
8
|
+
"X-Sent-From-Automate-Ax": "true",
|
|
9
|
+
};
|
|
10
|
+
const HTML_TO_TEXT = compile({ wordwrap: false });
|
|
11
|
+
const GMAIL_SECRET_SCHEMA = z.object({
|
|
12
|
+
accessToken: z.string().min(1),
|
|
13
|
+
});
|
|
14
|
+
const LABEL_LIST_VISIBILITY_SCHEMA = z.enum([
|
|
15
|
+
"labelHide",
|
|
16
|
+
"labelShow",
|
|
17
|
+
"labelShowIfUnread",
|
|
18
|
+
]);
|
|
19
|
+
const MESSAGE_LIST_VISIBILITY_SCHEMA = z.enum(["hide", "show"]);
|
|
20
|
+
const LABEL_TYPE_SCHEMA = z.enum(["system", "user"]);
|
|
21
|
+
/**
|
|
22
|
+
* Creates the official Gmail client from a resolved Google integration secret.
|
|
23
|
+
*
|
|
24
|
+
* @param secret - Refreshed Google integration secret.
|
|
25
|
+
*/
|
|
26
|
+
export function getGmailApi(secret) {
|
|
27
|
+
const { accessToken } = GMAIL_SECRET_SCHEMA.parse(secret);
|
|
28
|
+
return gmail({
|
|
29
|
+
auth: new auth.OAuth2({
|
|
30
|
+
credentials: { access_token: accessToken },
|
|
31
|
+
}),
|
|
32
|
+
version: "v1",
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Builds the RFC 5322 message Gmail expects in its `raw` field.
|
|
37
|
+
*
|
|
38
|
+
* Missing plain text is derived from HTML.
|
|
39
|
+
*
|
|
40
|
+
* @param options - Message recipients, content, headers, and attachments.
|
|
41
|
+
*/
|
|
42
|
+
export async function buildRawMessage(options) {
|
|
43
|
+
const message = new MailComposer({
|
|
44
|
+
attachments: await Promise.all((options.attachments ?? []).map(async (attachment) => {
|
|
45
|
+
const { contentId, disposition, file, filename } = attachment instanceof File ? { file: attachment } : attachment;
|
|
46
|
+
return {
|
|
47
|
+
cid: contentId,
|
|
48
|
+
content: Buffer.from(await file.arrayBuffer()),
|
|
49
|
+
contentDisposition: disposition,
|
|
50
|
+
contentType: file.type || undefined,
|
|
51
|
+
filename: filename ?? file.name,
|
|
52
|
+
};
|
|
53
|
+
})),
|
|
54
|
+
bcc: options.bcc,
|
|
55
|
+
cc: options.cc,
|
|
56
|
+
from: options.from,
|
|
57
|
+
headers: {
|
|
58
|
+
...options.headers,
|
|
59
|
+
...AUTOMATE_EMAIL_HEADERS,
|
|
60
|
+
},
|
|
61
|
+
html: options.html,
|
|
62
|
+
inReplyTo: options.inReplyTo,
|
|
63
|
+
priority: options.priority,
|
|
64
|
+
references: options.references,
|
|
65
|
+
replyTo: options.replyTo,
|
|
66
|
+
subject: options.subject ?? "",
|
|
67
|
+
text: options.text ??
|
|
68
|
+
(options.html === undefined ? undefined : HTML_TO_TEXT(options.html)),
|
|
69
|
+
to: options.to,
|
|
70
|
+
}).compile();
|
|
71
|
+
// Gmail derives Bcc delivery recipients from the raw message headers.
|
|
72
|
+
message.keepBcc = true;
|
|
73
|
+
return (await message.build()).toString("base64url");
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Resolves a Gmail label name or ID to its canonical ID.
|
|
77
|
+
*
|
|
78
|
+
* @param gmailApi - Authenticated Gmail client.
|
|
79
|
+
* @param labelSearch - Label display name or ID.
|
|
80
|
+
*/
|
|
81
|
+
export async function findLabelId(gmailApi, labelSearch) {
|
|
82
|
+
return (await findLabelIds(gmailApi, [labelSearch]))[0];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolves Gmail label names or IDs with one label-list request.
|
|
86
|
+
*
|
|
87
|
+
* @param gmailApi - Authenticated Gmail client.
|
|
88
|
+
* @param labelSearches - Label display names or IDs.
|
|
89
|
+
*/
|
|
90
|
+
export async function findLabelIds(gmailApi, labelSearches) {
|
|
91
|
+
const { data: { labels = [] }, } = await gmailApi.users.labels.list({ userId: "me" });
|
|
92
|
+
return labelSearches.map((labelSearch) => {
|
|
93
|
+
const normalizedSearch = labelSearch.trim().toLowerCase();
|
|
94
|
+
const labelId = labels.find((label) => label.id === labelSearch)?.id ??
|
|
95
|
+
labels.find((label) => label.name?.trim().toLowerCase() === normalizedSearch)?.id;
|
|
96
|
+
if (!labelId) {
|
|
97
|
+
throw new Error(`Gmail label "${labelSearch}" was not found.`);
|
|
98
|
+
}
|
|
99
|
+
return labelId;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Normalizes a raw Gmail API message into the public message representation.
|
|
104
|
+
*
|
|
105
|
+
* @param rawMessage - Gmail message fetched with `format: "raw"`.
|
|
106
|
+
*/
|
|
107
|
+
export async function getGmailMessage(rawMessage) {
|
|
108
|
+
if (!rawMessage.id || !rawMessage.threadId || !rawMessage.raw) {
|
|
109
|
+
throw new Error("Gmail returned an incomplete message.");
|
|
110
|
+
}
|
|
111
|
+
const parsed = await parseRawMessage(rawMessage.raw);
|
|
112
|
+
const sentAt = parsed.date ? new Date(parsed.date) : undefined;
|
|
113
|
+
return {
|
|
114
|
+
attachments: parsed.attachments.map(toAttachment),
|
|
115
|
+
bcc: flattenAddresses(parsed.bcc),
|
|
116
|
+
cc: flattenAddresses(parsed.cc),
|
|
117
|
+
deliveredTo: parsed.deliveredTo,
|
|
118
|
+
from: flattenAddresses(parsed.from).at(0),
|
|
119
|
+
headers: parsed.headers.map(({ originalKey, value }) => ({
|
|
120
|
+
name: originalKey,
|
|
121
|
+
value,
|
|
122
|
+
})),
|
|
123
|
+
historyId: rawMessage.historyId ?? undefined,
|
|
124
|
+
html: parsed.html,
|
|
125
|
+
inReplyTo: parsed.inReplyTo,
|
|
126
|
+
labelIds: rawMessage.labelIds ?? [],
|
|
127
|
+
messageId: rawMessage.id,
|
|
128
|
+
receivedAt: rawMessage.internalDate
|
|
129
|
+
? new Date(Number(rawMessage.internalDate))
|
|
130
|
+
: null,
|
|
131
|
+
references: parsed.references?.trim().split(/\s+/) ?? [],
|
|
132
|
+
replyTo: flattenAddresses(parsed.replyTo),
|
|
133
|
+
returnPath: parsed.returnPath,
|
|
134
|
+
rfc822MessageId: parsed.messageId,
|
|
135
|
+
sender: flattenAddresses(parsed.sender).at(0),
|
|
136
|
+
...(sentAt && !Number.isNaN(sentAt.getTime()) ? { sentAt } : {}),
|
|
137
|
+
sizeEstimate: rawMessage.sizeEstimate ?? undefined,
|
|
138
|
+
snippet: rawMessage.snippet ?? undefined,
|
|
139
|
+
subject: parsed.subject ?? "",
|
|
140
|
+
text: parsed.text ??
|
|
141
|
+
(parsed.html === undefined ? undefined : HTML_TO_TEXT(parsed.html)),
|
|
142
|
+
threadId: rawMessage.threadId,
|
|
143
|
+
to: flattenAddresses(parsed.to),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Resolves the headers and recipients needed to create a reply.
|
|
148
|
+
*
|
|
149
|
+
* @param gmailApi - Authenticated Gmail client.
|
|
150
|
+
* @param message - Gmail message receiving the reply.
|
|
151
|
+
* @param replyAll - Whether to include the original To and Cc recipients.
|
|
152
|
+
*/
|
|
153
|
+
export async function getReplyOptions(gmailApi, message, replyAll) {
|
|
154
|
+
if (!message.threadId)
|
|
155
|
+
throw new Error("Gmail message has no thread ID.");
|
|
156
|
+
const headers = getHeadersAsMap(message.payload?.headers);
|
|
157
|
+
const inReplyTo = headers.get("message-id");
|
|
158
|
+
const replyAddress = headers.get("reply-to") ?? headers.get("from");
|
|
159
|
+
const subject = headers.get("subject");
|
|
160
|
+
if (!inReplyTo || !replyAddress || !subject) {
|
|
161
|
+
throw new Error("Gmail message is missing required reply headers.");
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
cc: replyAll
|
|
165
|
+
? await getReplyAllCc(gmailApi, headers, replyAddress)
|
|
166
|
+
: undefined,
|
|
167
|
+
inReplyTo,
|
|
168
|
+
references: [
|
|
169
|
+
...(headers.get("references")?.trim().split(/\s+/) ?? []),
|
|
170
|
+
inReplyTo,
|
|
171
|
+
],
|
|
172
|
+
subject,
|
|
173
|
+
threadId: message.threadId,
|
|
174
|
+
to: replyAddress,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Parses a raw Gmail message with MIME charset and attachment handling.
|
|
179
|
+
*
|
|
180
|
+
* @param raw - Base64url-encoded RFC 5322 message.
|
|
181
|
+
*/
|
|
182
|
+
export async function parseRawMessage(raw) {
|
|
183
|
+
return await PostalMime.parse(Buffer.from(raw, "base64url"), {
|
|
184
|
+
attachmentEncoding: "arraybuffer",
|
|
185
|
+
rfc822Attachments: true,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
// FIX: this could just be zippy castArray
|
|
189
|
+
/**
|
|
190
|
+
* Converts one or many message IDs to the array required by Gmail batch APIs.
|
|
191
|
+
*
|
|
192
|
+
* @param messageIds - One Gmail message ID or an existing array.
|
|
193
|
+
*/
|
|
194
|
+
export function normalizeMessageIds(messageIds) {
|
|
195
|
+
return typeof messageIds === "string" ? [messageIds] : messageIds;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Converts optional singular or plural recipients to an array.
|
|
199
|
+
*
|
|
200
|
+
* @param recipients - One recipient, many recipients, or no recipients.
|
|
201
|
+
*/
|
|
202
|
+
export function normalizeRecipients(recipients) {
|
|
203
|
+
return recipients === undefined
|
|
204
|
+
? []
|
|
205
|
+
: Array.isArray(recipients)
|
|
206
|
+
? recipients
|
|
207
|
+
: [recipients];
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Fetches the metadata needed for message predicates and replies.
|
|
211
|
+
*
|
|
212
|
+
* @param gmailApi - Authenticated Gmail client.
|
|
213
|
+
* @param messageId - Immutable Gmail message ID.
|
|
214
|
+
*/
|
|
215
|
+
export async function getMessageMetadata(gmailApi, messageId) {
|
|
216
|
+
return (await gmailApi.users.messages.get({
|
|
217
|
+
format: "metadata",
|
|
218
|
+
id: messageId,
|
|
219
|
+
userId: "me",
|
|
220
|
+
})).data;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Requires Gmail to identify a created or mutated message.
|
|
224
|
+
*
|
|
225
|
+
* @param message - Gmail message response.
|
|
226
|
+
* @param operation - Operation named in failure output.
|
|
227
|
+
* @throws When Gmail omits the message or thread ID.
|
|
228
|
+
*/
|
|
229
|
+
export function toMessageMetadata(message, operation) {
|
|
230
|
+
if (!message.id || !message.threadId) {
|
|
231
|
+
throw new Error(`Gmail did not identify the ${operation}.`);
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
historyId: message.historyId ?? undefined,
|
|
235
|
+
labelIds: message.labelIds ?? [],
|
|
236
|
+
messageId: message.id,
|
|
237
|
+
threadId: message.threadId,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Builds and sends a reply for one resolved Gmail message.
|
|
242
|
+
*
|
|
243
|
+
* @param gmailApi - Authenticated Gmail client.
|
|
244
|
+
* @param original - Message receiving the reply.
|
|
245
|
+
* @param input - Reply body, recipients, headers, and attachments.
|
|
246
|
+
*/
|
|
247
|
+
export async function sendReply(gmailApi, original, input) {
|
|
248
|
+
const replyOptions = await getReplyOptions(gmailApi, original, input.replyAll ?? false);
|
|
249
|
+
return toMessageMetadata((await gmailApi.users.messages.send({
|
|
250
|
+
requestBody: {
|
|
251
|
+
raw: await buildRawMessage({
|
|
252
|
+
...getReplyMessageOptions(replyOptions, input),
|
|
253
|
+
bcc: input.bcc,
|
|
254
|
+
from: input.from,
|
|
255
|
+
headers: input.headers,
|
|
256
|
+
html: input.html,
|
|
257
|
+
priority: input.priority,
|
|
258
|
+
replyTo: input.replyTo,
|
|
259
|
+
text: input.text,
|
|
260
|
+
}),
|
|
261
|
+
threadId: replyOptions.threadId,
|
|
262
|
+
},
|
|
263
|
+
userId: "me",
|
|
264
|
+
})).data, "reply");
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Combines derived reply headers with caller-supplied recipients.
|
|
268
|
+
*
|
|
269
|
+
* @param reply - Reply fields derived from the original message.
|
|
270
|
+
* @param input - Optional reply overrides and additional recipients.
|
|
271
|
+
*/
|
|
272
|
+
export function getReplyMessageOptions(reply, input) {
|
|
273
|
+
return {
|
|
274
|
+
attachments: input.attachments,
|
|
275
|
+
cc: [...(reply.cc ?? []), ...normalizeRecipients(input.cc)],
|
|
276
|
+
inReplyTo: reply.inReplyTo,
|
|
277
|
+
references: reply.references,
|
|
278
|
+
subject: reply.subject,
|
|
279
|
+
to: [reply.to, ...normalizeRecipients(input.to)],
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Requires Gmail to identify a created or updated draft and its message.
|
|
284
|
+
*
|
|
285
|
+
* @param draft - Gmail draft response.
|
|
286
|
+
* @param operation - Operation named in failure output.
|
|
287
|
+
* @throws When Gmail omits the draft, message, or thread identity.
|
|
288
|
+
*/
|
|
289
|
+
export function toDraftIdentifier(draft, operation) {
|
|
290
|
+
if (!draft.id || !draft.message) {
|
|
291
|
+
throw new Error(`Gmail did not identify the ${operation}.`);
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
draftId: draft.id,
|
|
295
|
+
...toMessageMetadata(draft.message, `${operation} message`),
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Converts a Gmail label resource to its documented public representation.
|
|
300
|
+
*
|
|
301
|
+
* @param label - Gmail label resource.
|
|
302
|
+
* @throws When Gmail omits required label fields or returns invalid metadata.
|
|
303
|
+
*/
|
|
304
|
+
export function toGmailLabel(label) {
|
|
305
|
+
if (!label.id || !label.name) {
|
|
306
|
+
throw new Error("Gmail returned an incomplete label.");
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
...(label.color?.backgroundColor &&
|
|
310
|
+
label.color.textColor && {
|
|
311
|
+
color: {
|
|
312
|
+
backgroundColor: label.color.backgroundColor,
|
|
313
|
+
textColor: label.color.textColor,
|
|
314
|
+
},
|
|
315
|
+
}),
|
|
316
|
+
labelId: label.id,
|
|
317
|
+
labelListVisibility: label.labelListVisibility
|
|
318
|
+
? LABEL_LIST_VISIBILITY_SCHEMA.parse(label.labelListVisibility)
|
|
319
|
+
: undefined,
|
|
320
|
+
messageListVisibility: label.messageListVisibility === null ||
|
|
321
|
+
label.messageListVisibility === undefined
|
|
322
|
+
? undefined
|
|
323
|
+
: MESSAGE_LIST_VISIBILITY_SCHEMA.parse(label.messageListVisibility),
|
|
324
|
+
messagesTotal: label.messagesTotal ?? undefined,
|
|
325
|
+
messagesUnread: label.messagesUnread ?? undefined,
|
|
326
|
+
name: label.name,
|
|
327
|
+
threadsTotal: label.threadsTotal ?? undefined,
|
|
328
|
+
threadsUnread: label.threadsUnread ?? undefined,
|
|
329
|
+
type: label.type ? LABEL_TYPE_SCHEMA.parse(label.type) : undefined,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Converts one parsed PostalMime attachment into a File-backed attachment.
|
|
334
|
+
*
|
|
335
|
+
* @param attachment - Parsed MIME attachment.
|
|
336
|
+
*/
|
|
337
|
+
function toAttachment(attachment) {
|
|
338
|
+
const mimeType = attachment.mimeType || "application/octet-stream";
|
|
339
|
+
const filename = attachment.filename || "attachment";
|
|
340
|
+
return {
|
|
341
|
+
contentId: attachment.contentId,
|
|
342
|
+
description: attachment.description,
|
|
343
|
+
disposition: attachment.disposition ?? undefined,
|
|
344
|
+
file: new File([
|
|
345
|
+
attachment.content instanceof ArrayBuffer
|
|
346
|
+
? new Uint8Array(attachment.content)
|
|
347
|
+
: attachment.content,
|
|
348
|
+
], filename, { type: mimeType }),
|
|
349
|
+
filename,
|
|
350
|
+
mimeType,
|
|
351
|
+
related: attachment.related ?? false,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Flattens parsed mailbox groups into code-friendly mailbox values.
|
|
356
|
+
*
|
|
357
|
+
* @param addresses - One parsed address or an address list.
|
|
358
|
+
*/
|
|
359
|
+
function flattenAddresses(addresses) {
|
|
360
|
+
return (Array.isArray(addresses) ? addresses : addresses ? [addresses] : [])
|
|
361
|
+
.flatMap((address) => address.group ?? [address])
|
|
362
|
+
.filter((address) => Boolean(address.address))
|
|
363
|
+
.map(({ address, name }) => ({
|
|
364
|
+
address,
|
|
365
|
+
...(name && { name }),
|
|
366
|
+
}));
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Formats one PostalMime address or group.
|
|
370
|
+
*
|
|
371
|
+
* @param address - Parsed address.
|
|
372
|
+
*/
|
|
373
|
+
export function formatAddress(address) {
|
|
374
|
+
if (address.group) {
|
|
375
|
+
return `${address.name}: ${address.group.map(formatAddress).join(", ")}`;
|
|
376
|
+
}
|
|
377
|
+
if (!address.address)
|
|
378
|
+
return address.name;
|
|
379
|
+
return address.name ? `${address.name} <${address.address}>` : address.address;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Converts MIME headers into a lowercase-keyed map.
|
|
383
|
+
*
|
|
384
|
+
* @param headers - Gmail MIME headers.
|
|
385
|
+
*/
|
|
386
|
+
function getHeadersAsMap(headers) {
|
|
387
|
+
return new Map(headers
|
|
388
|
+
?.filter((header) => Boolean(header.name && header.value))
|
|
389
|
+
.map((header) => [header.name.toLowerCase(), header.value]) ??
|
|
390
|
+
[]);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Builds a deduplicated reply-all Cc list.
|
|
394
|
+
*
|
|
395
|
+
* @param gmailApi - Authenticated Gmail client.
|
|
396
|
+
* @param headers - Original message headers.
|
|
397
|
+
* @param replyAddress - Primary reply recipient.
|
|
398
|
+
*/
|
|
399
|
+
async function getReplyAllCc(gmailApi, headers, replyAddress) {
|
|
400
|
+
const { data: { emailAddress }, } = await gmailApi.users.getProfile({ userId: "me" });
|
|
401
|
+
const excluded = new Set([
|
|
402
|
+
...(emailAddress ? [emailAddress] : []),
|
|
403
|
+
...addressParser(replyAddress, { flatten: true }).flatMap((address) => address.address ? [address.address] : []),
|
|
404
|
+
]);
|
|
405
|
+
return [
|
|
406
|
+
...new Map([headers.get("to"), headers.get("cc")]
|
|
407
|
+
.flatMap((header) => header ? addressParser(header, { flatten: true }) : [])
|
|
408
|
+
.filter((address) => Boolean(address.address && !excluded.has(address.address)))
|
|
409
|
+
.map((address) => [address.address, formatAddress(address)])).values(),
|
|
410
|
+
];
|
|
411
|
+
}
|