Skip to content
Merged
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.67.0"
".": "0.68.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: 119
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-51549f813f3002e18c6ca8d850cc0c7932828d511c151e0412c73b6798d19e30.yml
openapi_spec_hash: ee77b293c4bda91c1a32cfdd12b8739e
config_hash: 57567e00b41af47cef1b78e51b747aa0
configured_endpoints: 120
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-d26459bd3514237e8d757be3cbdc76ca62f6083504b85601e57db830888964f7.yml
openapi_spec_hash: 5dd151a8099398819a97692c1c60c3c6
config_hash: 03c7e57f268c750e2415831662e95969
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
# Changelog

## 0.68.0 (2026-06-15)

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

### Features

* Add API key rotate endpoint ([c0d9f90](https://github.com/kernel/kernel-node-sdk/commit/c0d9f9023e79159def22465bb2249fdbd689cd98))
* **api:** surface deleted/expired API keys for audit trail (KERNEL-1350) ([2b7164c](https://github.com/kernel/kernel-node-sdk/commit/2b7164c38b4ecc99faf594914a6e2c6b4b094afb))


### Bug Fixes

* **pagination:** fail loudly when X-Has-More contradicts a missing X-Next-Offset ([994749d](https://github.com/kernel/kernel-node-sdk/commit/994749dd56176dfae27a60d9b8df6bf10c335eb8))
* **pagination:** stop on the X-Next-Offset 0 sentinel, not just has_more ([d318410](https://github.com/kernel/kernel-node-sdk/commit/d3184109680279c5c6565f730c874ae04c52a58d))
* **pagination:** stop skipping a page per auto-pagination iteration ([f7bf2d9](https://github.com/kernel/kernel-node-sdk/commit/f7bf2d92d25c85be6b0b33d6ce738f75917dceff))


### Styles

* prettier-format pagination test ([16ee899](https://github.com/kernel/kernel-node-sdk/commit/16ee899f00f755d72db94fe7cd37c1af1770d51f))


### Refactors

* **api:** align API key audit surface with browser sibling (KERNEL-1350) ([faf4119](https://github.com/kernel/kernel-node-sdk/commit/faf4119ff60ad8805c20e01f05ea59684dc91205))

## 0.67.0 (2026-06-11)

Full Changelog: [v0.66.0...v0.67.0](https://github.com/kernel/kernel-node-sdk/compare/v0.66.0...v0.67.0)
Expand Down
3 changes: 2 additions & 1 deletion api.md
Original file line number Diff line number Diff line change
Expand Up @@ -399,10 +399,11 @@ Types:
Methods:

- <code title="post /org/api_keys">client.apiKeys.<a href="./src/resources/api-keys.ts">create</a>({ ...params }) -> CreatedAPIKey</code>
- <code title="get /org/api_keys/{id}">client.apiKeys.<a href="./src/resources/api-keys.ts">retrieve</a>(id) -> APIKey</code>
- <code title="get /org/api_keys/{id}">client.apiKeys.<a href="./src/resources/api-keys.ts">retrieve</a>(id, { ...params }) -> APIKey</code>
- <code title="patch /org/api_keys/{id}">client.apiKeys.<a href="./src/resources/api-keys.ts">update</a>(id, { ...params }) -> APIKey</code>
- <code title="get /org/api_keys">client.apiKeys.<a href="./src/resources/api-keys.ts">list</a>({ ...params }) -> APIKeysOffsetPagination</code>
- <code title="delete /org/api_keys/{id}">client.apiKeys.<a href="./src/resources/api-keys.ts">delete</a>(id) -> void</code>
- <code title="post /org/api_keys/{id}/rotate">client.apiKeys.<a href="./src/resources/api-keys.ts">rotate</a>(id, { ...params }) -> CreatedAPIKey</code>

# CredentialProviders

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.67.0",
"version": "0.68.0",
"description": "The official TypeScript library for the Kernel API",
"author": "Kernel <>",
"types": "dist/index.d.ts",
Expand Down
4 changes: 4 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
APIKey,
APIKeyCreateParams,
APIKeyListParams,
APIKeyRetrieveParams,
APIKeyRotateParams,
APIKeyUpdateParams,
APIKeys,
APIKeysOffsetPagination,
Expand Down Expand Up @@ -1158,8 +1160,10 @@ export declare namespace Kernel {
type CreatedAPIKey as CreatedAPIKey,
type APIKeysOffsetPagination as APIKeysOffsetPagination,
type APIKeyCreateParams as APIKeyCreateParams,
type APIKeyRetrieveParams as APIKeyRetrieveParams,
type APIKeyUpdateParams as APIKeyUpdateParams,
type APIKeyListParams as APIKeyListParams,
type APIKeyRotateParams as APIKeyRotateParams,
};

export {
Expand Down
69 changes: 67 additions & 2 deletions src/resources/api-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ export class APIKeys extends APIResource {
* const apiKey = await client.apiKeys.retrieve('id');
* ```
*/
retrieve(id: string, options?: RequestOptions): APIPromise<APIKey> {
return this._client.get(path`/org/api_keys/${id}`, options);
retrieve(
id: string,
query: APIKeyRetrieveParams | null | undefined = {},
options?: RequestOptions,
): APIPromise<APIKey> {
return this._client.get(path`/org/api_keys/${id}`, { query, ...options });
}

/**
Expand Down Expand Up @@ -84,6 +88,24 @@ export class APIKeys extends APIResource {
headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
});
}

/**
* Rotate an API key. Issues a new key that copies the name and project of the
* rotated key, and schedules the rotated key to expire after a grace period so
* in-flight callers can swap over. The new plaintext key is returned once.
*
* @example
* ```ts
* const createdAPIKey = await client.apiKeys.rotate('id');
* ```
*/
rotate(
id: string,
body: APIKeyRotateParams | null | undefined = {},
options?: RequestOptions,
): APIPromise<CreatedAPIKey> {
return this._client.post(path`/org/api_keys/${id}/rotate`, { body, ...options });
}
}

export type APIKeysOffsetPagination = OffsetPagination<APIKey>;
Expand All @@ -101,6 +123,12 @@ export interface APIKey {

created_by: APIKey.CreatedBy;

/**
* When the API key was deleted (soft-deleted). Null for keys that have not been
* deleted.
*/
deleted_at: string | null;

/**
* When the API key expires
*/
Expand Down Expand Up @@ -174,6 +202,14 @@ export interface APIKeyCreateParams {
project_id?: string | null;
}

export interface APIKeyRetrieveParams {
/**
* When true, return the API key even if it has been deleted (soft-deleted), for
* audit purposes. Defaults to false, which returns 404 for a deleted key.
*/
include_deleted?: boolean;
}

export interface APIKeyUpdateParams {
/**
* New API key name
Expand All @@ -182,6 +218,12 @@ export interface APIKeyUpdateParams {
}

export interface APIKeyListParams extends OffsetPaginationParams {
/**
* Deprecated: use status=all instead. When true, include deleted (soft-deleted)
* API keys in the results for audit purposes.
*/
include_deleted?: boolean;

/**
* Case-insensitive substring match against API key name, creator, and project. API
* key identifiers and masked keys match by exact value or prefix.
Expand All @@ -197,6 +239,27 @@ export interface APIKeyListParams extends OffsetPaginationParams {
* Sort direction for API keys.
*/
sort_direction?: 'asc' | 'desc';

/**
* Filter API keys by status. "active" returns keys that are not deleted (default;
* expired-but-not-deleted keys are still included), "deleted" returns only
* soft-deleted keys, "all" returns both.
*/
status?: 'active' | 'deleted' | 'all';
}

export interface APIKeyRotateParams {
/**
* Lifetime in days for the new key, up to 3650. Omit to reuse the rotated key's
* original lifetime, or never-expires if it had none.
*/
days_to_expire?: number | null;

/**
* Grace period in days before the rotated key expires. Use 0 to expire it
* immediately. Omit for the default grace period of 7 days.
*/
expire_in_days?: number | null;
}

export declare namespace APIKeys {
Expand All @@ -205,7 +268,9 @@ export declare namespace APIKeys {
type CreatedAPIKey as CreatedAPIKey,
type APIKeysOffsetPagination as APIKeysOffsetPagination,
type APIKeyCreateParams as APIKeyCreateParams,
type APIKeyRetrieveParams as APIKeyRetrieveParams,
type APIKeyUpdateParams as APIKeyUpdateParams,
type APIKeyListParams as APIKeyListParams,
type APIKeyRotateParams as APIKeyRotateParams,
};
}
2 changes: 2 additions & 0 deletions src/resources/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ export {
type APIKey,
type CreatedAPIKey,
type APIKeyCreateParams,
type APIKeyRetrieveParams,
type APIKeyUpdateParams,
type APIKeyListParams,
type APIKeyRotateParams,
type APIKeysOffsetPagination,
} from './api-keys';
export {
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.67.0'; // x-release-please-version
export const VERSION = '0.68.0'; // x-release-please-version
34 changes: 34 additions & 0 deletions tests/api-resources/api-keys.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ describe('resource apiKeys', () => {
expect(dataAndResponse.response).toBe(rawResponse);
});

// Mock server tests are disabled
test.skip('retrieve: 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.apiKeys.retrieve('id', { include_deleted: true }, { path: '/_stainless_unknown_path' }),
).rejects.toThrow(Kernel.NotFoundError);
});

// Mock server tests are disabled
test.skip('update: only required params', async () => {
const responsePromise = client.apiKeys.update('id', { name: 'new-api-name' });
Expand Down Expand Up @@ -76,11 +84,13 @@ describe('resource apiKeys', () => {
await expect(
client.apiKeys.list(
{
include_deleted: true,
limit: 100,
offset: 0,
query: 'query',
sort_by: 'created_at',
sort_direction: 'asc',
status: 'active',
},
{ path: '/_stainless_unknown_path' },
),
Expand All @@ -98,4 +108,28 @@ describe('resource apiKeys', () => {
expect(dataAndResponse.data).toBe(response);
expect(dataAndResponse.response).toBe(rawResponse);
});

// Mock server tests are disabled
test.skip('rotate', async () => {
const responsePromise = client.apiKeys.rotate('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('rotate: 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.apiKeys.rotate(
'id',
{ days_to_expire: 30, expire_in_days: 7 },
{ path: '/_stainless_unknown_path' },
),
).rejects.toThrow(Kernel.NotFoundError);
});
});
Loading