bytex-sdk 1.8.1 → 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.
Files changed (2) hide show
  1. package/index.js +73 -90
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -6,50 +6,38 @@ const WORKER_URL = 'https://api.bytex.work/';
6
6
 
7
7
  export class BytexCloud {
8
8
  constructor(config = {}) {
9
+ this.config = config;
9
10
  this.apiKey = config.apiKey || null;
10
11
  this.workerUrl = config.workerUrl || WORKER_URL;
11
- this.provider = config.dbProvider || 'supabase';
12
12
 
13
- if (this.provider === 'supabase') {
14
- const url = config.supabaseUrl || SUPABASE_URL;
15
- const key = config.supabaseKey || SUPABASE_ANON_KEY;
16
-
17
- const supabaseConfig = {
18
- auth: {
19
- persistSession: true,
20
- autoRefreshToken: true,
21
- detectSessionInUrl: false
22
- }
23
- };
24
- if (config.storage) {
25
- supabaseConfig.auth.storage = config.storage;
13
+ const supabaseConfig = {
14
+ auth: {
15
+ persistSession: true,
16
+ autoRefreshToken: true,
17
+ detectSessionInUrl: false
26
18
  }
27
-
28
- this.supabase = createClient(url, key, supabaseConfig);
19
+ };
20
+ if (config.storage) {
21
+ supabaseConfig.auth.storage = config.storage;
29
22
  }
30
- this.user = null;
23
+
24
+ this.supabase = createClient(config.supabaseUrl || SUPABASE_URL, config.supabaseKey || SUPABASE_ANON_KEY, supabaseConfig);
31
25
  this._listeners = {};
32
26
  }
33
27
 
28
+ // --- CORE METHODS ---
34
29
  async login(email, password) {
35
30
  const { data, error } = await this.supabase.auth.signInWithPassword({ email, password });
36
- if (error) throw new Error(`Login Failed: ${error.message}`);
37
- this.user = data.user;
38
- this._emit('login', this.user);
31
+ if (error) throw new Error(error.message);
39
32
  return data.user;
40
33
  }
41
34
 
42
35
  async upload(name, data) {
43
36
  this._requireKey();
44
37
  const fd = new FormData();
45
- const blob = data instanceof Blob ? data : new Blob([data]);
46
- fd.append('file', blob, name);
47
-
48
- const res = await fetch(`${this.workerUrl}?action=upload&key=${this.apiKey}`, {
49
- method: 'POST',
50
- body: fd
51
- });
52
- if (!res.ok) throw new Error(`Upload failed: ${await res.text()}`);
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}`);
53
41
  return await res.json();
54
42
  }
55
43
 
@@ -57,22 +45,11 @@ export class BytexCloud {
57
45
  this._requireKey();
58
46
  const streamName = name.endsWith('.stream.btx') ? name : `${name}.stream.btx`;
59
47
  const url = `${this.workerUrl}?action=view&key=${this.apiKey}&file=${encodeURIComponent(streamName)}&_cb=${Date.now()}`;
60
-
61
48
  const { data: { session } } = await this.supabase.auth.getSession();
62
- const res = await fetch(url, {
63
- headers: {
64
- 'Authorization': `Bearer ${session?.access_token || ''}`,
65
- 'Cache-Control': 'no-cache'
66
- }
67
- });
68
- if (!res.ok) throw new Error(`Download failed: ${res.status}`);
49
+ const res = await fetch(url, { headers: { 'Authorization': `Bearer ${session?.access_token || ''}` } });
50
+ if (!res.ok) throw new Error(`Download Failed: ${res.status}`);
69
51
  const text = await res.text();
70
- try {
71
- return JSON.parse(text);
72
- } catch (e) {
73
- // Handle NDJSON
74
- return text.split('\n').filter(Boolean).map(line => JSON.parse(line));
75
- }
52
+ try { return JSON.parse(text); } catch (e) { return text.split('\n').filter(Boolean).map(line => JSON.parse(line)); }
76
53
  }
77
54
 
78
55
  async delete(name) {
@@ -81,75 +58,81 @@ export class BytexCloud {
81
58
  const { data: { session } } = await this.supabase.auth.getSession();
82
59
  const res = await fetch(`${this.workerUrl}?action=delete&key=${this.apiKey}&file=${encodeURIComponent(streamName)}`, {
83
60
  method: 'DELETE',
84
- headers: {
85
- 'Authorization': `Bearer ${session?.access_token || ''}`
86
- }
61
+ headers: { 'Authorization': `Bearer ${session?.access_token || ''}` }
87
62
  });
88
- if (!res.ok) throw new Error(`Delete failed: ${res.status}`);
89
- return { success: true };
90
- }
91
-
92
- async listFiles() {
93
- this._requireKey();
94
- const res = await fetch(`${this.workerUrl}?action=list&key=${this.apiKey}&cb=${Date.now()}`);
95
- if (!res.ok) throw new Error(`List failed: ${res.status}`);
96
- const text = await res.text();
97
- return text.split('\n').filter(Boolean).map(line => JSON.parse(line));
63
+ if (!res.ok) throw new Error(`Delete Failed: ${res.status}`);
64
+ return true;
98
65
  }
99
66
 
100
67
  /**
101
- * ByteX X-RAY: Full system diagnostic.
68
+ * ByteX X-RAY v2.1 (The Professional)
69
+ * Detailed diagnostic for Upload, Delete, and Streaming capabilities.
102
70
  */
103
71
  async xray() {
104
- console.log('[ByteX X-RAY] 🔍 Starting diagnostic scan...');
72
+ console.log('[ByteX X-RAY] 🔍 Running professional system diagnostics...');
105
73
  const report = {
106
74
  timestamp: new Date().toISOString(),
107
- sdk_version: '1.8.1',
108
- checks: {}
75
+ sdk_version: '1.9.5',
76
+ health_score: 100,
77
+ checks: {},
78
+ advice: []
109
79
  };
110
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
111
87
  try {
112
88
  this._requireKey();
113
- report.checks.api_key = { status: 'OK', key: `${this.apiKey.substring(0, 8)}...` };
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.');
114
94
  } catch (e) {
115
- report.checks.api_key = { status: 'ERROR', message: e.message };
95
+ report.checks.upload_capability = 'ERROR';
96
+ report.advice.push(`Upload Check Failed: ${e.message}`);
116
97
  }
117
98
 
118
- const { data: { session } } = await this.supabase.auth.getSession();
119
- report.checks.auth = {
120
- status: session ? 'LOGGED_IN' : 'GUEST',
121
- user: session?.user?.email || 'none'
122
- };
123
-
124
- const start = Date.now();
99
+ // 3. Delete/Management Permission Check
125
100
  try {
126
- const res = await fetch(`${this.workerUrl}?action=list&key=${this.apiKey}`);
127
- report.checks.worker = {
128
- status: res.ok ? 'ONLINE' : 'ERROR',
129
- latency_ms: Date.now() - start
130
- };
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
+ }
131
110
  } catch (e) {
132
- report.checks.worker = { status: 'OFFLINE', message: e.message };
111
+ report.checks.delete_capability = 'UNSUPPORTED';
133
112
  }
134
113
 
135
- const issues = Object.values(report.checks).filter(c => c.status === 'ERROR' || c.status === 'OFFLINE');
136
- report.health_score = issues.length === 0 ? 'EXCELLENT' : 'CRITICAL';
137
-
138
- return report;
139
- }
140
-
141
- _requireKey() {
142
- if (!this.apiKey) throw new Error('API Key required!');
143
- }
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'; }
144
124
 
145
- _emit(event, data) {
146
- if (this._listeners[event]) {
147
- this._listeners[event].forEach(cb => cb(data));
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.');
148
129
  }
149
- }
150
130
 
151
- on(event, callback) {
152
- if (!this._listeners[event]) this._listeners[event] = [];
153
- this._listeners[event].push(callback);
131
+ const issues = report.advice.length;
132
+ report.final_status = issues === 0 ? 'HEALTHY' : (issues < 3 ? 'WARNING' : 'CRITICAL');
133
+
134
+ return report;
154
135
  }
136
+
137
+ _requireKey() { if (!this.apiKey) throw new Error('API Key required! Use setApiKey().'); }
155
138
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bytex-sdk",
3
- "version": "1.8.1",
3
+ "version": "1.9.5",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {