@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/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## [1.4.1] — 2026-05-22
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **`Config.browserRefreshMode?: 'direct' | 'server-proxy' | 'none'`** 与
|
|
17
|
+
`refreshProxyURL` — 浏览器 Web OAuth token 刷新策略。默认 `direct` 保持既有行为;
|
|
18
|
+
`server-proxy` 可把刷新收口到同源 Route Handler,规避 OAuth issuer CORS 403;
|
|
19
|
+
`none` 用于产品自行处理过期登录态。新增错误码常量
|
|
20
|
+
`ErrOAuthCORSBlocked`、`ErrRefreshProxyFailed`、`ErrTokenExpired`。
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
12
24
|
## [1.4.0] — 2026-05-21
|
|
13
25
|
|
|
14
26
|
> csign `/login` Web OAuth 接入复核审计(`docs/audit/csign-login-oauth-audit-result-2026-05-21`)
|
package/dist/browser/index.mjs
CHANGED
|
@@ -2240,6 +2240,9 @@ var FilterStatusFallbackTkdistSkew = "fallback-tkdist-deployment-skew";
|
|
|
2240
2240
|
var FilterStatusFallbackNoBuckets = "fallback-no-buckets";
|
|
2241
2241
|
var FilterStatusFallbackMissingUser = "fallback-missing-userid";
|
|
2242
2242
|
var FilterStatusUnknown = "";
|
|
2243
|
+
var ErrOAuthCORSBlocked = "oauth_cors_blocked";
|
|
2244
|
+
var ErrRefreshProxyFailed = "refresh_proxy_failed";
|
|
2245
|
+
var ErrTokenExpired = "token_expired";
|
|
2243
2246
|
function newDeferred() {
|
|
2244
2247
|
let resolve;
|
|
2245
2248
|
let reject;
|
|
@@ -2257,6 +2260,10 @@ var Client = class _Client {
|
|
|
2257
2260
|
complianceBaseURL;
|
|
2258
2261
|
/** OAuth metadata profile — 刷新 token 时发现 metadata 用 (默认 'desktop') */
|
|
2259
2262
|
oauthMetadataProfile;
|
|
2263
|
+
/** Browser Web OAuth refresh strategy (default 'direct') */
|
|
2264
|
+
browserRefreshMode;
|
|
2265
|
+
/** Same-origin refresh proxy URL for browserRefreshMode='server-proxy' */
|
|
2266
|
+
refreshProxyURL;
|
|
2260
2267
|
/** OAuth metadata (lazy loaded) */
|
|
2261
2268
|
meta = null;
|
|
2262
2269
|
/** 当前 token (内存) */
|
|
@@ -2292,6 +2299,8 @@ var Client = class _Client {
|
|
|
2292
2299
|
this.serverURL = (cfg.serverURL ?? "https://acosmi.com").replace(/\/+$/, "");
|
|
2293
2300
|
this.complianceBaseURL = cfg.complianceBaseURL ? cfg.complianceBaseURL.replace(/\/+$/, "") : null;
|
|
2294
2301
|
this.oauthMetadataProfile = cfg.oauthMetadataProfile ?? "desktop";
|
|
2302
|
+
this.browserRefreshMode = cfg.browserRefreshMode ?? "direct";
|
|
2303
|
+
this.refreshProxyURL = cfg.refreshProxyURL ?? null;
|
|
2295
2304
|
this.store = cfg.store ?? defaultTokenStore();
|
|
2296
2305
|
this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
2297
2306
|
this.retryPolicy = effectivePolicy(cfg.retryPolicy ?? null);
|
|
@@ -2535,27 +2544,7 @@ var Client = class _Client {
|
|
|
2535
2544
|
if (!tokenSetIsExpired(this.tokens)) {
|
|
2536
2545
|
return this.tokens.access_token;
|
|
2537
2546
|
}
|
|
2538
|
-
|
|
2539
|
-
try {
|
|
2540
|
-
this.meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal);
|
|
2541
|
-
} catch (e) {
|
|
2542
|
-
throw new Error(
|
|
2543
|
-
`discover for refresh: ${e instanceof Error ? e.message : String(e)}`
|
|
2544
|
-
);
|
|
2545
|
-
}
|
|
2546
|
-
}
|
|
2547
|
-
let tokenResp;
|
|
2548
|
-
try {
|
|
2549
|
-
tokenResp = await refreshToken(this.meta, this.tokens.client_id, this.tokens.refresh_token, signal);
|
|
2550
|
-
} catch (e) {
|
|
2551
|
-
throw new Error(`refresh token: ${e instanceof Error ? e.message : String(e)}`);
|
|
2552
|
-
}
|
|
2553
|
-
this.tokens = newTokenSet(tokenResp, this.tokens.client_id, this.serverURL);
|
|
2554
|
-
try {
|
|
2555
|
-
await this.store.save(this.tokens);
|
|
2556
|
-
} catch (e) {
|
|
2557
|
-
console.warn(`[acosmi-sdk] warning: save refreshed token failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
2558
|
-
}
|
|
2547
|
+
await this.refreshCurrentToken(signal);
|
|
2559
2548
|
return this.tokens.access_token;
|
|
2560
2549
|
})
|
|
2561
2550
|
);
|
|
@@ -2568,26 +2557,111 @@ var Client = class _Client {
|
|
|
2568
2557
|
if (this.tokens == null) {
|
|
2569
2558
|
throw new Error("no tokens to refresh");
|
|
2570
2559
|
}
|
|
2571
|
-
|
|
2572
|
-
this.meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal);
|
|
2573
|
-
}
|
|
2574
|
-
const tokenResp = await refreshToken(
|
|
2575
|
-
this.meta,
|
|
2576
|
-
this.tokens.client_id,
|
|
2577
|
-
this.tokens.refresh_token,
|
|
2578
|
-
signal
|
|
2579
|
-
);
|
|
2580
|
-
this.tokens = newTokenSet(tokenResp, this.tokens.client_id, this.serverURL);
|
|
2581
|
-
try {
|
|
2582
|
-
await this.store.save(this.tokens);
|
|
2583
|
-
} catch (e) {
|
|
2584
|
-
console.warn(
|
|
2585
|
-
`[acosmi-sdk] warning: save refreshed token failed: ${e instanceof Error ? e.message : String(e)}`
|
|
2586
|
-
);
|
|
2587
|
-
}
|
|
2560
|
+
await this.refreshCurrentToken(signal);
|
|
2588
2561
|
})
|
|
2589
2562
|
);
|
|
2590
2563
|
}
|
|
2564
|
+
async refreshCurrentToken(signal) {
|
|
2565
|
+
if (this.tokens == null) {
|
|
2566
|
+
throw new Error("no tokens to refresh");
|
|
2567
|
+
}
|
|
2568
|
+
if (this.browserRefreshMode === "none") {
|
|
2569
|
+
throw new Error(`${ErrTokenExpired}: token refresh disabled`);
|
|
2570
|
+
}
|
|
2571
|
+
if (this.browserRefreshMode === "server-proxy") {
|
|
2572
|
+
await this.refreshCurrentTokenViaProxy(signal);
|
|
2573
|
+
return;
|
|
2574
|
+
}
|
|
2575
|
+
await this.refreshCurrentTokenDirect(signal);
|
|
2576
|
+
}
|
|
2577
|
+
async refreshCurrentTokenDirect(signal) {
|
|
2578
|
+
if (this.tokens == null) {
|
|
2579
|
+
throw new Error("no tokens to refresh");
|
|
2580
|
+
}
|
|
2581
|
+
if (this.meta == null) {
|
|
2582
|
+
try {
|
|
2583
|
+
this.meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal);
|
|
2584
|
+
} catch (e) {
|
|
2585
|
+
throw new Error(
|
|
2586
|
+
`discover for refresh: ${e instanceof Error ? e.message : String(e)}`
|
|
2587
|
+
);
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
let tokenResp;
|
|
2591
|
+
try {
|
|
2592
|
+
tokenResp = await refreshToken(
|
|
2593
|
+
this.meta,
|
|
2594
|
+
this.tokens.client_id,
|
|
2595
|
+
this.tokens.refresh_token,
|
|
2596
|
+
signal
|
|
2597
|
+
);
|
|
2598
|
+
} catch (e) {
|
|
2599
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
2600
|
+
if (isLikelyBrowserOAuthCORSError(message)) {
|
|
2601
|
+
throw new Error(`${ErrOAuthCORSBlocked}: refresh token: ${message}`);
|
|
2602
|
+
}
|
|
2603
|
+
throw new Error(`refresh token: ${message}`);
|
|
2604
|
+
}
|
|
2605
|
+
this.tokens = newTokenSet(tokenResp, this.tokens.client_id, this.serverURL);
|
|
2606
|
+
await this.saveRefreshedToken();
|
|
2607
|
+
}
|
|
2608
|
+
async refreshCurrentTokenViaProxy(signal) {
|
|
2609
|
+
if (this.tokens == null) {
|
|
2610
|
+
throw new Error("no tokens to refresh");
|
|
2611
|
+
}
|
|
2612
|
+
if (!this.refreshProxyURL) {
|
|
2613
|
+
throw new Error(`${ErrRefreshProxyFailed}: refreshProxyURL is required`);
|
|
2614
|
+
}
|
|
2615
|
+
let resp;
|
|
2616
|
+
try {
|
|
2617
|
+
resp = await this.fetchImpl(this.refreshProxyURL, {
|
|
2618
|
+
method: "POST",
|
|
2619
|
+
headers: { "Content-Type": "application/json" },
|
|
2620
|
+
body: JSON.stringify({
|
|
2621
|
+
client_id: this.tokens.client_id,
|
|
2622
|
+
refresh_token: this.tokens.refresh_token,
|
|
2623
|
+
server_url: this.tokens.server_url || this.serverURL
|
|
2624
|
+
}),
|
|
2625
|
+
signal
|
|
2626
|
+
});
|
|
2627
|
+
} catch (e) {
|
|
2628
|
+
throw new Error(
|
|
2629
|
+
`${ErrRefreshProxyFailed}: ${e instanceof Error ? e.message : String(e)}`
|
|
2630
|
+
);
|
|
2631
|
+
}
|
|
2632
|
+
if (!resp.ok) {
|
|
2633
|
+
let message = "";
|
|
2634
|
+
try {
|
|
2635
|
+
const body2 = await resp.json();
|
|
2636
|
+
if (typeof body2.error === "string") message = body2.error;
|
|
2637
|
+
} catch {
|
|
2638
|
+
}
|
|
2639
|
+
throw new Error(`${ErrRefreshProxyFailed}: HTTP ${resp.status}: ${message}`);
|
|
2640
|
+
}
|
|
2641
|
+
let body;
|
|
2642
|
+
try {
|
|
2643
|
+
body = await resp.json();
|
|
2644
|
+
} catch (e) {
|
|
2645
|
+
throw new Error(
|
|
2646
|
+
`${ErrRefreshProxyFailed}: decode: ${e instanceof Error ? e.message : String(e)}`
|
|
2647
|
+
);
|
|
2648
|
+
}
|
|
2649
|
+
if (!isTokenSetLike(body.tokenSet)) {
|
|
2650
|
+
throw new Error(`${ErrRefreshProxyFailed}: response missing tokenSet`);
|
|
2651
|
+
}
|
|
2652
|
+
this.tokens = body.tokenSet;
|
|
2653
|
+
await this.saveRefreshedToken();
|
|
2654
|
+
}
|
|
2655
|
+
async saveRefreshedToken() {
|
|
2656
|
+
if (this.tokens == null) return;
|
|
2657
|
+
try {
|
|
2658
|
+
await this.store.save(this.tokens);
|
|
2659
|
+
} catch (e) {
|
|
2660
|
+
console.warn(
|
|
2661
|
+
`[acosmi-sdk] warning: save refreshed token failed: ${e instanceof Error ? e.message : String(e)}`
|
|
2662
|
+
);
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2591
2665
|
/** 互斥锁 helper (替代 Go sync.Mutex) */
|
|
2592
2666
|
withMu(fn) {
|
|
2593
2667
|
const next = this.mu.then(fn, fn);
|
|
@@ -3286,6 +3360,15 @@ function defaultTokenStore() {
|
|
|
3286
3360
|
}
|
|
3287
3361
|
return new InMemoryTokenStore();
|
|
3288
3362
|
}
|
|
3363
|
+
function isLikelyBrowserOAuthCORSError(message) {
|
|
3364
|
+
const lower = message.toLowerCase();
|
|
3365
|
+
return lower.includes("failed to fetch") || lower.includes("networkerror") || lower.includes("cors") || lower.includes("http 403");
|
|
3366
|
+
}
|
|
3367
|
+
function isTokenSetLike(value) {
|
|
3368
|
+
if (value == null || typeof value !== "object") return false;
|
|
3369
|
+
const candidate = value;
|
|
3370
|
+
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";
|
|
3371
|
+
}
|
|
3289
3372
|
function zeroModelCapabilities() {
|
|
3290
3373
|
return {
|
|
3291
3374
|
supports_thinking: false,
|
|
@@ -5462,6 +5545,6 @@ Client.prototype.getBugReport = async function(bugID, signal) {
|
|
|
5462
5545
|
return resp.data;
|
|
5463
5546
|
};
|
|
5464
5547
|
|
|
5465
|
-
export { AgentRunStreamError, AgentRunsClient, AnthropicAdapter, BucketClassCommercial, BucketClassGeneric, BusinessError, Client, ComplianceClient, CompliancePollError, LocalStorageTokenStore as DefaultBrowserTokenStore, DefaultRetryPolicy, ErrAuthDenied, ErrBillingCallbackCannotCommit, ErrBillingCommitRequiresLocalVerify, ErrBillingS2sForbidden, ErrBrowserOpen, ErrComplianceStepUpRequired, ErrDiscovery, ErrEnvelopeGateClosed, ErrProviderNotConfigured, ErrProviderUnknownNoRetry, ErrRegistration, ErrSSLProxy, ErrSealApprovalContractHashMismatch, ErrSealApprovalExpired, ErrSealApprovalLocationMismatch, ErrSealApprovalNonceUsed, ErrSealApprovalNotApproved, ErrSealApprovalSealMismatch, ErrSealApprovalTransactorMismatch, ErrSealUseAlreadyConsumed, ErrStateMismatch, ErrTimeout, ErrTokenExchange, EventAuthURL, EventComplete, EventError, FileTokenStore, FilterStatusAdminBypass, FilterStatusDisabledByFlag, FilterStatusFallbackMissingUser, FilterStatusFallbackNoBuckets, FilterStatusFallbackTkdistError, FilterStatusFallbackTkdistSkew, FilterStatusInternalBypass, FilterStatusOK, FilterStatusUnknown, HTTPError, InMemoryTokenStore, LocalStorageTokenStore, ModelNotFoundError, NetworkError, OpenAIAdapter, OrderTerminalError, ProviderFormat, RateLimitError, ScopeAI, ScopeAccount, ScopeComplianceContractSigningRead, ScopeComplianceContractSigningWrite, ScopeComplianceEvidenceRead, ScopeComplianceEvidenceWrite, ScopeComplianceReportsPublish, ScopeComplianceReportsRead, ScopeComplianceReportsWrite, ScopeComplianceSealApprovalApprove, ScopeComplianceSealApprovalRequest, ScopeComplianceSealManage, ScopeComplianceSealUseExecute, ScopeComplianceTimestampIssue, ScopeComplianceTimestampVerify, ScopeEntitlements, ScopeModels, ScopeModelsChat, ScopeProfile, ScopeSkillStore, ScopeSkills, ScopeTokenPackages, ScopeTools, ScopeToolsExecute, ScopeWallet, ScopeWalletReadonly, ServerToolTypeWebSearch, StreamError, ThinkingHigh, ThinkingHighMinMaxTokens, ThinkingMax, ThinkingMaxFallbackMaxTokens, ThinkingOff, allScopes, anthropicResponseTextContent, anthropicResponseThinkingContent, anthropicResponseToolUseBlocks, apiResponseBusinessError, apiResponseGetMessage, authorize, bucketInfoIsCommercial, bucketRowIsCommercial, buildBetas, classifyComplianceError, commerceScopes, completeWebAuthorizationRequest, complianceScopes, computeBackoff, createWebAuthorizationRequest, defaultRetryable, defaultSafeToRetry, discover, discoverWebOAuthMetadata, discoverWithProfile, effectivePolicy, exchangeCode, extractAnthropicBlockMeta, fileLockDefaults, findDesktopVisualUnderstandingModel, findFirstModelByInputModality, generateState, getAdapter, getAdapterForModel, isBillingConfirmable, isComplianceBusinessError, isComplianceTerminalError, isSSLError, modelScopes, modelSupportsImageInput, modelSupportsInputModality, newFileTokenStore, newThinkingConfig, newTokenSet, newWebSearchTool, parseNotificationEvent, parseSettlement, parseSourcesEvent, refreshToken, register, registerWebOAuthClient, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge };
|
|
5548
|
+
export { AgentRunStreamError, AgentRunsClient, AnthropicAdapter, BucketClassCommercial, BucketClassGeneric, BusinessError, Client, ComplianceClient, CompliancePollError, LocalStorageTokenStore as DefaultBrowserTokenStore, DefaultRetryPolicy, ErrAuthDenied, ErrBillingCallbackCannotCommit, ErrBillingCommitRequiresLocalVerify, ErrBillingS2sForbidden, ErrBrowserOpen, ErrComplianceStepUpRequired, ErrDiscovery, ErrEnvelopeGateClosed, ErrOAuthCORSBlocked, ErrProviderNotConfigured, ErrProviderUnknownNoRetry, ErrRefreshProxyFailed, ErrRegistration, ErrSSLProxy, ErrSealApprovalContractHashMismatch, ErrSealApprovalExpired, ErrSealApprovalLocationMismatch, ErrSealApprovalNonceUsed, ErrSealApprovalNotApproved, ErrSealApprovalSealMismatch, ErrSealApprovalTransactorMismatch, ErrSealUseAlreadyConsumed, ErrStateMismatch, ErrTimeout, ErrTokenExchange, ErrTokenExpired, EventAuthURL, EventComplete, EventError, FileTokenStore, FilterStatusAdminBypass, FilterStatusDisabledByFlag, FilterStatusFallbackMissingUser, FilterStatusFallbackNoBuckets, FilterStatusFallbackTkdistError, FilterStatusFallbackTkdistSkew, FilterStatusInternalBypass, FilterStatusOK, FilterStatusUnknown, HTTPError, InMemoryTokenStore, LocalStorageTokenStore, ModelNotFoundError, NetworkError, OpenAIAdapter, OrderTerminalError, ProviderFormat, RateLimitError, ScopeAI, ScopeAccount, ScopeComplianceContractSigningRead, ScopeComplianceContractSigningWrite, ScopeComplianceEvidenceRead, ScopeComplianceEvidenceWrite, ScopeComplianceReportsPublish, ScopeComplianceReportsRead, ScopeComplianceReportsWrite, ScopeComplianceSealApprovalApprove, ScopeComplianceSealApprovalRequest, ScopeComplianceSealManage, ScopeComplianceSealUseExecute, ScopeComplianceTimestampIssue, ScopeComplianceTimestampVerify, ScopeEntitlements, ScopeModels, ScopeModelsChat, ScopeProfile, ScopeSkillStore, ScopeSkills, ScopeTokenPackages, ScopeTools, ScopeToolsExecute, ScopeWallet, ScopeWalletReadonly, ServerToolTypeWebSearch, StreamError, ThinkingHigh, ThinkingHighMinMaxTokens, ThinkingMax, ThinkingMaxFallbackMaxTokens, ThinkingOff, allScopes, anthropicResponseTextContent, anthropicResponseThinkingContent, anthropicResponseToolUseBlocks, apiResponseBusinessError, apiResponseGetMessage, authorize, bucketInfoIsCommercial, bucketRowIsCommercial, buildBetas, classifyComplianceError, commerceScopes, completeWebAuthorizationRequest, complianceScopes, computeBackoff, createWebAuthorizationRequest, defaultRetryable, defaultSafeToRetry, discover, discoverWebOAuthMetadata, discoverWithProfile, effectivePolicy, exchangeCode, extractAnthropicBlockMeta, fileLockDefaults, findDesktopVisualUnderstandingModel, findFirstModelByInputModality, generateState, getAdapter, getAdapterForModel, isBillingConfirmable, isComplianceBusinessError, isComplianceTerminalError, isSSLError, modelScopes, modelSupportsImageInput, modelSupportsInputModality, newFileTokenStore, newThinkingConfig, newTokenSet, newWebSearchTool, parseNotificationEvent, parseSettlement, parseSourcesEvent, refreshToken, register, registerWebOAuthClient, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge };
|
|
5466
5549
|
//# sourceMappingURL=index.mjs.map
|
|
5467
5550
|
//# sourceMappingURL=index.mjs.map
|