@opendatalabs/connect 0.8.0 → 0.8.1-canary.21ae77f
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 +55 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +7 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +567 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +2 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/connectors/index.d.ts +2 -0
- package/dist/connectors/index.d.ts.map +1 -0
- package/dist/connectors/index.js +2 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/registry.d.ts +29 -0
- package/dist/connectors/registry.d.ts.map +1 -0
- package/dist/connectors/registry.js +134 -0
- package/dist/connectors/registry.js.map +1 -0
- package/dist/core/cli-types.d.ts +110 -0
- package/dist/core/cli-types.d.ts.map +1 -0
- package/dist/core/cli-types.js +61 -0
- package/dist/core/cli-types.js.map +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/paths.d.ts +9 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +28 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/state-store.d.ts +16 -0
- package/dist/core/state-store.d.ts.map +1 -0
- package/dist/core/state-store.js +23 -0
- package/dist/core/state-store.js.map +1 -0
- package/dist/core/types.d.ts +4 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/personal-server/index.d.ts +8 -0
- package/dist/personal-server/index.d.ts.map +1 -0
- package/dist/personal-server/index.js +76 -0
- package/dist/personal-server/index.js.map +1 -0
- package/dist/react/useVanaData.d.ts +1 -1
- package/dist/react/useVanaData.d.ts.map +1 -1
- package/dist/react/useVanaData.js +22 -9
- package/dist/react/useVanaData.js.map +1 -1
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/managed-playwright.d.ts +33 -0
- package/dist/runtime/managed-playwright.d.ts.map +1 -0
- package/dist/runtime/managed-playwright.js +263 -0
- package/dist/runtime/managed-playwright.js.map +1 -0
- package/dist/runtime/repo-paths.d.ts +2 -0
- package/dist/runtime/repo-paths.d.ts.map +1 -0
- package/dist/runtime/repo-paths.js +19 -0
- package/dist/runtime/repo-paths.js.map +1 -0
- package/dist/server/config.d.ts +2 -0
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/config.js +1 -0
- package/dist/server/config.js.map +1 -1
- package/dist/server/connect.d.ts.map +1 -1
- package/dist/server/connect.js +7 -0
- package/dist/server/connect.js.map +1 -1
- package/package.json +24 -2
- package/runtime-assets/run-connector.cjs +275 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opendatalabs/connect",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1-canary.21ae77f",
|
|
4
4
|
"description": "SDK for integrating Vana Data Portability 'Connect data' flows",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -16,8 +16,12 @@
|
|
|
16
16
|
"publishConfig": {
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
|
+
"bin": {
|
|
20
|
+
"vana": "./dist/cli/bin.js"
|
|
21
|
+
},
|
|
19
22
|
"files": [
|
|
20
|
-
"dist"
|
|
23
|
+
"dist",
|
|
24
|
+
"runtime-assets"
|
|
21
25
|
],
|
|
22
26
|
"exports": {
|
|
23
27
|
".": {
|
|
@@ -35,11 +39,24 @@
|
|
|
35
39
|
"./core": {
|
|
36
40
|
"types": "./dist/core/index.d.ts",
|
|
37
41
|
"import": "./dist/core/index.js"
|
|
42
|
+
},
|
|
43
|
+
"./runtime": {
|
|
44
|
+
"types": "./dist/runtime/index.d.ts",
|
|
45
|
+
"import": "./dist/runtime/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./connectors": {
|
|
48
|
+
"types": "./dist/connectors/index.d.ts",
|
|
49
|
+
"import": "./dist/connectors/index.js"
|
|
50
|
+
},
|
|
51
|
+
"./cli": {
|
|
52
|
+
"types": "./dist/cli/main.d.ts",
|
|
53
|
+
"import": "./dist/cli/main.js"
|
|
38
54
|
}
|
|
39
55
|
},
|
|
40
56
|
"scripts": {
|
|
41
57
|
"build": "tsc --build",
|
|
42
58
|
"clean": "tsc --build --clean",
|
|
59
|
+
"cli": "node dist/cli/bin.js",
|
|
43
60
|
"skills:sync": "node scripts/sync-skills.js",
|
|
44
61
|
"test": "vitest run",
|
|
45
62
|
"test:watch": "vitest",
|
|
@@ -64,6 +81,11 @@
|
|
|
64
81
|
"engines": {
|
|
65
82
|
"node": ">=20.0.0"
|
|
66
83
|
},
|
|
84
|
+
"dependencies": {
|
|
85
|
+
"@inquirer/prompts": "^8.3.0",
|
|
86
|
+
"commander": "^14.0.3",
|
|
87
|
+
"zod": "^4.3.6"
|
|
88
|
+
},
|
|
67
89
|
"peerDependencies": {
|
|
68
90
|
"viem": "^2.0.0",
|
|
69
91
|
"react": ">=18.0.0"
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* run-connector.cjs — Run a data connector headlessly.
|
|
4
|
+
*
|
|
5
|
+
* Usage: node run-connector.cjs <connector-path> [start-url] [options]
|
|
6
|
+
*
|
|
7
|
+
* Options:
|
|
8
|
+
* --inputs '{"key":"val"}' Pre-supply credentials/2FA
|
|
9
|
+
* --output <path> Result file path (default: ~/.dataconnect/last-result.json)
|
|
10
|
+
* --pretty Human-readable colored output instead of JSON
|
|
11
|
+
* --runner-dir <path> Path to playwright-runner (auto-detected if not set)
|
|
12
|
+
*
|
|
13
|
+
* Exit codes: 0 success, 1 error, 2 needs input, 3 legacy auth unsupported.
|
|
14
|
+
*
|
|
15
|
+
* Default output is line-delimited JSON on stdout:
|
|
16
|
+
* need-input, legacy-auth, result, log, error
|
|
17
|
+
*
|
|
18
|
+
* With --pretty, output is colored human-readable text.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const { spawn } = require('child_process');
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
const os = require('os');
|
|
25
|
+
|
|
26
|
+
const homedir = os.homedir();
|
|
27
|
+
|
|
28
|
+
const rawArgs = process.argv.slice(2);
|
|
29
|
+
const positional = [];
|
|
30
|
+
let preSuppliedInputs = {};
|
|
31
|
+
let pretty = false;
|
|
32
|
+
let outputPath = path.join(homedir, '.dataconnect', 'last-result.json');
|
|
33
|
+
let runnerDir = null;
|
|
34
|
+
|
|
35
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
36
|
+
if (rawArgs[i] === '--inputs' && rawArgs[i + 1]) {
|
|
37
|
+
try { preSuppliedInputs = JSON.parse(rawArgs[++i]); }
|
|
38
|
+
catch (e) { console.error('Invalid --inputs JSON:', e.message); process.exit(1); }
|
|
39
|
+
} else if (rawArgs[i] === '--output' && rawArgs[i + 1]) {
|
|
40
|
+
outputPath = rawArgs[++i];
|
|
41
|
+
} else if (rawArgs[i] === '--runner-dir' && rawArgs[i + 1]) {
|
|
42
|
+
runnerDir = rawArgs[++i];
|
|
43
|
+
} else if (rawArgs[i] === '--pretty') {
|
|
44
|
+
pretty = true;
|
|
45
|
+
} else if (!rawArgs[i].startsWith('--')) {
|
|
46
|
+
positional.push(rawArgs[i]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const connectorPath = positional[0];
|
|
51
|
+
const startUrl = positional[1] || 'about:blank';
|
|
52
|
+
|
|
53
|
+
if (!connectorPath) {
|
|
54
|
+
console.error('Usage: node run-connector.cjs <connector-path> [start-url] [--inputs \'{"key":"val"}\'] [--pretty]');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const connectorSlug = path.basename(connectorPath, path.extname(connectorPath));
|
|
59
|
+
const runId = `${connectorSlug}-${Date.now()}`;
|
|
60
|
+
const PENDING_INPUT_PATH = path.join(homedir, '.dataconnect', `pending-input-${runId}.json`);
|
|
61
|
+
const INPUT_RESPONSE_PATH = path.join(homedir, '.dataconnect', `input-response-${runId}.json`);
|
|
62
|
+
|
|
63
|
+
const c = {
|
|
64
|
+
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
65
|
+
red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m',
|
|
66
|
+
blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m', gray: '\x1b[90m',
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
function prettyPrint(color, prefix, msg) {
|
|
70
|
+
const ts = new Date().toLocaleTimeString('en-US', { hour12: false });
|
|
71
|
+
console.log(`${c.gray}${ts}${c.reset} ${color}${prefix}${c.reset} ${msg}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function emit(obj) {
|
|
75
|
+
if (pretty) {
|
|
76
|
+
switch (obj.type) {
|
|
77
|
+
case 'need-input':
|
|
78
|
+
prettyPrint(c.magenta, '[input]', obj.message);
|
|
79
|
+
if (obj.schema?.properties) {
|
|
80
|
+
prettyPrint(c.dim, ' ', `Fields: ${Object.keys(obj.schema.properties).join(', ')}`);
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
case 'legacy-auth':
|
|
84
|
+
prettyPrint(c.yellow, '[auth] ', obj.message);
|
|
85
|
+
break;
|
|
86
|
+
case 'result': {
|
|
87
|
+
const size = fs.existsSync(obj.resultPath)
|
|
88
|
+
? (fs.statSync(obj.resultPath).size / 1024).toFixed(1) + ' KB'
|
|
89
|
+
: '';
|
|
90
|
+
prettyPrint(c.green, '[result]', `Saved to ${obj.resultPath} ${size ? `(${size})` : ''}`);
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case 'log':
|
|
94
|
+
prettyPrint(c.gray, '[log] ', obj.message || '');
|
|
95
|
+
break;
|
|
96
|
+
case 'error':
|
|
97
|
+
prettyPrint(c.red, '[error]', obj.message || '');
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
console.log(JSON.stringify(obj));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function resolveRunnerDir() {
|
|
106
|
+
if (runnerDir) {
|
|
107
|
+
if (fs.existsSync(path.join(runnerDir, 'index.cjs'))) return runnerDir;
|
|
108
|
+
console.error(`Runner not found at: ${runnerDir}`);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const candidates = [
|
|
113
|
+
path.join(homedir, '.dataconnect', 'playwright-runner'),
|
|
114
|
+
process.env.PLAYWRIGHT_RUNNER_DIR,
|
|
115
|
+
].filter(Boolean);
|
|
116
|
+
|
|
117
|
+
for (const dir of candidates) {
|
|
118
|
+
if (fs.existsSync(path.join(dir, 'index.cjs'))) return dir;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
console.error('Could not find playwright-runner. Run `vana setup` first.');
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
try { fs.unlinkSync(PENDING_INPUT_PATH); } catch {}
|
|
126
|
+
try { fs.unlinkSync(INPUT_RESPONSE_PATH); } catch {}
|
|
127
|
+
|
|
128
|
+
const resolvedRunnerDir = resolveRunnerDir();
|
|
129
|
+
|
|
130
|
+
if (pretty) {
|
|
131
|
+
console.log(`${c.bold}run-connector${c.reset}`);
|
|
132
|
+
console.log(` ${c.cyan}Connector:${c.reset} ${connectorPath}`);
|
|
133
|
+
console.log(` ${c.cyan}URL:${c.reset} ${startUrl}`);
|
|
134
|
+
console.log(` ${c.cyan}Output:${c.reset} ${outputPath}`);
|
|
135
|
+
console.log(` ${c.cyan}Runner:${c.reset} ${resolvedRunnerDir}`);
|
|
136
|
+
console.log('');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const runner = spawn(process.execPath, ['index.cjs'], {
|
|
140
|
+
cwd: resolvedRunnerDir,
|
|
141
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
runner.stderr.on('data', (chunk) => {
|
|
145
|
+
if (pretty) {
|
|
146
|
+
for (const line of chunk.toString().split('\n').filter(l => l.trim())) {
|
|
147
|
+
prettyPrint(c.dim, '[runner]', line.replace('[PlaywrightRunner] ', ''));
|
|
148
|
+
}
|
|
149
|
+
} else {
|
|
150
|
+
process.stderr.write(chunk);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
let buffer = '';
|
|
155
|
+
const consumedFields = new Set();
|
|
156
|
+
|
|
157
|
+
runner.stdout.on('data', (chunk) => {
|
|
158
|
+
buffer += chunk.toString();
|
|
159
|
+
const lines = buffer.split('\n');
|
|
160
|
+
buffer = lines.pop();
|
|
161
|
+
for (const line of lines) {
|
|
162
|
+
if (!line.trim()) continue;
|
|
163
|
+
try { handleMessage(JSON.parse(line)); }
|
|
164
|
+
catch (e) { process.stderr.write('[non-json] ' + line + '\n'); }
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
function handleMessage(msg) {
|
|
169
|
+
switch (msg.type) {
|
|
170
|
+
case 'ready':
|
|
171
|
+
runner.stdin.write(JSON.stringify({
|
|
172
|
+
type: 'run', runId,
|
|
173
|
+
connectorPath: path.resolve(connectorPath),
|
|
174
|
+
url: startUrl, headless: true, allowHeaded: false,
|
|
175
|
+
}) + '\n');
|
|
176
|
+
if (pretty) prettyPrint(c.green, '[ready]', 'Connected, starting connector...');
|
|
177
|
+
break;
|
|
178
|
+
|
|
179
|
+
case 'request-input': {
|
|
180
|
+
const { requestId, payload } = msg;
|
|
181
|
+
const schema = payload?.schema;
|
|
182
|
+
const fields = schema?.properties ? Object.keys(schema.properties) : [];
|
|
183
|
+
const available = fields.filter(f => f in preSuppliedInputs && !consumedFields.has(f));
|
|
184
|
+
|
|
185
|
+
if (available.length > 0) {
|
|
186
|
+
const data = {};
|
|
187
|
+
for (const f of fields) {
|
|
188
|
+
if (f in preSuppliedInputs && !consumedFields.has(f)) {
|
|
189
|
+
data[f] = preSuppliedInputs[f];
|
|
190
|
+
consumedFields.add(f);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
runner.stdin.write(JSON.stringify({
|
|
194
|
+
type: 'input-response', runId, requestId, data,
|
|
195
|
+
}) + '\n');
|
|
196
|
+
} else {
|
|
197
|
+
const pendingInput = {
|
|
198
|
+
requestId,
|
|
199
|
+
message: payload?.message || 'Input required',
|
|
200
|
+
schema: schema || {},
|
|
201
|
+
previousInputs: [...consumedFields],
|
|
202
|
+
timestamp: new Date().toISOString(),
|
|
203
|
+
};
|
|
204
|
+
fs.writeFileSync(PENDING_INPUT_PATH, JSON.stringify(pendingInput, null, 2));
|
|
205
|
+
|
|
206
|
+
emit({
|
|
207
|
+
type: 'need-input',
|
|
208
|
+
message: pendingInput.message,
|
|
209
|
+
schema: pendingInput.schema,
|
|
210
|
+
pendingInputPath: PENDING_INPUT_PATH,
|
|
211
|
+
responseInputPath: INPUT_RESPONSE_PATH,
|
|
212
|
+
...(consumedFields.size > 0 && { previousInputs: pendingInput.previousInputs }),
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const poll = setInterval(() => {
|
|
216
|
+
if (!fs.existsSync(INPUT_RESPONSE_PATH)) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
clearInterval(poll);
|
|
221
|
+
try {
|
|
222
|
+
const response = JSON.parse(fs.readFileSync(INPUT_RESPONSE_PATH, 'utf-8'));
|
|
223
|
+
try { fs.unlinkSync(INPUT_RESPONSE_PATH); } catch {}
|
|
224
|
+
try { fs.unlinkSync(PENDING_INPUT_PATH); } catch {}
|
|
225
|
+
|
|
226
|
+
if (response && typeof response === 'object') {
|
|
227
|
+
for (const f of Object.keys(response)) consumedFields.add(f);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
runner.stdin.write(JSON.stringify({
|
|
231
|
+
type: 'input-response', runId, requestId, data: response,
|
|
232
|
+
}) + '\n');
|
|
233
|
+
} catch (e) {
|
|
234
|
+
try { fs.unlinkSync(INPUT_RESPONSE_PATH); } catch {}
|
|
235
|
+
try { fs.unlinkSync(PENDING_INPUT_PATH); } catch {}
|
|
236
|
+
runner.stdin.write(JSON.stringify({
|
|
237
|
+
type: 'input-response', runId, requestId,
|
|
238
|
+
error: 'Invalid response file: ' + e.message,
|
|
239
|
+
}) + '\n');
|
|
240
|
+
}
|
|
241
|
+
}, 1000);
|
|
242
|
+
}
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
case 'run-completed':
|
|
247
|
+
if (msg.result?.ok) {
|
|
248
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
249
|
+
fs.writeFileSync(outputPath, JSON.stringify(msg.result.data, null, 2));
|
|
250
|
+
emit({ type: 'result', resultPath: outputPath });
|
|
251
|
+
process.exit(0);
|
|
252
|
+
}
|
|
253
|
+
emit({
|
|
254
|
+
type: 'error',
|
|
255
|
+
message: msg.result?.error || 'Connector run failed.',
|
|
256
|
+
});
|
|
257
|
+
process.exit(1);
|
|
258
|
+
break;
|
|
259
|
+
|
|
260
|
+
case 'run-error':
|
|
261
|
+
if (String(msg.error || '').includes('showBrowser') || String(msg.error || '').includes('promptUser')) {
|
|
262
|
+
emit({
|
|
263
|
+
type: 'legacy-auth',
|
|
264
|
+
message: 'This connector uses legacy authentication (showBrowser/promptUser) which is not supported in batch mode. Either use a migrated connector that supports requestInput, or establish a session manually first.',
|
|
265
|
+
});
|
|
266
|
+
process.exit(3);
|
|
267
|
+
}
|
|
268
|
+
emit({
|
|
269
|
+
type: 'error',
|
|
270
|
+
message: msg.error || 'Runner error.',
|
|
271
|
+
});
|
|
272
|
+
process.exit(1);
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
}
|