bytex-sdk 1.9.5 → 5.0.0
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/README.md +30 -41
- package/package.json +17 -12
- package/src/index.js +104 -0
- package/index.js +0 -138
- package/postinstall.js +0 -26
package/README.md
CHANGED
|
@@ -1,56 +1,45 @@
|
|
|
1
|
-
# ByteX SDK
|
|
2
|
-
> The official SDK for the ByteX Cloud Ecosystem.
|
|
1
|
+
# ByteX Cloud SDK 🚀
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
The official SDK for the ByteX ecosystem, enabling developers to build professional "Super SaaS" products with 100% cloud sovereignty (BYOC).
|
|
5
4
|
|
|
6
|
-
##
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **Middleware System**: Intercept and optimize uploads (e.g., auto-convert to WebP).
|
|
12
|
-
- **Bulk Operations**: Download or export entire projects as ZIP.
|
|
5
|
+
## Features
|
|
6
|
+
- 🔐 **Secure Authentication**: Integrated with Supabase.
|
|
7
|
+
- 📦 **Data Persistence**: Upload and download streams directly to your own Cloud (HuggingFace).
|
|
8
|
+
- 🕵️♂️ **X-Ray Diagnostics**: Built-in network and infrastructure health checks.
|
|
9
|
+
- ⚡ **Lightweight**: Zero-config needed for most use cases.
|
|
13
10
|
|
|
14
|
-
##
|
|
11
|
+
## Installation
|
|
15
12
|
```bash
|
|
16
|
-
npm install bytex-sdk
|
|
13
|
+
npm install @bytex/cloud-sdk
|
|
17
14
|
```
|
|
18
15
|
|
|
19
|
-
##
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
### Initialize
|
|
20
19
|
```javascript
|
|
21
|
-
import { BytexCloud } from 'bytex-sdk';
|
|
20
|
+
import { BytexCloud } from '@bytex/cloud-sdk';
|
|
21
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
const bytex = new BytexCloud({
|
|
24
|
+
apiKey: 'YOUR_API_KEY',
|
|
25
|
+
workerUrl: 'https://api.bytex.work/',
|
|
26
|
+
storage: AsyncStorage // for React Native
|
|
27
27
|
});
|
|
28
|
-
|
|
29
|
-
// Upload a file
|
|
30
|
-
await bytex.upload('hello.txt', 'Hello World');
|
|
31
|
-
|
|
32
|
-
// Get a streaming URL
|
|
33
|
-
const streamUrl = bytex.stream('video.mp4');
|
|
34
|
-
|
|
35
|
-
// List files
|
|
36
|
-
const files = await bytex.listFiles();
|
|
37
|
-
console.log(files);
|
|
38
28
|
```
|
|
39
29
|
|
|
40
|
-
|
|
30
|
+
### Upload Data
|
|
41
31
|
```javascript
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// Automatically optimize images to WebP before upload
|
|
47
|
-
bytex.use(BytexMiddlewares.imageOptimizer(0.8));
|
|
48
|
-
|
|
49
|
-
await bytex.upload('photo.jpg', fileData); // Uploads as photo.webp
|
|
32
|
+
await bytex.uploadData('my_project', {
|
|
33
|
+
status: 'active',
|
|
34
|
+
users: 1000
|
|
35
|
+
});
|
|
50
36
|
```
|
|
51
37
|
|
|
52
|
-
|
|
53
|
-
|
|
38
|
+
### Infrastructure Health Check (X-Ray)
|
|
39
|
+
```javascript
|
|
40
|
+
const report = await bytex.xray();
|
|
41
|
+
console.log(report.checks);
|
|
42
|
+
```
|
|
54
43
|
|
|
55
|
-
##
|
|
56
|
-
|
|
44
|
+
## License
|
|
45
|
+
MIT © ByteX Guru
|
package/package.json
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bytex-sdk",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "index.js",
|
|
3
|
+
"version": "5.0.0",
|
|
4
|
+
"description": "The official ByteX Cloud SDK for BYOC (Bring Your Own Cloud) infrastructure management.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
-
"postinstall": "node postinstall.js"
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
8
|
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"bytex",
|
|
11
|
+
"cloud",
|
|
12
|
+
"saas",
|
|
13
|
+
"byoc",
|
|
14
|
+
"supabase",
|
|
15
|
+
"huggingface"
|
|
16
|
+
],
|
|
17
|
+
"author": "ByteX Guru",
|
|
18
|
+
"license": "MIT",
|
|
10
19
|
"dependencies": {
|
|
11
|
-
"@supabase/supabase-js": "^2.
|
|
12
|
-
"
|
|
13
|
-
}
|
|
14
|
-
"keywords": [],
|
|
15
|
-
"author": "",
|
|
16
|
-
"license": "ISC",
|
|
17
|
-
"type": "module"
|
|
20
|
+
"@supabase/supabase-js": "^2.39.0",
|
|
21
|
+
"react-native-url-polyfill": "^2.0.0"
|
|
22
|
+
}
|
|
18
23
|
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { createClient } from '@supabase/supabase-js';
|
|
2
|
+
|
|
3
|
+
const SUPABASE_URL = 'https://vkiddclfbwmslaiyyftl.supabase.co';
|
|
4
|
+
const SUPABASE_ANON_KEY = 'sb_publishable_hXMlH9OmJG1_n1s-3lbXKg_6V-88Lj9';
|
|
5
|
+
const WORKER_URL = 'https://api.bytex.work/';
|
|
6
|
+
|
|
7
|
+
export class BytexCloud {
|
|
8
|
+
constructor(config = {}) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.apiKey = config.apiKey || null;
|
|
11
|
+
this.workerUrl = config.workerUrl || WORKER_URL;
|
|
12
|
+
|
|
13
|
+
const supabaseConfig = {
|
|
14
|
+
auth: {
|
|
15
|
+
persistSession: true,
|
|
16
|
+
autoRefreshToken: true,
|
|
17
|
+
detectSessionInUrl: false
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
if (config.storage) {
|
|
21
|
+
supabaseConfig.auth.storage = config.storage;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
this.supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, supabaseConfig);
|
|
25
|
+
this._listeners = {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async _execute(fn, action) {
|
|
29
|
+
try {
|
|
30
|
+
return await fn();
|
|
31
|
+
} catch (e) {
|
|
32
|
+
const diag = await this.xray();
|
|
33
|
+
const advice = diag.advice.length > 0 ? `\n[X-RAY Advice]: ${diag.advice.join(' ')}` : '';
|
|
34
|
+
throw new Error(`${action} failed: ${e.message}${advice}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async login(email, password) {
|
|
39
|
+
return this._execute(async () => {
|
|
40
|
+
const { data, error } = await this.supabase.auth.signInWithPassword({ email, password });
|
|
41
|
+
if (error) throw error;
|
|
42
|
+
return data.user;
|
|
43
|
+
}, 'Login');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async uploadData(name, data) {
|
|
47
|
+
return this._execute(async () => {
|
|
48
|
+
this._requireKey();
|
|
49
|
+
const streamName = name.endsWith('.btx') ? name : `${name}.stream.btx`;
|
|
50
|
+
const url = `${this.workerUrl}?action=upload&key=${this.apiKey}&file=${encodeURIComponent(streamName)}`;
|
|
51
|
+
const { data: { session } } = await this.supabase.auth.getSession();
|
|
52
|
+
|
|
53
|
+
const payload = typeof data === 'string' ? data : JSON.stringify(data);
|
|
54
|
+
|
|
55
|
+
const res = await fetch(url, {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
headers: {
|
|
58
|
+
'Authorization': `Bearer ${session?.access_token || ''}`,
|
|
59
|
+
'Content-Type': 'application/json'
|
|
60
|
+
},
|
|
61
|
+
body: payload
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (!res.ok) throw new Error(`Upload failed with status ${res.status}`);
|
|
65
|
+
return await res.json();
|
|
66
|
+
}, 'Upload');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async downloadData(name) {
|
|
70
|
+
return this._execute(async () => {
|
|
71
|
+
this._requireKey();
|
|
72
|
+
const streamName = name.endsWith('.btx') ? name : `${name}.stream.btx`;
|
|
73
|
+
const url = `${this.workerUrl}?action=view&key=${this.apiKey}&file=${encodeURIComponent(streamName)}&_cb=${Date.now()}`;
|
|
74
|
+
const { data: { session } } = await this.supabase.auth.getSession();
|
|
75
|
+
const res = await fetch(url, {
|
|
76
|
+
headers: { 'Authorization': `Bearer ${session?.access_token || ''}` }
|
|
77
|
+
});
|
|
78
|
+
if (!res.ok) throw new Error(`Status ${res.status}`);
|
|
79
|
+
const text = await res.text();
|
|
80
|
+
try { return JSON.parse(text); } catch (e) { return text.split('\n').filter(Boolean).map(line => JSON.parse(line)); }
|
|
81
|
+
}, 'Download');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async xray() {
|
|
85
|
+
const report = { timestamp: new Date().toISOString(), checks: {}, advice: [] };
|
|
86
|
+
const { data: { session } } = await this.supabase.auth.getSession();
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const res = await fetch(`${this.workerUrl}?action=list&key=${this.apiKey}`);
|
|
90
|
+
report.checks.connectivity = res.ok ? 'OK' : 'ERROR';
|
|
91
|
+
} catch (e) {
|
|
92
|
+
report.checks.connectivity = 'OFFLINE';
|
|
93
|
+
report.advice.push('ByteX Cloud unreachable. Check internet connection.');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!this.apiKey) report.advice.push('API Key is missing.');
|
|
97
|
+
if (!session) report.advice.push('User is not logged in.');
|
|
98
|
+
if (!this.config.storage) report.advice.push('AsyncStorage engine is missing.');
|
|
99
|
+
|
|
100
|
+
return report;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
_requireKey() { if (!this.apiKey) throw new Error('API Key required!'); }
|
|
104
|
+
}
|
package/index.js
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { createClient } from '@supabase/supabase-js';
|
|
2
|
-
|
|
3
|
-
const SUPABASE_URL = 'https://vkiddclfbwmslaiyyftl.supabase.co';
|
|
4
|
-
const SUPABASE_ANON_KEY = 'sb_publishable_hXMlH9OmJG1_n1s-3lbXKg_6V-88Lj9';
|
|
5
|
-
const WORKER_URL = 'https://api.bytex.work/';
|
|
6
|
-
|
|
7
|
-
export class BytexCloud {
|
|
8
|
-
constructor(config = {}) {
|
|
9
|
-
this.config = config;
|
|
10
|
-
this.apiKey = config.apiKey || null;
|
|
11
|
-
this.workerUrl = config.workerUrl || WORKER_URL;
|
|
12
|
-
|
|
13
|
-
const supabaseConfig = {
|
|
14
|
-
auth: {
|
|
15
|
-
persistSession: true,
|
|
16
|
-
autoRefreshToken: true,
|
|
17
|
-
detectSessionInUrl: false
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
if (config.storage) {
|
|
21
|
-
supabaseConfig.auth.storage = config.storage;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
this.supabase = createClient(config.supabaseUrl || SUPABASE_URL, config.supabaseKey || SUPABASE_ANON_KEY, supabaseConfig);
|
|
25
|
-
this._listeners = {};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// --- CORE METHODS ---
|
|
29
|
-
async login(email, password) {
|
|
30
|
-
const { data, error } = await this.supabase.auth.signInWithPassword({ email, password });
|
|
31
|
-
if (error) throw new Error(error.message);
|
|
32
|
-
return data.user;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async upload(name, data) {
|
|
36
|
-
this._requireKey();
|
|
37
|
-
const fd = new FormData();
|
|
38
|
-
fd.append('file', data instanceof Blob ? data : new Blob([data]), name);
|
|
39
|
-
const res = await fetch(`${this.workerUrl}?action=upload&key=${this.apiKey}`, { method: 'POST', body: fd });
|
|
40
|
-
if (!res.ok) throw new Error(`Upload Failed: ${res.statusText}`);
|
|
41
|
-
return await res.json();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async downloadData(name) {
|
|
45
|
-
this._requireKey();
|
|
46
|
-
const streamName = name.endsWith('.stream.btx') ? name : `${name}.stream.btx`;
|
|
47
|
-
const url = `${this.workerUrl}?action=view&key=${this.apiKey}&file=${encodeURIComponent(streamName)}&_cb=${Date.now()}`;
|
|
48
|
-
const { data: { session } } = await this.supabase.auth.getSession();
|
|
49
|
-
const res = await fetch(url, { headers: { 'Authorization': `Bearer ${session?.access_token || ''}` } });
|
|
50
|
-
if (!res.ok) throw new Error(`Download Failed: ${res.status}`);
|
|
51
|
-
const text = await res.text();
|
|
52
|
-
try { return JSON.parse(text); } catch (e) { return text.split('\n').filter(Boolean).map(line => JSON.parse(line)); }
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async delete(name) {
|
|
56
|
-
this._requireKey();
|
|
57
|
-
const streamName = name.endsWith('.stream.btx') ? name : `${name}.stream.btx`;
|
|
58
|
-
const { data: { session } } = await this.supabase.auth.getSession();
|
|
59
|
-
const res = await fetch(`${this.workerUrl}?action=delete&key=${this.apiKey}&file=${encodeURIComponent(streamName)}`, {
|
|
60
|
-
method: 'DELETE',
|
|
61
|
-
headers: { 'Authorization': `Bearer ${session?.access_token || ''}` }
|
|
62
|
-
});
|
|
63
|
-
if (!res.ok) throw new Error(`Delete Failed: ${res.status}`);
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* ByteX X-RAY v2.1 (The Professional)
|
|
69
|
-
* Detailed diagnostic for Upload, Delete, and Streaming capabilities.
|
|
70
|
-
*/
|
|
71
|
-
async xray() {
|
|
72
|
-
console.log('[ByteX X-RAY] 🔍 Running professional system diagnostics...');
|
|
73
|
-
const report = {
|
|
74
|
-
timestamp: new Date().toISOString(),
|
|
75
|
-
sdk_version: '1.9.5',
|
|
76
|
-
health_score: 100,
|
|
77
|
-
checks: {},
|
|
78
|
-
advice: []
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// 1. Auth & Session Integrity
|
|
82
|
-
const { data: { session } } = await this.supabase.auth.getSession();
|
|
83
|
-
report.checks.auth = { status: session ? 'OK' : 'GUEST', user: session?.user?.email || 'unauthenticated' };
|
|
84
|
-
if (!session) report.advice.push('User is not logged in. Most management operations (delete, protected view) will fail.');
|
|
85
|
-
|
|
86
|
-
// 2. Upload/Write Permission Check
|
|
87
|
-
try {
|
|
88
|
-
this._requireKey();
|
|
89
|
-
const testFd = new FormData();
|
|
90
|
-
testFd.append('file', new Blob(['test']), 'xray_probe.txt');
|
|
91
|
-
const upRes = await fetch(`${this.workerUrl}?action=upload&key=${this.apiKey}&probe=true`, { method: 'POST', body: testFd });
|
|
92
|
-
report.checks.upload_capability = upRes.ok ? 'OK' : 'RESTRICTED';
|
|
93
|
-
if (!upRes.ok) report.advice.push('Upload restricted. Your API Key might be READ-ONLY or the server rejected the probe.');
|
|
94
|
-
} catch (e) {
|
|
95
|
-
report.checks.upload_capability = 'ERROR';
|
|
96
|
-
report.advice.push(`Upload Check Failed: ${e.message}`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// 3. Delete/Management Permission Check
|
|
100
|
-
try {
|
|
101
|
-
const delRes = await fetch(`${this.workerUrl}?action=delete&key=${this.apiKey}&file=non_existent_probe`, {
|
|
102
|
-
method: 'DELETE',
|
|
103
|
-
headers: { 'Authorization': `Bearer ${session?.access_token || ''}` }
|
|
104
|
-
});
|
|
105
|
-
// 404 is actually GOOD here because it means the DELETE method was accepted by the worker
|
|
106
|
-
report.checks.delete_capability = (delRes.status === 404 || delRes.ok) ? 'OK' : 'FORBIDDEN';
|
|
107
|
-
if (delRes.status === 403 || delRes.status === 401) {
|
|
108
|
-
report.advice.push('Delete forbidden. Ensure your session is valid and you have owner permissions.');
|
|
109
|
-
}
|
|
110
|
-
} catch (e) {
|
|
111
|
-
report.checks.delete_capability = 'UNSUPPORTED';
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// 4. Streaming & Range Support
|
|
115
|
-
try {
|
|
116
|
-
const streamRes = await fetch(`${this.workerUrl}?action=view&key=${this.apiKey}&file=probe`, {
|
|
117
|
-
headers: { 'Range': 'bytes=0-1' }
|
|
118
|
-
});
|
|
119
|
-
report.checks.streaming = streamRes.headers.get('Accept-Ranges') ? 'OPTIMIZED' : 'STANDARD';
|
|
120
|
-
if (report.checks.streaming === 'STANDARD') {
|
|
121
|
-
report.advice.push('Server does not support partial content (Ranges). Large video seeking might be slow.');
|
|
122
|
-
}
|
|
123
|
-
} catch (e) { report.checks.streaming = 'UNKNOWN'; }
|
|
124
|
-
|
|
125
|
-
// 5. Code Implementation Audit
|
|
126
|
-
if (!this.config.storage && typeof navigator !== 'undefined') {
|
|
127
|
-
report.checks.implementation = 'INCOMPLETE';
|
|
128
|
-
report.advice.push('React Native detected but "storage" engine is missing in constructor. Sessions will NOT persist across app restarts.');
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const issues = report.advice.length;
|
|
132
|
-
report.final_status = issues === 0 ? 'HEALTHY' : (issues < 3 ? 'WARNING' : 'CRITICAL');
|
|
133
|
-
|
|
134
|
-
return report;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
_requireKey() { if (!this.apiKey) throw new Error('API Key required! Use setApiKey().'); }
|
|
138
|
-
}
|
package/postinstall.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
|
|
3
|
-
console.log('');
|
|
4
|
-
console.log(chalk.blue.bold('========================================='));
|
|
5
|
-
console.log(chalk.cyan.bold(' 🚀 Successfully installed ByteX SDK!'));
|
|
6
|
-
console.log(chalk.blue.bold('========================================='));
|
|
7
|
-
console.log('');
|
|
8
|
-
console.log(chalk.white('Get started by importing the SDK into your project:'));
|
|
9
|
-
console.log('');
|
|
10
|
-
console.log(chalk.gray(' // 1. Initialize ByteX'));
|
|
11
|
-
console.log(chalk.green(" import { BytexCloud } from 'bytex-sdk';"));
|
|
12
|
-
console.log(chalk.green(" const bytex = new BytexCloud();"));
|
|
13
|
-
console.log('');
|
|
14
|
-
console.log(chalk.gray(' // 2. Login & Generate/Select API Key directly in code'));
|
|
15
|
-
console.log(chalk.green(" await bytex.login('your@email.com', 'password');"));
|
|
16
|
-
console.log(chalk.green(" const myKey = await bytex.createKey('My Web App');"));
|
|
17
|
-
console.log(chalk.gray(' // (The active API Key is now set automatically!)'));
|
|
18
|
-
console.log('');
|
|
19
|
-
console.log(chalk.gray(' // 3. Upload a file'));
|
|
20
|
-
console.log(chalk.green(" await bytex.upload('document.pdf', fileData);"));
|
|
21
|
-
console.log('');
|
|
22
|
-
console.log(chalk.white('Want to do this via terminal instead? Try the CLI:'));
|
|
23
|
-
console.log(chalk.cyan(' npx bytex-cli init'));
|
|
24
|
-
console.log('');
|
|
25
|
-
console.log(chalk.gray('For full SDK documentation, visit: https://bytex.work/docs'));
|
|
26
|
-
console.log('');
|