bytex-sdk 1.9.5 → 2.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/index.js +68 -82
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -25,114 +25,100 @@ export class BytexCloud {
|
|
|
25
25
|
this._listeners = {};
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
// ---
|
|
28
|
+
// --- AUTO X-RAY WRAPPER ---
|
|
29
|
+
async _execute(fn, actionName) {
|
|
30
|
+
try {
|
|
31
|
+
return await fn();
|
|
32
|
+
} catch (e) {
|
|
33
|
+
console.warn(`[ByteX SDK] Error in ${actionName}. Running Auto X-RAY...`);
|
|
34
|
+
const diagnostic = await this.xray();
|
|
35
|
+
const advice = diagnostic.advice.length > 0 ? `\n[X-RAY Advice]: ${diagnostic.advice.join(' ')}` : '';
|
|
36
|
+
throw new Error(`${actionName} failed: ${e.message}${advice}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// --- CORE METHODS (ENHANCED WITH AUTO X-RAY) ---
|
|
29
41
|
async login(email, password) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
42
|
+
return this._execute(async () => {
|
|
43
|
+
const { data, error } = await this.supabase.auth.signInWithPassword({ email, password });
|
|
44
|
+
if (error) throw error;
|
|
45
|
+
return data.user;
|
|
46
|
+
}, 'Login');
|
|
33
47
|
}
|
|
34
48
|
|
|
35
49
|
async upload(name, data) {
|
|
36
|
-
this.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
return this._execute(async () => {
|
|
51
|
+
this._requireKey();
|
|
52
|
+
const fd = new FormData();
|
|
53
|
+
fd.append('file', data instanceof Blob ? data : new Blob([data]), name);
|
|
54
|
+
const res = await fetch(`${this.workerUrl}?action=upload&key=${this.apiKey}`, { method: 'POST', body: fd });
|
|
55
|
+
if (!res.ok) throw new Error(await res.text() || res.statusText);
|
|
56
|
+
return await res.json();
|
|
57
|
+
}, 'Upload');
|
|
42
58
|
}
|
|
43
59
|
|
|
44
60
|
async downloadData(name) {
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
return this._execute(async () => {
|
|
62
|
+
this._requireKey();
|
|
63
|
+
const streamName = name.endsWith('.btx') ? name : `${name}.stream.btx`;
|
|
64
|
+
const url = `${this.workerUrl}?action=view&key=${this.apiKey}&file=${encodeURIComponent(streamName)}&_cb=${Date.now()}`;
|
|
65
|
+
const { data: { session } } = await this.supabase.auth.getSession();
|
|
66
|
+
const res = await fetch(url, { headers: { 'Authorization': `Bearer ${session?.access_token || ''}` } });
|
|
67
|
+
if (!res.ok) throw new Error(`Status ${res.status}`);
|
|
68
|
+
const text = await res.text();
|
|
69
|
+
try { return JSON.parse(text); } catch (e) { return text.split('\n').filter(Boolean).map(line => JSON.parse(line)); }
|
|
70
|
+
}, 'Download');
|
|
53
71
|
}
|
|
54
72
|
|
|
55
73
|
async delete(name) {
|
|
56
|
-
this.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
return this._execute(async () => {
|
|
75
|
+
this._requireKey();
|
|
76
|
+
const streamName = name.endsWith('.btx') ? name : `${name}.stream.btx`;
|
|
77
|
+
const { data: { session } } = await this.supabase.auth.getSession();
|
|
78
|
+
const res = await fetch(`${this.workerUrl}?action=delete&key=${this.apiKey}&file=${encodeURIComponent(streamName)}`, {
|
|
79
|
+
method: 'DELETE',
|
|
80
|
+
headers: { 'Authorization': `Bearer ${session?.access_token || ''}` }
|
|
81
|
+
});
|
|
82
|
+
if (!res.ok) throw new Error(`Status ${res.status}`);
|
|
83
|
+
return true;
|
|
84
|
+
}, 'Delete');
|
|
65
85
|
}
|
|
66
86
|
|
|
67
87
|
/**
|
|
68
|
-
* ByteX X-RAY v2.
|
|
69
|
-
* Detailed diagnostic for Upload, Delete, and Streaming capabilities.
|
|
88
|
+
* ByteX X-RAY v2.5 (Self-Healing Diagnostic)
|
|
70
89
|
*/
|
|
71
90
|
async xray() {
|
|
72
|
-
|
|
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
|
|
91
|
+
const report = { timestamp: new Date().toISOString(), sdk_version: '2.0.0', checks: {}, advice: [] };
|
|
82
92
|
const { data: { session } } = await this.supabase.auth.getSession();
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// 2. Upload/Write Permission Check
|
|
93
|
+
|
|
94
|
+
// 1. Connectivity Check
|
|
95
|
+
const start = Date.now();
|
|
87
96
|
try {
|
|
88
|
-
this.
|
|
89
|
-
|
|
90
|
-
|
|
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.');
|
|
97
|
+
const res = await fetch(`${this.workerUrl}?action=list&key=${this.apiKey}`);
|
|
98
|
+
report.checks.connectivity = res.ok ? 'OK' : 'ERROR';
|
|
99
|
+
report.latency = Date.now() - start;
|
|
94
100
|
} catch (e) {
|
|
95
|
-
report.checks.
|
|
96
|
-
report.advice.push(
|
|
101
|
+
report.checks.connectivity = 'OFFLINE';
|
|
102
|
+
report.advice.push('ByteX Cloud is unreachable. Check your internet.');
|
|
97
103
|
}
|
|
98
104
|
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
}
|
|
105
|
+
// 2. API Key Check
|
|
106
|
+
if (!this.apiKey) {
|
|
107
|
+
report.checks.api_key = 'MISSING';
|
|
108
|
+
report.advice.push('No API Key detected. Please provide an apiKey in the constructor.');
|
|
109
|
+
} else { report.checks.api_key = 'OK'; }
|
|
113
110
|
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
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'; }
|
|
111
|
+
// 3. Auth Check
|
|
112
|
+
report.checks.auth = session ? 'AUTHENTICATED' : 'GUEST';
|
|
113
|
+
if (!session) report.advice.push('User is not logged in. Some operations may fail.');
|
|
124
114
|
|
|
125
|
-
//
|
|
115
|
+
// 4. Platform Audit (Mobile/Web)
|
|
126
116
|
if (!this.config.storage && typeof navigator !== 'undefined') {
|
|
127
|
-
report.
|
|
128
|
-
report.advice.push('React Native detected but "storage" engine is missing in constructor. Sessions will NOT persist across app restarts.');
|
|
117
|
+
report.advice.push('Storage engine (AsyncStorage) is missing. Sessions will not persist.');
|
|
129
118
|
}
|
|
130
119
|
|
|
131
|
-
const issues = report.advice.length;
|
|
132
|
-
report.final_status = issues === 0 ? 'HEALTHY' : (issues < 3 ? 'WARNING' : 'CRITICAL');
|
|
133
|
-
|
|
134
120
|
return report;
|
|
135
121
|
}
|
|
136
122
|
|
|
137
|
-
_requireKey() { if (!this.apiKey) throw new Error('API Key required!
|
|
123
|
+
_requireKey() { if (!this.apiKey) throw new Error('API Key required!'); }
|
|
138
124
|
}
|