zele 0.3.0 → 0.3.5

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.
Files changed (157) hide show
  1. package/README.md +1 -1
  2. package/bin/zele +27 -0
  3. package/dist/api-utils.d.ts +51 -2
  4. package/dist/api-utils.js +89 -3
  5. package/dist/api-utils.js.map +1 -1
  6. package/dist/auth.d.ts +27 -6
  7. package/dist/auth.js +185 -129
  8. package/dist/auth.js.map +1 -1
  9. package/dist/calendar-client.d.ts +16 -9
  10. package/dist/calendar-client.js +163 -59
  11. package/dist/calendar-client.js.map +1 -1
  12. package/dist/cli.js +26 -1
  13. package/dist/cli.js.map +1 -1
  14. package/dist/commands/attachment.js +17 -15
  15. package/dist/commands/attachment.js.map +1 -1
  16. package/dist/commands/auth-cmd.js +20 -9
  17. package/dist/commands/auth-cmd.js.map +1 -1
  18. package/dist/commands/calendar.js +67 -78
  19. package/dist/commands/calendar.js.map +1 -1
  20. package/dist/commands/draft.js +25 -18
  21. package/dist/commands/draft.js.map +1 -1
  22. package/dist/commands/label.js +33 -45
  23. package/dist/commands/label.js.map +1 -1
  24. package/dist/commands/mail-actions.js +11 -13
  25. package/dist/commands/mail-actions.js.map +1 -1
  26. package/dist/commands/mail.js +112 -126
  27. package/dist/commands/mail.js.map +1 -1
  28. package/dist/commands/profile.js +18 -21
  29. package/dist/commands/profile.js.map +1 -1
  30. package/dist/commands/watch.js +33 -261
  31. package/dist/commands/watch.js.map +1 -1
  32. package/dist/db.js +12 -13
  33. package/dist/db.js.map +1 -1
  34. package/dist/generated/browser.d.ts +12 -27
  35. package/dist/generated/client.d.ts +13 -28
  36. package/dist/generated/client.js +1 -1
  37. package/dist/generated/commonInputTypes.d.ts +90 -26
  38. package/dist/generated/enums.d.ts +0 -4
  39. package/dist/generated/enums.js +0 -3
  40. package/dist/generated/enums.js.map +1 -1
  41. package/dist/generated/internal/class.d.ts +22 -55
  42. package/dist/generated/internal/class.js +12 -4
  43. package/dist/generated/internal/class.js.map +1 -1
  44. package/dist/generated/internal/prismaNamespace.d.ts +272 -511
  45. package/dist/generated/internal/prismaNamespace.js +54 -66
  46. package/dist/generated/internal/prismaNamespace.js.map +1 -1
  47. package/dist/generated/internal/prismaNamespaceBrowser.d.ts +60 -74
  48. package/dist/generated/internal/prismaNamespaceBrowser.js +50 -62
  49. package/dist/generated/internal/prismaNamespaceBrowser.js.map +1 -1
  50. package/dist/generated/models/Account.d.ts +1637 -0
  51. package/dist/generated/models/Account.js +2 -0
  52. package/dist/generated/models/Account.js.map +1 -0
  53. package/dist/generated/models/CalendarList.d.ts +1161 -0
  54. package/dist/generated/models/CalendarList.js +2 -0
  55. package/dist/generated/models/CalendarList.js.map +1 -0
  56. package/dist/generated/models/Label.d.ts +1161 -0
  57. package/dist/generated/models/Label.js +2 -0
  58. package/dist/generated/models/Label.js.map +1 -0
  59. package/dist/generated/models/Profile.d.ts +1269 -0
  60. package/dist/generated/models/Profile.js +2 -0
  61. package/dist/generated/models/Profile.js.map +1 -0
  62. package/dist/generated/models/SyncState.d.ts +1130 -0
  63. package/dist/generated/models/SyncState.js +2 -0
  64. package/dist/generated/models/SyncState.js.map +1 -0
  65. package/dist/generated/models/Thread.d.ts +1608 -0
  66. package/dist/generated/models/Thread.js +2 -0
  67. package/dist/generated/models/Thread.js.map +1 -0
  68. package/dist/generated/models.d.ts +6 -9
  69. package/dist/gmail-client.d.ts +119 -94
  70. package/dist/gmail-client.js +862 -322
  71. package/dist/gmail-client.js.map +1 -1
  72. package/dist/mail-tui.d.ts +1 -0
  73. package/dist/mail-tui.js +517 -0
  74. package/dist/mail-tui.js.map +1 -0
  75. package/dist/output.d.ts +6 -0
  76. package/dist/output.js +124 -11
  77. package/dist/output.js.map +1 -1
  78. package/package.json +39 -11
  79. package/schema.prisma +81 -113
  80. package/src/api-utils.ts +103 -5
  81. package/src/auth.ts +224 -143
  82. package/src/calendar-client.ts +196 -89
  83. package/src/cli.ts +30 -1
  84. package/src/commands/attachment.ts +18 -19
  85. package/src/commands/auth-cmd.ts +19 -9
  86. package/src/commands/calendar.ts +42 -85
  87. package/src/commands/draft.ts +19 -22
  88. package/src/commands/label.ts +21 -57
  89. package/src/commands/mail-actions.ts +11 -19
  90. package/src/commands/mail.ts +102 -147
  91. package/src/commands/profile.ts +12 -28
  92. package/src/commands/watch.ts +37 -304
  93. package/src/db.ts +13 -16
  94. package/src/generated/browser.ts +49 -0
  95. package/src/generated/client.ts +71 -0
  96. package/src/generated/commonInputTypes.ts +332 -0
  97. package/src/generated/enums.ts +17 -0
  98. package/src/generated/internal/class.ts +250 -0
  99. package/src/generated/internal/prismaNamespace.ts +1198 -0
  100. package/src/generated/internal/prismaNamespaceBrowser.ts +169 -0
  101. package/src/generated/models/Account.ts +1848 -0
  102. package/src/generated/models/CalendarList.ts +1331 -0
  103. package/src/generated/models/Label.ts +1331 -0
  104. package/src/generated/models/Profile.ts +1439 -0
  105. package/src/generated/models/SyncState.ts +1300 -0
  106. package/src/generated/models/Thread.ts +1787 -0
  107. package/src/generated/models.ts +17 -0
  108. package/src/gmail-client.test.ts +59 -0
  109. package/src/gmail-client.ts +1034 -429
  110. package/src/mail-tui.tsx +1061 -0
  111. package/src/output.test.ts +1093 -0
  112. package/src/output.ts +128 -13
  113. package/src/schema.sql +58 -68
  114. package/src/test-fixtures/email-html/safe-claude-event.html +28 -0
  115. package/src/test-fixtures/email-html/safe-product-announcement.html +25 -0
  116. package/src/test-fixtures/email-html/safe-tracked-links.html +27 -0
  117. package/src/test-fixtures/email-html-snapshots/safe-claude-event.html.md +9 -0
  118. package/src/test-fixtures/email-html-snapshots/safe-product-announcement.html.md +13 -0
  119. package/src/test-fixtures/email-html-snapshots/safe-tracked-links.html.md +7 -0
  120. package/AGENTS.md +0 -26
  121. package/CHANGELOG.md +0 -43
  122. package/dist/generated/models/accounts.d.ts +0 -2000
  123. package/dist/generated/models/accounts.js +0 -2
  124. package/dist/generated/models/accounts.js.map +0 -1
  125. package/dist/generated/models/calendar_events.d.ts +0 -1433
  126. package/dist/generated/models/calendar_events.js +0 -2
  127. package/dist/generated/models/calendar_events.js.map +0 -1
  128. package/dist/generated/models/calendar_lists.d.ts +0 -1131
  129. package/dist/generated/models/calendar_lists.js +0 -2
  130. package/dist/generated/models/calendar_lists.js.map +0 -1
  131. package/dist/generated/models/label_counts.d.ts +0 -1131
  132. package/dist/generated/models/label_counts.js +0 -2
  133. package/dist/generated/models/label_counts.js.map +0 -1
  134. package/dist/generated/models/labels.d.ts +0 -1131
  135. package/dist/generated/models/labels.js +0 -2
  136. package/dist/generated/models/labels.js.map +0 -1
  137. package/dist/generated/models/profiles.d.ts +0 -1131
  138. package/dist/generated/models/profiles.js +0 -2
  139. package/dist/generated/models/profiles.js.map +0 -1
  140. package/dist/generated/models/sync_states.d.ts +0 -1107
  141. package/dist/generated/models/sync_states.js +0 -2
  142. package/dist/generated/models/sync_states.js.map +0 -1
  143. package/dist/generated/models/thread_lists.d.ts +0 -1404
  144. package/dist/generated/models/thread_lists.js +0 -2
  145. package/dist/generated/models/thread_lists.js.map +0 -1
  146. package/dist/generated/models/threads.d.ts +0 -1247
  147. package/dist/generated/models/threads.js +0 -2
  148. package/dist/generated/models/threads.js.map +0 -1
  149. package/dist/gmail-cache.d.ts +0 -60
  150. package/dist/gmail-cache.js +0 -264
  151. package/dist/gmail-cache.js.map +0 -1
  152. package/docs/gogcli-gmail-implementation.md +0 -599
  153. package/scripts/test-device-code-clients.ts +0 -186
  154. package/scripts/test-micropython-scopes.ts +0 -72
  155. package/scripts/test-oauth-clients.ts +0 -257
  156. package/src/gmail-cache.ts +0 -339
  157. package/tsconfig.json +0 -16
package/src/api-utils.ts CHANGED
@@ -1,27 +1,60 @@
1
1
  // Shared API utilities for Gmail and Calendar clients.
2
2
  // Retry logic for rate limit errors and bounded concurrency helper.
3
3
  // Extracted from gmail-client.ts to be reused across API clients.
4
+ //
5
+ // Auth error handling follows the errore pattern (errors as values):
6
+ // - Clients return AuthError instead of throwing for auth failures
7
+ // - Callers narrow with instanceof, no try/catch or string matching needed
8
+ // - See https://errore.org/ for the philosophy
9
+
10
+ import * as errore from 'errore'
4
11
 
5
12
  const MAX_CONCURRENCY = 10
6
13
 
7
- /** Run promises with bounded concurrency */
14
+ /** Exclude Error subtypes from a union. Used by mapConcurrent to strip
15
+ * error return types from the success array — errors are returned separately. */
16
+ type ExcludeError<T> = T extends Error ? never : T
17
+
18
+ /** Extract Error subtypes from a union. Used by mapConcurrent for the error branch. */
19
+ type ExtractError<T> = T extends Error ? T : never
20
+
21
+ type Falsy = false | 0 | '' | null | undefined
22
+
23
+ /** Generic truthy type guard for Array.filter() chains.
24
+ * Useful to drop null/undefined placeholders while preserving inferred item types. */
25
+ export function isTruthy<T>(value: T): value is Exclude<T, Falsy> {
26
+ return Boolean(value)
27
+ }
28
+
29
+ /** Run promises with bounded concurrency.
30
+ * Error-aware: if any callback returns an Error instance, remaining work is
31
+ * aborted and that error is returned as a value (no throwing needed).
32
+ * Callbacks should return Error for fatal failures (auth) and null for skip.
33
+ * The success array is typed without Error — errors are only in the Error branch. */
8
34
  export async function mapConcurrent<T, R>(
9
35
  items: T[],
10
36
  fn: (item: T) => Promise<R>,
11
37
  concurrency = MAX_CONCURRENCY,
12
- ): Promise<R[]> {
13
- const results: R[] = []
38
+ ): Promise<ExcludeError<R>[] | ExtractError<R>> {
39
+ const results: ExcludeError<R>[] = []
14
40
  let index = 0
41
+ let fatalError: Error | null = null
15
42
 
16
43
  async function worker() {
17
- while (index < items.length) {
44
+ while (index < items.length && !fatalError) {
18
45
  const i = index++
19
- results[i] = await fn(items[i]!)
46
+ const result = await fn(items[i]!)
47
+ if (result instanceof Error) {
48
+ fatalError = result
49
+ return
50
+ }
51
+ results[i] = result as ExcludeError<R>
20
52
  }
21
53
  }
22
54
 
23
55
  const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker())
24
56
  await Promise.all(workers)
57
+ if (fatalError) return fatalError as ExtractError<R>
25
58
  return results
26
59
  }
27
60
 
@@ -40,6 +73,71 @@ export async function withRetry<T>(fn: () => Promise<T>, maxAttempts = 10, delay
40
73
  throw new Error('unreachable')
41
74
  }
42
75
 
76
+ // ---------------------------------------------------------------------------
77
+ // Auth errors (errore pattern: errors as values, not exceptions)
78
+ // ---------------------------------------------------------------------------
79
+
80
+ /** Returned by client methods when authentication fails (expired token, revoked access, etc.).
81
+ * Callers check with `instanceof AuthError` and TypeScript narrows the type. */
82
+ export class AuthError extends errore.createTaggedError({
83
+ name: 'AuthError',
84
+ message: 'Authentication failed for $email: $reason',
85
+ }) {}
86
+
87
+ /** Returned when a requested resource doesn't exist (calendar, event, thread, draft, label). */
88
+ export class NotFoundError extends errore.createTaggedError({
89
+ name: 'NotFoundError',
90
+ message: '$resource not found',
91
+ }) {}
92
+
93
+ /** Returned when a thread has no messages (empty thread). */
94
+ export class EmptyThreadError extends errore.createTaggedError({
95
+ name: 'EmptyThreadError',
96
+ message: 'No messages in thread $threadId',
97
+ }) {}
98
+
99
+ /** Returned when data cannot be parsed (iCal, event response, raw email). */
100
+ export class ParseError extends errore.createTaggedError({
101
+ name: 'ParseError',
102
+ message: 'Failed to parse $what: $reason',
103
+ }) {}
104
+
105
+ /** Returned when required data is missing from an API response or cached object. */
106
+ export class MissingDataError extends errore.createTaggedError({
107
+ name: 'MissingDataError',
108
+ message: 'Missing $what for $resource',
109
+ }) {}
110
+
111
+ /** Returned when user input fails validation (reminder format, time expressions, etc.). */
112
+ export class ValidationError extends errore.createTaggedError({
113
+ name: 'ValidationError',
114
+ message: 'Invalid $field: $reason',
115
+ }) {}
116
+
117
+ /** Returned when a non-auth, non-ratelimit API call fails. */
118
+ export class ApiError extends errore.createTaggedError({
119
+ name: 'ApiError',
120
+ message: 'API call failed: $reason',
121
+ }) {}
122
+
123
+ /** Detect auth-like errors from underlying libraries (tsdav string errors, googleapis structured errors).
124
+ * Used inside clients to decide whether to return an AuthError.
125
+ * NOTE: String matching here is intentional — this is the boundary layer that converts
126
+ * untyped external library exceptions into typed AuthError values (errore "wrapping libraries" pattern). */
127
+ export function isAuthLikeError(err: unknown): boolean {
128
+ const e = err as any
129
+ const status = e?.code ?? e?.status ?? e?.response?.status
130
+ if (status === 401) return true
131
+ if (status === 403 && !isRateLimitError(e)) return true
132
+ const msg = String(err)
133
+ return msg.includes('Invalid credentials') || msg.includes('Unauthorized') || msg.includes('invalid_grant')
134
+ }
135
+
136
+
137
+ // ---------------------------------------------------------------------------
138
+ // Rate limit detection
139
+ // ---------------------------------------------------------------------------
140
+
43
141
  export function isRateLimitError(err: any): boolean {
44
142
  const status = err?.code ?? err?.status ?? err?.response?.status
45
143
  if (status === 429) return true