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); + }); +});