@kbve/droid 0.0.6 → 0.1.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.
- package/comlink.js +1 -7
- package/droid.mjs +191 -61
- package/index.d.ts +29 -0
- package/index.js +9054 -2763
- package/lib/gateway/SupabaseGateway.d.ts +38 -0
- package/lib/gateway/SupabaseGateway.d.ts.map +1 -0
- package/lib/gateway/WorkerCommunication.d.ts +39 -0
- package/lib/gateway/WorkerCommunication.d.ts.map +1 -0
- package/lib/gateway/WorkerPool.d.ts +55 -0
- package/lib/gateway/WorkerPool.d.ts.map +1 -0
- package/lib/gateway/capabilities.d.ts +23 -0
- package/lib/gateway/capabilities.d.ts.map +1 -0
- package/lib/gateway/index.d.ts +9 -0
- package/lib/gateway/index.d.ts.map +1 -0
- package/lib/gateway/strategies/DirectStrategy.d.ts +52 -0
- package/lib/gateway/strategies/DirectStrategy.d.ts.map +1 -0
- package/lib/gateway/strategies/SharedWorkerStrategy.d.ts +46 -0
- package/lib/gateway/strategies/SharedWorkerStrategy.d.ts.map +1 -0
- package/lib/gateway/strategies/WebWorkerStrategy.d.ts +45 -0
- package/lib/gateway/strategies/WebWorkerStrategy.d.ts.map +1 -0
- package/lib/gateway/types.d.ts +81 -0
- package/lib/gateway/types.d.ts.map +1 -0
- package/lib/workers/canvas-ui-renderer.d.ts +25 -0
- package/lib/workers/canvas-ui-renderer.d.ts.map +1 -0
- package/lib/workers/canvas-worker.d.ts +14 -0
- package/lib/workers/canvas-worker.d.ts.map +1 -0
- package/lib/workers/canvas-worker.js +291 -145
- package/lib/workers/data.d.ts +40 -0
- package/lib/workers/data.d.ts.map +1 -0
- package/lib/workers/db-worker.d.ts +69 -0
- package/lib/workers/db-worker.d.ts.map +1 -0
- package/lib/workers/db-worker.js +2680 -2147
- package/lib/workers/events.d.ts +11 -0
- package/lib/workers/events.d.ts.map +1 -0
- package/lib/workers/flexbuilder.d.ts +4 -0
- package/lib/workers/flexbuilder.d.ts.map +1 -0
- package/lib/workers/init.d.ts +11 -0
- package/lib/workers/init.d.ts.map +1 -0
- package/lib/workers/main.d.ts +107 -0
- package/lib/workers/main.d.ts.map +1 -0
- package/lib/workers/supabase-db-worker.d.ts +2 -0
- package/lib/workers/supabase-db-worker.d.ts.map +1 -0
- package/lib/workers/supabase-db-worker.js +9337 -0
- package/lib/workers/supabase-shared-worker.d.ts +2 -0
- package/lib/workers/supabase-shared-worker.d.ts.map +1 -0
- package/lib/workers/supabase-shared-worker.js +12635 -0
- package/lib/workers/tools.d.ts +4 -0
- package/lib/workers/tools.d.ts.map +1 -0
- package/lib/workers/validate.d.ts +15 -0
- package/lib/workers/validate.d.ts.map +1 -0
- package/lib/workers/ws-worker.d.ts +11 -0
- package/lib/workers/ws-worker.d.ts.map +1 -0
- package/lib/workers/ws-worker.js +174 -115
- package/main.js +4875 -0
- package/package.json +17 -6
- package/reference.js +688 -228
- package/src/index.ts +38 -13
- package/src/lib/droid.spec.ts +14 -19
- package/src/lib/droid.ts +48 -4
- package/src/lib/gateway/SupabaseGateway.ts +183 -0
- package/src/lib/gateway/WorkerCommunication.ts +132 -0
- package/src/lib/gateway/WorkerPool.ts +304 -0
- package/src/lib/gateway/capabilities.ts +80 -0
- package/src/lib/gateway/index.ts +15 -0
- package/src/lib/gateway/strategies/DirectStrategy.ts +443 -0
- package/src/lib/gateway/strategies/SharedWorkerStrategy.ts +278 -0
- package/src/lib/gateway/strategies/WebWorkerStrategy.ts +278 -0
- package/src/lib/gateway/types.ts +112 -0
- package/src/lib/mod/mod-manager.ts +13 -8
- package/src/lib/mod/module/bento/mod-bento.worker.ts +1 -1
- package/src/lib/mod/module/supabase/mod-supabase.spec.ts +21 -25
- package/src/lib/mod/module/supabase/mod-supabase.ts +68 -0
- package/src/lib/mod/module/supabase/mod-supabase.worker.ts +1 -56
- package/src/lib/state/auth.spec.ts +58 -0
- package/src/lib/state/auth.ts +30 -0
- package/src/lib/state/index.ts +34 -0
- package/src/lib/state/overlay-manager.ts +125 -0
- package/src/lib/state/router.ts +24 -0
- package/src/lib/state/theme-sync.ts +75 -0
- package/src/lib/state/toasts.spec.ts +106 -0
- package/src/lib/state/toasts.ts +34 -0
- package/src/lib/state/ui.spec.ts +148 -0
- package/src/lib/state/ui.ts +45 -0
- package/src/lib/state/welcome-toast.ts +76 -0
- package/src/lib/types/bento.spec.ts +116 -0
- package/src/lib/types/bento.ts +94 -55
- package/src/lib/types/event-types.spec.ts +93 -0
- package/src/lib/types/event-types.ts +39 -3
- package/src/lib/types/modules.ts +12 -5
- package/src/lib/types/ui-event-types.ts +66 -0
- package/src/lib/workers/canvas-ui-renderer.ts +266 -0
- package/src/lib/workers/canvas-worker.ts +94 -9
- package/src/lib/workers/data.ts +59 -36
- package/src/lib/workers/db-worker.ts +79 -32
- package/src/lib/workers/events.spec.ts +208 -0
- package/src/lib/workers/events.ts +27 -14
- package/src/lib/workers/flexbuilder.ts +2 -2
- package/src/lib/workers/init.ts +25 -17
- package/src/lib/workers/main.ts +510 -316
- package/src/lib/workers/supabase-db-worker.ts +221 -0
- package/src/lib/workers/supabase-shared-worker.ts +572 -0
- package/src/lib/workers/validate.ts +64 -0
- package/src/lib/workers/ws-worker.ts +156 -25
- package/src/setup-vitest.ts +4 -2
- package/src/types.ts +30 -0
- package/src/vite-env.d.ts +1 -0
- package/workers/main.js +10 -1123
- package/src/types.d.ts +0 -31
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
// Worker pool manager with round-robin routing for DB operations
|
|
2
|
+
|
|
3
|
+
import type { WorkerMessage, WorkerResponse } from './types';
|
|
4
|
+
|
|
5
|
+
export interface WorkerPoolConfig {
|
|
6
|
+
size: number;
|
|
7
|
+
workerUrl: string | URL;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* WorkerPool: Manages a pool of workers with round-robin load balancing
|
|
12
|
+
*
|
|
13
|
+
* Features:
|
|
14
|
+
* - Fixed-size pool (default: 3 workers)
|
|
15
|
+
* - Round-robin routing for database operations
|
|
16
|
+
* - Request/response tracking with UUIDs
|
|
17
|
+
* - Automatic error handling with exponential backoff retries
|
|
18
|
+
*/
|
|
19
|
+
export class WorkerPool {
|
|
20
|
+
private workers: Worker[] = [];
|
|
21
|
+
private poolSize: number;
|
|
22
|
+
private roundRobinIndex = 0;
|
|
23
|
+
private pending = new Map<
|
|
24
|
+
string,
|
|
25
|
+
{
|
|
26
|
+
resolve: (value: unknown) => void;
|
|
27
|
+
reject: (reason?: unknown) => void;
|
|
28
|
+
workerId: number;
|
|
29
|
+
}
|
|
30
|
+
>();
|
|
31
|
+
private workerUrl: string | URL;
|
|
32
|
+
private workerRetryCount = new Map<number, number>();
|
|
33
|
+
private workerRetryTimers = new Map<
|
|
34
|
+
number,
|
|
35
|
+
ReturnType<typeof setTimeout>
|
|
36
|
+
>();
|
|
37
|
+
|
|
38
|
+
private readonly MAX_RETRY_ATTEMPTS = 3;
|
|
39
|
+
private readonly BASE_RETRY_DELAY_MS = 1000;
|
|
40
|
+
private readonly MAX_RETRY_DELAY_MS = 8000;
|
|
41
|
+
private readonly REQUEST_TIMEOUT_MS = 30000;
|
|
42
|
+
|
|
43
|
+
constructor(config: WorkerPoolConfig) {
|
|
44
|
+
this.poolSize = config.size;
|
|
45
|
+
this.workerUrl = config.workerUrl;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Initialize the worker pool
|
|
50
|
+
*/
|
|
51
|
+
async init(): Promise<void> {
|
|
52
|
+
console.log(
|
|
53
|
+
`[WorkerPool] Initializing pool with ${this.poolSize} workers`,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i < this.poolSize; i++) {
|
|
57
|
+
try {
|
|
58
|
+
const worker = new Worker(this.workerUrl, {
|
|
59
|
+
type: 'module',
|
|
60
|
+
name: `db-worker-${i}`,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
worker.onmessage = (e: MessageEvent) =>
|
|
64
|
+
this.handleMessage(e.data, i);
|
|
65
|
+
worker.onerror = (err) => this.handleError(err, i);
|
|
66
|
+
|
|
67
|
+
this.workers.push(worker);
|
|
68
|
+
console.log(`[WorkerPool] Worker ${i} initialized`);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
console.error(
|
|
71
|
+
`[WorkerPool] Failed to create worker ${i}:`,
|
|
72
|
+
err,
|
|
73
|
+
);
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Wait for all workers to be ready
|
|
79
|
+
await Promise.all(
|
|
80
|
+
this.workers.map((_worker, i) =>
|
|
81
|
+
this.sendToWorker(i, {
|
|
82
|
+
id: crypto.randomUUID(),
|
|
83
|
+
type: 'ping',
|
|
84
|
+
payload: {},
|
|
85
|
+
}),
|
|
86
|
+
),
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
console.log('[WorkerPool] All workers ready');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private getNextWorker(): number {
|
|
93
|
+
const workerId = this.roundRobinIndex;
|
|
94
|
+
this.roundRobinIndex = (this.roundRobinIndex + 1) % this.poolSize;
|
|
95
|
+
return workerId;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private sendToWorker<T>(
|
|
99
|
+
workerId: number,
|
|
100
|
+
message: WorkerMessage,
|
|
101
|
+
): Promise<T> {
|
|
102
|
+
return new Promise<T>((resolve, reject) => {
|
|
103
|
+
const worker = this.workers[workerId];
|
|
104
|
+
if (!worker) {
|
|
105
|
+
return reject(new Error(`Worker ${workerId} not available`));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const timer = setTimeout(() => {
|
|
109
|
+
if (this.pending.has(message.id)) {
|
|
110
|
+
this.pending.delete(message.id);
|
|
111
|
+
reject(
|
|
112
|
+
new Error(
|
|
113
|
+
`Worker ${workerId} request ${message.type} timed out after ${this.REQUEST_TIMEOUT_MS}ms`,
|
|
114
|
+
),
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}, this.REQUEST_TIMEOUT_MS);
|
|
118
|
+
|
|
119
|
+
this.pending.set(message.id, {
|
|
120
|
+
resolve: (value: unknown) => {
|
|
121
|
+
clearTimeout(timer);
|
|
122
|
+
resolve(value as T);
|
|
123
|
+
},
|
|
124
|
+
reject: (err: unknown) => {
|
|
125
|
+
clearTimeout(timer);
|
|
126
|
+
reject(err);
|
|
127
|
+
},
|
|
128
|
+
workerId,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
worker.postMessage(message);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
clearTimeout(timer);
|
|
135
|
+
this.pending.delete(message.id);
|
|
136
|
+
reject(err);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Send message to next available worker (round-robin)
|
|
143
|
+
*/
|
|
144
|
+
send<T>(type: string, payload?: unknown): Promise<T> {
|
|
145
|
+
const workerId = this.getNextWorker();
|
|
146
|
+
const id = crypto.randomUUID();
|
|
147
|
+
const message: WorkerMessage = { id, type, payload };
|
|
148
|
+
|
|
149
|
+
return this.sendToWorker<T>(workerId, message);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private handleMessage(response: WorkerResponse, workerId: number) {
|
|
153
|
+
const { id, ok, data, error } = response;
|
|
154
|
+
|
|
155
|
+
if (!id) {
|
|
156
|
+
console.warn(
|
|
157
|
+
`[WorkerPool] Worker ${workerId} sent message without ID:`,
|
|
158
|
+
response,
|
|
159
|
+
);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const pending = this.pending.get(id);
|
|
164
|
+
if (!pending) {
|
|
165
|
+
console.warn(
|
|
166
|
+
`[WorkerPool] Received response for unknown request ${id}`,
|
|
167
|
+
);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
this.pending.delete(id);
|
|
172
|
+
|
|
173
|
+
if (ok) {
|
|
174
|
+
pending.resolve(data);
|
|
175
|
+
} else {
|
|
176
|
+
pending.reject(new Error(error || 'Worker request failed'));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private handleError(error: ErrorEvent, workerId: number) {
|
|
181
|
+
console.error(`[WorkerPool] Worker ${workerId} error:`, error);
|
|
182
|
+
|
|
183
|
+
const failedRequests: string[] = [];
|
|
184
|
+
for (const [id, pending] of this.pending.entries()) {
|
|
185
|
+
if (pending.workerId === workerId) {
|
|
186
|
+
pending.reject(
|
|
187
|
+
new Error(`Worker ${workerId} crashed: ${error.message}`),
|
|
188
|
+
);
|
|
189
|
+
failedRequests.push(id);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
failedRequests.forEach((id) => this.pending.delete(id));
|
|
194
|
+
|
|
195
|
+
this.scheduleWorkerRecreation(workerId);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private scheduleWorkerRecreation(workerId: number) {
|
|
199
|
+
const retryCount = this.workerRetryCount.get(workerId) || 0;
|
|
200
|
+
|
|
201
|
+
if (retryCount >= this.MAX_RETRY_ATTEMPTS) {
|
|
202
|
+
console.error(
|
|
203
|
+
`[WorkerPool] Worker ${workerId} has failed ${retryCount} times. Giving up.`,
|
|
204
|
+
);
|
|
205
|
+
this.workerRetryCount.delete(workerId);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const delay = Math.min(
|
|
210
|
+
this.BASE_RETRY_DELAY_MS * Math.pow(2, retryCount),
|
|
211
|
+
this.MAX_RETRY_DELAY_MS,
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
console.log(
|
|
215
|
+
`[WorkerPool] Scheduling worker ${workerId} recreation in ${delay}ms (attempt ${retryCount + 1}/${this.MAX_RETRY_ATTEMPTS})`,
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const existingTimer = this.workerRetryTimers.get(workerId);
|
|
219
|
+
if (existingTimer) {
|
|
220
|
+
clearTimeout(existingTimer);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const timer = setTimeout(() => {
|
|
224
|
+
this.workerRetryTimers.delete(workerId);
|
|
225
|
+
this.recreateWorker(workerId);
|
|
226
|
+
}, delay);
|
|
227
|
+
|
|
228
|
+
this.workerRetryTimers.set(workerId, timer);
|
|
229
|
+
this.workerRetryCount.set(workerId, retryCount + 1);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private async recreateWorker(workerId: number) {
|
|
233
|
+
const retryCount = this.workerRetryCount.get(workerId) || 0;
|
|
234
|
+
console.log(
|
|
235
|
+
`[WorkerPool] Attempting to recreate worker ${workerId} (attempt ${retryCount}/${this.MAX_RETRY_ATTEMPTS})`,
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
const worker = new Worker(this.workerUrl, {
|
|
240
|
+
type: 'module',
|
|
241
|
+
name: `db-worker-${workerId}`,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
worker.onmessage = (e: MessageEvent) =>
|
|
245
|
+
this.handleMessage(e.data, workerId);
|
|
246
|
+
worker.onerror = (err) => this.handleError(err, workerId);
|
|
247
|
+
|
|
248
|
+
this.workers[workerId] = worker;
|
|
249
|
+
|
|
250
|
+
await this.sendToWorker(workerId, {
|
|
251
|
+
id: crypto.randomUUID(),
|
|
252
|
+
type: 'ping',
|
|
253
|
+
payload: {},
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
console.log(
|
|
257
|
+
`[WorkerPool] Worker ${workerId} recreated successfully`,
|
|
258
|
+
);
|
|
259
|
+
this.workerRetryCount.delete(workerId);
|
|
260
|
+
} catch (err) {
|
|
261
|
+
console.error(
|
|
262
|
+
`[WorkerPool] Failed to recreate worker ${workerId}:`,
|
|
263
|
+
err,
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Terminate all workers
|
|
270
|
+
*/
|
|
271
|
+
terminate() {
|
|
272
|
+
console.log('[WorkerPool] Terminating all workers');
|
|
273
|
+
|
|
274
|
+
this.workerRetryTimers.forEach((timer) => clearTimeout(timer));
|
|
275
|
+
this.workerRetryTimers.clear();
|
|
276
|
+
this.workerRetryCount.clear();
|
|
277
|
+
|
|
278
|
+
this.workers.forEach((worker, i) => {
|
|
279
|
+
try {
|
|
280
|
+
worker.terminate();
|
|
281
|
+
} catch (err) {
|
|
282
|
+
console.error(
|
|
283
|
+
`[WorkerPool] Error terminating worker ${i}:`,
|
|
284
|
+
err,
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
this.workers = [];
|
|
290
|
+
this.pending.clear();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Get pool statistics
|
|
295
|
+
*/
|
|
296
|
+
getStats() {
|
|
297
|
+
return {
|
|
298
|
+
size: this.poolSize,
|
|
299
|
+
activeWorkers: this.workers.length,
|
|
300
|
+
pendingRequests: this.pending.size,
|
|
301
|
+
nextWorker: this.roundRobinIndex,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Browser capability detection for strategy selection
|
|
2
|
+
|
|
3
|
+
import type { BrowserCapabilities, StrategyType } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Detect browser capabilities for worker and communication support
|
|
7
|
+
*/
|
|
8
|
+
export function detectCapabilities(): BrowserCapabilities {
|
|
9
|
+
// SSR guard
|
|
10
|
+
if (typeof window === 'undefined') {
|
|
11
|
+
return {
|
|
12
|
+
hasSharedWorker: false,
|
|
13
|
+
hasWorker: false,
|
|
14
|
+
hasBroadcastChannel: false,
|
|
15
|
+
isAndroid: false,
|
|
16
|
+
isSafari: false,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const userAgent = navigator.userAgent || '';
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
hasSharedWorker: typeof SharedWorker !== 'undefined',
|
|
24
|
+
hasWorker: typeof Worker !== 'undefined',
|
|
25
|
+
hasBroadcastChannel: typeof BroadcastChannel !== 'undefined',
|
|
26
|
+
isAndroid: /Android/i.test(userAgent),
|
|
27
|
+
isSafari: /Safari/i.test(userAgent) && !/Chrome/i.test(userAgent),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Select the best strategy based on browser capabilities
|
|
33
|
+
*
|
|
34
|
+
* Priority:
|
|
35
|
+
* 1. SharedWorker + Worker Pool (desktop Chrome, Firefox, Edge)
|
|
36
|
+
* 2. WebWorker Pool only (Android, Safari, or no SharedWorker)
|
|
37
|
+
* 3. Direct/Main thread (emergency fallback)
|
|
38
|
+
*/
|
|
39
|
+
export function selectStrategy(capabilities?: BrowserCapabilities): StrategyType {
|
|
40
|
+
const caps = capabilities || detectCapabilities();
|
|
41
|
+
|
|
42
|
+
// Desktop with SharedWorker support (best performance)
|
|
43
|
+
if (caps.hasSharedWorker && caps.hasBroadcastChannel && !caps.isAndroid) {
|
|
44
|
+
return 'shared-worker';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Android or browsers without SharedWorker (still use worker pool)
|
|
48
|
+
if (caps.hasWorker && caps.hasBroadcastChannel) {
|
|
49
|
+
return 'web-worker';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Fallback to main thread (no workers or BroadcastChannel)
|
|
53
|
+
return 'direct';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Log detected capabilities for debugging
|
|
58
|
+
*/
|
|
59
|
+
export function logCapabilities(capabilities: BrowserCapabilities) {
|
|
60
|
+
console.log('[SupabaseGateway] Browser capabilities:', {
|
|
61
|
+
SharedWorker: capabilities.hasSharedWorker ? 'yes' : 'no',
|
|
62
|
+
Worker: capabilities.hasWorker ? 'yes' : 'no',
|
|
63
|
+
BroadcastChannel: capabilities.hasBroadcastChannel ? 'yes' : 'no',
|
|
64
|
+
Platform: capabilities.isAndroid ? 'Android' : capabilities.isSafari ? 'Safari' : 'Desktop',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get a human-readable description of the selected strategy
|
|
70
|
+
*/
|
|
71
|
+
export function getStrategyDescription(strategy: StrategyType): string {
|
|
72
|
+
switch (strategy) {
|
|
73
|
+
case 'shared-worker':
|
|
74
|
+
return 'SharedWorker + DB Worker Pool (optimal for desktop)';
|
|
75
|
+
case 'web-worker':
|
|
76
|
+
return 'WebSocket Worker + DB Worker Pool (optimized for mobile)';
|
|
77
|
+
case 'direct':
|
|
78
|
+
return 'Direct/Main thread (compatibility fallback)';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Main exports for Supabase Gateway
|
|
2
|
+
|
|
3
|
+
export { SupabaseGateway } from './SupabaseGateway';
|
|
4
|
+
export { WorkerPool } from './WorkerPool';
|
|
5
|
+
export { getWorkerCommunication, WorkerCommunication } from './WorkerCommunication';
|
|
6
|
+
export {
|
|
7
|
+
detectCapabilities,
|
|
8
|
+
selectStrategy,
|
|
9
|
+
logCapabilities,
|
|
10
|
+
getStrategyDescription
|
|
11
|
+
} from './capabilities';
|
|
12
|
+
export * from './types';
|
|
13
|
+
export { SharedWorkerStrategy } from './strategies/SharedWorkerStrategy';
|
|
14
|
+
export { WebWorkerStrategy } from './strategies/WebWorkerStrategy';
|
|
15
|
+
export { DirectStrategy } from './strategies/DirectStrategy';
|