bytex-sdk 1.9.0 → 1.9.5
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/index.js +62 -45
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -25,7 +25,7 @@ export class BytexCloud {
|
|
|
25
25
|
this._listeners = {};
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
//
|
|
28
|
+
// --- CORE METHODS ---
|
|
29
29
|
async login(email, password) {
|
|
30
30
|
const { data, error } = await this.supabase.auth.signInWithPassword({ email, password });
|
|
31
31
|
if (error) throw new Error(error.message);
|
|
@@ -37,85 +37,102 @@ export class BytexCloud {
|
|
|
37
37
|
const fd = new FormData();
|
|
38
38
|
fd.append('file', data instanceof Blob ? data : new Blob([data]), name);
|
|
39
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}`);
|
|
40
41
|
return await res.json();
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
async downloadData(name) {
|
|
44
45
|
this._requireKey();
|
|
45
|
-
const
|
|
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()}`;
|
|
46
48
|
const { data: { session } } = await this.supabase.auth.getSession();
|
|
47
49
|
const res = await fetch(url, { headers: { 'Authorization': `Bearer ${session?.access_token || ''}` } });
|
|
50
|
+
if (!res.ok) throw new Error(`Download Failed: ${res.status}`);
|
|
48
51
|
const text = await res.text();
|
|
49
52
|
try { return JSON.parse(text); } catch (e) { return text.split('\n').filter(Boolean).map(line => JSON.parse(line)); }
|
|
50
53
|
}
|
|
51
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
|
+
|
|
52
67
|
/**
|
|
53
|
-
* ByteX X-RAY v2.
|
|
54
|
-
*
|
|
68
|
+
* ByteX X-RAY v2.1 (The Professional)
|
|
69
|
+
* Detailed diagnostic for Upload, Delete, and Streaming capabilities.
|
|
55
70
|
*/
|
|
56
71
|
async xray() {
|
|
57
|
-
console.log('[ByteX X-RAY] 🔍
|
|
72
|
+
console.log('[ByteX X-RAY] 🔍 Running professional system diagnostics...');
|
|
58
73
|
const report = {
|
|
59
74
|
timestamp: new Date().toISOString(),
|
|
60
|
-
sdk_version: '1.9.
|
|
75
|
+
sdk_version: '1.9.5',
|
|
61
76
|
health_score: 100,
|
|
62
|
-
|
|
77
|
+
checks: {},
|
|
63
78
|
advice: []
|
|
64
79
|
};
|
|
65
80
|
|
|
66
|
-
// 1.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
report.advice.push('React Native detected but no storage engine (AsyncStorage) provided. Sessions will not persist.');
|
|
71
|
-
report.health_score -= 20;
|
|
72
|
-
}
|
|
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.');
|
|
73
85
|
|
|
74
|
-
// 2.
|
|
86
|
+
// 2. Upload/Write Permission Check
|
|
75
87
|
try {
|
|
76
88
|
this._requireKey();
|
|
77
|
-
|
|
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.');
|
|
78
94
|
} catch (e) {
|
|
79
|
-
report.
|
|
80
|
-
report.advice.push(
|
|
81
|
-
report.health_score -= 40;
|
|
95
|
+
report.checks.upload_capability = 'ERROR';
|
|
96
|
+
report.advice.push(`Upload Check Failed: ${e.message}`);
|
|
82
97
|
}
|
|
83
98
|
|
|
84
|
-
// 3.
|
|
85
|
-
const start = Date.now();
|
|
99
|
+
// 3. Delete/Management Permission Check
|
|
86
100
|
try {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
report.advice.push('
|
|
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.');
|
|
95
109
|
}
|
|
96
110
|
} catch (e) {
|
|
97
|
-
report.
|
|
98
|
-
report.advice.push('ByteX Cloud is unreachable. Check your internet or firewall settings.');
|
|
99
|
-
report.health_score -= 30;
|
|
111
|
+
report.checks.delete_capability = 'UNSUPPORTED';
|
|
100
112
|
}
|
|
101
113
|
|
|
102
|
-
// 4.
|
|
114
|
+
// 4. Streaming & Range Support
|
|
103
115
|
try {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
report.health_score -= 10;
|
|
111
|
-
}
|
|
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.');
|
|
112
122
|
}
|
|
113
|
-
} catch (e) {
|
|
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
|
+
}
|
|
114
130
|
|
|
115
|
-
|
|
131
|
+
const issues = report.advice.length;
|
|
132
|
+
report.final_status = issues === 0 ? 'HEALTHY' : (issues < 3 ? 'WARNING' : 'CRITICAL');
|
|
133
|
+
|
|
116
134
|
return report;
|
|
117
135
|
}
|
|
118
136
|
|
|
119
|
-
_requireKey() { if (!this.apiKey) throw new Error('API Key required!'); }
|
|
120
|
-
_emit(event, data) { if (this._listeners[event]) this._listeners[event].forEach(cb => cb(data)); }
|
|
137
|
+
_requireKey() { if (!this.apiKey) throw new Error('API Key required! Use setApiKey().'); }
|
|
121
138
|
}
|