zele 0.0.0 → 0.1.1
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/AGENTS.md +22 -0
- package/dist/auth.d.ts +34 -0
- package/dist/auth.js +294 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +38 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/attachment.d.ts +2 -0
- package/dist/commands/attachment.js +85 -0
- package/dist/commands/attachment.js.map +1 -0
- package/dist/commands/auth-cmd.d.ts +2 -0
- package/dist/commands/auth-cmd.js +72 -0
- package/dist/commands/auth-cmd.js.map +1 -0
- package/dist/commands/draft.d.ts +2 -0
- package/dist/commands/draft.js +168 -0
- package/dist/commands/draft.js.map +1 -0
- package/dist/commands/label.d.ts +2 -0
- package/dist/commands/label.js +168 -0
- package/dist/commands/label.js.map +1 -0
- package/dist/commands/mail-actions.d.ts +2 -0
- package/dist/commands/mail-actions.js +86 -0
- package/dist/commands/mail-actions.js.map +1 -0
- package/dist/commands/mail.d.ts +2 -0
- package/dist/commands/mail.js +369 -0
- package/dist/commands/mail.js.map +1 -0
- package/dist/commands/profile.d.ts +2 -0
- package/dist/commands/profile.js +53 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/db.d.ts +11 -0
- package/dist/db.js +83 -0
- package/dist/db.js.map +1 -0
- package/dist/email-utils.d.ts +15 -0
- package/dist/email-utils.js +53 -0
- package/dist/email-utils.js.map +1 -0
- package/dist/generated/browser.d.ts +39 -0
- package/dist/generated/browser.js +18 -0
- package/dist/generated/browser.js.map +1 -0
- package/dist/generated/client.d.ts +56 -0
- package/dist/generated/client.js +33 -0
- package/dist/generated/client.js.map +1 -0
- package/dist/generated/commonInputTypes.d.ts +226 -0
- package/dist/generated/commonInputTypes.js +11 -0
- package/dist/generated/commonInputTypes.js.map +1 -0
- package/dist/generated/enums.d.ts +9 -0
- package/dist/generated/enums.js +17 -0
- package/dist/generated/enums.js.map +1 -0
- package/dist/generated/internal/class.d.ts +192 -0
- package/dist/generated/internal/class.js +42 -0
- package/dist/generated/internal/class.js.map +1 -0
- package/dist/generated/internal/prismaNamespace.d.ts +1021 -0
- package/dist/generated/internal/prismaNamespace.js +139 -0
- package/dist/generated/internal/prismaNamespace.js.map +1 -0
- package/dist/generated/internal/prismaNamespaceBrowser.d.ts +103 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +110 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js.map +1 -0
- package/dist/generated/models/accounts.d.ts +1719 -0
- package/dist/generated/models/accounts.js +2 -0
- package/dist/generated/models/accounts.js.map +1 -0
- package/dist/generated/models/label_counts.d.ts +1131 -0
- package/dist/generated/models/label_counts.js +2 -0
- package/dist/generated/models/label_counts.js.map +1 -0
- package/dist/generated/models/labels.d.ts +1131 -0
- package/dist/generated/models/labels.js +2 -0
- package/dist/generated/models/labels.js.map +1 -0
- package/dist/generated/models/profiles.d.ts +1131 -0
- package/dist/generated/models/profiles.js +2 -0
- package/dist/generated/models/profiles.js.map +1 -0
- package/dist/generated/models/sync_states.d.ts +1107 -0
- package/dist/generated/models/sync_states.js +2 -0
- package/dist/generated/models/sync_states.js.map +1 -0
- package/dist/generated/models/thread_lists.d.ts +1404 -0
- package/dist/generated/models/thread_lists.js +2 -0
- package/dist/generated/models/thread_lists.js.map +1 -0
- package/dist/generated/models/threads.d.ts +1247 -0
- package/dist/generated/models/threads.js +2 -0
- package/dist/generated/models/threads.js.map +1 -0
- package/dist/generated/models.d.ts +8 -0
- package/dist/generated/models.js +2 -0
- package/dist/generated/models.js.map +1 -0
- package/dist/gmail-cache.d.ts +38 -0
- package/dist/gmail-cache.js +188 -0
- package/dist/gmail-cache.js.map +1 -0
- package/dist/gmail-client.d.ts +344 -0
- package/dist/gmail-client.js +974 -0
- package/dist/gmail-client.js.map +1 -0
- package/dist/output.d.ts +30 -0
- package/dist/output.js +177 -0
- package/dist/output.js.map +1 -0
- package/docs/gogcli-gmail-implementation.md +599 -0
- package/package.json +42 -18
- package/schema.prisma +125 -0
- package/src/auth.ts +364 -0
- package/src/cli.ts +51 -0
- package/src/commands/attachment.ts +106 -0
- package/src/commands/auth-cmd.ts +89 -0
- package/src/commands/draft.ts +208 -0
- package/src/commands/label.ts +220 -0
- package/src/commands/mail-actions.ts +119 -0
- package/src/commands/mail.ts +450 -0
- package/src/commands/profile.ts +65 -0
- package/src/db.ts +101 -0
- package/src/email-utils.ts +63 -0
- package/src/gmail-cache.ts +243 -0
- package/src/gmail-client.ts +1438 -0
- package/src/output.ts +204 -0
- package/src/schema.sql +62 -0
- package/tsconfig.json +16 -0
- package/src/index.test.ts +0 -9
- package/src/index.ts +0 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
## development
|
|
2
|
+
|
|
3
|
+
to run the cli locally use `tsx src/cli.ts`
|
|
4
|
+
|
|
5
|
+
## goke typing
|
|
6
|
+
|
|
7
|
+
do not add manual type annotations to `.action(async ...)` parameters in goke commands; rely on goke option inference.
|
|
8
|
+
|
|
9
|
+
## database
|
|
10
|
+
|
|
11
|
+
zele uses a single SQLite database at `~/.zele/zele.db` as the source of truth for CLI state.
|
|
12
|
+
|
|
13
|
+
all persistent state is stored in this DB via Prisma models:
|
|
14
|
+
- `accounts`: OAuth tokens per email account
|
|
15
|
+
- `thread_lists` + `threads`: cached mail list/read payloads
|
|
16
|
+
- `labels` + `label_counts`: cached label metadata and unread counters
|
|
17
|
+
- `profiles`: cached account profile data
|
|
18
|
+
- `sync_states`: misc per-account sync metadata (for example history IDs)
|
|
19
|
+
|
|
20
|
+
## migrations
|
|
21
|
+
|
|
22
|
+
`src/db.ts` runs `src/schema.sql` on startup (idempotent migration) so new tables/indexes are applied automatically on each CLI process start.
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { OAuth2Client } from 'google-auth-library';
|
|
2
|
+
import { GmailClient } from './gmail-client.js';
|
|
3
|
+
export declare function createOAuth2Client(): OAuth2Client;
|
|
4
|
+
/**
|
|
5
|
+
* Run the full browser OAuth flow and save the account to the DB.
|
|
6
|
+
* Returns the email and an authenticated GmailClient.
|
|
7
|
+
*/
|
|
8
|
+
export declare function login(): Promise<{
|
|
9
|
+
email: string;
|
|
10
|
+
client: GmailClient;
|
|
11
|
+
}>;
|
|
12
|
+
export declare function logout(email: string): Promise<void>;
|
|
13
|
+
export declare function listAccounts(): Promise<string[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Get authenticated GmailClient instances for all accounts (or filtered by email list).
|
|
16
|
+
* If no accounts are registered, throws with a helpful message.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getClients(accounts?: string[]): Promise<Array<{
|
|
19
|
+
email: string;
|
|
20
|
+
client: GmailClient;
|
|
21
|
+
}>>;
|
|
22
|
+
/**
|
|
23
|
+
* Get a single authenticated GmailClient. Errors if multiple accounts exist
|
|
24
|
+
* and no --account filter was provided.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getClient(accounts?: string[]): Promise<{
|
|
27
|
+
email: string;
|
|
28
|
+
client: GmailClient;
|
|
29
|
+
}>;
|
|
30
|
+
export interface AuthStatus {
|
|
31
|
+
email: string;
|
|
32
|
+
expiresAt?: Date;
|
|
33
|
+
}
|
|
34
|
+
export declare function getAuthStatuses(): Promise<AuthStatus[]>;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
// OAuth2 authentication module for zele.
|
|
2
|
+
// Multi-account support: tokens are stored in the Prisma-managed SQLite DB
|
|
3
|
+
// (accounts table) keyed by email. Supports login (browser OAuth), per-account
|
|
4
|
+
// token refresh, and helpers to get authenticated GmailClient instances for
|
|
5
|
+
// one or all accounts.
|
|
6
|
+
// Migration: on first use, if legacy ~/.zele/tokens.json exists, it is
|
|
7
|
+
// imported into the DB and renamed to tokens.json.bak.
|
|
8
|
+
import http from 'node:http';
|
|
9
|
+
import readline from 'node:readline';
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import os from 'node:os';
|
|
13
|
+
import { OAuth2Client } from 'google-auth-library';
|
|
14
|
+
import fkill from 'fkill';
|
|
15
|
+
import pc from 'picocolors';
|
|
16
|
+
import { getPrisma } from './db.js';
|
|
17
|
+
import { GmailClient } from './gmail-client.js';
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Config
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
const ZELE_DIR = path.join(os.homedir(), '.zele');
|
|
22
|
+
const LEGACY_TOKENS_FILE = path.join(ZELE_DIR, 'tokens.json');
|
|
23
|
+
const CLIENT_ID = process.env.ZELE_CLIENT_ID ??
|
|
24
|
+
'406964657835-aq8lmia8j95dhl1a2bvharmfk3t1hgqj.apps.googleusercontent.com';
|
|
25
|
+
const CLIENT_SECRET = process.env.ZELE_CLIENT_SECRET ?? 'kSmqreRr0qwBWJgbf5Y-PjSU';
|
|
26
|
+
const REDIRECT_PORT = 8089;
|
|
27
|
+
const SCOPES = [
|
|
28
|
+
'https://mail.google.com/', // Gmail (full)
|
|
29
|
+
'https://www.googleapis.com/auth/calendar', // Calendar (full)
|
|
30
|
+
'https://www.googleapis.com/auth/userinfo.email', // Email identity
|
|
31
|
+
];
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// OAuth2 client factory
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
export function createOAuth2Client() {
|
|
36
|
+
return new OAuth2Client({
|
|
37
|
+
clientId: CLIENT_ID,
|
|
38
|
+
clientSecret: CLIENT_SECRET,
|
|
39
|
+
redirectUri: `http://localhost:${REDIRECT_PORT}`,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Legacy migration: tokens.json → DB
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
async function migrateLegacyTokens() {
|
|
46
|
+
if (!fs.existsSync(LEGACY_TOKENS_FILE))
|
|
47
|
+
return;
|
|
48
|
+
const prisma = await getPrisma();
|
|
49
|
+
const count = await prisma.accounts.count();
|
|
50
|
+
if (count > 0) {
|
|
51
|
+
// DB already has accounts — skip migration
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const data = fs.readFileSync(LEGACY_TOKENS_FILE, 'utf-8');
|
|
56
|
+
const tokens = JSON.parse(data);
|
|
57
|
+
// We need to discover the email for this token
|
|
58
|
+
const oauth2Client = createOAuth2Client();
|
|
59
|
+
oauth2Client.setCredentials(tokens);
|
|
60
|
+
// Refresh if expired
|
|
61
|
+
if (tokens.expiry_date && tokens.expiry_date < Date.now()) {
|
|
62
|
+
const { credentials } = await oauth2Client.refreshAccessToken();
|
|
63
|
+
oauth2Client.setCredentials(credentials);
|
|
64
|
+
Object.assign(tokens, credentials);
|
|
65
|
+
}
|
|
66
|
+
const client = new GmailClient({ auth: oauth2Client });
|
|
67
|
+
const profile = await client.getProfile();
|
|
68
|
+
const email = profile.emailAddress;
|
|
69
|
+
await prisma.accounts.create({
|
|
70
|
+
data: {
|
|
71
|
+
email,
|
|
72
|
+
tokens: JSON.stringify(tokens),
|
|
73
|
+
updated_at: new Date(),
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
// Rename old file so we don't migrate again
|
|
77
|
+
fs.renameSync(LEGACY_TOKENS_FILE, LEGACY_TOKENS_FILE + '.bak');
|
|
78
|
+
process.stderr.write(pc.green(`Migrated legacy tokens for ${email}`) + '\n');
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
process.stderr.write(pc.yellow(`Warning: legacy token migration failed: ${err}`) + '\n');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Browser OAuth flow
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
function extractCodeFromInput(input) {
|
|
88
|
+
const trimmed = input.trim();
|
|
89
|
+
if (!trimmed)
|
|
90
|
+
return null;
|
|
91
|
+
try {
|
|
92
|
+
const url = new URL(trimmed);
|
|
93
|
+
const code = url.searchParams.get('code');
|
|
94
|
+
if (code)
|
|
95
|
+
return code;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Not a URL
|
|
99
|
+
}
|
|
100
|
+
if (trimmed.length > 10 && !trimmed.includes(' ')) {
|
|
101
|
+
return trimmed;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
async function getAuthCodeFromBrowser(oauth2Client) {
|
|
106
|
+
const authUrl = oauth2Client.generateAuthUrl({
|
|
107
|
+
access_type: 'offline',
|
|
108
|
+
scope: SCOPES,
|
|
109
|
+
prompt: 'consent',
|
|
110
|
+
});
|
|
111
|
+
await fkill(`:${REDIRECT_PORT}`, { force: true, silent: true }).catch(() => { });
|
|
112
|
+
process.stderr.write('\n' + pc.bold('1.') + ' Open this URL to authorize:\n\n');
|
|
113
|
+
process.stderr.write(' ' + pc.cyan(pc.underline(authUrl)) + '\n\n');
|
|
114
|
+
process.stderr.write(pc.bold('2.') + ' If running locally, the browser will redirect automatically.\n');
|
|
115
|
+
process.stderr.write(pc.dim(' If running remotely, the redirect page won\'t load — that\'s fine.') + '\n');
|
|
116
|
+
process.stderr.write(pc.dim(' Just copy the URL from your browser\'s address bar and paste it below.') + '\n\n');
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
let resolved = false;
|
|
119
|
+
let server = null;
|
|
120
|
+
let rl = null;
|
|
121
|
+
function finish(code) {
|
|
122
|
+
if (resolved)
|
|
123
|
+
return;
|
|
124
|
+
resolved = true;
|
|
125
|
+
server?.close();
|
|
126
|
+
if (rl) {
|
|
127
|
+
rl.close();
|
|
128
|
+
process.stdin.unref();
|
|
129
|
+
}
|
|
130
|
+
resolve(code);
|
|
131
|
+
}
|
|
132
|
+
function fail(err) {
|
|
133
|
+
if (resolved)
|
|
134
|
+
return;
|
|
135
|
+
resolved = true;
|
|
136
|
+
server?.close();
|
|
137
|
+
rl?.close();
|
|
138
|
+
reject(err);
|
|
139
|
+
}
|
|
140
|
+
server = http.createServer((req, res) => {
|
|
141
|
+
const url = new URL(req.url, `http://localhost:${REDIRECT_PORT}`);
|
|
142
|
+
const code = url.searchParams.get('code');
|
|
143
|
+
const error = url.searchParams.get('error');
|
|
144
|
+
if (error) {
|
|
145
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
146
|
+
res.end(`<h1>Error: ${error}</h1>`);
|
|
147
|
+
fail(new Error(error));
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (code) {
|
|
151
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
152
|
+
res.end('<h1>Success! You can close this window.</h1>');
|
|
153
|
+
finish(code);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
157
|
+
res.end('<h1>No authorization code received</h1>');
|
|
158
|
+
});
|
|
159
|
+
server.listen(REDIRECT_PORT);
|
|
160
|
+
if (process.stdin.isTTY) {
|
|
161
|
+
rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
162
|
+
rl.question(pc.dim('Paste redirect URL here (or wait for auto-redirect): '), (answer) => {
|
|
163
|
+
const code = extractCodeFromInput(answer);
|
|
164
|
+
if (code) {
|
|
165
|
+
finish(code);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
process.stderr.write(pc.yellow('Could not extract authorization code from input.') + '\n');
|
|
169
|
+
process.stderr.write(pc.dim('Waiting for browser redirect...') + '\n');
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// Login: browser OAuth → save tokens to DB
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
/**
|
|
179
|
+
* Run the full browser OAuth flow and save the account to the DB.
|
|
180
|
+
* Returns the email and an authenticated GmailClient.
|
|
181
|
+
*/
|
|
182
|
+
export async function login() {
|
|
183
|
+
const oauth2Client = createOAuth2Client();
|
|
184
|
+
const code = await getAuthCodeFromBrowser(oauth2Client);
|
|
185
|
+
process.stderr.write(pc.dim('Got authorization code, exchanging for tokens...') + '\n');
|
|
186
|
+
const { tokens } = await oauth2Client.getToken(code);
|
|
187
|
+
oauth2Client.setCredentials(tokens);
|
|
188
|
+
// Discover email
|
|
189
|
+
const client = new GmailClient({ auth: oauth2Client });
|
|
190
|
+
const profile = await client.getProfile();
|
|
191
|
+
const email = profile.emailAddress;
|
|
192
|
+
// Upsert account in DB
|
|
193
|
+
const prisma = await getPrisma();
|
|
194
|
+
await prisma.accounts.upsert({
|
|
195
|
+
where: { email },
|
|
196
|
+
create: { email, tokens: JSON.stringify(tokens), updated_at: new Date() },
|
|
197
|
+
update: { tokens: JSON.stringify(tokens), updated_at: new Date() },
|
|
198
|
+
});
|
|
199
|
+
return { email, client };
|
|
200
|
+
}
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// Logout: remove account from DB
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
export async function logout(email) {
|
|
205
|
+
const prisma = await getPrisma();
|
|
206
|
+
await prisma.accounts.delete({ where: { email } });
|
|
207
|
+
}
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
// Account listing
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
export async function listAccounts() {
|
|
212
|
+
await migrateLegacyTokens();
|
|
213
|
+
const prisma = await getPrisma();
|
|
214
|
+
const rows = await prisma.accounts.findMany({ select: { email: true } });
|
|
215
|
+
return rows.map((r) => r.email);
|
|
216
|
+
}
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
// Get authenticated clients
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
/**
|
|
221
|
+
* Create an authenticated OAuth2Client for a known account.
|
|
222
|
+
* Loads tokens from DB, refreshes if expired, saves refreshed tokens back.
|
|
223
|
+
*/
|
|
224
|
+
async function authenticateAccount(email) {
|
|
225
|
+
const prisma = await getPrisma();
|
|
226
|
+
const row = await prisma.accounts.findUnique({ where: { email } });
|
|
227
|
+
if (!row) {
|
|
228
|
+
throw new Error(`No account found for ${email}. Run: zele auth login`);
|
|
229
|
+
}
|
|
230
|
+
const tokens = JSON.parse(row.tokens);
|
|
231
|
+
const oauth2Client = createOAuth2Client();
|
|
232
|
+
oauth2Client.setCredentials(tokens);
|
|
233
|
+
// Refresh if expired — merge to preserve refresh_token which Google
|
|
234
|
+
// often omits from refresh responses
|
|
235
|
+
if (tokens.expiry_date && tokens.expiry_date < Date.now()) {
|
|
236
|
+
process.stderr.write(pc.dim(`Token expired for ${email}, refreshing...`) + '\n');
|
|
237
|
+
const { credentials } = await oauth2Client.refreshAccessToken();
|
|
238
|
+
const merged = { ...tokens, ...credentials };
|
|
239
|
+
oauth2Client.setCredentials(merged);
|
|
240
|
+
await prisma.accounts.update({
|
|
241
|
+
where: { email },
|
|
242
|
+
data: { tokens: JSON.stringify(merged), updated_at: new Date() },
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return oauth2Client;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Get authenticated GmailClient instances for all accounts (or filtered by email list).
|
|
249
|
+
* If no accounts are registered, throws with a helpful message.
|
|
250
|
+
*/
|
|
251
|
+
export async function getClients(accounts) {
|
|
252
|
+
await migrateLegacyTokens();
|
|
253
|
+
const allEmails = await listAccounts();
|
|
254
|
+
if (allEmails.length === 0) {
|
|
255
|
+
throw new Error('No accounts registered. Run: zele auth login');
|
|
256
|
+
}
|
|
257
|
+
const emails = accounts && accounts.length > 0
|
|
258
|
+
? allEmails.filter((e) => accounts.includes(e))
|
|
259
|
+
: allEmails;
|
|
260
|
+
if (emails.length === 0) {
|
|
261
|
+
const available = allEmails.join(', ');
|
|
262
|
+
throw new Error(`No matching accounts. Available: ${available}`);
|
|
263
|
+
}
|
|
264
|
+
const results = await Promise.all(emails.map(async (email) => {
|
|
265
|
+
const auth = await authenticateAccount(email);
|
|
266
|
+
return { email, client: new GmailClient({ auth }) };
|
|
267
|
+
}));
|
|
268
|
+
return results;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Get a single authenticated GmailClient. Errors if multiple accounts exist
|
|
272
|
+
* and no --account filter was provided.
|
|
273
|
+
*/
|
|
274
|
+
export async function getClient(accounts) {
|
|
275
|
+
const clients = await getClients(accounts);
|
|
276
|
+
if (clients.length === 1) {
|
|
277
|
+
return clients[0];
|
|
278
|
+
}
|
|
279
|
+
const emails = clients.map((c) => c.email).join('\n ');
|
|
280
|
+
throw new Error(`Multiple accounts matched. Specify --account:\n ${emails}`);
|
|
281
|
+
}
|
|
282
|
+
export async function getAuthStatuses() {
|
|
283
|
+
await migrateLegacyTokens();
|
|
284
|
+
const prisma = await getPrisma();
|
|
285
|
+
const rows = await prisma.accounts.findMany();
|
|
286
|
+
return rows.map((row) => {
|
|
287
|
+
const tokens = JSON.parse(row.tokens);
|
|
288
|
+
return {
|
|
289
|
+
email: row.email,
|
|
290
|
+
expiresAt: tokens.expiry_date ? new Date(tokens.expiry_date) : undefined,
|
|
291
|
+
};
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// zele — Gmail CLI built on goke.
|
|
3
|
+
// Entry point: registers all commands, global options, help, and version.
|
|
4
|
+
// Uses goke for command parsing with zod schemas for type-safe options.
|
|
5
|
+
import { goke } from 'goke';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { registerAuthCommands } from './commands/auth-cmd.js';
|
|
8
|
+
import { registerMailCommands } from './commands/mail.js';
|
|
9
|
+
import { registerMailActionCommands } from './commands/mail-actions.js';
|
|
10
|
+
import { registerDraftCommands } from './commands/draft.js';
|
|
11
|
+
import { registerLabelCommands } from './commands/label.js';
|
|
12
|
+
import { registerAttachmentCommands } from './commands/attachment.js';
|
|
13
|
+
import { registerProfileCommands } from './commands/profile.js';
|
|
14
|
+
const cli = goke('zele');
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Global options
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
cli.option('--account <account>', z.array(z.string()).describe('Filter by email account (repeatable)'));
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Register all command modules
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
registerAuthCommands(cli);
|
|
23
|
+
registerMailCommands(cli);
|
|
24
|
+
registerMailActionCommands(cli);
|
|
25
|
+
registerDraftCommands(cli);
|
|
26
|
+
registerLabelCommands(cli);
|
|
27
|
+
registerAttachmentCommands(cli);
|
|
28
|
+
registerProfileCommands(cli);
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Help & version
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
cli.help();
|
|
33
|
+
cli.version('0.1.1');
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Parse & run
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
cli.parse();
|
|
38
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,kCAAkC;AAClC,0EAA0E;AAC1E,wEAAwE;AAExE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAA;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAE/D,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;AAExB,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E,GAAG,CAAC,MAAM,CACR,qBAAqB,EACrB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,sCAAsC,CAAC,CACrE,CAAA;AAED,8EAA8E;AAC9E,+BAA+B;AAC/B,8EAA8E;AAE9E,oBAAoB,CAAC,GAAG,CAAC,CAAA;AACzB,oBAAoB,CAAC,GAAG,CAAC,CAAA;AACzB,0BAA0B,CAAC,GAAG,CAAC,CAAA;AAC/B,qBAAqB,CAAC,GAAG,CAAC,CAAA;AAC1B,qBAAqB,CAAC,GAAG,CAAC,CAAA;AAC1B,0BAA0B,CAAC,GAAG,CAAC,CAAA;AAC/B,uBAAuB,CAAC,GAAG,CAAC,CAAA;AAE5B,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E,GAAG,CAAC,IAAI,EAAE,CAAA;AACV,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;AAEpB,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,GAAG,CAAC,KAAK,EAAE,CAAA"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Attachment commands: list, get (download).
|
|
2
|
+
// Lists attachments for a message and downloads them to disk.
|
|
3
|
+
// Skips re-download if file already exists with same size (like gogcli).
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { getClient } from '../auth.js';
|
|
8
|
+
import * as out from '../output.js';
|
|
9
|
+
export function registerAttachmentCommands(cli) {
|
|
10
|
+
// =========================================================================
|
|
11
|
+
// attachment list
|
|
12
|
+
// =========================================================================
|
|
13
|
+
cli
|
|
14
|
+
.command('attachment list <messageId>', 'List attachments for a message')
|
|
15
|
+
.action(async (messageId, options) => {
|
|
16
|
+
const { client } = await getClient(options.account);
|
|
17
|
+
const msg = await client.getMessage({ messageId });
|
|
18
|
+
if ('raw' in msg) {
|
|
19
|
+
out.error('Cannot list attachments for raw messages');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const attachments = msg.attachments;
|
|
23
|
+
if (attachments.length === 0) {
|
|
24
|
+
out.hint('No attachments');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
out.printList(attachments.map((a) => ({
|
|
28
|
+
attachment_id: a.attachmentId,
|
|
29
|
+
filename: a.filename,
|
|
30
|
+
type: a.mimeType,
|
|
31
|
+
size: formatSize(a.size),
|
|
32
|
+
})));
|
|
33
|
+
out.hint(`${attachments.length} attachment(s)`);
|
|
34
|
+
});
|
|
35
|
+
// =========================================================================
|
|
36
|
+
// attachment get
|
|
37
|
+
// =========================================================================
|
|
38
|
+
cli
|
|
39
|
+
.command('attachment get <messageId> <attachmentId>', 'Download an attachment')
|
|
40
|
+
.option('--out-dir <outDir>', z.string().default('.').describe('Output directory'))
|
|
41
|
+
.option('--filename <filename>', z.string().describe('Override filename'))
|
|
42
|
+
.action(async (messageId, attachmentId, options) => {
|
|
43
|
+
const { client } = await getClient(options.account);
|
|
44
|
+
// Get attachment metadata first
|
|
45
|
+
const msg = await client.getMessage({ messageId });
|
|
46
|
+
if ('raw' in msg) {
|
|
47
|
+
out.error('Cannot get attachments for raw messages');
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
const meta = msg.attachments.find((a) => a.attachmentId === attachmentId);
|
|
51
|
+
const filename = options.filename ?? meta?.filename ?? `${messageId}_${attachmentId.slice(0, 8)}`;
|
|
52
|
+
const outPath = path.resolve(options.outDir, filename);
|
|
53
|
+
// Check if file already exists with same size (skip re-download)
|
|
54
|
+
if (fs.existsSync(outPath) && meta) {
|
|
55
|
+
const stat = fs.statSync(outPath);
|
|
56
|
+
if (stat.size === meta.size) {
|
|
57
|
+
out.printYaml({ path: outPath, cached: true, size: stat.size });
|
|
58
|
+
out.hint(`Cached: ${outPath}`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Download
|
|
63
|
+
const base64Data = await client.getAttachment({ messageId, attachmentId });
|
|
64
|
+
const buffer = Buffer.from(base64Data, 'base64');
|
|
65
|
+
// Ensure output directory exists
|
|
66
|
+
const dir = path.dirname(outPath);
|
|
67
|
+
if (!fs.existsSync(dir)) {
|
|
68
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
69
|
+
}
|
|
70
|
+
fs.writeFileSync(outPath, buffer);
|
|
71
|
+
out.printYaml({ path: outPath, cached: false, size: buffer.length });
|
|
72
|
+
out.success(`Saved: ${outPath} (${formatSize(buffer.length)})`);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Helpers
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
function formatSize(bytes) {
|
|
79
|
+
if (bytes < 1024)
|
|
80
|
+
return `${bytes} B`;
|
|
81
|
+
if (bytes < 1024 * 1024)
|
|
82
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
83
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=attachment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment.js","sourceRoot":"","sources":["../../src/commands/attachment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Auth commands: login, logout, status.
|
|
2
|
+
// Manages OAuth2 authentication for zele.
|
|
3
|
+
// Supports multiple accounts: login adds accounts, logout removes one.
|
|
4
|
+
import { login, logout, listAccounts, getAuthStatuses } from '../auth.js';
|
|
5
|
+
import * as out from '../output.js';
|
|
6
|
+
export function registerAuthCommands(cli) {
|
|
7
|
+
cli
|
|
8
|
+
.command('auth login', 'Authenticate with Google (opens browser)')
|
|
9
|
+
.action(async () => {
|
|
10
|
+
const { email } = await login();
|
|
11
|
+
out.success(`Authenticated as ${email}`);
|
|
12
|
+
});
|
|
13
|
+
cli
|
|
14
|
+
.command('auth logout [email]', 'Remove stored credentials for an account')
|
|
15
|
+
.option('--force', 'Skip confirmation')
|
|
16
|
+
.action(async (email, options) => {
|
|
17
|
+
const accounts = await listAccounts();
|
|
18
|
+
if (accounts.length === 0) {
|
|
19
|
+
out.hint('No accounts currently authenticated');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// If no email specified and multiple accounts: error with list
|
|
23
|
+
if (!email && accounts.length > 1) {
|
|
24
|
+
out.error('Multiple accounts logged in. Specify which to remove:');
|
|
25
|
+
for (const a of accounts) {
|
|
26
|
+
process.stderr.write(` ${a}\n`);
|
|
27
|
+
}
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
// If no email and only one account, use that one
|
|
31
|
+
const targetEmail = email ?? accounts[0];
|
|
32
|
+
if (!accounts.includes(targetEmail)) {
|
|
33
|
+
out.error(`Account not found: ${targetEmail}`);
|
|
34
|
+
out.hint(`Logged in accounts: ${accounts.join(', ')}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
if (!options.force) {
|
|
38
|
+
if (!process.stdin.isTTY) {
|
|
39
|
+
out.error('Use --force to logout non-interactively');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
const readline = await import('node:readline');
|
|
43
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
44
|
+
const answer = await new Promise((resolve) => {
|
|
45
|
+
rl.question(`Remove credentials for ${targetEmail}? [y/N] `, resolve);
|
|
46
|
+
});
|
|
47
|
+
rl.close();
|
|
48
|
+
if (answer.toLowerCase() !== 'y') {
|
|
49
|
+
out.hint('Cancelled');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
await logout(targetEmail);
|
|
54
|
+
out.success(`Credentials removed for ${targetEmail}`);
|
|
55
|
+
});
|
|
56
|
+
cli
|
|
57
|
+
.command('auth status', 'Show authentication status')
|
|
58
|
+
.action(async () => {
|
|
59
|
+
const statuses = await getAuthStatuses();
|
|
60
|
+
if (statuses.length === 0) {
|
|
61
|
+
out.hint('Not authenticated. Run: zele auth login');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
out.printList(statuses.map((s) => ({
|
|
65
|
+
email: s.email,
|
|
66
|
+
status: 'Authenticated',
|
|
67
|
+
expires: s.expiresAt?.toISOString() ?? 'unknown',
|
|
68
|
+
})));
|
|
69
|
+
out.hint(`${statuses.length} account(s)`);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=auth-cmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-cmd.js","sourceRoot":"","sources":["../../src/commands/auth-cmd.ts"],"names":[],"mappings":"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"}
|