Skip to content

Commit e08b560

Browse files
feat: Expose audit logs in public SDK
1 parent e380b1e commit e08b560

7 files changed

Lines changed: 283 additions & 5 deletions

File tree

.stats.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 122
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-d9b82fc5346c9be1bf9c2b18792fdcdec6a80a86153ca765c9e93e597b46fa24.yml
3-
openapi_spec_hash: 9cbaab975acfa421b795d11aa635c57e
4-
config_hash: 99b2b2a25e8067ad9c9214e38e01d64c
1+
configured_endpoints: 123
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-784ee80ab17dd58e4b44292a4732d1669263d9928df5685e2683c59398e7a043.yml
3+
openapi_spec_hash: d34b07cf9549aef3469c82379f526f95
4+
config_hash: d52b040438a187c46050e0e8395b2f47

api.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,16 @@ Methods:
393393
- <code title="get /org/limits">client.organization.limits.<a href="./src/resources/organization/limits.ts">retrieve</a>() -> OrgLimits</code>
394394
- <code title="patch /org/limits">client.organization.limits.<a href="./src/resources/organization/limits.ts">update</a>({ ...params }) -> OrgLimits</code>
395395

396+
# AuditLogs
397+
398+
Types:
399+
400+
- <code><a href="./src/resources/audit-logs.ts">AuditLogEntry</a></code>
401+
402+
Methods:
403+
404+
- <code title="get /audit-logs">client.auditLogs.<a href="./src/resources/audit-logs.ts">list</a>({ ...params }) -> AuditLogEntriesPageTokenPagination</code>
405+
396406
# APIKeys
397407

398408
Types:

src/client.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@ import { stringifyQuery } from './internal/utils/query';
1515
import { VERSION } from './version';
1616
import * as Errors from './core/error';
1717
import * as Pagination from './core/pagination';
18-
import { AbstractPage, type OffsetPaginationParams, OffsetPaginationResponse } from './core/pagination';
18+
import {
19+
AbstractPage,
20+
type OffsetPaginationParams,
21+
OffsetPaginationResponse,
22+
type PageTokenPaginationParams,
23+
PageTokenPaginationResponse,
24+
} from './core/pagination';
1925
import * as Uploads from './core/uploads';
2026
import * as API from './resources/index';
2127
import { APIPromise } from './core/api-promise';
@@ -36,6 +42,12 @@ import {
3642
browserRoutingSubresourcesFromEnv,
3743
createRoutingFetch,
3844
} from './lib/browser-routing';
45+
import {
46+
AuditLogEntriesPageTokenPagination,
47+
AuditLogEntry,
48+
AuditLogListParams,
49+
AuditLogs,
50+
} from './resources/audit-logs';
3951
import {
4052
BrowserPool,
4153
BrowserPoolAcquireParams,
@@ -1005,6 +1017,10 @@ export class Kernel {
10051017
*/
10061018
projects: API.Projects = new API.Projects(this);
10071019
organization: API.Organization = new API.Organization(this);
1020+
/**
1021+
* Read audit log records for the authenticated organization.
1022+
*/
1023+
auditLogs: API.AuditLogs = new API.AuditLogs(this);
10081024
/**
10091025
* Create and manage API keys for organization and project-scoped access.
10101026
*/
@@ -1027,12 +1043,19 @@ Kernel.BrowserPools = BrowserPools;
10271043
Kernel.Credentials = Credentials;
10281044
Kernel.Projects = Projects;
10291045
Kernel.Organization = Organization;
1046+
Kernel.AuditLogs = AuditLogs;
10301047
Kernel.APIKeys = APIKeys;
10311048
Kernel.CredentialProviders = CredentialProviders;
10321049

10331050
export declare namespace Kernel {
10341051
export type RequestOptions = Opts.RequestOptions;
10351052

1053+
export import PageTokenPagination = Pagination.PageTokenPagination;
1054+
export {
1055+
type PageTokenPaginationParams as PageTokenPaginationParams,
1056+
type PageTokenPaginationResponse as PageTokenPaginationResponse,
1057+
};
1058+
10361059
export import OffsetPagination = Pagination.OffsetPagination;
10371060
export {
10381061
type OffsetPaginationParams as OffsetPaginationParams,
@@ -1164,6 +1187,13 @@ export declare namespace Kernel {
11641187

11651188
export { Organization as Organization };
11661189

1190+
export {
1191+
AuditLogs as AuditLogs,
1192+
type AuditLogEntry as AuditLogEntry,
1193+
type AuditLogEntriesPageTokenPagination as AuditLogEntriesPageTokenPagination,
1194+
type AuditLogListParams as AuditLogListParams,
1195+
};
1196+
11671197
export {
11681198
APIKeys as APIKeys,
11691199
type APIKey as APIKey,

src/core/pagination.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,62 @@ export class PagePromise<
107107
}
108108
}
109109

110+
export type PageTokenPaginationResponse<Item> = Item[];
111+
112+
export interface PageTokenPaginationParams {
113+
page_token?: string;
114+
115+
limit?: number;
116+
}
117+
118+
export class PageTokenPagination<Item> extends AbstractPage<Item> {
119+
items: Array<Item>;
120+
121+
next_page_token: string | null;
122+
123+
has_more: boolean | null;
124+
125+
constructor(
126+
client: Kernel,
127+
response: Response,
128+
body: PageTokenPaginationResponse<Item>,
129+
options: FinalRequestOptions,
130+
) {
131+
super(client, response, body, options);
132+
133+
this.items = body || [];
134+
this.next_page_token = this.response.headers.get('x-next-page-token') ?? null;
135+
this.has_more = maybeCoerceBoolean(this.response.headers.get('x-has-more')) ?? null;
136+
}
137+
138+
getPaginatedItems(): Item[] {
139+
return this.items ?? [];
140+
}
141+
142+
override hasNextPage(): boolean {
143+
if (this.has_more === false) {
144+
return false;
145+
}
146+
147+
return super.hasNextPage();
148+
}
149+
150+
nextPageRequestOptions(): PageRequestOptions | null {
151+
const cursor = this.next_page_token;
152+
if (!cursor) {
153+
return null;
154+
}
155+
156+
return {
157+
...this.options,
158+
query: {
159+
...maybeObj(this.options.query),
160+
page_token: cursor,
161+
},
162+
};
163+
}
164+
}
165+
110166
export type OffsetPaginationResponse<Item> = Item[];
111167

112168
export interface OffsetPaginationParams {

src/resources/audit-logs.ts

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
import { APIResource } from '../core/resource';
4+
import { PagePromise, PageTokenPagination, type PageTokenPaginationParams } from '../core/pagination';
5+
import { RequestOptions } from '../internal/request-options';
6+
7+
/**
8+
* Read audit log records for the authenticated organization.
9+
*/
10+
export class AuditLogs extends APIResource {
11+
/**
12+
* API for searching audit logs. Limited to at most 30 day search, returns up to
13+
* 100 records per page. Not recommended for bulk export.
14+
*/
15+
list(
16+
query: AuditLogListParams,
17+
options?: RequestOptions,
18+
): PagePromise<AuditLogEntriesPageTokenPagination, AuditLogEntry> {
19+
return this._client.getAPIList('/audit-logs', PageTokenPagination<AuditLogEntry>, { query, ...options });
20+
}
21+
}
22+
23+
export type AuditLogEntriesPageTokenPagination = PageTokenPagination<AuditLogEntry>;
24+
25+
export interface AuditLogEntry {
26+
/**
27+
* Authentication strategy used for the request.
28+
*/
29+
auth_strategy: string;
30+
31+
/**
32+
* Client IP address.
33+
*/
34+
client_ip: string;
35+
36+
/**
37+
* Request host.
38+
*/
39+
domain: string;
40+
41+
/**
42+
* Request duration in milliseconds.
43+
*/
44+
duration_ms: number;
45+
46+
/**
47+
* Email of the authenticated user at request time, if any.
48+
*/
49+
email: string;
50+
51+
/**
52+
* HTTP method.
53+
*/
54+
method: string;
55+
56+
/**
57+
* Request path.
58+
*/
59+
path: string;
60+
61+
/**
62+
* Matched API route pattern, if available.
63+
*/
64+
route: string;
65+
66+
/**
67+
* HTTP response status code.
68+
*/
69+
status: number;
70+
71+
/**
72+
* UTC time when the request was received.
73+
*/
74+
timestamp: string;
75+
76+
/**
77+
* User agent header.
78+
*/
79+
user_agent: string;
80+
81+
/**
82+
* ID of the authenticated user, if any.
83+
*/
84+
user_id: string;
85+
}
86+
87+
export interface AuditLogListParams extends PageTokenPaginationParams {
88+
/**
89+
* Upper bound (exclusive) for the audit record timestamp.
90+
*/
91+
end: string;
92+
93+
/**
94+
* Lower bound (inclusive) for the audit record timestamp.
95+
*/
96+
start: string;
97+
98+
/**
99+
* Filter by authentication strategy.
100+
*/
101+
auth_strategy?: string;
102+
103+
/**
104+
* Filter out results by HTTP method.
105+
*/
106+
exclude_method?: string;
107+
108+
/**
109+
* Filter by HTTP method.
110+
*/
111+
method?: string;
112+
113+
/**
114+
* Free-text search over path, user ID, email, client IP, and status.
115+
*/
116+
search?: string;
117+
118+
/**
119+
* Additional user IDs to OR into free-text search.
120+
*/
121+
search_user_id?: Array<string>;
122+
123+
/**
124+
* Filter by service name.
125+
*/
126+
service?: string;
127+
}
128+
129+
export declare namespace AuditLogs {
130+
export {
131+
type AuditLogEntry as AuditLogEntry,
132+
type AuditLogEntriesPageTokenPagination as AuditLogEntriesPageTokenPagination,
133+
type AuditLogListParams as AuditLogListParams,
134+
};
135+
}

src/resources/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ export {
1818
type AppListParams,
1919
type AppListResponsesOffsetPagination,
2020
} from './apps';
21+
export {
22+
AuditLogs,
23+
type AuditLogEntry,
24+
type AuditLogListParams,
25+
type AuditLogEntriesPageTokenPagination,
26+
} from './audit-logs';
2127
export { Auth } from './auth/auth';
2228
export {
2329
BrowserPools,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
import Kernel from '@onkernel/sdk';
4+
5+
const client = new Kernel({
6+
apiKey: 'My API Key',
7+
baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010',
8+
});
9+
10+
describe('resource auditLogs', () => {
11+
// Mock server tests are disabled
12+
test.skip('list: only required params', async () => {
13+
const responsePromise = client.auditLogs.list({
14+
end: '2026-01-02T00:00:00Z',
15+
start: '2026-01-01T00:00:00Z',
16+
});
17+
const rawResponse = await responsePromise.asResponse();
18+
expect(rawResponse).toBeInstanceOf(Response);
19+
const response = await responsePromise;
20+
expect(response).not.toBeInstanceOf(Response);
21+
const dataAndResponse = await responsePromise.withResponse();
22+
expect(dataAndResponse.data).toBe(response);
23+
expect(dataAndResponse.response).toBe(rawResponse);
24+
});
25+
26+
// Mock server tests are disabled
27+
test.skip('list: required and optional params', async () => {
28+
const response = await client.auditLogs.list({
29+
end: '2026-01-02T00:00:00Z',
30+
start: '2026-01-01T00:00:00Z',
31+
auth_strategy: 'auth_strategy',
32+
exclude_method: 'exclude_method',
33+
limit: 1,
34+
method: 'method',
35+
page_token: 'page_token',
36+
search: 'search',
37+
search_user_id: ['string'],
38+
service: 'service',
39+
});
40+
});
41+
});

0 commit comments

Comments
 (0)