@qidcloud/sdk 1.2.0 → 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.
@@ -30,4 +30,32 @@ export declare class EdgeModule {
30
30
  delete(name: string, userToken?: string): Promise<{
31
31
  success: boolean;
32
32
  }>;
33
+ /**
34
+ * Deploy a new function or update an existing one
35
+ * @param data Deployment data including name, code, and optional envVars
36
+ * @param userToken Optional session token
37
+ */
38
+ deploy(data: {
39
+ name: string;
40
+ code: string;
41
+ runtime?: string;
42
+ envVars?: any;
43
+ overwrite?: boolean;
44
+ }, userToken?: string): Promise<{
45
+ success: boolean;
46
+ message: string;
47
+ }>;
48
+ /**
49
+ * Get available serverless runtimes
50
+ */
51
+ getRuntimes(): Promise<string[]>;
52
+ /**
53
+ * Toggle centralized logging for the project's edge functions
54
+ * @param enabled Whether to enable or disable logging
55
+ * @param userToken Optional session token
56
+ */
57
+ toggleLogging(enabled: boolean, userToken?: string): Promise<{
58
+ success: boolean;
59
+ loggingEnabled: boolean;
60
+ }>;
33
61
  }
@@ -23,7 +23,7 @@ export declare class VaultModule {
23
23
  */
24
24
  download(fileId: string, userToken?: string): Promise<ArrayBuffer>;
25
25
  /**
26
- * Delete a file from storage
26
+ * Delete a file from storage (Soft Delete)
27
27
  * @param fileId Unique ID of the file
28
28
  * @param userToken Session token for user-scoped storage
29
29
  */
@@ -31,4 +31,27 @@ export declare class VaultModule {
31
31
  success: boolean;
32
32
  message: string;
33
33
  }>;
34
+ /**
35
+ * List deleted files in the project enclave (Recycle Bin)
36
+ * @param userToken Session token for user-scoped storage
37
+ */
38
+ listDeleted(userToken?: string): Promise<QidFile[]>;
39
+ /**
40
+ * Restore a deleted file from the recycle bin
41
+ * @param fileId Unique ID of the file
42
+ * @param userToken Session token for user-scoped storage
43
+ */
44
+ restore(fileId: string, userToken?: string): Promise<{
45
+ success: boolean;
46
+ message: string;
47
+ }>;
48
+ /**
49
+ * Permanently purge a deleted file
50
+ * @param fileId Unique ID of the file
51
+ * @param userToken Session token for user-scoped storage
52
+ */
53
+ purge(fileId: string, userToken?: string): Promise<{
54
+ success: boolean;
55
+ message: string;
56
+ }>;
34
57
  }
package/package.json CHANGED
@@ -1,52 +1,35 @@
1
- {
2
- "name": "@qidcloud/sdk",
3
- "version": "1.2.0",
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
- "pqc",
15
- "quantum-resistant",
16
- "passwordless",
17
- "enclave",
18
- "security",
19
- "auth"
20
- ],
21
- "author": "QidCloud Team",
22
- "license": "ISC",
23
- "publishConfig": {
24
- "access": "public"
25
- },
26
- "repository": {
27
- "type": "git",
28
- "url": "git+https://github.com/CHANDU32455/QIDCLOUD.git"
29
- },
30
- "files": [
31
- "dist",
32
- "README.md"
33
- ],
34
- "type": "commonjs",
35
- "dependencies": {
36
- "axios": "^1.13.5",
37
- "socket.io-client": "^4.8.3"
38
- },
39
- "devDependencies": {
40
- "@rollup/plugin-commonjs": "^29.0.0",
41
- "@rollup/plugin-node-resolve": "^16.0.3",
42
- "@rollup/plugin-typescript": "^12.3.0",
43
- "@types/node": "^25.2.3",
44
- "@types/react": "^19.2.13",
45
- "@types/react-dom": "^19.2.3",
46
- "react": "^19.2.4",
47
- "react-dom": "^19.2.4",
48
- "rollup": "^4.57.1",
49
- "tslib": "^2.8.1",
50
- "typescript": "^5.9.3"
51
- }
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
+ }
52
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 ADDED
@@ -0,0 +1,57 @@
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';
8
+
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
+ }
53
+
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
+ }