@acosmi/sdk-ts 1.4.0 → 1.4.1
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/CHANGELOG.md +12 -0
- package/dist/browser/index.mjs +122 -39
- package/dist/browser/index.mjs.map +1 -1
- package/dist/index.mjs +122 -39
- package/dist/index.mjs.map +1 -1
- package/dist/node/index.cjs +124 -38
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +25 -2
- package/dist/node/index.d.ts +25 -2
- package/dist/node/index.mjs +122 -39
- package/dist/node/index.mjs.map +1 -1
- package/package.json +9 -2
package/dist/node/index.cjs
CHANGED
|
@@ -2242,6 +2242,9 @@ var FilterStatusFallbackTkdistSkew = "fallback-tkdist-deployment-skew";
|
|
|
2242
2242
|
var FilterStatusFallbackNoBuckets = "fallback-no-buckets";
|
|
2243
2243
|
var FilterStatusFallbackMissingUser = "fallback-missing-userid";
|
|
2244
2244
|
var FilterStatusUnknown = "";
|
|
2245
|
+
var ErrOAuthCORSBlocked = "oauth_cors_blocked";
|
|
2246
|
+
var ErrRefreshProxyFailed = "refresh_proxy_failed";
|
|
2247
|
+
var ErrTokenExpired = "token_expired";
|
|
2245
2248
|
function newDeferred() {
|
|
2246
2249
|
let resolve;
|
|
2247
2250
|
let reject;
|
|
@@ -2259,6 +2262,10 @@ var Client = class _Client {
|
|
|
2259
2262
|
complianceBaseURL;
|
|
2260
2263
|
/** OAuth metadata profile — 刷新 token 时发现 metadata 用 (默认 'desktop') */
|
|
2261
2264
|
oauthMetadataProfile;
|
|
2265
|
+
/** Browser Web OAuth refresh strategy (default 'direct') */
|
|
2266
|
+
browserRefreshMode;
|
|
2267
|
+
/** Same-origin refresh proxy URL for browserRefreshMode='server-proxy' */
|
|
2268
|
+
refreshProxyURL;
|
|
2262
2269
|
/** OAuth metadata (lazy loaded) */
|
|
2263
2270
|
meta = null;
|
|
2264
2271
|
/** 当前 token (内存) */
|
|
@@ -2294,6 +2301,8 @@ var Client = class _Client {
|
|
|
2294
2301
|
this.serverURL = (cfg.serverURL ?? "https://acosmi.com").replace(/\/+$/, "");
|
|
2295
2302
|
this.complianceBaseURL = cfg.complianceBaseURL ? cfg.complianceBaseURL.replace(/\/+$/, "") : null;
|
|
2296
2303
|
this.oauthMetadataProfile = cfg.oauthMetadataProfile ?? "desktop";
|
|
2304
|
+
this.browserRefreshMode = cfg.browserRefreshMode ?? "direct";
|
|
2305
|
+
this.refreshProxyURL = cfg.refreshProxyURL ?? null;
|
|
2297
2306
|
this.store = cfg.store ?? defaultTokenStore();
|
|
2298
2307
|
this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
2299
2308
|
this.retryPolicy = effectivePolicy(cfg.retryPolicy ?? null);
|
|
@@ -2537,27 +2546,7 @@ var Client = class _Client {
|
|
|
2537
2546
|
if (!tokenSetIsExpired(this.tokens)) {
|
|
2538
2547
|
return this.tokens.access_token;
|
|
2539
2548
|
}
|
|
2540
|
-
|
|
2541
|
-
try {
|
|
2542
|
-
this.meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal);
|
|
2543
|
-
} catch (e) {
|
|
2544
|
-
throw new Error(
|
|
2545
|
-
`discover for refresh: ${e instanceof Error ? e.message : String(e)}`
|
|
2546
|
-
);
|
|
2547
|
-
}
|
|
2548
|
-
}
|
|
2549
|
-
let tokenResp;
|
|
2550
|
-
try {
|
|
2551
|
-
tokenResp = await refreshToken(this.meta, this.tokens.client_id, this.tokens.refresh_token, signal);
|
|
2552
|
-
} catch (e) {
|
|
2553
|
-
throw new Error(`refresh token: ${e instanceof Error ? e.message : String(e)}`);
|
|
2554
|
-
}
|
|
2555
|
-
this.tokens = newTokenSet(tokenResp, this.tokens.client_id, this.serverURL);
|
|
2556
|
-
try {
|
|
2557
|
-
await this.store.save(this.tokens);
|
|
2558
|
-
} catch (e) {
|
|
2559
|
-
console.warn(`[acosmi-sdk] warning: save refreshed token failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
2560
|
-
}
|
|
2549
|
+
await this.refreshCurrentToken(signal);
|
|
2561
2550
|
return this.tokens.access_token;
|
|
2562
2551
|
})
|
|
2563
2552
|
);
|
|
@@ -2570,26 +2559,111 @@ var Client = class _Client {
|
|
|
2570
2559
|
if (this.tokens == null) {
|
|
2571
2560
|
throw new Error("no tokens to refresh");
|
|
2572
2561
|
}
|
|
2573
|
-
|
|
2574
|
-
this.meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal);
|
|
2575
|
-
}
|
|
2576
|
-
const tokenResp = await refreshToken(
|
|
2577
|
-
this.meta,
|
|
2578
|
-
this.tokens.client_id,
|
|
2579
|
-
this.tokens.refresh_token,
|
|
2580
|
-
signal
|
|
2581
|
-
);
|
|
2582
|
-
this.tokens = newTokenSet(tokenResp, this.tokens.client_id, this.serverURL);
|
|
2583
|
-
try {
|
|
2584
|
-
await this.store.save(this.tokens);
|
|
2585
|
-
} catch (e) {
|
|
2586
|
-
console.warn(
|
|
2587
|
-
`[acosmi-sdk] warning: save refreshed token failed: ${e instanceof Error ? e.message : String(e)}`
|
|
2588
|
-
);
|
|
2589
|
-
}
|
|
2562
|
+
await this.refreshCurrentToken(signal);
|
|
2590
2563
|
})
|
|
2591
2564
|
);
|
|
2592
2565
|
}
|
|
2566
|
+
async refreshCurrentToken(signal) {
|
|
2567
|
+
if (this.tokens == null) {
|
|
2568
|
+
throw new Error("no tokens to refresh");
|
|
2569
|
+
}
|
|
2570
|
+
if (this.browserRefreshMode === "none") {
|
|
2571
|
+
throw new Error(`${ErrTokenExpired}: token refresh disabled`);
|
|
2572
|
+
}
|
|
2573
|
+
if (this.browserRefreshMode === "server-proxy") {
|
|
2574
|
+
await this.refreshCurrentTokenViaProxy(signal);
|
|
2575
|
+
return;
|
|
2576
|
+
}
|
|
2577
|
+
await this.refreshCurrentTokenDirect(signal);
|
|
2578
|
+
}
|
|
2579
|
+
async refreshCurrentTokenDirect(signal) {
|
|
2580
|
+
if (this.tokens == null) {
|
|
2581
|
+
throw new Error("no tokens to refresh");
|
|
2582
|
+
}
|
|
2583
|
+
if (this.meta == null) {
|
|
2584
|
+
try {
|
|
2585
|
+
this.meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal);
|
|
2586
|
+
} catch (e) {
|
|
2587
|
+
throw new Error(
|
|
2588
|
+
`discover for refresh: ${e instanceof Error ? e.message : String(e)}`
|
|
2589
|
+
);
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
let tokenResp;
|
|
2593
|
+
try {
|
|
2594
|
+
tokenResp = await refreshToken(
|
|
2595
|
+
this.meta,
|
|
2596
|
+
this.tokens.client_id,
|
|
2597
|
+
this.tokens.refresh_token,
|
|
2598
|
+
signal
|
|
2599
|
+
);
|
|
2600
|
+
} catch (e) {
|
|
2601
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
2602
|
+
if (isLikelyBrowserOAuthCORSError(message)) {
|
|
2603
|
+
throw new Error(`${ErrOAuthCORSBlocked}: refresh token: ${message}`);
|
|
2604
|
+
}
|
|
2605
|
+
throw new Error(`refresh token: ${message}`);
|
|
2606
|
+
}
|
|
2607
|
+
this.tokens = newTokenSet(tokenResp, this.tokens.client_id, this.serverURL);
|
|
2608
|
+
await this.saveRefreshedToken();
|
|
2609
|
+
}
|
|
2610
|
+
async refreshCurrentTokenViaProxy(signal) {
|
|
2611
|
+
if (this.tokens == null) {
|
|
2612
|
+
throw new Error("no tokens to refresh");
|
|
2613
|
+
}
|
|
2614
|
+
if (!this.refreshProxyURL) {
|
|
2615
|
+
throw new Error(`${ErrRefreshProxyFailed}: refreshProxyURL is required`);
|
|
2616
|
+
}
|
|
2617
|
+
let resp;
|
|
2618
|
+
try {
|
|
2619
|
+
resp = await this.fetchImpl(this.refreshProxyURL, {
|
|
2620
|
+
method: "POST",
|
|
2621
|
+
headers: { "Content-Type": "application/json" },
|
|
2622
|
+
body: JSON.stringify({
|
|
2623
|
+
client_id: this.tokens.client_id,
|
|
2624
|
+
refresh_token: this.tokens.refresh_token,
|
|
2625
|
+
server_url: this.tokens.server_url || this.serverURL
|
|
2626
|
+
}),
|
|
2627
|
+
signal
|
|
2628
|
+
});
|
|
2629
|
+
} catch (e) {
|
|
2630
|
+
throw new Error(
|
|
2631
|
+
`${ErrRefreshProxyFailed}: ${e instanceof Error ? e.message : String(e)}`
|
|
2632
|
+
);
|
|
2633
|
+
}
|
|
2634
|
+
if (!resp.ok) {
|
|
2635
|
+
let message = "";
|
|
2636
|
+
try {
|
|
2637
|
+
const body2 = await resp.json();
|
|
2638
|
+
if (typeof body2.error === "string") message = body2.error;
|
|
2639
|
+
} catch {
|
|
2640
|
+
}
|
|
2641
|
+
throw new Error(`${ErrRefreshProxyFailed}: HTTP ${resp.status}: ${message}`);
|
|
2642
|
+
}
|
|
2643
|
+
let body;
|
|
2644
|
+
try {
|
|
2645
|
+
body = await resp.json();
|
|
2646
|
+
} catch (e) {
|
|
2647
|
+
throw new Error(
|
|
2648
|
+
`${ErrRefreshProxyFailed}: decode: ${e instanceof Error ? e.message : String(e)}`
|
|
2649
|
+
);
|
|
2650
|
+
}
|
|
2651
|
+
if (!isTokenSetLike(body.tokenSet)) {
|
|
2652
|
+
throw new Error(`${ErrRefreshProxyFailed}: response missing tokenSet`);
|
|
2653
|
+
}
|
|
2654
|
+
this.tokens = body.tokenSet;
|
|
2655
|
+
await this.saveRefreshedToken();
|
|
2656
|
+
}
|
|
2657
|
+
async saveRefreshedToken() {
|
|
2658
|
+
if (this.tokens == null) return;
|
|
2659
|
+
try {
|
|
2660
|
+
await this.store.save(this.tokens);
|
|
2661
|
+
} catch (e) {
|
|
2662
|
+
console.warn(
|
|
2663
|
+
`[acosmi-sdk] warning: save refreshed token failed: ${e instanceof Error ? e.message : String(e)}`
|
|
2664
|
+
);
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2593
2667
|
/** 互斥锁 helper (替代 Go sync.Mutex) */
|
|
2594
2668
|
withMu(fn) {
|
|
2595
2669
|
const next = this.mu.then(fn, fn);
|
|
@@ -3288,6 +3362,15 @@ function defaultTokenStore() {
|
|
|
3288
3362
|
}
|
|
3289
3363
|
return new InMemoryTokenStore();
|
|
3290
3364
|
}
|
|
3365
|
+
function isLikelyBrowserOAuthCORSError(message) {
|
|
3366
|
+
const lower = message.toLowerCase();
|
|
3367
|
+
return lower.includes("failed to fetch") || lower.includes("networkerror") || lower.includes("cors") || lower.includes("http 403");
|
|
3368
|
+
}
|
|
3369
|
+
function isTokenSetLike(value) {
|
|
3370
|
+
if (value == null || typeof value !== "object") return false;
|
|
3371
|
+
const candidate = value;
|
|
3372
|
+
return typeof candidate.access_token === "string" && typeof candidate.refresh_token === "string" && typeof candidate.expires_at === "string" && typeof candidate.scope === "string" && typeof candidate.client_id === "string" && typeof candidate.server_url === "string";
|
|
3373
|
+
}
|
|
3291
3374
|
function zeroModelCapabilities() {
|
|
3292
3375
|
return {
|
|
3293
3376
|
supports_thinking: false,
|
|
@@ -5478,8 +5561,10 @@ exports.ErrBrowserOpen = ErrBrowserOpen;
|
|
|
5478
5561
|
exports.ErrComplianceStepUpRequired = ErrComplianceStepUpRequired;
|
|
5479
5562
|
exports.ErrDiscovery = ErrDiscovery;
|
|
5480
5563
|
exports.ErrEnvelopeGateClosed = ErrEnvelopeGateClosed;
|
|
5564
|
+
exports.ErrOAuthCORSBlocked = ErrOAuthCORSBlocked;
|
|
5481
5565
|
exports.ErrProviderNotConfigured = ErrProviderNotConfigured;
|
|
5482
5566
|
exports.ErrProviderUnknownNoRetry = ErrProviderUnknownNoRetry;
|
|
5567
|
+
exports.ErrRefreshProxyFailed = ErrRefreshProxyFailed;
|
|
5483
5568
|
exports.ErrRegistration = ErrRegistration;
|
|
5484
5569
|
exports.ErrSSLProxy = ErrSSLProxy;
|
|
5485
5570
|
exports.ErrSealApprovalContractHashMismatch = ErrSealApprovalContractHashMismatch;
|
|
@@ -5493,6 +5578,7 @@ exports.ErrSealUseAlreadyConsumed = ErrSealUseAlreadyConsumed;
|
|
|
5493
5578
|
exports.ErrStateMismatch = ErrStateMismatch;
|
|
5494
5579
|
exports.ErrTimeout = ErrTimeout;
|
|
5495
5580
|
exports.ErrTokenExchange = ErrTokenExchange;
|
|
5581
|
+
exports.ErrTokenExpired = ErrTokenExpired;
|
|
5496
5582
|
exports.EventAuthURL = EventAuthURL;
|
|
5497
5583
|
exports.EventComplete = EventComplete;
|
|
5498
5584
|
exports.EventError = EventError;
|