diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fc5553b..945fbaf 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.24.0" + ".": "0.25.0" } diff --git a/.stats.yml b/.stats.yml index 99bb6c4..434275e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 89 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-13214b99e392aab631aa1ca99b6a51a58df81e34156d21b8d639bea779566123.yml -openapi_spec_hash: a88d175fc3980de3097ac1411d8dcbff -config_hash: 179f33af31ece83563163d5b3d751d13 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-8d66dbedea5b240936b338809f272568ca84a452fc13dbda835479f2ec068b41.yml +openapi_spec_hash: 7c499bfce2e996f1fff5e7791cea390e +config_hash: fcc2db3ed48ab4e8d1b588d31d394a23 diff --git a/CHANGELOG.md b/CHANGELOG.md index 10efd02..3981d46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 0.25.0 (2026-01-07) + +Full Changelog: [v0.24.0...v0.25.0](https://github.com/onkernel/kernel-node-sdk/compare/v0.24.0...v0.25.0) + +### Features + +* **api:** add health check endpoint for proxies ([999dfe5](https://github.com/onkernel/kernel-node-sdk/commit/999dfe58dbdfae072207e03d83efea58eb914a32)) +* **auth:** add auto_login credential flow ([3f4eb01](https://github.com/onkernel/kernel-node-sdk/commit/3f4eb01bb73f679828e195a74f41214d69c01453)) +* Enhance AuthAgentInvocation with step and last activity tracking ([8380eb6](https://github.com/onkernel/kernel-node-sdk/commit/8380eb6cef2c8229bee4e263bcd0637f9fcb1480)) + + +### Chores + +* break long lines in snippets into multiline ([c546f46](https://github.com/onkernel/kernel-node-sdk/commit/c546f46485ea1e853347db59c4abc5d8c9389b6c)) +* **internal:** codegen related update ([00a9097](https://github.com/onkernel/kernel-node-sdk/commit/00a9097ee42022b917f90fa6dd33938a3f1a9866)) + ## 0.24.0 (2025-12-17) Full Changelog: [v0.23.0...v0.24.0](https://github.com/onkernel/kernel-node-sdk/compare/v0.23.0...v0.24.0) diff --git a/LICENSE b/LICENSE index b32a077..3b7d20d 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Kernel + Copyright 2026 Kernel Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 3007e65..586ba14 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,10 @@ You can use the `for await … of` syntax to iterate through items across all pa async function fetchAllDeploymentListResponses(params) { const allDeploymentListResponses = []; // Automatically fetches more pages as needed. - for await (const deploymentListResponse of client.deployments.list({ app_name: 'YOUR_APP', limit: 2 })) { + for await (const deploymentListResponse of client.deployments.list({ + app_name: 'YOUR_APP', + limit: 2, + })) { allDeploymentListResponses.push(deploymentListResponse); } return allDeploymentListResponses; @@ -203,7 +206,9 @@ const response = await client.browsers.create({ stealth: true }).asResponse(); console.log(response.headers.get('X-My-Header')); console.log(response.statusText); // access the underlying Response object -const { data: browser, response: raw } = await client.browsers.create({ stealth: true }).withResponse(); +const { data: browser, response: raw } = await client.browsers + .create({ stealth: true }) + .withResponse(); console.log(raw.headers.get('X-My-Header')); console.log(browser.session_id); ``` diff --git a/api.md b/api.md index 4086b1a..8d44e74 100644 --- a/api.md +++ b/api.md @@ -201,6 +201,7 @@ Types: - ProxyCreateResponse - ProxyRetrieveResponse - ProxyListResponse +- ProxyCheckResponse Methods: @@ -208,6 +209,7 @@ Methods: - client.proxies.retrieve(id) -> ProxyRetrieveResponse - client.proxies.list() -> ProxyListResponse - client.proxies.delete(id) -> void +- client.proxies.check(id) -> ProxyCheckResponse # Extensions @@ -249,7 +251,6 @@ Methods: Types: -- AgentAuthDiscoverResponse - AgentAuthInvocationResponse - AgentAuthSubmitResponse - AuthAgent @@ -257,7 +258,6 @@ Types: - AuthAgentInvocationCreateRequest - AuthAgentInvocationCreateResponse - DiscoveredField -- ReauthResponse Methods: @@ -265,7 +265,6 @@ Methods: - client.agents.auth.retrieve(id) -> AuthAgent - client.agents.auth.list({ ...params }) -> AuthAgentsOffsetPagination - client.agents.auth.delete(id) -> void -- client.agents.auth.reauth(id) -> ReauthResponse ### Invocations @@ -277,7 +276,6 @@ Methods: - client.agents.auth.invocations.create({ ...params }) -> AuthAgentInvocationCreateResponse - client.agents.auth.invocations.retrieve(invocationID) -> AgentAuthInvocationResponse -- client.agents.auth.invocations.discover(invocationID, { ...params }) -> AgentAuthDiscoverResponse - client.agents.auth.invocations.exchange(invocationID, { ...params }) -> InvocationExchangeResponse - client.agents.auth.invocations.submit(invocationID, { ...params }) -> AgentAuthSubmitResponse @@ -288,11 +286,13 @@ Types: - CreateCredentialRequest - Credential - UpdateCredentialRequest +- CredentialTotpCodeResponse Methods: - client.credentials.create({ ...params }) -> Credential -- client.credentials.retrieve(id) -> Credential -- client.credentials.update(id, { ...params }) -> Credential +- client.credentials.retrieve(idOrName) -> Credential +- client.credentials.update(idOrName, { ...params }) -> Credential - client.credentials.list({ ...params }) -> CredentialsOffsetPagination -- client.credentials.delete(id) -> void +- client.credentials.delete(idOrName) -> void +- client.credentials.totpCode(idOrName) -> CredentialTotpCodeResponse diff --git a/package.json b/package.json index ce072cc..7443df6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@onkernel/sdk", - "version": "0.24.0", + "version": "0.25.0", "description": "The official TypeScript library for the Kernel API", "author": "Kernel <>", "types": "dist/index.d.ts", diff --git a/src/client.ts b/src/client.ts index 1bc8783..52ecc53 100644 --- a/src/client.ts +++ b/src/client.ts @@ -35,6 +35,7 @@ import { Credential, CredentialCreateParams, CredentialListParams, + CredentialTotpCodeResponse, CredentialUpdateParams, Credentials, CredentialsOffsetPagination, @@ -77,6 +78,7 @@ import { import { ProfileCreateParams, ProfileListResponse, Profiles } from './resources/profiles'; import { Proxies, + ProxyCheckResponse, ProxyCreateParams, ProxyCreateResponse, ProxyListResponse, @@ -950,6 +952,7 @@ export declare namespace Kernel { type ProxyCreateResponse as ProxyCreateResponse, type ProxyRetrieveResponse as ProxyRetrieveResponse, type ProxyListResponse as ProxyListResponse, + type ProxyCheckResponse as ProxyCheckResponse, type ProxyCreateParams as ProxyCreateParams, }; @@ -980,6 +983,7 @@ export declare namespace Kernel { type CreateCredentialRequest as CreateCredentialRequest, type Credential as Credential, type UpdateCredentialRequest as UpdateCredentialRequest, + type CredentialTotpCodeResponse as CredentialTotpCodeResponse, type CredentialsOffsetPagination as CredentialsOffsetPagination, type CredentialCreateParams as CredentialCreateParams, type CredentialUpdateParams as CredentialUpdateParams, diff --git a/src/resources/agents/agents.ts b/src/resources/agents/agents.ts index cb21314..dd0955e 100644 --- a/src/resources/agents/agents.ts +++ b/src/resources/agents/agents.ts @@ -3,7 +3,6 @@ import { APIResource } from '../../core/resource'; import * as AuthAPI from './auth/auth'; import { - AgentAuthDiscoverResponse, AgentAuthInvocationResponse, AgentAuthSubmitResponse, Auth, @@ -15,7 +14,6 @@ import { AuthCreateParams, AuthListParams, DiscoveredField, - ReauthResponse, } from './auth/auth'; export class Agents extends APIResource { @@ -27,7 +25,6 @@ Agents.Auth = Auth; export declare namespace Agents { export { Auth as Auth, - type AgentAuthDiscoverResponse as AgentAuthDiscoverResponse, type AgentAuthInvocationResponse as AgentAuthInvocationResponse, type AgentAuthSubmitResponse as AgentAuthSubmitResponse, type AuthAgent as AuthAgent, @@ -35,7 +32,6 @@ export declare namespace Agents { type AuthAgentInvocationCreateRequest as AuthAgentInvocationCreateRequest, type AuthAgentInvocationCreateResponse as AuthAgentInvocationCreateResponse, type DiscoveredField as DiscoveredField, - type ReauthResponse as ReauthResponse, type AuthAgentsOffsetPagination as AuthAgentsOffsetPagination, type AuthCreateParams as AuthCreateParams, type AuthListParams as AuthListParams, diff --git a/src/resources/agents/auth/auth.ts b/src/resources/agents/auth/auth.ts index 636daba..6e9372e 100644 --- a/src/resources/agents/auth/auth.ts +++ b/src/resources/agents/auth/auth.ts @@ -4,7 +4,6 @@ import { APIResource } from '../../../core/resource'; import * as InvocationsAPI from './invocations'; import { InvocationCreateParams, - InvocationDiscoverParams, InvocationExchangeParams, InvocationExchangeResponse, InvocationSubmitParams, @@ -28,8 +27,8 @@ export class Auth extends APIResource { * @example * ```ts * const authAgent = await client.agents.auth.create({ + * domain: 'netflix.com', * profile_name: 'user-123', - * target_domain: 'netflix.com', * }); * ``` */ @@ -51,7 +50,7 @@ export class Auth extends APIResource { } /** - * List auth agents with optional filters for profile_name and target_domain. + * List auth agents with optional filters for profile_name and domain. * * @example * ```ts @@ -86,126 +85,117 @@ export class Auth extends APIResource { headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), }); } - - /** - * Triggers automatic re-authentication for an auth agent using stored credentials. - * Requires the auth agent to have a linked credential, stored selectors, and - * login_url. Returns immediately with status indicating whether re-auth was - * started. - * - * @example - * ```ts - * const reauthResponse = await client.agents.auth.reauth( - * 'id', - * ); - * ``` - */ - reauth(id: string, options?: RequestOptions): APIPromise { - return this._client.post(path`/agents/auth/${id}/reauth`, options); - } } export type AuthAgentsOffsetPagination = OffsetPagination; /** - * Response from discover endpoint matching AuthBlueprint schema + * Response from get invocation endpoint */ -export interface AgentAuthDiscoverResponse { - /** - * Whether discovery succeeded - */ - success: boolean; - +export interface AgentAuthInvocationResponse { /** - * Error message if discovery failed + * App name (org name at time of invocation creation) */ - error_message?: string; + app_name: string; /** - * Discovered form fields (present when success is true) + * Domain for authentication */ - fields?: Array; + domain: string; /** - * Whether user is already logged in + * When the handoff code expires */ - logged_in?: boolean; + expires_at: string; /** - * URL of the discovered login page + * Invocation status */ - login_url?: string; + status: 'IN_PROGRESS' | 'SUCCESS' | 'EXPIRED' | 'CANCELED' | 'FAILED'; /** - * Title of the login page + * Current step in the invocation workflow */ - page_title?: string; -} + step: + | 'initialized' + | 'discovering' + | 'awaiting_input' + | 'awaiting_external_action' + | 'submitting' + | 'completed' + | 'expired'; -/** - * Response from get invocation endpoint - */ -export interface AgentAuthInvocationResponse { /** - * App name (org name at time of invocation creation) + * The invocation type: + * + * - login: First-time authentication + * - reauth: Re-authentication for previously authenticated agents + * - auto_login: Legacy type (no longer created, kept for backward compatibility) */ - app_name: string; + type: 'login' | 'auto_login' | 'reauth'; /** - * When the handoff code expires + * Error message explaining why the invocation failed (present when status=FAILED) */ - expires_at: string; + error_message?: string | null; /** - * Invocation status + * Instructions for user when external action is required (present when + * step=awaiting_external_action) */ - status: 'IN_PROGRESS' | 'SUCCESS' | 'EXPIRED' | 'CANCELED'; + external_action_message?: string | null; /** - * Target domain for authentication + * Browser live view URL for debugging the invocation */ - target_domain: string; -} + live_view_url?: string | null; -/** - * Response from submit endpoint matching SubmitResult schema - */ -export interface AgentAuthSubmitResponse { /** - * Whether submission succeeded + * Fields currently awaiting input (present when step=awaiting_input) */ - success: boolean; + pending_fields?: Array | null; /** - * Additional fields needed (e.g., OTP) - present when needs_additional_auth is - * true + * SSO buttons available on the page (present when step=awaiting_input) */ - additional_fields?: Array; + pending_sso_buttons?: Array | null; /** - * App name (only present when logged_in is true) + * Names of fields that have been submitted (present when step=submitting or later) */ - app_name?: string; + submitted_fields?: Array | null; +} +export namespace AgentAuthInvocationResponse { /** - * Error message if submission failed + * An SSO button for signing in with an external identity provider */ - error_message?: string; + export interface PendingSSOButton { + /** + * Visible button text + */ + label: string; - /** - * Whether user is now logged in - */ - logged_in?: boolean; + /** + * Identity provider name + */ + provider: string; - /** - * Whether additional authentication fields are needed - */ - needs_additional_auth?: boolean; + /** + * XPath selector for the button + */ + selector: string; + } +} +/** + * Response from submit endpoint - returns immediately after submission is accepted + */ +export interface AgentAuthSubmitResponse { /** - * Target domain (only present when logged_in is true) + * Whether the submission was accepted for processing */ - target_domain?: string; + accepted: boolean; } /** @@ -233,6 +223,13 @@ export interface AuthAgent { */ status: 'AUTHENTICATED' | 'NEEDS_AUTH'; + /** + * Additional domains that are valid for this auth agent's authentication flow + * (besides the primary domain). Useful when login pages redirect to different + * domains. + */ + allowed_domains?: Array; + /** * Whether automatic re-authentication is possible (has credential_id, selectors, * and login_url) @@ -264,15 +261,22 @@ export interface AuthAgent { * Request to create or find an auth agent */ export interface AuthAgentCreateRequest { + /** + * Domain for authentication + */ + domain: string; + /** * Name of the profile to use for this auth agent */ profile_name: string; /** - * Target domain for authentication + * Additional domains that are valid for this auth agent's authentication flow + * (besides the primary domain). Useful when login pages redirect to different + * domains. */ - target_domain: string; + allowed_domains?: Array; /** * Optional name of an existing credential to use for this auth agent. If provided, @@ -323,52 +327,37 @@ export interface AuthAgentInvocationCreateRequest { } /** - * Response when the agent is already authenticated. + * Response from creating an invocation. Always returns an invocation_id. */ -export type AuthAgentInvocationCreateResponse = - | AuthAgentInvocationCreateResponse.AuthAgentAlreadyAuthenticated - | AuthAgentInvocationCreateResponse.AuthAgentInvocationCreated; - -export namespace AuthAgentInvocationCreateResponse { +export interface AuthAgentInvocationCreateResponse { /** - * Response when the agent is already authenticated. + * When the handoff code expires. */ - export interface AuthAgentAlreadyAuthenticated { - /** - * Indicates the agent is already authenticated and no invocation was created. - */ - status: 'already_authenticated'; - } + expires_at: string; /** - * Response when a new invocation was created. + * One-time code for handoff. */ - export interface AuthAgentInvocationCreated { - /** - * When the handoff code expires. - */ - expires_at: string; - - /** - * One-time code for handoff. - */ - handoff_code: string; + handoff_code: string; - /** - * URL to redirect user to. - */ - hosted_url: string; + /** + * URL to redirect user to. + */ + hosted_url: string; - /** - * Unique identifier for the invocation. - */ - invocation_id: string; + /** + * Unique identifier for the invocation. + */ + invocation_id: string; - /** - * Indicates an invocation was created. - */ - status: 'invocation_created'; - } + /** + * The invocation type: + * + * - login: First-time authentication + * - reauth: Re-authentication for previously authenticated agents + * - auto_login: Legacy type (no longer created, kept for backward compatibility) + */ + type: 'login' | 'auto_login' | 'reauth'; } /** @@ -393,7 +382,7 @@ export interface DiscoveredField { /** * Field type */ - type: 'text' | 'email' | 'password' | 'tel' | 'number' | 'url' | 'code'; + type: 'text' | 'email' | 'password' | 'tel' | 'number' | 'url' | 'code' | 'totp'; /** * Field placeholder @@ -406,36 +395,23 @@ export interface DiscoveredField { required?: boolean; } -/** - * Response from triggering re-authentication - */ -export interface ReauthResponse { - /** - * Result of the re-authentication attempt - */ - status: 'reauth_started' | 'already_authenticated' | 'cannot_reauth'; - - /** - * ID of the re-auth invocation if one was created - */ - invocation_id?: string; - +export interface AuthCreateParams { /** - * Human-readable description of the result + * Domain for authentication */ - message?: string; -} + domain: string; -export interface AuthCreateParams { /** * Name of the profile to use for this auth agent */ profile_name: string; /** - * Target domain for authentication + * Additional domains that are valid for this auth agent's authentication flow + * (besides the primary domain). Useful when login pages redirect to different + * domains. */ - target_domain: string; + allowed_domains?: Array; /** * Optional name of an existing credential to use for this auth agent. If provided, @@ -470,21 +446,20 @@ export namespace AuthCreateParams { export interface AuthListParams extends OffsetPaginationParams { /** - * Filter by profile name + * Filter by domain */ - profile_name?: string; + domain?: string; /** - * Filter by target domain + * Filter by profile name */ - target_domain?: string; + profile_name?: string; } Auth.Invocations = Invocations; export declare namespace Auth { export { - type AgentAuthDiscoverResponse as AgentAuthDiscoverResponse, type AgentAuthInvocationResponse as AgentAuthInvocationResponse, type AgentAuthSubmitResponse as AgentAuthSubmitResponse, type AuthAgent as AuthAgent, @@ -492,7 +467,6 @@ export declare namespace Auth { type AuthAgentInvocationCreateRequest as AuthAgentInvocationCreateRequest, type AuthAgentInvocationCreateResponse as AuthAgentInvocationCreateResponse, type DiscoveredField as DiscoveredField, - type ReauthResponse as ReauthResponse, type AuthAgentsOffsetPagination as AuthAgentsOffsetPagination, type AuthCreateParams as AuthCreateParams, type AuthListParams as AuthListParams, @@ -502,7 +476,6 @@ export declare namespace Auth { Invocations as Invocations, type InvocationExchangeResponse as InvocationExchangeResponse, type InvocationCreateParams as InvocationCreateParams, - type InvocationDiscoverParams as InvocationDiscoverParams, type InvocationExchangeParams as InvocationExchangeParams, type InvocationSubmitParams as InvocationSubmitParams, }; diff --git a/src/resources/agents/auth/index.ts b/src/resources/agents/auth/index.ts index bf85b04..490ad25 100644 --- a/src/resources/agents/auth/index.ts +++ b/src/resources/agents/auth/index.ts @@ -2,7 +2,6 @@ export { Auth, - type AgentAuthDiscoverResponse, type AgentAuthInvocationResponse, type AgentAuthSubmitResponse, type AuthAgent, @@ -10,7 +9,6 @@ export { type AuthAgentInvocationCreateRequest, type AuthAgentInvocationCreateResponse, type DiscoveredField, - type ReauthResponse, type AuthCreateParams, type AuthListParams, type AuthAgentsOffsetPagination, @@ -19,7 +17,6 @@ export { Invocations, type InvocationExchangeResponse, type InvocationCreateParams, - type InvocationDiscoverParams, type InvocationExchangeParams, type InvocationSubmitParams, } from './invocations'; diff --git a/src/resources/agents/auth/invocations.ts b/src/resources/agents/auth/invocations.ts index 84e9cf7..94cefbd 100644 --- a/src/resources/agents/auth/invocations.ts +++ b/src/resources/agents/auth/invocations.ts @@ -28,8 +28,8 @@ export class Invocations extends APIResource { } /** - * Returns invocation details including app_name and target_domain. Uses the JWT - * returned by the exchange endpoint, or standard API key or JWT authentication. + * Returns invocation details including status, app_name, and domain. Supports both + * API key and JWT (from exchange endpoint) authentication. * * @example * ```ts @@ -43,27 +43,6 @@ export class Invocations extends APIResource { return this._client.get(path`/agents/auth/invocations/${invocationID}`, options); } - /** - * Inspects the target site to detect logged-in state or discover required fields. - * Returns 200 with success: true when fields are found, or 4xx/5xx for failures. - * Requires the JWT returned by the exchange endpoint. - * - * @example - * ```ts - * const agentAuthDiscoverResponse = - * await client.agents.auth.invocations.discover( - * 'invocation_id', - * ); - * ``` - */ - discover( - invocationID: string, - body: InvocationDiscoverParams | null | undefined = {}, - options?: RequestOptions, - ): APIPromise { - return this._client.post(path`/agents/auth/invocations/${invocationID}/discover`, { body, ...options }); - } - /** * Validates the handoff code and returns a JWT token for subsequent requests. No * authentication required (the handoff code serves as the credential). @@ -86,8 +65,9 @@ export class Invocations extends APIResource { } /** - * Submits field values for the discovered login form and may return additional - * auth fields or success. Requires the JWT returned by the exchange endpoint. + * Submits field values for the discovered login form. Returns immediately after + * submission is accepted. Poll the invocation endpoint to track progress and get + * results. * * @example * ```ts @@ -141,14 +121,6 @@ export interface InvocationCreateParams { save_credential_as?: string; } -export interface InvocationDiscoverParams { - /** - * Optional login page URL. If provided, will override the stored login URL for - * this discovery invocation and skip Phase 1 discovery. - */ - login_url?: string; -} - export interface InvocationExchangeParams { /** * Handoff code from start endpoint @@ -156,18 +128,28 @@ export interface InvocationExchangeParams { code: string; } -export interface InvocationSubmitParams { - /** - * Values for the discovered login fields - */ - field_values: { [key: string]: string }; +export type InvocationSubmitParams = InvocationSubmitParams.Variant0 | InvocationSubmitParams.Variant1; + +export declare namespace InvocationSubmitParams { + export interface Variant0 { + /** + * Values for the discovered login fields + */ + field_values: { [key: string]: string }; + } + + export interface Variant1 { + /** + * Selector of SSO button to click + */ + sso_button: string; + } } export declare namespace Invocations { export { type InvocationExchangeResponse as InvocationExchangeResponse, type InvocationCreateParams as InvocationCreateParams, - type InvocationDiscoverParams as InvocationDiscoverParams, type InvocationExchangeParams as InvocationExchangeParams, type InvocationSubmitParams as InvocationSubmitParams, }; diff --git a/src/resources/agents/index.ts b/src/resources/agents/index.ts index fbd9005..65bd5a4 100644 --- a/src/resources/agents/index.ts +++ b/src/resources/agents/index.ts @@ -3,7 +3,6 @@ export { Agents } from './agents'; export { Auth, - type AgentAuthDiscoverResponse, type AgentAuthInvocationResponse, type AgentAuthSubmitResponse, type AuthAgent, @@ -11,7 +10,6 @@ export { type AuthAgentInvocationCreateRequest, type AuthAgentInvocationCreateResponse, type DiscoveredField, - type ReauthResponse, type AuthCreateParams, type AuthListParams, type AuthAgentsOffsetPagination, diff --git a/src/resources/credentials.ts b/src/resources/credentials.ts index a90dea7..2f384a7 100644 --- a/src/resources/credentials.ts +++ b/src/resources/credentials.ts @@ -9,8 +9,7 @@ import { path } from '../internal/utils/path'; export class Credentials extends APIResource { /** - * Create a new credential for storing login information. Values are encrypted at - * rest. + * Create a new credential for storing login information. * * @example * ```ts @@ -29,27 +28,32 @@ export class Credentials extends APIResource { } /** - * Retrieve a credential by its ID. Credential values are not returned. + * Retrieve a credential by its ID or name. Credential values are not returned. * * @example * ```ts - * const credential = await client.credentials.retrieve('id'); + * const credential = await client.credentials.retrieve( + * 'id_or_name', + * ); * ``` */ - retrieve(id: string, options?: RequestOptions): APIPromise { - return this._client.get(path`/credentials/${id}`, options); + retrieve(idOrName: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/credentials/${idOrName}`, options); } /** - * Update a credential's name or values. Values are encrypted at rest. + * Update a credential's name or values. When values are provided, they are merged + * with existing values (new keys are added, existing keys are overwritten). * * @example * ```ts - * const credential = await client.credentials.update('id'); + * const credential = await client.credentials.update( + * 'id_or_name', + * ); * ``` */ - update(id: string, body: CredentialUpdateParams, options?: RequestOptions): APIPromise { - return this._client.patch(path`/credentials/${id}`, { body, ...options }); + update(idOrName: string, body: CredentialUpdateParams, options?: RequestOptions): APIPromise { + return this._client.patch(path`/credentials/${idOrName}`, { body, ...options }); } /** @@ -72,19 +76,35 @@ export class Credentials extends APIResource { } /** - * Delete a credential by its ID. + * Delete a credential by its ID or name. * * @example * ```ts - * await client.credentials.delete('id'); + * await client.credentials.delete('id_or_name'); * ``` */ - delete(id: string, options?: RequestOptions): APIPromise { - return this._client.delete(path`/credentials/${id}`, { + delete(idOrName: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/credentials/${idOrName}`, { ...options, headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), }); } + + /** + * Returns the current 6-digit TOTP code for a credential with a configured + * totp_secret. Use this to complete 2FA setup on sites or when you need a fresh + * code. + * + * @example + * ```ts + * const response = await client.credentials.totpCode( + * 'id_or_name', + * ); + * ``` + */ + totpCode(idOrName: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/credentials/${idOrName}/totp-code`, options); + } } export type CredentialsOffsetPagination = OffsetPagination; @@ -107,6 +127,20 @@ export interface CreateCredentialRequest { * Field name to value mapping (e.g., username, password) */ values: { [key: string]: string }; + + /** + * If set, indicates this credential should be used with the specified SSO provider + * (e.g., google, github, microsoft). When the target site has a matching SSO + * button, it will be clicked first before filling credential values on the + * identity provider's login page. + */ + sso_provider?: string; + + /** + * Base32-encoded TOTP secret for generating one-time passwords. Used for automatic + * 2FA during login. + */ + totp_secret?: string; } /** @@ -137,6 +171,30 @@ export interface Credential { * When the credential was last updated */ updated_at: string; + + /** + * Whether this credential has a TOTP secret configured for automatic 2FA + */ + has_totp_secret?: boolean; + + /** + * If set, indicates this credential should be used with the specified SSO provider + * (e.g., google, github, microsoft). When the target site has a matching SSO + * button, it will be clicked first before filling credential values on the + * identity provider's login page. + */ + sso_provider?: string | null; + + /** + * Current 6-digit TOTP code. Only included in create/update responses when + * totp_secret was just set. + */ + totp_code?: string; + + /** + * When the totp_code expires. Only included when totp_code is present. + */ + totp_code_expires_at?: string; } /** @@ -149,12 +207,36 @@ export interface UpdateCredentialRequest { name?: string; /** - * Field name to value mapping (e.g., username, password). Replaces all existing - * values. + * If set, indicates this credential should be used with the specified SSO + * provider. Set to empty string or null to remove. + */ + sso_provider?: string | null; + + /** + * Base32-encoded TOTP secret for generating one-time passwords. Spaces and + * formatting are automatically normalized. Set to empty string to remove. + */ + totp_secret?: string; + + /** + * Field name to value mapping. Values are merged with existing values (new keys + * added, existing keys overwritten). */ values?: { [key: string]: string }; } +export interface CredentialTotpCodeResponse { + /** + * Current 6-digit TOTP code + */ + code: string; + + /** + * When this code expires (ISO 8601 timestamp) + */ + expires_at: string; +} + export interface CredentialCreateParams { /** * Target domain this credential is for @@ -170,6 +252,20 @@ export interface CredentialCreateParams { * Field name to value mapping (e.g., username, password) */ values: { [key: string]: string }; + + /** + * If set, indicates this credential should be used with the specified SSO provider + * (e.g., google, github, microsoft). When the target site has a matching SSO + * button, it will be clicked first before filling credential values on the + * identity provider's login page. + */ + sso_provider?: string; + + /** + * Base32-encoded TOTP secret for generating one-time passwords. Used for automatic + * 2FA during login. + */ + totp_secret?: string; } export interface CredentialUpdateParams { @@ -179,8 +275,20 @@ export interface CredentialUpdateParams { name?: string; /** - * Field name to value mapping (e.g., username, password). Replaces all existing - * values. + * If set, indicates this credential should be used with the specified SSO + * provider. Set to empty string or null to remove. + */ + sso_provider?: string | null; + + /** + * Base32-encoded TOTP secret for generating one-time passwords. Spaces and + * formatting are automatically normalized. Set to empty string to remove. + */ + totp_secret?: string; + + /** + * Field name to value mapping. Values are merged with existing values (new keys + * added, existing keys overwritten). */ values?: { [key: string]: string }; } @@ -197,6 +305,7 @@ export declare namespace Credentials { type CreateCredentialRequest as CreateCredentialRequest, type Credential as Credential, type UpdateCredentialRequest as UpdateCredentialRequest, + type CredentialTotpCodeResponse as CredentialTotpCodeResponse, type CredentialsOffsetPagination as CredentialsOffsetPagination, type CredentialCreateParams as CredentialCreateParams, type CredentialUpdateParams as CredentialUpdateParams, diff --git a/src/resources/index.ts b/src/resources/index.ts index c7a0aa1..f487726 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -37,6 +37,7 @@ export { type CreateCredentialRequest, type Credential, type UpdateCredentialRequest, + type CredentialTotpCodeResponse, type CredentialCreateParams, type CredentialUpdateParams, type CredentialListParams, @@ -81,5 +82,6 @@ export { type ProxyCreateResponse, type ProxyRetrieveResponse, type ProxyListResponse, + type ProxyCheckResponse, type ProxyCreateParams, } from './proxies'; diff --git a/src/resources/proxies.ts b/src/resources/proxies.ts index 7c409f5..a8040b1 100644 --- a/src/resources/proxies.ts +++ b/src/resources/proxies.ts @@ -37,6 +37,13 @@ export class Proxies extends APIResource { headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), }); } + + /** + * Run a health check on the proxy to verify it's working. + */ + check(id: string, options?: RequestOptions): APIPromise { + return this._client.post(path`/proxies/${id}/check`, options); + } } /** @@ -703,6 +710,226 @@ export namespace ProxyListResponse { } } +/** + * Configuration for routing traffic through a proxy. + */ +export interface ProxyCheckResponse { + /** + * Proxy type to use. In terms of quality for avoiding bot-detection, from best to + * worst: `mobile` > `residential` > `isp` > `datacenter`. + */ + type: 'datacenter' | 'isp' | 'residential' | 'mobile' | 'custom'; + + id?: string; + + /** + * Configuration specific to the selected proxy `type`. + */ + config?: + | ProxyCheckResponse.DatacenterProxyConfig + | ProxyCheckResponse.IspProxyConfig + | ProxyCheckResponse.ResidentialProxyConfig + | ProxyCheckResponse.MobileProxyConfig + | ProxyCheckResponse.CustomProxyConfig; + + /** + * Timestamp of the last health check performed on this proxy. + */ + last_checked?: string; + + /** + * Readable name of the proxy. + */ + name?: string; + + /** + * Protocol to use for the proxy connection. + */ + protocol?: 'http' | 'https'; + + /** + * Current health status of the proxy. + */ + status?: 'available' | 'unavailable'; +} + +export namespace ProxyCheckResponse { + /** + * Configuration for a datacenter proxy. + */ + export interface DatacenterProxyConfig { + /** + * ISO 3166 country code. Defaults to US if not provided. + */ + country?: string; + } + + /** + * Configuration for an ISP proxy. + */ + export interface IspProxyConfig { + /** + * ISO 3166 country code. Defaults to US if not provided. + */ + country?: string; + } + + /** + * Configuration for residential proxies. + */ + export interface ResidentialProxyConfig { + /** + * Autonomous system number. See https://bgp.potaroo.net/cidr/autnums.html + */ + asn?: string; + + /** + * City name (no spaces, e.g. `sanfrancisco`). If provided, `country` must also be + * provided. + */ + city?: string; + + /** + * ISO 3166 country code. + */ + country?: string; + + /** + * @deprecated Operating system of the residential device. + */ + os?: 'windows' | 'macos' | 'android'; + + /** + * Two-letter state code. + */ + state?: string; + + /** + * US ZIP code. + */ + zip?: string; + } + + /** + * Configuration for mobile proxies. + */ + export interface MobileProxyConfig { + /** + * Autonomous system number. See https://bgp.potaroo.net/cidr/autnums.html + */ + asn?: string; + + /** + * Mobile carrier. + */ + carrier?: + | 'a1' + | 'aircel' + | 'airtel' + | 'att' + | 'celcom' + | 'chinamobile' + | 'claro' + | 'comcast' + | 'cox' + | 'digi' + | 'dt' + | 'docomo' + | 'dtac' + | 'etisalat' + | 'idea' + | 'kyivstar' + | 'meo' + | 'megafon' + | 'mtn' + | 'mtnza' + | 'mts' + | 'optus' + | 'orange' + | 'qwest' + | 'reliance_jio' + | 'robi' + | 'sprint' + | 'telefonica' + | 'telstra' + | 'tmobile' + | 'tigo' + | 'tim' + | 'verizon' + | 'vimpelcom' + | 'vodacomza' + | 'vodafone' + | 'vivo' + | 'zain' + | 'vivabo' + | 'telenormyanmar' + | 'kcelljsc' + | 'swisscom' + | 'singtel' + | 'asiacell' + | 'windit' + | 'cellc' + | 'ooredoo' + | 'drei' + | 'umobile' + | 'cableone' + | 'proximus' + | 'tele2' + | 'mobitel' + | 'o2' + | 'bouygues' + | 'free' + | 'sfr' + | 'digicel'; + + /** + * City name (no spaces, e.g. `sanfrancisco`). If provided, `country` must also be + * provided. + */ + city?: string; + + /** + * ISO 3166 country code + */ + country?: string; + + /** + * Two-letter state code. + */ + state?: string; + + /** + * US ZIP code. + */ + zip?: string; + } + + /** + * Configuration for a custom proxy (e.g., private proxy server). + */ + export interface CustomProxyConfig { + /** + * Proxy host address or IP. + */ + host: string; + + /** + * Proxy port. + */ + port: number; + + /** + * Whether the proxy has a password. + */ + has_password?: boolean; + + /** + * Username for proxy authentication. + */ + username?: string; + } +} + export interface ProxyCreateParams { /** * Proxy type to use. In terms of quality for avoiding bot-detection, from best to @@ -913,6 +1140,7 @@ export declare namespace Proxies { type ProxyCreateResponse as ProxyCreateResponse, type ProxyRetrieveResponse as ProxyRetrieveResponse, type ProxyListResponse as ProxyListResponse, + type ProxyCheckResponse as ProxyCheckResponse, type ProxyCreateParams as ProxyCreateParams, }; } diff --git a/src/version.ts b/src/version.ts index 7434729..4931d4f 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.24.0'; // x-release-please-version +export const VERSION = '0.25.0'; // x-release-please-version diff --git a/tests/api-resources/agents/auth/auth.test.ts b/tests/api-resources/agents/auth/auth.test.ts index 1882e82..1f8a923 100644 --- a/tests/api-resources/agents/auth/auth.test.ts +++ b/tests/api-resources/agents/auth/auth.test.ts @@ -10,10 +10,7 @@ const client = new Kernel({ describe('resource auth', () => { // Prism tests are disabled test.skip('create: only required params', async () => { - const responsePromise = client.agents.auth.create({ - profile_name: 'user-123', - target_domain: 'netflix.com', - }); + const responsePromise = client.agents.auth.create({ domain: 'netflix.com', profile_name: 'user-123' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -26,8 +23,9 @@ describe('resource auth', () => { // Prism tests are disabled test.skip('create: required and optional params', async () => { const response = await client.agents.auth.create({ + domain: 'netflix.com', profile_name: 'user-123', - target_domain: 'netflix.com', + allowed_domains: ['login.netflix.com', 'auth.netflix.com'], credential_name: 'my-netflix-login', login_url: 'https://netflix.com/login', proxy: { proxy_id: 'proxy_id' }, @@ -63,7 +61,12 @@ describe('resource auth', () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( client.agents.auth.list( - { limit: 100, offset: 0, profile_name: 'profile_name', target_domain: 'target_domain' }, + { + domain: 'domain', + limit: 100, + offset: 0, + profile_name: 'profile_name', + }, { path: '/_stainless_unknown_path' }, ), ).rejects.toThrow(Kernel.NotFoundError); @@ -80,16 +83,4 @@ describe('resource auth', () => { expect(dataAndResponse.data).toBe(response); expect(dataAndResponse.response).toBe(rawResponse); }); - - // Prism tests are disabled - test.skip('reauth', async () => { - const responsePromise = client.agents.auth.reauth('id'); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); }); diff --git a/tests/api-resources/agents/auth/invocations.test.ts b/tests/api-resources/agents/auth/invocations.test.ts index fc178bb..b30496c 100644 --- a/tests/api-resources/agents/auth/invocations.test.ts +++ b/tests/api-resources/agents/auth/invocations.test.ts @@ -40,30 +40,6 @@ describe('resource invocations', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // Prism tests are disabled - test.skip('discover', async () => { - const responsePromise = client.agents.auth.invocations.discover('invocation_id'); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); - - // Prism tests are disabled - test.skip('discover: request options and params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.agents.auth.invocations.discover( - 'invocation_id', - { login_url: 'https://doordash.com/account/login' }, - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(Kernel.NotFoundError); - }); - // Prism tests are disabled test.skip('exchange: only required params', async () => { const responsePromise = client.agents.auth.invocations.exchange('invocation_id', { code: 'abc123xyz' }); diff --git a/tests/api-resources/apps.test.ts b/tests/api-resources/apps.test.ts index 85debc7..d1a35f2 100644 --- a/tests/api-resources/apps.test.ts +++ b/tests/api-resources/apps.test.ts @@ -25,7 +25,12 @@ describe('resource apps', () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( client.apps.list( - { app_name: 'app_name', limit: 1, offset: 0, version: 'version' }, + { + app_name: 'app_name', + limit: 1, + offset: 0, + version: 'version', + }, { path: '/_stainless_unknown_path' }, ), ).rejects.toThrow(Kernel.NotFoundError); diff --git a/tests/api-resources/browser-pools.test.ts b/tests/api-resources/browser-pools.test.ts index 2fdc93e..97737bb 100644 --- a/tests/api-resources/browser-pools.test.ts +++ b/tests/api-resources/browser-pools.test.ts @@ -29,11 +29,19 @@ describe('resource browserPools', () => { headless: false, kiosk_mode: true, name: 'my-pool', - profile: { id: 'id', name: 'name', save_changes: true }, + profile: { + id: 'id', + name: 'name', + save_changes: true, + }, proxy_id: 'proxy_id', stealth: true, timeout_seconds: 60, - viewport: { height: 800, width: 1280, refresh_rate: 60 }, + viewport: { + height: 800, + width: 1280, + refresh_rate: 60, + }, }); }); @@ -71,11 +79,19 @@ describe('resource browserPools', () => { headless: false, kiosk_mode: true, name: 'my-pool', - profile: { id: 'id', name: 'name', save_changes: true }, + profile: { + id: 'id', + name: 'name', + save_changes: true, + }, proxy_id: 'proxy_id', stealth: true, timeout_seconds: 60, - viewport: { height: 800, width: 1280, refresh_rate: 60 }, + viewport: { + height: 800, + width: 1280, + refresh_rate: 60, + }, }); }); diff --git a/tests/api-resources/browsers/browsers.test.ts b/tests/api-resources/browsers/browsers.test.ts index c44ac77..5b315b4 100644 --- a/tests/api-resources/browsers/browsers.test.ts +++ b/tests/api-resources/browsers/browsers.test.ts @@ -31,11 +31,19 @@ describe('resource browsers', () => { invocation_id: 'rr33xuugxj9h0bkf1rdt2bet', kiosk_mode: true, persistence: { id: 'my-awesome-browser-for-user-1234' }, - profile: { id: 'id', name: 'name', save_changes: true }, + profile: { + id: 'id', + name: 'name', + save_changes: true, + }, proxy_id: 'proxy_id', stealth: true, timeout_seconds: 10, - viewport: { height: 800, width: 1280, refresh_rate: 60 }, + viewport: { + height: 800, + width: 1280, + refresh_rate: 60, + }, }, { path: '/_stainless_unknown_path' }, ), @@ -71,7 +79,11 @@ describe('resource browsers', () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( client.browsers.list( - { include_deleted: true, limit: 1, offset: 0 }, + { + include_deleted: true, + limit: 1, + offset: 0, + }, { path: '/_stainless_unknown_path' }, ), ).rejects.toThrow(Kernel.NotFoundError); diff --git a/tests/api-resources/browsers/computer.test.ts b/tests/api-resources/browsers/computer.test.ts index eb938fd..b95f0fa 100644 --- a/tests/api-resources/browsers/computer.test.ts +++ b/tests/api-resources/browsers/computer.test.ts @@ -13,7 +13,14 @@ describe('resource computer', () => { await expect( client.browsers.computer.captureScreenshot( 'id', - { region: { height: 0, width: 0, x: 0, y: 0 } }, + { + region: { + height: 0, + width: 0, + x: 0, + y: 0, + }, + }, { path: '/_stainless_unknown_path' }, ), ).rejects.toThrow(Kernel.NotFoundError); @@ -89,7 +96,11 @@ describe('resource computer', () => { // Prism tests are disabled test.skip('moveMouse: required and optional params', async () => { - const response = await client.browsers.computer.moveMouse('id', { x: 0, y: 0, hold_keys: ['string'] }); + const response = await client.browsers.computer.moveMouse('id', { + x: 0, + y: 0, + hold_keys: ['string'], + }); }); // Prism tests are disabled diff --git a/tests/api-resources/credentials.test.ts b/tests/api-resources/credentials.test.ts index eaf6c33..d825b4e 100644 --- a/tests/api-resources/credentials.test.ts +++ b/tests/api-resources/credentials.test.ts @@ -30,12 +30,14 @@ describe('resource credentials', () => { domain: 'netflix.com', name: 'my-netflix-login', values: { username: 'user@example.com', password: 'mysecretpassword' }, + sso_provider: 'google', + totp_secret: 'JBSWY3DPEHPK3PXP', }); }); // Prism tests are disabled test.skip('retrieve', async () => { - const responsePromise = client.credentials.retrieve('id'); + const responsePromise = client.credentials.retrieve('id_or_name'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -47,7 +49,7 @@ describe('resource credentials', () => { // Prism tests are disabled test.skip('update', async () => { - const responsePromise = client.credentials.update('id', {}); + const responsePromise = client.credentials.update('id_or_name', {}); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -74,7 +76,11 @@ describe('resource credentials', () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( client.credentials.list( - { domain: 'domain', limit: 100, offset: 0 }, + { + domain: 'domain', + limit: 100, + offset: 0, + }, { path: '/_stainless_unknown_path' }, ), ).rejects.toThrow(Kernel.NotFoundError); @@ -82,7 +88,19 @@ describe('resource credentials', () => { // Prism tests are disabled test.skip('delete', async () => { - const responsePromise = client.credentials.delete('id'); + const responsePromise = client.credentials.delete('id_or_name'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Prism tests are disabled + test.skip('totpCode', async () => { + const responsePromise = client.credentials.totpCode('id_or_name'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; diff --git a/tests/api-resources/deployments.test.ts b/tests/api-resources/deployments.test.ts index 12d3bb7..b3f0c20 100644 --- a/tests/api-resources/deployments.test.ts +++ b/tests/api-resources/deployments.test.ts @@ -49,7 +49,11 @@ describe('resource deployments', () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( client.deployments.list( - { app_name: 'app_name', limit: 1, offset: 0 }, + { + app_name: 'app_name', + limit: 1, + offset: 0, + }, { path: '/_stainless_unknown_path' }, ), ).rejects.toThrow(Kernel.NotFoundError); diff --git a/tests/api-resources/proxies.test.ts b/tests/api-resources/proxies.test.ts index ebc101a..1086c4f 100644 --- a/tests/api-resources/proxies.test.ts +++ b/tests/api-resources/proxies.test.ts @@ -65,4 +65,16 @@ describe('resource proxies', () => { expect(dataAndResponse.data).toBe(response); expect(dataAndResponse.response).toBe(rawResponse); }); + + // Prism tests are disabled + test.skip('check', async () => { + const responsePromise = client.proxies.check('id'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); }); diff --git a/tests/index.test.ts b/tests/index.test.ts index 68b144c..90d04c4 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -87,7 +87,11 @@ describe('instantiate client', () => { error: jest.fn(), }; - const client = new Kernel({ logger: logger, logLevel: 'debug', apiKey: 'My API Key' }); + const client = new Kernel({ + logger: logger, + logLevel: 'debug', + apiKey: 'My API Key', + }); await forceAPIResponseForClient(client); expect(debugMock).toHaveBeenCalled(); @@ -107,7 +111,11 @@ describe('instantiate client', () => { error: jest.fn(), }; - const client = new Kernel({ logger: logger, logLevel: 'info', apiKey: 'My API Key' }); + const client = new Kernel({ + logger: logger, + logLevel: 'info', + apiKey: 'My API Key', + }); await forceAPIResponseForClient(client); expect(debugMock).not.toHaveBeenCalled(); @@ -157,7 +165,11 @@ describe('instantiate client', () => { }; process.env['KERNEL_LOG'] = 'debug'; - const client = new Kernel({ logger: logger, logLevel: 'off', apiKey: 'My API Key' }); + const client = new Kernel({ + logger: logger, + logLevel: 'off', + apiKey: 'My API Key', + }); await forceAPIResponseForClient(client); expect(debugMock).not.toHaveBeenCalled(); @@ -173,7 +185,11 @@ describe('instantiate client', () => { }; process.env['KERNEL_LOG'] = 'not a log level'; - const client = new Kernel({ logger: logger, logLevel: 'debug', apiKey: 'My API Key' }); + const client = new Kernel({ + logger: logger, + logLevel: 'debug', + apiKey: 'My API Key', + }); expect(client.logLevel).toBe('debug'); expect(warnMock).not.toHaveBeenCalled(); }); @@ -267,7 +283,11 @@ describe('instantiate client', () => { return new Response(JSON.stringify({}), { headers: { 'Content-Type': 'application/json' } }); }; - const client = new Kernel({ baseURL: 'http://localhost:5000/', apiKey: 'My API Key', fetch: testFetch }); + const client = new Kernel({ + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: testFetch, + }); await client.patch('/foo'); expect(capturedRequest?.method).toEqual('PATCH'); @@ -320,7 +340,11 @@ describe('instantiate client', () => { `"Ambiguous URL; The \`baseURL\` option (or KERNEL_BASE_URL env var) and the \`environment\` option are given. If you want to use the environment you must pass baseURL: null"`, ); - const client = new Kernel({ apiKey: 'My API Key', baseURL: null, environment: 'production' }); + const client = new Kernel({ + apiKey: 'My API Key', + baseURL: null, + environment: 'production', + }); expect(client.baseURL).toEqual('https://api.onkernel.com/'); }); @@ -358,7 +382,11 @@ describe('instantiate client', () => { describe('withOptions', () => { test('creates a new client with overridden options', async () => { - const client = new Kernel({ baseURL: 'http://localhost:5000/', maxRetries: 3, apiKey: 'My API Key' }); + const client = new Kernel({ + baseURL: 'http://localhost:5000/', + maxRetries: 3, + apiKey: 'My API Key', + }); const newClient = client.withOptions({ maxRetries: 5, @@ -398,7 +426,11 @@ describe('instantiate client', () => { }); test('respects runtime property changes when creating new client', () => { - const client = new Kernel({ baseURL: 'http://localhost:5000/', timeout: 1000, apiKey: 'My API Key' }); + const client = new Kernel({ + baseURL: 'http://localhost:5000/', + timeout: 1000, + apiKey: 'My API Key', + }); // Modify the client properties directly after creation client.baseURL = 'http://localhost:6000/'; @@ -544,7 +576,11 @@ describe('retries', () => { return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; - const client = new Kernel({ apiKey: 'My API Key', timeout: 10, fetch: testFetch }); + const client = new Kernel({ + apiKey: 'My API Key', + timeout: 10, + fetch: testFetch, + }); expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); expect(count).toEqual(2); @@ -574,7 +610,11 @@ describe('retries', () => { return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; - const client = new Kernel({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + const client = new Kernel({ + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); @@ -598,7 +638,11 @@ describe('retries', () => { capturedRequest = init; return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; - const client = new Kernel({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + const client = new Kernel({ + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect( await client.request({ @@ -660,7 +704,11 @@ describe('retries', () => { capturedRequest = init; return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; - const client = new Kernel({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + const client = new Kernel({ + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect( await client.request({