dsh-opendesign-corouter 0.1.2 → 0.1.4
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/README.md +6 -6
- package/SECURITY.md +3 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/lib/adapter.d.ts +1 -1
- package/lib/auth.d.ts +18 -3
- package/lib/client.d.ts +12 -4
- package/lib/client.js +224 -117
- package/lib/device-auth.d.ts +34 -0
- package/lib/generated/typert.host.js +77 -57
- package/lib/generated/typert.remote-client.js +77 -57
- package/lib/index.d.ts +5 -1
- package/lib/index.js +628 -389
- package/lib/index.js.map +4 -4
- package/lib/login.d.ts +21 -131
- package/lib/model-settings.d.ts +3 -3
- package/lib/quota.d.ts +6 -0
- package/lib/remote.d.ts +4 -0
- package/package.json +2 -2
package/lib/login.d.ts
CHANGED
|
@@ -1,74 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
/** The API host whose cookies matter; `context.cookies()` uses it to pick the right ones. */
|
|
5
|
-
export declare const API_COOKIE_URL = "https://amr-api.open-design.ai/api/v1/workspaces/current";
|
|
6
|
-
export interface RawCookie {
|
|
7
|
-
name?: string;
|
|
8
|
-
value?: string;
|
|
9
|
-
expires?: number;
|
|
10
|
-
}
|
|
11
|
-
/** One usable console session: the exact `Cookie` header a browser would send. */
|
|
12
|
-
export interface ExtractedCookie {
|
|
13
|
-
cookie: string;
|
|
14
|
-
expiresAt: number;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Pick the session cookies by **URL scope**, never by name. The real cookie is
|
|
18
|
-
* better-auth's `__Secure-better-auth.session_token` today, but it can be renamed at any
|
|
19
|
-
* time and no third party can enumerate the alternatives; joining every unexpired cookie
|
|
20
|
-
* that applies to the API URL reproduces exactly what the browser itself sends. Before
|
|
21
|
-
* login completes this may also collect non-auth cookies (`od_attr`, `__cf_bm`), which is
|
|
22
|
-
* harmless: such a bundle fails `verify` and is therefore never saved.
|
|
23
|
-
*/
|
|
24
|
-
export declare function extractConsoleSession(cookies: readonly RawCookie[], now?: number): ExtractedCookie | null;
|
|
25
|
-
export interface LoginSite {
|
|
26
|
-
origin: string;
|
|
27
|
-
loginUrl: string;
|
|
28
|
-
cookieUrls: readonly string[];
|
|
29
|
-
extract(cookies: readonly RawCookie[], now: number): ExtractedCookie | null;
|
|
30
|
-
}
|
|
31
|
-
/** Site parameters, overridable so a rebrand (for example a new console origin) needs no code fork. */
|
|
32
|
-
export declare function consoleSite(overrides?: {
|
|
33
|
-
origin?: string;
|
|
34
|
-
loginUrl?: string;
|
|
35
|
-
cookieUrls?: readonly string[];
|
|
36
|
-
}): LoginSite;
|
|
37
|
-
export interface VerifyResult {
|
|
38
|
-
/** Whether the account was read at all; a read-but-quota-unknown result still verifies. */
|
|
39
|
-
balanceOk: boolean;
|
|
40
|
-
/** Set when the quota endpoint failed; the cookie itself is still valid, so the host may still save it. */
|
|
41
|
-
usageError?: {
|
|
42
|
-
code: string;
|
|
43
|
-
} | undefined;
|
|
44
|
-
/**
|
|
45
|
-
* Caller-supplied context, echoed nowhere and used only for the success message. The Host
|
|
46
|
-
* re-reads the real quota after commit, so these are never trusted as state.
|
|
47
|
-
*/
|
|
48
|
-
coverage?: string | undefined;
|
|
49
|
-
windows?: readonly unknown[] | undefined;
|
|
50
|
-
}
|
|
51
|
-
/** Host-supplied operations. No Host type is imported: the caller wires these. */
|
|
1
|
+
import { type DeviceTokens } from './device-auth.js';
|
|
2
|
+
export type { DeviceTokens } from './device-auth.js';
|
|
3
|
+
/** Host operations. No quota verification: the authorization server issues the identity. */
|
|
52
4
|
export interface LoginCallbacks {
|
|
53
|
-
/** Snapshot the state a commit must not overwrite, keyed by the revision the caller saw. */
|
|
54
5
|
capture(expectedRevision: string): unknown | Promise<unknown>;
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
* Persist the verified cookie. The Host's store must run its write inside a mutex and call
|
|
59
|
-
* `signal.throwIfAborted()` there, so a cancel that landed before the mutex was acquired
|
|
60
|
-
* wins, and one that lands afterwards does not.
|
|
61
|
-
*
|
|
62
|
-
* `expiresAt` is the cookie bundle's earliest declared expiry in epoch ms, or `0` when the
|
|
63
|
-
* console declared none (a session cookie). It is passed through so the Host can store it and
|
|
64
|
-
* let `resolveSession` expire a stale grant proactively instead of waiting for a 401.
|
|
65
|
-
*/
|
|
66
|
-
commit(cookie: string, captured: unknown, signal: AbortSignal, expiresAt: number): Promise<unknown>;
|
|
6
|
+
/** Re-check signal under the Host's atomic store mutex before accepting the write.
|
|
7
|
+
* Once accepted, resolve: success is the linearization point, even after cancellation. */
|
|
8
|
+
commit(tokens: DeviceTokens, captured: unknown, signal: AbortSignal): Promise<unknown>;
|
|
67
9
|
}
|
|
68
|
-
/**
|
|
69
|
-
* Attempt phases, matching the shared wire contract (`LoginPhase` in `remote.ts`) exactly;
|
|
70
|
-
* `success`/`cancelled`/`error` are terminal. The Host maps `status()` onto the wire type.
|
|
71
|
-
*/
|
|
72
10
|
export type LoginPhase = 'idle' | 'launching' | 'waiting' | 'verifying' | 'success' | 'cancelled' | 'error';
|
|
73
11
|
export interface LoginStatus {
|
|
74
12
|
jobId: string | null;
|
|
@@ -77,8 +15,9 @@ export interface LoginStatus {
|
|
|
77
15
|
finishedAt?: string;
|
|
78
16
|
message?: string;
|
|
79
17
|
errorCode?: string;
|
|
80
|
-
|
|
81
|
-
|
|
18
|
+
activationUrl?: string;
|
|
19
|
+
userCode?: string;
|
|
20
|
+
expiresAt?: string;
|
|
82
21
|
}
|
|
83
22
|
export interface LoginStartRequest {
|
|
84
23
|
expectedRevision: string;
|
|
@@ -86,88 +25,39 @@ export interface LoginStartRequest {
|
|
|
86
25
|
export interface LoginJobRequest {
|
|
87
26
|
jobId: string;
|
|
88
27
|
}
|
|
89
|
-
/** Minimal structural browser surface, so tests need no Playwright and Host wiring stays loose. */
|
|
90
|
-
export interface BrowserLike {
|
|
91
|
-
on?(event: 'disconnected', listener: () => void): void;
|
|
92
|
-
newContext(): Promise<ContextLike>;
|
|
93
|
-
close(): Promise<void>;
|
|
94
|
-
}
|
|
95
|
-
export interface ContextLike {
|
|
96
|
-
newPage(): Promise<PageLike>;
|
|
97
|
-
cookies(urls: readonly string[]): Promise<readonly RawCookie[]>;
|
|
98
|
-
}
|
|
99
|
-
export interface PageLike {
|
|
100
|
-
on?(event: 'close', listener: () => void): void;
|
|
101
|
-
goto(url: string, options?: {
|
|
102
|
-
waitUntil?: string;
|
|
103
|
-
timeout?: number;
|
|
104
|
-
}): Promise<unknown>;
|
|
105
|
-
}
|
|
106
|
-
export type Launcher = (signal: AbortSignal) => Promise<BrowserLike | null>;
|
|
107
28
|
export interface LoginOptions {
|
|
108
|
-
|
|
109
|
-
/** Total life of one login attempt. Default five minutes. */
|
|
110
|
-
timeoutMs?: number;
|
|
111
|
-
pollMs?: number;
|
|
29
|
+
fetcher?: typeof fetch;
|
|
112
30
|
now?: () => number;
|
|
113
|
-
/** Injected browser launcher; the default uses `playwright-core` and a real Chrome window. */
|
|
114
|
-
launch?: Launcher;
|
|
115
|
-
/** Injected sleep, for tests. */
|
|
116
31
|
delay?: (ms: number, signal: AbortSignal) => Promise<void>;
|
|
32
|
+
/** May shorten, but cannot extend, the local five-minute maximum. */
|
|
33
|
+
timeoutMs?: number;
|
|
117
34
|
}
|
|
118
35
|
export declare class LoginError extends Error {
|
|
119
36
|
readonly code: 'opendesign/login-state' | 'opendesign/login-disposed' | 'opendesign/login-capture';
|
|
120
37
|
constructor(code: 'opendesign/login-state' | 'opendesign/login-disposed' | 'opendesign/login-capture');
|
|
121
38
|
}
|
|
122
|
-
/**
|
|
123
|
-
* Chrome flags that let a *human* pass the console's bot check. The console looks at
|
|
124
|
-
* `navigator.webdriver` when its Cloudflare challenge is submitted; `headless: false` alone
|
|
125
|
-
* leaves it `true`, and this blink switch is what the official Playwright browser tool
|
|
126
|
-
* appends for chromium. This is not a challenge bypass — the user still solves it — it only
|
|
127
|
-
* avoids announcing automation before they can act. `ignoreDefaultArgs` is a no-op on
|
|
128
|
-
* 1.63.0 and stays for forward compatibility.
|
|
129
|
-
*/
|
|
130
|
-
export declare const CHROME_LAUNCH_OPTIONS: {
|
|
131
|
-
readonly channel: "chrome";
|
|
132
|
-
readonly headless: false;
|
|
133
|
-
readonly ignoreDefaultArgs: readonly ["--enable-automation"];
|
|
134
|
-
readonly args: readonly ["--disable-blink-features=AutomationControlled"];
|
|
135
|
-
};
|
|
136
39
|
export declare class ConsoleLogin {
|
|
137
|
-
private job;
|
|
138
|
-
private disposed;
|
|
139
40
|
private readonly callbacks;
|
|
140
41
|
private readonly options;
|
|
42
|
+
private job;
|
|
43
|
+
private disposed;
|
|
141
44
|
private readonly now;
|
|
142
45
|
private readonly delay;
|
|
46
|
+
private readonly fetcher;
|
|
143
47
|
constructor(callbacks: LoginCallbacks, options?: LoginOptions);
|
|
144
|
-
/**
|
|
48
|
+
/** Explicit public allowlist. Codes are never available after waiting or expiry. */
|
|
145
49
|
status(): LoginStatus;
|
|
146
|
-
/**
|
|
147
|
-
* Queue one attempt and return immediately: the RPC that starts a login must not wait on a
|
|
148
|
-
* browser window or on a human. Re-entrant calls while an attempt is live return that
|
|
149
|
-
* attempt's status instead of opening a second browser.
|
|
150
|
-
*/
|
|
50
|
+
/** Synchronous/non-blocking and idempotent while capture/network/commit is pending. */
|
|
151
51
|
start(request: LoginStartRequest): LoginStatus;
|
|
152
|
-
/**
|
|
153
|
-
* Abandon the attempt. While `commit` is in flight this only aborts the signal and records
|
|
154
|
-
* the request: the Host's atomic store decides, because the commit is the linearization
|
|
155
|
-
* point. A cancel that wins that race reports `cancelled`; one that loses reports `success`
|
|
156
|
-
* and the cookie really is stored.
|
|
157
|
-
*/
|
|
158
52
|
cancel(request: LoginJobRequest): LoginStatus;
|
|
159
|
-
/** Plugin teardown: abort the attempt and close the browser. */
|
|
160
53
|
dispose(): void;
|
|
161
54
|
private alive;
|
|
162
55
|
private stopTimer;
|
|
163
|
-
private
|
|
56
|
+
private armExpiry;
|
|
57
|
+
private clearCode;
|
|
58
|
+
private expire;
|
|
59
|
+
private requestCancellation;
|
|
164
60
|
private finish;
|
|
165
|
-
private resolveBrowser;
|
|
166
61
|
private run;
|
|
167
|
-
/**
|
|
168
|
-
* Persist the verified session; `commit` resolving is the linearization point. Returns
|
|
169
|
-
* `retry` when the store rejected the write transiently, so the caller decides when to try
|
|
170
|
-
* again instead of claiming a success that did not happen.
|
|
171
|
-
*/
|
|
172
62
|
private commit;
|
|
173
63
|
}
|
package/lib/model-settings.d.ts
CHANGED
|
@@ -30,9 +30,9 @@ export interface ModelSettings {
|
|
|
30
30
|
/** Model id → settings. Keys are model ids, never provider-scoped. */
|
|
31
31
|
export type ModelSettingsMap = Record<string, ModelSettings>;
|
|
32
32
|
/**
|
|
33
|
-
* Validate an untrusted settings payload
|
|
34
|
-
*
|
|
35
|
-
*
|
|
33
|
+
* Validate an untrusted settings payload into a fresh, allowlisted map.
|
|
34
|
+
* This is also a Schemastery transform: all runtime dependencies must live inside
|
|
35
|
+
* the function so JSON serialization and fresh-realm rehydration preserve validation.
|
|
36
36
|
*/
|
|
37
37
|
export declare function parseModelSettingsMap(value: unknown): ModelSettingsMap;
|
|
38
38
|
/**
|
package/lib/quota.d.ts
CHANGED
|
@@ -2,10 +2,12 @@ export declare const API_BASE = "https://amr-api.open-design.ai/api/v1";
|
|
|
2
2
|
export declare const CURRENT_URL = "https://amr-api.open-design.ai/api/v1/workspaces/current";
|
|
3
3
|
export declare const SUMMARY_URL = "https://amr-api.open-design.ai/api/v1/billing/summary";
|
|
4
4
|
export declare const usageUrl: (workspace: string) => string;
|
|
5
|
+
export declare const preflightUrl: (workspace: string) => string;
|
|
5
6
|
export type SessionSource = 'desktop' | 'login' | 'environment';
|
|
6
7
|
export interface Session {
|
|
7
8
|
headers: Record<string, string>;
|
|
8
9
|
source: SessionSource;
|
|
10
|
+
credentialType?: 'device';
|
|
9
11
|
}
|
|
10
12
|
export interface QuotaWindow {
|
|
11
13
|
durationSeconds: number;
|
|
@@ -57,4 +59,8 @@ export declare function normalizeQuota(body: unknown, summary?: unknown): Pick<Q
|
|
|
57
59
|
/** Billing period of the subscription pool; absent fields stay unknown, never derived. */
|
|
58
60
|
export declare function normalizeSubscription(summary: unknown): Pick<QuotaSnapshot, 'subscriptionPeriodStart' | 'subscriptionPeriodEnd'>;
|
|
59
61
|
export declare function normalizeBalances(summary: unknown): QuotaSnapshot['balances'];
|
|
62
|
+
/** Device contract: opencode-opendesign-auth 0.1.4, workspace preflight + personal summary.
|
|
63
|
+
* Unlike desktop reads, this path never invokes vela or borrows desktop account data.
|
|
64
|
+
*/
|
|
65
|
+
export declare function readDeviceQuota(session: Session, signal?: AbortSignal, fetcher?: typeof fetch): Promise<QuotaSnapshot>;
|
|
60
66
|
export declare function readQuota(session: Session, signal?: AbortSignal, fetcher?: typeof fetch): Promise<QuotaSnapshot>;
|
package/lib/remote.d.ts
CHANGED
|
@@ -39,6 +39,10 @@ export interface LoginState {
|
|
|
39
39
|
message?: string;
|
|
40
40
|
startedAt?: string;
|
|
41
41
|
finishedAt?: string;
|
|
42
|
+
/** Public device approval information; available only while waiting. */
|
|
43
|
+
activationUrl?: string;
|
|
44
|
+
userCode?: string;
|
|
45
|
+
expiresAt?: string;
|
|
42
46
|
}
|
|
43
47
|
/** Everything the settings/usage surface may read; no field is derived from a secret. */
|
|
44
48
|
export interface Status {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-opendesign-corouter",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "OpenDesign CoRouter:套餐赠送与付费模型双 Provider、桌面登录态额度及独立登录",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -94,7 +94,6 @@
|
|
|
94
94
|
},
|
|
95
95
|
"dependencies": {
|
|
96
96
|
"@deepseek-ai/schemastery": "~3.18.5",
|
|
97
|
-
"playwright-core": "1.63.0",
|
|
98
97
|
"zod": "4.6.6"
|
|
99
98
|
},
|
|
100
99
|
"overrides": {
|
|
@@ -116,6 +115,7 @@
|
|
|
116
115
|
"@types/react": "^18.3.1",
|
|
117
116
|
"@types/react-dom": "^18.3.0",
|
|
118
117
|
"esbuild": "^0.28.2",
|
|
118
|
+
"playwright-core": "1.63.0",
|
|
119
119
|
"react": "18.3.1",
|
|
120
120
|
"react-dom": "18.3.1",
|
|
121
121
|
"tsx": "^4.23.13",
|