Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.70.0"
".": "0.71.0"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 122
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-d9b82fc5346c9be1bf9c2b18792fdcdec6a80a86153ca765c9e93e597b46fa24.yml
openapi_spec_hash: 9cbaab975acfa421b795d11aa635c57e
config_hash: 99b2b2a25e8067ad9c9214e38e01d64c
configured_endpoints: 123
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-ac06dd66a7a0da0dd6dd6cd98127652891b914e880dbaed90d7ab666b13af8a9.yml
openapi_spec_hash: 1d35ae59d6570497f8b379ded59f0434
config_hash: d52b040438a187c46050e0e8395b2f47
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 0.71.0 (2026-06-25)

Full Changelog: [v0.70.0...v0.71.0](https://github.com/kernel/kernel-node-sdk/compare/v0.70.0...v0.71.0)

### Features

* Expose audit logs in public SDK ([e08b560](https://github.com/kernel/kernel-node-sdk/commit/e08b560f83fd5532f2e45940dd2b92bdbbe27951))

## 0.70.0 (2026-06-24)

Full Changelog: [v0.69.0...v0.70.0](https://github.com/kernel/kernel-node-sdk/compare/v0.69.0...v0.70.0)
Expand Down
10 changes: 10 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,16 @@ Methods:
- <code title="get /org/limits">client.organization.limits.<a href="./src/resources/organization/limits.ts">retrieve</a>() -> OrgLimits</code>
- <code title="patch /org/limits">client.organization.limits.<a href="./src/resources/organization/limits.ts">update</a>({ ...params }) -> OrgLimits</code>

# AuditLogs

Types:

- <code><a href="./src/resources/audit-logs.ts">AuditLogEntry</a></code>

Methods:

- <code title="get /audit-logs">client.auditLogs.<a href="./src/resources/audit-logs.ts">list</a>({ ...params }) -> AuditLogEntriesPageTokenPagination</code>

# APIKeys

Types:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onkernel/sdk",
"version": "0.70.0",
"version": "0.71.0",
"description": "The official TypeScript library for the Kernel API",
"author": "Kernel <>",
"types": "dist/index.d.ts",
Expand Down
32 changes: 31 additions & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ import { stringifyQuery } from './internal/utils/query';
import { VERSION } from './version';
import * as Errors from './core/error';
import * as Pagination from './core/pagination';
import { AbstractPage, type OffsetPaginationParams, OffsetPaginationResponse } from './core/pagination';
import {
AbstractPage,
type OffsetPaginationParams,
OffsetPaginationResponse,
type PageTokenPaginationParams,
PageTokenPaginationResponse,
} from './core/pagination';
import * as Uploads from './core/uploads';
import * as API from './resources/index';
import { APIPromise } from './core/api-promise';
Expand All @@ -36,6 +42,12 @@ import {
browserRoutingSubresourcesFromEnv,
createRoutingFetch,
} from './lib/browser-routing';
import {
AuditLogEntriesPageTokenPagination,
AuditLogEntry,
AuditLogListParams,
AuditLogs,
} from './resources/audit-logs';
import {
BrowserPool,
BrowserPoolAcquireParams,
Expand Down Expand Up @@ -1005,6 +1017,10 @@ export class Kernel {
*/
projects: API.Projects = new API.Projects(this);
organization: API.Organization = new API.Organization(this);
/**
* Read audit log records for the authenticated organization.
*/
auditLogs: API.AuditLogs = new API.AuditLogs(this);
/**
* Create and manage API keys for organization and project-scoped access.
*/
Expand All @@ -1027,12 +1043,19 @@ Kernel.BrowserPools = BrowserPools;
Kernel.Credentials = Credentials;
Kernel.Projects = Projects;
Kernel.Organization = Organization;
Kernel.AuditLogs = AuditLogs;
Kernel.APIKeys = APIKeys;
Kernel.CredentialProviders = CredentialProviders;

export declare namespace Kernel {
export type RequestOptions = Opts.RequestOptions;

export import PageTokenPagination = Pagination.PageTokenPagination;
export {
type PageTokenPaginationParams as PageTokenPaginationParams,
type PageTokenPaginationResponse as PageTokenPaginationResponse,
};

export import OffsetPagination = Pagination.OffsetPagination;
export {
type OffsetPaginationParams as OffsetPaginationParams,
Expand Down Expand Up @@ -1164,6 +1187,13 @@ export declare namespace Kernel {

export { Organization as Organization };

export {
AuditLogs as AuditLogs,
type AuditLogEntry as AuditLogEntry,
type AuditLogEntriesPageTokenPagination as AuditLogEntriesPageTokenPagination,
type AuditLogListParams as AuditLogListParams,
};

export {
APIKeys as APIKeys,
type APIKey as APIKey,
Expand Down
56 changes: 56 additions & 0 deletions src/core/pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,62 @@ export class PagePromise<
}
}

export type PageTokenPaginationResponse<Item> = Item[];

export interface PageTokenPaginationParams {
page_token?: string;

limit?: number;
}

export class PageTokenPagination<Item> extends AbstractPage<Item> {
items: Array<Item>;

next_page_token: string | null;

has_more: boolean | null;

constructor(
client: Kernel,
response: Response,
body: PageTokenPaginationResponse<Item>,
options: FinalRequestOptions,
) {
super(client, response, body, options);

this.items = body || [];
this.next_page_token = this.response.headers.get('x-next-page-token') ?? null;
this.has_more = maybeCoerceBoolean(this.response.headers.get('x-has-more')) ?? null;
}

getPaginatedItems(): Item[] {
return this.items ?? [];
}

override hasNextPage(): boolean {
if (this.has_more === false) {
return false;
}

return super.hasNextPage();
}

nextPageRequestOptions(): PageRequestOptions | null {
const cursor = this.next_page_token;
if (!cursor) {
return null;
}

return {
...this.options,
query: {
...maybeObj(this.options.query),
page_token: cursor,
},
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Silent audit log pagination truncation

High Severity

PageTokenPagination stops auto-paginating when x-has-more is true but x-next-page-token is missing or empty. This causes callers to silently miss records, as the system treats pagination as complete instead of indicating an issue.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3de2942. Configure here.

}

export type OffsetPaginationResponse<Item> = Item[];

export interface OffsetPaginationParams {
Expand Down
135 changes: 135 additions & 0 deletions src/resources/audit-logs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

import { APIResource } from '../core/resource';
import { PagePromise, PageTokenPagination, type PageTokenPaginationParams } from '../core/pagination';
import { RequestOptions } from '../internal/request-options';

/**
* 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<AuditLogEntriesPageTokenPagination, AuditLogEntry> {
return this._client.getAPIList('/audit-logs', PageTokenPagination<AuditLogEntry>, { query, ...options });
}
}

export type AuditLogEntriesPageTokenPagination = PageTokenPagination<AuditLogEntry>;

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?: string;

/**
* 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<string>;

/**
* Filter by service name.
*/
service?: string;
}

export declare namespace AuditLogs {
export {
type AuditLogEntry as AuditLogEntry,
type AuditLogEntriesPageTokenPagination as AuditLogEntriesPageTokenPagination,
type AuditLogListParams as AuditLogListParams,
};
}
6 changes: 6 additions & 0 deletions src/resources/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ export {
type AppListParams,
type AppListResponsesOffsetPagination,
} from './apps';
export {
AuditLogs,
type AuditLogEntry,
type AuditLogListParams,
type AuditLogEntriesPageTokenPagination,
} from './audit-logs';
export { Auth } from './auth/auth';
export {
BrowserPools,
Expand Down
2 changes: 1 addition & 1 deletion src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const VERSION = '0.70.0'; // x-release-please-version
export const VERSION = '0.71.0'; // x-release-please-version
41 changes: 41 additions & 0 deletions tests/api-resources/audit-logs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// 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 auditLogs', () => {
// Mock server tests are disabled
test.skip('list: only required params', async () => {
const responsePromise = client.auditLogs.list({
end: '2026-01-02T00:00:00Z',
start: '2026-01-01T00:00:00Z',
});
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: required and optional params', async () => {
const response = await client.auditLogs.list({
end: '2026-01-02T00:00:00Z',
start: '2026-01-01T00:00:00Z',
auth_strategy: 'auth_strategy',
exclude_method: 'exclude_method',
limit: 1,
method: 'method',
page_token: 'page_token',
search: 'search',
search_user_id: ['string'],
service: 'service',
});
});
});
Loading