dsh-opendesign-corouter 0.1.3 → 0.1.5
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 +22 -1
- package/lib/adapter.d.ts +1 -1
- package/lib/auth.d.ts +18 -3
- package/lib/browser-open.d.ts +104 -0
- package/lib/client.d.ts +14 -1
- package/lib/client.js +122 -15
- package/lib/device-auth.d.ts +36 -0
- package/lib/generated/typert.host.js +39 -1
- package/lib/generated/typert.remote-client.d.ts +2 -1
- package/lib/generated/typert.remote-client.js +39 -1
- package/lib/index.d.ts +10 -2
- package/lib/index.js +800 -277
- package/lib/index.js.map +4 -4
- package/lib/login.d.ts +31 -133
- package/lib/quota.d.ts +6 -0
- package/lib/remote.d.ts +11 -0
- package/package.json +1 -1
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,90 +25,49 @@ 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;
|
|
34
|
+
/**
|
|
35
|
+
* Called once whenever an approval job leaves `waiting` — success, cancel, expiry or
|
|
36
|
+
* failure — including on a timer with nobody polling. Resource cleanup lives here
|
|
37
|
+
* instead of in a status getter, whose side effect depends on someone reading it.
|
|
38
|
+
*/
|
|
39
|
+
onSettled?: () => void;
|
|
117
40
|
}
|
|
118
41
|
export declare class LoginError extends Error {
|
|
119
42
|
readonly code: 'opendesign/login-state' | 'opendesign/login-disposed' | 'opendesign/login-capture';
|
|
120
43
|
constructor(code: 'opendesign/login-state' | 'opendesign/login-disposed' | 'opendesign/login-capture');
|
|
121
44
|
}
|
|
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
45
|
export declare class ConsoleLogin {
|
|
137
|
-
private job;
|
|
138
|
-
private disposed;
|
|
139
46
|
private readonly callbacks;
|
|
140
47
|
private readonly options;
|
|
48
|
+
private job;
|
|
49
|
+
private disposed;
|
|
141
50
|
private readonly now;
|
|
142
51
|
private readonly delay;
|
|
52
|
+
private readonly fetcher;
|
|
143
53
|
constructor(callbacks: LoginCallbacks, options?: LoginOptions);
|
|
144
|
-
/**
|
|
54
|
+
/** Explicit public allowlist. Codes are never available after waiting or expiry. */
|
|
145
55
|
status(): LoginStatus;
|
|
146
|
-
/**
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
* attempt's status instead of opening a second browser.
|
|
150
|
-
*/
|
|
56
|
+
/** Host-only: the live approval link, so the Host can open it in a bounded window. */
|
|
57
|
+
activationLink(): string | undefined;
|
|
58
|
+
/** Synchronous/non-blocking and idempotent while capture/network/commit is pending. */
|
|
151
59
|
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
60
|
cancel(request: LoginJobRequest): LoginStatus;
|
|
159
|
-
/** Plugin teardown: abort the attempt and close the browser. */
|
|
160
61
|
dispose(): void;
|
|
161
|
-
/** Every cancellation source must let an in-flight atomic store decide the final outcome. */
|
|
162
|
-
private requestCancellation;
|
|
163
62
|
private alive;
|
|
164
63
|
private stopTimer;
|
|
165
|
-
private
|
|
64
|
+
private armExpiry;
|
|
65
|
+
private clearCode;
|
|
66
|
+
private expire;
|
|
67
|
+
private requestCancellation;
|
|
166
68
|
private finish;
|
|
167
|
-
|
|
69
|
+
/** Report one terminal transition per job, exactly once. */
|
|
70
|
+
private settle;
|
|
168
71
|
private run;
|
|
169
|
-
/**
|
|
170
|
-
* Persist the verified session; `commit` resolving is the linearization point. Returns
|
|
171
|
-
* `retry` when the store rejected the write transiently, so the caller decides when to try
|
|
172
|
-
* again instead of claiming a success that did not happen.
|
|
173
|
-
*/
|
|
174
72
|
private commit;
|
|
175
73
|
}
|
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 {
|
|
@@ -66,6 +70,11 @@ export interface SaveApiKeyRequest {
|
|
|
66
70
|
value: string;
|
|
67
71
|
expectedRevision: string;
|
|
68
72
|
}
|
|
73
|
+
/** Outcome of asking the Host to show the approval page in a temporary window. */
|
|
74
|
+
export interface ActivationOpenState {
|
|
75
|
+
code: 'opened' | 'no-link' | 'invalid-url' | 'unavailable' | 'failed';
|
|
76
|
+
opened: boolean;
|
|
77
|
+
}
|
|
69
78
|
/** Rebuild a `QuotaSnapshot` from an allowlist; unknown keys are dropped. */
|
|
70
79
|
export declare function parseQuotaSnapshot(value: unknown): QuotaSnapshot;
|
|
71
80
|
/** Rebuild a `LoginState` from an allowlist; the job's secret material never had a field here. */
|
|
@@ -85,3 +94,5 @@ export declare function parseCancelLoginRequest(value: unknown): CancelLoginRequ
|
|
|
85
94
|
* names a UTF-16 code point instead of the setting to fix.
|
|
86
95
|
*/
|
|
87
96
|
export declare function parseSaveApiKeyRequest(value: unknown): SaveApiKeyRequest;
|
|
97
|
+
/** The opener reports one public code; an unknown value is refused, never guessed. */
|
|
98
|
+
export declare function parseActivationOpenState(value: unknown): ActivationOpenState;
|