@qidcloud/sdk 1.1.1 → 1.2.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/package.json CHANGED
@@ -1,31 +1,35 @@
1
- {
2
- "name": "@qidcloud/sdk",
3
- "version": "1.1.1",
4
- "description": "Information-Theoretic Security SDK for Web",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "scripts": {
9
- "build": "tsc"
10
- },
11
- "keywords": [
12
- "quantum",
13
- "pqc",
14
- "security",
15
- "kyber",
16
- "dilithium"
17
- ],
18
- "author": "Q-Gate",
19
- "license": "ISC",
20
- "dependencies": {
21
- "@asanrom/dilithium": "^1.0.1",
22
- "axios": "^1.6.0",
23
- "crystals-kyber-js": "^1.1.1",
24
- "eventemitter3": "^5.0.1",
25
- "socket.io-client": "^4.7.0"
26
- },
27
- "devDependencies": {
28
- "@types/node": "^20.19.27",
29
- "typescript": "^5.0.0"
30
- }
1
+ {
2
+ "name": "@qidcloud/sdk",
3
+ "version": "1.2.1",
4
+ "description": "The official JavaScript/TypeScript SDK for QidCloud Identity and Enclave Services.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "rollup -c",
10
+ "watch": "rollup -c -w",
11
+ "test": "echo \"Error: no test specified\" && exit 1"
12
+ },
13
+ "keywords": [],
14
+ "author": "",
15
+ "license": "ISC",
16
+ "type": "commonjs",
17
+ "dependencies": {
18
+ "axios": "^1.13.5",
19
+ "qrcode.react": "^4.2.0",
20
+ "socket.io-client": "^4.8.3"
21
+ },
22
+ "devDependencies": {
23
+ "@rollup/plugin-commonjs": "^29.0.0",
24
+ "@rollup/plugin-node-resolve": "^16.0.3",
25
+ "@rollup/plugin-typescript": "^12.3.0",
26
+ "@types/node": "^25.2.3",
27
+ "@types/react": "^19.2.13",
28
+ "@types/react-dom": "^19.2.3",
29
+ "react": "^19.2.4",
30
+ "react-dom": "^19.2.4",
31
+ "rollup": "^4.57.1",
32
+ "tslib": "^2.8.1",
33
+ "typescript": "^5.9.3"
34
+ }
31
35
  }
@@ -0,0 +1,26 @@
1
+ import typescript from '@rollup/plugin-typescript';
2
+ import resolve from '@rollup/plugin-node-resolve';
3
+ import commonjs from '@rollup/plugin-commonjs';
4
+ import pkg from './package.json' with { type: 'json' };
5
+
6
+ export default {
7
+ input: 'src/index.ts',
8
+ output: [
9
+ {
10
+ file: pkg.main,
11
+ format: 'cjs',
12
+ sourcemap: true,
13
+ },
14
+ {
15
+ file: pkg.module,
16
+ format: 'es',
17
+ sourcemap: true,
18
+ },
19
+ ],
20
+ external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})],
21
+ plugins: [
22
+ resolve(),
23
+ commonjs(),
24
+ typescript({ tsconfig: './tsconfig.json' }),
25
+ ],
26
+ };
@@ -0,0 +1,174 @@
1
+ import React from 'react';
2
+ import { QRCodeSVG } from 'qrcode.react';
3
+ import { QidCloud } from '../index';
4
+ import { QidUser } from '../types';
5
+ import { useQidAuth } from '../hooks/useQidAuth';
6
+
7
+ interface QidSignInButtonProps {
8
+ sdk: QidCloud;
9
+ onSuccess: (user: QidUser, token: string) => void;
10
+ onError?: (error: string) => void;
11
+ className?: string;
12
+ buttonText?: string;
13
+ }
14
+
15
+ /**
16
+ * A ready-to-use React component for QidCloud QR identity authentication.
17
+ */
18
+ export const QidSignInButton: React.FC<QidSignInButtonProps> = ({
19
+ sdk,
20
+ onSuccess,
21
+ onError,
22
+ className,
23
+ buttonText = 'Login with QidCloud'
24
+ }: QidSignInButtonProps) => {
25
+ const {
26
+ user,
27
+ token,
28
+ error,
29
+ session,
30
+ initializing,
31
+ login,
32
+ cancel
33
+ } = useQidAuth(sdk);
34
+
35
+ // Watch for success
36
+ React.useEffect(() => {
37
+ if (user && token) {
38
+ onSuccess(user, token);
39
+ }
40
+ }, [user, token, onSuccess]);
41
+
42
+ // Watch for errors
43
+ React.useEffect(() => {
44
+ if (error && onError) {
45
+ onError(error);
46
+ }
47
+ }, [error, onError]);
48
+
49
+ return (
50
+ <>
51
+ <button
52
+ onClick={login}
53
+ disabled={initializing || !!session}
54
+ className={className || 'qid-signin-btn'}
55
+ style={{
56
+ backgroundColor: '#00e5ff',
57
+ color: '#000',
58
+ padding: '12px 24px',
59
+ borderRadius: '12px',
60
+ border: 'none',
61
+ fontWeight: '900',
62
+ cursor: (initializing || !!session) ? 'not-allowed' : 'pointer',
63
+ display: 'flex',
64
+ alignItems: 'center',
65
+ gap: '10px',
66
+ textTransform: 'uppercase',
67
+ fontSize: '0.85rem',
68
+ letterSpacing: '0.5px',
69
+ boxShadow: '0 4px 15px rgba(0, 229, 255, 0.3)',
70
+ transition: 'all 0.2s'
71
+ }}
72
+ >
73
+ <div style={{
74
+ width: '8px',
75
+ height: '8px',
76
+ borderRadius: '50%',
77
+ backgroundColor: (initializing || !!session) ? '#333' : '#000',
78
+ boxShadow: (initializing || !!session) ? 'none' : '0 0 8px rgba(0,0,0,0.5)'
79
+ }} />
80
+ {initializing ? 'Preparing Handshake...' : (session ? 'Awaiting Scan...' : buttonText)}
81
+ </button>
82
+
83
+ {session && (
84
+ <div className="qid-modal-overlay" style={{
85
+ position: 'fixed',
86
+ top: 0, left: 0, right: 0, bottom: 0,
87
+ backgroundColor: 'rgba(0,0,0,0.92)',
88
+ display: 'flex',
89
+ justifyContent: 'center',
90
+ alignItems: 'center',
91
+ zIndex: 9999,
92
+ backdropFilter: 'blur(8px)'
93
+ }}>
94
+ <div className="qid-modal-content" style={{
95
+ backgroundColor: '#0a0a0a',
96
+ padding: '40px',
97
+ borderRadius: '28px',
98
+ textAlign: 'center',
99
+ color: '#fff',
100
+ maxWidth: '420px',
101
+ width: '90%',
102
+ border: '1px solid rgba(0, 229, 255, 0.2)',
103
+ boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.5)'
104
+ }}>
105
+ <div style={{ marginBottom: '25px' }}>
106
+ <div style={{
107
+ display: 'inline-block',
108
+ padding: '12px 20px',
109
+ borderRadius: '30px',
110
+ backgroundColor: 'rgba(0, 229, 255, 0.1)',
111
+ border: '1px solid rgba(0, 229, 255, 0.3)',
112
+ marginBottom: '15px'
113
+ }}>
114
+ <span style={{ color: '#00e5ff', fontSize: '0.7rem', fontWeight: '900', letterSpacing: '2px' }}>PQC ENCLAVE SECURED</span>
115
+ </div>
116
+ <h2 style={{ fontSize: '1.75rem', fontWeight: '900', marginBottom: '10px', letterSpacing: '-0.5px' }}>Identity Handshake</h2>
117
+ <p style={{ fontSize: '0.95rem', color: '#94a3b8', lineHeight: '1.6' }}>
118
+ Scan this encrypted gateway with your QidCloud app to authorize access.
119
+ </p>
120
+ </div>
121
+
122
+ <div style={{
123
+ backgroundColor: '#fff',
124
+ padding: '24px',
125
+ display: 'inline-block',
126
+ borderRadius: '24px',
127
+ marginBottom: '30px',
128
+ boxShadow: '0 10px 40px rgba(0,0,0,0.3)'
129
+ }}>
130
+ <QRCodeSVG
131
+ value={session.qrData}
132
+ size={220}
133
+ level="H"
134
+ includeMargin={false}
135
+ imageSettings={{
136
+ src: "https://api.qidcloud.com/favicon.ico",
137
+ x: undefined,
138
+ y: undefined,
139
+ height: 40,
140
+ width: 40,
141
+ excavate: true,
142
+ }}
143
+ />
144
+ </div>
145
+
146
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '15px' }}>
147
+ <div style={{ height: '4px', width: '60px', backgroundColor: '#00e5ff', margin: '0 auto', borderRadius: '2px', opacity: 0.5 }} />
148
+
149
+ <button onClick={cancel} style={{
150
+ display: 'block',
151
+ width: '100%',
152
+ padding: '16px',
153
+ backgroundColor: 'transparent',
154
+ color: '#64748b',
155
+ border: '1px solid rgba(148, 163, 184, 0.2)',
156
+ borderRadius: '16px',
157
+ cursor: 'pointer',
158
+ fontWeight: '700',
159
+ transition: 'all 0.2s',
160
+ fontSize: '0.9rem'
161
+ }}>
162
+ Cancel Handshake
163
+ </button>
164
+ </div>
165
+
166
+ <div style={{ marginTop: '25px', fontSize: '0.75rem', color: '#475569' }}>
167
+ Session ID: {session.sessionId.slice(0, 8)}...
168
+ </div>
169
+ </div>
170
+ </div>
171
+ )}
172
+ </>
173
+ );
174
+ };
@@ -0,0 +1,104 @@
1
+ import { useState, useCallback, useEffect, useRef } from 'react';
2
+ import { QidCloud } from '../index';
3
+ import { QidUser, QidAuthSession } from '../types';
4
+
5
+ export interface UseQidAuthReturn {
6
+ user: QidUser | null;
7
+ token: string | null;
8
+ loading: boolean;
9
+ error: string | null;
10
+ session: QidAuthSession | null;
11
+ initializing: boolean;
12
+ login: () => Promise<void>;
13
+ logout: () => void;
14
+ cancel: () => void;
15
+ }
16
+
17
+ /**
18
+ * A React hook for managing QidCloud authentication lifecycle.
19
+ * Handles handshake initialization, WebSocket listeners, and profile fetching.
20
+ */
21
+ export function useQidAuth(sdk: QidCloud): UseQidAuthReturn {
22
+ const [user, setUser] = useState<QidUser | null>(null);
23
+ const [token, setToken] = useState<string | null>(null);
24
+ const [session, setSession] = useState<QidAuthSession | null>(null);
25
+ const [loading, setLoading] = useState(false);
26
+ const [initializing, setInitializing] = useState(false);
27
+ const [error, setError] = useState<string | null>(null);
28
+
29
+ // Use ref to track if we should still be listening (to avoid state updates after unmount/cancel)
30
+ const activeSessionId = useRef<string | null>(null);
31
+
32
+ const logout = useCallback(() => {
33
+ setUser(null);
34
+ setToken(null);
35
+ setSession(null);
36
+ sdk.auth.disconnect();
37
+ }, [sdk]);
38
+
39
+ const cancel = useCallback(() => {
40
+ activeSessionId.current = null;
41
+ setSession(null);
42
+ setInitializing(false);
43
+ sdk.auth.disconnect();
44
+ }, [sdk]);
45
+
46
+ const login = useCallback(async () => {
47
+ setInitializing(true);
48
+ setError(null);
49
+ try {
50
+ const newSession = await sdk.auth.createSession();
51
+ setSession(newSession);
52
+ activeSessionId.current = newSession.sessionId;
53
+
54
+ sdk.auth.listen(
55
+ newSession.sessionId,
56
+ async (receivedToken: string) => {
57
+ // Safety check: is this still the active session?
58
+ if (activeSessionId.current !== newSession.sessionId) return;
59
+
60
+ setLoading(true);
61
+ setInitializing(false);
62
+ try {
63
+ const profile = await sdk.auth.getProfile(receivedToken);
64
+ setToken(receivedToken);
65
+ setUser(profile);
66
+ } catch (err: any) {
67
+ setError(err.message || 'Failed to fetch user profile');
68
+ } finally {
69
+ setLoading(false);
70
+ setSession(null);
71
+ }
72
+ },
73
+ (err: string) => {
74
+ if (activeSessionId.current !== newSession.sessionId) return;
75
+ setError(err);
76
+ setInitializing(false);
77
+ setSession(null);
78
+ }
79
+ );
80
+ } catch (err: any) {
81
+ setError(err.message || 'Failed to initiate login handshake');
82
+ setInitializing(false);
83
+ }
84
+ }, [sdk]);
85
+
86
+ // Cleanup on unmount
87
+ useEffect(() => {
88
+ return () => {
89
+ sdk.auth.disconnect();
90
+ };
91
+ }, [sdk]);
92
+
93
+ return {
94
+ user,
95
+ token,
96
+ loading,
97
+ error,
98
+ session,
99
+ initializing,
100
+ login,
101
+ logout,
102
+ cancel
103
+ };
104
+ }
package/src/index.ts CHANGED
@@ -1,7 +1,57 @@
1
- import { QidCloud, QidConfig, UserProfile } from './QidCloud';
2
- import UnifiedStorage from './storage';
3
- import * as PQC from './crypto/pqc';
1
+ import axios, { AxiosInstance } from 'axios';
2
+ import { QidConfig } from './types';
3
+ import { AuthModule } from './modules/auth';
4
+ import { DbModule } from './modules/db';
5
+ import { EdgeModule } from './modules/edge';
6
+ import { VaultModule } from './modules/vault';
7
+ import { LogsModule } from './modules/logs';
4
8
 
5
- export { QidCloud, QidCloud as PQAuth, QidConfig, UserProfile, UnifiedStorage, PQC };
9
+ export class QidCloud {
10
+ private config: QidConfig;
11
+ public api: AxiosInstance;
12
+
13
+ public auth: AuthModule;
14
+ public db: DbModule;
15
+ public edge: EdgeModule;
16
+ public vault: VaultModule;
17
+ public logs: LogsModule;
18
+
19
+ constructor(config: QidConfig) {
20
+ this.config = {
21
+ baseUrl: 'https://api.qidcloud.com',
22
+ ...config,
23
+ };
24
+
25
+ this.api = axios.create({
26
+ baseURL: this.config.baseUrl,
27
+ headers: {
28
+ 'x-api-key': this.config.apiKey,
29
+ 'Content-Type': 'application/json',
30
+ },
31
+ });
32
+
33
+ this.auth = new AuthModule(this);
34
+ this.db = new DbModule(this);
35
+ this.edge = new EdgeModule(this);
36
+ this.vault = new VaultModule(this);
37
+ this.logs = new LogsModule(this);
38
+ }
39
+
40
+ /**
41
+ * Get the current project configuration
42
+ */
43
+ getConfig(): QidConfig {
44
+ return { ...this.config };
45
+ }
46
+
47
+ // Modules will be initialized here
48
+ // public auth = new AuthModule(this);
49
+ // public db = new DbModule(this);
50
+ // public storage = new StorageModule(this);
51
+ // public edge = new EdgeModule(this);
52
+ }
6
53
 
7
54
  export default QidCloud;
55
+ export * from './types';
56
+ export { QidSignInButton } from './components/QidSignInButton';
57
+ export { useQidAuth } from './hooks/useQidAuth';
@@ -0,0 +1,77 @@
1
+ import { io, Socket } from 'socket.io-client';
2
+ import { QidCloud } from '../index';
3
+ import { QidAuthSession, QidUser } from '../types';
4
+
5
+ export class AuthModule {
6
+ private sdk: QidCloud;
7
+ private socket: Socket | null = null;
8
+
9
+ constructor(sdk: QidCloud) {
10
+ this.sdk = sdk;
11
+ }
12
+
13
+ /**
14
+ * Initialize a new handshake session for QR login
15
+ */
16
+ async createSession(): Promise<QidAuthSession> {
17
+ const resp = await this.sdk.api.post('/api/initiate-generic');
18
+ const { sessionId, nonce } = resp.data;
19
+
20
+ // Construct QR data
21
+ const qrData = `qid: handshake:${sessionId}:${nonce} `;
22
+
23
+ return {
24
+ sessionId,
25
+ qrData,
26
+ expiresAt: Date.now() + 120000 // 2 minutes
27
+ };
28
+ }
29
+
30
+ /**
31
+ * Listen for authorization events for a specific session
32
+ */
33
+ listen(sessionId: string, onAuthorized: (token: string) => void, onDenied?: (msg: string) => void) {
34
+ if (!this.socket) {
35
+ const baseUrl = this.sdk.getConfig().baseUrl || 'https://api.qidcloud.com';
36
+ this.socket = io(baseUrl);
37
+ }
38
+
39
+ this.socket.emit('join', sessionId);
40
+
41
+ this.socket.on('authenticated', (token: string) => {
42
+ onAuthorized(token);
43
+ });
44
+
45
+ this.socket.on('identity_authorized', (data: any) => {
46
+ // Some backend routes wrap the token in an object
47
+ const token = typeof data === 'string' ? data : data.token;
48
+ onAuthorized(token);
49
+ });
50
+
51
+ this.socket.on('identity_denied', (data: any) => {
52
+ if (onDenied) onDenied(data.message || 'Authorization denied');
53
+ });
54
+ }
55
+
56
+ /**
57
+ * Stop listening and disconnect socket
58
+ */
59
+ disconnect() {
60
+ if (this.socket) {
61
+ this.socket.disconnect();
62
+ this.socket = null;
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Fetch user profile using a session token
68
+ */
69
+ async getProfile(token: string): Promise<QidUser> {
70
+ const resp = await this.sdk.api.get('/api/me', {
71
+ headers: {
72
+ 'Authorization': `Bearer ${token}`
73
+ }
74
+ });
75
+ return resp.data;
76
+ }
77
+ }
@@ -0,0 +1,40 @@
1
+ import { QidCloud } from '../index';
2
+ import { QidDbResponse } from '../types';
3
+
4
+ export class DbModule {
5
+ private sdk: QidCloud;
6
+
7
+ constructor(sdk: QidCloud) {
8
+ this.sdk = sdk;
9
+ }
10
+
11
+ /**
12
+ * Execute a SQL query against the project's enclave database
13
+ * @param sql The SQL query string
14
+ * @param params Parameterized values for the query
15
+ * @param userToken Optional session token for user-scoped access
16
+ */
17
+ async query<T = any>(sql: string, params: any[] = [], userToken?: string): Promise<QidDbResponse<T>> {
18
+ const headers: any = {};
19
+ if (userToken) {
20
+ headers['Authorization'] = `Bearer ${userToken}`;
21
+ }
22
+
23
+ const resp = await this.sdk.api.post('/api/db/query', { sql, params }, { headers });
24
+ return resp.data;
25
+ }
26
+
27
+ /**
28
+ * Initialize the project's enclave database schema
29
+ * Useful for first-time project setup
30
+ */
31
+ async setup(userToken?: string): Promise<{ success: boolean; schemaName: string }> {
32
+ const headers: any = {};
33
+ if (userToken) {
34
+ headers['Authorization'] = `Bearer ${userToken}`;
35
+ }
36
+
37
+ const resp = await this.sdk.api.post('/api/db/setup', {}, { headers });
38
+ return resp.data;
39
+ }
40
+ }
@@ -0,0 +1,98 @@
1
+ import { QidCloud } from '../index';
2
+ import { QidEdgeResponse } from '../types';
3
+
4
+ export class EdgeModule {
5
+ private sdk: QidCloud;
6
+
7
+ constructor(sdk: QidCloud) {
8
+ this.sdk = sdk;
9
+ }
10
+
11
+ /**
12
+ * Invoke a serverless edge function
13
+ * @param name Name of the function to invoke
14
+ * @param params Arguments passed to the function
15
+ * @param userToken Optional session token for user-scoped access
16
+ */
17
+ async invoke(name: string, params: any = {}, userToken?: string): Promise<QidEdgeResponse> {
18
+ const headers: any = {};
19
+ if (userToken) {
20
+ headers['Authorization'] = `Bearer ${userToken}`;
21
+ }
22
+
23
+ const resp = await this.sdk.api.post('/api/edge/invoke', { name, params }, { headers });
24
+ return resp.data;
25
+ }
26
+
27
+ /**
28
+ * List all functions in the project enclave
29
+ */
30
+ async list(): Promise<any[]> {
31
+ const resp = await this.sdk.api.get('/api/edge/list');
32
+ return resp.data;
33
+ }
34
+
35
+ /**
36
+ * Get logs for a specific function
37
+ * @param name Function name
38
+ * @param userToken Optional session token
39
+ */
40
+ async getLogs(name: string, userToken?: string): Promise<any[]> {
41
+ const headers: any = {};
42
+ if (userToken) headers['Authorization'] = `Bearer ${userToken}`;
43
+ const resp = await this.sdk.api.get(`/api/edge/${name}/logs`, { headers });
44
+ return resp.data;
45
+ }
46
+
47
+ /**
48
+ * Get project-wide enclave logs
49
+ */
50
+ async getProjectLogs(userToken?: string): Promise<any[]> {
51
+ const headers: any = {};
52
+ if (userToken) headers['Authorization'] = `Bearer ${userToken}`;
53
+ const resp = await this.sdk.api.get('/api/edge/logs/project', { headers });
54
+ return resp.data;
55
+ }
56
+
57
+ /**
58
+ * Delete a function from the enclave
59
+ */
60
+ async delete(name: string, userToken?: string): Promise<{ success: boolean }> {
61
+ const headers: any = {};
62
+ if (userToken) headers['Authorization'] = `Bearer ${userToken}`;
63
+ const resp = await this.sdk.api.delete(`/api/edge/${name}`, { headers });
64
+ return resp.data;
65
+ }
66
+
67
+ /**
68
+ * Deploy a new function or update an existing one
69
+ * @param data Deployment data including name, code, and optional envVars
70
+ * @param userToken Optional session token
71
+ */
72
+ async deploy(data: { name: string; code: string; runtime?: string; envVars?: any; overwrite?: boolean }, userToken?: string): Promise<{ success: boolean; message: string }> {
73
+ const headers: any = {};
74
+ if (userToken) headers['Authorization'] = `Bearer ${userToken}`;
75
+ const resp = await this.sdk.api.post('/api/edge/deploy', data, { headers });
76
+ return resp.data;
77
+ }
78
+
79
+ /**
80
+ * Get available serverless runtimes
81
+ */
82
+ async getRuntimes(): Promise<string[]> {
83
+ const resp = await this.sdk.api.get('/api/edge/runtimes');
84
+ return resp.data;
85
+ }
86
+
87
+ /**
88
+ * Toggle centralized logging for the project's edge functions
89
+ * @param enabled Whether to enable or disable logging
90
+ * @param userToken Optional session token
91
+ */
92
+ async toggleLogging(enabled: boolean, userToken?: string): Promise<{ success: boolean; loggingEnabled: boolean }> {
93
+ const headers: any = {};
94
+ if (userToken) headers['Authorization'] = `Bearer ${userToken}`;
95
+ const resp = await this.sdk.api.post('/api/edge/logs/settings', { enabled }, { headers });
96
+ return resp.data;
97
+ }
98
+ }
@@ -0,0 +1,30 @@
1
+ import { QidCloud } from '../index';
2
+
3
+ export class LogsModule {
4
+ private sdk: QidCloud;
5
+
6
+ constructor(sdk: QidCloud) {
7
+ this.sdk = sdk;
8
+ }
9
+
10
+ /**
11
+ * Write a custom application log to the project enclave
12
+ * @param message The log message
13
+ * @param source The source of the log (e.g. 'auth-service', 'frontend')
14
+ * @param level Log level (info, warn, error)
15
+ * @param metadata Structured data for searching/filtering
16
+ */
17
+ async write(message: string, source: string = 'app', level: string = 'info', metadata: any = {}): Promise<{ success: boolean }> {
18
+ const resp = await this.sdk.api.post('/api/logs', { message, source, level, metadata });
19
+ return resp.data;
20
+ }
21
+
22
+ /**
23
+ * Retrieve application logs for the project
24
+ * @param query Filters (limit, level, etc.)
25
+ */
26
+ async fetch(query: any = {}): Promise<any[]> {
27
+ const resp = await this.sdk.api.get('/api/logs', { params: query });
28
+ return resp.data;
29
+ }
30
+ }