zele 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +112 -0
- package/dist/api-utils.d.ts +6 -0
- package/dist/api-utils.js +52 -0
- package/dist/api-utils.js.map +1 -0
- package/dist/auth.d.ts +16 -0
- package/dist/auth.js +74 -5
- package/dist/auth.js.map +1 -1
- package/dist/calendar-client.d.ts +135 -0
- package/dist/calendar-client.js +498 -0
- package/dist/calendar-client.js.map +1 -0
- package/dist/calendar-time.d.ts +24 -0
- package/dist/calendar-time.js +245 -0
- package/dist/calendar-time.js.map +1 -0
- package/dist/cli.js +5 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/auth-cmd.js +5 -5
- package/dist/commands/auth-cmd.js.map +1 -1
- package/dist/commands/calendar.d.ts +2 -0
- package/dist/commands/calendar.js +563 -0
- package/dist/commands/calendar.js.map +1 -0
- package/dist/generated/browser.d.ts +10 -0
- package/dist/generated/client.d.ts +10 -0
- package/dist/generated/internal/class.d.ts +22 -0
- package/dist/generated/internal/class.js +2 -2
- package/dist/generated/internal/class.js.map +1 -1
- package/dist/generated/internal/prismaNamespace.d.ts +174 -1
- package/dist/generated/internal/prismaNamespace.js +21 -0
- package/dist/generated/internal/prismaNamespace.js.map +1 -1
- package/dist/generated/internal/prismaNamespaceBrowser.d.ts +23 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +21 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js.map +1 -1
- package/dist/generated/models/accounts.d.ts +281 -0
- package/dist/generated/models/calendar_events.d.ts +1433 -0
- package/dist/generated/models/calendar_events.js +2 -0
- package/dist/generated/models/calendar_events.js.map +1 -0
- package/dist/generated/models/calendar_lists.d.ts +1131 -0
- package/dist/generated/models/calendar_lists.js +2 -0
- package/dist/generated/models/calendar_lists.js.map +1 -0
- package/dist/generated/models.d.ts +2 -0
- package/dist/gmail-cache.d.ts +22 -0
- package/dist/gmail-cache.js +76 -0
- package/dist/gmail-cache.js.map +1 -1
- package/dist/gmail-client.js +1 -48
- package/dist/gmail-client.js.map +1 -1
- package/dist/output.d.ts +11 -0
- package/dist/output.js +42 -0
- package/dist/output.js.map +1 -1
- package/package.json +4 -2
- package/schema.prisma +39 -6
- package/scripts/test-device-code-clients.ts +186 -0
- package/scripts/test-micropython-scopes.ts +72 -0
- package/scripts/test-oauth-clients.ts +257 -0
- package/src/api-utils.ts +60 -0
- package/src/auth.ts +92 -5
- package/src/calendar-client.ts +758 -0
- package/src/calendar-time.ts +299 -0
- package/src/cli.ts +5 -3
- package/src/commands/auth-cmd.ts +5 -5
- package/src/commands/calendar.ts +634 -0
- package/src/gmail-cache.ts +96 -0
- package/src/gmail-client.ts +1 -57
- package/src/output.ts +51 -0
- package/src/schema.sql +22 -0
package/src/auth.ts
CHANGED
|
@@ -16,6 +16,7 @@ import fkill from 'fkill'
|
|
|
16
16
|
import pc from 'picocolors'
|
|
17
17
|
import { getPrisma } from './db.js'
|
|
18
18
|
import { GmailClient } from './gmail-client.js'
|
|
19
|
+
import { CalendarClient } from './calendar-client.js'
|
|
19
20
|
|
|
20
21
|
// ---------------------------------------------------------------------------
|
|
21
22
|
// Config
|
|
@@ -24,12 +25,42 @@ import { GmailClient } from './gmail-client.js'
|
|
|
24
25
|
const ZELE_DIR = path.join(os.homedir(), '.zele')
|
|
25
26
|
const LEGACY_TOKENS_FILE = path.join(ZELE_DIR, 'tokens.json')
|
|
26
27
|
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Known open-source Google OAuth clients (Desktop app type).
|
|
30
|
+
// All support localhost + OOB redirects. All have Gmail, Calendar, Drive,
|
|
31
|
+
// Contacts, Tasks, and other Google API scopes enabled.
|
|
32
|
+
// None support device code flow (requires "TVs and Limited Input" client type,
|
|
33
|
+
// which Google restricts — Gmail scopes are blocked from device code entirely).
|
|
34
|
+
// Source: public open-source repos, tested 2026-02-09.
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
const OAUTH_CLIENTS = {
|
|
37
|
+
// Mozilla Thunderbird — largest user base, highest Google quota.
|
|
38
|
+
// Source: searchfox.org/comm-central/source/mailnews/base/src/OAuth2Providers.sys.mjs
|
|
39
|
+
thunderbird: {
|
|
40
|
+
clientId: '406964657835-aq8lmia8j95dhl1a2bvharmfk3t1hgqj.apps.googleusercontent.com',
|
|
41
|
+
clientSecret: 'kSmqreRr0qwBWJgbf5Y-PjSU',
|
|
42
|
+
},
|
|
43
|
+
// GNOME Online Accounts — used by Evolution, GNOME Calendar, Nautilus (Drive).
|
|
44
|
+
// Source: github.com/GNOME/gnome-online-accounts/blob/master/meson_options.txt
|
|
45
|
+
gnome: {
|
|
46
|
+
clientId: '44438659992-7kgjeitenc16ssihbtdjbgguch7ju55s.apps.googleusercontent.com',
|
|
47
|
+
clientSecret: '-gMLuQyDiI0XrQS_vx_mhuYF',
|
|
48
|
+
},
|
|
49
|
+
// KDE KAccounts — used by KMail, KOrganizer, Kontact.
|
|
50
|
+
// Source: github.com/KDE/kaccounts-providers google.provider.in
|
|
51
|
+
kde: {
|
|
52
|
+
clientId: '317066460457-pkpkedrvt2ldq6g2hj1egfka2n7vpuoo.apps.googleusercontent.com',
|
|
53
|
+
clientSecret: 'Y8eFAaWfcanV3amZdDvtbYUq',
|
|
54
|
+
},
|
|
55
|
+
} as const
|
|
56
|
+
|
|
57
|
+
const ACTIVE_CLIENT = OAUTH_CLIENTS.thunderbird
|
|
58
|
+
|
|
27
59
|
const CLIENT_ID =
|
|
28
|
-
process.env.ZELE_CLIENT_ID ??
|
|
29
|
-
'406964657835-aq8lmia8j95dhl1a2bvharmfk3t1hgqj.apps.googleusercontent.com'
|
|
60
|
+
process.env.ZELE_CLIENT_ID ?? ACTIVE_CLIENT.clientId
|
|
30
61
|
|
|
31
62
|
const CLIENT_SECRET =
|
|
32
|
-
process.env.ZELE_CLIENT_SECRET ??
|
|
63
|
+
process.env.ZELE_CLIENT_SECRET ?? ACTIVE_CLIENT.clientSecret
|
|
33
64
|
|
|
34
65
|
const REDIRECT_PORT = 8089
|
|
35
66
|
const SCOPES = [
|
|
@@ -266,7 +297,7 @@ async function authenticateAccount(email: string): Promise<OAuth2Client> {
|
|
|
266
297
|
const prisma = await getPrisma()
|
|
267
298
|
const row = await prisma.accounts.findUnique({ where: { email } })
|
|
268
299
|
if (!row) {
|
|
269
|
-
throw new Error(`No account found for ${email}. Run: zele
|
|
300
|
+
throw new Error(`No account found for ${email}. Run: zele login`)
|
|
270
301
|
}
|
|
271
302
|
|
|
272
303
|
const tokens: Credentials = JSON.parse(row.tokens)
|
|
@@ -300,7 +331,7 @@ export async function getClients(
|
|
|
300
331
|
|
|
301
332
|
const allEmails = await listAccounts()
|
|
302
333
|
if (allEmails.length === 0) {
|
|
303
|
-
throw new Error('No accounts registered. Run: zele
|
|
334
|
+
throw new Error('No accounts registered. Run: zele login')
|
|
304
335
|
}
|
|
305
336
|
|
|
306
337
|
const emails = accounts && accounts.length > 0
|
|
@@ -340,6 +371,62 @@ export async function getClient(
|
|
|
340
371
|
)
|
|
341
372
|
}
|
|
342
373
|
|
|
374
|
+
// ---------------------------------------------------------------------------
|
|
375
|
+
// Calendar client helpers
|
|
376
|
+
// ---------------------------------------------------------------------------
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Get authenticated CalendarClient instances for all accounts (or filtered by email list).
|
|
380
|
+
*/
|
|
381
|
+
export async function getCalendarClients(
|
|
382
|
+
accounts?: string[],
|
|
383
|
+
): Promise<Array<{ email: string; client: CalendarClient }>> {
|
|
384
|
+
await migrateLegacyTokens()
|
|
385
|
+
|
|
386
|
+
const allEmails = await listAccounts()
|
|
387
|
+
if (allEmails.length === 0) {
|
|
388
|
+
throw new Error('No accounts registered. Run: zele login')
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const emails = accounts && accounts.length > 0
|
|
392
|
+
? allEmails.filter((e) => accounts.includes(e))
|
|
393
|
+
: allEmails
|
|
394
|
+
|
|
395
|
+
if (emails.length === 0) {
|
|
396
|
+
const available = allEmails.join(', ')
|
|
397
|
+
throw new Error(`No matching accounts. Available: ${available}`)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const results = await Promise.all(
|
|
401
|
+
emails.map(async (email) => {
|
|
402
|
+
const auth = await authenticateAccount(email)
|
|
403
|
+
const { token } = await auth.getAccessToken()
|
|
404
|
+
if (!token) throw new Error(`Failed to get access token for ${email}`)
|
|
405
|
+
return { email, client: new CalendarClient({ accessToken: token, email }) }
|
|
406
|
+
}),
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
return results
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Get a single authenticated CalendarClient. Errors if multiple accounts exist
|
|
414
|
+
* and no --account filter was provided.
|
|
415
|
+
*/
|
|
416
|
+
export async function getCalendarClient(
|
|
417
|
+
accounts?: string[],
|
|
418
|
+
): Promise<{ email: string; client: CalendarClient }> {
|
|
419
|
+
const clients = await getCalendarClients(accounts)
|
|
420
|
+
if (clients.length === 1) {
|
|
421
|
+
return clients[0]!
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const emails = clients.map((c) => c.email).join('\n ')
|
|
425
|
+
throw new Error(
|
|
426
|
+
`Multiple accounts matched. Specify --account:\n ${emails}`,
|
|
427
|
+
)
|
|
428
|
+
}
|
|
429
|
+
|
|
343
430
|
// ---------------------------------------------------------------------------
|
|
344
431
|
// Auth status (for auth status command)
|
|
345
432
|
// ---------------------------------------------------------------------------
|