@corsair-dev/cli 0.1.2 → 0.1.3
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 +3 -3
- package/dist/index.js +221 -14
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @corsair-
|
|
1
|
+
# @corsair-dev/cli
|
|
2
2
|
|
|
3
3
|
The Corsair CLI handles everything needed to get a Corsair instance running: database setup, credential storage, and OAuth token acquisition. The intention is that a developer (or an agent) can go from a blank project to a fully authorized integration with a minimal number of commands, without ever needing to manually touch a database or manage encryption keys.
|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ All output is JSON, so both humans and agents can consume it the same way.
|
|
|
11
11
|
The CLI is included when you install `corsair`:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
pnpm add corsair @corsair-
|
|
14
|
+
pnpm add corsair @corsair-dev/cli
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
The `corsair` binary is available immediately after install via `pnpm exec corsair <command>` or `npx corsair <command>`. No additional configuration needed.
|
|
@@ -106,7 +106,7 @@ npx corsair auth --plugin=gmail --credentials
|
|
|
106
106
|
"client_secret": "***",
|
|
107
107
|
"access_token": "ya29.A...abc",
|
|
108
108
|
"refresh_token": "1//0g...xyz",
|
|
109
|
-
"expires_at": "
|
|
109
|
+
"expires_at": "1234567890"
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
```
|
package/dist/index.js
CHANGED
|
@@ -268,7 +268,7 @@ async function oauthExchangeCode(database, plugin, kek, tenantId, code, redirect
|
|
|
268
268
|
});
|
|
269
269
|
await accountKm.set_access_token(tokens.access_token);
|
|
270
270
|
if (tokens.refresh_token) await accountKm.set_refresh_token(tokens.refresh_token);
|
|
271
|
-
if (tokens.expires_in) await accountKm.set_expires_at((Date.now() + tokens.expires_in
|
|
271
|
+
if (tokens.expires_in) await accountKm.set_expires_at((Math.floor(Date.now() / 1e3) + tokens.expires_in).toString());
|
|
272
272
|
out({ status: "success", plugin: plugin.id, tenant: tenantId });
|
|
273
273
|
}
|
|
274
274
|
async function oauthWithCode(database, plugin, kek, tenantId, code) {
|
|
@@ -1124,6 +1124,46 @@ or reinstall your dependencies:
|
|
|
1124
1124
|
process.exit(1);
|
|
1125
1125
|
}
|
|
1126
1126
|
}
|
|
1127
|
+
function resolveClient(instance, tenant) {
|
|
1128
|
+
const obj = instance;
|
|
1129
|
+
if ("withTenant" in obj && typeof obj.withTenant === "function") {
|
|
1130
|
+
if (!tenant) {
|
|
1131
|
+
console.error("[#corsair]: This is a multi-tenant instance. Pass --tenant=<id>.");
|
|
1132
|
+
process.exit(1);
|
|
1133
|
+
}
|
|
1134
|
+
return obj.withTenant(tenant);
|
|
1135
|
+
}
|
|
1136
|
+
return obj;
|
|
1137
|
+
}
|
|
1138
|
+
function navigateToEndpoint(client, path3) {
|
|
1139
|
+
const parts = path3.split(".");
|
|
1140
|
+
let current = client;
|
|
1141
|
+
for (const part of parts) {
|
|
1142
|
+
if (current === null || typeof current !== "object") return void 0;
|
|
1143
|
+
current = current[part];
|
|
1144
|
+
}
|
|
1145
|
+
return typeof current === "function" ? current : void 0;
|
|
1146
|
+
}
|
|
1147
|
+
function parseListArgs(args) {
|
|
1148
|
+
let plugin;
|
|
1149
|
+
let type;
|
|
1150
|
+
for (const arg of args) {
|
|
1151
|
+
const eqIdx = arg.indexOf("=");
|
|
1152
|
+
if (arg.startsWith("--") && eqIdx !== -1) {
|
|
1153
|
+
const key = arg.slice(2, eqIdx);
|
|
1154
|
+
const value = arg.slice(eqIdx + 1);
|
|
1155
|
+
if (key === "plugin") {
|
|
1156
|
+
plugin = value;
|
|
1157
|
+
continue;
|
|
1158
|
+
}
|
|
1159
|
+
if (key === "type" && (value === "api" || value === "webhooks" || value === "db")) {
|
|
1160
|
+
type = value;
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
return { plugin, type };
|
|
1166
|
+
}
|
|
1127
1167
|
function parseAuthArgs(args) {
|
|
1128
1168
|
let pluginId;
|
|
1129
1169
|
let tenantId;
|
|
@@ -1180,24 +1220,84 @@ function parseSetupArgs(args) {
|
|
|
1180
1220
|
}
|
|
1181
1221
|
return { backfill, credentials };
|
|
1182
1222
|
}
|
|
1223
|
+
function parseRunArgs(args) {
|
|
1224
|
+
let endpointPath;
|
|
1225
|
+
let input;
|
|
1226
|
+
let tenant;
|
|
1227
|
+
for (let i = 0; i < args.length; i++) {
|
|
1228
|
+
const arg = args[i];
|
|
1229
|
+
if (arg === "--tenant" && args[i + 1]) {
|
|
1230
|
+
tenant = args[++i];
|
|
1231
|
+
} else if (arg.startsWith("--tenant=")) {
|
|
1232
|
+
tenant = arg.slice("--tenant=".length);
|
|
1233
|
+
} else if (arg === "--input" && args[i + 1]) {
|
|
1234
|
+
input = args[++i];
|
|
1235
|
+
} else if (arg.startsWith("--input=")) {
|
|
1236
|
+
input = arg.slice("--input=".length);
|
|
1237
|
+
} else if (!arg.startsWith("-")) {
|
|
1238
|
+
if (!endpointPath) endpointPath = arg;
|
|
1239
|
+
else if (!input) input = arg;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
return { path: endpointPath, input, tenant };
|
|
1243
|
+
}
|
|
1244
|
+
function parseScriptArgs(args) {
|
|
1245
|
+
let code;
|
|
1246
|
+
let tenant;
|
|
1247
|
+
for (let i = 0; i < args.length; i++) {
|
|
1248
|
+
const arg = args[i];
|
|
1249
|
+
if (arg === "--code" && args[i + 1]) {
|
|
1250
|
+
code = args[++i];
|
|
1251
|
+
} else if (arg.startsWith("--code=")) {
|
|
1252
|
+
code = arg.slice("--code=".length);
|
|
1253
|
+
} else if (arg === "--tenant" && args[i + 1]) {
|
|
1254
|
+
tenant = args[++i];
|
|
1255
|
+
} else if (arg.startsWith("--tenant=")) {
|
|
1256
|
+
tenant = arg.slice("--tenant=".length);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
return { code, tenant };
|
|
1260
|
+
}
|
|
1261
|
+
function printHelp() {
|
|
1262
|
+
console.log("[#corsair]: Corsair CLI\n");
|
|
1263
|
+
console.log("Commands:");
|
|
1264
|
+
console.log(" corsair setup Initialize your Corsair instance");
|
|
1265
|
+
console.log(" corsair setup -backfill Initialize and backfill initial data");
|
|
1266
|
+
console.log(" corsair setup --<plugin> <field>=VALUE ... Set credentials for a plugin");
|
|
1267
|
+
console.log("");
|
|
1268
|
+
console.log(" corsair auth --plugin=<id> Start OAuth flow (outputs auth URL as JSON)");
|
|
1269
|
+
console.log(" corsair auth --plugin=<id> --code=<code> Exchange OAuth code for tokens");
|
|
1270
|
+
console.log(" corsair auth --plugin=<id> --credentials Show current credential status");
|
|
1271
|
+
console.log("");
|
|
1272
|
+
console.log(" corsair list List all API endpoint paths across all plugins");
|
|
1273
|
+
console.log(" corsair list --plugin=<id> List paths for a specific plugin");
|
|
1274
|
+
console.log(" corsair list --type=api|webhooks|db Filter by operation type (default: api)");
|
|
1275
|
+
console.log(" corsair list --plugin=<id> --type=<type> Combine plugin + type filters");
|
|
1276
|
+
console.log("");
|
|
1277
|
+
console.log(" corsair schema <path> Show schema for an endpoint, webhook, or DB entity");
|
|
1278
|
+
console.log(" corsair schema slack.api.messages.post Example: API endpoint schema");
|
|
1279
|
+
console.log(" corsair schema slack.webhooks.messages.message Example: webhook schema");
|
|
1280
|
+
console.log(" corsair schema slack.db.messages.search Example: DB search schema");
|
|
1281
|
+
console.log("");
|
|
1282
|
+
console.log(" corsair run <path> [input-json] Call an API endpoint and print the result");
|
|
1283
|
+
console.log(" corsair run slack.api.channels.list Example: no input needed");
|
|
1284
|
+
console.log(` corsair run slack.api.messages.post '{"channel":"C123","text":"hi"}'`);
|
|
1285
|
+
console.log(" corsair run <path> [input-json] --tenant=<id> Multi-tenant variant");
|
|
1286
|
+
console.log("");
|
|
1287
|
+
console.log(' corsair script --code "<js>" Run a sandboxed script with corsair injected');
|
|
1288
|
+
console.log(' corsair script --code "<js>" --tenant=<id> Multi-tenant variant');
|
|
1289
|
+
console.log(" # corsair is pre-injected; use return to output a value:");
|
|
1290
|
+
console.log(` # --code "const r = await corsair.slack.api.channels.list(); return r.channels.find(c => c.name === 'general')?.id"`);
|
|
1291
|
+
console.log("");
|
|
1292
|
+
console.log(" corsair watch-renew Renew Google webhook watch (Gmail/Drive/Calendar)");
|
|
1293
|
+
console.log(" corsair help Show this help message\n");
|
|
1294
|
+
}
|
|
1183
1295
|
async function main() {
|
|
1184
1296
|
const cwd = process.cwd();
|
|
1185
1297
|
const args = process.argv.slice(2);
|
|
1186
1298
|
const command = args[0];
|
|
1187
1299
|
if (command === "help" || command === "--help" || command === "-h") {
|
|
1188
|
-
|
|
1189
|
-
console.log("Commands:");
|
|
1190
|
-
console.log(" corsair setup Initialize your Corsair instance");
|
|
1191
|
-
console.log(" corsair setup -backfill Initialize and backfill initial data");
|
|
1192
|
-
console.log(" corsair setup --<plugin> <field>=VALUE ... Set credentials for a plugin");
|
|
1193
|
-
console.log(" corsair auth --plugin=<id> Start OAuth flow (outputs auth URL as JSON)");
|
|
1194
|
-
console.log(" corsair auth --plugin=<id> --code=<code> Exchange OAuth code for tokens");
|
|
1195
|
-
console.log(" corsair auth --plugin=<id> --credentials Show current credential status");
|
|
1196
|
-
console.log(
|
|
1197
|
-
" corsair watch-renew Renew Google webhook watch (Gmail/Drive/Calendar)"
|
|
1198
|
-
);
|
|
1199
|
-
console.log(" corsair migrate Create a data migration script");
|
|
1200
|
-
console.log(" corsair migrate help Show migration help\n");
|
|
1300
|
+
printHelp();
|
|
1201
1301
|
return;
|
|
1202
1302
|
}
|
|
1203
1303
|
if (command === "setup") {
|
|
@@ -1222,6 +1322,113 @@ async function main() {
|
|
|
1222
1322
|
await runWatchRenew2({ cwd });
|
|
1223
1323
|
return;
|
|
1224
1324
|
}
|
|
1325
|
+
if (command === "list") {
|
|
1326
|
+
const { plugin, type } = parseListArgs(args.slice(1));
|
|
1327
|
+
const instance = await getCorsairInstance({ cwd });
|
|
1328
|
+
const corsair = instance;
|
|
1329
|
+
if (typeof corsair.list_operations !== "function") {
|
|
1330
|
+
console.error("[#corsair]: list_operations not available on this Corsair instance.");
|
|
1331
|
+
process.exit(1);
|
|
1332
|
+
}
|
|
1333
|
+
const result = corsair.list_operations({ plugin, type });
|
|
1334
|
+
if (typeof result === "string") {
|
|
1335
|
+
console.log(result);
|
|
1336
|
+
} else if (Array.isArray(result)) {
|
|
1337
|
+
for (const path3 of result) {
|
|
1338
|
+
console.log(path3);
|
|
1339
|
+
}
|
|
1340
|
+
console.log("");
|
|
1341
|
+
console.log("Run `pnpm corsair schema <path>` to get the schema for any of the above.");
|
|
1342
|
+
} else if (result && typeof result === "object") {
|
|
1343
|
+
const grouped = result;
|
|
1344
|
+
for (const [pluginId, paths] of Object.entries(grouped)) {
|
|
1345
|
+
console.log(`${pluginId}:`);
|
|
1346
|
+
for (const path3 of paths) {
|
|
1347
|
+
console.log(` ${path3}`);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
console.log("");
|
|
1351
|
+
console.log("Run `pnpm corsair schema <path>` to get the schema for any of the above.");
|
|
1352
|
+
}
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
if (command === "run") {
|
|
1356
|
+
const { path: endpointPath, input, tenant } = parseRunArgs(args.slice(1));
|
|
1357
|
+
if (!endpointPath) {
|
|
1358
|
+
console.error("[#corsair]: Usage: corsair run <path> [input-json]");
|
|
1359
|
+
console.error(`[#corsair]: Example: corsair run slack.api.messages.post '{"channel":"C123","text":"hi"}'`);
|
|
1360
|
+
process.exit(1);
|
|
1361
|
+
}
|
|
1362
|
+
const instance = await getCorsairInstance({ cwd });
|
|
1363
|
+
const client = resolveClient(instance, tenant);
|
|
1364
|
+
const fn = navigateToEndpoint(client, endpointPath);
|
|
1365
|
+
if (!fn) {
|
|
1366
|
+
console.error(`[#corsair]: Could not find endpoint "${endpointPath}".`);
|
|
1367
|
+
console.error("[#corsair]: Run `pnpm corsair list` to see available paths.");
|
|
1368
|
+
process.exit(1);
|
|
1369
|
+
}
|
|
1370
|
+
let parsedInput = {};
|
|
1371
|
+
if (input) {
|
|
1372
|
+
try {
|
|
1373
|
+
parsedInput = JSON.parse(input);
|
|
1374
|
+
} catch {
|
|
1375
|
+
console.error("[#corsair]: Invalid JSON input. Make sure to quote the JSON string.");
|
|
1376
|
+
process.exit(1);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
try {
|
|
1380
|
+
const result = await fn(parsedInput);
|
|
1381
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1382
|
+
} catch (e) {
|
|
1383
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1384
|
+
console.error(`[#corsair]: ${msg.slice(0, 500)}`);
|
|
1385
|
+
process.exit(1);
|
|
1386
|
+
}
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
if (command === "script") {
|
|
1390
|
+
const { code, tenant } = parseScriptArgs(args.slice(1));
|
|
1391
|
+
if (!code) {
|
|
1392
|
+
console.error('[#corsair]: Usage: corsair script --code "<js>"');
|
|
1393
|
+
console.error(`[#corsair]: Example: corsair script --code "const r = await corsair.slack.channels.list(); return r.channels.find(c => c.name === 'general')?.id"`);
|
|
1394
|
+
process.exit(1);
|
|
1395
|
+
}
|
|
1396
|
+
const instance = await getCorsairInstance({ cwd });
|
|
1397
|
+
const client = resolveClient(instance, tenant);
|
|
1398
|
+
const AsyncFunction = Object.getPrototypeOf(async function() {
|
|
1399
|
+
}).constructor;
|
|
1400
|
+
const fn = new AsyncFunction("corsair", code);
|
|
1401
|
+
try {
|
|
1402
|
+
const result = await fn(client);
|
|
1403
|
+
if (result !== void 0) {
|
|
1404
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1405
|
+
}
|
|
1406
|
+
} catch (e) {
|
|
1407
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1408
|
+
console.error(`[#corsair]: ${msg.slice(0, 500)}`);
|
|
1409
|
+
process.exit(1);
|
|
1410
|
+
}
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
if (command === "schema") {
|
|
1414
|
+
const schemaPath = args[1];
|
|
1415
|
+
if (!schemaPath) {
|
|
1416
|
+
console.error("[#corsair]: Usage: corsair schema <path>");
|
|
1417
|
+
console.error("[#corsair]: Example: corsair schema slack.api.messages.post");
|
|
1418
|
+
process.exit(1);
|
|
1419
|
+
}
|
|
1420
|
+
const instance = await getCorsairInstance({ cwd });
|
|
1421
|
+
const corsair = instance;
|
|
1422
|
+
if (typeof corsair.get_schema !== "function") {
|
|
1423
|
+
console.error("[#corsair]: get_schema not available on this Corsair instance.");
|
|
1424
|
+
process.exit(1);
|
|
1425
|
+
}
|
|
1426
|
+
const result = corsair.get_schema(schemaPath);
|
|
1427
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
printHelp();
|
|
1431
|
+
console.log("");
|
|
1225
1432
|
console.log(`[#corsair]: Looking for Corsair instance in ${cwd}...
|
|
1226
1433
|
`);
|
|
1227
1434
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corsair-dev/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"@clack/prompts": "^1.0.0",
|
|
24
24
|
"c12": "^3.3.3",
|
|
25
25
|
"zod": "^3.25.76",
|
|
26
|
-
"corsair": "0.1.
|
|
26
|
+
"corsair": "0.1.46"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/jest": "^29.5.14",
|