@wspc/cli 0.1.8 → 0.1.10
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 +50 -30
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +31 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1520,9 +1520,9 @@ function createConsistencyFetch(opts) {
|
|
|
1520
1520
|
}
|
|
1521
1521
|
|
|
1522
1522
|
// src/version.ts
|
|
1523
|
-
var VERSION = "0.1.
|
|
1523
|
+
var VERSION = "0.1.10";
|
|
1524
1524
|
var SPEC_SHA = "bec760cd";
|
|
1525
|
-
var SPEC_FETCHED_AT = "2026-07-
|
|
1525
|
+
var SPEC_FETCHED_AT = "2026-07-07T06:24:39.560Z";
|
|
1526
1526
|
var API_BASE = "https://api.wspc.ai";
|
|
1527
1527
|
|
|
1528
1528
|
// src/index.ts
|
|
@@ -1564,8 +1564,33 @@ function createAuthInterceptor(mode) {
|
|
|
1564
1564
|
}
|
|
1565
1565
|
let accessToken = mode.accessToken;
|
|
1566
1566
|
let refreshToken = mode.refreshToken;
|
|
1567
|
+
let expiresAt = mode.expiresAt;
|
|
1568
|
+
const { baseUrl, clientId, onTokenRefresh } = mode;
|
|
1567
1569
|
const fetchImpl = mode.fetchImpl ?? fetch;
|
|
1568
1570
|
const now = mode.now ?? Date.now;
|
|
1571
|
+
const SKEW_MS = 3e4;
|
|
1572
|
+
async function refresh() {
|
|
1573
|
+
const refreshRes = await fetchImpl(`${baseUrl}/auth/oauth/token`, {
|
|
1574
|
+
method: "POST",
|
|
1575
|
+
headers: {
|
|
1576
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
1577
|
+
"user-agent": USER_AGENT
|
|
1578
|
+
},
|
|
1579
|
+
body: new URLSearchParams({
|
|
1580
|
+
grant_type: "refresh_token",
|
|
1581
|
+
refresh_token: refreshToken,
|
|
1582
|
+
client_id: clientId
|
|
1583
|
+
})
|
|
1584
|
+
});
|
|
1585
|
+
if (!refreshRes.ok) {
|
|
1586
|
+
throw new WspcAuthExpiredError(await expiredMessage(refreshRes));
|
|
1587
|
+
}
|
|
1588
|
+
const tokens = await refreshRes.json();
|
|
1589
|
+
accessToken = tokens.access_token;
|
|
1590
|
+
refreshToken = tokens.refresh_token;
|
|
1591
|
+
expiresAt = now() + tokens.expires_in * 1e3;
|
|
1592
|
+
await onTokenRefresh({ accessToken, refreshToken, expiresAt });
|
|
1593
|
+
}
|
|
1569
1594
|
return {
|
|
1570
1595
|
async onRequest(req) {
|
|
1571
1596
|
req.headers.set("authorization", `Bearer ${accessToken}`);
|
|
@@ -1573,31 +1598,12 @@ function createAuthInterceptor(mode) {
|
|
|
1573
1598
|
return req;
|
|
1574
1599
|
},
|
|
1575
1600
|
async execute(req) {
|
|
1601
|
+
if (expiresAt !== void 0 && now() >= expiresAt - SKEW_MS) {
|
|
1602
|
+
await refresh();
|
|
1603
|
+
}
|
|
1576
1604
|
const first = await fetchImpl(await this.onRequest(req.clone()));
|
|
1577
1605
|
if (first.status !== 401) return first;
|
|
1578
|
-
|
|
1579
|
-
method: "POST",
|
|
1580
|
-
headers: {
|
|
1581
|
-
"content-type": "application/x-www-form-urlencoded",
|
|
1582
|
-
"user-agent": USER_AGENT
|
|
1583
|
-
},
|
|
1584
|
-
body: new URLSearchParams({
|
|
1585
|
-
grant_type: "refresh_token",
|
|
1586
|
-
refresh_token: refreshToken,
|
|
1587
|
-
client_id: mode.clientId
|
|
1588
|
-
})
|
|
1589
|
-
});
|
|
1590
|
-
if (!refreshRes.ok) {
|
|
1591
|
-
throw new WspcAuthExpiredError(await expiredMessage(refreshRes));
|
|
1592
|
-
}
|
|
1593
|
-
const tokens = await refreshRes.json();
|
|
1594
|
-
accessToken = tokens.access_token;
|
|
1595
|
-
refreshToken = tokens.refresh_token;
|
|
1596
|
-
await mode.onTokenRefresh({
|
|
1597
|
-
accessToken,
|
|
1598
|
-
refreshToken,
|
|
1599
|
-
expiresAt: now() + tokens.expires_in * 1e3
|
|
1600
|
-
});
|
|
1606
|
+
await refresh();
|
|
1601
1607
|
return fetchImpl(await this.onRequest(req.clone()));
|
|
1602
1608
|
}
|
|
1603
1609
|
};
|
|
@@ -1654,6 +1660,7 @@ function buildInterceptor(store, resolved, fetchImpl) {
|
|
|
1654
1660
|
return createAuthInterceptor({
|
|
1655
1661
|
accessToken: creds.access_token,
|
|
1656
1662
|
refreshToken: creds.refresh_token,
|
|
1663
|
+
expiresAt: creds.access_token_expires_at,
|
|
1657
1664
|
baseUrl: apiBase,
|
|
1658
1665
|
clientId,
|
|
1659
1666
|
fetchImpl,
|
|
@@ -6331,6 +6338,15 @@ function createDriveRealtimeSource(args) {
|
|
|
6331
6338
|
if (stopped || authFailed) return;
|
|
6332
6339
|
clearReconnectTimer();
|
|
6333
6340
|
const id = ++connectionId;
|
|
6341
|
+
const headers = args.headers;
|
|
6342
|
+
if (typeof headers !== "function") {
|
|
6343
|
+
openSocket(id, headers);
|
|
6344
|
+
return;
|
|
6345
|
+
}
|
|
6346
|
+
void headers().then((resolved) => openSocket(id, resolved)).catch((error) => closeConnection(id, error));
|
|
6347
|
+
}
|
|
6348
|
+
function openSocket(id, headers) {
|
|
6349
|
+
if (id !== connectionId || stopped || authFailed) return;
|
|
6334
6350
|
const url = buildDriveRealtimeUrl(args.baseUrl, args.libraryId, currentRealtime);
|
|
6335
6351
|
activeSocket = connect(url, {
|
|
6336
6352
|
open() {
|
|
@@ -6345,7 +6361,7 @@ function createDriveRealtimeSource(args) {
|
|
|
6345
6361
|
close(error) {
|
|
6346
6362
|
closeConnection(id, error ?? "close");
|
|
6347
6363
|
}
|
|
6348
|
-
},
|
|
6364
|
+
}, headers === void 0 ? void 0 : { headers });
|
|
6349
6365
|
}
|
|
6350
6366
|
function closeConnection(id, error) {
|
|
6351
6367
|
if (id !== connectionId || stopped || authFailed) return;
|
|
@@ -6540,6 +6556,9 @@ function isInvalidCursorReason(reason) {
|
|
|
6540
6556
|
return /\bcursor[_ -]?(invalid|expired|gone|missing|not[_ -]?found)\b|\binvalid[_ -]?cursor\b/i.test(reason);
|
|
6541
6557
|
}
|
|
6542
6558
|
function isRealtimeAuthError(error) {
|
|
6559
|
+
if (typeof error === "object" && error !== null && error.code === "WSPC_AUTH_EXPIRED") {
|
|
6560
|
+
return true;
|
|
6561
|
+
}
|
|
6543
6562
|
return /\b(401|403|auth|authorization|unauthorized|forbidden)\b/i.test(String(error));
|
|
6544
6563
|
}
|
|
6545
6564
|
function nativeWebSocketConnector(url, handlers, init) {
|
|
@@ -6683,16 +6702,17 @@ async function runDriveWatch(root, options = {}) {
|
|
|
6683
6702
|
realtimeSource = options.once ? void 0 : options.realtimeSource;
|
|
6684
6703
|
if (!options.once && realtimeSource === void 0) {
|
|
6685
6704
|
state = await ensureDriveRealtimeState(root);
|
|
6686
|
-
const
|
|
6687
|
-
|
|
6688
|
-
});
|
|
6705
|
+
const verifyPath = `/drive/libraries/${encodeURIComponent(state.library_id)}`;
|
|
6706
|
+
const { baseUrl } = await loadRealtimeAuthHeaders({ verifyPath });
|
|
6689
6707
|
const realtime = state.realtime;
|
|
6690
6708
|
if (realtime === void 0) {
|
|
6691
6709
|
throw new Error("drive realtime state is required");
|
|
6692
6710
|
}
|
|
6693
6711
|
realtimeSource = createDriveRealtimeSource({
|
|
6694
6712
|
baseUrl,
|
|
6695
|
-
headers
|
|
6713
|
+
// Tokens expire while watching; resolve fresh headers on every
|
|
6714
|
+
// (re)connect so an idle drop cannot loop on a stale snapshot.
|
|
6715
|
+
headers: async () => (await loadRealtimeAuthHeaders({ verifyPath })).headers,
|
|
6696
6716
|
libraryId: state.library_id,
|
|
6697
6717
|
realtime,
|
|
6698
6718
|
writeRealtimeState: (next) => writeDriveRealtimeState(root, next)
|