@vinnyum/newsletter-sync 1.0.0 → 1.0.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/README.md +54 -19
- package/bin/cli.js +7 -1
- package/index.js +46 -9
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ npx newsletter-sync [options]
|
|
|
27
27
|
### Options
|
|
28
28
|
|
|
29
29
|
| Flag | Description |
|
|
30
|
-
|
|
30
|
+
| --- | --- |
|
|
31
31
|
| `-c, --config <file>` | Path to a JSON configuration file |
|
|
32
32
|
| `--apiKey <key>` | Composio API Key (overrides env `COMPOSIO_API_KEY`) |
|
|
33
33
|
| `--zohoAccountId <id>` | Zoho Mail Account ID |
|
|
@@ -38,20 +38,22 @@ npx newsletter-sync [options]
|
|
|
38
38
|
| `--fromEmail <email>` | From email address for Zoho Mail alert emails |
|
|
39
39
|
| `--processed <path>` | Path to save the processed IDs tracking list (default: `./processed_emails.json`) |
|
|
40
40
|
| `--log <path>` | Path to save the execution logs (default: `./cron.log`) |
|
|
41
|
+
| `--supabaseUrl <url>` | Supabase Project URL (overrides env `SUPABASE_URL`) |
|
|
42
|
+
| `--supabaseKey <key>` | Supabase Key (overrides env `SUPABASE_KEY`) |
|
|
41
43
|
|
|
42
|
-
## Setup Example
|
|
44
|
+
## Setup Example (Local Execution)
|
|
43
45
|
|
|
44
46
|
### 1. Create a `config.json` file
|
|
45
47
|
|
|
46
48
|
```json
|
|
47
49
|
{
|
|
48
50
|
"composioApiKey": "your-composio-api-key",
|
|
49
|
-
"zohoAccountId": "
|
|
50
|
-
"zohoFolderId": "
|
|
51
|
-
"senderFilter": "newsletter@
|
|
52
|
-
"notebookId": "
|
|
53
|
-
"alertEmail": "
|
|
54
|
-
"fromEmail": "
|
|
51
|
+
"zohoAccountId": "your-zoho-account-id",
|
|
52
|
+
"zohoFolderId": "your-zoho-folder-id",
|
|
53
|
+
"senderFilter": "newsletter@example.com",
|
|
54
|
+
"notebookId": "your-notebook-id-uuid",
|
|
55
|
+
"alertEmail": "alerts@yourdomain.com",
|
|
56
|
+
"fromEmail": "sender@yourdomain.com",
|
|
55
57
|
"processedPath": "./processed_emails.json",
|
|
56
58
|
"logPath": "./cron.log"
|
|
57
59
|
}
|
|
@@ -63,16 +65,49 @@ npx newsletter-sync [options]
|
|
|
63
65
|
npx newsletter-sync --config ./config.json
|
|
64
66
|
```
|
|
65
67
|
|
|
66
|
-
|
|
68
|
+
---
|
|
67
69
|
|
|
68
|
-
|
|
70
|
+
## Setup for Cloud Execution (GitHub Actions + Supabase)
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
To run this tool in the cloud weekly, we use a combination of GitHub Actions and a Supabase database to track processed email IDs.
|
|
73
|
+
|
|
74
|
+
### 1. Setup Supabase Table
|
|
75
|
+
|
|
76
|
+
In your Supabase SQL Editor, run the following DDL query to create the tracking table:
|
|
77
|
+
|
|
78
|
+
```sql
|
|
79
|
+
create table processed_emails (
|
|
80
|
+
message_id text primary key,
|
|
81
|
+
created_at timestamp with time zone default timezone('utc'::text, now()) not null
|
|
82
|
+
);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 2. Export NotebookLM Cookies
|
|
86
|
+
|
|
87
|
+
The `nlm` CLI needs your Google Account session. To get the cookies in JSON format:
|
|
88
|
+
|
|
89
|
+
1. Log in to [notebooklm.google.com](https://notebooklm.google.com) in Chrome.
|
|
90
|
+
2. Use a Chrome extension like **EditThisCookie** or **Get cookies.txt as JSON** to copy all active cookies as a JSON array.
|
|
91
|
+
|
|
92
|
+
### 3. Add Secrets in GitHub Repository
|
|
93
|
+
|
|
94
|
+
Go to your GitHub repository Settings ➜ Secrets and Variables ➜ Actions, and add the following repository secrets:
|
|
95
|
+
|
|
96
|
+
- `COMPOSIO_API_KEY`: Your Composio API Key.
|
|
97
|
+
- `SUPABASE_URL`: Your Supabase Project URL.
|
|
98
|
+
- `SUPABASE_KEY`: Your Supabase Project Anon/Service Key.
|
|
99
|
+
- `NLM_COOKIES_JSON`: The JSON array of cookies copied in step 2.
|
|
100
|
+
- `SYNC_CONFIG_JSON`: A JSON config representing your Zoho and NotebookLM IDs:
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"zohoAccountId": "your-zoho-account-id",
|
|
105
|
+
"zohoFolderId": "your-zoho-folder-id",
|
|
106
|
+
"senderFilter": "newsletter@example.com",
|
|
107
|
+
"notebookId": "your-notebook-id-uuid",
|
|
108
|
+
"alertEmail": "alerts@yourdomain.com",
|
|
109
|
+
"fromEmail": "sender@yourdomain.com"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Once configured, the GitHub Action workflow will run automatically every Monday at 9:00 AM UTC. You can also trigger it manually from the Actions tab in your repository.
|
package/bin/cli.js
CHANGED
|
@@ -16,6 +16,8 @@ const options = {
|
|
|
16
16
|
fromEmail: { type: 'string' },
|
|
17
17
|
processed: { type: 'string' },
|
|
18
18
|
log: { type: 'string' },
|
|
19
|
+
supabaseUrl: { type: 'string' },
|
|
20
|
+
supabaseKey: { type: 'string' },
|
|
19
21
|
help: { type: 'boolean', short: 'h' }
|
|
20
22
|
};
|
|
21
23
|
|
|
@@ -34,6 +36,8 @@ Options:
|
|
|
34
36
|
--fromEmail <email> From email for error alert emails (must be verified in Zoho)
|
|
35
37
|
--processed <path> Path to processed_emails.json (default: ./processed_emails.json)
|
|
36
38
|
--log <path> Path to execution log file (default: ./cron.log)
|
|
39
|
+
--supabaseUrl <url> Supabase Project URL (can be set as SUPABASE_URL env var)
|
|
40
|
+
--supabaseKey <key> Supabase Anon/Service Key (can be set as SUPABASE_KEY env var)
|
|
37
41
|
-h, --help Show help
|
|
38
42
|
`);
|
|
39
43
|
}
|
|
@@ -74,7 +78,9 @@ async function main() {
|
|
|
74
78
|
alertEmail: values.alertEmail || configData.alertEmail,
|
|
75
79
|
fromEmail: values.fromEmail || configData.fromEmail,
|
|
76
80
|
processedPath: values.processed || configData.processedPath || './processed_emails.json',
|
|
77
|
-
logPath: values.log || configData.logPath || './cron.log'
|
|
81
|
+
logPath: values.log || configData.logPath || './cron.log',
|
|
82
|
+
supabaseUrl: values.supabaseUrl || configData.supabaseUrl || process.env.SUPABASE_URL,
|
|
83
|
+
supabaseKey: values.supabaseKey || configData.supabaseKey || process.env.SUPABASE_KEY
|
|
78
84
|
};
|
|
79
85
|
|
|
80
86
|
// 3. Run Sincronizador
|
package/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { execSync } from 'node:child_process';
|
|
4
4
|
import puppeteer from 'puppeteer';
|
|
5
|
+
import { createClient } from '@supabase/supabase-js';
|
|
5
6
|
import ComposioModule from '@composio/client';
|
|
6
7
|
|
|
7
8
|
const Composio = ComposioModule.default || ComposioModule.Composio || ComposioModule;
|
|
@@ -20,7 +21,9 @@ export async function runSync(options = {}) {
|
|
|
20
21
|
alertEmail,
|
|
21
22
|
fromEmail,
|
|
22
23
|
processedPath = './processed_emails.json',
|
|
23
|
-
logPath = './cron.log'
|
|
24
|
+
logPath = './cron.log',
|
|
25
|
+
supabaseUrl = process.env.SUPABASE_URL,
|
|
26
|
+
supabaseKey = process.env.SUPABASE_KEY
|
|
24
27
|
} = options;
|
|
25
28
|
|
|
26
29
|
// Helper for logging
|
|
@@ -40,13 +43,35 @@ export async function runSync(options = {}) {
|
|
|
40
43
|
if (!senderFilter) throw new Error("Missing Sender Filter. Pass --senderFilter.");
|
|
41
44
|
if (!notebookId) throw new Error("Missing Notebook ID. Pass --notebookId.");
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
// Initialize State Tracker (Supabase or Local JSON)
|
|
47
|
+
const useSupabase = !!(supabaseUrl && supabaseKey);
|
|
48
|
+
let supabaseClient = null;
|
|
44
49
|
let processed = [];
|
|
45
|
-
|
|
50
|
+
|
|
51
|
+
if (useSupabase) {
|
|
52
|
+
log("Using Supabase database for tracking processed emails.");
|
|
53
|
+
supabaseClient = createClient(supabaseUrl, supabaseKey);
|
|
46
54
|
try {
|
|
47
|
-
|
|
55
|
+
const { data, error } = await supabaseClient
|
|
56
|
+
.from('processed_emails')
|
|
57
|
+
.select('message_id');
|
|
58
|
+
|
|
59
|
+
if (error) throw error;
|
|
60
|
+
processed = (data || []).map(row => row.message_id);
|
|
61
|
+
log(`Loaded ${processed.length} processed IDs from Supabase.`);
|
|
48
62
|
} catch (e) {
|
|
49
|
-
|
|
63
|
+
throw new Error(`Failed to load processed emails from Supabase: ${e.message}`);
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
const processedFile = path.resolve(process.cwd(), processedPath);
|
|
67
|
+
log(`Using local file for tracking processed emails: ${processedFile}`);
|
|
68
|
+
if (fs.existsSync(processedFile)) {
|
|
69
|
+
try {
|
|
70
|
+
processed = JSON.parse(fs.readFileSync(processedFile, 'utf8'));
|
|
71
|
+
log(`Loaded ${processed.length} processed IDs from local file.`);
|
|
72
|
+
} catch (e) {
|
|
73
|
+
log(`Warning: Failed to parse processed list, starting fresh.`);
|
|
74
|
+
}
|
|
50
75
|
}
|
|
51
76
|
}
|
|
52
77
|
|
|
@@ -145,13 +170,25 @@ export async function runSync(options = {}) {
|
|
|
145
170
|
}
|
|
146
171
|
|
|
147
172
|
// Track as processed
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
173
|
+
if (useSupabase) {
|
|
174
|
+
const { error } = await supabaseClient
|
|
175
|
+
.from('processed_emails')
|
|
176
|
+
.insert({ message_id: email.messageId });
|
|
177
|
+
|
|
178
|
+
if (error) {
|
|
179
|
+
log(`Warning: Failed to save ${email.messageId} to Supabase: ${error.message}`);
|
|
180
|
+
} else {
|
|
181
|
+
log(`Logged ${email.messageId} to Supabase.`);
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
const processedFile = path.resolve(process.cwd(), processedPath);
|
|
185
|
+
processed.push(email.messageId);
|
|
186
|
+
fs.writeFileSync(processedFile, JSON.stringify(processed, null, 2));
|
|
187
|
+
log(`Logged ${email.messageId} to local file.`);
|
|
188
|
+
}
|
|
151
189
|
|
|
152
190
|
} catch (itemError) {
|
|
153
191
|
log(`Error processing email ${email.messageId}: ${itemError.message}`);
|
|
154
|
-
// Continue with other items
|
|
155
192
|
}
|
|
156
193
|
}
|
|
157
194
|
|
package/package.json
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vinnyum/newsletter-sync",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Weekly automated newsletter to PDF converter and Google NotebookLM source synchronizer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"newsletter-sync": "
|
|
8
|
+
"newsletter-sync": "bin/cli.js"
|
|
9
9
|
},
|
|
10
10
|
"engines": {
|
|
11
11
|
"node": ">=18.0.0"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@composio/client": "^0.1.0-alpha.75",
|
|
15
|
+
"@supabase/supabase-js": "^2.48.0",
|
|
15
16
|
"puppeteer": "^25.3.0"
|
|
16
17
|
},
|
|
17
18
|
"author": {
|