diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 94994d4..e5a17c2 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.67.0" + ".": "0.68.0" } diff --git a/.stats.yml b/.stats.yml index a164009..2919208 100644 --- a/.stats.yml +++ b/.stats.yml @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index cd0a696..5ef0b92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/api.md b/api.md index 79b9205..7a48707 100644 --- a/api.md +++ b/api.md @@ -399,10 +399,11 @@ Types: Methods: - client.apiKeys.create({ ...params }) -> CreatedAPIKey -- client.apiKeys.retrieve(id) -> APIKey +- client.apiKeys.retrieve(id, { ...params }) -> APIKey - client.apiKeys.update(id, { ...params }) -> APIKey - client.apiKeys.list({ ...params }) -> APIKeysOffsetPagination - client.apiKeys.delete(id) -> void +- client.apiKeys.rotate(id, { ...params }) -> CreatedAPIKey # CredentialProviders diff --git a/package.json b/package.json index e2856f2..6e3d5cd 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/client.ts b/src/client.ts index 8a94d12..53d9a64 100644 --- a/src/client.ts +++ b/src/client.ts @@ -23,6 +23,8 @@ import { APIKey, APIKeyCreateParams, APIKeyListParams, + APIKeyRetrieveParams, + APIKeyRotateParams, APIKeyUpdateParams, APIKeys, APIKeysOffsetPagination, @@ -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 { diff --git a/src/resources/api-keys.ts b/src/resources/api-keys.ts index a855c96..60b41f5 100644 --- a/src/resources/api-keys.ts +++ b/src/resources/api-keys.ts @@ -34,8 +34,12 @@ export class APIKeys extends APIResource { * const apiKey = await client.apiKeys.retrieve('id'); * ``` */ - retrieve(id: string, options?: RequestOptions): APIPromise { - return this._client.get(path`/org/api_keys/${id}`, options); + retrieve( + id: string, + query: APIKeyRetrieveParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get(path`/org/api_keys/${id}`, { query, ...options }); } /** @@ -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 { + return this._client.post(path`/org/api_keys/${id}/rotate`, { body, ...options }); + } } export type APIKeysOffsetPagination = OffsetPagination; @@ -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 */ @@ -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 @@ -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. @@ -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 { @@ -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, }; } diff --git a/src/resources/index.ts b/src/resources/index.ts index 491319d..bc3f9ff 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -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 { diff --git a/src/version.ts b/src/version.ts index ed32717..71e7340 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.67.0'; // x-release-please-version +export const VERSION = '0.68.0'; // x-release-please-version diff --git a/tests/api-resources/api-keys.test.ts b/tests/api-resources/api-keys.test.ts index 14a45a0..b179ccf 100644 --- a/tests/api-resources/api-keys.test.ts +++ b/tests/api-resources/api-keys.test.ts @@ -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' }); @@ -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' }, ), @@ -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); + }); });