@divizend/scratch-core 1.0.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.
- package/basic/demo.ts +11 -0
- package/basic/index.ts +490 -0
- package/core/Auth.ts +63 -0
- package/core/Currency.ts +16 -0
- package/core/Env.ts +186 -0
- package/core/Fragment.ts +43 -0
- package/core/FragmentServingMode.ts +37 -0
- package/core/JsonSchemaValidator.ts +173 -0
- package/core/ProjectRoot.ts +76 -0
- package/core/Scratch.ts +44 -0
- package/core/URI.ts +203 -0
- package/core/Universe.ts +406 -0
- package/core/index.ts +27 -0
- package/gsuite/core/GSuite.ts +237 -0
- package/gsuite/core/GSuiteAdmin.ts +81 -0
- package/gsuite/core/GSuiteOrgConfig.ts +47 -0
- package/gsuite/core/GSuiteUser.ts +115 -0
- package/gsuite/core/index.ts +21 -0
- package/gsuite/documents/Document.ts +173 -0
- package/gsuite/documents/Documents.ts +52 -0
- package/gsuite/documents/index.ts +19 -0
- package/gsuite/drive/Drive.ts +118 -0
- package/gsuite/drive/DriveFile.ts +147 -0
- package/gsuite/drive/index.ts +19 -0
- package/gsuite/gmail/Gmail.ts +430 -0
- package/gsuite/gmail/GmailLabel.ts +55 -0
- package/gsuite/gmail/GmailMessage.ts +428 -0
- package/gsuite/gmail/GmailMessagePart.ts +298 -0
- package/gsuite/gmail/GmailThread.ts +97 -0
- package/gsuite/gmail/index.ts +5 -0
- package/gsuite/gmail/utils.ts +184 -0
- package/gsuite/index.ts +28 -0
- package/gsuite/spreadsheets/CellValue.ts +71 -0
- package/gsuite/spreadsheets/Sheet.ts +128 -0
- package/gsuite/spreadsheets/SheetValues.ts +12 -0
- package/gsuite/spreadsheets/Spreadsheet.ts +76 -0
- package/gsuite/spreadsheets/Spreadsheets.ts +52 -0
- package/gsuite/spreadsheets/index.ts +25 -0
- package/gsuite/spreadsheets/utils.ts +52 -0
- package/gsuite/utils.ts +104 -0
- package/http-server/HttpServer.ts +110 -0
- package/http-server/NativeHttpServer.ts +1084 -0
- package/http-server/index.ts +3 -0
- package/http-server/middlewares/01-cors.ts +33 -0
- package/http-server/middlewares/02-static.ts +67 -0
- package/http-server/middlewares/03-request-logger.ts +159 -0
- package/http-server/middlewares/04-body-parser.ts +54 -0
- package/http-server/middlewares/05-no-cache.ts +23 -0
- package/http-server/middlewares/06-response-handler.ts +39 -0
- package/http-server/middlewares/handler-wrapper.ts +250 -0
- package/http-server/middlewares/index.ts +37 -0
- package/http-server/middlewares/types.ts +27 -0
- package/index.ts +24 -0
- package/package.json +37 -0
- package/queue/EmailQueue.ts +228 -0
- package/queue/RateLimiter.ts +54 -0
- package/queue/index.ts +2 -0
- package/resend/Resend.ts +190 -0
- package/resend/index.ts +11 -0
- package/s2/S2.ts +335 -0
- package/s2/index.ts +11 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gmail - Email Management and Processing Service
|
|
3
|
+
*
|
|
4
|
+
* The Gmail class provides comprehensive access to Gmail functionality through
|
|
5
|
+
* the Gmail API v1. It handles email operations including reading, sending,
|
|
6
|
+
* labeling, and thread management with efficient pagination and caching.
|
|
7
|
+
*
|
|
8
|
+
* Key Features:
|
|
9
|
+
* - Email listing with pagination and filtering
|
|
10
|
+
* - Thread-based conversation management
|
|
11
|
+
* - Email composition and sending with attachments
|
|
12
|
+
* - Label management and organization
|
|
13
|
+
* - Efficient data fetching with skip/limit support
|
|
14
|
+
*
|
|
15
|
+
* The class implements smart pagination that only fetches full message content
|
|
16
|
+
* for messages that will actually be displayed, optimizing performance for
|
|
17
|
+
* large email accounts.
|
|
18
|
+
*
|
|
19
|
+
* @class Gmail
|
|
20
|
+
* @version 1.0.0
|
|
21
|
+
* @author Divizend GmbH
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { google, gmail_v1 } from "googleapis";
|
|
25
|
+
import { JWT } from "google-auth-library";
|
|
26
|
+
import { GmailLabel, GmailMessage, GSuiteUser, Universe } from "../..";
|
|
27
|
+
import { GmailThread } from "./GmailThread";
|
|
28
|
+
import {
|
|
29
|
+
htmlFromText,
|
|
30
|
+
escapeHtml,
|
|
31
|
+
stripHtmlToText,
|
|
32
|
+
encodeDisplayName,
|
|
33
|
+
chunk76,
|
|
34
|
+
base64Url,
|
|
35
|
+
} from "./utils";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Configuration for Gmail sending operations
|
|
39
|
+
*/
|
|
40
|
+
export type GmailSendConfig = {
|
|
41
|
+
/** Email address to send from */
|
|
42
|
+
fromEmail: string;
|
|
43
|
+
/** Display name for the sender */
|
|
44
|
+
fromName: string;
|
|
45
|
+
/** HTML signature to append to emails */
|
|
46
|
+
signatureHtml: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Parameters for Gmail listing operations
|
|
51
|
+
*/
|
|
52
|
+
export type GmailListParams = {
|
|
53
|
+
/** Whether to fetch full message content */
|
|
54
|
+
full?: boolean;
|
|
55
|
+
/** Number of items to skip for pagination */
|
|
56
|
+
skip?: number;
|
|
57
|
+
/** Maximum number of items to return */
|
|
58
|
+
limit?: number;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Parameters for Gmail sending operations
|
|
63
|
+
*/
|
|
64
|
+
export type GmailSendParams = {
|
|
65
|
+
/** Recipient email address */
|
|
66
|
+
to: string;
|
|
67
|
+
/** Email subject line */
|
|
68
|
+
subject: string;
|
|
69
|
+
/** Email body content */
|
|
70
|
+
body: string;
|
|
71
|
+
/** Optional file attachments */
|
|
72
|
+
attachments?: {
|
|
73
|
+
filename: string;
|
|
74
|
+
mimeType: string;
|
|
75
|
+
content: Buffer;
|
|
76
|
+
}[];
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export class Gmail {
|
|
80
|
+
/** Gmail API v1 client instance */
|
|
81
|
+
public readonly gmail: gmail_v1.Gmail;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Creates a new Gmail instance
|
|
85
|
+
*
|
|
86
|
+
* @param universe - Reference to the central Universe instance
|
|
87
|
+
* @param auth - JWT authentication for the Gmail user
|
|
88
|
+
*/
|
|
89
|
+
constructor(private readonly universe: Universe, private auth: JWT) {
|
|
90
|
+
this.gmail = google.gmail({ version: "v1", auth: this.auth });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Gets the GSuiteUser instance for the authenticated user
|
|
95
|
+
*
|
|
96
|
+
* This provides access to other Google Workspace services
|
|
97
|
+
* for the same user.
|
|
98
|
+
*/
|
|
99
|
+
get user(): GSuiteUser {
|
|
100
|
+
return this.universe.gsuite.user(this.email);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Gets the email address of the authenticated user
|
|
105
|
+
*/
|
|
106
|
+
get email(): string {
|
|
107
|
+
return this.auth.subject!;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Retrieves all Gmail labels for the authenticated user
|
|
112
|
+
*
|
|
113
|
+
* Labels are used to organize and categorize emails.
|
|
114
|
+
* This method fetches the complete label list from Gmail.
|
|
115
|
+
*
|
|
116
|
+
* @returns Promise<GmailLabel[]> - Array of Gmail labels
|
|
117
|
+
* @throws Error if no labels are found or the API call fails
|
|
118
|
+
*/
|
|
119
|
+
async getLabels(): Promise<GmailLabel[]> {
|
|
120
|
+
const response = await this.gmail.users.labels.list({
|
|
121
|
+
userId: "me",
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
if (!response.data.labels) {
|
|
125
|
+
throw new Error("No labels found");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return response.data.labels.map((label) => new GmailLabel(this, label));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Finds the ID of a Gmail label by name
|
|
133
|
+
*
|
|
134
|
+
* This method searches through all available labels to find
|
|
135
|
+
* the one matching the specified name, which is useful for
|
|
136
|
+
* filtering operations.
|
|
137
|
+
*
|
|
138
|
+
* @param label - The name of the label to find
|
|
139
|
+
* @returns Promise<string> - The label ID
|
|
140
|
+
* @throws Error if the label is not found
|
|
141
|
+
*/
|
|
142
|
+
async getLabelId(label: string): Promise<string> {
|
|
143
|
+
const labels = await this.getLabels();
|
|
144
|
+
const labelId = labels.find((l) => l.name === label)?.id;
|
|
145
|
+
if (!labelId) {
|
|
146
|
+
throw new Error(`Label ${label} not found`);
|
|
147
|
+
}
|
|
148
|
+
return labelId;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Generic async generator that handles pagination with skip/limit logic
|
|
153
|
+
*
|
|
154
|
+
* This method provides efficient pagination by only fetching full data
|
|
155
|
+
* for items that will actually be yielded, optimizing performance for
|
|
156
|
+
* large datasets.
|
|
157
|
+
*
|
|
158
|
+
* @param messageGenerator - Base generator for the items
|
|
159
|
+
* @param params - Pagination parameters (skip, limit, full)
|
|
160
|
+
* @param fetchFull - Optional function to fetch full item data
|
|
161
|
+
* @returns AsyncGenerator<T> - Paginated items with optional full data
|
|
162
|
+
*/
|
|
163
|
+
private async *paginate<T>(
|
|
164
|
+
messageGenerator: AsyncGenerator<T>,
|
|
165
|
+
params: { skip?: number; limit?: number; full?: boolean },
|
|
166
|
+
fetchFull?: (item: T) => Promise<T>
|
|
167
|
+
): AsyncGenerator<T> {
|
|
168
|
+
let skipped = 0;
|
|
169
|
+
let yielded = 0;
|
|
170
|
+
const limit = params.limit || Infinity;
|
|
171
|
+
const skip = params.skip || 0;
|
|
172
|
+
|
|
173
|
+
for await (const item of messageGenerator) {
|
|
174
|
+
// Skip items until we reach the skip count
|
|
175
|
+
if (skipped < skip) {
|
|
176
|
+
skipped++;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Check if we've reached the limit
|
|
181
|
+
if (yielded >= limit) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Only fetch full data if needed and for items we'll actually yield
|
|
186
|
+
let finalItem = item;
|
|
187
|
+
if (params.full && fetchFull) {
|
|
188
|
+
finalItem = await fetchFull(item);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
yielded++;
|
|
192
|
+
yield finalItem;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async *listMessages(
|
|
197
|
+
label?: string,
|
|
198
|
+
params?: GmailListParams
|
|
199
|
+
): AsyncGenerator<GmailMessage> {
|
|
200
|
+
let nextPageToken: string | null | undefined;
|
|
201
|
+
let labelId = label ? await this.getLabelId(label) : undefined;
|
|
202
|
+
|
|
203
|
+
// Create the base message generator without skip/limit
|
|
204
|
+
const baseMessageGenerator = this.createBaseMessageGenerator(
|
|
205
|
+
labelId,
|
|
206
|
+
nextPageToken
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
// Use the pagination helper
|
|
210
|
+
yield* this.paginate(
|
|
211
|
+
baseMessageGenerator,
|
|
212
|
+
params || {},
|
|
213
|
+
async (msg: GmailMessage) => msg.fetch()
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Creates the base message generator without pagination logic
|
|
219
|
+
*/
|
|
220
|
+
private async *createBaseMessageGenerator(
|
|
221
|
+
labelId: string | undefined,
|
|
222
|
+
initialPageToken?: string | null
|
|
223
|
+
): AsyncGenerator<GmailMessage> {
|
|
224
|
+
let nextPageToken = initialPageToken;
|
|
225
|
+
|
|
226
|
+
while (true) {
|
|
227
|
+
const request: gmail_v1.Params$Resource$Users$Messages$List = {
|
|
228
|
+
userId: "me",
|
|
229
|
+
maxResults: 500,
|
|
230
|
+
};
|
|
231
|
+
if (labelId) {
|
|
232
|
+
request.labelIds = [labelId];
|
|
233
|
+
}
|
|
234
|
+
if (nextPageToken) {
|
|
235
|
+
request.pageToken = nextPageToken;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const response = await this.gmail.users.messages.list(request);
|
|
239
|
+
|
|
240
|
+
for (const message of response.data.messages || []) {
|
|
241
|
+
yield new GmailMessage(this, message, false);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
nextPageToken = response.data.nextPageToken;
|
|
245
|
+
if (!nextPageToken) {
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async *listThreads(
|
|
252
|
+
label?: string,
|
|
253
|
+
params?: GmailListParams
|
|
254
|
+
): AsyncGenerator<GmailThread> {
|
|
255
|
+
let nextPageToken: string | null | undefined;
|
|
256
|
+
let labelId = label ? await this.getLabelId(label) : undefined;
|
|
257
|
+
|
|
258
|
+
// Create the base thread generator without skip/limit
|
|
259
|
+
const baseThreadGenerator = this.createBaseThreadGenerator(
|
|
260
|
+
labelId,
|
|
261
|
+
nextPageToken
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
// Use the pagination helper
|
|
265
|
+
yield* this.paginate(
|
|
266
|
+
baseThreadGenerator,
|
|
267
|
+
params || {},
|
|
268
|
+
async (thread: GmailThread) => thread.fetch()
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Creates the base thread generator without pagination logic
|
|
274
|
+
*/
|
|
275
|
+
private async *createBaseThreadGenerator(
|
|
276
|
+
labelId: string | undefined,
|
|
277
|
+
initialPageToken?: string | null
|
|
278
|
+
): AsyncGenerator<GmailThread> {
|
|
279
|
+
let nextPageToken = initialPageToken;
|
|
280
|
+
|
|
281
|
+
while (true) {
|
|
282
|
+
const request: gmail_v1.Params$Resource$Users$Threads$List = {
|
|
283
|
+
userId: "me",
|
|
284
|
+
maxResults: 500,
|
|
285
|
+
};
|
|
286
|
+
if (labelId) {
|
|
287
|
+
request.labelIds = [labelId];
|
|
288
|
+
}
|
|
289
|
+
if (nextPageToken) {
|
|
290
|
+
request.pageToken = nextPageToken;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const response = await this.gmail.users.threads.list(request);
|
|
294
|
+
|
|
295
|
+
for (const thread of response.data.threads || []) {
|
|
296
|
+
yield new GmailThread(this, thread, []);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
nextPageToken = response.data.nextPageToken;
|
|
300
|
+
if (!nextPageToken) {
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async getSendConfig(): Promise<GmailSendConfig> {
|
|
307
|
+
let fromEmail = this.email!;
|
|
308
|
+
let fromName = "";
|
|
309
|
+
let signatureHtml = "";
|
|
310
|
+
|
|
311
|
+
// Try Gmail Send-As for fromEmail, displayName, and signature
|
|
312
|
+
const sendAsList = await this.gmail.users.settings.sendAs.list({
|
|
313
|
+
userId: "me",
|
|
314
|
+
});
|
|
315
|
+
const sendAs =
|
|
316
|
+
sendAsList.data.sendAs?.find((s) => s.isDefault) ||
|
|
317
|
+
sendAsList.data.sendAs?.find((s) => s.sendAsEmail === this.email) ||
|
|
318
|
+
sendAsList.data.sendAs?.[0];
|
|
319
|
+
|
|
320
|
+
if (sendAs?.sendAsEmail) {
|
|
321
|
+
fromEmail = sendAs.sendAsEmail;
|
|
322
|
+
}
|
|
323
|
+
if (sendAs?.displayName && sendAs.displayName.trim()) {
|
|
324
|
+
fromName = sendAs.displayName.trim();
|
|
325
|
+
}
|
|
326
|
+
if (sendAs?.signature) {
|
|
327
|
+
signatureHtml = sendAs.signature;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Fallback: resolve name via Admin Directory
|
|
331
|
+
if (!fromName) {
|
|
332
|
+
const directoryInfo = this.user.directoryData;
|
|
333
|
+
const dirName =
|
|
334
|
+
directoryInfo.name?.fullName ||
|
|
335
|
+
[directoryInfo.name?.givenName, directoryInfo.name?.familyName]
|
|
336
|
+
.filter(Boolean)
|
|
337
|
+
.join(" ");
|
|
338
|
+
if (dirName && dirName.trim()) {
|
|
339
|
+
fromName = dirName.trim();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (!fromName) {
|
|
344
|
+
throw new Error("From name not found");
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return { fromEmail, fromName, signatureHtml };
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
async send({ to, subject, body, attachments }: GmailSendParams) {
|
|
351
|
+
const sendConfig = await this.getSendConfig();
|
|
352
|
+
|
|
353
|
+
const encodedSubject = `=?UTF-8?B?${Buffer.from(subject, "utf8").toString(
|
|
354
|
+
"base64"
|
|
355
|
+
)}?=`;
|
|
356
|
+
|
|
357
|
+
const emailText = (body + "\n" + sendConfig.fromName).trimEnd();
|
|
358
|
+
|
|
359
|
+
// HTML with bold contract; signature preceded by blank line + `--`
|
|
360
|
+
const htmlWithoutSig = htmlFromText(emailText);
|
|
361
|
+
const htmlSignature = sendConfig.signatureHtml
|
|
362
|
+
? `<div><br>--<br></div>${sendConfig.signatureHtml}`
|
|
363
|
+
: "";
|
|
364
|
+
const textSignature = sendConfig.signatureHtml
|
|
365
|
+
? `\n\n--\n${stripHtmlToText(sendConfig.signatureHtml)}`
|
|
366
|
+
: "";
|
|
367
|
+
|
|
368
|
+
const htmlBody = htmlWithoutSig + htmlSignature;
|
|
369
|
+
const textBody = emailText + textSignature;
|
|
370
|
+
|
|
371
|
+
// MIME boundaries
|
|
372
|
+
const boundaryMixed = "mixed_" + Date.now().toString(36);
|
|
373
|
+
const boundaryAlt = "alt_" + Math.random().toString(36).slice(2);
|
|
374
|
+
|
|
375
|
+
// From header (include name if available)
|
|
376
|
+
const fromHeader = sendConfig.fromName
|
|
377
|
+
? `${encodeDisplayName(sendConfig.fromName)} <${sendConfig.fromEmail}>`
|
|
378
|
+
: `<${sendConfig.fromEmail}>`;
|
|
379
|
+
|
|
380
|
+
// Compose message
|
|
381
|
+
const lines: string[] = [
|
|
382
|
+
`From: ${fromHeader}`,
|
|
383
|
+
`To: <${to}>`,
|
|
384
|
+
`Subject: ${encodedSubject}`,
|
|
385
|
+
"MIME-Version: 1.0",
|
|
386
|
+
`Date: ${new Date().toUTCString()}`,
|
|
387
|
+
`Content-Type: multipart/mixed; boundary="${boundaryMixed}"`,
|
|
388
|
+
"",
|
|
389
|
+
`--${boundaryMixed}`,
|
|
390
|
+
`Content-Type: multipart/alternative; boundary="${boundaryAlt}"`,
|
|
391
|
+
"",
|
|
392
|
+
`--${boundaryAlt}`,
|
|
393
|
+
"Content-Type: text/plain; charset=UTF-8",
|
|
394
|
+
"Content-Transfer-Encoding: 8bit",
|
|
395
|
+
"",
|
|
396
|
+
textBody,
|
|
397
|
+
"",
|
|
398
|
+
`--${boundaryAlt}`,
|
|
399
|
+
"Content-Type: text/html; charset=UTF-8",
|
|
400
|
+
"Content-Transfer-Encoding: 8bit",
|
|
401
|
+
"",
|
|
402
|
+
htmlBody,
|
|
403
|
+
"",
|
|
404
|
+
`--${boundaryAlt}--`,
|
|
405
|
+
"",
|
|
406
|
+
`--${boundaryMixed}`,
|
|
407
|
+
];
|
|
408
|
+
|
|
409
|
+
for (const attachment of attachments || []) {
|
|
410
|
+
const attachmentChunked = chunk76(attachment.content.toString("base64"));
|
|
411
|
+
lines.push(
|
|
412
|
+
`Content-Type: ${attachment.mimeType}; name="${attachment.filename}"`,
|
|
413
|
+
"Content-Transfer-Encoding: base64",
|
|
414
|
+
`Content-Disposition: attachment; filename="${attachment.filename}"`,
|
|
415
|
+
"",
|
|
416
|
+
attachmentChunked,
|
|
417
|
+
`--${boundaryMixed}--`
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
lines.push("");
|
|
422
|
+
|
|
423
|
+
// Send
|
|
424
|
+
const rawMessage = base64Url(lines.join("\r\n"));
|
|
425
|
+
await this.gmail.users.messages.send({
|
|
426
|
+
userId: "me",
|
|
427
|
+
requestBody: { raw: rawMessage },
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GmailLabel - Email Label Management
|
|
3
|
+
*
|
|
4
|
+
* The GmailLabel class represents a Gmail label (category) that can be used
|
|
5
|
+
* to organize and filter emails. Labels provide a way to categorize messages
|
|
6
|
+
* beyond the standard Gmail folders like Inbox, Sent, and Trash.
|
|
7
|
+
*
|
|
8
|
+
* Labels can be:
|
|
9
|
+
* - System labels (Inbox, Sent, Drafts, etc.)
|
|
10
|
+
* - User-created labels for custom organization
|
|
11
|
+
* - Nested labels for hierarchical organization
|
|
12
|
+
*
|
|
13
|
+
* This class provides a simple interface for accessing label properties
|
|
14
|
+
* and integrating with the broader Gmail management system.
|
|
15
|
+
*
|
|
16
|
+
* @class GmailLabel
|
|
17
|
+
* @version 1.0.0
|
|
18
|
+
* @author Divizend GmbH
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { gmail_v1 } from "googleapis";
|
|
22
|
+
import { Gmail } from "../..";
|
|
23
|
+
|
|
24
|
+
export class GmailLabel {
|
|
25
|
+
/**
|
|
26
|
+
* Creates a new GmailLabel instance
|
|
27
|
+
*
|
|
28
|
+
* @param gmail - Reference to the Gmail service instance
|
|
29
|
+
* @param label - Raw Gmail API label data
|
|
30
|
+
*/
|
|
31
|
+
constructor(
|
|
32
|
+
private readonly gmail: Gmail,
|
|
33
|
+
public readonly label: gmail_v1.Schema$Label
|
|
34
|
+
) {}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Gets the display name of the label
|
|
38
|
+
*
|
|
39
|
+
* This is the human-readable name that appears in the Gmail interface
|
|
40
|
+
* and is used for filtering and organization.
|
|
41
|
+
*/
|
|
42
|
+
get name() {
|
|
43
|
+
return this.label.name;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Gets the unique identifier for the label
|
|
48
|
+
*
|
|
49
|
+
* The label ID is used internally by Gmail for API operations
|
|
50
|
+
* and should not be displayed to users.
|
|
51
|
+
*/
|
|
52
|
+
get id() {
|
|
53
|
+
return this.label.id;
|
|
54
|
+
}
|
|
55
|
+
}
|