@wspc/cli 0.0.18 → 0.0.20
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/dist/cli.js +48 -50
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/spec/openapi.json +4 -34
package/dist/cli.js
CHANGED
|
@@ -1321,13 +1321,6 @@ var SERVICE_HEADERS = {
|
|
|
1321
1321
|
email: "x-cb-email",
|
|
1322
1322
|
push: "x-cb-push"
|
|
1323
1323
|
};
|
|
1324
|
-
var SERVICE_PREFIXES = [
|
|
1325
|
-
{ service: "auth", prefix: "/auth" },
|
|
1326
|
-
{ service: "todo", prefix: "/todo" },
|
|
1327
|
-
{ service: "calendar", prefix: "/calendar" },
|
|
1328
|
-
{ service: "email", prefix: "/email" },
|
|
1329
|
-
{ service: "push", prefix: "/push" }
|
|
1330
|
-
];
|
|
1331
1324
|
var KNOWN_HEADERS = Object.values(SERVICE_HEADERS);
|
|
1332
1325
|
function normalizeBasePath(pathname) {
|
|
1333
1326
|
const trimmed = pathname.replace(/\/+$/, "");
|
|
@@ -1338,23 +1331,11 @@ function isUnderApiBase(url, apiBase) {
|
|
|
1338
1331
|
const basePath = normalizeBasePath(base.pathname);
|
|
1339
1332
|
return url.origin === base.origin && (basePath === "/" || url.pathname === basePath || url.pathname.startsWith(`${basePath}/`));
|
|
1340
1333
|
}
|
|
1341
|
-
function
|
|
1342
|
-
|
|
1343
|
-
if (basePath === "/") return url.pathname;
|
|
1344
|
-
if (url.pathname === basePath) return "/";
|
|
1345
|
-
return url.pathname.slice(basePath.length) || "/";
|
|
1346
|
-
}
|
|
1347
|
-
function pathMatchesPrefix(pathname, prefix) {
|
|
1348
|
-
return pathname === prefix || pathname.startsWith(`${prefix}/`);
|
|
1349
|
-
}
|
|
1350
|
-
function serviceForPath(pathname) {
|
|
1351
|
-
return SERVICE_PREFIXES.find(({ prefix }) => pathMatchesPrefix(pathname, prefix))?.service;
|
|
1352
|
-
}
|
|
1353
|
-
function stripKnownBookmarkHeaders(request, keep) {
|
|
1354
|
-
if (!KNOWN_HEADERS.some((header) => header !== keep && request.headers.has(header))) return request;
|
|
1334
|
+
function stripKnownBookmarkHeaders(request) {
|
|
1335
|
+
if (!KNOWN_HEADERS.some((header) => request.headers.has(header))) return request;
|
|
1355
1336
|
const headers = new Headers(request.headers);
|
|
1356
1337
|
for (const header of KNOWN_HEADERS) {
|
|
1357
|
-
|
|
1338
|
+
headers.delete(header);
|
|
1358
1339
|
}
|
|
1359
1340
|
return new Request(request, { headers });
|
|
1360
1341
|
}
|
|
@@ -1378,21 +1359,22 @@ function createConsistencyFetch(opts) {
|
|
|
1378
1359
|
const request = new Request(input, init);
|
|
1379
1360
|
const url = new URL(request.url);
|
|
1380
1361
|
const applies = isUnderApiBase(url, opts.apiBase);
|
|
1381
|
-
let outgoing = request;
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
const headers = new Headers(outgoing.headers);
|
|
1362
|
+
let outgoing = stripKnownBookmarkHeaders(request);
|
|
1363
|
+
const injectedBookmarks = [];
|
|
1364
|
+
if (applies) {
|
|
1365
|
+
const config = await opts.store.read();
|
|
1366
|
+
const bookmarks = config.envs[opts.envName]?.consistency_bookmarks;
|
|
1367
|
+
if (bookmarks) {
|
|
1368
|
+
const headers = new Headers(outgoing.headers);
|
|
1369
|
+
for (const [serviceName, header] of Object.entries(SERVICE_HEADERS)) {
|
|
1370
|
+
const service = serviceName;
|
|
1371
|
+
const bookmark = bookmarks[service];
|
|
1372
|
+
if (!bookmark) continue;
|
|
1393
1373
|
headers.set(header, bookmark);
|
|
1374
|
+
injectedBookmarks.push([service, bookmark]);
|
|
1375
|
+
}
|
|
1376
|
+
if (injectedBookmarks.length > 0) {
|
|
1394
1377
|
outgoing = new Request(outgoing, { headers });
|
|
1395
|
-
injectedService = service;
|
|
1396
1378
|
}
|
|
1397
1379
|
}
|
|
1398
1380
|
}
|
|
@@ -1402,7 +1384,7 @@ function createConsistencyFetch(opts) {
|
|
|
1402
1384
|
const value = response.headers.get(header);
|
|
1403
1385
|
return value ? [[serviceName, value]] : [];
|
|
1404
1386
|
});
|
|
1405
|
-
const shouldCheckInvalidBookmark =
|
|
1387
|
+
const shouldCheckInvalidBookmark = injectedBookmarks.length > 0;
|
|
1406
1388
|
const invalidBookmark = shouldCheckInvalidBookmark ? await responseHasInvalidBookmark(response) : false;
|
|
1407
1389
|
if (nextBookmarks.length === 0 && !invalidBookmark) return response;
|
|
1408
1390
|
await opts.store.update((config) => {
|
|
@@ -1412,8 +1394,12 @@ function createConsistencyFetch(opts) {
|
|
|
1412
1394
|
for (const [serviceName, value] of nextBookmarks) {
|
|
1413
1395
|
env.consistency_bookmarks[serviceName] = value;
|
|
1414
1396
|
}
|
|
1415
|
-
if (invalidBookmark
|
|
1416
|
-
|
|
1397
|
+
if (invalidBookmark) {
|
|
1398
|
+
for (const [service, injectedValue] of injectedBookmarks) {
|
|
1399
|
+
if (env.consistency_bookmarks[service] === injectedValue) {
|
|
1400
|
+
delete env.consistency_bookmarks[service];
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1417
1403
|
}
|
|
1418
1404
|
if (Object.keys(env.consistency_bookmarks).length === 0) {
|
|
1419
1405
|
delete env.consistency_bookmarks;
|
|
@@ -1424,9 +1410,9 @@ function createConsistencyFetch(opts) {
|
|
|
1424
1410
|
}
|
|
1425
1411
|
|
|
1426
1412
|
// src/version.ts
|
|
1427
|
-
var VERSION = "0.0.
|
|
1428
|
-
var SPEC_SHA = "
|
|
1429
|
-
var SPEC_FETCHED_AT = "2026-06-
|
|
1413
|
+
var VERSION = "0.0.20";
|
|
1414
|
+
var SPEC_SHA = "1b183552";
|
|
1415
|
+
var SPEC_FETCHED_AT = "2026-06-17T12:14:35.785Z";
|
|
1430
1416
|
var API_BASE = "https://api.wspc.ai";
|
|
1431
1417
|
|
|
1432
1418
|
// src/index.ts
|
|
@@ -3674,6 +3660,24 @@ async function fetchMe(opts) {
|
|
|
3674
3660
|
}
|
|
3675
3661
|
|
|
3676
3662
|
// src/handwritten/auth/login.ts
|
|
3663
|
+
function renderDevicePrompt(prompt) {
|
|
3664
|
+
const mins = Math.max(1, Math.round((prompt.expires_in ?? 0) / 60));
|
|
3665
|
+
const lines = ["", ` ${bold("wspc login")}`, ""];
|
|
3666
|
+
if (prompt.verification_uri_complete) {
|
|
3667
|
+
lines.push(` ${dim("Open this link to sign in (code already filled in):")}`);
|
|
3668
|
+
lines.push(` ${cyan(prompt.verification_uri_complete)}`);
|
|
3669
|
+
lines.push("");
|
|
3670
|
+
lines.push(` ${dim(`Or go to ${prompt.verification_uri} and enter:`)}`);
|
|
3671
|
+
lines.push(` ${bold(prompt.user_code)}`);
|
|
3672
|
+
} else {
|
|
3673
|
+
lines.push(` ${dim(`Go to ${prompt.verification_uri} and enter:`)}`);
|
|
3674
|
+
lines.push(` ${bold(prompt.user_code)}`);
|
|
3675
|
+
}
|
|
3676
|
+
lines.push("");
|
|
3677
|
+
lines.push(` ${dim(`Code expires in ${mins}m \xB7 waiting for approval\u2026`)}`);
|
|
3678
|
+
lines.push("");
|
|
3679
|
+
return lines.join("\n");
|
|
3680
|
+
}
|
|
3677
3681
|
function getOrCreateEnv(c, envName, apiBase) {
|
|
3678
3682
|
const existing = c.envs[envName];
|
|
3679
3683
|
if (existing) {
|
|
@@ -3716,7 +3720,7 @@ async function runLogin(opts) {
|
|
|
3716
3720
|
if (who2.email !== LEGACY_ACCOUNT_KEY) delete env2.accounts[LEGACY_ACCOUNT_KEY];
|
|
3717
3721
|
c2.current_env = envName;
|
|
3718
3722
|
await opts.store.write(c2);
|
|
3719
|
-
opts.output.write(
|
|
3723
|
+
opts.output.write(`${green("\u2713")} logged in (api key) as ${bold(who2.email)} ${dim(`\u2192 env "${envName}"`)}`);
|
|
3720
3724
|
return;
|
|
3721
3725
|
}
|
|
3722
3726
|
const ensureClient = opts.ensureClient ?? ((env2) => ensureClientId({ store: opts.store, envName: env2, baseUrl: opts.baseUrl }));
|
|
@@ -3730,13 +3734,7 @@ async function runLogin(opts) {
|
|
|
3730
3734
|
onPrompt: (p) => {
|
|
3731
3735
|
const prompt = p;
|
|
3732
3736
|
opts.output.writeJson({ event: "device_code_issued", ...prompt });
|
|
3733
|
-
opts.output.write(
|
|
3734
|
-
=== wspc login ===`);
|
|
3735
|
-
opts.output.write(`verification_uri: ${prompt.verification_uri}`);
|
|
3736
|
-
opts.output.write(`user_code: ${prompt.user_code}`);
|
|
3737
|
-
opts.output.write(`expires_in: ${prompt.expires_in}`);
|
|
3738
|
-
opts.output.write(`=== waiting for approval ===
|
|
3739
|
-
`);
|
|
3737
|
+
opts.output.write(renderDevicePrompt(prompt));
|
|
3740
3738
|
}
|
|
3741
3739
|
});
|
|
3742
3740
|
const who = await me({
|
|
@@ -3762,7 +3760,7 @@ async function runLogin(opts) {
|
|
|
3762
3760
|
c.current_env = envName;
|
|
3763
3761
|
await opts.store.write(c);
|
|
3764
3762
|
opts.output.writeJson({ event: "login_success", email: who.email });
|
|
3765
|
-
opts.output.write(
|
|
3763
|
+
opts.output.write(`${green("\u2713")} logged in as ${bold(who.email)} ${dim(`\u2192 env "${envName}"`)}`);
|
|
3766
3764
|
}
|
|
3767
3765
|
|
|
3768
3766
|
// src/handwritten/commands/login.ts
|