stellar-memory 0.5.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/LICENSE +21 -0
- package/README.md +362 -0
- package/dist/api/routes/analytics.d.ts +15 -0
- package/dist/api/routes/analytics.js +131 -0
- package/dist/api/routes/analytics.js.map +1 -0
- package/dist/api/routes/conflicts.d.ts +12 -0
- package/dist/api/routes/conflicts.js +67 -0
- package/dist/api/routes/conflicts.js.map +1 -0
- package/dist/api/routes/consolidation.d.ts +11 -0
- package/dist/api/routes/consolidation.js +63 -0
- package/dist/api/routes/consolidation.js.map +1 -0
- package/dist/api/routes/constellation.d.ts +4 -0
- package/dist/api/routes/constellation.js +84 -0
- package/dist/api/routes/constellation.js.map +1 -0
- package/dist/api/routes/memories.d.ts +4 -0
- package/dist/api/routes/memories.js +219 -0
- package/dist/api/routes/memories.js.map +1 -0
- package/dist/api/routes/observations.d.ts +10 -0
- package/dist/api/routes/observations.js +42 -0
- package/dist/api/routes/observations.js.map +1 -0
- package/dist/api/routes/orbit.d.ts +4 -0
- package/dist/api/routes/orbit.js +71 -0
- package/dist/api/routes/orbit.js.map +1 -0
- package/dist/api/routes/projects.d.ts +15 -0
- package/dist/api/routes/projects.js +121 -0
- package/dist/api/routes/projects.js.map +1 -0
- package/dist/api/routes/scan.d.ts +4 -0
- package/dist/api/routes/scan.js +403 -0
- package/dist/api/routes/scan.js.map +1 -0
- package/dist/api/routes/sun.d.ts +4 -0
- package/dist/api/routes/sun.js +43 -0
- package/dist/api/routes/sun.js.map +1 -0
- package/dist/api/routes/system.d.ts +4 -0
- package/dist/api/routes/system.js +70 -0
- package/dist/api/routes/system.js.map +1 -0
- package/dist/api/routes/temporal.d.ts +13 -0
- package/dist/api/routes/temporal.js +82 -0
- package/dist/api/routes/temporal.js.map +1 -0
- package/dist/api/server.d.ts +2 -0
- package/dist/api/server.js +99 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/websocket.d.ts +53 -0
- package/dist/api/websocket.js +168 -0
- package/dist/api/websocket.js.map +1 -0
- package/dist/cli/index.d.ts +12 -0
- package/dist/cli/index.js +35 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +10 -0
- package/dist/cli/init.js +163 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/engine/analytics.d.ts +93 -0
- package/dist/engine/analytics.js +437 -0
- package/dist/engine/analytics.js.map +1 -0
- package/dist/engine/conflict.d.ts +54 -0
- package/dist/engine/conflict.js +322 -0
- package/dist/engine/conflict.js.map +1 -0
- package/dist/engine/consolidation.d.ts +83 -0
- package/dist/engine/consolidation.js +368 -0
- package/dist/engine/consolidation.js.map +1 -0
- package/dist/engine/constellation.d.ts +66 -0
- package/dist/engine/constellation.js +382 -0
- package/dist/engine/constellation.js.map +1 -0
- package/dist/engine/corona.d.ts +53 -0
- package/dist/engine/corona.js +181 -0
- package/dist/engine/corona.js.map +1 -0
- package/dist/engine/embedding.d.ts +44 -0
- package/dist/engine/embedding.js +168 -0
- package/dist/engine/embedding.js.map +1 -0
- package/dist/engine/gravity.d.ts +63 -0
- package/dist/engine/gravity.js +121 -0
- package/dist/engine/gravity.js.map +1 -0
- package/dist/engine/multiproject.d.ts +75 -0
- package/dist/engine/multiproject.js +241 -0
- package/dist/engine/multiproject.js.map +1 -0
- package/dist/engine/observation.d.ts +82 -0
- package/dist/engine/observation.js +357 -0
- package/dist/engine/observation.js.map +1 -0
- package/dist/engine/orbit.d.ts +91 -0
- package/dist/engine/orbit.js +249 -0
- package/dist/engine/orbit.js.map +1 -0
- package/dist/engine/planet.d.ts +64 -0
- package/dist/engine/planet.js +432 -0
- package/dist/engine/planet.js.map +1 -0
- package/dist/engine/procedural.d.ts +71 -0
- package/dist/engine/procedural.js +259 -0
- package/dist/engine/procedural.js.map +1 -0
- package/dist/engine/quality.d.ts +48 -0
- package/dist/engine/quality.js +245 -0
- package/dist/engine/quality.js.map +1 -0
- package/dist/engine/repository.d.ts +79 -0
- package/dist/engine/repository.js +13 -0
- package/dist/engine/repository.js.map +1 -0
- package/dist/engine/sun.d.ts +61 -0
- package/dist/engine/sun.js +240 -0
- package/dist/engine/sun.js.map +1 -0
- package/dist/engine/temporal.d.ts +67 -0
- package/dist/engine/temporal.js +283 -0
- package/dist/engine/temporal.js.map +1 -0
- package/dist/engine/types.d.ts +179 -0
- package/dist/engine/types.js +27 -0
- package/dist/engine/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/connector-registry.d.ts +20 -0
- package/dist/mcp/connector-registry.js +35 -0
- package/dist/mcp/connector-registry.js.map +1 -0
- package/dist/mcp/server.d.ts +13 -0
- package/dist/mcp/server.js +242 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/daemon-tool.d.ts +16 -0
- package/dist/mcp/tools/daemon-tool.js +58 -0
- package/dist/mcp/tools/daemon-tool.js.map +1 -0
- package/dist/mcp/tools/ingestion-tools.d.ts +20 -0
- package/dist/mcp/tools/ingestion-tools.js +34 -0
- package/dist/mcp/tools/ingestion-tools.js.map +1 -0
- package/dist/mcp/tools/memory-tools.d.ts +122 -0
- package/dist/mcp/tools/memory-tools.js +1037 -0
- package/dist/mcp/tools/memory-tools.js.map +1 -0
- package/dist/scanner/cloud/github.d.ts +34 -0
- package/dist/scanner/cloud/github.js +260 -0
- package/dist/scanner/cloud/github.js.map +1 -0
- package/dist/scanner/cloud/google-drive.d.ts +30 -0
- package/dist/scanner/cloud/google-drive.js +289 -0
- package/dist/scanner/cloud/google-drive.js.map +1 -0
- package/dist/scanner/cloud/notion.d.ts +33 -0
- package/dist/scanner/cloud/notion.js +231 -0
- package/dist/scanner/cloud/notion.js.map +1 -0
- package/dist/scanner/cloud/slack.d.ts +38 -0
- package/dist/scanner/cloud/slack.js +282 -0
- package/dist/scanner/cloud/slack.js.map +1 -0
- package/dist/scanner/cloud/types.d.ts +73 -0
- package/dist/scanner/cloud/types.js +9 -0
- package/dist/scanner/cloud/types.js.map +1 -0
- package/dist/scanner/index.d.ts +35 -0
- package/dist/scanner/index.js +420 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/local/filesystem.d.ts +33 -0
- package/dist/scanner/local/filesystem.js +203 -0
- package/dist/scanner/local/filesystem.js.map +1 -0
- package/dist/scanner/local/git.d.ts +24 -0
- package/dist/scanner/local/git.js +161 -0
- package/dist/scanner/local/git.js.map +1 -0
- package/dist/scanner/local/parsers/code.d.ts +3 -0
- package/dist/scanner/local/parsers/code.js +127 -0
- package/dist/scanner/local/parsers/code.js.map +1 -0
- package/dist/scanner/local/parsers/index.d.ts +11 -0
- package/dist/scanner/local/parsers/index.js +24 -0
- package/dist/scanner/local/parsers/index.js.map +1 -0
- package/dist/scanner/local/parsers/json-parser.d.ts +3 -0
- package/dist/scanner/local/parsers/json-parser.js +117 -0
- package/dist/scanner/local/parsers/json-parser.js.map +1 -0
- package/dist/scanner/local/parsers/markdown.d.ts +3 -0
- package/dist/scanner/local/parsers/markdown.js +120 -0
- package/dist/scanner/local/parsers/markdown.js.map +1 -0
- package/dist/scanner/local/parsers/text.d.ts +3 -0
- package/dist/scanner/local/parsers/text.js +41 -0
- package/dist/scanner/local/parsers/text.js.map +1 -0
- package/dist/scanner/metadata-scanner.d.ts +67 -0
- package/dist/scanner/metadata-scanner.js +356 -0
- package/dist/scanner/metadata-scanner.js.map +1 -0
- package/dist/scanner/types.d.ts +47 -0
- package/dist/scanner/types.js +19 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/service/daemon.d.ts +23 -0
- package/dist/service/daemon.js +105 -0
- package/dist/service/daemon.js.map +1 -0
- package/dist/service/scheduler.d.ts +73 -0
- package/dist/service/scheduler.js +281 -0
- package/dist/service/scheduler.js.map +1 -0
- package/dist/storage/database.d.ts +10 -0
- package/dist/storage/database.js +265 -0
- package/dist/storage/database.js.map +1 -0
- package/dist/storage/queries.d.ts +85 -0
- package/dist/storage/queries.js +865 -0
- package/dist/storage/queries.js.map +1 -0
- package/dist/storage/sqlite-repository.d.ts +32 -0
- package/dist/storage/sqlite-repository.js +68 -0
- package/dist/storage/sqlite-repository.js.map +1 -0
- package/dist/storage/vec.d.ts +62 -0
- package/dist/storage/vec.js +111 -0
- package/dist/storage/vec.js.map +1 -0
- package/dist/utils/config.d.ts +5 -0
- package/dist/utils/config.js +60 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/logger.js +86 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/time.d.ts +21 -0
- package/dist/utils/time.js +42 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/tokenizer.d.ts +13 -0
- package/dist/utils/tokenizer.js +46 -0
- package/dist/utils/tokenizer.js.map +1 -0
- package/package.json +77 -0
- package/scripts/check-node.mjs +36 -0
- package/scripts/setup.mjs +157 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scanner/cloud/google-drive.ts — Google Drive connector.
|
|
3
|
+
*
|
|
4
|
+
* Supports both Service Account (server-to-server) and OAuth2 personal auth.
|
|
5
|
+
* Documents are exported as text/plain so binary formats (Sheets, Slides) are
|
|
6
|
+
* readable without additional parsers.
|
|
7
|
+
*
|
|
8
|
+
* Required credentials (one of two modes):
|
|
9
|
+
* Service Account: { client_email, private_key }
|
|
10
|
+
* OAuth2 personal: { client_id, client_secret, refresh_token }
|
|
11
|
+
*
|
|
12
|
+
* Required env var (or pass as credential):
|
|
13
|
+
* GOOGLE_DRIVE_ROOT_FOLDER_ID — optional; if set, scan is scoped to that folder
|
|
14
|
+
*
|
|
15
|
+
* Rate limits: Google Drive API v3 — 10 requests/second for metadata,
|
|
16
|
+
* 1 request/second for export. We apply exponential backoff on 429/503.
|
|
17
|
+
*/
|
|
18
|
+
import { createLogger } from '../../utils/logger.js';
|
|
19
|
+
const log = createLogger('google-drive');
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// GoogleDriveConnector
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
export class GoogleDriveConnector {
|
|
24
|
+
name = 'Google Drive';
|
|
25
|
+
type = 'google-drive';
|
|
26
|
+
auth = null;
|
|
27
|
+
// -------------------------------------------------------------------------
|
|
28
|
+
// authenticate
|
|
29
|
+
// -------------------------------------------------------------------------
|
|
30
|
+
async authenticate(credentials) {
|
|
31
|
+
validateCredentials(credentials);
|
|
32
|
+
const mode = credentials['client_email']
|
|
33
|
+
? 'service-account'
|
|
34
|
+
: 'oauth2';
|
|
35
|
+
log.info('Authenticating with Google Drive', { mode });
|
|
36
|
+
const accessToken = await fetchAccessToken(mode, credentials);
|
|
37
|
+
this.auth = {
|
|
38
|
+
mode,
|
|
39
|
+
accessToken,
|
|
40
|
+
expiresAt: new Date(Date.now() + 55 * 60 * 1000), // 55 min (tokens last 60)
|
|
41
|
+
credentials,
|
|
42
|
+
};
|
|
43
|
+
log.info('Google Drive authentication successful', { mode });
|
|
44
|
+
}
|
|
45
|
+
isAuthenticated() {
|
|
46
|
+
return this.auth !== null && new Date() < this.auth.expiresAt;
|
|
47
|
+
}
|
|
48
|
+
// -------------------------------------------------------------------------
|
|
49
|
+
// fetchDocuments
|
|
50
|
+
// -------------------------------------------------------------------------
|
|
51
|
+
async fetchDocuments(since) {
|
|
52
|
+
this.assertAuthenticated();
|
|
53
|
+
// Refresh token if within 2 minutes of expiry
|
|
54
|
+
if (this.auth && new Date() >= new Date(this.auth.expiresAt.getTime() - 120_000)) {
|
|
55
|
+
await this.refreshToken();
|
|
56
|
+
}
|
|
57
|
+
const query = buildDriveQuery(since);
|
|
58
|
+
log.info('Fetching Google Drive documents', { since: since?.toISOString(), query });
|
|
59
|
+
const files = await listFiles(this.auth.accessToken, query);
|
|
60
|
+
log.info('Found files in Google Drive', { count: files.length });
|
|
61
|
+
const docs = [];
|
|
62
|
+
for (const file of files) {
|
|
63
|
+
try {
|
|
64
|
+
const content = await exportFileContent(this.auth.accessToken, file.id, file.mimeType);
|
|
65
|
+
docs.push({
|
|
66
|
+
id: file.id,
|
|
67
|
+
title: file.name,
|
|
68
|
+
content,
|
|
69
|
+
url: `https://drive.google.com/file/d/${file.id}/view`,
|
|
70
|
+
mimeType: file.mimeType,
|
|
71
|
+
lastModified: new Date(file.modifiedTime),
|
|
72
|
+
author: file.owners?.[0]?.displayName,
|
|
73
|
+
metadata: {
|
|
74
|
+
driveId: file.id,
|
|
75
|
+
webViewLink: file.webViewLink,
|
|
76
|
+
iconLink: file.iconLink,
|
|
77
|
+
owners: file.owners,
|
|
78
|
+
sharedWithMe: file.sharedWithMe ?? false,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
log.warn('Failed to export Google Drive file', { fileId: file.id, name: file.name });
|
|
84
|
+
log.error('Export error', err instanceof Error ? err : new Error(String(err)));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return docs;
|
|
88
|
+
}
|
|
89
|
+
// -------------------------------------------------------------------------
|
|
90
|
+
// toMemory
|
|
91
|
+
// -------------------------------------------------------------------------
|
|
92
|
+
toMemory(doc) {
|
|
93
|
+
return {
|
|
94
|
+
content: `# ${doc.title}\n\n${doc.content}`,
|
|
95
|
+
summary: doc.title.slice(0, 120),
|
|
96
|
+
type: 'context',
|
|
97
|
+
tags: ['google-drive', 'cloud'],
|
|
98
|
+
source: 'cloud',
|
|
99
|
+
source_path: doc.url,
|
|
100
|
+
metadata: {
|
|
101
|
+
...doc.metadata,
|
|
102
|
+
cloudService: 'google-drive',
|
|
103
|
+
lastModified: doc.lastModified.toISOString(),
|
|
104
|
+
author: doc.author,
|
|
105
|
+
mimeType: doc.mimeType,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// -------------------------------------------------------------------------
|
|
110
|
+
// Private helpers
|
|
111
|
+
// -------------------------------------------------------------------------
|
|
112
|
+
assertAuthenticated() {
|
|
113
|
+
if (!this.isAuthenticated()) {
|
|
114
|
+
throw new Error('GoogleDriveConnector: not authenticated. Call authenticate() first.');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async refreshToken() {
|
|
118
|
+
if (!this.auth)
|
|
119
|
+
return;
|
|
120
|
+
log.debug('Refreshing Google Drive access token');
|
|
121
|
+
const token = await fetchAccessToken(this.auth.mode, this.auth.credentials);
|
|
122
|
+
this.auth.accessToken = token;
|
|
123
|
+
this.auth.expiresAt = new Date(Date.now() + 55 * 60 * 1000);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const GOOGLE_API_BASE = 'https://www.googleapis.com';
|
|
127
|
+
const MAX_RETRIES = 4;
|
|
128
|
+
async function fetchWithBackoff(url, init, attempt = 0) {
|
|
129
|
+
const res = await fetch(url, init);
|
|
130
|
+
if ((res.status === 429 || res.status === 503) && attempt < MAX_RETRIES) {
|
|
131
|
+
const delay = Math.min(1000 * 2 ** attempt, 16_000);
|
|
132
|
+
log.debug('Rate limited, retrying', { status: res.status, delay, attempt });
|
|
133
|
+
await sleep(delay);
|
|
134
|
+
return fetchWithBackoff(url, init, attempt + 1);
|
|
135
|
+
}
|
|
136
|
+
return res;
|
|
137
|
+
}
|
|
138
|
+
function sleep(ms) {
|
|
139
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
140
|
+
}
|
|
141
|
+
async function fetchAccessToken(mode, credentials) {
|
|
142
|
+
if (mode === 'service-account') {
|
|
143
|
+
return fetchServiceAccountToken(credentials);
|
|
144
|
+
}
|
|
145
|
+
return fetchOAuth2Token(credentials);
|
|
146
|
+
}
|
|
147
|
+
async function fetchServiceAccountToken(credentials) {
|
|
148
|
+
// Build a signed JWT and exchange it for an access token using Google's token endpoint.
|
|
149
|
+
// In production this would use the googleapis library; here we call the REST endpoint
|
|
150
|
+
// directly to keep the implementation self-contained without requiring the npm package
|
|
151
|
+
// at type-check time (the dep is declared in package.json).
|
|
152
|
+
const { client_email, private_key } = credentials;
|
|
153
|
+
if (!client_email || !private_key) {
|
|
154
|
+
throw new Error('Service account credentials must include client_email and private_key');
|
|
155
|
+
}
|
|
156
|
+
const now = Math.floor(Date.now() / 1000);
|
|
157
|
+
const claim = {
|
|
158
|
+
iss: client_email,
|
|
159
|
+
scope: 'https://www.googleapis.com/auth/drive.readonly',
|
|
160
|
+
aud: 'https://oauth2.googleapis.com/token',
|
|
161
|
+
iat: now,
|
|
162
|
+
exp: now + 3600,
|
|
163
|
+
};
|
|
164
|
+
// Sign the JWT using the private key via Node.js crypto (available natively)
|
|
165
|
+
const { createSign } = await import('node:crypto');
|
|
166
|
+
const header = base64url(JSON.stringify({ alg: 'RS256', typ: 'JWT' }));
|
|
167
|
+
const payload = base64url(JSON.stringify(claim));
|
|
168
|
+
const input = `${header}.${payload}`;
|
|
169
|
+
const signer = createSign('SHA256');
|
|
170
|
+
signer.update(input);
|
|
171
|
+
const signature = signer.sign(private_key, 'base64url');
|
|
172
|
+
const jwt = `${input}.${signature}`;
|
|
173
|
+
const res = await fetch('https://oauth2.googleapis.com/token', {
|
|
174
|
+
method: 'POST',
|
|
175
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
176
|
+
body: new URLSearchParams({
|
|
177
|
+
grant_type: 'urn:ietf:params:oauth2:grant-type:jwt-bearer',
|
|
178
|
+
assertion: jwt,
|
|
179
|
+
}),
|
|
180
|
+
});
|
|
181
|
+
if (!res.ok) {
|
|
182
|
+
const text = await res.text();
|
|
183
|
+
throw new Error(`Failed to fetch service account token: ${res.status} ${text}`);
|
|
184
|
+
}
|
|
185
|
+
const data = await res.json();
|
|
186
|
+
return data.access_token;
|
|
187
|
+
}
|
|
188
|
+
async function fetchOAuth2Token(credentials) {
|
|
189
|
+
const { client_id, client_secret, refresh_token } = credentials;
|
|
190
|
+
if (!client_id || !client_secret || !refresh_token) {
|
|
191
|
+
throw new Error('OAuth2 credentials must include client_id, client_secret, and refresh_token');
|
|
192
|
+
}
|
|
193
|
+
const res = await fetch('https://oauth2.googleapis.com/token', {
|
|
194
|
+
method: 'POST',
|
|
195
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
196
|
+
body: new URLSearchParams({
|
|
197
|
+
client_id,
|
|
198
|
+
client_secret,
|
|
199
|
+
refresh_token,
|
|
200
|
+
grant_type: 'refresh_token',
|
|
201
|
+
}),
|
|
202
|
+
});
|
|
203
|
+
if (!res.ok) {
|
|
204
|
+
const text = await res.text();
|
|
205
|
+
throw new Error(`Failed to refresh OAuth2 token: ${res.status} ${text}`);
|
|
206
|
+
}
|
|
207
|
+
const data = await res.json();
|
|
208
|
+
return data.access_token;
|
|
209
|
+
}
|
|
210
|
+
function base64url(str) {
|
|
211
|
+
return Buffer.from(str).toString('base64url');
|
|
212
|
+
}
|
|
213
|
+
async function listFiles(accessToken, query) {
|
|
214
|
+
const fields = 'files(id,name,mimeType,modifiedTime,webViewLink,iconLink,owners,sharedWithMe)';
|
|
215
|
+
const params = new URLSearchParams({
|
|
216
|
+
q: query,
|
|
217
|
+
fields,
|
|
218
|
+
pageSize: '100',
|
|
219
|
+
orderBy: 'modifiedTime desc',
|
|
220
|
+
});
|
|
221
|
+
const url = `${GOOGLE_API_BASE}/drive/v3/files?${params}`;
|
|
222
|
+
const res = await fetchWithBackoff(url, {
|
|
223
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
224
|
+
});
|
|
225
|
+
if (!res.ok) {
|
|
226
|
+
const text = await res.text();
|
|
227
|
+
throw new Error(`Drive files.list failed: ${res.status} ${text}`);
|
|
228
|
+
}
|
|
229
|
+
const data = await res.json();
|
|
230
|
+
return data.files ?? [];
|
|
231
|
+
}
|
|
232
|
+
async function exportFileContent(accessToken, fileId, mimeType) {
|
|
233
|
+
let url;
|
|
234
|
+
if (isGoogleDoc(mimeType)) {
|
|
235
|
+
// Google Workspace formats must be exported
|
|
236
|
+
const exportMime = getExportMime(mimeType);
|
|
237
|
+
url = `${GOOGLE_API_BASE}/drive/v3/files/${fileId}/export?mimeType=${encodeURIComponent(exportMime)}`;
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
// Binary or text files can be downloaded directly
|
|
241
|
+
url = `${GOOGLE_API_BASE}/drive/v3/files/${fileId}?alt=media`;
|
|
242
|
+
}
|
|
243
|
+
const res = await fetchWithBackoff(url, {
|
|
244
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
245
|
+
});
|
|
246
|
+
if (!res.ok) {
|
|
247
|
+
throw new Error(`Export failed for file ${fileId}: ${res.status}`);
|
|
248
|
+
}
|
|
249
|
+
return res.text();
|
|
250
|
+
}
|
|
251
|
+
function isGoogleDoc(mimeType) {
|
|
252
|
+
return mimeType.startsWith('application/vnd.google-apps.');
|
|
253
|
+
}
|
|
254
|
+
function getExportMime(googleMime) {
|
|
255
|
+
const map = {
|
|
256
|
+
'application/vnd.google-apps.document': 'text/plain',
|
|
257
|
+
'application/vnd.google-apps.spreadsheet': 'text/csv',
|
|
258
|
+
'application/vnd.google-apps.presentation': 'text/plain',
|
|
259
|
+
'application/vnd.google-apps.drawing': 'image/svg+xml',
|
|
260
|
+
};
|
|
261
|
+
return map[googleMime] ?? 'text/plain';
|
|
262
|
+
}
|
|
263
|
+
function buildDriveQuery(since) {
|
|
264
|
+
const parts = [
|
|
265
|
+
'trashed = false',
|
|
266
|
+
'(mimeType = "text/plain" or mimeType = "text/markdown" or ' +
|
|
267
|
+
'mimeType = "application/vnd.google-apps.document" or ' +
|
|
268
|
+
'mimeType = "application/vnd.google-apps.spreadsheet" or ' +
|
|
269
|
+
'mimeType = "application/pdf")',
|
|
270
|
+
];
|
|
271
|
+
if (since) {
|
|
272
|
+
parts.push(`modifiedTime > "${since.toISOString()}"`);
|
|
273
|
+
}
|
|
274
|
+
const rootFolder = process.env['GOOGLE_DRIVE_ROOT_FOLDER_ID'];
|
|
275
|
+
if (rootFolder) {
|
|
276
|
+
parts.push(`"${rootFolder}" in parents`);
|
|
277
|
+
}
|
|
278
|
+
return parts.join(' and ');
|
|
279
|
+
}
|
|
280
|
+
function validateCredentials(credentials) {
|
|
281
|
+
const hasServiceAccount = credentials['client_email'] && credentials['private_key'];
|
|
282
|
+
const hasOAuth2 = credentials['client_id'] && credentials['client_secret'] && credentials['refresh_token'];
|
|
283
|
+
if (!hasServiceAccount && !hasOAuth2) {
|
|
284
|
+
throw new Error('GoogleDriveConnector requires either service account credentials ' +
|
|
285
|
+
'(client_email + private_key) or OAuth2 credentials ' +
|
|
286
|
+
'(client_id + client_secret + refresh_token)');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
//# sourceMappingURL=google-drive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-drive.js","sourceRoot":"","sources":["../../../src/scanner/cloud/google-drive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scanner/cloud/notion.ts — Notion connector.
|
|
3
|
+
*
|
|
4
|
+
* Uses the official Notion API (api.notion.com).
|
|
5
|
+
* Authentication: Internal Integration Token (api_key credential).
|
|
6
|
+
*
|
|
7
|
+
* Fetch strategy:
|
|
8
|
+
* 1. List all pages the integration has access to via /v1/search.
|
|
9
|
+
* 2. For each page, retrieve blocks and convert to Markdown text.
|
|
10
|
+
* 3. Incremental sync: filter by last_edited_time > since.
|
|
11
|
+
*
|
|
12
|
+
* Rate limits: Notion allows 3 requests/second per integration.
|
|
13
|
+
* We throttle to ≤3 req/s and apply exponential backoff on 429.
|
|
14
|
+
*
|
|
15
|
+
* Privacy: Only pages shared with the integration are visible.
|
|
16
|
+
* Private / unshared pages are never accessible.
|
|
17
|
+
*/
|
|
18
|
+
import type { CloudConnector, CloudDocument, MemoryCreateInput } from './types.js';
|
|
19
|
+
export declare class NotionConnector implements CloudConnector {
|
|
20
|
+
readonly name = "Notion";
|
|
21
|
+
readonly type: "notion";
|
|
22
|
+
private apiKey;
|
|
23
|
+
private lastRequestAt;
|
|
24
|
+
authenticate(credentials: Record<string, string>): Promise<void>;
|
|
25
|
+
isAuthenticated(): boolean;
|
|
26
|
+
fetchDocuments(since?: Date): Promise<CloudDocument[]>;
|
|
27
|
+
toMemory(doc: CloudDocument): MemoryCreateInput;
|
|
28
|
+
private assertAuthenticated;
|
|
29
|
+
private request;
|
|
30
|
+
private searchPages;
|
|
31
|
+
private extractPageContent;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=notion.d.ts.map
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scanner/cloud/notion.ts — Notion connector.
|
|
3
|
+
*
|
|
4
|
+
* Uses the official Notion API (api.notion.com).
|
|
5
|
+
* Authentication: Internal Integration Token (api_key credential).
|
|
6
|
+
*
|
|
7
|
+
* Fetch strategy:
|
|
8
|
+
* 1. List all pages the integration has access to via /v1/search.
|
|
9
|
+
* 2. For each page, retrieve blocks and convert to Markdown text.
|
|
10
|
+
* 3. Incremental sync: filter by last_edited_time > since.
|
|
11
|
+
*
|
|
12
|
+
* Rate limits: Notion allows 3 requests/second per integration.
|
|
13
|
+
* We throttle to ≤3 req/s and apply exponential backoff on 429.
|
|
14
|
+
*
|
|
15
|
+
* Privacy: Only pages shared with the integration are visible.
|
|
16
|
+
* Private / unshared pages are never accessible.
|
|
17
|
+
*/
|
|
18
|
+
import { createLogger } from '../../utils/logger.js';
|
|
19
|
+
const log = createLogger('notion');
|
|
20
|
+
const NOTION_API_BASE = 'https://api.notion.com/v1';
|
|
21
|
+
const NOTION_API_VERSION = '2022-06-28';
|
|
22
|
+
const MAX_RETRIES = 4;
|
|
23
|
+
const REQUEST_INTERVAL_MS = 350; // ~3 req/s
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// NotionConnector
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
export class NotionConnector {
|
|
28
|
+
name = 'Notion';
|
|
29
|
+
type = 'notion';
|
|
30
|
+
apiKey = null;
|
|
31
|
+
lastRequestAt = 0;
|
|
32
|
+
// -------------------------------------------------------------------------
|
|
33
|
+
// authenticate
|
|
34
|
+
// -------------------------------------------------------------------------
|
|
35
|
+
async authenticate(credentials) {
|
|
36
|
+
const key = credentials['api_key'];
|
|
37
|
+
if (!key) {
|
|
38
|
+
throw new Error('NotionConnector requires an "api_key" credential (Internal Integration Token)');
|
|
39
|
+
}
|
|
40
|
+
// Verify the token by calling /v1/users/me
|
|
41
|
+
const res = await this.request('GET', '/users/me', key);
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
throw new Error(`Notion authentication failed: ${res.status}`);
|
|
44
|
+
}
|
|
45
|
+
this.apiKey = key;
|
|
46
|
+
log.info('Notion authentication successful');
|
|
47
|
+
}
|
|
48
|
+
isAuthenticated() {
|
|
49
|
+
return this.apiKey !== null;
|
|
50
|
+
}
|
|
51
|
+
// -------------------------------------------------------------------------
|
|
52
|
+
// fetchDocuments
|
|
53
|
+
// -------------------------------------------------------------------------
|
|
54
|
+
async fetchDocuments(since) {
|
|
55
|
+
this.assertAuthenticated();
|
|
56
|
+
log.info('Fetching Notion pages', { since: since?.toISOString() });
|
|
57
|
+
const pages = await this.searchPages(since);
|
|
58
|
+
log.info('Found Notion pages', { count: pages.length });
|
|
59
|
+
const docs = [];
|
|
60
|
+
for (const page of pages) {
|
|
61
|
+
try {
|
|
62
|
+
const content = await this.extractPageContent(page.id);
|
|
63
|
+
const title = extractPageTitle(page);
|
|
64
|
+
docs.push({
|
|
65
|
+
id: page.id,
|
|
66
|
+
title,
|
|
67
|
+
content,
|
|
68
|
+
url: page.url,
|
|
69
|
+
mimeType: 'text/markdown',
|
|
70
|
+
lastModified: new Date(page.last_edited_time),
|
|
71
|
+
metadata: {
|
|
72
|
+
notionId: page.id,
|
|
73
|
+
notionUrl: page.url,
|
|
74
|
+
lastEditedTime: page.last_edited_time,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
log.warn('Failed to extract Notion page content', { pageId: page.id });
|
|
80
|
+
log.error('Extraction error', err instanceof Error ? err : new Error(String(err)));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return docs;
|
|
84
|
+
}
|
|
85
|
+
// -------------------------------------------------------------------------
|
|
86
|
+
// toMemory
|
|
87
|
+
// -------------------------------------------------------------------------
|
|
88
|
+
toMemory(doc) {
|
|
89
|
+
return {
|
|
90
|
+
content: `# ${doc.title}\n\n${doc.content}`,
|
|
91
|
+
summary: doc.title.slice(0, 120),
|
|
92
|
+
type: 'context',
|
|
93
|
+
tags: ['notion', 'cloud'],
|
|
94
|
+
source: 'cloud',
|
|
95
|
+
source_path: doc.url,
|
|
96
|
+
metadata: {
|
|
97
|
+
...doc.metadata,
|
|
98
|
+
cloudService: 'notion',
|
|
99
|
+
lastModified: doc.lastModified.toISOString(),
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// -------------------------------------------------------------------------
|
|
104
|
+
// Private helpers
|
|
105
|
+
// -------------------------------------------------------------------------
|
|
106
|
+
assertAuthenticated() {
|
|
107
|
+
if (!this.isAuthenticated()) {
|
|
108
|
+
throw new Error('NotionConnector: not authenticated. Call authenticate() first.');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async request(method, path, apiKey, body) {
|
|
112
|
+
// Throttle to stay within rate limit
|
|
113
|
+
const now = Date.now();
|
|
114
|
+
const elapsed = now - this.lastRequestAt;
|
|
115
|
+
if (elapsed < REQUEST_INTERVAL_MS) {
|
|
116
|
+
await sleep(REQUEST_INTERVAL_MS - elapsed);
|
|
117
|
+
}
|
|
118
|
+
this.lastRequestAt = Date.now();
|
|
119
|
+
const key = apiKey ?? this.apiKey;
|
|
120
|
+
const init = {
|
|
121
|
+
method,
|
|
122
|
+
headers: {
|
|
123
|
+
Authorization: `Bearer ${key}`,
|
|
124
|
+
'Notion-Version': NOTION_API_VERSION,
|
|
125
|
+
'Content-Type': 'application/json',
|
|
126
|
+
},
|
|
127
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
128
|
+
};
|
|
129
|
+
return fetchWithBackoff(`${NOTION_API_BASE}${path}`, init);
|
|
130
|
+
}
|
|
131
|
+
async searchPages(since) {
|
|
132
|
+
const pages = [];
|
|
133
|
+
let cursor;
|
|
134
|
+
do {
|
|
135
|
+
const body = {
|
|
136
|
+
filter: { value: 'page', property: 'object' },
|
|
137
|
+
page_size: 100,
|
|
138
|
+
...(cursor ? { start_cursor: cursor } : {}),
|
|
139
|
+
};
|
|
140
|
+
const res = await this.request('POST', '/search', undefined, body);
|
|
141
|
+
if (!res.ok) {
|
|
142
|
+
const text = await res.text();
|
|
143
|
+
throw new Error(`Notion search failed: ${res.status} ${text}`);
|
|
144
|
+
}
|
|
145
|
+
const data = await res.json();
|
|
146
|
+
for (const page of data.results) {
|
|
147
|
+
if (!since || new Date(page.last_edited_time) > since) {
|
|
148
|
+
pages.push(page);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
cursor = data.has_more && data.next_cursor ? data.next_cursor : undefined;
|
|
152
|
+
} while (cursor);
|
|
153
|
+
return pages;
|
|
154
|
+
}
|
|
155
|
+
async extractPageContent(pageId) {
|
|
156
|
+
const lines = [];
|
|
157
|
+
let cursor;
|
|
158
|
+
do {
|
|
159
|
+
const path = `/blocks/${pageId}/children?page_size=100${cursor ? `&start_cursor=${cursor}` : ''}`;
|
|
160
|
+
const res = await this.request('GET', path);
|
|
161
|
+
if (!res.ok) {
|
|
162
|
+
const text = await res.text();
|
|
163
|
+
throw new Error(`Notion blocks fetch failed: ${res.status} ${text}`);
|
|
164
|
+
}
|
|
165
|
+
const data = await res.json();
|
|
166
|
+
for (const block of data.results) {
|
|
167
|
+
const line = blockToMarkdown(block);
|
|
168
|
+
if (line)
|
|
169
|
+
lines.push(line);
|
|
170
|
+
}
|
|
171
|
+
cursor = data.has_more && data.next_cursor ? data.next_cursor : undefined;
|
|
172
|
+
} while (cursor);
|
|
173
|
+
return lines.join('\n');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
// Notion block → Markdown converter
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
function blockToMarkdown(block) {
|
|
180
|
+
const type = block.type;
|
|
181
|
+
const richText = block[type]?.rich_text ?? [];
|
|
182
|
+
const text = richText.map(rt => rt.plain_text).join('');
|
|
183
|
+
switch (type) {
|
|
184
|
+
case 'heading_1': return `# ${text}`;
|
|
185
|
+
case 'heading_2': return `## ${text}`;
|
|
186
|
+
case 'heading_3': return `### ${text}`;
|
|
187
|
+
case 'paragraph': return text;
|
|
188
|
+
case 'bulleted_list_item': return `- ${text}`;
|
|
189
|
+
case 'numbered_list_item': return `1. ${text}`;
|
|
190
|
+
case 'to_do': {
|
|
191
|
+
const checked = block['to_do']?.checked ?? false;
|
|
192
|
+
return `- [${checked ? 'x' : ' '}] ${text}`;
|
|
193
|
+
}
|
|
194
|
+
case 'code': {
|
|
195
|
+
const lang = block['code']?.language ?? '';
|
|
196
|
+
return `\`\`\`${lang}\n${text}\n\`\`\``;
|
|
197
|
+
}
|
|
198
|
+
case 'quote': return `> ${text}`;
|
|
199
|
+
case 'divider': return '---';
|
|
200
|
+
case 'callout': return `> **Note:** ${text}`;
|
|
201
|
+
default: return text;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function extractPageTitle(page) {
|
|
205
|
+
for (const prop of Object.values(page.properties)) {
|
|
206
|
+
if (prop.type === 'title') {
|
|
207
|
+
return prop.title
|
|
208
|
+
.map(t => t.plain_text)
|
|
209
|
+
.join('');
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return `Notion page ${page.id}`;
|
|
213
|
+
}
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
// HTTP helpers
|
|
216
|
+
// ---------------------------------------------------------------------------
|
|
217
|
+
async function fetchWithBackoff(url, init, attempt = 0) {
|
|
218
|
+
const res = await fetch(url, init);
|
|
219
|
+
if ((res.status === 429 || res.status === 503) && attempt < MAX_RETRIES) {
|
|
220
|
+
const retryAfter = parseInt(res.headers.get('Retry-After') ?? '1', 10);
|
|
221
|
+
const delay = Math.max(retryAfter * 1000, Math.min(1000 * 2 ** attempt, 16_000));
|
|
222
|
+
log.debug('Rate limited by Notion, retrying', { delay, attempt });
|
|
223
|
+
await sleep(delay);
|
|
224
|
+
return fetchWithBackoff(url, init, attempt + 1);
|
|
225
|
+
}
|
|
226
|
+
return res;
|
|
227
|
+
}
|
|
228
|
+
function sleep(ms) {
|
|
229
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=notion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notion.js","sourceRoot":"","sources":["../../../src/scanner/cloud/notion.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scanner/cloud/slack.ts — Slack connector.
|
|
3
|
+
*
|
|
4
|
+
* Collects: channel message history, thread conversations, pinned messages.
|
|
5
|
+
* Intentionally EXCLUDES: DMs and private channels (privacy by default).
|
|
6
|
+
* DMs can be included by setting credential `include_dms=true` explicitly.
|
|
7
|
+
*
|
|
8
|
+
* Authentication: Bot Token (xoxb-…) with scopes:
|
|
9
|
+
* channels:history, channels:read, groups:history, groups:read,
|
|
10
|
+
* pins:read, users:read (for display names)
|
|
11
|
+
* Credential key: `bot_token`
|
|
12
|
+
*
|
|
13
|
+
* Rate limits: Slack Tier 3 = 50 req/min. We add 60ms between requests.
|
|
14
|
+
* Exponential backoff on 429 honouring the Retry-After header.
|
|
15
|
+
*
|
|
16
|
+
* Incremental sync: channel history accepts `oldest` (Unix timestamp).
|
|
17
|
+
*/
|
|
18
|
+
import type { CloudConnector, CloudDocument, MemoryCreateInput } from './types.js';
|
|
19
|
+
export declare class SlackConnector implements CloudConnector {
|
|
20
|
+
readonly name = "Slack";
|
|
21
|
+
readonly type: "slack";
|
|
22
|
+
private token;
|
|
23
|
+
private includeDMs;
|
|
24
|
+
private lastRequestAt;
|
|
25
|
+
private userCache;
|
|
26
|
+
authenticate(credentials: Record<string, string>): Promise<void>;
|
|
27
|
+
isAuthenticated(): boolean;
|
|
28
|
+
fetchDocuments(since?: Date): Promise<CloudDocument[]>;
|
|
29
|
+
toMemory(doc: CloudDocument): MemoryCreateInput;
|
|
30
|
+
private assertAuthenticated;
|
|
31
|
+
private call;
|
|
32
|
+
private listChannels;
|
|
33
|
+
private fetchPinnedMessages;
|
|
34
|
+
private fetchChannelHistory;
|
|
35
|
+
private fetchThread;
|
|
36
|
+
private resolveUser;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=slack.d.ts.map
|