@rakomi/node 0.0.0 → 0.1.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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -1
  3. package/SECURITY.md +206 -0
  4. package/dist/agents.d.ts +90 -0
  5. package/dist/agents.js +203 -0
  6. package/dist/anonymous.d.ts +50 -0
  7. package/dist/anonymous.js +105 -0
  8. package/dist/ciba.d.ts +97 -0
  9. package/dist/ciba.js +282 -0
  10. package/dist/client.d.ts +93 -0
  11. package/dist/client.js +202 -0
  12. package/dist/credentials.d.ts +87 -0
  13. package/dist/credentials.js +104 -0
  14. package/dist/device.d.ts +76 -0
  15. package/dist/device.js +244 -0
  16. package/dist/doctor.d.ts +11 -0
  17. package/dist/doctor.js +135 -0
  18. package/dist/dpop-session.d.ts +90 -0
  19. package/dist/dpop-session.js +127 -0
  20. package/dist/dpop.d.ts +24 -0
  21. package/dist/dpop.js +51 -0
  22. package/dist/env-detect.d.ts +11 -0
  23. package/dist/env-detect.js +26 -0
  24. package/dist/errors.d.ts +307 -0
  25. package/dist/errors.js +385 -0
  26. package/dist/eudi.d.ts +23 -0
  27. package/dist/eudi.js +27 -0
  28. package/dist/flags.d.ts +50 -0
  29. package/dist/flags.js +173 -0
  30. package/dist/guards.d.ts +16 -0
  31. package/dist/guards.js +104 -0
  32. package/dist/index.d.ts +30 -0
  33. package/dist/index.js +18 -0
  34. package/dist/internal/canonical-url.d.ts +13 -0
  35. package/dist/internal/canonical-url.js +52 -0
  36. package/dist/internal/shared-constants.d.ts +3 -0
  37. package/dist/internal/shared-constants.js +3 -0
  38. package/dist/jwks-cache.d.ts +31 -0
  39. package/dist/jwks-cache.js +135 -0
  40. package/dist/link.d.ts +73 -0
  41. package/dist/link.js +262 -0
  42. package/dist/middleware.d.ts +21 -0
  43. package/dist/middleware.js +84 -0
  44. package/dist/oauth.d.ts +46 -0
  45. package/dist/oauth.js +457 -0
  46. package/dist/rbac.d.ts +12 -0
  47. package/dist/rbac.js +20 -0
  48. package/dist/token-exchange.d.ts +65 -0
  49. package/dist/token-exchange.js +163 -0
  50. package/dist/types.d.ts +436 -0
  51. package/dist/types.js +1 -0
  52. package/dist/verify-publisher-webhook.d.ts +25 -0
  53. package/dist/verify-publisher-webhook.js +47 -0
  54. package/dist/verify-token.d.ts +3 -0
  55. package/dist/verify-token.js +148 -0
  56. package/dist/verify-webhook.d.ts +7 -0
  57. package/dist/verify-webhook.js +101 -0
  58. package/package.json +61 -5
  59. package/sbom.cdx.json +52 -0
package/dist/client.js ADDED
@@ -0,0 +1,202 @@
1
+ import { AgentsClient } from './agents.js';
2
+ import { anonymousSignin, } from './anonymous.js';
3
+ import { awaitCibaDecision as awaitCibaDecisionImpl, initiateCiba as initiateCibaImpl, pollCiba as pollCibaImpl, } from './ciba.js';
4
+ import { CredentialsClient } from './credentials.js';
5
+ import { CONFIG_INVALID_BASE_URL, CONFIG_MISSING_API_KEY, CONFIG_MISSING_WEBHOOK_SECRET, OAUTH_MISSING_CLIENT_ID, RakomiError, } from './errors.js';
6
+ import { FlagsClient } from './flags.js';
7
+ import { JwksCache } from './jwks-cache.js';
8
+ import { LinkClient } from './link.js';
9
+ import { createMiddleware } from './middleware.js';
10
+ import { buildAuthorizeUrl as buildAuthorizeUrlImpl, exchangeCode as exchangeCodeImpl, generatePKCE as generatePKCEImpl, generateState as generateStateImpl, refreshToken as refreshTokenImpl, } from './oauth.js';
11
+ import { exchangeTokenOrThrow as exchangeTokenOrThrowImpl, exchangeTokenViaApi as exchangeTokenViaApiImpl, } from './token-exchange.js';
12
+ import { verifyToken } from './verify-token.js';
13
+ import { verifyWebhook as verifyWebhookImpl } from './verify-webhook.js';
14
+ const DEFAULT_BASE_URL = 'https://api.rakomi.com';
15
+ const DEFAULT_CLOCK_TOLERANCE = 30;
16
+ const MAX_CLOCK_TOLERANCE = 120;
17
+ const DEFAULT_WEBHOOK_TOLERANCE = 300;
18
+ const MAX_WEBHOOK_TOLERANCE = 600;
19
+ const API_KEY_PREFIXES = ['ca_live_', 'ca_test_', 'akm_live_', 'akm_test_'];
20
+ export class RakomiClient {
21
+ apiKey;
22
+ baseUrl;
23
+ clockTolerance;
24
+ environment;
25
+ webhookSecret;
26
+ webhookTolerance;
27
+ clientId;
28
+ clientSecret;
29
+ jwksCache = null;
30
+ flags;
31
+ /** Verifiable Credentials issuance (tenant server-to-server). */
32
+ credentials;
33
+ /** c: user-scoped account-linking resource. Requires end-user JWT per call. */
34
+ link;
35
+ /** end-user agent management (`users.me.agents.list/.revoke`). Requires end-user JWT per call. */
36
+ users;
37
+ constructor(config) {
38
+ if (!config.apiKey) {
39
+ throw new RakomiError(CONFIG_MISSING_API_KEY());
40
+ }
41
+ if (!API_KEY_PREFIXES.some((prefix) => config.apiKey.startsWith(prefix))) {
42
+ throw new RakomiError(CONFIG_MISSING_API_KEY());
43
+ }
44
+ this.apiKey = config.apiKey;
45
+ if (config.baseUrl !== undefined) {
46
+ let url;
47
+ try {
48
+ url = new URL(config.baseUrl);
49
+ }
50
+ catch {
51
+ throw new RakomiError(CONFIG_INVALID_BASE_URL());
52
+ }
53
+ const isLocalhost = url.hostname === '127.0.0.1' || url.hostname === 'localhost';
54
+ if (url.protocol !== 'https:' && !isLocalhost) {
55
+ throw new RakomiError(CONFIG_INVALID_BASE_URL());
56
+ }
57
+ let end = config.baseUrl.length;
58
+ while (end > 0 && config.baseUrl.charCodeAt(end - 1) === 47)
59
+ end--;
60
+ this.baseUrl = config.baseUrl.slice(0, end);
61
+ }
62
+ else {
63
+ this.baseUrl = DEFAULT_BASE_URL;
64
+ }
65
+ const tolerance = config.clockTolerance ?? DEFAULT_CLOCK_TOLERANCE;
66
+ this.clockTolerance = Math.min(Math.max(0, tolerance), MAX_CLOCK_TOLERANCE);
67
+ this.environment = config.environment;
68
+ this.webhookSecret = config.webhookSecret;
69
+ const whTolerance = config.webhookTolerance ?? DEFAULT_WEBHOOK_TOLERANCE;
70
+ this.webhookTolerance = Math.min(Math.max(0, whTolerance), MAX_WEBHOOK_TOLERANCE);
71
+ this.clientId = config.clientId;
72
+ this.clientSecret = config.clientSecret;
73
+ this.flags = new FlagsClient(this.baseUrl, this.apiKey);
74
+ this.credentials = new CredentialsClient(this.baseUrl, this.apiKey);
75
+ this.link = new LinkClient({ baseUrl: this.baseUrl });
76
+ this.users = { me: { agents: new AgentsClient({ baseUrl: this.baseUrl }) } };
77
+ }
78
+ async verifyToken(token) {
79
+ if (!this.jwksCache) {
80
+ this.jwksCache = new JwksCache(this.baseUrl);
81
+ }
82
+ const sdkEnv = this.apiKey.startsWith('akm_test_') ? 'test' : 'live';
83
+ return verifyToken(token, this.jwksCache, this.clockTolerance, sdkEnv);
84
+ }
85
+ async verifyWebhook(body, headers, options) {
86
+ if (!this.webhookSecret) {
87
+ return { ok: false, error: CONFIG_MISSING_WEBHOOK_SECRET() };
88
+ }
89
+ const rawTolerance = options?.tolerance ?? this.webhookTolerance;
90
+ const tolerance = Math.min(Math.max(0, rawTolerance), MAX_WEBHOOK_TOLERANCE);
91
+ return verifyWebhookImpl(body, headers, this.webhookSecret, tolerance);
92
+ }
93
+ middleware(options) {
94
+ return createMiddleware((token) => this.verifyToken(token), options, this.environment);
95
+ }
96
+ generatePKCE() {
97
+ return generatePKCEImpl();
98
+ }
99
+ generateState() {
100
+ return generateStateImpl();
101
+ }
102
+ buildAuthorizeUrl(options) {
103
+ const clientId = options.clientId ?? this.clientId;
104
+ if (!clientId) {
105
+ throw new RakomiError(OAUTH_MISSING_CLIENT_ID());
106
+ }
107
+ return buildAuthorizeUrlImpl({
108
+ ...options,
109
+ clientId,
110
+ baseUrl: options.baseUrl ?? this.baseUrl,
111
+ });
112
+ }
113
+ async exchangeCode(options) {
114
+ return exchangeCodeImpl({
115
+ ...options,
116
+ clientId: options.clientId ?? this.clientId,
117
+ clientSecret: options.clientSecret ?? this.clientSecret,
118
+ baseUrl: options.baseUrl ?? this.baseUrl,
119
+ });
120
+ }
121
+ async refreshToken(options) {
122
+ return refreshTokenImpl({
123
+ ...options,
124
+ clientId: options.clientId ?? this.clientId,
125
+ clientSecret: options.clientSecret ?? this.clientSecret,
126
+ baseUrl: options.baseUrl ?? this.baseUrl,
127
+ });
128
+ }
129
+ /**
130
+ * RFC 8693 token-exchange resource.
131
+ *
132
+ * Exchange a user's currently-valid access token for a scoped-down agent
133
+ * token. Returns RFC 8693 §2.2.1 response. Throwing variant for ergonomic
134
+ * try/catch flows (typed errors per RFC 6749 §5.2 codes); the underlying
135
+ * Result-based variant is exposed as `tokens.exchangeViaApi(...)`.
136
+ *
137
+ * The SDK client MUST be constructed with `clientId` + `clientSecret`
138
+ * referencing an agent-type OAuth client (server-side only — never embed
139
+ * `clientSecret` in browser/mobile code). Invocations without those credentials
140
+ * throw `TokenExchangeInvalidClientError` synchronously.
141
+ */
142
+ tokens = {
143
+ exchange: async (options) => {
144
+ if (!this.clientId || !this.clientSecret) {
145
+ throw new RakomiError(OAUTH_MISSING_CLIENT_ID());
146
+ }
147
+ return exchangeTokenOrThrowImpl({ baseUrl: this.baseUrl, clientId: this.clientId, clientSecret: this.clientSecret }, options);
148
+ },
149
+ exchangeViaApi: async (options) => {
150
+ if (!this.clientId || !this.clientSecret) {
151
+ return { ok: false, error: OAUTH_MISSING_CLIENT_ID() };
152
+ }
153
+ return exchangeTokenViaApiImpl({ baseUrl: this.baseUrl, clientId: this.clientId, clientSecret: this.clientSecret }, options);
154
+ },
155
+ };
156
+ /**
157
+ * OIDC CIBA Core 1.0 (asynchronous user consent) resource.
158
+ *
159
+ * Three operations:
160
+ * - `initiate(options)` → POST /oauth/bc-authorize.
161
+ * - `poll(authReqId)` → POST /oauth/token grant=ciba.
162
+ * - `awaitDecision(opts)` → poll-loop until decision / abort.
163
+ *
164
+ * The SDK client MUST be constructed with `clientId` + `clientSecret`
165
+ * referencing a confidential or agent-type OAuth client registered with
166
+ * `grantTypes` including `urn:openid:params:grant-type:ciba` and the
167
+ * Pro+ tier flag. Invocations without those credentials reject the
168
+ * Result with `OAUTH_MISSING_CLIENT_ID`.
169
+ */
170
+ ciba = {
171
+ initiate: async (options) => {
172
+ if (!this.clientId || !this.clientSecret) {
173
+ return { ok: false, error: OAUTH_MISSING_CLIENT_ID() };
174
+ }
175
+ return initiateCibaImpl({ baseUrl: this.baseUrl, clientId: this.clientId, clientSecret: this.clientSecret }, options);
176
+ },
177
+ poll: async (authReqId) => {
178
+ if (!this.clientId || !this.clientSecret) {
179
+ return { ok: false, error: OAUTH_MISSING_CLIENT_ID() };
180
+ }
181
+ return pollCibaImpl({ baseUrl: this.baseUrl, clientId: this.clientId, clientSecret: this.clientSecret }, authReqId);
182
+ },
183
+ awaitDecision: async (options) => {
184
+ if (!this.clientId || !this.clientSecret) {
185
+ throw new RakomiError(OAUTH_MISSING_CLIENT_ID());
186
+ }
187
+ return awaitCibaDecisionImpl({ baseUrl: this.baseUrl, clientId: this.clientId, clientSecret: this.clientSecret }, options);
188
+ },
189
+ };
190
+ /**
191
+ * Create an anonymous user and return its token pair.
192
+ *
193
+ * Call from a trusted backend. Returns a Result (never throws on known API
194
+ * errors); on 403/402/429 the error is mapped to a stable SDK error code.
195
+ */
196
+ async anonymous(options = {}) {
197
+ return anonymousSignin({
198
+ baseUrl: this.baseUrl,
199
+ apiKey: this.apiKey,
200
+ }, options);
201
+ }
202
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Verifiable Credentials Issuer SDK accessors (`@rakomi/node`).
3
+ *
4
+ * Server-to-server methods for tenant backends to issue, list, get, and revoke VCs via
5
+ * the Rakomi issuer (OpenID4VCI).
6
+ *
7
+ * Error contract (closed set): `invalid_claims`, `tenant_disabled`, `rate_limited`, `no_pepper`,
8
+ * `user_not_found`, `schema_violation`, `dpia_not_acknowledged`, `minor_blocked`,
9
+ * `pid_attribute_forbidden`.
10
+ */
11
+ /**
12
+ * VC issuer SDK errors are thrown as `VcSdkError` (extending Error). Code semantics align
13
+ * with the Rakomi API error codes (e.g. `vc/tenant_disabled`, `vc/invalid_claims`).
14
+ */
15
+ export declare class VcSdkError extends Error {
16
+ readonly code: string;
17
+ readonly httpStatus: number;
18
+ constructor(code: string, message: string, httpStatus: number);
19
+ }
20
+ export type VcBuiltinType = 'MembershipCredential' | 'SubscriptionCredential' | 'VerifiedEmailCredential' | 'AgeVerificationCredential' | 'CustomCredential';
21
+ export type VcRevocationReason = 'key_compromise' | 'service_terminated' | 'attribute_change' | 'user_request' | 'other';
22
+ export type VcCredentialStatus = 'active' | 'revoked' | 'expired';
23
+ export interface VcCredentialResponse {
24
+ jti: string;
25
+ vct: string;
26
+ credential_type: VcBuiltinType;
27
+ custom_type_name: string | null;
28
+ user_id: string;
29
+ subject_type: 'user' | 'agent' | 'org';
30
+ issued_at: string;
31
+ valid_from: string | null;
32
+ valid_until: string | null;
33
+ revoked_at: string | null;
34
+ revocation_reason: VcRevocationReason | null;
35
+ status: VcCredentialStatus;
36
+ signing_kid: string;
37
+ holder_jkt: string | null;
38
+ }
39
+ export interface VcOfferResponse {
40
+ jti: string;
41
+ vct: string;
42
+ status: {
43
+ idx: number;
44
+ uri: string;
45
+ };
46
+ credential_offer_uri: string;
47
+ download_url: string;
48
+ expires_at: string;
49
+ }
50
+ export interface VcIssueParams {
51
+ userId: string;
52
+ credentialType: VcBuiltinType;
53
+ customTypeName?: string;
54
+ claims: Record<string, unknown>;
55
+ validFrom?: string;
56
+ validUntil?: string;
57
+ subjectType?: 'user' | 'agent' | 'org';
58
+ }
59
+ export interface VcListParams {
60
+ userId?: string;
61
+ credentialType?: VcBuiltinType;
62
+ limit?: number;
63
+ offset?: number;
64
+ }
65
+ export interface VcRevokeParams {
66
+ reason: VcRevocationReason;
67
+ }
68
+ export declare class CredentialsClient {
69
+ private readonly baseUrl;
70
+ private readonly apiKey;
71
+ constructor(baseUrl: string, apiKey: string);
72
+ issue(params: VcIssueParams): Promise<VcOfferResponse>;
73
+ list(params?: VcListParams): Promise<{
74
+ data: VcCredentialResponse[];
75
+ }>;
76
+ get(jti: string): Promise<VcCredentialResponse>;
77
+ revoke(jti: string, reason?: VcRevocationReason): Promise<{
78
+ jti: string;
79
+ revoked_at: string;
80
+ status: {
81
+ idx: number;
82
+ uri: string;
83
+ list_version: number;
84
+ };
85
+ }>;
86
+ private parse;
87
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Verifiable Credentials Issuer SDK accessors (`@rakomi/node`).
3
+ *
4
+ * Server-to-server methods for tenant backends to issue, list, get, and revoke VCs via
5
+ * the Rakomi issuer (OpenID4VCI).
6
+ *
7
+ * Error contract (closed set): `invalid_claims`, `tenant_disabled`, `rate_limited`, `no_pepper`,
8
+ * `user_not_found`, `schema_violation`, `dpia_not_acknowledged`, `minor_blocked`,
9
+ * `pid_attribute_forbidden`.
10
+ */
11
+ /**
12
+ * VC issuer SDK errors are thrown as `VcSdkError` (extending Error). Code semantics align
13
+ * with the Rakomi API error codes (e.g. `vc/tenant_disabled`, `vc/invalid_claims`).
14
+ */
15
+ export class VcSdkError extends Error {
16
+ code;
17
+ httpStatus;
18
+ constructor(code, message, httpStatus) {
19
+ super(message);
20
+ this.code = code;
21
+ this.httpStatus = httpStatus;
22
+ this.name = 'VcSdkError';
23
+ }
24
+ }
25
+ export class CredentialsClient {
26
+ baseUrl;
27
+ apiKey;
28
+ constructor(baseUrl, apiKey) {
29
+ this.baseUrl = baseUrl;
30
+ this.apiKey = apiKey;
31
+ }
32
+ async issue(params) {
33
+ const res = await fetch(`${this.baseUrl}/v1/credentials/issue`, {
34
+ method: 'POST',
35
+ headers: {
36
+ 'Content-Type': 'application/json',
37
+ 'X-API-Key': this.apiKey,
38
+ },
39
+ redirect: 'error',
40
+ body: JSON.stringify({
41
+ user_id: params.userId,
42
+ credential_type: params.credentialType,
43
+ custom_type_name: params.customTypeName,
44
+ claims: params.claims,
45
+ valid_from: params.validFrom,
46
+ valid_until: params.validUntil,
47
+ subject_type: params.subjectType,
48
+ }),
49
+ });
50
+ return this.parse(res, 'issue');
51
+ }
52
+ async list(params = {}) {
53
+ const url = new URL(`${this.baseUrl}/v1/credentials`);
54
+ if (params.userId)
55
+ url.searchParams.set('user_id', params.userId);
56
+ if (params.credentialType)
57
+ url.searchParams.set('credential_type', params.credentialType);
58
+ if (params.limit !== undefined)
59
+ url.searchParams.set('limit', String(params.limit));
60
+ if (params.offset !== undefined)
61
+ url.searchParams.set('offset', String(params.offset));
62
+ const res = await fetch(url, {
63
+ headers: { 'X-API-Key': this.apiKey },
64
+ redirect: 'error',
65
+ });
66
+ return this.parse(res, 'list');
67
+ }
68
+ async get(jti) {
69
+ const res = await fetch(`${this.baseUrl}/v1/credentials/${encodeURIComponent(jti)}`, {
70
+ headers: { 'X-API-Key': this.apiKey },
71
+ redirect: 'error',
72
+ });
73
+ return this.parse(res, 'get');
74
+ }
75
+ async revoke(jti, reason = 'user_request') {
76
+ const res = await fetch(`${this.baseUrl}/v1/credentials/${encodeURIComponent(jti)}/revoke`, {
77
+ method: 'POST',
78
+ headers: {
79
+ 'Content-Type': 'application/json',
80
+ 'X-API-Key': this.apiKey,
81
+ },
82
+ redirect: 'error',
83
+ body: JSON.stringify({ reason }),
84
+ });
85
+ return this.parse(res, 'revoke');
86
+ }
87
+ async parse(res, op) {
88
+ if (!res.ok) {
89
+ let code = `vc/${op}_failed`;
90
+ let message = `VC ${op} failed with HTTP ${res.status}`;
91
+ try {
92
+ const body = (await res.json());
93
+ if (body.code)
94
+ code = body.code;
95
+ if (body.message)
96
+ message = body.message;
97
+ }
98
+ catch {
99
+ }
100
+ throw new VcSdkError(code, message, res.status);
101
+ }
102
+ return (await res.json());
103
+ }
104
+ }
@@ -0,0 +1,76 @@
1
+ import type { OAuthTokenResponse, VerifyResult } from './types.js';
2
+ export interface StartDeviceAuthorizationOptions {
3
+ clientId: string;
4
+ /** Optional confidential-client secret. Public clients omit. */
5
+ clientSecret?: string;
6
+ /** Space-separated scopes or array. Defaults to client's registered scopes. */
7
+ scope?: string | string[];
8
+ /** OIDC nonce — propagated into id_token at success-poll time. */
9
+ nonce?: string;
10
+ baseUrl?: string;
11
+ }
12
+ export interface DeviceAuthorizationIssued {
13
+ device_code: string;
14
+ user_code: string;
15
+ verification_uri: string;
16
+ verification_uri_complete: string;
17
+ expires_in: number;
18
+ interval: number;
19
+ message?: string;
20
+ }
21
+ export interface PollForDeviceTokenOptions {
22
+ deviceCode: string;
23
+ clientId: string;
24
+ clientSecret?: string;
25
+ baseUrl?: string;
26
+ /** Honored by the underlying fetch — aborting cancels the in-flight request. */
27
+ signal?: AbortSignal;
28
+ }
29
+ export interface AwaitDeviceTokensOptions extends PollForDeviceTokenOptions {
30
+ /** Server-suggested initial interval in seconds. */
31
+ intervalSeconds: number;
32
+ /** Hard client-side timeout in milliseconds (defaults to 30 min). */
33
+ timeoutMs?: number;
34
+ /** AbortSignal for caller-driven cancellation. */
35
+ signal?: AbortSignal;
36
+ }
37
+ export interface RunDeviceFlowOptions {
38
+ clientId: string;
39
+ clientSecret?: string;
40
+ scope?: string | string[];
41
+ nonce?: string;
42
+ baseUrl?: string;
43
+ /** Called once with the issued user_code + verification URLs so the caller can display them. */
44
+ onCode: (issued: DeviceAuthorizationIssued) => void | Promise<void>;
45
+ signal?: AbortSignal;
46
+ /** Override the timeout from issued.expires_in. */
47
+ timeoutMs?: number;
48
+ }
49
+ /**
50
+ * POST /oauth/device/code — initiate a device authorization request.
51
+ */
52
+ export declare function startDeviceAuthorization(options: StartDeviceAuthorizationOptions): Promise<VerifyResult<DeviceAuthorizationIssued>>;
53
+ /**
54
+ * POST /oauth/token — single poll for a device authorization grant.
55
+ *
56
+ * Returns:
57
+ * - ok: true → access_token + refresh_token (+ id_token if openid was requested)
58
+ * - ok: false, error.code === 'device/authorization_pending' → keep polling
59
+ * - ok: false, error.code === 'device/slow_down' → increment interval +5s, keep polling
60
+ * - ok: false, error.code === 'device/access_denied' | 'device/expired_token' → stop
61
+ * - ok: false, OAuth/network error → stop
62
+ */
63
+ export declare function pollForDeviceToken(options: PollForDeviceTokenOptions): Promise<VerifyResult<OAuthTokenResponse>>;
64
+ /**
65
+ * High-level helper: poll the token endpoint at the server-suggested interval
66
+ * until success, terminal error, timeout, or abort. Honors RFC 8628 §3.5
67
+ * `slow_down` by incrementing the interval by 5s before the next poll.
68
+ */
69
+ export declare function awaitDeviceTokens(options: AwaitDeviceTokensOptions): Promise<VerifyResult<OAuthTokenResponse>>;
70
+ /**
71
+ * One-shot device flow: initiate, surface the code via `onCode`, poll until
72
+ * tokens are issued. Returns the same VerifyResult as awaitDeviceTokens.
73
+ *
74
+ * Copy-paste recipe for CLIs and AI agents.
75
+ */
76
+ export declare function run(options: RunDeviceFlowOptions): Promise<VerifyResult<OAuthTokenResponse>>;