@arbidocs/client 0.5.77 → 0.5.78
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/index.cjs +86 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +275 -31
- package/dist/index.d.ts +275 -31
- package/dist/index.js +86 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1518,6 +1518,88 @@ function createAutoReloginMiddleware(config) {
|
|
|
1518
1518
|
};
|
|
1519
1519
|
}
|
|
1520
1520
|
|
|
1521
|
+
// src/middleware/request-dedup.ts
|
|
1522
|
+
function authTokenOf(input, init) {
|
|
1523
|
+
if (input instanceof Request) {
|
|
1524
|
+
const fromRequest = input.headers.get("authorization");
|
|
1525
|
+
if (fromRequest) return fromRequest;
|
|
1526
|
+
}
|
|
1527
|
+
if (init?.headers) {
|
|
1528
|
+
return new Headers(init.headers).get("authorization") ?? "";
|
|
1529
|
+
}
|
|
1530
|
+
return "";
|
|
1531
|
+
}
|
|
1532
|
+
function createDedupFetch(originalFetch) {
|
|
1533
|
+
const inFlightRequests = /* @__PURE__ */ new Map();
|
|
1534
|
+
return function dedupFetch(input, init) {
|
|
1535
|
+
const method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
|
|
1536
|
+
if (method !== "GET") {
|
|
1537
|
+
return originalFetch(input, init);
|
|
1538
|
+
}
|
|
1539
|
+
const url = input instanceof Request ? input.url : String(input);
|
|
1540
|
+
const key = `GET:${url}\0${authTokenOf(input, init)}`;
|
|
1541
|
+
const existing = inFlightRequests.get(key);
|
|
1542
|
+
if (existing) {
|
|
1543
|
+
return existing.then((r) => r.clone());
|
|
1544
|
+
}
|
|
1545
|
+
const promise = originalFetch(input, init).finally(() => {
|
|
1546
|
+
inFlightRequests.delete(key);
|
|
1547
|
+
});
|
|
1548
|
+
inFlightRequests.set(key, promise);
|
|
1549
|
+
return promise.then((r) => r.clone());
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
// src/middleware/settings-write-breaker.ts
|
|
1554
|
+
var WINDOW_MS = 6e4;
|
|
1555
|
+
var MAX_WRITES_PER_WINDOW = 30;
|
|
1556
|
+
var SETTINGS_WRITE_BREAKER_CODE = "CLIENT_SETTINGS_WRITE_BREAKER";
|
|
1557
|
+
function isSettingsWrite(input, init) {
|
|
1558
|
+
const method = (input instanceof Request ? input.method : init?.method ?? "GET").toUpperCase();
|
|
1559
|
+
if (method !== "PATCH") return false;
|
|
1560
|
+
const url = input instanceof Request ? input.url : String(input);
|
|
1561
|
+
try {
|
|
1562
|
+
const base = typeof location !== "undefined" ? location.origin : "http://localhost";
|
|
1563
|
+
return new URL(url, base).pathname.endsWith("/v1/user/settings");
|
|
1564
|
+
} catch {
|
|
1565
|
+
return false;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
function breakerResponse() {
|
|
1569
|
+
return new Response(
|
|
1570
|
+
JSON.stringify({
|
|
1571
|
+
detail: {
|
|
1572
|
+
code: SETTINGS_WRITE_BREAKER_CODE,
|
|
1573
|
+
message: "Too many settings updates from this tab \u2014 write dropped by the client circuit breaker."
|
|
1574
|
+
}
|
|
1575
|
+
}),
|
|
1576
|
+
{ status: 429, headers: { "Content-Type": "application/json" } }
|
|
1577
|
+
);
|
|
1578
|
+
}
|
|
1579
|
+
function createSettingsWriteBreakerFetch(originalFetch) {
|
|
1580
|
+
let acceptedAt = [];
|
|
1581
|
+
let trippedThisEpisode = false;
|
|
1582
|
+
return function settingsWriteBreakerFetch(input, init) {
|
|
1583
|
+
if (!isSettingsWrite(input, init)) {
|
|
1584
|
+
return originalFetch(input, init);
|
|
1585
|
+
}
|
|
1586
|
+
const now = Date.now();
|
|
1587
|
+
acceptedAt = acceptedAt.filter((t) => now - t < WINDOW_MS);
|
|
1588
|
+
if (acceptedAt.length >= MAX_WRITES_PER_WINDOW) {
|
|
1589
|
+
if (!trippedThisEpisode) {
|
|
1590
|
+
trippedThisEpisode = true;
|
|
1591
|
+
console.error(
|
|
1592
|
+
`[settings-write-breaker] over ${MAX_WRITES_PER_WINDOW} PATCH /v1/user/settings in ${WINDOW_MS / 1e3}s \u2014 dropping further writes. This indicates a client-side write loop.`
|
|
1593
|
+
);
|
|
1594
|
+
}
|
|
1595
|
+
return Promise.resolve(breakerResponse());
|
|
1596
|
+
}
|
|
1597
|
+
trippedThisEpisode = false;
|
|
1598
|
+
acceptedAt.push(now);
|
|
1599
|
+
return originalFetch(input, init);
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1521
1603
|
// src/relogin/handler.ts
|
|
1522
1604
|
var RELOGIN_COOLDOWN_MS = 5e3;
|
|
1523
1605
|
function createReloginHandler(deps) {
|
|
@@ -2058,11 +2140,12 @@ function createTransport(options) {
|
|
|
2058
2140
|
const baseUrlOption = options.baseUrl;
|
|
2059
2141
|
const base = typeof baseUrlOption === "function" ? baseUrlOption : () => baseUrlOption;
|
|
2060
2142
|
const transport = createHttpTransport(options.transport);
|
|
2061
|
-
const
|
|
2143
|
+
const guardedFetch = createSettingsWriteBreakerFetch(createDedupFetch(transport.fetch));
|
|
2144
|
+
const retryFetch = createRetryFetch(guardedFetch);
|
|
2062
2145
|
const gate = createSessionGate();
|
|
2063
2146
|
const sessionFetch = gatedFetch(gate, retryFetch);
|
|
2064
2147
|
const http = {
|
|
2065
|
-
fetch: gatedFetch(gate,
|
|
2148
|
+
fetch: gatedFetch(gate, guardedFetch),
|
|
2066
2149
|
customFetch: transport.customFetch,
|
|
2067
2150
|
withFetch: (adapter) => gatedFetch(gate, transport.withFetch(adapter))
|
|
2068
2151
|
};
|
|
@@ -2423,6 +2506,6 @@ var logger = {
|
|
|
2423
2506
|
}
|
|
2424
2507
|
};
|
|
2425
2508
|
|
|
2426
|
-
export { ACCESS_TOKEN_STORAGE_KEY, API_PREFIX, CALL_KEY_BYTES, CHAT_KEY_BYTES, ENCRYPTED_RECOVERY_KEY_SIZE, RECOVERY_KEY_ERRORS, SECURE_MAIL_KEY_BYTES, UNENCRYPTED_RECOVERY_KEY_SIZE, authRequestError, base64Decode, base64Encode, base64ToBytes, base64UrlToBytes, browserSessionStateStorage, buildCallFragment, buildCallLink, buildWebSocketUrl, bytesToBase64, bytesToBase64Url, canPersistSession, changePassword, clearAllData, clearSession, computeSharedSecret, configureLogger, createAllWorkspacesOpener, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createHttpTransport, createMemorySessionPersistence, createOfflineSealer, createRecoveryFile, createRecoveryUrl, createReloginHandler, createSessionManager, createWorkspaceKeys, createWorkspaceOpens, createWorkspaceReopener, decodeCallKey, decodeSecureMailKey, decryptCallTitle, decryptFile, decryptMessage, decryptMessageWithSharedSecret, decryptRecoveryKey, decryptWithChatKey, deriveDirectChatKey, deriveEncryptionKeypairFromSigning, derivePublicKey, disconnectSso, encodeCallKey, encryptCallTitle, encryptFile, encryptMessage, encryptMessageWithSharedSecret, encryptRecoveryKey, encryptWithChatKey, encryptionKeypairFromSigningKey, generateCallKey, generateChatKey, generateIdentityKeypair, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRegistrationCredentials, generateUserKeypairs, getRecoveryKeyFilename, getSession, getUserEncryptionKeypair, hasSession, identityFromLoginResponse, initSodium, initializeDatabase, isAbortError, isEncryptedRecoveryKey, isMessageType, logger, openCallKeyOf, openSealedCallKey, openSealedChatKey, openSecureMail, parseCallFragment, parseRecoveryUrl, parseServerMessage, passwordChangeErrorMessage, prewarmKeyPairs, readSessionClaims, requestSsoDisconnectCode, saveSession, sealCallKey, sealCallKeyForPeers, sealChatKey, sealKeyForSession, sealSecureMail, sealedBoxDecrypt, sealedBoxEncrypt, secureMailClaim, signMessage, unlockIdentityWithPassword, unwrapIdentityKey, unwrapWorkspaceKey, updateWrappedIdentityKey, validateRecoveryKeyFile, workspaceKeyRequiredOf, wrapIdentityKey };
|
|
2509
|
+
export { ACCESS_TOKEN_STORAGE_KEY, API_PREFIX, CALL_KEY_BYTES, CHAT_KEY_BYTES, ENCRYPTED_RECOVERY_KEY_SIZE, RECOVERY_KEY_ERRORS, SECURE_MAIL_KEY_BYTES, SETTINGS_WRITE_BREAKER_CODE, UNENCRYPTED_RECOVERY_KEY_SIZE, authRequestError, base64Decode, base64Encode, base64ToBytes, base64UrlToBytes, browserSessionStateStorage, buildCallFragment, buildCallLink, buildWebSocketUrl, bytesToBase64, bytesToBase64Url, canPersistSession, changePassword, clearAllData, clearSession, computeSharedSecret, configureLogger, createAllWorkspacesOpener, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createHttpTransport, createMemorySessionPersistence, createOfflineSealer, createRecoveryFile, createRecoveryUrl, createReloginHandler, createSessionManager, createWorkspaceKeys, createWorkspaceOpens, createWorkspaceReopener, decodeCallKey, decodeSecureMailKey, decryptCallTitle, decryptFile, decryptMessage, decryptMessageWithSharedSecret, decryptRecoveryKey, decryptWithChatKey, deriveDirectChatKey, deriveEncryptionKeypairFromSigning, derivePublicKey, disconnectSso, encodeCallKey, encryptCallTitle, encryptFile, encryptMessage, encryptMessageWithSharedSecret, encryptRecoveryKey, encryptWithChatKey, encryptionKeypairFromSigningKey, generateCallKey, generateChatKey, generateIdentityKeypair, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRegistrationCredentials, generateUserKeypairs, getRecoveryKeyFilename, getSession, getUserEncryptionKeypair, hasSession, identityFromLoginResponse, initSodium, initializeDatabase, isAbortError, isEncryptedRecoveryKey, isMessageType, logger, openCallKeyOf, openSealedCallKey, openSealedChatKey, openSecureMail, parseCallFragment, parseRecoveryUrl, parseServerMessage, passwordChangeErrorMessage, prewarmKeyPairs, readSessionClaims, requestSsoDisconnectCode, saveSession, sealCallKey, sealCallKeyForPeers, sealChatKey, sealKeyForSession, sealSecureMail, sealedBoxDecrypt, sealedBoxEncrypt, secureMailClaim, signMessage, unlockIdentityWithPassword, unwrapIdentityKey, unwrapWorkspaceKey, updateWrappedIdentityKey, validateRecoveryKeyFile, workspaceKeyRequiredOf, wrapIdentityKey };
|
|
2427
2510
|
//# sourceMappingURL=index.js.map
|
|
2428
2511
|
//# sourceMappingURL=index.js.map
|