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
@@ -1,339 +0,0 @@
1
- // Prisma-based cache for Gmail API responses.
2
- // Each cache entry is scoped to an account email. TTL-based expiry is checked
3
- // at read time. All methods are async (Prisma is async).
4
- // Single SQLite DB shared across all accounts via the Prisma singleton.
5
-
6
- import { getPrisma } from './db.js'
7
-
8
- // TTL constants in milliseconds
9
- export const TTL = {
10
- THREAD_LIST: 5 * 60 * 1000, // 5 minutes
11
- THREAD: 30 * 60 * 1000, // 30 minutes
12
- LABELS: 30 * 60 * 1000, // 30 minutes
13
- PROFILE: 24 * 60 * 60 * 1000, // 24 hours
14
- LABEL_COUNTS: 2 * 60 * 1000, // 2 minutes
15
- CALENDAR_LIST: 30 * 60 * 1000, // 30 minutes
16
- CALENDAR_EVENTS: 5 * 60 * 1000, // 5 minutes
17
- } as const
18
-
19
- function isExpired(createdAt: Date, ttlMs: number): boolean {
20
- return createdAt.getTime() + ttlMs < Date.now()
21
- }
22
-
23
- // ---------------------------------------------------------------------------
24
- // Thread list cache
25
- // ---------------------------------------------------------------------------
26
-
27
- export async function cacheThreadList(
28
- email: string,
29
- params: { folder?: string; query?: string; maxResults?: number; labelIds?: string[]; pageToken?: string },
30
- data: unknown,
31
- ): Promise<void> {
32
- const prisma = await getPrisma()
33
- const where = {
34
- email,
35
- folder: params.folder ?? '',
36
- query: params.query ?? '',
37
- label_ids: params.labelIds?.join(',') ?? '',
38
- page_token: params.pageToken ?? '',
39
- max_results: params.maxResults ?? 0,
40
- }
41
-
42
- await prisma.thread_lists.upsert({
43
- where: { email_folder_query_label_ids_page_token_max_results: where },
44
- create: { ...where, data: JSON.stringify(data), ttl_ms: TTL.THREAD_LIST },
45
- update: { data: JSON.stringify(data), ttl_ms: TTL.THREAD_LIST, created_at: new Date() },
46
- })
47
- }
48
-
49
- export async function getCachedThreadList<T = unknown>(
50
- email: string,
51
- params: { folder?: string; query?: string; maxResults?: number; labelIds?: string[]; pageToken?: string },
52
- ): Promise<T | undefined> {
53
- const prisma = await getPrisma()
54
- const row = await prisma.thread_lists.findUnique({
55
- where: {
56
- email_folder_query_label_ids_page_token_max_results: {
57
- email,
58
- folder: params.folder ?? '',
59
- query: params.query ?? '',
60
- label_ids: params.labelIds?.join(',') ?? '',
61
- page_token: params.pageToken ?? '',
62
- max_results: params.maxResults ?? 0,
63
- },
64
- },
65
- })
66
-
67
- if (!row || isExpired(row.created_at, row.ttl_ms)) return undefined
68
- return JSON.parse(row.data) as T
69
- }
70
-
71
- export async function invalidateThreadLists(email: string): Promise<void> {
72
- const prisma = await getPrisma()
73
- await prisma.thread_lists.deleteMany({ where: { email } })
74
- }
75
-
76
- // ---------------------------------------------------------------------------
77
- // Individual thread cache
78
- // ---------------------------------------------------------------------------
79
-
80
- export async function cacheThread(
81
- email: string,
82
- threadId: string,
83
- data: unknown,
84
- ): Promise<void> {
85
- const prisma = await getPrisma()
86
- await prisma.threads.upsert({
87
- where: { email_thread_id: { email, thread_id: threadId } },
88
- create: { email, thread_id: threadId, data: JSON.stringify(data), ttl_ms: TTL.THREAD },
89
- update: { data: JSON.stringify(data), ttl_ms: TTL.THREAD, created_at: new Date() },
90
- })
91
- }
92
-
93
- export async function getCachedThread<T = unknown>(
94
- email: string,
95
- threadId: string,
96
- ): Promise<T | undefined> {
97
- const prisma = await getPrisma()
98
- const row = await prisma.threads.findUnique({
99
- where: { email_thread_id: { email, thread_id: threadId } },
100
- })
101
-
102
- if (!row || isExpired(row.created_at, row.ttl_ms)) return undefined
103
- return JSON.parse(row.data) as T
104
- }
105
-
106
- export async function invalidateThread(email: string, threadId: string): Promise<void> {
107
- const prisma = await getPrisma()
108
- await prisma.threads.deleteMany({ where: { email, thread_id: threadId } })
109
- }
110
-
111
- export async function invalidateThreads(email: string, threadIds: string[]): Promise<void> {
112
- const prisma = await getPrisma()
113
- await prisma.threads.deleteMany({ where: { email, thread_id: { in: threadIds } } })
114
- }
115
-
116
- // ---------------------------------------------------------------------------
117
- // Labels cache
118
- // ---------------------------------------------------------------------------
119
-
120
- export async function cacheLabels(email: string, data: unknown): Promise<void> {
121
- const prisma = await getPrisma()
122
- await prisma.labels.upsert({
123
- where: { email },
124
- create: { email, data: JSON.stringify(data), ttl_ms: TTL.LABELS },
125
- update: { data: JSON.stringify(data), ttl_ms: TTL.LABELS, created_at: new Date() },
126
- })
127
- }
128
-
129
- export async function getCachedLabels<T = unknown>(email: string): Promise<T | undefined> {
130
- const prisma = await getPrisma()
131
- const row = await prisma.labels.findUnique({ where: { email } })
132
- if (!row || isExpired(row.created_at, row.ttl_ms)) return undefined
133
- return JSON.parse(row.data) as T
134
- }
135
-
136
- export async function invalidateLabels(email: string): Promise<void> {
137
- const prisma = await getPrisma()
138
- await prisma.labels.deleteMany({ where: { email } })
139
- }
140
-
141
- // ---------------------------------------------------------------------------
142
- // Label counts cache
143
- // ---------------------------------------------------------------------------
144
-
145
- export async function cacheLabelCounts(email: string, data: unknown): Promise<void> {
146
- const prisma = await getPrisma()
147
- await prisma.label_counts.upsert({
148
- where: { email },
149
- create: { email, data: JSON.stringify(data), ttl_ms: TTL.LABEL_COUNTS },
150
- update: { data: JSON.stringify(data), ttl_ms: TTL.LABEL_COUNTS, created_at: new Date() },
151
- })
152
- }
153
-
154
- export async function getCachedLabelCounts<T = unknown>(email: string): Promise<T | undefined> {
155
- const prisma = await getPrisma()
156
- const row = await prisma.label_counts.findUnique({ where: { email } })
157
- if (!row || isExpired(row.created_at, row.ttl_ms)) return undefined
158
- return JSON.parse(row.data) as T
159
- }
160
-
161
- export async function invalidateLabelCounts(email: string): Promise<void> {
162
- const prisma = await getPrisma()
163
- await prisma.label_counts.deleteMany({ where: { email } })
164
- }
165
-
166
- // ---------------------------------------------------------------------------
167
- // Profile cache
168
- // ---------------------------------------------------------------------------
169
-
170
- export async function cacheProfile(email: string, data: unknown): Promise<void> {
171
- const prisma = await getPrisma()
172
- await prisma.profiles.upsert({
173
- where: { email },
174
- create: { email, data: JSON.stringify(data), ttl_ms: TTL.PROFILE },
175
- update: { data: JSON.stringify(data), ttl_ms: TTL.PROFILE, created_at: new Date() },
176
- })
177
- }
178
-
179
- export async function getCachedProfile<T = unknown>(email: string): Promise<T | undefined> {
180
- const prisma = await getPrisma()
181
- const row = await prisma.profiles.findUnique({ where: { email } })
182
- if (!row || isExpired(row.created_at, row.ttl_ms)) return undefined
183
- return JSON.parse(row.data) as T
184
- }
185
-
186
- // ---------------------------------------------------------------------------
187
- // Sync state (persistent, no TTL)
188
- // ---------------------------------------------------------------------------
189
-
190
- export async function getLastHistoryId(email: string): Promise<string | undefined> {
191
- const prisma = await getPrisma()
192
- const row = await prisma.sync_states.findUnique({
193
- where: { email_key: { email, key: 'history_id' } },
194
- })
195
- return row?.value
196
- }
197
-
198
- export async function setLastHistoryId(email: string, historyId: string): Promise<void> {
199
- const prisma = await getPrisma()
200
- await prisma.sync_states.upsert({
201
- where: { email_key: { email, key: 'history_id' } },
202
- create: { email, key: 'history_id', value: historyId },
203
- update: { value: historyId },
204
- })
205
- }
206
-
207
- // ---------------------------------------------------------------------------
208
- // Calendar list cache
209
- // ---------------------------------------------------------------------------
210
-
211
- export async function cacheCalendarList(email: string, data: unknown): Promise<void> {
212
- const prisma = await getPrisma()
213
- await prisma.calendar_lists.upsert({
214
- where: { email },
215
- create: { email, data: JSON.stringify(data), ttl_ms: TTL.CALENDAR_LIST },
216
- update: { data: JSON.stringify(data), ttl_ms: TTL.CALENDAR_LIST, created_at: new Date() },
217
- })
218
- }
219
-
220
- export async function getCachedCalendarList<T = unknown>(email: string): Promise<T | undefined> {
221
- const prisma = await getPrisma()
222
- const row = await prisma.calendar_lists.findUnique({ where: { email } })
223
- if (!row || isExpired(row.created_at, row.ttl_ms)) return undefined
224
- return JSON.parse(row.data) as T
225
- }
226
-
227
- export async function invalidateCalendarLists(email: string): Promise<void> {
228
- const prisma = await getPrisma()
229
- await prisma.calendar_lists.deleteMany({ where: { email } })
230
- }
231
-
232
- // ---------------------------------------------------------------------------
233
- // Calendar events cache
234
- // ---------------------------------------------------------------------------
235
-
236
- export async function cacheCalendarEvents(
237
- email: string,
238
- params: { calendarId?: string; timeMin?: string; timeMax?: string; query?: string; maxResults?: number; pageToken?: string },
239
- data: unknown,
240
- ): Promise<void> {
241
- const prisma = await getPrisma()
242
- const where = {
243
- email,
244
- calendar_id: params.calendarId ?? '',
245
- time_min: params.timeMin ?? '',
246
- time_max: params.timeMax ?? '',
247
- query: params.query ?? '',
248
- max_results: params.maxResults ?? 0,
249
- page_token: params.pageToken ?? '',
250
- }
251
-
252
- await prisma.calendar_events.upsert({
253
- where: { email_calendar_id_time_min_time_max_query_max_results_page_token: where },
254
- create: { ...where, data: JSON.stringify(data), ttl_ms: TTL.CALENDAR_EVENTS },
255
- update: { data: JSON.stringify(data), ttl_ms: TTL.CALENDAR_EVENTS, created_at: new Date() },
256
- })
257
- }
258
-
259
- export async function getCachedCalendarEvents<T = unknown>(
260
- email: string,
261
- params: { calendarId?: string; timeMin?: string; timeMax?: string; query?: string; maxResults?: number; pageToken?: string },
262
- ): Promise<T | undefined> {
263
- const prisma = await getPrisma()
264
- const row = await prisma.calendar_events.findUnique({
265
- where: {
266
- email_calendar_id_time_min_time_max_query_max_results_page_token: {
267
- email,
268
- calendar_id: params.calendarId ?? '',
269
- time_min: params.timeMin ?? '',
270
- time_max: params.timeMax ?? '',
271
- query: params.query ?? '',
272
- max_results: params.maxResults ?? 0,
273
- page_token: params.pageToken ?? '',
274
- },
275
- },
276
- })
277
-
278
- if (!row || isExpired(row.created_at, row.ttl_ms)) return undefined
279
- return JSON.parse(row.data) as T
280
- }
281
-
282
- export async function invalidateCalendarEvents(email: string, calendarId?: string): Promise<void> {
283
- const prisma = await getPrisma()
284
- if (calendarId) {
285
- await prisma.calendar_events.deleteMany({ where: { email, calendar_id: calendarId } })
286
- } else {
287
- await prisma.calendar_events.deleteMany({ where: { email } })
288
- }
289
- }
290
-
291
- // ---------------------------------------------------------------------------
292
- // Housekeeping
293
- // ---------------------------------------------------------------------------
294
-
295
- export async function clearExpired(): Promise<void> {
296
- const prisma = await getPrisma()
297
- const now = Date.now()
298
- // Use raw SQL for the timestamp arithmetic across all cache tables
299
- await prisma.$executeRawUnsafe(
300
- `DELETE FROM thread_lists WHERE (strftime('%s', created_at) * 1000 + ttl_ms) < ?`,
301
- now,
302
- )
303
- await prisma.$executeRawUnsafe(
304
- `DELETE FROM threads WHERE (strftime('%s', created_at) * 1000 + ttl_ms) < ?`,
305
- now,
306
- )
307
- await prisma.$executeRawUnsafe(
308
- `DELETE FROM labels WHERE (strftime('%s', created_at) * 1000 + ttl_ms) < ?`,
309
- now,
310
- )
311
- await prisma.$executeRawUnsafe(
312
- `DELETE FROM label_counts WHERE (strftime('%s', created_at) * 1000 + ttl_ms) < ?`,
313
- now,
314
- )
315
- await prisma.$executeRawUnsafe(
316
- `DELETE FROM profiles WHERE (strftime('%s', created_at) * 1000 + ttl_ms) < ?`,
317
- now,
318
- )
319
- await prisma.$executeRawUnsafe(
320
- `DELETE FROM calendar_lists WHERE (strftime('%s', created_at) * 1000 + ttl_ms) < ?`,
321
- now,
322
- )
323
- await prisma.$executeRawUnsafe(
324
- `DELETE FROM calendar_events WHERE (strftime('%s', created_at) * 1000 + ttl_ms) < ?`,
325
- now,
326
- )
327
- }
328
-
329
- export async function clearAll(email: string): Promise<void> {
330
- const prisma = await getPrisma()
331
- await prisma.thread_lists.deleteMany({ where: { email } })
332
- await prisma.threads.deleteMany({ where: { email } })
333
- await prisma.labels.deleteMany({ where: { email } })
334
- await prisma.label_counts.deleteMany({ where: { email } })
335
- await prisma.profiles.deleteMany({ where: { email } })
336
- await prisma.sync_states.deleteMany({ where: { email } })
337
- await prisma.calendar_lists.deleteMany({ where: { email } })
338
- await prisma.calendar_events.deleteMany({ where: { email } })
339
- }
package/tsconfig.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2023",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "rootDir": "src",
7
- "outDir": "dist",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "declaration": true,
12
- "sourceMap": true
13
- },
14
- "include": ["src"],
15
- "exclude": ["node_modules"]
16
- }