diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7d9b009..78e7f27 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.10.0" + ".": "0.11.0" } diff --git a/.stats.yml b/.stats.yml index b791078..6ac19ba 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 41 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-a7c1df5070fe59642d7a1f168aa902a468227752bfc930cbf38930f7c205dbb6.yml -openapi_spec_hash: eab65e39aef4f0a0952b82adeecf6b5b -config_hash: 5de78bc29ac060562575cb54bb26826c +configured_endpoints: 46 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-e98d46c55826cdf541a9ee0df04ce92806ac6d4d92957ae79f897270b7d85b23.yml +openapi_spec_hash: 8a1af54fc0a4417165b8a52e6354b685 +config_hash: 043ddc54629c6d8b889123770cb4769f diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c88191..9b9bb96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 0.11.0 (2025-09-04) + +Full Changelog: [v0.10.0...v0.11.0](https://github.com/onkernel/kernel-node-sdk/compare/v0.10.0...v0.11.0) + +### Features + +* **api:** adding support for browser profiles ([e614d58](https://github.com/onkernel/kernel-node-sdk/commit/e614d585a515121a2bba520941ee667f60f1e3ce)) + + +### Chores + +* **internal:** update global Error reference ([2697844](https://github.com/onkernel/kernel-node-sdk/commit/26978447f89c1fb152ef98ff2cc841ec1b76ad87)) + ## 0.10.0 (2025-08-27) Full Changelog: [v0.9.1...v0.10.0](https://github.com/onkernel/kernel-node-sdk/compare/v0.9.1...v0.10.0) diff --git a/api.md b/api.md index 69fe6bf..4c61dfb 100644 --- a/api.md +++ b/api.md @@ -59,6 +59,7 @@ Methods: Types: - BrowserPersistence +- Profile - BrowserCreateResponse - BrowserRetrieveResponse - BrowserListResponse @@ -145,3 +146,17 @@ Methods: Methods: - client.browsers.logs.stream(id, { ...params }) -> LogEvent + +# Profiles + +Types: + +- ProfileListResponse + +Methods: + +- client.profiles.create({ ...params }) -> Profile +- client.profiles.retrieve(idOrName) -> Profile +- client.profiles.list() -> ProfileListResponse +- client.profiles.delete(idOrName) -> void +- client.profiles.download(idOrName) -> Response diff --git a/package.json b/package.json index af5ef84..75126b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@onkernel/sdk", - "version": "0.10.0", + "version": "0.11.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 9956866..130658c 100644 --- a/src/client.ts +++ b/src/client.ts @@ -39,6 +39,7 @@ import { InvocationUpdateResponse, Invocations, } from './resources/invocations'; +import { ProfileCreateParams, ProfileListResponse, Profiles } from './resources/profiles'; import { BrowserCreateParams, BrowserCreateResponse, @@ -47,6 +48,7 @@ import { BrowserPersistence, BrowserRetrieveResponse, Browsers, + Profile, } from './resources/browsers/browsers'; import { type Fetch } from './internal/builtin-types'; import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers'; @@ -435,7 +437,7 @@ export class Kernel { const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError); const headersTime = Date.now(); - if (response instanceof Error) { + if (response instanceof globalThis.Error) { const retryMessage = `retrying, ${retriesRemaining} attempts remaining`; if (options.signal?.aborted) { throw new Errors.APIUserAbortError(); @@ -795,12 +797,14 @@ export class Kernel { apps: API.Apps = new API.Apps(this); invocations: API.Invocations = new API.Invocations(this); browsers: API.Browsers = new API.Browsers(this); + profiles: API.Profiles = new API.Profiles(this); } Kernel.Deployments = Deployments; Kernel.Apps = Apps; Kernel.Invocations = Invocations; Kernel.Browsers = Browsers; +Kernel.Profiles = Profiles; export declare namespace Kernel { export type RequestOptions = Opts.RequestOptions; @@ -833,6 +837,7 @@ export declare namespace Kernel { export { Browsers as Browsers, type BrowserPersistence as BrowserPersistence, + type Profile as Profile, type BrowserCreateResponse as BrowserCreateResponse, type BrowserRetrieveResponse as BrowserRetrieveResponse, type BrowserListResponse as BrowserListResponse, @@ -840,6 +845,12 @@ export declare namespace Kernel { type BrowserDeleteParams as BrowserDeleteParams, }; + export { + Profiles as Profiles, + type ProfileListResponse as ProfileListResponse, + type ProfileCreateParams as ProfileCreateParams, + }; + export type AppAction = API.AppAction; export type ErrorDetail = API.ErrorDetail; export type ErrorEvent = API.ErrorEvent; diff --git a/src/resources/browsers/browsers.ts b/src/resources/browsers/browsers.ts index 20a3e0c..5cc3415 100644 --- a/src/resources/browsers/browsers.ts +++ b/src/resources/browsers/browsers.ts @@ -146,6 +146,36 @@ export interface BrowserPersistence { id: string; } +/** + * Browser profile metadata. + */ +export interface Profile { + /** + * Unique identifier for the profile + */ + id: string; + + /** + * Timestamp when the profile was created + */ + created_at: string; + + /** + * Timestamp when the profile was last used + */ + last_used_at?: string; + + /** + * Optional, easier-to-reference name for the profile + */ + name?: string | null; + + /** + * Timestamp when the profile was last updated + */ + updated_at?: string; +} + export interface BrowserCreateResponse { /** * Websocket URL for Chrome DevTools Protocol connections to the browser session @@ -187,6 +217,11 @@ export interface BrowserCreateResponse { * Optional persistence configuration for the browser session. */ persistence?: BrowserPersistence; + + /** + * Browser profile metadata. + */ + profile?: Profile; } export interface BrowserRetrieveResponse { @@ -230,6 +265,11 @@ export interface BrowserRetrieveResponse { * Optional persistence configuration for the browser session. */ persistence?: BrowserPersistence; + + /** + * Browser profile metadata. + */ + profile?: Profile; } export type BrowserListResponse = Array; @@ -276,6 +316,11 @@ export namespace BrowserListResponse { * Optional persistence configuration for the browser session. */ persistence?: BrowsersAPI.BrowserPersistence; + + /** + * Browser profile metadata. + */ + profile?: BrowsersAPI.Profile; } } @@ -296,6 +341,13 @@ export interface BrowserCreateParams { */ persistence?: BrowserPersistence; + /** + * Profile selection for the browser session. Provide either id or name. If + * specified, the matching profile will be loaded into the browser session. + * Profiles must be created beforehand. + */ + profile?: BrowserCreateParams.Profile; + /** * If true, launches the browser in stealth mode to reduce detection by anti-bot * mechanisms. @@ -310,6 +362,32 @@ export interface BrowserCreateParams { timeout_seconds?: number; } +export namespace BrowserCreateParams { + /** + * Profile selection for the browser session. Provide either id or name. If + * specified, the matching profile will be loaded into the browser session. + * Profiles must be created beforehand. + */ + export interface Profile { + /** + * Profile ID to load for this browser session + */ + id?: string; + + /** + * Profile name to load for this browser session (instead of id). Must be 1-255 + * characters, using letters, numbers, dots, underscores, or hyphens. + */ + name?: string; + + /** + * If true, save changes made during the session back to the profile when the + * session ends. + */ + save_changes?: boolean; + } +} + export interface BrowserDeleteParams { /** * Persistent browser identifier @@ -325,6 +403,7 @@ Browsers.Logs = Logs; export declare namespace Browsers { export { type BrowserPersistence as BrowserPersistence, + type Profile as Profile, type BrowserCreateResponse as BrowserCreateResponse, type BrowserRetrieveResponse as BrowserRetrieveResponse, type BrowserListResponse as BrowserListResponse, diff --git a/src/resources/browsers/index.ts b/src/resources/browsers/index.ts index 3437de1..bcd5b40 100644 --- a/src/resources/browsers/index.ts +++ b/src/resources/browsers/index.ts @@ -3,6 +3,7 @@ export { Browsers, type BrowserPersistence, + type Profile, type BrowserCreateResponse, type BrowserRetrieveResponse, type BrowserListResponse, diff --git a/src/resources/index.ts b/src/resources/index.ts index a368fed..6b0e380 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -5,6 +5,7 @@ export { Apps, type AppListResponse, type AppListParams } from './apps'; export { Browsers, type BrowserPersistence, + type Profile, type BrowserCreateResponse, type BrowserRetrieveResponse, type BrowserListResponse, @@ -32,3 +33,4 @@ export { type InvocationCreateParams, type InvocationUpdateParams, } from './invocations'; +export { Profiles, type ProfileListResponse, type ProfileCreateParams } from './profiles'; diff --git a/src/resources/profiles.ts b/src/resources/profiles.ts new file mode 100644 index 0000000..774f764 --- /dev/null +++ b/src/resources/profiles.ts @@ -0,0 +1,67 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import * as BrowsersAPI from './browsers/browsers'; +import { APIPromise } from '../core/api-promise'; +import { buildHeaders } from '../internal/headers'; +import { RequestOptions } from '../internal/request-options'; +import { path } from '../internal/utils/path'; + +export class Profiles extends APIResource { + /** + * Create a browser profile that can be used to load state into future browser + * sessions. + */ + create(body: ProfileCreateParams, options?: RequestOptions): APIPromise { + return this._client.post('/profiles', { body, ...options }); + } + + /** + * Retrieve details for a single profile by its ID or name. + */ + retrieve(idOrName: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/profiles/${idOrName}`, options); + } + + /** + * List profiles with optional filtering and pagination. + */ + list(options?: RequestOptions): APIPromise { + return this._client.get('/profiles', options); + } + + /** + * Delete a profile by its ID or by its name. + */ + delete(idOrName: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/profiles/${idOrName}`, { + ...options, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), + }); + } + + /** + * Download the profile. Profiles are JSON files containing the pieces of state + * that we save. + */ + download(idOrName: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/profiles/${idOrName}/download`, { + ...options, + headers: buildHeaders([{ Accept: 'application/octet-stream' }, options?.headers]), + __binaryResponse: true, + }); + } +} + +export type ProfileListResponse = Array; + +export interface ProfileCreateParams { + /** + * Optional name of the profile. Must be unique within the organization. + */ + name?: string; +} + +export declare namespace Profiles { + export { type ProfileListResponse as ProfileListResponse, type ProfileCreateParams as ProfileCreateParams }; +} diff --git a/src/version.ts b/src/version.ts index c2e5b96..9085e9d 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.10.0'; // x-release-please-version +export const VERSION = '0.11.0'; // x-release-please-version diff --git a/tests/api-resources/browsers/browsers.test.ts b/tests/api-resources/browsers/browsers.test.ts index 7685e68..5d360af 100644 --- a/tests/api-resources/browsers/browsers.test.ts +++ b/tests/api-resources/browsers/browsers.test.ts @@ -29,6 +29,7 @@ describe('resource browsers', () => { headless: false, invocation_id: 'rr33xuugxj9h0bkf1rdt2bet', persistence: { id: 'my-awesome-browser-for-user-1234' }, + profile: { id: 'id', name: 'name', save_changes: true }, stealth: true, timeout_seconds: 0, }, diff --git a/tests/api-resources/profiles.test.ts b/tests/api-resources/profiles.test.ts new file mode 100644 index 0000000..9fe686a --- /dev/null +++ b/tests/api-resources/profiles.test.ts @@ -0,0 +1,58 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource profiles', () => { + // Prism tests are disabled + test.skip('create', async () => { + const responsePromise = client.profiles.create({}); + 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('retrieve', async () => { + const responsePromise = client.profiles.retrieve('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('list', async () => { + const responsePromise = client.profiles.list(); + 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('delete', async () => { + const responsePromise = client.profiles.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); + }); +});