@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
|
@@ -1,45 +1,148 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { LocalStorageAPI } from './db-worker';
|
|
3
|
-
import { toReference, builder } from './flexbuilder';
|
|
4
|
-
|
|
1
|
+
import { expose } from 'comlink';
|
|
5
2
|
|
|
6
3
|
interface SharedWorkerGlobalScope extends Worker {
|
|
7
4
|
onconnect: (event: MessageEvent) => void;
|
|
8
5
|
}
|
|
9
6
|
declare const self: SharedWorkerGlobalScope;
|
|
10
7
|
|
|
11
|
-
|
|
12
8
|
let ws: WebSocket | null = null;
|
|
13
|
-
let onMessageCallback: ((data:
|
|
9
|
+
let onMessageCallback: ((data: string | ArrayBuffer) => void) | null = null;
|
|
10
|
+
let onStatusCallback: ((status: string) => void) | null = null;
|
|
11
|
+
|
|
12
|
+
// Heartbeat
|
|
13
|
+
let heartbeatTimer: ReturnType<typeof setInterval> | null = null;
|
|
14
|
+
let lastPongTime = 0;
|
|
15
|
+
const HEARTBEAT_INTERVAL_MS = 30000;
|
|
16
|
+
const HEARTBEAT_TIMEOUT_MS = 60000;
|
|
17
|
+
|
|
18
|
+
// Reconnect
|
|
19
|
+
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
|
20
|
+
let reconnectAttempts = 0;
|
|
21
|
+
let lastUrl: string | null = null;
|
|
22
|
+
const MAX_RECONNECT_ATTEMPTS = 5;
|
|
23
|
+
const RECONNECT_DELAY_MS = 3000;
|
|
24
|
+
|
|
25
|
+
function startHeartbeat() {
|
|
26
|
+
stopHeartbeat();
|
|
27
|
+
heartbeatTimer = setInterval(() => {
|
|
28
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
29
|
+
stopHeartbeat();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (
|
|
33
|
+
lastPongTime > 0 &&
|
|
34
|
+
Date.now() - lastPongTime > HEARTBEAT_TIMEOUT_MS
|
|
35
|
+
) {
|
|
36
|
+
console.warn('[WS] Heartbeat timeout — closing connection');
|
|
37
|
+
stopHeartbeat();
|
|
38
|
+
ws.close(1001, 'Heartbeat timeout');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
ws.send(JSON.stringify({ type: 'ping' }));
|
|
43
|
+
} catch (err) {
|
|
44
|
+
console.error('[WS] Failed to send heartbeat:', err);
|
|
45
|
+
}
|
|
46
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
47
|
+
}
|
|
14
48
|
|
|
49
|
+
function stopHeartbeat() {
|
|
50
|
+
if (heartbeatTimer) {
|
|
51
|
+
clearInterval(heartbeatTimer);
|
|
52
|
+
heartbeatTimer = null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function broadcastStatus(status: string) {
|
|
57
|
+
onStatusCallback?.(status);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function attemptReconnect() {
|
|
61
|
+
if (!lastUrl || reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
|
62
|
+
if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
|
63
|
+
console.error(
|
|
64
|
+
`[WS] Max reconnect attempts (${MAX_RECONNECT_ATTEMPTS}) reached`,
|
|
65
|
+
);
|
|
66
|
+
broadcastStatus('failed');
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
reconnectAttempts++;
|
|
72
|
+
console.log(
|
|
73
|
+
`[WS] Reconnecting (${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`,
|
|
74
|
+
);
|
|
75
|
+
broadcastStatus('reconnecting');
|
|
76
|
+
|
|
77
|
+
reconnectTimer = setTimeout(() => {
|
|
78
|
+
if (lastUrl) wsInstanceAPI.connect(lastUrl);
|
|
79
|
+
}, RECONNECT_DELAY_MS);
|
|
80
|
+
}
|
|
15
81
|
|
|
16
82
|
// --- WebSocket API ---
|
|
17
83
|
const wsInstanceAPI = {
|
|
18
84
|
async connect(url: string) {
|
|
19
|
-
if (ws) return;
|
|
85
|
+
if (ws && ws.readyState === WebSocket.OPEN) return;
|
|
86
|
+
|
|
87
|
+
// Clean up any existing connection
|
|
88
|
+
if (ws) {
|
|
89
|
+
ws.onclose = null;
|
|
90
|
+
ws.close();
|
|
91
|
+
ws = null;
|
|
92
|
+
}
|
|
20
93
|
|
|
94
|
+
lastUrl = url;
|
|
21
95
|
ws = new WebSocket(url);
|
|
22
96
|
ws.binaryType = 'arraybuffer';
|
|
23
97
|
|
|
24
|
-
ws.onopen = () =>
|
|
98
|
+
ws.onopen = () => {
|
|
99
|
+
console.log('[WS] Connected:', url);
|
|
100
|
+
reconnectAttempts = 0;
|
|
101
|
+
lastPongTime = Date.now();
|
|
102
|
+
startHeartbeat();
|
|
103
|
+
broadcastStatus('connected');
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
ws.onmessage = (e) => {
|
|
107
|
+
try {
|
|
108
|
+
// Handle JSON pong responses
|
|
109
|
+
if (typeof e.data === 'string') {
|
|
110
|
+
try {
|
|
111
|
+
const parsed = JSON.parse(e.data);
|
|
112
|
+
if (parsed.type === 'pong') {
|
|
113
|
+
lastPongTime = Date.now();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
} catch {
|
|
117
|
+
// Not JSON, pass through
|
|
118
|
+
}
|
|
119
|
+
}
|
|
25
120
|
|
|
26
|
-
ws.onmessage = (e) => {
|
|
27
|
-
try {
|
|
28
|
-
console.log('[WS] Received binary message');
|
|
29
|
-
|
|
30
121
|
if (e.data instanceof ArrayBuffer) {
|
|
31
|
-
onMessageCallback?.(e.data);
|
|
122
|
+
onMessageCallback?.(e.data);
|
|
123
|
+
} else {
|
|
124
|
+
onMessageCallback?.(e.data);
|
|
32
125
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
126
|
+
} catch (err) {
|
|
127
|
+
console.error('[WS] Failed to forward message', err);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
ws.onerror = (e) => {
|
|
132
|
+
console.error('[WS] Error:', e);
|
|
133
|
+
broadcastStatus('error');
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
ws.onclose = (event) => {
|
|
137
|
+
console.log('[WS] Disconnected:', event.code, event.reason);
|
|
42
138
|
ws = null;
|
|
139
|
+
stopHeartbeat();
|
|
140
|
+
broadcastStatus('disconnected');
|
|
141
|
+
|
|
142
|
+
// Auto-reconnect on abnormal closure
|
|
143
|
+
if (event.code !== 1000) {
|
|
144
|
+
attemptReconnect();
|
|
145
|
+
}
|
|
43
146
|
};
|
|
44
147
|
},
|
|
45
148
|
|
|
@@ -52,22 +155,50 @@ const wsInstanceAPI = {
|
|
|
52
155
|
},
|
|
53
156
|
|
|
54
157
|
async close() {
|
|
55
|
-
|
|
158
|
+
if (reconnectTimer) {
|
|
159
|
+
clearTimeout(reconnectTimer);
|
|
160
|
+
reconnectTimer = null;
|
|
161
|
+
}
|
|
162
|
+
stopHeartbeat();
|
|
163
|
+
reconnectAttempts = 0;
|
|
164
|
+
lastUrl = null;
|
|
165
|
+
ws?.close(1000, 'Client request');
|
|
56
166
|
ws = null;
|
|
167
|
+
broadcastStatus('disconnected');
|
|
57
168
|
},
|
|
58
169
|
|
|
59
|
-
onMessage(callback: (data:
|
|
170
|
+
onMessage(callback: (data: string | ArrayBuffer) => void) {
|
|
60
171
|
onMessageCallback = callback;
|
|
61
172
|
},
|
|
62
173
|
|
|
174
|
+
onStatus(callback: (status: string) => void) {
|
|
175
|
+
onStatusCallback = callback;
|
|
176
|
+
},
|
|
63
177
|
|
|
178
|
+
async getStatus(): Promise<string> {
|
|
179
|
+
if (!ws) return 'disconnected';
|
|
180
|
+
const map: Record<number, string> = {
|
|
181
|
+
[WebSocket.CONNECTING]: 'connecting',
|
|
182
|
+
[WebSocket.OPEN]: 'connected',
|
|
183
|
+
[WebSocket.CLOSING]: 'closing',
|
|
184
|
+
[WebSocket.CLOSED]: 'disconnected',
|
|
185
|
+
};
|
|
186
|
+
return map[ws.readyState] || 'unknown';
|
|
187
|
+
},
|
|
64
188
|
};
|
|
65
189
|
|
|
66
190
|
export type WSInstance = typeof wsInstanceAPI;
|
|
67
191
|
|
|
192
|
+
const ports = new Set<MessagePort>();
|
|
193
|
+
|
|
68
194
|
self.onconnect = (event: MessageEvent) => {
|
|
69
195
|
const port = event.ports[0];
|
|
196
|
+
const isFirst = ports.size === 0;
|
|
197
|
+
ports.add(port);
|
|
70
198
|
port.start();
|
|
199
|
+
port.postMessage({ type: isFirst ? 'first-connect' : 'reconnect' });
|
|
200
|
+
port.addEventListener('message', (e: MessageEvent) => {
|
|
201
|
+
if (e.data?.type === 'close') ports.delete(port);
|
|
202
|
+
});
|
|
71
203
|
expose(wsInstanceAPI, port);
|
|
72
204
|
};
|
|
73
|
-
|
package/src/setup-vitest.ts
CHANGED
package/src/types.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DroidEvents } from './lib/workers/events';
|
|
2
|
+
import type { FlexDataAPI } from './lib/workers/data';
|
|
3
|
+
import type { ModManager } from './lib/types/modules';
|
|
4
|
+
import type { SupabaseGateway } from './lib/gateway/SupabaseGateway';
|
|
5
|
+
import type { ToastPayload } from './lib/types/ui-event-types';
|
|
6
|
+
import type { DroidScaleLevel } from './lib/workers/main';
|
|
7
|
+
import type { OverlayManager } from './lib/state/overlay-manager';
|
|
8
|
+
|
|
9
|
+
export interface KBVEGlobal {
|
|
10
|
+
api?: unknown;
|
|
11
|
+
i18n?: unknown;
|
|
12
|
+
uiux?: Record<string, unknown>;
|
|
13
|
+
ws?: unknown;
|
|
14
|
+
data?: FlexDataAPI;
|
|
15
|
+
mod?: ModManager;
|
|
16
|
+
events: typeof DroidEvents;
|
|
17
|
+
overlay?: OverlayManager;
|
|
18
|
+
gateway?: SupabaseGateway;
|
|
19
|
+
downscale?: () => Promise<void>;
|
|
20
|
+
upscale?: () => Promise<void>;
|
|
21
|
+
scaleLevel?: () => DroidScaleLevel;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
declare global {
|
|
26
|
+
interface Window {
|
|
27
|
+
kbve: KBVEGlobal;
|
|
28
|
+
__kbveToastQueue?: ToastPayload[] | null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|