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.
- package/README.md +1 -1
- package/bin/zele +27 -0
- package/dist/api-utils.d.ts +51 -2
- package/dist/api-utils.js +89 -3
- package/dist/api-utils.js.map +1 -1
- package/dist/auth.d.ts +27 -6
- package/dist/auth.js +185 -129
- package/dist/auth.js.map +1 -1
- package/dist/calendar-client.d.ts +16 -9
- package/dist/calendar-client.js +163 -59
- package/dist/calendar-client.js.map +1 -1
- package/dist/cli.js +26 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/attachment.js +17 -15
- package/dist/commands/attachment.js.map +1 -1
- package/dist/commands/auth-cmd.js +20 -9
- package/dist/commands/auth-cmd.js.map +1 -1
- package/dist/commands/calendar.js +67 -78
- package/dist/commands/calendar.js.map +1 -1
- package/dist/commands/draft.js +25 -18
- package/dist/commands/draft.js.map +1 -1
- package/dist/commands/label.js +33 -45
- package/dist/commands/label.js.map +1 -1
- package/dist/commands/mail-actions.js +11 -13
- package/dist/commands/mail-actions.js.map +1 -1
- package/dist/commands/mail.js +112 -126
- package/dist/commands/mail.js.map +1 -1
- package/dist/commands/profile.js +18 -21
- package/dist/commands/profile.js.map +1 -1
- package/dist/commands/watch.js +33 -261
- package/dist/commands/watch.js.map +1 -1
- package/dist/db.js +12 -13
- package/dist/db.js.map +1 -1
- package/dist/generated/browser.d.ts +12 -27
- package/dist/generated/client.d.ts +13 -28
- package/dist/generated/client.js +1 -1
- package/dist/generated/commonInputTypes.d.ts +90 -26
- package/dist/generated/enums.d.ts +0 -4
- package/dist/generated/enums.js +0 -3
- package/dist/generated/enums.js.map +1 -1
- package/dist/generated/internal/class.d.ts +22 -55
- package/dist/generated/internal/class.js +12 -4
- package/dist/generated/internal/class.js.map +1 -1
- package/dist/generated/internal/prismaNamespace.d.ts +272 -511
- package/dist/generated/internal/prismaNamespace.js +54 -66
- package/dist/generated/internal/prismaNamespace.js.map +1 -1
- package/dist/generated/internal/prismaNamespaceBrowser.d.ts +60 -74
- package/dist/generated/internal/prismaNamespaceBrowser.js +50 -62
- package/dist/generated/internal/prismaNamespaceBrowser.js.map +1 -1
- package/dist/generated/models/Account.d.ts +1637 -0
- package/dist/generated/models/Account.js +2 -0
- package/dist/generated/models/Account.js.map +1 -0
- package/dist/generated/models/CalendarList.d.ts +1161 -0
- package/dist/generated/models/CalendarList.js +2 -0
- package/dist/generated/models/CalendarList.js.map +1 -0
- package/dist/generated/models/Label.d.ts +1161 -0
- package/dist/generated/models/Label.js +2 -0
- package/dist/generated/models/Label.js.map +1 -0
- package/dist/generated/models/Profile.d.ts +1269 -0
- package/dist/generated/models/Profile.js +2 -0
- package/dist/generated/models/Profile.js.map +1 -0
- package/dist/generated/models/SyncState.d.ts +1130 -0
- package/dist/generated/models/SyncState.js +2 -0
- package/dist/generated/models/SyncState.js.map +1 -0
- package/dist/generated/models/Thread.d.ts +1608 -0
- package/dist/generated/models/Thread.js +2 -0
- package/dist/generated/models/Thread.js.map +1 -0
- package/dist/generated/models.d.ts +6 -9
- package/dist/gmail-client.d.ts +119 -94
- package/dist/gmail-client.js +862 -322
- package/dist/gmail-client.js.map +1 -1
- package/dist/mail-tui.d.ts +1 -0
- package/dist/mail-tui.js +517 -0
- package/dist/mail-tui.js.map +1 -0
- package/dist/output.d.ts +6 -0
- package/dist/output.js +124 -11
- package/dist/output.js.map +1 -1
- package/package.json +39 -11
- package/schema.prisma +81 -113
- package/src/api-utils.ts +103 -5
- package/src/auth.ts +224 -143
- package/src/calendar-client.ts +196 -89
- package/src/cli.ts +30 -1
- package/src/commands/attachment.ts +18 -19
- package/src/commands/auth-cmd.ts +19 -9
- package/src/commands/calendar.ts +42 -85
- package/src/commands/draft.ts +19 -22
- package/src/commands/label.ts +21 -57
- package/src/commands/mail-actions.ts +11 -19
- package/src/commands/mail.ts +102 -147
- package/src/commands/profile.ts +12 -28
- package/src/commands/watch.ts +37 -304
- package/src/db.ts +13 -16
- package/src/generated/browser.ts +49 -0
- package/src/generated/client.ts +71 -0
- package/src/generated/commonInputTypes.ts +332 -0
- package/src/generated/enums.ts +17 -0
- package/src/generated/internal/class.ts +250 -0
- package/src/generated/internal/prismaNamespace.ts +1198 -0
- package/src/generated/internal/prismaNamespaceBrowser.ts +169 -0
- package/src/generated/models/Account.ts +1848 -0
- package/src/generated/models/CalendarList.ts +1331 -0
- package/src/generated/models/Label.ts +1331 -0
- package/src/generated/models/Profile.ts +1439 -0
- package/src/generated/models/SyncState.ts +1300 -0
- package/src/generated/models/Thread.ts +1787 -0
- package/src/generated/models.ts +17 -0
- package/src/gmail-client.test.ts +59 -0
- package/src/gmail-client.ts +1034 -429
- package/src/mail-tui.tsx +1061 -0
- package/src/output.test.ts +1093 -0
- package/src/output.ts +128 -13
- package/src/schema.sql +58 -68
- package/src/test-fixtures/email-html/safe-claude-event.html +28 -0
- package/src/test-fixtures/email-html/safe-product-announcement.html +25 -0
- package/src/test-fixtures/email-html/safe-tracked-links.html +27 -0
- package/src/test-fixtures/email-html-snapshots/safe-claude-event.html.md +9 -0
- package/src/test-fixtures/email-html-snapshots/safe-product-announcement.html.md +13 -0
- package/src/test-fixtures/email-html-snapshots/safe-tracked-links.html.md +7 -0
- package/AGENTS.md +0 -26
- package/CHANGELOG.md +0 -43
- package/dist/generated/models/accounts.d.ts +0 -2000
- package/dist/generated/models/accounts.js +0 -2
- package/dist/generated/models/accounts.js.map +0 -1
- package/dist/generated/models/calendar_events.d.ts +0 -1433
- package/dist/generated/models/calendar_events.js +0 -2
- package/dist/generated/models/calendar_events.js.map +0 -1
- package/dist/generated/models/calendar_lists.d.ts +0 -1131
- package/dist/generated/models/calendar_lists.js +0 -2
- package/dist/generated/models/calendar_lists.js.map +0 -1
- package/dist/generated/models/label_counts.d.ts +0 -1131
- package/dist/generated/models/label_counts.js +0 -2
- package/dist/generated/models/label_counts.js.map +0 -1
- package/dist/generated/models/labels.d.ts +0 -1131
- package/dist/generated/models/labels.js +0 -2
- package/dist/generated/models/labels.js.map +0 -1
- package/dist/generated/models/profiles.d.ts +0 -1131
- package/dist/generated/models/profiles.js +0 -2
- package/dist/generated/models/profiles.js.map +0 -1
- package/dist/generated/models/sync_states.d.ts +0 -1107
- package/dist/generated/models/sync_states.js +0 -2
- package/dist/generated/models/sync_states.js.map +0 -1
- package/dist/generated/models/thread_lists.d.ts +0 -1404
- package/dist/generated/models/thread_lists.js +0 -2
- package/dist/generated/models/thread_lists.js.map +0 -1
- package/dist/generated/models/threads.d.ts +0 -1247
- package/dist/generated/models/threads.js +0 -2
- package/dist/generated/models/threads.js.map +0 -1
- package/dist/gmail-cache.d.ts +0 -60
- package/dist/gmail-cache.js +0 -264
- package/dist/gmail-cache.js.map +0 -1
- package/docs/gogcli-gmail-implementation.md +0 -599
- package/scripts/test-device-code-clients.ts +0 -186
- package/scripts/test-micropython-scopes.ts +0 -72
- package/scripts/test-oauth-clients.ts +0 -257
- package/src/gmail-cache.ts +0 -339
- 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
|
-
/**
|
|
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
|
-
|
|
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
|