@epsbv/oauth-sdk 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +4 -0
- package/build/client.d.ts +10 -0
- package/build/client.js +24 -0
- package/build/const.d.ts +2 -0
- package/build/const.js +3 -0
- package/build/error.d.ts +20 -0
- package/build/error.js +67 -0
- package/build/identity/index.d.ts +35 -0
- package/build/identity/index.js +56 -0
- package/build/identity/types.d.ts +22 -0
- package/build/identity/types.js +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.js +4 -0
- package/build/oauth/index.d.ts +15 -0
- package/build/oauth/index.js +105 -0
- package/build/oauth/types.d.ts +108 -0
- package/build/oauth/types.js +1 -0
- package/build/tenant/index.d.ts +102 -0
- package/build/tenant/index.js +131 -0
- package/build/tenant/types.d.ts +44 -0
- package/build/tenant/types.js +17 -0
- package/build/tsconfig.tsbuildinfo +1 -0
- package/build/types.d.ts +15 -0
- package/build/types.js +13 -0
- package/build/utils/fetch.d.ts +8 -0
- package/build/utils/fetch.js +134 -0
- package/build/utils/secret.d.ts +4 -0
- package/build/utils/secret.js +19 -0
- package/package.json +27 -0
- package/src/client.ts +34 -0
- package/src/const.ts +4 -0
- package/src/error.ts +82 -0
- package/src/identity/index.ts +74 -0
- package/src/identity/types.ts +52 -0
- package/src/index.ts +4 -0
- package/src/oauth/index.ts +137 -0
- package/src/oauth/types.ts +114 -0
- package/src/tenant/index.ts +211 -0
- package/src/tenant/types.ts +57 -0
- package/src/types.ts +17 -0
- package/src/utils/fetch.ts +161 -0
- package/src/utils/secret.ts +28 -0
- package/tsconfig.json +16 -0
package/src/error.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export class FetchError extends Error {
|
|
2
|
+
constructor(cause: unknown) {
|
|
3
|
+
super("Failed to send request", {
|
|
4
|
+
cause
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class RequestError extends Error {
|
|
10
|
+
public code: string;
|
|
11
|
+
public description: string | null;
|
|
12
|
+
public uri: string | null;
|
|
13
|
+
public state: string | null;
|
|
14
|
+
|
|
15
|
+
constructor(code: string, description: string | null, uri: string | null, state: string | null) {
|
|
16
|
+
super(`OAuth request error: ${code}`);
|
|
17
|
+
|
|
18
|
+
this.code = code;
|
|
19
|
+
this.description = description;
|
|
20
|
+
this.uri = uri;
|
|
21
|
+
this.state = state;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public static create(result: object) : RequestError{
|
|
25
|
+
let code: string;
|
|
26
|
+
|
|
27
|
+
if ("error" in result && typeof result.error === "string") {
|
|
28
|
+
code = result.error;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
throw new Error("Invalid error response");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let description: string | null = null;
|
|
35
|
+
let uri: string | null = null;
|
|
36
|
+
let state: string | null = null;
|
|
37
|
+
|
|
38
|
+
if ("error_description" in result) {
|
|
39
|
+
if (typeof result.error_description !== "string") {
|
|
40
|
+
throw new Error("Invalid data");
|
|
41
|
+
}
|
|
42
|
+
description = result.error_description;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if ("error_uri" in result) {
|
|
46
|
+
if (typeof result.error_uri !== "string") {
|
|
47
|
+
throw new Error("Invalid data");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
uri = result.error_uri;
|
|
51
|
+
}
|
|
52
|
+
if ("state" in result) {
|
|
53
|
+
if (typeof result.state !== "string") {
|
|
54
|
+
throw new Error("Invalid data");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
state = result.state;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return new RequestError(code, description, uri, state)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export class UnexpectedResponseError extends Error {
|
|
65
|
+
public status: number;
|
|
66
|
+
|
|
67
|
+
constructor(responseStatus: number) {
|
|
68
|
+
super("Unexpected error response");
|
|
69
|
+
this.status = responseStatus;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class UnexpectedErrorResponseBodyError extends Error {
|
|
74
|
+
public status: number;
|
|
75
|
+
public data: unknown;
|
|
76
|
+
|
|
77
|
+
constructor(status: number, data: unknown) {
|
|
78
|
+
super("Unexpected error response body");
|
|
79
|
+
this.status = status;
|
|
80
|
+
this.data = data;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Device, Identity } from "./types";
|
|
2
|
+
import { ApiClient } from "../client";
|
|
3
|
+
import { ClientOptions, Language } from "../types";
|
|
4
|
+
import { apiUrl } from "../const";
|
|
5
|
+
|
|
6
|
+
export * from './types'
|
|
7
|
+
|
|
8
|
+
export class IdentityClient extends ApiClient {
|
|
9
|
+
constructor({ token }: Omit<ClientOptions, 'baseUrl'>) {
|
|
10
|
+
super({ token, baseUrl: apiUrl })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get info() {
|
|
14
|
+
return new Identity$Info(this.options)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get avatar() {
|
|
18
|
+
return new Identity$Avatar(this.options)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get devices() {
|
|
22
|
+
return new Identity$Devices(this.options)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class Identity$Info extends ApiClient {
|
|
27
|
+
constructor(options: ClientOptions) {
|
|
28
|
+
super(options)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async get() {
|
|
32
|
+
return await this.fetchUrlEncoded<Identity>('/e/identity', 'GET')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async delete() {
|
|
36
|
+
return await this.fetchUrlEncoded('/e/identity', 'DELETE')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async update(body: { first_name: string, last_name: string, language: Language }): Promise<{}> {
|
|
40
|
+
return await this.fetchUrlEncoded('/e/identity', 'PUT', { body })
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class Identity$Avatar extends ApiClient {
|
|
45
|
+
constructor(options: ClientOptions) {
|
|
46
|
+
super(options)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async get() {
|
|
50
|
+
return await this.fetchUrlEncoded<string>('/e/identity/avatar', 'GET')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async delete() {
|
|
54
|
+
return await this.fetchUrlEncoded('/e/identity/avatar', 'DELETE')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async update(body: { avatar: File }): Promise<{}> {
|
|
58
|
+
return await this.fetchMultipart('/e/identity/avatar', 'PUT', { body })
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
class Identity$Devices extends ApiClient {
|
|
63
|
+
constructor(options: ClientOptions) {
|
|
64
|
+
super(options)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async get() {
|
|
68
|
+
return await this.fetchUrlEncoded<Device[]>('/e/identity/devices', 'GET')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async delete({ id }: { id: string }) {
|
|
72
|
+
return await this.fetchUrlEncoded(`/e/identity/devices/${id}`, 'DELETE')
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Language, Status } from "../types"
|
|
2
|
+
|
|
3
|
+
// export enum OrginizationType {
|
|
4
|
+
// Admin = "admin",
|
|
5
|
+
// Distributor = "distributor",
|
|
6
|
+
// Builder = "builder"
|
|
7
|
+
// }
|
|
8
|
+
|
|
9
|
+
// export enum OrganizationRole {
|
|
10
|
+
// Ceo = "ceo",
|
|
11
|
+
// Admin = "admin",
|
|
12
|
+
// Member = "member"
|
|
13
|
+
// }
|
|
14
|
+
|
|
15
|
+
// export interface Originization {
|
|
16
|
+
// id: string
|
|
17
|
+
// name: string
|
|
18
|
+
// type: OrginizationType
|
|
19
|
+
// role: OrganizationRole
|
|
20
|
+
// email: string
|
|
21
|
+
// avatar: string | undefined
|
|
22
|
+
// status: Status
|
|
23
|
+
// parent: string,
|
|
24
|
+
// language: Language,
|
|
25
|
+
// created_at: Date,
|
|
26
|
+
// updated_at: Date,
|
|
27
|
+
// }
|
|
28
|
+
|
|
29
|
+
export interface Identity {
|
|
30
|
+
uid: string,
|
|
31
|
+
admin: boolean,
|
|
32
|
+
email: string,
|
|
33
|
+
avatar?: string,
|
|
34
|
+
first_name: string,
|
|
35
|
+
last_name: string,
|
|
36
|
+
language: Language,
|
|
37
|
+
|
|
38
|
+
provider: 'google' | 'internal' | 'microsoft' | 'apple',
|
|
39
|
+
provider_id: string | undefined
|
|
40
|
+
|
|
41
|
+
created_at: Date,
|
|
42
|
+
updated_at: Date,
|
|
43
|
+
verified_at?: Date,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface Device {
|
|
47
|
+
id: string,
|
|
48
|
+
name: string,
|
|
49
|
+
type: string,
|
|
50
|
+
created_at: Date,
|
|
51
|
+
activity_at: Date
|
|
52
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { OAuthTokens, OAuthUrlOptions, type OAuthClientOptions } from "./types";
|
|
2
|
+
import { FetchMethod, FetchOptions, fetchUrlEncoded } from "../utils/fetch";
|
|
3
|
+
import { apiUrl, oauthUrl } from "../const";
|
|
4
|
+
import { encodeCredentials } from "../utils/secret";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export { generateState, generateCodeVerifier, createS256CodeChallenge } from '../utils/secret'
|
|
8
|
+
|
|
9
|
+
const authorizationEndpoint = `${oauthUrl}/oauth/auth`;
|
|
10
|
+
|
|
11
|
+
export class OAuthClient {
|
|
12
|
+
private clientId: string;
|
|
13
|
+
private redirectURI: string;
|
|
14
|
+
private credentials: string
|
|
15
|
+
|
|
16
|
+
constructor({ clientId, clientSecret, redirectURI }: OAuthClientOptions) {
|
|
17
|
+
this.clientId = clientId;
|
|
18
|
+
this.redirectURI = redirectURI;
|
|
19
|
+
|
|
20
|
+
this.credentials = encodeCredentials(clientId, clientSecret);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Generate an authorization URL
|
|
24
|
+
public createAuthorizationURL(options: OAuthUrlOptions): URL {
|
|
25
|
+
return this.createAuthorizationURLWithPKCE(options)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private createAuthorizationURLWithPKCE({ state, code_challenge_method, code_challenge, scope, response_type, access_type, include_granted_scopes, prompt }: OAuthUrlOptions) {
|
|
29
|
+
const url = new URL(authorizationEndpoint);
|
|
30
|
+
|
|
31
|
+
url.searchParams.set('state', state)
|
|
32
|
+
url.searchParams.set('client_id', this.clientId);
|
|
33
|
+
url.searchParams.set('access_type', access_type ?? 'online'); // determines 'refresh' or 'access' token
|
|
34
|
+
url.searchParams.set('response_type', response_type); // determines if parameters returned are in fragment identifier or search params
|
|
35
|
+
url.searchParams.set('redirect_uri', this.redirectURI);
|
|
36
|
+
|
|
37
|
+
if (prompt) {
|
|
38
|
+
url.searchParams.set('prompt', prompt);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (include_granted_scopes != undefined) {
|
|
42
|
+
url.searchParams.set('include_granted_scopes', `${include_granted_scopes}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (code_challenge_method) {
|
|
46
|
+
url.searchParams.set('code_challenge_method', code_challenge_method)
|
|
47
|
+
|
|
48
|
+
if (code_challenge) {
|
|
49
|
+
url.searchParams.set('code_challenge', code_challenge)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (scope.length > 0) {
|
|
54
|
+
url.searchParams.set('scope', scope.join(' '))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return url;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public async getToken(code: string, codeVerifier?: string) {
|
|
61
|
+
// Retreive the token from the OAuth server
|
|
62
|
+
try {
|
|
63
|
+
return await this.fetch<OAuthTokens>('/e/oauth/token', 'POST', {
|
|
64
|
+
body: {
|
|
65
|
+
grant_type: 'authorization_code',
|
|
66
|
+
code,
|
|
67
|
+
redirect_uri: this.redirectURI,
|
|
68
|
+
code_verifier: codeVerifier
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// const { header } = jwt.decode(token, { complete: true })
|
|
73
|
+
// const { keys } = await this.fetch<Jwks>('/oauth/jwks', 'GET')
|
|
74
|
+
|
|
75
|
+
// const certificate = keys[0];
|
|
76
|
+
|
|
77
|
+
// console.log(keys)
|
|
78
|
+
|
|
79
|
+
// if (certificate) {
|
|
80
|
+
// jwt.verify(
|
|
81
|
+
// token,
|
|
82
|
+
// `-----BEGIN PUBLIC KEY-----\n${certificate.x5c[0]}\n-----END PUBLIC KEY-----`, {
|
|
83
|
+
// algorithms: [certificate.alg]
|
|
84
|
+
// })
|
|
85
|
+
|
|
86
|
+
// }
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
throw new Error(error)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public async refreshAccessToken(refresh_token: string) {
|
|
94
|
+
try {
|
|
95
|
+
return await this.fetch<OAuthTokens>('/e/oauth/token', 'POST', {
|
|
96
|
+
body: {
|
|
97
|
+
grant_type: 'refresh_token',
|
|
98
|
+
refresh_token: refresh_token,
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// const { header } = jwt.decode(token, { complete: true })
|
|
103
|
+
// const { keys } = await this.fetch<Jwks>('/oauth/jwks', 'GET')
|
|
104
|
+
|
|
105
|
+
// const certificate = keys[0];
|
|
106
|
+
|
|
107
|
+
// console.log(keys)
|
|
108
|
+
|
|
109
|
+
// if (certificate) {
|
|
110
|
+
// jwt.verify(
|
|
111
|
+
// token,
|
|
112
|
+
// `-----BEGIN PUBLIC KEY-----\n${certificate.x5c[0]}\n-----END PUBLIC KEY-----`, {
|
|
113
|
+
// algorithms: [certificate.alg]
|
|
114
|
+
// })
|
|
115
|
+
|
|
116
|
+
// }
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
throw new Error(error)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public async revokeToken(token: string) {
|
|
124
|
+
await fetchUrlEncoded(`${apiUrl}/e/oauth/revoke`, 'POST', {
|
|
125
|
+
body: { token }
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async fetch<T>(endpoint: string, method: FetchMethod, params?: FetchOptions): Promise<T> {
|
|
130
|
+
const headers = new Headers(params?.headers ?? {});
|
|
131
|
+
|
|
132
|
+
headers.append('User-Agent', 'eps/oauth-client')
|
|
133
|
+
headers.append('Authorization', `Bearer ${this.credentials}`)
|
|
134
|
+
|
|
135
|
+
return await fetchUrlEncoded<T>(`${apiUrl}${endpoint}`, method, { body: params?.body ?? null, headers });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Algorithm } from "jsonwebtoken";
|
|
2
|
+
|
|
3
|
+
export type OAuthScope = 'email' | 'profile'
|
|
4
|
+
|
|
5
|
+
export interface OAuthClientOptions {
|
|
6
|
+
clientId: string,
|
|
7
|
+
clientSecret: string,
|
|
8
|
+
redirectURI: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface OAuthUrlOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Recommended. Indicates whether your application can refresh access tokens
|
|
14
|
+
* when the user is not present at the browser. Valid parameter values are
|
|
15
|
+
* 'online', which is the default value, and 'offline'. Set the value to
|
|
16
|
+
* 'offline' if your application needs to refresh access tokens when the user
|
|
17
|
+
* is not present at the browser. This value instructs the Google
|
|
18
|
+
* authorization server to return a refresh token and an access token the
|
|
19
|
+
* first time that your application exchanges an authorization code for
|
|
20
|
+
* tokens.
|
|
21
|
+
*/
|
|
22
|
+
access_type?: 'online' | 'offline';
|
|
23
|
+
/**
|
|
24
|
+
* Defaults back to 'code''.
|
|
25
|
+
*/
|
|
26
|
+
response_type: 'code' | 'token';
|
|
27
|
+
/**
|
|
28
|
+
* Required. A space-delimited list of scopes that identify the resources that
|
|
29
|
+
* your application could access on the user's behalf. These values inform the
|
|
30
|
+
* consent screen that Google displays to the user. Scopes enable your
|
|
31
|
+
* application to only request access to the resources that it needs while
|
|
32
|
+
* also enabling users to control the amount of access that they grant to your
|
|
33
|
+
* application. Thus, there is an inverse relationship between the number of
|
|
34
|
+
* scopes requested and the likelihood of obtaining user consent. The
|
|
35
|
+
* OAuth 2.0 API Scopes document provides a full list of scopes that you might
|
|
36
|
+
* use to access Google APIs. We recommend that your application request
|
|
37
|
+
* access to authorization scopes in context whenever possible. By requesting
|
|
38
|
+
* access to user data in context, via incremental authorization, you help
|
|
39
|
+
* users to more easily understand why your application needs the access it is
|
|
40
|
+
* requesting.
|
|
41
|
+
*/
|
|
42
|
+
scope?: OAuthScope[];
|
|
43
|
+
/**
|
|
44
|
+
* Recommended. Specifies any string value that your application uses to
|
|
45
|
+
* maintain state between your authorization request and the authorization
|
|
46
|
+
* server's response. The server returns the exact value that you send as a
|
|
47
|
+
* name=value pair in the hash (#) fragment of the 'redirect_uri' after the
|
|
48
|
+
* user consents to or denies your application's access request. You can use
|
|
49
|
+
* this parameter for several purposes, such as directing the user to the
|
|
50
|
+
* correct resource in your application, sending nonces, and mitigating
|
|
51
|
+
* cross-site request forgery. Since your redirect_uri can be guessed, using a
|
|
52
|
+
* state value can increase your assurance that an incoming connection is the
|
|
53
|
+
* result of an authentication request. If you generate a random string or
|
|
54
|
+
* encode the hash of a cookie or another value that captures the client's
|
|
55
|
+
* state, you can validate the response to additionally ensure that the
|
|
56
|
+
* request and response originated in the same browser, providing protection
|
|
57
|
+
* against attacks such as cross-site request forgery. See the OpenID Connect
|
|
58
|
+
* documentation for an example of how to create and confirm a state token.
|
|
59
|
+
*/
|
|
60
|
+
state?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Optional. Enables applications to use incremental authorization to request
|
|
63
|
+
* access to additional scopes in context. If you set this parameter's value
|
|
64
|
+
* to true and the authorization request is granted, then the new access token
|
|
65
|
+
* will also cover any scopes to which the user previously granted the
|
|
66
|
+
* application access. See the incremental authorization section for examples.
|
|
67
|
+
*/
|
|
68
|
+
include_granted_scopes?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Optional. A space-delimited, case-sensitive list of prompts to present the
|
|
71
|
+
* user. If you don't specify this parameter, the user will be prompted only
|
|
72
|
+
* the first time your app requests access. Possible values are:
|
|
73
|
+
*
|
|
74
|
+
* 'none' - Donot display any authentication or consent screens. Must not be
|
|
75
|
+
* specified with other values.
|
|
76
|
+
* 'consent' - Prompt the user for consent.
|
|
77
|
+
* 'select_account' - Prompt the user to select an account.
|
|
78
|
+
*/
|
|
79
|
+
prompt?: 'consent' | 'select_account';
|
|
80
|
+
/**
|
|
81
|
+
* Recommended. Specifies what method was used to encode a 'code_verifier'
|
|
82
|
+
* that will be used during authorization code exchange. This parameter must
|
|
83
|
+
* be used with the 'code_challenge' parameter. The value of the
|
|
84
|
+
* 'code_challenge_method' defaults to "plain" if not present in the request
|
|
85
|
+
* that includes a 'code_challenge'. The only supported values for this
|
|
86
|
+
* parameter are "S256" or "plain".
|
|
87
|
+
*/
|
|
88
|
+
code_challenge_method?: 'S256' | 'plain';
|
|
89
|
+
/**
|
|
90
|
+
* Recommended. Specifies an encoded 'code_verifier' that will be used as a
|
|
91
|
+
* server-side challenge during authorization code exchange. This parameter
|
|
92
|
+
* must be used with the 'code_challenge' parameter described above.
|
|
93
|
+
*/
|
|
94
|
+
code_challenge?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface OAuthTokens {
|
|
98
|
+
access_token: string,
|
|
99
|
+
refresh_token?: string
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface Jwks {
|
|
103
|
+
keys: Jwk[]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface Jwk {
|
|
107
|
+
alg: Algorithm,
|
|
108
|
+
e: string,
|
|
109
|
+
kid: string,
|
|
110
|
+
kty: string
|
|
111
|
+
n: string,
|
|
112
|
+
use: string
|
|
113
|
+
x5c: string[]
|
|
114
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { ApiClient } from "../client";
|
|
2
|
+
import { apiUrl } from "../const";
|
|
3
|
+
import { ClientOptions, Language } from "../types";
|
|
4
|
+
import { Client, ClientType, Tenant, TenantRole, TenantUser } from "./types";
|
|
5
|
+
|
|
6
|
+
export * from './types'
|
|
7
|
+
|
|
8
|
+
// interface List<T> {
|
|
9
|
+
// page: number,
|
|
10
|
+
// page_count: number
|
|
11
|
+
// items: T[]
|
|
12
|
+
// }
|
|
13
|
+
|
|
14
|
+
export class TenantClient extends ApiClient {
|
|
15
|
+
constructor({ token }: Omit<ClientOptions, 'baseUrl'>) {
|
|
16
|
+
super({ token, baseUrl: apiUrl })
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get info() {
|
|
20
|
+
return new Tenant$Info(this.options)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get avatar() {
|
|
24
|
+
return new Tenant$Avatar(this.options)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get users() {
|
|
28
|
+
return new Tenant$Users(this.options)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get partners() {
|
|
32
|
+
return new Tenant$Partners(this.options)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// get clients() {
|
|
36
|
+
// return null
|
|
37
|
+
// }
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
// async info() {
|
|
45
|
+
// return await this.fetchUrlEncoded<Tenant>('/e/tenant/info', 'GET')
|
|
46
|
+
// }
|
|
47
|
+
|
|
48
|
+
// async role() {
|
|
49
|
+
// return await this.fetchUrlEncoded<Tenant>('/tenant/role', 'GET')
|
|
50
|
+
// }
|
|
51
|
+
|
|
52
|
+
// async children(page?: number) {
|
|
53
|
+
// return await this.fetchUrlEncoded<List<Tenant>>(`/tenant/children?page=${page ?? 0}`, 'GET')
|
|
54
|
+
// }
|
|
55
|
+
|
|
56
|
+
// members() {
|
|
57
|
+
// return {
|
|
58
|
+
// list: () => this.fetchUrlEncoded<TenantMember[]>('/tenant/members', 'GET'),
|
|
59
|
+
// get: (uid: string) => this.fetchUrlEncoded<TenantMember>(`/tenant/members/${uid}`, 'GET'),
|
|
60
|
+
// }
|
|
61
|
+
// }
|
|
62
|
+
|
|
63
|
+
// clients() {
|
|
64
|
+
// return {
|
|
65
|
+
// list: () => this.fetchUrlEncoded<Client[]>('/tenant/clients', 'GET'),
|
|
66
|
+
// get: (id: string) => this.fetchUrlEncoded<Client>(`/tenant/clients/${id}`, 'GET'),
|
|
67
|
+
// // delete: (id: string) => this.fetch(`/tenant/clients/${id}`, 'DELETE'),
|
|
68
|
+
// // create: (name: string, type: ClientType, redirect_uri: string) => this.fetch<Client>(`/tenant/clients`, 'POST', { body: { name, type, redirect_uri } }),
|
|
69
|
+
// // update: (id: string, body: { name: string, redirect_uri: string }) => this.fetch<any>(`/tenant/clients/${id}`, 'PUT', { body }),
|
|
70
|
+
// }
|
|
71
|
+
// }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
class Tenant$Partners extends ApiClient {
|
|
75
|
+
constructor(options: ClientOptions) {
|
|
76
|
+
super(options)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get users() {
|
|
80
|
+
return new Tenant$Partners$Users(this.options)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get avatar() {
|
|
84
|
+
return new Tenant$Partners$Avatar(this.options)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async list() {
|
|
88
|
+
return await this.fetchUrlEncoded<Tenant[]>(`/e/tenant/partners`, 'GET')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async get(params: { id: string }) {
|
|
92
|
+
return await this.fetchUrlEncoded<Tenant>(`/e/tenant/partners/${params.id}`, 'GET')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// async create(params: { email: string, org_name: string, org_email: string, org_language: Language }) {
|
|
96
|
+
// return await this.fetchUrlEncoded<Tenant>(`/e/tenant/partners`, 'POST', {
|
|
97
|
+
// body: params
|
|
98
|
+
// })
|
|
99
|
+
// }
|
|
100
|
+
|
|
101
|
+
async update(params: { id: string, data: { name: string, email: string, language: Language } }) {
|
|
102
|
+
return await this.fetchUrlEncoded(`/e/tenant/partners/${params.id}`, 'PUT', {
|
|
103
|
+
body: params.data
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async delete(params: { id: string }) {
|
|
108
|
+
return await this.fetchUrlEncoded(`/e/tenant/partners/${params.id}`, 'DELETE')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
class Tenant$Partners$Avatar extends ApiClient {
|
|
114
|
+
constructor(options: ClientOptions) {
|
|
115
|
+
super(options)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async get(params: { id: string }) {
|
|
119
|
+
return await this.fetchUrlEncoded<string>(`/e/tenant/partners/${params.id}/avatar`, 'GET')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async delete(params: { id: string }) {
|
|
123
|
+
return await this.fetchUrlEncoded(`/e/tenant/partners/${params.id}/avatar`, 'DELETE')
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async update(params: { id: string, data: { avatar: File } }): Promise<{}> {
|
|
127
|
+
return await this.fetchMultipart(`/e/tenant/partners/${params.id}/avatar`, 'PUT', { body: params.data })
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
class Tenant$Partners$Users extends ApiClient {
|
|
132
|
+
constructor(options: ClientOptions) {
|
|
133
|
+
super(options)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async list(params: { id: string }) {
|
|
137
|
+
return await this.fetchUrlEncoded<TenantUser>(`/e/tenant/partners/${params.id}/users`, 'GET')
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async get(params: { id: string, uid: string }) {
|
|
141
|
+
return await this.fetchUrlEncoded<TenantUser>(`/e/tenant/partners/${params.id}/users/${params.uid}`, 'GET')
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async update(params: { id: string, uid: string, data: { first_name: string, last_name: string, role: TenantRole, language: Language } }) {
|
|
145
|
+
return await this.fetchUrlEncoded(`/e/tenant/partners/${params.id}/users/${params.uid}`, 'PUT', {
|
|
146
|
+
body: params.data
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// async delete(params: { id: string, uid: string }) {
|
|
151
|
+
// return await this.fetchUrlEncoded(`/e/tenant/partners/${params.id}/users/${params.uid}`, 'DELETE')
|
|
152
|
+
// }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
class Tenant$Users extends ApiClient {
|
|
156
|
+
constructor(options: ClientOptions) {
|
|
157
|
+
super(options)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async list() {
|
|
161
|
+
return await this.fetchUrlEncoded<TenantUser>(`/e/tenant/users`, 'GET')
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async get(params: { uid: string }) {
|
|
165
|
+
return await this.fetchUrlEncoded<TenantUser>(`/e/tenant/users/${params.uid}`, 'GET')
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async update(params: { uid: string, data: { first_name: string, last_name: string, role: TenantRole, language: Language } }) {
|
|
169
|
+
return await this.fetchUrlEncoded(`/e/tenant/users/${params.uid}`, 'PUT', {
|
|
170
|
+
body: params.data
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async delete(params: { uid: string }) {
|
|
175
|
+
return await this.fetchUrlEncoded(`/e/tenant/users/${params.uid}`, 'DELETE')
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
class Tenant$Info extends ApiClient {
|
|
180
|
+
constructor(options: ClientOptions) {
|
|
181
|
+
super(options)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async get() {
|
|
185
|
+
return await this.fetchUrlEncoded<Tenant>(`/e/tenant`, 'GET')
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async update(data: { name: string, email: string, language: Language }) {
|
|
189
|
+
await this.fetchUrlEncoded(`/e/tenant`, 'PUT', {
|
|
190
|
+
body: data
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
class Tenant$Avatar extends ApiClient {
|
|
196
|
+
constructor(options: ClientOptions) {
|
|
197
|
+
super(options)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async get() {
|
|
201
|
+
return await this.fetchUrlEncoded<string>('/e/tenant/avatar', 'GET')
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async delete() {
|
|
205
|
+
return await this.fetchUrlEncoded('/e/tenant/avatar', 'DELETE')
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async update(body: { avatar: File }): Promise<{}> {
|
|
209
|
+
return await this.fetchMultipart('/e/tenant/avatar', 'PUT', { body })
|
|
210
|
+
}
|
|
211
|
+
}
|