@sogni-ai/sogni-client 0.3.2 → 0.4.0-aplha.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.
Files changed (49) hide show
  1. package/README.md +3 -2
  2. package/dist/Account/index.d.ts +127 -3
  3. package/dist/Account/index.js +126 -2
  4. package/dist/Account/index.js.map +1 -1
  5. package/dist/Projects/Job.d.ts +5 -0
  6. package/dist/Projects/Job.js +6 -0
  7. package/dist/Projects/Job.js.map +1 -1
  8. package/dist/Projects/index.d.ts +6 -6
  9. package/dist/Projects/index.js +12 -2
  10. package/dist/Projects/index.js.map +1 -1
  11. package/dist/Projects/types/events.d.ts +2 -0
  12. package/dist/version.d.ts +1 -1
  13. package/dist/version.js +1 -1
  14. package/dist/version.js.map +1 -1
  15. package/package.json +5 -3
  16. package/src/Account/CurrentAccount.ts +101 -0
  17. package/src/Account/index.ts +367 -0
  18. package/src/Account/types.ts +90 -0
  19. package/src/ApiClient/WebSocketClient/ErrorCode.ts +15 -0
  20. package/src/ApiClient/WebSocketClient/events.ts +94 -0
  21. package/src/ApiClient/WebSocketClient/index.ts +203 -0
  22. package/src/ApiClient/WebSocketClient/messages.ts +7 -0
  23. package/src/ApiClient/WebSocketClient/types.ts +1 -0
  24. package/src/ApiClient/events.ts +20 -0
  25. package/src/ApiClient/index.ts +124 -0
  26. package/src/ApiGroup.ts +25 -0
  27. package/src/Projects/Job.ts +132 -0
  28. package/src/Projects/Project.ts +185 -0
  29. package/src/Projects/createJobRequestMessage.ts +99 -0
  30. package/src/Projects/index.ts +350 -0
  31. package/src/Projects/models.json +8906 -0
  32. package/src/Projects/types/EstimationResponse.ts +45 -0
  33. package/src/Projects/types/events.ts +80 -0
  34. package/src/Projects/types/index.ts +146 -0
  35. package/src/Stats/index.ts +15 -0
  36. package/src/Stats/types.ts +34 -0
  37. package/src/events.ts +5 -0
  38. package/src/index.ts +120 -0
  39. package/src/lib/DataEntity.ts +38 -0
  40. package/src/lib/DefaultLogger.ts +47 -0
  41. package/src/lib/EIP712Helper.ts +57 -0
  42. package/src/lib/RestClient.ts +76 -0
  43. package/src/lib/TypedEventEmitter.ts +66 -0
  44. package/src/lib/base64.ts +9 -0
  45. package/src/lib/getUUID.ts +8 -0
  46. package/src/lib/isNodejs.ts +4 -0
  47. package/src/types/ErrorData.ts +6 -0
  48. package/src/types/json.ts +5 -0
  49. package/src/version.ts +1 -0
@@ -0,0 +1,45 @@
1
+ export interface EstimationResponse {
2
+ request: Request;
3
+ rate: Rate;
4
+ quote: Quote;
5
+ }
6
+
7
+ export interface Quote {
8
+ model: Model;
9
+ job: Job;
10
+ project: Job;
11
+ }
12
+
13
+ export interface Job {
14
+ costInRenderSec: string;
15
+ costInUSD: string;
16
+ costInToken: string;
17
+ calculatedStepCount?: number;
18
+ }
19
+
20
+ export interface Model {
21
+ weight: string;
22
+ secPerStep: string;
23
+ secPerPreview: string;
24
+ secForCN: string;
25
+ }
26
+
27
+ export interface Rate {
28
+ costPerBaseHQRenderInUSD: string;
29
+ tokenMarkePriceUSD: string;
30
+ costPerRenderSecUSD: string;
31
+ costPerRenderSecToken: string;
32
+ network: string;
33
+ networkCostMultiplier: string;
34
+ }
35
+
36
+ export interface Request {
37
+ model: string;
38
+ name: string;
39
+ imageCount: number;
40
+ stepCount: number;
41
+ previewCount: number;
42
+ cnEnabled: boolean;
43
+ denoiseStrength: string;
44
+ time: Date;
45
+ }
@@ -0,0 +1,80 @@
1
+ import { AvailableModel } from './index';
2
+ import ErrorData from '../../types/ErrorData';
3
+
4
+ export interface ProjectEventBase {
5
+ projectId: string;
6
+ }
7
+
8
+ export interface ProjectQueued extends ProjectEventBase {
9
+ type: 'queued';
10
+ queuePosition: number;
11
+ }
12
+
13
+ export interface ProjectCompleted extends ProjectEventBase {
14
+ type: 'completed';
15
+ }
16
+
17
+ export interface ProjectError extends ProjectEventBase {
18
+ type: 'error';
19
+ error: ErrorData;
20
+ }
21
+
22
+ export type ProjectEvent = ProjectQueued | ProjectCompleted | ProjectError;
23
+
24
+ export interface JobEventBase {
25
+ projectId: string;
26
+ jobId: string;
27
+ }
28
+
29
+ export interface JobInitiating extends JobEventBase {
30
+ type: 'initiating';
31
+ workerName: string;
32
+ }
33
+
34
+ export interface JobStarted extends JobEventBase {
35
+ type: 'started';
36
+ workerName: string;
37
+ }
38
+
39
+ export interface JobProgress extends JobEventBase {
40
+ type: 'progress';
41
+ step: number;
42
+ stepCount: number;
43
+ }
44
+
45
+ export interface JobPreview extends JobEventBase {
46
+ type: 'preview';
47
+ url: string;
48
+ }
49
+
50
+ export interface JobCompleted extends JobEventBase {
51
+ type: 'completed';
52
+ steps: number;
53
+ seed: number;
54
+ /**
55
+ * URL to the result image, could be null if the job was canceled or triggered NSFW filter while
56
+ * it was not disabled by the user
57
+ */
58
+ resultUrl: string | null;
59
+ isNSFW: boolean;
60
+ userCanceled: boolean;
61
+ }
62
+
63
+ export interface JobError extends JobEventBase {
64
+ type: 'error';
65
+ error: ErrorData;
66
+ }
67
+
68
+ export type JobEvent =
69
+ | JobInitiating
70
+ | JobStarted
71
+ | JobProgress
72
+ | JobPreview
73
+ | JobCompleted
74
+ | JobError;
75
+
76
+ export interface ProjectApiEvents {
77
+ availableModels: AvailableModel[];
78
+ project: ProjectEvent;
79
+ job: JobEvent;
80
+ }
@@ -0,0 +1,146 @@
1
+ import { SupernetType } from '../../ApiClient/WebSocketClient/types';
2
+
3
+ export interface AvailableModel {
4
+ id: string;
5
+ name: string;
6
+ workerCount: number;
7
+ }
8
+
9
+ export interface AiModel {
10
+ isSD3: boolean;
11
+ modelShortName: string;
12
+ isIOSslowest: boolean;
13
+ hasOriginalVersionOnly: boolean;
14
+ isUserModel: boolean;
15
+ isTurboXL: boolean;
16
+ isRealistic: boolean;
17
+ isArtistic: boolean;
18
+ tier: string;
19
+ splitAttentionSuffix: string;
20
+ isSD3XL: boolean;
21
+ originalAttentionSuffix: string;
22
+ isLCM: boolean;
23
+ zipWeight: number;
24
+ modelId: string;
25
+ modelVersion: string;
26
+ parentId: string;
27
+ quantized: boolean;
28
+ isXL: boolean;
29
+ splitAttentionV2Suffix: string;
30
+ supportsAttentionV2: boolean;
31
+ supportsControlNet: boolean;
32
+ supportsEncoder: boolean;
33
+ onlySplitEinsumV2available: boolean;
34
+ customSize?: number[];
35
+ }
36
+
37
+ export type Scheduler =
38
+ | 'DPM Solver Multistep (DPM-Solver++)'
39
+ | 'PNDM (Pseudo-linear multi-step)'
40
+ | 'LCM (Latent Consistency Model)'
41
+ | 'Discrete Flow Scheduler (SD3)'
42
+ | 'Euler'; // Used by Flux
43
+
44
+ export type TimeStepSpacing = 'Karras' | 'Leading' | 'Linear';
45
+
46
+ export interface ProjectParams {
47
+ /**
48
+ * ID of the model to use, available models are available in the `availableModels` property of the `ProjectsApi` instance.
49
+ */
50
+ modelId: string;
51
+ /**
52
+ * Prompt for what to be created
53
+ */
54
+ positivePrompt: string;
55
+ /**
56
+ * Prompt for what to be avoided
57
+ */
58
+ negativePrompt: string;
59
+ /**
60
+ * Image style prompt
61
+ */
62
+ stylePrompt: string;
63
+ /**
64
+ * Number of steps. For most Stable Diffusion models, optimal value is 20
65
+ */
66
+ steps: number;
67
+ /**
68
+ * Guidance scale. For most Stable Diffusion models, optimal value is 7.5
69
+ */
70
+ guidance: number;
71
+ /**
72
+ * Disable NSFW filter for Project. Default is false, meaning NSFW filter is enabled.
73
+ * If image triggers NSFW filter, it will not be available for download.
74
+ */
75
+ disableNSFWFilter?: boolean;
76
+ /**
77
+ * Seed for one of images in project. Other will get random seed. Must be Uint32
78
+ */
79
+ seed?: number;
80
+ /**
81
+ * Number of images to generate
82
+ */
83
+ numberOfImages: number;
84
+ /**
85
+ * Generate images based on starting image.
86
+ * `File` - file object from input[type=file]
87
+ * `Buffer` - buffer object with image data
88
+ * `Blob` - blob object with image data
89
+ */
90
+ startingImage?: File | Buffer | Blob;
91
+ /**
92
+ * How strong effect of starting image should be. From 0 to 1, default 0.5
93
+ */
94
+ startingImageStrength?: number;
95
+ /**
96
+ * Number of previews to generate. Note that previews affect project cost\
97
+ */
98
+ numberOfPreviews?: number;
99
+ /**
100
+ * Scheduler to use
101
+ */
102
+ scheduler?: Scheduler;
103
+ /**
104
+ * Time step spacing method
105
+ */
106
+ timeStepSpacing?: TimeStepSpacing;
107
+ }
108
+
109
+ export type ImageUrlParams = {
110
+ imageId: string;
111
+ jobId: string;
112
+ type: 'preview' | 'complete' | 'startingImage' | 'cnImage';
113
+ // This seems to be unused currently
114
+ startContentType?: string;
115
+ };
116
+
117
+ export interface EstimateRequest {
118
+ /**
119
+ * Network to use. Can be 'fast' or 'relaxed'
120
+ */
121
+ network: SupernetType;
122
+ /**
123
+ * Model ID
124
+ */
125
+ model: string;
126
+ /**
127
+ * Number of images to generate
128
+ */
129
+ imageCount: number;
130
+ /**
131
+ * Number of steps
132
+ */
133
+ stepCount: number;
134
+ /**
135
+ * Number of preview images to generate
136
+ */
137
+ previewCount: number;
138
+ /**
139
+ * Control network enabled
140
+ */
141
+ cnEnabled?: boolean;
142
+ /**
143
+ * How strong effect of starting image should be. From 0 to 1, default 0.5
144
+ */
145
+ startingImageStrength?: number;
146
+ }
@@ -0,0 +1,15 @@
1
+ import ApiGroup from '../ApiGroup';
2
+ import { ApiReponse } from '../ApiClient';
3
+ import { LeaderboardItem, LeaderboardParams } from './types';
4
+
5
+ class StatsApi extends ApiGroup {
6
+ async leaderboard(params: LeaderboardParams) {
7
+ const res = await this.client.rest.get<ApiReponse<LeaderboardItem[]>>(
8
+ '/v1/leaderboard/',
9
+ params
10
+ );
11
+ return res.data;
12
+ }
13
+ }
14
+
15
+ export default StatsApi;
@@ -0,0 +1,34 @@
1
+ export type LeaderboardType =
2
+ | 'renderUSDCompleteWorker'
3
+ | 'renderUSDCompleteArtist'
4
+ | 'renderSecCompleteWorker'
5
+ | 'renderSecCompleteArtist'
6
+ | 'renderTokenCompleteWorker'
7
+ | 'renderTokenCompleteArtist'
8
+ | 'jobCompleteWorker'
9
+ | 'jobCompleteArtist'
10
+ | 'projectCompleteArtist'
11
+ | 'uloginWorker'
12
+ | 'uloginArtist'
13
+ | 'tokenVolume'
14
+ | 'referral';
15
+
16
+ export interface LeaderboardParams {
17
+ type: LeaderboardType;
18
+ period: 'day' | 'lifetime';
19
+ username?: string;
20
+ network?: 'fast' | 'relaxed' | 'all';
21
+ page?: number;
22
+ limit?: number;
23
+ date?: number;
24
+ address?: string;
25
+ }
26
+
27
+ export interface LeaderboardItem {
28
+ rank: number;
29
+ username: string;
30
+ address: string;
31
+ country: string;
32
+ value: string;
33
+ role: string;
34
+ }
package/src/events.ts ADDED
@@ -0,0 +1,5 @@
1
+ export type { ApiClientEvents } from './ApiClient/events';
2
+ export type { ProjectApiEvents } from './Projects/types/events';
3
+ export type { EntityEvents } from './lib/DataEntity';
4
+ export type { JobEventMap } from './Projects/Job';
5
+ export type { ProjectEventMap } from './Projects/Project';
package/src/index.ts ADDED
@@ -0,0 +1,120 @@
1
+ import { AbstractProvider, JsonRpcProvider, getDefaultProvider } from 'ethers';
2
+ // Account API
3
+ import AccountApi from './Account';
4
+ import CurrentAccount from './Account/CurrentAccount';
5
+ // ApiClient
6
+ import ApiClient, { ApiError } from './ApiClient';
7
+ import { SupernetType } from './ApiClient/WebSocketClient/types';
8
+ import { ApiConfig } from './ApiGroup';
9
+ // Utils
10
+ import { DefaultLogger, Logger, LogLevel } from './lib/DefaultLogger';
11
+ import EIP712Helper from './lib/EIP712Helper';
12
+ // Projects API
13
+ import ProjectsApi from './Projects';
14
+ import Job, { JobStatus } from './Projects/Job';
15
+ import Project, { ProjectStatus } from './Projects/Project';
16
+ import { AvailableModel, ProjectParams, Scheduler, TimeStepSpacing } from './Projects/types';
17
+ // Stats API
18
+ import StatsApi from './Stats';
19
+ // Base Types
20
+ import ErrorData from './types/ErrorData';
21
+
22
+ export type {
23
+ AvailableModel,
24
+ ErrorData,
25
+ JobStatus,
26
+ Logger,
27
+ LogLevel,
28
+ ProjectParams,
29
+ ProjectStatus,
30
+ Scheduler,
31
+ SupernetType,
32
+ TimeStepSpacing
33
+ };
34
+
35
+ export { ApiError, CurrentAccount, Job, Project };
36
+
37
+ export interface SogniClientConfig {
38
+ /**
39
+ * The application ID string. Must be unique, multiple connections with the same ID will be rejected.
40
+ */
41
+ appId: string;
42
+ /**
43
+ * Override the default REST API endpoint
44
+ * @internal
45
+ */
46
+ restEndpoint?: string;
47
+ /**
48
+ * Override the default WebSocket API endpoint
49
+ * @internal
50
+ */
51
+ socketEndpoint?: string;
52
+ /**
53
+ * Which network to use after logging in. Can be 'fast' or 'relaxed'
54
+ */
55
+ network: SupernetType;
56
+ /**
57
+ * Logger to use. If not provided, a default console logger will be used
58
+ */
59
+ logger?: Logger;
60
+ /**
61
+ * Log level to use. This option is ignored if a logger is provided
62
+ * @default 'warn'
63
+ **/
64
+ logLevel?: LogLevel;
65
+ /**
66
+ * If provided, the client will connect to this JSON-RPC endpoint to interact with the blockchain
67
+ */
68
+ jsonRpcUrl?: string;
69
+ /**
70
+ * If true, the client will connect to the testnet. Ignored if jsonRpcUrl is provided
71
+ */
72
+ testnet?: boolean;
73
+ }
74
+
75
+ export class SogniClient {
76
+ account: AccountApi;
77
+ projects: ProjectsApi;
78
+ stats: StatsApi;
79
+
80
+ apiClient: ApiClient;
81
+
82
+ private constructor(config: ApiConfig) {
83
+ this.account = new AccountApi(config);
84
+ this.projects = new ProjectsApi(config);
85
+ this.stats = new StatsApi(config);
86
+
87
+ this.apiClient = config.client;
88
+ }
89
+
90
+ get currentAccount() {
91
+ return this.account.currentAccount;
92
+ }
93
+
94
+ /**
95
+ * Instance creation may involve async operations, so we use a static method
96
+ * @param config
97
+ */
98
+ static async createInstance(config: SogniClientConfig): Promise<SogniClient> {
99
+ const restEndpoint = config.restEndpoint || 'https://api.sogni.ai';
100
+ const socketEndpoint = config.socketEndpoint || 'wss://socket.sogni.ai';
101
+ const network = config.network || 'fast';
102
+ const logger = config.logger || new DefaultLogger(config.logLevel || 'warn');
103
+ const isTestnet = config.testnet !== undefined ? config.testnet : true;
104
+
105
+ const client = new ApiClient(restEndpoint, socketEndpoint, config.appId, network, logger);
106
+ let provider: AbstractProvider;
107
+ if ('jsonRpcUrl' in config) {
108
+ provider = new JsonRpcProvider(config.jsonRpcUrl);
109
+ } else {
110
+ provider = getDefaultProvider(isTestnet ? 84532 : 8453);
111
+ }
112
+ const chainId = await provider.getNetwork().then((network) => network.chainId);
113
+ const eip712 = new EIP712Helper({
114
+ name: 'Sogni-testnet',
115
+ version: '1',
116
+ chainId: chainId.toString()
117
+ });
118
+ return new SogniClient({ client, provider, eip712 });
119
+ }
120
+ }
@@ -0,0 +1,38 @@
1
+ import { cloneDeep } from 'lodash';
2
+ import TypedEventEmitter from './TypedEventEmitter';
3
+
4
+ /**
5
+ * @inline
6
+ */
7
+ export interface EntityEvents {
8
+ updated: string[];
9
+ }
10
+
11
+ abstract class DataEntity<D, E extends EntityEvents = EntityEvents> extends TypedEventEmitter<E> {
12
+ protected data: D;
13
+
14
+ constructor(data: D) {
15
+ super();
16
+ this.data = data;
17
+ }
18
+
19
+ /**
20
+ * @internal
21
+ * @param delta
22
+ */
23
+ _update(delta: Partial<D>) {
24
+ //@ts-ignore
25
+ const changedKeys = Object.keys(delta).filter((key) => this.data[key] !== delta[key]);
26
+ this.data = { ...this.data, ...delta };
27
+ this.emit('updated', changedKeys);
28
+ }
29
+
30
+ /**
31
+ * Get a copy of the entity's data
32
+ */
33
+ toJSON(): D {
34
+ return cloneDeep(this.data);
35
+ }
36
+ }
37
+
38
+ export default DataEntity;
@@ -0,0 +1,47 @@
1
+ export type LogLevel = 'error' | 'warn' | 'info' | 'debug';
2
+
3
+ export const LOG_LEVELS: Record<LogLevel, number> = {
4
+ error: 0,
5
+ warn: 1,
6
+ info: 2,
7
+ debug: 3
8
+ };
9
+
10
+ export interface Logger {
11
+ error(...args: any[]): void;
12
+ warn(...args: any[]): void;
13
+ info(...args: any[]): void;
14
+ debug(...args: any[]): void;
15
+ }
16
+
17
+ export class DefaultLogger implements Logger {
18
+ private _level: number;
19
+
20
+ constructor(level: LogLevel = 'warn') {
21
+ this._level = LOG_LEVELS[level];
22
+ }
23
+
24
+ error(...args: any[]) {
25
+ if (this._level >= LOG_LEVELS.error) {
26
+ console.error(...args);
27
+ }
28
+ }
29
+
30
+ warn(...args: any[]) {
31
+ if (this._level >= LOG_LEVELS.warn) {
32
+ console.warn(...args);
33
+ }
34
+ }
35
+
36
+ info(...args: any[]) {
37
+ if (this._level >= LOG_LEVELS.info) {
38
+ console.info(...args);
39
+ }
40
+ }
41
+
42
+ debug(...args: any[]) {
43
+ if (this._level >= LOG_LEVELS.debug) {
44
+ console.debug(...args);
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,57 @@
1
+ import { AbstractSigner, TypedDataDomain, TypedDataField } from 'ethers';
2
+
3
+ type EIP712Types = Record<string, TypedDataField[]>;
4
+ type SupportedTypes = 'authentication' | 'signup';
5
+
6
+ const EIP712_TYPES: Record<SupportedTypes, EIP712Types> = {
7
+ authentication: {
8
+ Authentication: [
9
+ { name: 'walletAddress', type: 'address' },
10
+ { name: 'nonce', type: 'string' }
11
+ ]
12
+ },
13
+ signup: {
14
+ Signup: [
15
+ { name: 'appid', type: 'string' },
16
+ { name: 'username', type: 'string' },
17
+ { name: 'email', type: 'string' },
18
+ { name: 'subscribe', type: 'uint256' },
19
+ { name: 'walletAddress', type: 'address' },
20
+ { name: 'nonce', type: 'string' }
21
+ ]
22
+ }
23
+ };
24
+
25
+ interface Options {
26
+ name: string;
27
+ version: string;
28
+ chainId: string;
29
+ }
30
+
31
+ class EIP712Helper {
32
+ private readonly EIP712Domain: TypedDataDomain;
33
+
34
+ constructor(options: Options) {
35
+ this.EIP712Domain = {
36
+ name: options.name,
37
+ version: options.version,
38
+ chainId: options.chainId,
39
+ verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
40
+ };
41
+ }
42
+
43
+ signTypedData(
44
+ signer: AbstractSigner,
45
+ type: SupportedTypes,
46
+ data: Record<string, string | number>
47
+ ) {
48
+ const types = EIP712_TYPES[type];
49
+ if (!types) {
50
+ throw new Error(`Unknown type: ${type}`);
51
+ }
52
+
53
+ return signer.signTypedData(this.EIP712Domain, types, data);
54
+ }
55
+ }
56
+
57
+ export default EIP712Helper;
@@ -0,0 +1,76 @@
1
+ import { ApiError, ApiErrorResponse } from '../ApiClient';
2
+ import TypedEventEmitter, { EventMap } from './TypedEventEmitter';
3
+ import { JSONValue } from '../types/json';
4
+ import { Logger } from './DefaultLogger';
5
+
6
+ export interface AuthData {
7
+ token: string;
8
+ }
9
+
10
+ class RestClient<E extends EventMap = never> extends TypedEventEmitter<E> {
11
+ readonly baseUrl: string;
12
+ protected _auth: AuthData | null = null;
13
+ protected _logger: Logger;
14
+
15
+ constructor(baseUrl: string, logger: Logger) {
16
+ super();
17
+ this.baseUrl = baseUrl;
18
+ this._logger = logger;
19
+ }
20
+
21
+ get auth(): AuthData | null {
22
+ return this._auth;
23
+ }
24
+
25
+ set auth(auth: AuthData | null) {
26
+ this._auth = auth;
27
+ }
28
+
29
+ private formatUrl(relativeUrl: string, query: Record<string, string> = {}): string {
30
+ const url = new URL(relativeUrl, this.baseUrl);
31
+ Object.keys(query).forEach((key) => {
32
+ url.searchParams.append(key, query[key]);
33
+ });
34
+ return url.toString();
35
+ }
36
+
37
+ private request<T = JSONValue>(url: string, options: RequestInit = {}): Promise<T> {
38
+ return fetch(url, {
39
+ ...options,
40
+ headers: {
41
+ ...(options.headers || {}),
42
+ ...(this.auth ? { Authorization: this.auth.token } : {})
43
+ }
44
+ }).then((r) => this.processResponse(r) as T);
45
+ }
46
+
47
+ private async processResponse(response: Response): Promise<JSONValue> {
48
+ let responseData;
49
+ try {
50
+ responseData = await response.json();
51
+ } catch (e) {
52
+ this._logger.error('Failed to parse response:', e);
53
+ throw new Error('Failed to parse response');
54
+ }
55
+ if (!response.ok) {
56
+ throw new ApiError(response.status, responseData as ApiErrorResponse);
57
+ }
58
+ return responseData as JSONValue;
59
+ }
60
+
61
+ get<T = JSONValue>(path: string, query: Record<string, any> = {}): Promise<T> {
62
+ return this.request<T>(this.formatUrl(path, query), query);
63
+ }
64
+
65
+ post<T = JSONValue>(path: string, body: Record<string, unknown> = {}): Promise<T> {
66
+ return this.request<T>(this.formatUrl(path), {
67
+ method: 'POST',
68
+ headers: {
69
+ 'Content-Type': 'application/json'
70
+ },
71
+ body: JSON.stringify(body)
72
+ });
73
+ }
74
+ }
75
+
76
+ export default RestClient;