zele 0.3.16 → 0.3.17
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 +91 -36
- package/dist/api-utils.d.ts +4 -0
- package/dist/api-utils.js +6 -0
- package/dist/api-utils.js.map +1 -1
- package/dist/auth.d.ts +71 -9
- package/dist/auth.js +186 -10
- package/dist/auth.js.map +1 -1
- package/dist/commands/attachment.js +2 -0
- package/dist/commands/attachment.js.map +1 -1
- package/dist/commands/auth-cmd.js +104 -6
- package/dist/commands/auth-cmd.js.map +1 -1
- package/dist/commands/draft.js +7 -1
- package/dist/commands/draft.js.map +1 -1
- package/dist/commands/filter.js +7 -2
- package/dist/commands/filter.js.map +1 -1
- package/dist/commands/label.js +19 -9
- package/dist/commands/label.js.map +1 -1
- package/dist/commands/mail-actions.js.map +1 -1
- package/dist/commands/mail.js +49 -22
- package/dist/commands/mail.js.map +1 -1
- package/dist/commands/profile.js +25 -18
- package/dist/commands/profile.js.map +1 -1
- package/dist/db.js +24 -0
- package/dist/db.js.map +1 -1
- package/dist/generated/internal/class.js +2 -2
- package/dist/generated/internal/class.js.map +1 -1
- package/dist/generated/internal/prismaNamespace.d.ts +2 -0
- package/dist/generated/internal/prismaNamespace.js +2 -0
- package/dist/generated/internal/prismaNamespace.js.map +1 -1
- package/dist/generated/internal/prismaNamespaceBrowser.d.ts +2 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +2 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js.map +1 -1
- package/dist/generated/models/Account.d.ts +97 -1
- package/dist/gmail-client.d.ts +14 -0
- package/dist/gmail-client.js +46 -0
- package/dist/gmail-client.js.map +1 -1
- package/dist/imap-smtp-client.d.ts +235 -0
- package/dist/imap-smtp-client.js +1225 -0
- package/dist/imap-smtp-client.js.map +1 -0
- package/dist/mail-tui.js.map +1 -1
- package/package.json +5 -2
- package/schema.prisma +7 -5
- package/skills/zele/SKILL.md +50 -21
- package/src/api-utils.ts +6 -0
- package/src/auth.ts +282 -14
- package/src/commands/attachment.ts +1 -0
- package/src/commands/auth-cmd.ts +112 -6
- package/src/commands/draft.ts +5 -1
- package/src/commands/filter.ts +9 -3
- package/src/commands/label.ts +22 -11
- package/src/commands/mail-actions.ts +2 -1
- package/src/commands/mail.ts +52 -22
- package/src/commands/profile.ts +27 -17
- package/src/db.ts +28 -0
- package/src/generated/internal/class.ts +2 -2
- package/src/generated/internal/prismaNamespace.ts +2 -0
- package/src/generated/internal/prismaNamespaceBrowser.ts +2 -0
- package/src/generated/models/Account.ts +97 -1
- package/src/gmail-client.test.ts +155 -2
- package/src/gmail-client.ts +65 -0
- package/src/imap-smtp-client.ts +1381 -0
- package/src/mail-tui.tsx +2 -1
- package/src/schema.sql +2 -0
|
@@ -27,6 +27,8 @@ export type AggregateAccount = {
|
|
|
27
27
|
export type AccountMinAggregateOutputType = {
|
|
28
28
|
email: string | null
|
|
29
29
|
appId: string | null
|
|
30
|
+
accountType: string | null
|
|
31
|
+
capabilities: string | null
|
|
30
32
|
accountStatus: $Enums.AccountStatus | null
|
|
31
33
|
tokens: string | null
|
|
32
34
|
createdAt: Date | null
|
|
@@ -36,6 +38,8 @@ export type AccountMinAggregateOutputType = {
|
|
|
36
38
|
export type AccountMaxAggregateOutputType = {
|
|
37
39
|
email: string | null
|
|
38
40
|
appId: string | null
|
|
41
|
+
accountType: string | null
|
|
42
|
+
capabilities: string | null
|
|
39
43
|
accountStatus: $Enums.AccountStatus | null
|
|
40
44
|
tokens: string | null
|
|
41
45
|
createdAt: Date | null
|
|
@@ -45,6 +49,8 @@ export type AccountMaxAggregateOutputType = {
|
|
|
45
49
|
export type AccountCountAggregateOutputType = {
|
|
46
50
|
email: number
|
|
47
51
|
appId: number
|
|
52
|
+
accountType: number
|
|
53
|
+
capabilities: number
|
|
48
54
|
accountStatus: number
|
|
49
55
|
tokens: number
|
|
50
56
|
createdAt: number
|
|
@@ -56,6 +62,8 @@ export type AccountCountAggregateOutputType = {
|
|
|
56
62
|
export type AccountMinAggregateInputType = {
|
|
57
63
|
email?: true
|
|
58
64
|
appId?: true
|
|
65
|
+
accountType?: true
|
|
66
|
+
capabilities?: true
|
|
59
67
|
accountStatus?: true
|
|
60
68
|
tokens?: true
|
|
61
69
|
createdAt?: true
|
|
@@ -65,6 +73,8 @@ export type AccountMinAggregateInputType = {
|
|
|
65
73
|
export type AccountMaxAggregateInputType = {
|
|
66
74
|
email?: true
|
|
67
75
|
appId?: true
|
|
76
|
+
accountType?: true
|
|
77
|
+
capabilities?: true
|
|
68
78
|
accountStatus?: true
|
|
69
79
|
tokens?: true
|
|
70
80
|
createdAt?: true
|
|
@@ -74,6 +84,8 @@ export type AccountMaxAggregateInputType = {
|
|
|
74
84
|
export type AccountCountAggregateInputType = {
|
|
75
85
|
email?: true
|
|
76
86
|
appId?: true
|
|
87
|
+
accountType?: true
|
|
88
|
+
capabilities?: true
|
|
77
89
|
accountStatus?: true
|
|
78
90
|
tokens?: true
|
|
79
91
|
createdAt?: true
|
|
@@ -156,6 +168,8 @@ export type AccountGroupByArgs<ExtArgs extends runtime.Types.Extensions.Internal
|
|
|
156
168
|
export type AccountGroupByOutputType = {
|
|
157
169
|
email: string
|
|
158
170
|
appId: string
|
|
171
|
+
accountType: string
|
|
172
|
+
capabilities: string
|
|
159
173
|
accountStatus: $Enums.AccountStatus
|
|
160
174
|
tokens: string
|
|
161
175
|
createdAt: Date
|
|
@@ -186,6 +200,8 @@ export type AccountWhereInput = {
|
|
|
186
200
|
NOT?: Prisma.AccountWhereInput | Prisma.AccountWhereInput[]
|
|
187
201
|
email?: Prisma.StringFilter<"Account"> | string
|
|
188
202
|
appId?: Prisma.StringFilter<"Account"> | string
|
|
203
|
+
accountType?: Prisma.StringFilter<"Account"> | string
|
|
204
|
+
capabilities?: Prisma.StringFilter<"Account"> | string
|
|
189
205
|
accountStatus?: Prisma.EnumAccountStatusFilter<"Account"> | $Enums.AccountStatus
|
|
190
206
|
tokens?: Prisma.StringFilter<"Account"> | string
|
|
191
207
|
createdAt?: Prisma.DateTimeFilter<"Account"> | Date | string
|
|
@@ -200,6 +216,8 @@ export type AccountWhereInput = {
|
|
|
200
216
|
export type AccountOrderByWithRelationInput = {
|
|
201
217
|
email?: Prisma.SortOrder
|
|
202
218
|
appId?: Prisma.SortOrder
|
|
219
|
+
accountType?: Prisma.SortOrder
|
|
220
|
+
capabilities?: Prisma.SortOrder
|
|
203
221
|
accountStatus?: Prisma.SortOrder
|
|
204
222
|
tokens?: Prisma.SortOrder
|
|
205
223
|
createdAt?: Prisma.SortOrder
|
|
@@ -218,6 +236,8 @@ export type AccountWhereUniqueInput = Prisma.AtLeast<{
|
|
|
218
236
|
NOT?: Prisma.AccountWhereInput | Prisma.AccountWhereInput[]
|
|
219
237
|
email?: Prisma.StringFilter<"Account"> | string
|
|
220
238
|
appId?: Prisma.StringFilter<"Account"> | string
|
|
239
|
+
accountType?: Prisma.StringFilter<"Account"> | string
|
|
240
|
+
capabilities?: Prisma.StringFilter<"Account"> | string
|
|
221
241
|
accountStatus?: Prisma.EnumAccountStatusFilter<"Account"> | $Enums.AccountStatus
|
|
222
242
|
tokens?: Prisma.StringFilter<"Account"> | string
|
|
223
243
|
createdAt?: Prisma.DateTimeFilter<"Account"> | Date | string
|
|
@@ -232,6 +252,8 @@ export type AccountWhereUniqueInput = Prisma.AtLeast<{
|
|
|
232
252
|
export type AccountOrderByWithAggregationInput = {
|
|
233
253
|
email?: Prisma.SortOrder
|
|
234
254
|
appId?: Prisma.SortOrder
|
|
255
|
+
accountType?: Prisma.SortOrder
|
|
256
|
+
capabilities?: Prisma.SortOrder
|
|
235
257
|
accountStatus?: Prisma.SortOrder
|
|
236
258
|
tokens?: Prisma.SortOrder
|
|
237
259
|
createdAt?: Prisma.SortOrder
|
|
@@ -247,6 +269,8 @@ export type AccountScalarWhereWithAggregatesInput = {
|
|
|
247
269
|
NOT?: Prisma.AccountScalarWhereWithAggregatesInput | Prisma.AccountScalarWhereWithAggregatesInput[]
|
|
248
270
|
email?: Prisma.StringWithAggregatesFilter<"Account"> | string
|
|
249
271
|
appId?: Prisma.StringWithAggregatesFilter<"Account"> | string
|
|
272
|
+
accountType?: Prisma.StringWithAggregatesFilter<"Account"> | string
|
|
273
|
+
capabilities?: Prisma.StringWithAggregatesFilter<"Account"> | string
|
|
250
274
|
accountStatus?: Prisma.EnumAccountStatusWithAggregatesFilter<"Account"> | $Enums.AccountStatus
|
|
251
275
|
tokens?: Prisma.StringWithAggregatesFilter<"Account"> | string
|
|
252
276
|
createdAt?: Prisma.DateTimeWithAggregatesFilter<"Account"> | Date | string
|
|
@@ -256,6 +280,8 @@ export type AccountScalarWhereWithAggregatesInput = {
|
|
|
256
280
|
export type AccountCreateInput = {
|
|
257
281
|
email: string
|
|
258
282
|
appId: string
|
|
283
|
+
accountType?: string
|
|
284
|
+
capabilities?: string
|
|
259
285
|
accountStatus: $Enums.AccountStatus
|
|
260
286
|
tokens: string
|
|
261
287
|
createdAt: Date | string
|
|
@@ -270,6 +296,8 @@ export type AccountCreateInput = {
|
|
|
270
296
|
export type AccountUncheckedCreateInput = {
|
|
271
297
|
email: string
|
|
272
298
|
appId: string
|
|
299
|
+
accountType?: string
|
|
300
|
+
capabilities?: string
|
|
273
301
|
accountStatus: $Enums.AccountStatus
|
|
274
302
|
tokens: string
|
|
275
303
|
createdAt: Date | string
|
|
@@ -284,6 +312,8 @@ export type AccountUncheckedCreateInput = {
|
|
|
284
312
|
export type AccountUpdateInput = {
|
|
285
313
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
286
314
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
315
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
316
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
287
317
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
288
318
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
289
319
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -298,6 +328,8 @@ export type AccountUpdateInput = {
|
|
|
298
328
|
export type AccountUncheckedUpdateInput = {
|
|
299
329
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
300
330
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
331
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
332
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
301
333
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
302
334
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
303
335
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -312,6 +344,8 @@ export type AccountUncheckedUpdateInput = {
|
|
|
312
344
|
export type AccountCreateManyInput = {
|
|
313
345
|
email: string
|
|
314
346
|
appId: string
|
|
347
|
+
accountType?: string
|
|
348
|
+
capabilities?: string
|
|
315
349
|
accountStatus: $Enums.AccountStatus
|
|
316
350
|
tokens: string
|
|
317
351
|
createdAt: Date | string
|
|
@@ -321,6 +355,8 @@ export type AccountCreateManyInput = {
|
|
|
321
355
|
export type AccountUpdateManyMutationInput = {
|
|
322
356
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
323
357
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
358
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
359
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
324
360
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
325
361
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
326
362
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -330,6 +366,8 @@ export type AccountUpdateManyMutationInput = {
|
|
|
330
366
|
export type AccountUncheckedUpdateManyInput = {
|
|
331
367
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
332
368
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
369
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
370
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
333
371
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
334
372
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
335
373
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -344,6 +382,8 @@ export type AccountEmailAppIdCompoundUniqueInput = {
|
|
|
344
382
|
export type AccountCountOrderByAggregateInput = {
|
|
345
383
|
email?: Prisma.SortOrder
|
|
346
384
|
appId?: Prisma.SortOrder
|
|
385
|
+
accountType?: Prisma.SortOrder
|
|
386
|
+
capabilities?: Prisma.SortOrder
|
|
347
387
|
accountStatus?: Prisma.SortOrder
|
|
348
388
|
tokens?: Prisma.SortOrder
|
|
349
389
|
createdAt?: Prisma.SortOrder
|
|
@@ -353,6 +393,8 @@ export type AccountCountOrderByAggregateInput = {
|
|
|
353
393
|
export type AccountMaxOrderByAggregateInput = {
|
|
354
394
|
email?: Prisma.SortOrder
|
|
355
395
|
appId?: Prisma.SortOrder
|
|
396
|
+
accountType?: Prisma.SortOrder
|
|
397
|
+
capabilities?: Prisma.SortOrder
|
|
356
398
|
accountStatus?: Prisma.SortOrder
|
|
357
399
|
tokens?: Prisma.SortOrder
|
|
358
400
|
createdAt?: Prisma.SortOrder
|
|
@@ -362,6 +404,8 @@ export type AccountMaxOrderByAggregateInput = {
|
|
|
362
404
|
export type AccountMinOrderByAggregateInput = {
|
|
363
405
|
email?: Prisma.SortOrder
|
|
364
406
|
appId?: Prisma.SortOrder
|
|
407
|
+
accountType?: Prisma.SortOrder
|
|
408
|
+
capabilities?: Prisma.SortOrder
|
|
365
409
|
accountStatus?: Prisma.SortOrder
|
|
366
410
|
tokens?: Prisma.SortOrder
|
|
367
411
|
createdAt?: Prisma.SortOrder
|
|
@@ -458,6 +502,8 @@ export type AccountUpdateOneRequiredWithoutSyncStatesNestedInput = {
|
|
|
458
502
|
export type AccountCreateWithoutThreadsInput = {
|
|
459
503
|
email: string
|
|
460
504
|
appId: string
|
|
505
|
+
accountType?: string
|
|
506
|
+
capabilities?: string
|
|
461
507
|
accountStatus: $Enums.AccountStatus
|
|
462
508
|
tokens: string
|
|
463
509
|
createdAt: Date | string
|
|
@@ -471,6 +517,8 @@ export type AccountCreateWithoutThreadsInput = {
|
|
|
471
517
|
export type AccountUncheckedCreateWithoutThreadsInput = {
|
|
472
518
|
email: string
|
|
473
519
|
appId: string
|
|
520
|
+
accountType?: string
|
|
521
|
+
capabilities?: string
|
|
474
522
|
accountStatus: $Enums.AccountStatus
|
|
475
523
|
tokens: string
|
|
476
524
|
createdAt: Date | string
|
|
@@ -500,6 +548,8 @@ export type AccountUpdateToOneWithWhereWithoutThreadsInput = {
|
|
|
500
548
|
export type AccountUpdateWithoutThreadsInput = {
|
|
501
549
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
502
550
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
551
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
552
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
503
553
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
504
554
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
505
555
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -513,6 +563,8 @@ export type AccountUpdateWithoutThreadsInput = {
|
|
|
513
563
|
export type AccountUncheckedUpdateWithoutThreadsInput = {
|
|
514
564
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
515
565
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
566
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
567
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
516
568
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
517
569
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
518
570
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -526,6 +578,8 @@ export type AccountUncheckedUpdateWithoutThreadsInput = {
|
|
|
526
578
|
export type AccountCreateWithoutLabelsInput = {
|
|
527
579
|
email: string
|
|
528
580
|
appId: string
|
|
581
|
+
accountType?: string
|
|
582
|
+
capabilities?: string
|
|
529
583
|
accountStatus: $Enums.AccountStatus
|
|
530
584
|
tokens: string
|
|
531
585
|
createdAt: Date | string
|
|
@@ -539,6 +593,8 @@ export type AccountCreateWithoutLabelsInput = {
|
|
|
539
593
|
export type AccountUncheckedCreateWithoutLabelsInput = {
|
|
540
594
|
email: string
|
|
541
595
|
appId: string
|
|
596
|
+
accountType?: string
|
|
597
|
+
capabilities?: string
|
|
542
598
|
accountStatus: $Enums.AccountStatus
|
|
543
599
|
tokens: string
|
|
544
600
|
createdAt: Date | string
|
|
@@ -568,6 +624,8 @@ export type AccountUpdateToOneWithWhereWithoutLabelsInput = {
|
|
|
568
624
|
export type AccountUpdateWithoutLabelsInput = {
|
|
569
625
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
570
626
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
627
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
628
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
571
629
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
572
630
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
573
631
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -581,6 +639,8 @@ export type AccountUpdateWithoutLabelsInput = {
|
|
|
581
639
|
export type AccountUncheckedUpdateWithoutLabelsInput = {
|
|
582
640
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
583
641
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
642
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
643
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
584
644
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
585
645
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
586
646
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -594,6 +654,8 @@ export type AccountUncheckedUpdateWithoutLabelsInput = {
|
|
|
594
654
|
export type AccountCreateWithoutProfilesInput = {
|
|
595
655
|
email: string
|
|
596
656
|
appId: string
|
|
657
|
+
accountType?: string
|
|
658
|
+
capabilities?: string
|
|
597
659
|
accountStatus: $Enums.AccountStatus
|
|
598
660
|
tokens: string
|
|
599
661
|
createdAt: Date | string
|
|
@@ -607,6 +669,8 @@ export type AccountCreateWithoutProfilesInput = {
|
|
|
607
669
|
export type AccountUncheckedCreateWithoutProfilesInput = {
|
|
608
670
|
email: string
|
|
609
671
|
appId: string
|
|
672
|
+
accountType?: string
|
|
673
|
+
capabilities?: string
|
|
610
674
|
accountStatus: $Enums.AccountStatus
|
|
611
675
|
tokens: string
|
|
612
676
|
createdAt: Date | string
|
|
@@ -636,6 +700,8 @@ export type AccountUpdateToOneWithWhereWithoutProfilesInput = {
|
|
|
636
700
|
export type AccountUpdateWithoutProfilesInput = {
|
|
637
701
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
638
702
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
703
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
704
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
639
705
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
640
706
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
641
707
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -649,6 +715,8 @@ export type AccountUpdateWithoutProfilesInput = {
|
|
|
649
715
|
export type AccountUncheckedUpdateWithoutProfilesInput = {
|
|
650
716
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
651
717
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
718
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
719
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
652
720
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
653
721
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
654
722
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -662,6 +730,8 @@ export type AccountUncheckedUpdateWithoutProfilesInput = {
|
|
|
662
730
|
export type AccountCreateWithoutCalendarListsInput = {
|
|
663
731
|
email: string
|
|
664
732
|
appId: string
|
|
733
|
+
accountType?: string
|
|
734
|
+
capabilities?: string
|
|
665
735
|
accountStatus: $Enums.AccountStatus
|
|
666
736
|
tokens: string
|
|
667
737
|
createdAt: Date | string
|
|
@@ -675,6 +745,8 @@ export type AccountCreateWithoutCalendarListsInput = {
|
|
|
675
745
|
export type AccountUncheckedCreateWithoutCalendarListsInput = {
|
|
676
746
|
email: string
|
|
677
747
|
appId: string
|
|
748
|
+
accountType?: string
|
|
749
|
+
capabilities?: string
|
|
678
750
|
accountStatus: $Enums.AccountStatus
|
|
679
751
|
tokens: string
|
|
680
752
|
createdAt: Date | string
|
|
@@ -704,6 +776,8 @@ export type AccountUpdateToOneWithWhereWithoutCalendarListsInput = {
|
|
|
704
776
|
export type AccountUpdateWithoutCalendarListsInput = {
|
|
705
777
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
706
778
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
779
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
780
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
707
781
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
708
782
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
709
783
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -717,6 +791,8 @@ export type AccountUpdateWithoutCalendarListsInput = {
|
|
|
717
791
|
export type AccountUncheckedUpdateWithoutCalendarListsInput = {
|
|
718
792
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
719
793
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
794
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
795
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
720
796
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
721
797
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
722
798
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -730,6 +806,8 @@ export type AccountUncheckedUpdateWithoutCalendarListsInput = {
|
|
|
730
806
|
export type AccountCreateWithoutSyncStatesInput = {
|
|
731
807
|
email: string
|
|
732
808
|
appId: string
|
|
809
|
+
accountType?: string
|
|
810
|
+
capabilities?: string
|
|
733
811
|
accountStatus: $Enums.AccountStatus
|
|
734
812
|
tokens: string
|
|
735
813
|
createdAt: Date | string
|
|
@@ -743,6 +821,8 @@ export type AccountCreateWithoutSyncStatesInput = {
|
|
|
743
821
|
export type AccountUncheckedCreateWithoutSyncStatesInput = {
|
|
744
822
|
email: string
|
|
745
823
|
appId: string
|
|
824
|
+
accountType?: string
|
|
825
|
+
capabilities?: string
|
|
746
826
|
accountStatus: $Enums.AccountStatus
|
|
747
827
|
tokens: string
|
|
748
828
|
createdAt: Date | string
|
|
@@ -772,6 +852,8 @@ export type AccountUpdateToOneWithWhereWithoutSyncStatesInput = {
|
|
|
772
852
|
export type AccountUpdateWithoutSyncStatesInput = {
|
|
773
853
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
774
854
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
855
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
856
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
775
857
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
776
858
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
777
859
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -785,6 +867,8 @@ export type AccountUpdateWithoutSyncStatesInput = {
|
|
|
785
867
|
export type AccountUncheckedUpdateWithoutSyncStatesInput = {
|
|
786
868
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
|
787
869
|
appId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
870
|
+
accountType?: Prisma.StringFieldUpdateOperationsInput | string
|
|
871
|
+
capabilities?: Prisma.StringFieldUpdateOperationsInput | string
|
|
788
872
|
accountStatus?: Prisma.EnumAccountStatusFieldUpdateOperationsInput | $Enums.AccountStatus
|
|
789
873
|
tokens?: Prisma.StringFieldUpdateOperationsInput | string
|
|
790
874
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
@@ -838,6 +922,8 @@ export type AccountCountOutputTypeCountSyncStatesArgs<ExtArgs extends runtime.Ty
|
|
|
838
922
|
export type AccountSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
|
839
923
|
email?: boolean
|
|
840
924
|
appId?: boolean
|
|
925
|
+
accountType?: boolean
|
|
926
|
+
capabilities?: boolean
|
|
841
927
|
accountStatus?: boolean
|
|
842
928
|
tokens?: boolean
|
|
843
929
|
createdAt?: boolean
|
|
@@ -853,6 +939,8 @@ export type AccountSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs
|
|
|
853
939
|
export type AccountSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
|
854
940
|
email?: boolean
|
|
855
941
|
appId?: boolean
|
|
942
|
+
accountType?: boolean
|
|
943
|
+
capabilities?: boolean
|
|
856
944
|
accountStatus?: boolean
|
|
857
945
|
tokens?: boolean
|
|
858
946
|
createdAt?: boolean
|
|
@@ -862,6 +950,8 @@ export type AccountSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Exten
|
|
|
862
950
|
export type AccountSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
|
863
951
|
email?: boolean
|
|
864
952
|
appId?: boolean
|
|
953
|
+
accountType?: boolean
|
|
954
|
+
capabilities?: boolean
|
|
865
955
|
accountStatus?: boolean
|
|
866
956
|
tokens?: boolean
|
|
867
957
|
createdAt?: boolean
|
|
@@ -871,13 +961,15 @@ export type AccountSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Exten
|
|
|
871
961
|
export type AccountSelectScalar = {
|
|
872
962
|
email?: boolean
|
|
873
963
|
appId?: boolean
|
|
964
|
+
accountType?: boolean
|
|
965
|
+
capabilities?: boolean
|
|
874
966
|
accountStatus?: boolean
|
|
875
967
|
tokens?: boolean
|
|
876
968
|
createdAt?: boolean
|
|
877
969
|
updatedAt?: boolean
|
|
878
970
|
}
|
|
879
971
|
|
|
880
|
-
export type AccountOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"email" | "appId" | "accountStatus" | "tokens" | "createdAt" | "updatedAt", ExtArgs["result"]["account"]>
|
|
972
|
+
export type AccountOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"email" | "appId" | "accountType" | "capabilities" | "accountStatus" | "tokens" | "createdAt" | "updatedAt", ExtArgs["result"]["account"]>
|
|
881
973
|
export type AccountInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
|
882
974
|
threads?: boolean | Prisma.Account$threadsArgs<ExtArgs>
|
|
883
975
|
labels?: boolean | Prisma.Account$labelsArgs<ExtArgs>
|
|
@@ -901,6 +993,8 @@ export type $AccountPayload<ExtArgs extends runtime.Types.Extensions.InternalArg
|
|
|
901
993
|
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
|
902
994
|
email: string
|
|
903
995
|
appId: string
|
|
996
|
+
accountType: string
|
|
997
|
+
capabilities: string
|
|
904
998
|
accountStatus: $Enums.AccountStatus
|
|
905
999
|
tokens: string
|
|
906
1000
|
createdAt: Date
|
|
@@ -1335,6 +1429,8 @@ export interface Prisma__AccountClient<T, Null = never, ExtArgs extends runtime.
|
|
|
1335
1429
|
export interface AccountFieldRefs {
|
|
1336
1430
|
readonly email: Prisma.FieldRef<"Account", 'String'>
|
|
1337
1431
|
readonly appId: Prisma.FieldRef<"Account", 'String'>
|
|
1432
|
+
readonly accountType: Prisma.FieldRef<"Account", 'String'>
|
|
1433
|
+
readonly capabilities: Prisma.FieldRef<"Account", 'String'>
|
|
1338
1434
|
readonly accountStatus: Prisma.FieldRef<"Account", 'AccountStatus'>
|
|
1339
1435
|
readonly tokens: Prisma.FieldRef<"Account", 'String'>
|
|
1340
1436
|
readonly createdAt: Prisma.FieldRef<"Account", 'DateTime'>
|
package/src/gmail-client.test.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Tests for GmailClient parsing behavior used by TUI previews.
|
|
2
2
|
// Captures entity/encoding regressions in snippet fields from Gmail metadata responses.
|
|
3
3
|
|
|
4
|
-
import { expect, test } from 'vitest'
|
|
4
|
+
import { expect, test, describe } from 'vitest'
|
|
5
5
|
import { OAuth2Client } from 'google-auth-library'
|
|
6
|
-
import { GmailClient } from './gmail-client.js'
|
|
6
|
+
import { GmailClient, parseAuthResults } from './gmail-client.js'
|
|
7
7
|
|
|
8
8
|
// Create a real client instance for testing (no account context needed for parsing tests)
|
|
9
9
|
const auth = new OAuth2Client()
|
|
@@ -62,3 +62,156 @@ test('thread list snippet strips zero-width and preheader garbage', () => {
|
|
|
62
62
|
const parsed = client.parseThreadListItem(rawThread as any)
|
|
63
63
|
expect(parsed.snippet).toBe('A host sent you a message')
|
|
64
64
|
})
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// parseAuthResults
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
describe('parseAuthResults', () => {
|
|
71
|
+
test('parses standard Gmail Authentication-Results header', () => {
|
|
72
|
+
const header = `mx.google.com;
|
|
73
|
+
dkim=pass header.i=@example.com header.s=selector1;
|
|
74
|
+
spf=pass (google.com: domain of user@example.com designates 1.2.3.4 as permitted sender) smtp.mailfrom=user@example.com;
|
|
75
|
+
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com`
|
|
76
|
+
const result = parseAuthResults(header)
|
|
77
|
+
expect(result).toMatchInlineSnapshot(`
|
|
78
|
+
{
|
|
79
|
+
"authentic": true,
|
|
80
|
+
"dkim": "pass",
|
|
81
|
+
"dmarc": "pass",
|
|
82
|
+
"raw": "mx.google.com;
|
|
83
|
+
dkim=pass header.i=@example.com header.s=selector1;
|
|
84
|
+
spf=pass (google.com: domain of user@example.com designates 1.2.3.4 as permitted sender) smtp.mailfrom=user@example.com;
|
|
85
|
+
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com",
|
|
86
|
+
"spf": "pass",
|
|
87
|
+
}
|
|
88
|
+
`)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test('detects failed authentication', () => {
|
|
92
|
+
const header = `mx.google.com;
|
|
93
|
+
dkim=fail (bad signature) header.i=@spoofed.com;
|
|
94
|
+
spf=softfail (google.com: domain transitioning) smtp.mailfrom=other.com;
|
|
95
|
+
dmarc=fail (p=REJECT) header.from=spoofed.com`
|
|
96
|
+
const result = parseAuthResults(header)
|
|
97
|
+
expect(result).toMatchInlineSnapshot(`
|
|
98
|
+
{
|
|
99
|
+
"authentic": false,
|
|
100
|
+
"dkim": "fail",
|
|
101
|
+
"dmarc": "fail",
|
|
102
|
+
"raw": "mx.google.com;
|
|
103
|
+
dkim=fail (bad signature) header.i=@spoofed.com;
|
|
104
|
+
spf=softfail (google.com: domain transitioning) smtp.mailfrom=other.com;
|
|
105
|
+
dmarc=fail (p=REJECT) header.from=spoofed.com",
|
|
106
|
+
"spf": "softfail",
|
|
107
|
+
}
|
|
108
|
+
`)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test('handles missing protocols gracefully', () => {
|
|
112
|
+
const header = `mx.google.com; spf=pass smtp.mailfrom=user@example.com`
|
|
113
|
+
const result = parseAuthResults(header)
|
|
114
|
+
expect(result).toMatchInlineSnapshot(`
|
|
115
|
+
{
|
|
116
|
+
"authentic": false,
|
|
117
|
+
"dkim": "none",
|
|
118
|
+
"dmarc": "none",
|
|
119
|
+
"raw": "mx.google.com; spf=pass smtp.mailfrom=user@example.com",
|
|
120
|
+
"spf": "pass",
|
|
121
|
+
}
|
|
122
|
+
`)
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
test('handles bestguesspass for DMARC', () => {
|
|
126
|
+
const header = `mx.google.com; dkim=pass header.i=@example.com; spf=pass; dmarc=bestguesspass header.from=example.com`
|
|
127
|
+
const result = parseAuthResults(header)
|
|
128
|
+
expect(result).toMatchInlineSnapshot(`
|
|
129
|
+
{
|
|
130
|
+
"authentic": false,
|
|
131
|
+
"dkim": "pass",
|
|
132
|
+
"dmarc": "bestguesspass",
|
|
133
|
+
"raw": "mx.google.com; dkim=pass header.i=@example.com; spf=pass; dmarc=bestguesspass header.from=example.com",
|
|
134
|
+
"spf": "pass",
|
|
135
|
+
}
|
|
136
|
+
`)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
test('parseMessage includes auth for received messages', () => {
|
|
140
|
+
const rawMessage = {
|
|
141
|
+
id: 'msg_auth_1',
|
|
142
|
+
threadId: 'thread_auth_1',
|
|
143
|
+
snippet: 'Test',
|
|
144
|
+
payload: {
|
|
145
|
+
headers: [
|
|
146
|
+
{ name: 'Subject', value: 'Auth test' },
|
|
147
|
+
{ name: 'From', value: 'sender@example.com' },
|
|
148
|
+
{ name: 'To', value: 'me@example.com' },
|
|
149
|
+
{ name: 'Date', value: 'Wed, 25 Mar 2026 10:00:00 +0000' },
|
|
150
|
+
{ name: 'Authentication-Results', value: 'mx.google.com; dkim=pass header.i=@example.com; spf=pass; dmarc=pass (p=REJECT) header.from=example.com' },
|
|
151
|
+
],
|
|
152
|
+
mimeType: 'text/plain',
|
|
153
|
+
body: { data: Buffer.from('hello').toString('base64url') },
|
|
154
|
+
},
|
|
155
|
+
labelIds: ['INBOX'],
|
|
156
|
+
}
|
|
157
|
+
const parsed = client.parseMessage(rawMessage as any)
|
|
158
|
+
expect(parsed.auth).toMatchInlineSnapshot(`
|
|
159
|
+
{
|
|
160
|
+
"authentic": true,
|
|
161
|
+
"dkim": "pass",
|
|
162
|
+
"dmarc": "pass",
|
|
163
|
+
"raw": "mx.google.com; dkim=pass header.i=@example.com; spf=pass; dmarc=pass (p=REJECT) header.from=example.com",
|
|
164
|
+
"spf": "pass",
|
|
165
|
+
}
|
|
166
|
+
`)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
test('parseMessage prefers Gmail trusted header over upstream headers', () => {
|
|
170
|
+
const rawMessage = {
|
|
171
|
+
id: 'msg_multi_auth',
|
|
172
|
+
threadId: 'thread_multi_auth',
|
|
173
|
+
snippet: 'Multi-header',
|
|
174
|
+
payload: {
|
|
175
|
+
headers: [
|
|
176
|
+
{ name: 'Subject', value: 'Forwarded' },
|
|
177
|
+
{ name: 'From', value: 'sender@example.com' },
|
|
178
|
+
{ name: 'To', value: 'me@example.com' },
|
|
179
|
+
{ name: 'Date', value: 'Wed, 25 Mar 2026 10:00:00 +0000' },
|
|
180
|
+
// Upstream relay header (untrusted, appears first)
|
|
181
|
+
{ name: 'Authentication-Results', value: 'relay.untrusted.com; dkim=fail; spf=fail; dmarc=fail' },
|
|
182
|
+
// Gmail's trusted header (should be preferred)
|
|
183
|
+
{ name: 'Authentication-Results', value: 'mx.google.com; dkim=pass header.i=@example.com; spf=pass; dmarc=pass (p=REJECT)' },
|
|
184
|
+
],
|
|
185
|
+
mimeType: 'text/plain',
|
|
186
|
+
body: { data: Buffer.from('hello').toString('base64url') },
|
|
187
|
+
},
|
|
188
|
+
labelIds: ['INBOX'],
|
|
189
|
+
}
|
|
190
|
+
const parsed = client.parseMessage(rawMessage as any)
|
|
191
|
+
expect(parsed.auth?.authentic).toBe(true)
|
|
192
|
+
expect(parsed.auth?.spf).toBe('pass')
|
|
193
|
+
expect(parsed.auth?.dkim).toBe('pass')
|
|
194
|
+
expect(parsed.auth?.dmarc).toBe('pass')
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
test('parseMessage returns null auth for sent messages', () => {
|
|
198
|
+
const rawMessage = {
|
|
199
|
+
id: 'msg_sent_1',
|
|
200
|
+
threadId: 'thread_sent_1',
|
|
201
|
+
snippet: 'Sent',
|
|
202
|
+
payload: {
|
|
203
|
+
headers: [
|
|
204
|
+
{ name: 'Subject', value: 'Outgoing' },
|
|
205
|
+
{ name: 'From', value: 'me@example.com' },
|
|
206
|
+
{ name: 'To', value: 'other@example.com' },
|
|
207
|
+
{ name: 'Date', value: 'Wed, 25 Mar 2026 10:00:00 +0000' },
|
|
208
|
+
],
|
|
209
|
+
mimeType: 'text/plain',
|
|
210
|
+
body: { data: Buffer.from('hello').toString('base64url') },
|
|
211
|
+
},
|
|
212
|
+
labelIds: ['SENT'],
|
|
213
|
+
}
|
|
214
|
+
const parsed = client.parseMessage(rawMessage as any)
|
|
215
|
+
expect(parsed.auth).toBeNull()
|
|
216
|
+
})
|
|
217
|
+
})
|
package/src/gmail-client.ts
CHANGED
|
@@ -22,6 +22,18 @@ import type { AccountId } from './auth.js'
|
|
|
22
22
|
// Types
|
|
23
23
|
// ---------------------------------------------------------------------------
|
|
24
24
|
|
|
25
|
+
export type AuthVerdict = 'pass' | 'fail' | 'softfail' | 'neutral' | 'none' | 'temperror' | 'permerror' | 'bestguesspass'
|
|
26
|
+
|
|
27
|
+
export interface AuthResult {
|
|
28
|
+
spf: AuthVerdict
|
|
29
|
+
dkim: AuthVerdict
|
|
30
|
+
dmarc: AuthVerdict
|
|
31
|
+
/** true when all three are 'pass' — the email is fully authenticated */
|
|
32
|
+
authentic: boolean
|
|
33
|
+
/** raw Authentication-Results header value */
|
|
34
|
+
raw: string
|
|
35
|
+
}
|
|
36
|
+
|
|
25
37
|
export interface Sender {
|
|
26
38
|
name?: string
|
|
27
39
|
email: string
|
|
@@ -50,6 +62,8 @@ export interface ParsedMessage {
|
|
|
50
62
|
mimeType: string // 'text/plain' or 'text/html'
|
|
51
63
|
textBody: string | null // decoded text/plain body when available (for reply parsing)
|
|
52
64
|
attachments: AttachmentMeta[]
|
|
65
|
+
/** SPF/DKIM/DMARC authentication results from Gmail. null for sent/draft messages. */
|
|
66
|
+
auth: AuthResult | null
|
|
53
67
|
}
|
|
54
68
|
|
|
55
69
|
export interface AttachmentMeta {
|
|
@@ -1282,6 +1296,20 @@ export class GmailClient {
|
|
|
1282
1296
|
|
|
1283
1297
|
const { body, mimeType, textBody } = this.extractBody(message.payload ?? {})
|
|
1284
1298
|
|
|
1299
|
+
// Authentication-Results: multiple MTAs can add this header. Prefer the one
|
|
1300
|
+
// stamped by Gmail's trusted authserv-id (mx.google.com) to avoid trusting
|
|
1301
|
+
// headers injected by upstream/untrusted relays.
|
|
1302
|
+
const authHeaders = headers
|
|
1303
|
+
.filter((h) => h.name?.toLowerCase() === 'authentication-results')
|
|
1304
|
+
.map((h) => h.value ?? '')
|
|
1305
|
+
.filter((v) => v.length > 0)
|
|
1306
|
+
const trustedAuthHeader =
|
|
1307
|
+
authHeaders.find((v) => v.trim().toLowerCase().startsWith('mx.google.com'))
|
|
1308
|
+
?? authHeaders[0]
|
|
1309
|
+
?? null
|
|
1310
|
+
const isSentOrDraft = labelIds.includes('SENT') || labelIds.includes('DRAFT')
|
|
1311
|
+
const auth = trustedAuthHeader && !isSentOrDraft ? parseAuthResults(trustedAuthHeader) : null
|
|
1312
|
+
|
|
1285
1313
|
return {
|
|
1286
1314
|
id: message.id ?? '',
|
|
1287
1315
|
threadId: message.threadId ?? '',
|
|
@@ -1308,6 +1336,7 @@ export class GmailClient {
|
|
|
1308
1336
|
mimeType,
|
|
1309
1337
|
textBody,
|
|
1310
1338
|
attachments: this.extractAttachmentMeta(message.payload?.parts ?? []),
|
|
1339
|
+
auth,
|
|
1311
1340
|
}
|
|
1312
1341
|
}
|
|
1313
1342
|
|
|
@@ -2015,6 +2044,42 @@ export class GmailClient {
|
|
|
2015
2044
|
}
|
|
2016
2045
|
}
|
|
2017
2046
|
|
|
2047
|
+
// ---------------------------------------------------------------------------
|
|
2048
|
+
// Email authentication: parse the Authentication-Results header
|
|
2049
|
+
// ---------------------------------------------------------------------------
|
|
2050
|
+
// Gmail adds an Authentication-Results header to every received message with
|
|
2051
|
+
// SPF, DKIM, and DMARC verdicts. Format is semi-structured:
|
|
2052
|
+
// Authentication-Results: mx.google.com;
|
|
2053
|
+
// dkim=pass header.i=@example.com header.s=sel1;
|
|
2054
|
+
// spf=pass (...) smtp.mailfrom=user@example.com;
|
|
2055
|
+
// dmarc=pass (p=REJECT) header.from=example.com
|
|
2056
|
+
// We extract the verdict keyword after each protocol name.
|
|
2057
|
+
// ---------------------------------------------------------------------------
|
|
2058
|
+
|
|
2059
|
+
const AUTH_VERDICTS = new Set(['pass', 'fail', 'softfail', 'neutral', 'none', 'temperror', 'permerror', 'bestguesspass'])
|
|
2060
|
+
|
|
2061
|
+
/** Parse a Gmail Authentication-Results header into structured verdicts. */
|
|
2062
|
+
export function parseAuthResults(header: string): AuthResult {
|
|
2063
|
+
const lower = header.toLowerCase()
|
|
2064
|
+
const extract = (protocol: string): AuthVerdict => {
|
|
2065
|
+
// Match "protocol=verdict" — verdict is a word that stops at whitespace, semicolons, or parens
|
|
2066
|
+
const re = new RegExp(`\\b${protocol}\\s*=\\s*([a-z]+)`)
|
|
2067
|
+
const match = re.exec(lower)
|
|
2068
|
+
const verdict = match?.[1] ?? 'none'
|
|
2069
|
+
return AUTH_VERDICTS.has(verdict) ? verdict as AuthVerdict : 'none'
|
|
2070
|
+
}
|
|
2071
|
+
const spf = extract('spf')
|
|
2072
|
+
const dkim = extract('dkim')
|
|
2073
|
+
const dmarc = extract('dmarc')
|
|
2074
|
+
return {
|
|
2075
|
+
spf,
|
|
2076
|
+
dkim,
|
|
2077
|
+
dmarc,
|
|
2078
|
+
authentic: spf === 'pass' && dkim === 'pass' && dmarc === 'pass',
|
|
2079
|
+
raw: header,
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2018
2083
|
// ---------------------------------------------------------------------------
|
|
2019
2084
|
// Watch: folder label mapping
|
|
2020
2085
|
// ---------------------------------------------------------------------------
|