-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(stable): add support for sessions API (#1177)
- Loading branch information
Showing
6 changed files
with
312 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import type { SessionFilter } from 'stable/src/api/sessions/types'; | ||
import { beforeAll, describe, expect, test } from 'vitest'; | ||
import type CogniteClient from '../../cogniteClient'; | ||
import { setupLoggedInClient } from '../testUtils'; | ||
|
||
describe('Sessions integration test', () => { | ||
let testSessionId: number | undefined = undefined; | ||
let client: CogniteClient; | ||
|
||
beforeAll(async () => { | ||
client = setupLoggedInClient(); | ||
}); | ||
|
||
test('create', async () => { | ||
const clientSecret = process.env.COGNITE_CLIENT_SECRET || ''; | ||
const clientId = process.env.COGNITE_CLIENT_ID || ''; | ||
expect(clientSecret).toBeTruthy(); | ||
expect(clientId).toBeTruthy(); | ||
const result = await client.sessions.create([ | ||
{ | ||
clientSecret, | ||
clientId, | ||
}, | ||
]); | ||
|
||
expect(result).toHaveLength(1); | ||
expect(typeof result[0].id).toBe('number'); | ||
testSessionId = result[0].id; | ||
|
||
expect(result[0].status).toBe('READY'); | ||
expect(typeof result[0].nonce).toBe('string'); | ||
expect(result[0].type).toBe('CLIENT_CREDENTIALS'); | ||
expect(result[0].clientId).toBe(clientId); | ||
}); | ||
|
||
test('list', async () => { | ||
expect(testSessionId).toBeTruthy(); | ||
const filter: SessionFilter = { status: 'READY' }; | ||
const items = await client.sessions.list({ filter }).autoPagingToArray(); | ||
|
||
expect(items.length).toBeGreaterThan(0); | ||
const foundSession = items.find((session) => session.id === testSessionId); | ||
expect(foundSession).toBeDefined(); | ||
expect(foundSession?.creationTime).toBeLessThan(Date.now()); | ||
expect(foundSession?.expirationTime).toBeGreaterThan(Date.now()); | ||
}); | ||
|
||
test('retrieve', async () => { | ||
expect(testSessionId).toBeTruthy(); | ||
const result = await client.sessions.retrieve([{ id: testSessionId }]); | ||
expect(result).toHaveLength(1); | ||
expect(result[0].id).toBe(testSessionId); | ||
}); | ||
|
||
test('revoke', async () => { | ||
expect(testSessionId).toBeTruthy(); | ||
const result = await client.sessions.revoke([{ id: testSessionId }]); | ||
expect(result).toHaveLength(1); | ||
expect(result[0].status).toBe('REVOKED'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import nock from 'nock'; | ||
import { beforeEach, describe, expect, test } from 'vitest'; | ||
import type CogniteClient from '../../cogniteClient'; | ||
import { mockBaseUrl, setupMockableClient } from '../testUtils'; | ||
|
||
describe('Sessions unit test', () => { | ||
let client: CogniteClient; | ||
|
||
beforeEach(() => { | ||
nock.cleanAll(); | ||
client = setupMockableClient(); | ||
}); | ||
|
||
test('create', async () => { | ||
const createItem = { tokenExchange: true as const }; | ||
const response = { | ||
items: [{ id: 1, status: 'ACTIVE', nonce: 'abc' }], | ||
}; | ||
|
||
nock(mockBaseUrl) | ||
.post(/\/sessions/) | ||
.reply(200, response); | ||
|
||
const result = await client.sessions.create([createItem]); | ||
expect(result).toEqual(response.items); | ||
}); | ||
|
||
test('list', async () => { | ||
const filter = { status: 'ACTIVE' as const }; | ||
const response = { items: [{ id: 1, status: 'ACTIVE' }] }; | ||
|
||
nock(mockBaseUrl) | ||
.get(/\/sessions/) | ||
.query(filter) | ||
.reply(200, response); | ||
|
||
const items = await client.sessions.list({ filter }).autoPagingToArray(); | ||
expect(items).toEqual(response.items); | ||
}); | ||
|
||
test('retrieve', async () => { | ||
const ids = [{ id: 1 }]; | ||
const response = { items: [{ id: 1, status: 'ACTIVE' }] }; | ||
|
||
nock(mockBaseUrl) | ||
.post(/\/sessions\/byids/) | ||
.reply(200, response); | ||
|
||
const result = await client.sessions.retrieve(ids); | ||
expect(result).toEqual(response.items); | ||
}); | ||
|
||
test('revoke', async () => { | ||
const ids = [{ id: 1 }]; | ||
const response = { items: [{ id: 1, status: 'REVOKED' }] }; | ||
|
||
nock(mockBaseUrl) | ||
.post(/\/sessions\/revoke/) | ||
.reply(200, response); | ||
|
||
const result = await client.sessions.revoke(ids); | ||
expect(result).toEqual(response.items); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { | ||
BaseResourceAPI, | ||
type InternalId, | ||
type ItemsResponse, | ||
type ItemsWrapper, | ||
} from '@cognite/sdk-core'; | ||
import type { | ||
Session, | ||
SessionCreate, | ||
SessionCreateResultItem, | ||
SessionFilterQuery, | ||
} from './types'; | ||
|
||
export class SessionsApi extends BaseResourceAPI<Session> { | ||
/** | ||
* [Create a session](https://api-docs.cognite.com/20230101/tag/Sessions/operation/createSessions) | ||
* | ||
* ```js | ||
* client.sessions.create([{ clientId: 'client-id', clientSecret: 'client-secret' }]) | ||
* ``` | ||
* */ | ||
public create = async ( | ||
items: SessionCreate[] | ||
): Promise<SessionCreateResultItem[]> => { | ||
const response = await this.post<ItemsWrapper<SessionCreateResultItem[]>>( | ||
this.url(), | ||
{ data: { items } } | ||
); | ||
return response.data.items; | ||
}; | ||
|
||
/** | ||
* [List sessions](https://api-docs.cognite.com/20230101/tag/Sessions/operation/listSessions) | ||
* | ||
* ```js | ||
* client.sessions.list({ filter: { status: 'ACTIVE' } }) | ||
* ``` | ||
*/ | ||
public list = (query?: SessionFilterQuery) => { | ||
const { filter, ...rest } = query || {}; | ||
return this.listEndpoint(this.callListEndpointWithGet, { | ||
...rest, | ||
...filter, | ||
}); | ||
}; | ||
|
||
/** | ||
* [Retrieve sessions with given IDs](https://api-docs.cognite.com/20230101/tag/Sessions/operation/getSessionsByIds) | ||
* | ||
* ```js | ||
* client.sessions.retrieve([{ id: 1 }]) | ||
* ``` | ||
*/ | ||
public retrieve = (ids: InternalId[]) => { | ||
return this.retrieveEndpoint(ids); | ||
}; | ||
|
||
/** | ||
* [Revoke access to a session](https://api-docs.cognite.com/20230101/tag/Sessions/operation/revokeSessions) | ||
* | ||
* ```js | ||
* client.sessions.revoke([{ id: 1 }]) | ||
* ``` | ||
*/ | ||
async revoke(ids: InternalId[]) { | ||
const url = this.url('revoke'); | ||
const res = await this.post<ItemsResponse<Session>>(url, { | ||
data: { items: ids }, | ||
}); | ||
return res.data.items; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import type { EpochTimestamp, FilterQuery } from '../../types'; | ||
|
||
export type SessionStatus = | ||
| 'READY' | ||
| 'ACTIVE' | ||
| 'CANCELLED' | ||
| 'EXPIRED' | ||
| 'REVOKED' | ||
| 'ACCESS_LOST'; | ||
|
||
export const SessionStatus = { | ||
READY: 'READY' as SessionStatus, | ||
ACTIVE: 'ACTIVE' as SessionStatus, | ||
CANCELLED: 'CANCELLED' as SessionStatus, | ||
EXPIRED: 'EXPIRED' as SessionStatus, | ||
REVOKED: 'REVOKED' as SessionStatus, | ||
ACCESS_LOST: 'ACCESS_LOST' as SessionStatus, | ||
}; | ||
|
||
export type SessionType = | ||
| 'CLIENT_CREDENTIALS' | ||
| 'TOKEN_EXCHANGE' | ||
| 'ONESHOT_TOKEN_EXCHANGE'; | ||
|
||
export const SessionType = { | ||
CLIENT_CREDENTIALS: 'CLIENT_CREDENTIALS' as SessionType, | ||
TOKEN_EXCHANGE: 'TOKEN_EXCHANGE' as SessionType, | ||
ONESHOT_TOKEN_EXCHANGE: 'ONESHOT_TOKEN_EXCHANGE' as SessionType, | ||
}; | ||
|
||
/** | ||
* A response with the ID, nonce and other information related to the session. The nonce | ||
is short-lived and should be immediately passed to the endpoint that will use | ||
the session. | ||
*/ | ||
export interface SessionCreateResultItem { | ||
/** ID of the session */ | ||
id: number; | ||
/** Client ID in identity provider. Returned only if the session was created using client credentials */ | ||
clientId?: string; | ||
/** Nonce to be passed to the internal service that will bind the session */ | ||
nonce: string; | ||
/** Current status of the session */ | ||
status: SessionStatus; | ||
/** Values reserved for future use */ | ||
type?: SessionType; | ||
} | ||
|
||
/** | ||
* Credentials for a session using client credentials from an identity provider. | ||
*/ | ||
export interface SessionWithClientCredentialsCreate { | ||
/** Client ID in identity provider */ | ||
clientId: string; | ||
/** Client secret in identity provider */ | ||
clientSecret: string; | ||
} | ||
/** | ||
* Credentials for a session using one-shot token exchange to reuse the user's credentials. | ||
One-shot sessions are short-lived sessions that are not refreshed and do not require support for token exchange from the identity provider. | ||
*/ | ||
export interface SessionWithOneshotTokenExchangeCreate { | ||
/** Use one-shot token exchange for the session. Must be `true`. */ | ||
oneshotTokenExchange: true; | ||
} | ||
/** | ||
* Credentials for a session using token exchange to reuse the user's credentials. | ||
*/ | ||
export interface SessionWithTokenExchangeCreate { | ||
/** Use token exchange for the session. Must be `true`. */ | ||
tokenExchange: true; | ||
} | ||
|
||
export type SessionCreate = | ||
| SessionWithClientCredentialsCreate | ||
| SessionWithTokenExchangeCreate | ||
| SessionWithOneshotTokenExchangeCreate; | ||
|
||
export interface SessionFilter { | ||
/** Current status of the session */ | ||
status?: | ||
| 'READY' | ||
| 'ACTIVE' | ||
| 'CANCELLED' | ||
| 'EXPIRED' | ||
| 'REVOKED' | ||
| 'ACCESS_LOST'; | ||
} | ||
|
||
export interface SessionFilterQuery extends FilterQuery { | ||
filter?: SessionFilter; | ||
} | ||
|
||
export interface Session { | ||
/** ID of the session */ | ||
id?: number; | ||
/** Client ID in identity provider. Returned only if the session was created using client credentials */ | ||
clientId?: string; | ||
/** Session creation time, in milliseconds since 1970 */ | ||
creationTime?: EpochTimestamp; | ||
/** Session expiry time, in milliseconds since 1970. This value is updated on refreshing a token */ | ||
expirationTime?: EpochTimestamp; | ||
/** Current status of the session */ | ||
status?: SessionStatus; | ||
/** Values reserved for future use */ | ||
type?: SessionType; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters