@corsair-dev/cli 0.1.1 → 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 CHANGED
@@ -1,4 +1,4 @@
1
- # @corsair-ai/cli
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-ai/cli
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": "1234567890000"
109
+ "expires_at": "1234567890"
110
110
  }
111
111
  }
112
112
  ```
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAsLA;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQhE;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,kBAAkB,CAAC,EACxC,GAAG,EACH,UAAU,EACV,kBAA0B,GAC1B,EAAE;IACF,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B,eA2JA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAsLA;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQhE;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,kBAAkB,CAAC,EACxC,GAAG,EACH,UAAU,EACV,kBAA0B,GAC1B,EAAE;IACF,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B,eA8KA"}
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 * 1e3).toString());
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) {
@@ -1060,10 +1060,30 @@ async function getCorsairInstance({
1060
1060
  );
1061
1061
  process.exit(1);
1062
1062
  }
1063
+ const msg = typeof e === "object" && e && "message" in e && typeof e.message === "string" ? e.message : String(e);
1064
+ if (msg.includes("Could not locate the bindings file") || msg.includes("NODE_MODULE_VERSION") || msg.includes(".node")) {
1065
+ if (shouldThrowOnError) {
1066
+ throw new Error(
1067
+ `Native module error in ${possiblePath}: ${msg}
1068
+
1069
+ This is likely because a native Node.js addon (e.g. better-sqlite3) needs to be rebuilt for your current Node.js version. Try running:
1070
+ npm rebuild
1071
+ or reinstall your dependencies:
1072
+ rm -rf node_modules && npm install`
1073
+ );
1074
+ }
1075
+ console.error(`[#corsair]: Error loading ${possiblePath}: Native module binding not found.`);
1076
+ console.log("");
1077
+ console.log("[#corsair]: A native Node.js addon (e.g. better-sqlite3) needs to be rebuilt for your current Node.js version.");
1078
+ console.log("[#corsair]: Try running:");
1079
+ console.log(" npm rebuild");
1080
+ console.log("[#corsair]: Or reinstall your dependencies:");
1081
+ console.log(" rm -rf node_modules && npm install");
1082
+ process.exit(1);
1083
+ }
1063
1084
  if (shouldThrowOnError) {
1064
1085
  throw e;
1065
1086
  }
1066
- const msg = typeof e === "object" && e && "message" in e && typeof e.message === "string" ? e.message : String(e);
1067
1087
  console.error(`[#corsair]: Error loading ${possiblePath}:`, msg);
1068
1088
  process.exit(1);
1069
1089
  }
@@ -1104,6 +1124,46 @@ async function getCorsairInstance({
1104
1124
  process.exit(1);
1105
1125
  }
1106
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
+ }
1107
1167
  function parseAuthArgs(args) {
1108
1168
  let pluginId;
1109
1169
  let tenantId;
@@ -1160,24 +1220,84 @@ function parseSetupArgs(args) {
1160
1220
  }
1161
1221
  return { backfill, credentials };
1162
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
+ }
1163
1295
  async function main() {
1164
1296
  const cwd = process.cwd();
1165
1297
  const args = process.argv.slice(2);
1166
1298
  const command = args[0];
1167
1299
  if (command === "help" || command === "--help" || command === "-h") {
1168
- console.log("[#corsair]: Corsair CLI\n");
1169
- console.log("Commands:");
1170
- console.log(" corsair setup Initialize your Corsair instance");
1171
- console.log(" corsair setup -backfill Initialize and backfill initial data");
1172
- console.log(" corsair setup --<plugin> <field>=VALUE ... Set credentials for a plugin");
1173
- console.log(" corsair auth --plugin=<id> Start OAuth flow (outputs auth URL as JSON)");
1174
- console.log(" corsair auth --plugin=<id> --code=<code> Exchange OAuth code for tokens");
1175
- console.log(" corsair auth --plugin=<id> --credentials Show current credential status");
1176
- console.log(
1177
- " corsair watch-renew Renew Google webhook watch (Gmail/Drive/Calendar)"
1178
- );
1179
- console.log(" corsair migrate Create a data migration script");
1180
- console.log(" corsair migrate help Show migration help\n");
1300
+ printHelp();
1181
1301
  return;
1182
1302
  }
1183
1303
  if (command === "setup") {
@@ -1202,6 +1322,113 @@ async function main() {
1202
1322
  await runWatchRenew2({ cwd });
1203
1323
  return;
1204
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("");
1205
1432
  console.log(`[#corsair]: Looking for Corsair instance in ${cwd}...
1206
1433
  `);
1207
1434
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@corsair-dev/cli",
3
- "version": "0.1.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.45"
26
+ "corsair": "0.1.46"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/jest": "^29.5.14",