From bb67ffadedc5ba80f393a40588a94203c392ae7c Mon Sep 17 00:00:00 2001
From: "kernel-internal[bot]"
<260533166+kernel-internal[bot]@users.noreply.github.com>
Date: Fri, 7 Aug 2026 13:23:28 +0000
Subject: [PATCH 1/3] feat: Expose profile save behavior in browser responses
Stainless-Generated-From: f726e3683e448853773ff4d4b80c3c4a6923fd51
---
src/resources/browser-pools.ts | 6 ++++++
src/resources/browsers/browsers.ts | 24 ++++++++++++++++++++++++
src/resources/invocations.ts | 6 ++++++
3 files changed, 36 insertions(+)
diff --git a/src/resources/browser-pools.ts b/src/resources/browser-pools.ts
index e649cbbb..d3de6c55 100644
--- a/src/resources/browser-pools.ts
+++ b/src/resources/browser-pools.ts
@@ -432,6 +432,12 @@ export interface BrowserPoolAcquireResponse {
*/
profile?: BrowsersAPI.Profile;
+ /**
+ * Whether changes made during this browser session are saved back to its profile
+ * when the session ends. Omitted when no profile is attached.
+ */
+ profile_save_changes?: boolean;
+
/**
* ID of the proxy associated with this browser session, if any.
*/
diff --git a/src/resources/browsers/browsers.ts b/src/resources/browsers/browsers.ts
index 40ca5cde..6520400a 100644
--- a/src/resources/browsers/browsers.ts
+++ b/src/resources/browsers/browsers.ts
@@ -426,6 +426,12 @@ export interface BrowserCreateResponse {
*/
profile?: Profile;
+ /**
+ * Whether changes made during this browser session are saved back to its profile
+ * when the session ends. Omitted when no profile is attached.
+ */
+ profile_save_changes?: boolean;
+
/**
* ID of the proxy associated with this browser session, if any.
*/
@@ -558,6 +564,12 @@ export interface BrowserRetrieveResponse {
*/
profile?: Profile;
+ /**
+ * Whether changes made during this browser session are saved back to its profile
+ * when the session ends. Omitted when no profile is attached.
+ */
+ profile_save_changes?: boolean;
+
/**
* ID of the proxy associated with this browser session, if any.
*/
@@ -690,6 +702,12 @@ export interface BrowserUpdateResponse {
*/
profile?: Profile;
+ /**
+ * Whether changes made during this browser session are saved back to its profile
+ * when the session ends. Omitted when no profile is attached.
+ */
+ profile_save_changes?: boolean;
+
/**
* ID of the proxy associated with this browser session, if any.
*/
@@ -822,6 +840,12 @@ export interface BrowserListResponse {
*/
profile?: Profile;
+ /**
+ * Whether changes made during this browser session are saved back to its profile
+ * when the session ends. Omitted when no profile is attached.
+ */
+ profile_save_changes?: boolean;
+
/**
* ID of the proxy associated with this browser session, if any.
*/
diff --git a/src/resources/invocations.ts b/src/resources/invocations.ts
index 4c66e43a..02a051d6 100644
--- a/src/resources/invocations.ts
+++ b/src/resources/invocations.ts
@@ -503,6 +503,12 @@ export namespace InvocationListBrowsersResponse {
*/
profile?: BrowsersAPI.Profile;
+ /**
+ * Whether changes made during this browser session are saved back to its profile
+ * when the session ends. Omitted when no profile is attached.
+ */
+ profile_save_changes?: boolean;
+
/**
* ID of the proxy associated with this browser session, if any.
*/
From b6b6518d71b4a209d933d19fd5d612cd1e41427d Mon Sep 17 00:00:00 2001
From: "kernel-internal[bot]"
<260533166+kernel-internal[bot]@users.noreply.github.com>
Date: Fri, 7 Aug 2026 19:51:22 +0000
Subject: [PATCH 2/3] feat: Add audit logs plan paywall to the dashboard
Stainless-Generated-From: dc92ffe81ea63e5db991bab3b3350ff53f00df26
---
.stats.yml | 2 +-
api.md | 24 +-
src/client.ts | 14 +-
src/resources/audit-logs.ts | 250 +---------------
src/resources/audit-logs/audit-logs.ts | 281 ++++++++++++++++++
.../audit-logs/export-destinations.ts | 262 ++++++++++++++++
src/resources/audit-logs/index.ts | 25 ++
src/resources/index.ts | 2 +-
.../{ => audit-logs}/audit-logs.test.ts | 0
.../audit-logs/export-destinations.test.ts | 110 +++++++
10 files changed, 709 insertions(+), 261 deletions(-)
create mode 100644 src/resources/audit-logs/audit-logs.ts
create mode 100644 src/resources/audit-logs/export-destinations.ts
create mode 100644 src/resources/audit-logs/index.ts
rename tests/api-resources/{ => audit-logs}/audit-logs.test.ts (100%)
create mode 100644 tests/api-resources/audit-logs/export-destinations.test.ts
diff --git a/.stats.yml b/.stats.yml
index 71c320fc..4bb27f8b 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 127
+configured_endpoints: 133
diff --git a/api.md b/api.md
index c5ab27bb..f64913aa 100644
--- a/api.md
+++ b/api.md
@@ -404,12 +404,30 @@ Methods:
Types:
-- AuditLogEntry
+- AuditLogEntry
Methods:
-- client.auditLogs.list({ ...params }) -> AuditLogEntriesPageTokenPagination
-- client.auditLogs.exportChunk({ ...params }) -> Response
+- client.auditLogs.list({ ...params }) -> AuditLogEntriesPageTokenPagination
+- client.auditLogs.exportChunk({ ...params }) -> Response
+
+## ExportDestinations
+
+Types:
+
+- AuditLogExportDestination
+- AuditLogExportDestinationTestResult
+- CreateAuditLogExportDestinationRequest
+- UpdateAuditLogExportDestinationRequest
+
+Methods:
+
+- client.auditLogs.exportDestinations.create({ ...params }) -> AuditLogExportDestination
+- client.auditLogs.exportDestinations.retrieve(id) -> AuditLogExportDestination
+- client.auditLogs.exportDestinations.update(id, { ...params }) -> AuditLogExportDestination
+- client.auditLogs.exportDestinations.list({ ...params }) -> AuditLogExportDestinationsOffsetPagination
+- client.auditLogs.exportDestinations.delete(id) -> void
+- client.auditLogs.exportDestinations.test(id) -> AuditLogExportDestinationTestResult
# APIKeys
diff --git a/src/client.ts b/src/client.ts
index ff09dd2f..1e9d0f3a 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -42,13 +42,6 @@ import {
browserRoutingSubresourcesFromEnv,
createRoutingFetch,
} from './lib/browser-routing';
-import {
- AuditLogEntriesPageTokenPagination,
- AuditLogEntry,
- AuditLogExportChunkParams,
- AuditLogListParams,
- AuditLogs,
-} from './resources/audit-logs';
import {
BrowserPool,
BrowserPoolAcquireParams,
@@ -143,6 +136,13 @@ import {
ProxyUpdateParams,
ProxyUpdateResponse,
} from './resources/proxies';
+import {
+ AuditLogEntriesPageTokenPagination,
+ AuditLogEntry,
+ AuditLogExportChunkParams,
+ AuditLogListParams,
+ AuditLogs,
+} from './resources/audit-logs/audit-logs';
import { Auth } from './resources/auth/auth';
import {
BrowserCreateParams,
diff --git a/src/resources/audit-logs.ts b/src/resources/audit-logs.ts
index ca7dd082..c25da2bb 100644
--- a/src/resources/audit-logs.ts
+++ b/src/resources/audit-logs.ts
@@ -1,251 +1,3 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-import { APIResource } from '../core/resource';
-import { APIPromise } from '../core/api-promise';
-import { PagePromise, PageTokenPagination, type PageTokenPaginationParams } from '../core/pagination';
-import { buildHeaders } from '../internal/headers';
-import { RequestOptions } from '../internal/request-options';
-import {
- downloadAuditLogs,
- type AuditLogDownloadDestination,
- type AuditLogDownloadOptions,
- type AuditLogDownloadParams,
- type AuditLogDownloadProgress,
- type AuditLogDownloadResult,
-} from '../lib/audit-log-download';
-
-export type {
- AuditLogDownloadDestination,
- AuditLogDownloadOptions,
- AuditLogDownloadParams,
- AuditLogDownloadProgress,
- AuditLogDownloadResult,
-} from '../lib/audit-log-download';
-
-/**
- * Read audit log records for the authenticated organization.
- */
-export class AuditLogs extends APIResource {
- /**
- * API for searching audit logs. Limited to at most 30 day search, returns up to
- * 100 records per page. Not recommended for bulk export.
- */
- list(
- query: AuditLogListParams,
- options?: RequestOptions,
- ): PagePromise {
- return this._client.getAPIList('/audit-logs', PageTokenPagination, { query, ...options });
- }
-
- /**
- * Download an organization's audit log records for a time range as a file, for
- * archival, compliance, or offline analysis. For interactive browsing, use GET
- * /audit-logs.
- */
- exportChunk(query: AuditLogExportChunkParams, options?: RequestOptions): APIPromise {
- return this._client.get('/audit-logs/export/chunk', {
- query,
- ...options,
- headers: buildHeaders([{ Accept: 'application/octet-stream' }, options?.headers]),
- __binaryResponse: true,
- });
- }
-
- /**
- * Download a complete gzip-compressed JSON Lines audit log export to a writable
- * destination. The SDK verifies every chunk and retries transient transfer
- * failures. It does not close the destination. If the download fails, the
- * destination may contain a partial export; use a temporary file and atomic
- * rename when the completed export must be published atomically.
- */
- download(
- query: AuditLogDownloadParams,
- destination: AuditLogDownloadDestination,
- options?: AuditLogDownloadOptions,
- ): Promise {
- return downloadAuditLogs(
- (chunkQuery, chunkOptions) => this.exportChunk(chunkQuery, chunkOptions),
- query,
- destination,
- this._client.timeout,
- options,
- );
- }
-}
-
-export type AuditLogEntriesPageTokenPagination = PageTokenPagination;
-
-export interface AuditLogEntry {
- /**
- * Authentication strategy used for the request.
- */
- auth_strategy: string;
-
- /**
- * Client IP address.
- */
- client_ip: string;
-
- /**
- * Request host.
- */
- domain: string;
-
- /**
- * Request duration in milliseconds.
- */
- duration_ms: number;
-
- /**
- * Email of the authenticated user at request time, if any.
- */
- email: string;
-
- /**
- * HTTP method.
- */
- method: string;
-
- /**
- * Request path.
- */
- path: string;
-
- /**
- * Matched API route pattern, if available.
- */
- route: string;
-
- /**
- * HTTP response status code.
- */
- status: number;
-
- /**
- * UTC time when the request was received.
- */
- timestamp: string;
-
- /**
- * User agent header.
- */
- user_agent: string;
-
- /**
- * ID of the authenticated user, if any.
- */
- user_id: string;
-}
-
-export interface AuditLogListParams extends PageTokenPaginationParams {
- /**
- * Upper bound (exclusive) for the audit record timestamp.
- */
- end: string;
-
- /**
- * Lower bound (inclusive) for the audit record timestamp.
- */
- start: string;
-
- /**
- * Filter by authentication strategy.
- */
- auth_strategy?: string;
-
- /**
- * Filter out results by HTTP method.
- */
- exclude_method?: Array;
-
- /**
- * Filter by HTTP method.
- */
- method?: string;
-
- /**
- * Free-text search over path, user ID, email, client IP, and status.
- */
- search?: string;
-
- /**
- * Additional user IDs to OR into free-text search.
- */
- search_user_id?: Array;
-
- /**
- * Filter by service name.
- */
- service?: string;
-}
-
-export interface AuditLogExportChunkParams {
- /**
- * Upper bound (exclusive) for the audit record timestamp.
- */
- end: string;
-
- /**
- * Lower bound (inclusive) for the audit record timestamp.
- */
- start: string;
-
- /**
- * Filter by authentication strategy.
- */
- auth_strategy?: string;
-
- /**
- * Opaque cursor from X-Next-Cursor for the next chunk of older records.
- */
- cursor?: string;
-
- /**
- * Filter out results by HTTP method.
- */
- exclude_method?: Array;
-
- /**
- * Encoding for the returned chunk.
- */
- format?: 'jsonl' | 'jsonl.gz';
-
- /**
- * Maximum number of records to return in this chunk.
- */
- limit?: number;
-
- /**
- * Filter by HTTP method.
- */
- method?: string;
-
- /**
- * Free-text search over path, user ID, email, client IP, and status.
- */
- search?: string;
-
- /**
- * Additional user IDs to OR into free-text search.
- */
- search_user_id?: Array;
-
- /**
- * Filter by service name.
- */
- service?: string;
-}
-
-export declare namespace AuditLogs {
- export {
- type AuditLogEntry as AuditLogEntry,
- type AuditLogEntriesPageTokenPagination as AuditLogEntriesPageTokenPagination,
- type AuditLogListParams as AuditLogListParams,
- type AuditLogExportChunkParams as AuditLogExportChunkParams,
- type AuditLogDownloadDestination as AuditLogDownloadDestination,
- type AuditLogDownloadOptions as AuditLogDownloadOptions,
- type AuditLogDownloadParams as AuditLogDownloadParams,
- type AuditLogDownloadProgress as AuditLogDownloadProgress,
- type AuditLogDownloadResult as AuditLogDownloadResult,
- };
-}
+export * from './audit-logs/index';
diff --git a/src/resources/audit-logs/audit-logs.ts b/src/resources/audit-logs/audit-logs.ts
new file mode 100644
index 00000000..d628206a
--- /dev/null
+++ b/src/resources/audit-logs/audit-logs.ts
@@ -0,0 +1,281 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../core/resource';
+import * as ExportDestinationsAPI from './export-destinations';
+import {
+ AuditLogExportDestination,
+ AuditLogExportDestinationTestResult,
+ AuditLogExportDestinationsOffsetPagination,
+ CreateAuditLogExportDestinationRequest,
+ ExportDestinationCreateParams,
+ ExportDestinationListParams,
+ ExportDestinationUpdateParams,
+ ExportDestinations,
+ UpdateAuditLogExportDestinationRequest,
+} from './export-destinations';
+import { APIPromise } from '../../core/api-promise';
+import { PagePromise, PageTokenPagination, type PageTokenPaginationParams } from '../../core/pagination';
+import { buildHeaders } from '../../internal/headers';
+import { RequestOptions } from '../../internal/request-options';
+import {
+ downloadAuditLogs,
+ type AuditLogDownloadDestination,
+ type AuditLogDownloadOptions,
+ type AuditLogDownloadParams,
+ type AuditLogDownloadProgress,
+ type AuditLogDownloadResult,
+} from '../../lib/audit-log-download';
+
+export type {
+ AuditLogDownloadDestination,
+ AuditLogDownloadOptions,
+ AuditLogDownloadParams,
+ AuditLogDownloadProgress,
+ AuditLogDownloadResult,
+} from '../../lib/audit-log-download';
+
+/**
+ * Read audit log records for the authenticated organization.
+ */
+export class AuditLogs extends APIResource {
+ exportDestinations: ExportDestinationsAPI.ExportDestinations = new ExportDestinationsAPI.ExportDestinations(
+ this._client,
+ );
+
+ /**
+ * API for searching audit logs. Limited to at most 30 day search, returns up to
+ * 100 records per page. Not recommended for bulk export.
+ */
+ list(
+ query: AuditLogListParams,
+ options?: RequestOptions,
+ ): PagePromise {
+ return this._client.getAPIList('/audit-logs', PageTokenPagination, { query, ...options });
+ }
+
+ /**
+ * Download an organization's audit log records for a time range as a file, for
+ * archival, compliance, or offline analysis. For interactive browsing, use GET
+ * /audit-logs.
+ */
+ exportChunk(query: AuditLogExportChunkParams, options?: RequestOptions): APIPromise {
+ return this._client.get('/audit-logs/export/chunk', {
+ query,
+ ...options,
+ headers: buildHeaders([{ Accept: 'application/octet-stream' }, options?.headers]),
+ __binaryResponse: true,
+ });
+ }
+
+ /**
+ * Download a complete gzip-compressed JSON Lines audit log export to a writable
+ * destination. The SDK verifies every chunk and retries transient transfer
+ * failures. It does not close the destination. If the download fails, the
+ * destination may contain a partial export; use a temporary file and atomic
+ * rename when the completed export must be published atomically.
+ */
+ download(
+ query: AuditLogDownloadParams,
+ destination: AuditLogDownloadDestination,
+ options?: AuditLogDownloadOptions,
+ ): Promise {
+ return downloadAuditLogs(
+ (chunkQuery, chunkOptions) => this.exportChunk(chunkQuery, chunkOptions),
+ query,
+ destination,
+ this._client.timeout,
+ options,
+ );
+ }
+}
+
+export type AuditLogEntriesPageTokenPagination = PageTokenPagination;
+
+export interface AuditLogEntry {
+ /**
+ * Authentication strategy used for the request.
+ */
+ auth_strategy: string;
+
+ /**
+ * Client IP address.
+ */
+ client_ip: string;
+
+ /**
+ * Request host.
+ */
+ domain: string;
+
+ /**
+ * Request duration in milliseconds.
+ */
+ duration_ms: number;
+
+ /**
+ * Email of the authenticated user at request time, if any.
+ */
+ email: string;
+
+ /**
+ * HTTP method.
+ */
+ method: string;
+
+ /**
+ * Request path.
+ */
+ path: string;
+
+ /**
+ * Matched API route pattern, if available.
+ */
+ route: string;
+
+ /**
+ * HTTP response status code.
+ */
+ status: number;
+
+ /**
+ * UTC time when the request was received.
+ */
+ timestamp: string;
+
+ /**
+ * User agent header.
+ */
+ user_agent: string;
+
+ /**
+ * ID of the authenticated user, if any.
+ */
+ user_id: string;
+}
+
+export interface AuditLogListParams extends PageTokenPaginationParams {
+ /**
+ * Upper bound (exclusive) for the audit record timestamp.
+ */
+ end: string;
+
+ /**
+ * Lower bound (inclusive) for the audit record timestamp.
+ */
+ start: string;
+
+ /**
+ * Filter by authentication strategy.
+ */
+ auth_strategy?: string;
+
+ /**
+ * Filter out results by HTTP method.
+ */
+ exclude_method?: Array;
+
+ /**
+ * Filter by HTTP method.
+ */
+ method?: string;
+
+ /**
+ * Free-text search over path, user ID, email, client IP, and status.
+ */
+ search?: string;
+
+ /**
+ * Additional user IDs to OR into free-text search.
+ */
+ search_user_id?: Array;
+
+ /**
+ * Filter by service name.
+ */
+ service?: string;
+}
+
+export interface AuditLogExportChunkParams {
+ /**
+ * Upper bound (exclusive) for the audit record timestamp.
+ */
+ end: string;
+
+ /**
+ * Lower bound (inclusive) for the audit record timestamp.
+ */
+ start: string;
+
+ /**
+ * Filter by authentication strategy.
+ */
+ auth_strategy?: string;
+
+ /**
+ * Opaque cursor from X-Next-Cursor for the next chunk of older records.
+ */
+ cursor?: string;
+
+ /**
+ * Filter out results by HTTP method.
+ */
+ exclude_method?: Array;
+
+ /**
+ * Encoding for the returned chunk.
+ */
+ format?: 'jsonl' | 'jsonl.gz';
+
+ /**
+ * Maximum number of records to return in this chunk.
+ */
+ limit?: number;
+
+ /**
+ * Filter by HTTP method.
+ */
+ method?: string;
+
+ /**
+ * Free-text search over path, user ID, email, client IP, and status.
+ */
+ search?: string;
+
+ /**
+ * Additional user IDs to OR into free-text search.
+ */
+ search_user_id?: Array;
+
+ /**
+ * Filter by service name.
+ */
+ service?: string;
+}
+
+AuditLogs.ExportDestinations = ExportDestinations;
+
+export declare namespace AuditLogs {
+ export {
+ type AuditLogEntry as AuditLogEntry,
+ type AuditLogEntriesPageTokenPagination as AuditLogEntriesPageTokenPagination,
+ type AuditLogListParams as AuditLogListParams,
+ type AuditLogExportChunkParams as AuditLogExportChunkParams,
+ type AuditLogDownloadDestination as AuditLogDownloadDestination,
+ type AuditLogDownloadOptions as AuditLogDownloadOptions,
+ type AuditLogDownloadParams as AuditLogDownloadParams,
+ type AuditLogDownloadProgress as AuditLogDownloadProgress,
+ type AuditLogDownloadResult as AuditLogDownloadResult,
+ };
+
+ export {
+ ExportDestinations as ExportDestinations,
+ type AuditLogExportDestination as AuditLogExportDestination,
+ type AuditLogExportDestinationTestResult as AuditLogExportDestinationTestResult,
+ type CreateAuditLogExportDestinationRequest as CreateAuditLogExportDestinationRequest,
+ type UpdateAuditLogExportDestinationRequest as UpdateAuditLogExportDestinationRequest,
+ type AuditLogExportDestinationsOffsetPagination as AuditLogExportDestinationsOffsetPagination,
+ type ExportDestinationCreateParams as ExportDestinationCreateParams,
+ type ExportDestinationUpdateParams as ExportDestinationUpdateParams,
+ type ExportDestinationListParams as ExportDestinationListParams,
+ };
+}
diff --git a/src/resources/audit-logs/export-destinations.ts b/src/resources/audit-logs/export-destinations.ts
new file mode 100644
index 00000000..aa7c5355
--- /dev/null
+++ b/src/resources/audit-logs/export-destinations.ts
@@ -0,0 +1,262 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../core/resource';
+import { APIPromise } from '../../core/api-promise';
+import { OffsetPagination, type OffsetPaginationParams, PagePromise } from '../../core/pagination';
+import { buildHeaders } from '../../internal/headers';
+import { RequestOptions } from '../../internal/request-options';
+import { path } from '../../internal/utils/path';
+
+/**
+ * Read audit log records for the authenticated organization.
+ */
+export class ExportDestinations extends APIResource {
+ /**
+ * Create a paused destination. Activate it with a status update once the
+ * destination test passes. Requires an active Enterprise plan.
+ */
+ create(
+ body: ExportDestinationCreateParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.post('/audit-logs/export/destinations', { body, ...options });
+ }
+
+ /**
+ * Retrieve details for a single audit log export destination by its ID.
+ */
+ retrieve(id: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/audit-logs/export/destinations/${id}`, options);
+ }
+
+ /**
+ * Apply a partial update to a destination. Requires an active Enterprise plan.
+ * Returns 409 when the destination was changed concurrently, because the merged
+ * configuration this request validated is no longer the one that would be stored;
+ * retry against fresh state. Pausing prevents new delivery attempts, but an S3
+ * upload already in progress may complete after the response.
+ */
+ update(
+ id: string,
+ body: ExportDestinationUpdateParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.patch(path`/audit-logs/export/destinations/${id}`, { body, ...options });
+ }
+
+ /**
+ * List audit log export destinations for the organization with pagination support.
+ */
+ list(
+ query: ExportDestinationListParams | null | undefined = {},
+ options?: RequestOptions,
+ ): PagePromise {
+ return this._client.getAPIList(
+ '/audit-logs/export/destinations',
+ OffsetPagination,
+ { query, ...options },
+ );
+ }
+
+ /**
+ * Soft delete the destination and prevent new delivery attempts. An S3 upload
+ * already in progress may complete after the response.
+ */
+ delete(id: string, options?: RequestOptions): APIPromise {
+ return this._client.delete(path`/audit-logs/export/destinations/${id}`, {
+ ...options,
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
+ });
+ }
+
+ /**
+ * Verify the destination is writable by assuming the configured role and uploading
+ * a temporary probe object with the same request metadata as a real delivery.
+ * Requires an active Enterprise plan.
+ */
+ test(id: string, options?: RequestOptions): APIPromise {
+ return this._client.post(path`/audit-logs/export/destinations/${id}/test`, options);
+ }
+}
+
+export type AuditLogExportDestinationsOffsetPagination = OffsetPagination;
+
+/**
+ * An organization-scoped audit log export destination.
+ *
+ * Delivery is at-least-once for rows visible when their window is committed: a
+ * delivery that is retried rewrites the same object, and the same `event_id` can
+ * appear in more than one object, so consumers must deduplicate on `event_id`.
+ * Each event-time window is held for ten minutes before it commits; a row that
+ * becomes visible after its window is committed may not be delivered.
+ *
+ * Objects are written as
+ * `/destination_id=/org_id=/date=/hour=/-.jsonl.gz`,
+ * where `date` and `hour` are the UTC calendar hour that fully contains every row
+ * in the object, so the layout is safe to register as a Hive-partitioned table.
+ * The object name is derived from the rows it holds, so a retried delivery
+ * rewrites its own object.
+ */
+export interface AuditLogExportDestination {
+ id: string;
+
+ bucket: string;
+
+ consecutive_failures: number;
+
+ created_at: string;
+
+ external_id: string;
+
+ format: 'jsonl.gz';
+
+ /**
+ * The Kernel role that assumes `role_arn` in your account to deliver logs. Allow
+ * this role as the principal in your role's trust policy, and require
+ * `external_id` as the `sts:ExternalId` condition.
+ *
+ * Recreating a destination issues a new `external_id`, which the trust policy has
+ * to be updated to match.
+ */
+ kernel_role_arn: string;
+
+ prefix: string;
+
+ region: string;
+
+ role_arn: string;
+
+ /**
+ * Pausing prevents new delivery attempts. An S3 upload already in progress may
+ * complete after the pause response; its rows can appear again after the
+ * destination is resumed.
+ */
+ status: 'active' | 'paused';
+
+ type: 's3';
+
+ updated_at: string;
+
+ kms_key_id?: string;
+
+ /**
+ * Sanitized description of the most recent delivery failure.
+ */
+ last_error?: string;
+
+ last_error_at?: string;
+
+ /**
+ * Opaque, versioned checkpoint for forward-only continuous export. This value is
+ * not compatible with audit-log list page tokens.
+ *
+ * Delivery starts at the moment the destination is activated, so events recorded
+ * before that are not delivered. Pausing stops delivery and resuming starts again
+ * from the time of the resume: events recorded while a destination was paused are
+ * never exported, and pausing is not a way to defer delivery.
+ */
+ last_exported_cursor?: string;
+
+ last_success_at?: string;
+
+ next_attempt_at?: string;
+}
+
+export interface AuditLogExportDestinationTestResult {
+ stage: 'assume_role' | 'put_object' | 'complete';
+
+ success: boolean;
+
+ error?: AuditLogExportDestinationTestResult.Error;
+}
+
+export namespace AuditLogExportDestinationTestResult {
+ export interface Error {
+ code: 'assume_role_failed' | 'put_object_failed';
+
+ message: string;
+ }
+}
+
+export interface CreateAuditLogExportDestinationRequest {
+ bucket: string;
+
+ format: 'jsonl.gz';
+
+ prefix: string;
+
+ region: string;
+
+ role_arn: string;
+
+ type: 's3';
+
+ kms_key_id?: string;
+}
+
+export interface UpdateAuditLogExportDestinationRequest {
+ bucket?: string;
+
+ /**
+ * KMS key ID, alias, or ARN. Set to an empty string to remove the configured KMS
+ * key; omit or send null to leave unchanged.
+ */
+ kms_key_id?: string;
+
+ prefix?: string;
+
+ region?: string;
+
+ role_arn?: string;
+
+ status?: 'active' | 'paused';
+}
+
+export interface ExportDestinationCreateParams {
+ bucket: string;
+
+ format: 'jsonl.gz';
+
+ prefix: string;
+
+ region: string;
+
+ role_arn: string;
+
+ type: 's3';
+
+ kms_key_id?: string;
+}
+
+export interface ExportDestinationUpdateParams {
+ bucket?: string;
+
+ /**
+ * KMS key ID, alias, or ARN. Set to an empty string to remove the configured KMS
+ * key; omit or send null to leave unchanged.
+ */
+ kms_key_id?: string;
+
+ prefix?: string;
+
+ region?: string;
+
+ role_arn?: string;
+
+ status?: 'active' | 'paused';
+}
+
+export interface ExportDestinationListParams extends OffsetPaginationParams {}
+
+export declare namespace ExportDestinations {
+ export {
+ type AuditLogExportDestination as AuditLogExportDestination,
+ type AuditLogExportDestinationTestResult as AuditLogExportDestinationTestResult,
+ type CreateAuditLogExportDestinationRequest as CreateAuditLogExportDestinationRequest,
+ type UpdateAuditLogExportDestinationRequest as UpdateAuditLogExportDestinationRequest,
+ type AuditLogExportDestinationsOffsetPagination as AuditLogExportDestinationsOffsetPagination,
+ type ExportDestinationCreateParams as ExportDestinationCreateParams,
+ type ExportDestinationUpdateParams as ExportDestinationUpdateParams,
+ type ExportDestinationListParams as ExportDestinationListParams,
+ };
+}
diff --git a/src/resources/audit-logs/index.ts b/src/resources/audit-logs/index.ts
new file mode 100644
index 00000000..f182ebed
--- /dev/null
+++ b/src/resources/audit-logs/index.ts
@@ -0,0 +1,25 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export {
+ AuditLogs,
+ type AuditLogEntry,
+ type AuditLogListParams,
+ type AuditLogExportChunkParams,
+ type AuditLogEntriesPageTokenPagination,
+ type AuditLogDownloadDestination,
+ type AuditLogDownloadOptions,
+ type AuditLogDownloadParams,
+ type AuditLogDownloadProgress,
+ type AuditLogDownloadResult,
+} from './audit-logs';
+export {
+ ExportDestinations,
+ type AuditLogExportDestination,
+ type AuditLogExportDestinationTestResult,
+ type CreateAuditLogExportDestinationRequest,
+ type UpdateAuditLogExportDestinationRequest,
+ type ExportDestinationCreateParams,
+ type ExportDestinationUpdateParams,
+ type ExportDestinationListParams,
+ type AuditLogExportDestinationsOffsetPagination,
+} from './export-destinations';
diff --git a/src/resources/index.ts b/src/resources/index.ts
index 8afbadf4..dac7da9c 100644
--- a/src/resources/index.ts
+++ b/src/resources/index.ts
@@ -24,7 +24,7 @@ export {
type AuditLogListParams,
type AuditLogExportChunkParams,
type AuditLogEntriesPageTokenPagination,
-} from './audit-logs';
+} from './audit-logs/audit-logs';
export { Auth } from './auth/auth';
export {
BrowserPools,
diff --git a/tests/api-resources/audit-logs.test.ts b/tests/api-resources/audit-logs/audit-logs.test.ts
similarity index 100%
rename from tests/api-resources/audit-logs.test.ts
rename to tests/api-resources/audit-logs/audit-logs.test.ts
diff --git a/tests/api-resources/audit-logs/export-destinations.test.ts b/tests/api-resources/audit-logs/export-destinations.test.ts
new file mode 100644
index 00000000..bb724708
--- /dev/null
+++ b/tests/api-resources/audit-logs/export-destinations.test.ts
@@ -0,0 +1,110 @@
+// 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 exportDestinations', () => {
+ // Mock server tests are disabled
+ test.skip('create: only required params', async () => {
+ const responsePromise = client.auditLogs.exportDestinations.create({
+ bucket: 'xxx',
+ format: 'jsonl.gz',
+ prefix: 'prefix',
+ region: 'x',
+ role_arn: 'x',
+ type: 's3',
+ });
+ 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);
+ });
+
+ // Mock server tests are disabled
+ test.skip('create: required and optional params', async () => {
+ const response = await client.auditLogs.exportDestinations.create({
+ bucket: 'xxx',
+ format: 'jsonl.gz',
+ prefix: 'prefix',
+ region: 'x',
+ role_arn: 'x',
+ type: 's3',
+ kms_key_id: 'kms_key_id',
+ });
+ });
+
+ // Mock server tests are disabled
+ test.skip('retrieve', async () => {
+ const responsePromise = client.auditLogs.exportDestinations.retrieve('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);
+ });
+
+ // Mock server tests are disabled
+ test.skip('update', async () => {
+ const responsePromise = client.auditLogs.exportDestinations.update('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);
+ });
+
+ // Mock server tests are disabled
+ test.skip('list', async () => {
+ const responsePromise = client.auditLogs.exportDestinations.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);
+ });
+
+ // Mock server tests are disabled
+ test.skip('list: 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.auditLogs.exportDestinations.list({ limit: 1, offset: 0 }, { path: '/_stainless_unknown_path' }),
+ ).rejects.toThrow(Kernel.NotFoundError);
+ });
+
+ // Mock server tests are disabled
+ test.skip('delete', async () => {
+ const responsePromise = client.auditLogs.exportDestinations.delete('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);
+ });
+
+ // Mock server tests are disabled
+ test.skip('test', async () => {
+ const responsePromise = client.auditLogs.exportDestinations.test('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);
+ });
+});
From ccf84484a26f12234ba4df34ded9e864fc3a848b Mon Sep 17 00:00:00 2001
From: "kernel-internal[bot]"
<260533166+kernel-internal[bot]@users.noreply.github.com>
Date: Fri, 7 Aug 2026 21:08:46 +0000
Subject: [PATCH 3/3] feat: Expose authenticated request context
Stainless-Generated-From: 6e370a57405066ad44066d88f375704812affb83
---
.stats.yml | 2 +-
api.md | 10 ++
src/resources/auth/auth.ts | 6 ++
src/resources/auth/context.ts | 125 +++++++++++++++++++++++
src/resources/auth/index.ts | 1 +
tests/api-resources/auth/context.test.ts | 22 ++++
6 files changed, 165 insertions(+), 1 deletion(-)
create mode 100644 src/resources/auth/context.ts
create mode 100644 tests/api-resources/auth/context.test.ts
diff --git a/.stats.yml b/.stats.yml
index 4bb27f8b..50996d49 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 133
+configured_endpoints: 134
diff --git a/api.md b/api.md
index f64913aa..c9292971 100644
--- a/api.md
+++ b/api.md
@@ -261,6 +261,16 @@ Methods:
# Auth
+## Context
+
+Types:
+
+- AuthContext
+
+Methods:
+
+- client.auth.context.retrieve() -> AuthContext
+
## Connections
Types:
diff --git a/src/resources/auth/auth.ts b/src/resources/auth/auth.ts
index b950b004..945723a8 100644
--- a/src/resources/auth/auth.ts
+++ b/src/resources/auth/auth.ts
@@ -21,14 +21,20 @@ import {
SubmitFieldsRequest,
SubmitFieldsResponse,
} from './connections';
+import * as ContextAPI from './context';
+import { AuthContext, Context } from './context';
export class Auth extends APIResource {
+ context: ContextAPI.Context = new ContextAPI.Context(this._client);
connections: ConnectionsAPI.Connections = new ConnectionsAPI.Connections(this._client);
}
+Auth.Context = Context;
Auth.Connections = Connections;
export declare namespace Auth {
+ export { Context as Context, type AuthContext as AuthContext };
+
export {
Connections as Connections,
type LoginResponse as LoginResponse,
diff --git a/src/resources/auth/context.ts b/src/resources/auth/context.ts
new file mode 100644
index 00000000..41023c99
--- /dev/null
+++ b/src/resources/auth/context.ts
@@ -0,0 +1,125 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../core/resource';
+import { APIPromise } from '../../core/api-promise';
+import { RequestOptions } from '../../internal/request-options';
+
+/**
+ * Inspect the identity and authorization context for the current request.
+ */
+export class Context extends APIResource {
+ /**
+ * Returns the authenticated principal, organization, credential scope, and
+ * effective request scope. The response is derived from the verified request
+ * context and does not expose credential secrets.
+ *
+ * @example
+ * ```ts
+ * const authContext = await client.auth.context.retrieve();
+ * ```
+ */
+ retrieve(options?: RequestOptions): APIPromise {
+ return this._client.get('/auth/context', options);
+ }
+}
+
+/**
+ * The identity and authorization context resolved for the current request.
+ */
+export interface AuthContext {
+ authentication: AuthContext.Authentication;
+
+ /**
+ * The credential's maximum scope and the effective scope selected for this
+ * request. Future permission data can be added without changing scope semantics.
+ */
+ authorization: AuthContext.Authorization;
+
+ organization: AuthContext.Organization;
+
+ principal: AuthContext.Principal;
+}
+
+export namespace AuthContext {
+ export interface Authentication {
+ /**
+ * The API key ID when authenticated with an API key; null for session credentials.
+ */
+ credential_id: string | null;
+
+ /**
+ * The credential format used to authenticate the request.
+ */
+ method: 'api_key' | 'jwt';
+
+ /**
+ * The source classification resolved by authentication middleware.
+ */
+ source: 'api_key' | 'oauth' | 'dashboard';
+ }
+
+ /**
+ * The credential's maximum scope and the effective scope selected for this
+ * request. Future permission data can be added without changing scope semantics.
+ */
+ export interface Authorization {
+ /**
+ * A scope within the authenticated organization. A null project_id represents
+ * organization-wide scope.
+ */
+ credential_scope: Authorization.CredentialScope;
+
+ /**
+ * A scope within the authenticated organization. A null project_id represents
+ * organization-wide scope.
+ */
+ effective_scope: Authorization.EffectiveScope;
+ }
+
+ export namespace Authorization {
+ /**
+ * A scope within the authenticated organization. A null project_id represents
+ * organization-wide scope.
+ */
+ export interface CredentialScope {
+ /**
+ * The Kernel project ID, or null when the scope is organization-wide.
+ */
+ project_id: string | null;
+ }
+
+ /**
+ * A scope within the authenticated organization. A null project_id represents
+ * organization-wide scope.
+ */
+ export interface EffectiveScope {
+ /**
+ * The Kernel project ID, or null when the scope is organization-wide.
+ */
+ project_id: string | null;
+ }
+ }
+
+ export interface Organization {
+ /**
+ * The authenticated Kernel organization ID.
+ */
+ id: string;
+ }
+
+ export interface Principal {
+ /**
+ * The API key ID for API-key principals or user ID for user principals.
+ */
+ id: string;
+
+ /**
+ * The kind of principal authenticated for the request.
+ */
+ type: 'api_key' | 'user';
+ }
+}
+
+export declare namespace Context {
+ export { type AuthContext as AuthContext };
+}
diff --git a/src/resources/auth/index.ts b/src/resources/auth/index.ts
index 7d82d6ec..38494a56 100644
--- a/src/resources/auth/index.ts
+++ b/src/resources/auth/index.ts
@@ -20,3 +20,4 @@ export {
type ManagedAuthsOffsetPagination,
type ManagedAuthTimelineEventsOffsetPagination,
} from './connections';
+export { Context, type AuthContext } from './context';
diff --git a/tests/api-resources/auth/context.test.ts b/tests/api-resources/auth/context.test.ts
new file mode 100644
index 00000000..8aa0b3d0
--- /dev/null
+++ b/tests/api-resources/auth/context.test.ts
@@ -0,0 +1,22 @@
+// 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 context', () => {
+ // Mock server tests are disabled
+ test.skip('retrieve', async () => {
+ const responsePromise = client.auth.context.retrieve();
+ 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);
+ });
+});