@theokit/sdk 4.10.0 → 4.11.0
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 +36 -0
- package/dist/auth/index.cjs +552 -0
- package/dist/auth/index.cjs.map +1 -0
- package/dist/auth/index.d.cts +19 -0
- package/dist/auth/index.d.ts +19 -0
- package/dist/auth/index.js +533 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/{cron-BF_AI5NP.d.ts → cron-C7catiH8.d.ts} +7 -2
- package/dist/{cron-DXEhagMa.d.cts → cron-DK1WVZnI.d.cts} +7 -2
- package/dist/cron.cjs +16 -6
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.d.cts +1 -1
- package/dist/cron.d.ts +1 -1
- package/dist/cron.js +16 -6
- package/dist/cron.js.map +1 -1
- package/dist/eval.cjs +16 -6
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +16 -6
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +16 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +16 -6
- package/dist/index.js.map +1 -1
- package/dist/internal/auth/auth-types.d.ts +93 -0
- package/dist/internal/auth/credential-store.d.ts +19 -0
- package/dist/internal/auth/oauth-device.d.ts +55 -0
- package/dist/internal/auth/oauth-engine.d.ts +21 -0
- package/dist/internal/auth/resolve-credential.d.ts +16 -0
- package/dist/internal/providers/types.d.ts +1 -1
- package/dist/types/provider-profile.d.ts +6 -1
- package/package.json +12 -2
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M42 — shared auth contract types. A LEAF module: pure type declarations, NO runtime imports (no zod, no
|
|
3
|
+
* node:fs). Every auth module (`credential-store`, `oauth-engine`, `oauth-device`, `resolve-credential`)
|
|
4
|
+
* imports its cross-module types from here so the barrel's rollup-plugin-dts bundle sees a single canonical
|
|
5
|
+
* origin — the codebase's established "leaf-type-only deps" pattern (see tsup.config.ts), which sidesteps
|
|
6
|
+
* the rollup-dts cross-module resolution limitation that a value-module type export trips.
|
|
7
|
+
*
|
|
8
|
+
* @internal (re-exported from the package barrel as public)
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The flat bearer surface every consumer holds. `kind:'api'` is the classic API-key path; `kind:'oauth'` is
|
|
12
|
+
* an OAuth session whose `apiKey` is the CURRENT access token, so consumers keep passing a flat bearer
|
|
13
|
+
* string unchanged. `provider` is an open string (any registered provider name).
|
|
14
|
+
*/
|
|
15
|
+
export interface ResolvedCredential {
|
|
16
|
+
kind: "api" | "oauth";
|
|
17
|
+
provider: string;
|
|
18
|
+
/** The effective BEARER the transport sends — an API key, or (oauth) the current access token. */
|
|
19
|
+
apiKey: string;
|
|
20
|
+
/** Where it came from — an env var NAME or a file path. Never the value. */
|
|
21
|
+
source: string;
|
|
22
|
+
/** True when the provider was derived rather than declared. */
|
|
23
|
+
inferred: boolean;
|
|
24
|
+
/** oauth only: epoch ms the access token expires. Drives the refresh in the oauth engine. */
|
|
25
|
+
expiresAt?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface StoredApiCredential {
|
|
28
|
+
type?: "api";
|
|
29
|
+
provider?: string;
|
|
30
|
+
api_key: string;
|
|
31
|
+
}
|
|
32
|
+
export interface StoredOAuthCredential {
|
|
33
|
+
type: "oauth";
|
|
34
|
+
provider: string;
|
|
35
|
+
access: string;
|
|
36
|
+
refresh: string;
|
|
37
|
+
/** Epoch ms the access token expires. */
|
|
38
|
+
expires: number;
|
|
39
|
+
account_id?: string;
|
|
40
|
+
}
|
|
41
|
+
export type StoredCredential = StoredApiCredential | StoredOAuthCredential;
|
|
42
|
+
/** A provider's OAuth endpoints + client identity. Passed in (provider-agnostic, like OpenCode). */
|
|
43
|
+
export interface OAuthProviderConfig {
|
|
44
|
+
provider: string;
|
|
45
|
+
authorizeEndpoint: string;
|
|
46
|
+
tokenEndpoint: string;
|
|
47
|
+
clientId: string;
|
|
48
|
+
scopes: readonly string[];
|
|
49
|
+
redirectUri: string;
|
|
50
|
+
}
|
|
51
|
+
/** The token triple persisted to the store's oauth variant. */
|
|
52
|
+
export interface OAuthTokens {
|
|
53
|
+
access: string;
|
|
54
|
+
refresh: string;
|
|
55
|
+
/** Epoch ms the access token expires. */
|
|
56
|
+
expires: number;
|
|
57
|
+
accountId?: string;
|
|
58
|
+
}
|
|
59
|
+
/** Injected HTTP + clock effects — deterministic in tests, real in production. */
|
|
60
|
+
export interface HttpDeps {
|
|
61
|
+
fetch: typeof fetch;
|
|
62
|
+
now: () => number;
|
|
63
|
+
}
|
|
64
|
+
/** A device-grant config: the OAuth config plus the RFC 8628 device authorization endpoint. */
|
|
65
|
+
export interface DeviceOAuthConfig extends OAuthProviderConfig {
|
|
66
|
+
/** RFC 8628 device authorization endpoint — returns device_code + user_code + verification_uri. */
|
|
67
|
+
deviceCodeEndpoint: string;
|
|
68
|
+
}
|
|
69
|
+
/** The device authorization the user acts on. Times/interval are SECONDS (RFC 8628). */
|
|
70
|
+
export interface DeviceCodeGrant {
|
|
71
|
+
deviceCode: string;
|
|
72
|
+
userCode: string;
|
|
73
|
+
verificationUri: string;
|
|
74
|
+
/** Seconds between token polls (server-mandated minimum). */
|
|
75
|
+
interval: number;
|
|
76
|
+
/** Seconds until the device_code expires. */
|
|
77
|
+
expiresIn: number;
|
|
78
|
+
}
|
|
79
|
+
/** Injected effects for the device flow — deterministic in tests, real in production. */
|
|
80
|
+
export interface DeviceDeps {
|
|
81
|
+
fetch: typeof fetch;
|
|
82
|
+
sleep: (ms: number) => Promise<void>;
|
|
83
|
+
now: () => number;
|
|
84
|
+
}
|
|
85
|
+
/** The OpenAI two-step device config: usercode + poll endpoints return an authorization_code (not tokens). */
|
|
86
|
+
export interface OpenAIDeviceConfig extends OAuthProviderConfig {
|
|
87
|
+
/** POST `{client_id}` here → `{device_auth_id, user_code, interval}`. */
|
|
88
|
+
deviceUsercodeEndpoint: string;
|
|
89
|
+
/** Poll `{device_auth_id, user_code}` here → 200 `{authorization_code, code_verifier}`; 403/404 = pending. */
|
|
90
|
+
devicePollEndpoint: string;
|
|
91
|
+
/** Verification URL the user opens to enter the code. */
|
|
92
|
+
verificationUri: string;
|
|
93
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** The store directory, honoring an optional `homeEnvVar` override. */
|
|
2
|
+
export declare function credentialHome(config: CredentialStoreConfig, env?: Record<string, string | undefined>): string;
|
|
3
|
+
/** The credential file path inside the (possibly overridden) store directory. */
|
|
4
|
+
export declare function authFilePath(config: CredentialStoreConfig, env?: Record<string, string | undefined>): string;
|
|
5
|
+
/** A credential problem the caller can act on. Never carries the key value. */
|
|
6
|
+
export declare class CredentialError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
export declare function readAuthFile(config: CredentialStoreConfig, env?: Record<string, string | undefined>): StoredCredential | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Read the stored OAuth credential (with its refresh token), or `undefined` when the store is absent or
|
|
12
|
+
* holds an api credential. The oauth engine needs the refresh token, which the resolved bearer does not
|
|
13
|
+
* carry. Enforces the same 0600/0700 gates as every other read.
|
|
14
|
+
*/
|
|
15
|
+
export declare function readStoredOAuth(config: CredentialStoreConfig, env?: Record<string, string | undefined>): StoredOAuthCredential | undefined;
|
|
16
|
+
export declare function writeCredential(cred: {
|
|
17
|
+
provider: string;
|
|
18
|
+
apiKey: string;
|
|
19
|
+
} | StoredOAuthCredential, config: CredentialStoreConfig, env?: Record<string, string | undefined>): string;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { DeviceCodeGrant, DeviceDeps, DeviceOAuthConfig, OAuthTokens, OpenAIDeviceConfig } from "./auth-types.js";
|
|
2
|
+
/** Step 1 — request a device code. POSTs `{client_id, scope}` to the device endpoint. */
|
|
3
|
+
export declare function requestDeviceCode(config: DeviceOAuthConfig, deps: Pick<DeviceDeps, "fetch">): Promise<DeviceCodeGrant>;
|
|
4
|
+
/**
|
|
5
|
+
* Step 2 — poll the token endpoint until the user approves (or the code expires). Handles RFC 8628
|
|
6
|
+
* `authorization_pending` (keep waiting) and `slow_down` (back off), with an expiry deadline so it cannot
|
|
7
|
+
* spin forever.
|
|
8
|
+
*/
|
|
9
|
+
export declare function pollDeviceToken(config: DeviceOAuthConfig, grant: DeviceCodeGrant, deps: DeviceDeps): Promise<OAuthTokens>;
|
|
10
|
+
/**
|
|
11
|
+
* The full device login: request a code, hand the user the verification URL + user code via `onPrompt`
|
|
12
|
+
* (never printed here — the caller renders it, keeping this module output-free), then poll to completion.
|
|
13
|
+
*/
|
|
14
|
+
export declare function deviceLogin(config: DeviceOAuthConfig, deps: DeviceDeps, hooks: {
|
|
15
|
+
onPrompt: (p: {
|
|
16
|
+
userCode: string;
|
|
17
|
+
verificationUri: string;
|
|
18
|
+
expiresIn: number;
|
|
19
|
+
}) => void;
|
|
20
|
+
}): Promise<OAuthTokens>;
|
|
21
|
+
/** The OpenAI two-step device config: usercode + poll endpoints return an authorization_code (not tokens). */
|
|
22
|
+
/** Step 1 (OpenAI) — request the user code. */
|
|
23
|
+
export declare function requestOpenAIUsercode(config: OpenAIDeviceConfig, deps: Pick<DeviceDeps, "fetch">): Promise<{
|
|
24
|
+
deviceAuthId: string;
|
|
25
|
+
userCode: string;
|
|
26
|
+
interval: number;
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* Step 2+3 (OpenAI) — poll for the authorization code (200 = ready; 403/404 = pending; else fail), then
|
|
30
|
+
* exchange it for tokens at the standard `/oauth/token` endpoint (reuses `exchangeCode`).
|
|
31
|
+
*/
|
|
32
|
+
export declare function openaiDeviceLogin(config: OpenAIDeviceConfig, deps: DeviceDeps, hooks: {
|
|
33
|
+
onPrompt: (p: {
|
|
34
|
+
userCode: string;
|
|
35
|
+
verificationUri: string;
|
|
36
|
+
}) => void;
|
|
37
|
+
}): Promise<OAuthTokens>;
|
|
38
|
+
/** JWT id/access-token claims we read to attribute an account. Adapted from OpenCode's codex plugin. */
|
|
39
|
+
interface IdTokenClaims {
|
|
40
|
+
chatgpt_account_id?: string;
|
|
41
|
+
organizations?: Array<{
|
|
42
|
+
id: string;
|
|
43
|
+
}>;
|
|
44
|
+
"https://api.openai.com/auth"?: {
|
|
45
|
+
chatgpt_account_id?: string;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** Decode a JWT's claim set (no signature verification — used only to read a self-reported account id). */
|
|
49
|
+
export declare function parseJwtClaims(token: string): IdTokenClaims | undefined;
|
|
50
|
+
/** Best-effort account id from an id/access token's claims (OpenAI/ChatGPT shape). Adapted from OpenCode. */
|
|
51
|
+
export declare function extractAccountId(tokens: {
|
|
52
|
+
id_token?: string;
|
|
53
|
+
access_token?: string;
|
|
54
|
+
}): string | undefined;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CredentialStoreConfig, HttpDeps, OAuthProviderConfig, OAuthTokens, ResolvedCredential } from "./auth-types.js";
|
|
2
|
+
/** Exchange an authorization `code` (+ PKCE verifier) for the token pair. */
|
|
3
|
+
export declare function exchangeCode(config: OAuthProviderConfig, input: {
|
|
4
|
+
code: string;
|
|
5
|
+
verifier: string;
|
|
6
|
+
}, deps: HttpDeps): Promise<OAuthTokens>;
|
|
7
|
+
/** Swap a refresh token for a fresh access (and possibly rotated refresh) token. */
|
|
8
|
+
export declare function refreshOAuthTokens(config: OAuthProviderConfig, refresh: string, deps: HttpDeps): Promise<OAuthTokens>;
|
|
9
|
+
/** Persist a token triple to the store's oauth variant through the hardened 0600 writer. */
|
|
10
|
+
export declare function persistOAuthTokens(provider: string, tokens: OAuthTokens, store: CredentialStoreConfig, env?: Record<string, string | undefined>): string;
|
|
11
|
+
/**
|
|
12
|
+
* Return a credential guaranteed fresh enough to use. An `api` credential passes through untouched. An
|
|
13
|
+
* `oauth` credential still valid (beyond the skew window) passes through; an expired one is refreshed,
|
|
14
|
+
* re-persisted 0600, and returned with the new access token. Concurrent refreshes of the same store are
|
|
15
|
+
* coalesced (single-use refresh tokens); the rejected promise is evicted so a failure is not cached-poison.
|
|
16
|
+
*/
|
|
17
|
+
export declare function ensureFreshCredential(resolved: ResolvedCredential, opts: {
|
|
18
|
+
config: OAuthProviderConfig;
|
|
19
|
+
store: CredentialStoreConfig;
|
|
20
|
+
env?: Record<string, string | undefined>;
|
|
21
|
+
}, deps: HttpDeps): Promise<ResolvedCredential>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ResolveCredentialOptions {
|
|
2
|
+
/** The provider whose stored credential to resolve. */
|
|
3
|
+
provider: string;
|
|
4
|
+
/** Where the credential store lives. */
|
|
5
|
+
store: CredentialStoreConfig;
|
|
6
|
+
/** Env for the store's optional `homeEnvVar` override. Never an ambient read. */
|
|
7
|
+
env?: Record<string, string | undefined>;
|
|
8
|
+
/** Required to refresh an oauth credential; omit for an api-only store. */
|
|
9
|
+
oauth?: OAuthProviderConfig;
|
|
10
|
+
/** Injected HTTP + clock for deterministic tests; default globals. */
|
|
11
|
+
deps?: {
|
|
12
|
+
fetch?: typeof fetch;
|
|
13
|
+
now?: () => number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export declare function resolveCredential(opts: ResolveCredentialOptions): Promise<ResolvedCredential | undefined>;
|
|
@@ -34,7 +34,12 @@ export interface ProviderTransformContext {
|
|
|
34
34
|
* @public
|
|
35
35
|
*/
|
|
36
36
|
export interface ProviderTransform {
|
|
37
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Dynamic per-request headers, merged OVER the profile's static `extraHeaders`, and spread AFTER the
|
|
39
|
+
* transport's base `authorization`/`content-type`. A provider that owns its auth MAY intentionally set
|
|
40
|
+
* `authorization` here to override the resolved bearer — but a stray `authorization`/`content-type` key
|
|
41
|
+
* will silently replace the base header, so return only the headers you mean to add.
|
|
42
|
+
*/
|
|
38
43
|
headers?(ctx: ProviderTransformContext): Record<string, string>;
|
|
39
44
|
/** A fetch to use for this provider's requests (refresh-aware / fully provider-controlled). */
|
|
40
45
|
fetch?(ctx: ProviderTransformContext): typeof fetch;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theokit/sdk",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "TypeScript SDK for the Theo agent harness
|
|
3
|
+
"version": "4.11.0",
|
|
4
|
+
"description": "TypeScript SDK for the Theo agent harness \u2014 same surface, local or cloud.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/usetheodev/theokit-sdk#readme",
|
|
7
7
|
"bugs": "https://github.com/usetheodev/theokit-sdk/issues",
|
|
@@ -218,6 +218,16 @@
|
|
|
218
218
|
"default": "./dist/sanitize/index.cjs"
|
|
219
219
|
}
|
|
220
220
|
},
|
|
221
|
+
"./auth": {
|
|
222
|
+
"import": {
|
|
223
|
+
"types": "./dist/auth/index.d.ts",
|
|
224
|
+
"default": "./dist/auth/index.js"
|
|
225
|
+
},
|
|
226
|
+
"require": {
|
|
227
|
+
"types": "./dist/auth/index.d.cts",
|
|
228
|
+
"default": "./dist/auth/index.cjs"
|
|
229
|
+
}
|
|
230
|
+
},
|
|
221
231
|
"./internal/persistence": {
|
|
222
232
|
"import": {
|
|
223
233
|
"types": "./dist/internal/persistence/index.d.ts",
|