@kbve/droid 0.0.6 → 0.1.2

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 (190) hide show
  1. package/droid.mjs +2312 -74
  2. package/index.d.ts +32 -0
  3. package/lib/agents/api-types.d.ts +121 -0
  4. package/lib/agents/api-types.d.ts.map +1 -0
  5. package/lib/agents/auth/init.d.ts +8 -0
  6. package/lib/agents/auth/init.d.ts.map +1 -0
  7. package/lib/agents/cache.d.ts +9 -0
  8. package/lib/agents/cache.d.ts.map +1 -0
  9. package/lib/agents/client/callGuildVault.d.ts +3 -0
  10. package/lib/agents/client/callGuildVault.d.ts.map +1 -0
  11. package/lib/agents/client/callJson.d.ts +3 -0
  12. package/lib/agents/client/callJson.d.ts.map +1 -0
  13. package/lib/agents/config.d.ts +36 -0
  14. package/lib/agents/config.d.ts.map +1 -0
  15. package/lib/agents/constants.d.ts +11 -0
  16. package/lib/agents/constants.d.ts.map +1 -0
  17. package/lib/agents/createAgents.d.ts +4 -0
  18. package/lib/agents/createAgents.d.ts.map +1 -0
  19. package/lib/agents/ctx.d.ts +46 -0
  20. package/lib/agents/ctx.d.ts.map +1 -0
  21. package/lib/agents/discord/bot.d.ts +21 -0
  22. package/lib/agents/discord/bot.d.ts.map +1 -0
  23. package/lib/agents/discord/guilds.d.ts +8 -0
  24. package/lib/agents/discord/guilds.d.ts.map +1 -0
  25. package/lib/agents/formDrafts.d.ts +5 -0
  26. package/lib/agents/formDrafts.d.ts.map +1 -0
  27. package/lib/agents/generated/agents-schema.d.ts +73 -0
  28. package/lib/agents/generated/agents-schema.d.ts.map +1 -0
  29. package/lib/agents/generated/discordsh-agents-schema.d.ts +71 -0
  30. package/lib/agents/generated/discordsh-agents-schema.d.ts.map +1 -0
  31. package/lib/agents/github/backfill.d.ts +23 -0
  32. package/lib/agents/github/backfill.d.ts.map +1 -0
  33. package/lib/agents/github/events.d.ts +10 -0
  34. package/lib/agents/github/events.d.ts.map +1 -0
  35. package/lib/agents/github/pat.d.ts +13 -0
  36. package/lib/agents/github/pat.d.ts.map +1 -0
  37. package/lib/agents/github/repoConfig.d.ts +25 -0
  38. package/lib/agents/github/repoConfig.d.ts.map +1 -0
  39. package/lib/agents/github/tokens.d.ts +22 -0
  40. package/lib/agents/github/tokens.d.ts.map +1 -0
  41. package/lib/agents/github/webhook.d.ts +37 -0
  42. package/lib/agents/github/webhook.d.ts.map +1 -0
  43. package/lib/agents/index.d.ts +8 -0
  44. package/lib/agents/index.d.ts.map +1 -0
  45. package/lib/agents/state/atoms.d.ts +122 -0
  46. package/lib/agents/state/atoms.d.ts.map +1 -0
  47. package/lib/agents/types.d.ts +65 -0
  48. package/lib/agents/types.d.ts.map +1 -0
  49. package/lib/gateway/SupabaseGateway.d.ts +38 -0
  50. package/lib/gateway/SupabaseGateway.d.ts.map +1 -0
  51. package/lib/gateway/WorkerCommunication.d.ts +39 -0
  52. package/lib/gateway/WorkerCommunication.d.ts.map +1 -0
  53. package/lib/gateway/WorkerPool.d.ts +55 -0
  54. package/lib/gateway/WorkerPool.d.ts.map +1 -0
  55. package/lib/gateway/capabilities.d.ts +23 -0
  56. package/lib/gateway/capabilities.d.ts.map +1 -0
  57. package/lib/gateway/index.d.ts +9 -0
  58. package/lib/gateway/index.d.ts.map +1 -0
  59. package/lib/gateway/strategies/DirectStrategy.d.ts +52 -0
  60. package/lib/gateway/strategies/DirectStrategy.d.ts.map +1 -0
  61. package/lib/gateway/strategies/SharedWorkerStrategy.d.ts +46 -0
  62. package/lib/gateway/strategies/SharedWorkerStrategy.d.ts.map +1 -0
  63. package/lib/gateway/strategies/WebWorkerStrategy.d.ts +45 -0
  64. package/lib/gateway/strategies/WebWorkerStrategy.d.ts.map +1 -0
  65. package/lib/gateway/types.d.ts +81 -0
  66. package/lib/gateway/types.d.ts.map +1 -0
  67. package/lib/workers/canvas-ui-renderer.d.ts +25 -0
  68. package/lib/workers/canvas-ui-renderer.d.ts.map +1 -0
  69. package/lib/workers/canvas-worker.d.ts +14 -0
  70. package/lib/workers/canvas-worker.d.ts.map +1 -0
  71. package/lib/workers/canvas-worker.js +5 -302
  72. package/lib/workers/data.d.ts +40 -0
  73. package/lib/workers/data.d.ts.map +1 -0
  74. package/lib/workers/db-worker.d.ts +69 -0
  75. package/lib/workers/db-worker.d.ts.map +1 -0
  76. package/lib/workers/db-worker.js +13 -3636
  77. package/lib/workers/events.d.ts +11 -0
  78. package/lib/workers/events.d.ts.map +1 -0
  79. package/lib/workers/flexbuilder.d.ts +4 -0
  80. package/lib/workers/flexbuilder.d.ts.map +1 -0
  81. package/lib/workers/init.d.ts +11 -0
  82. package/lib/workers/init.d.ts.map +1 -0
  83. package/lib/workers/main.d.ts +105 -0
  84. package/lib/workers/main.d.ts.map +1 -0
  85. package/lib/workers/supabase-db-worker.d.ts +2 -0
  86. package/lib/workers/supabase-db-worker.d.ts.map +1 -0
  87. package/lib/workers/supabase-db-worker.js +23 -0
  88. package/lib/workers/supabase-shared-worker.d.ts +2 -0
  89. package/lib/workers/supabase-shared-worker.d.ts.map +1 -0
  90. package/lib/workers/supabase-shared-worker.js +25 -0
  91. package/lib/workers/tools.d.ts +4 -0
  92. package/lib/workers/tools.d.ts.map +1 -0
  93. package/lib/workers/validate.d.ts +15 -0
  94. package/lib/workers/validate.d.ts.map +1 -0
  95. package/lib/workers/ws-worker.d.ts +10 -0
  96. package/lib/workers/ws-worker.d.ts.map +1 -0
  97. package/lib/workers/ws-worker.js +5 -273
  98. package/main.js +5711 -0
  99. package/package.json +18 -6
  100. package/src/index.ts +41 -13
  101. package/src/lib/agents/api-types.ts +170 -0
  102. package/src/lib/agents/auth/init.ts +200 -0
  103. package/src/lib/agents/cache.ts +127 -0
  104. package/src/lib/agents/client/callGuildVault.ts +71 -0
  105. package/src/lib/agents/client/callJson.ts +64 -0
  106. package/src/lib/agents/config.ts +83 -0
  107. package/src/lib/agents/constants.ts +11 -0
  108. package/src/lib/agents/createAgents.ts +62 -0
  109. package/src/lib/agents/ctx.ts +63 -0
  110. package/src/lib/agents/discord/bot.ts +169 -0
  111. package/src/lib/agents/discord/guilds.ts +106 -0
  112. package/src/lib/agents/formDrafts.ts +55 -0
  113. package/src/lib/agents/generated/agents-schema.ts +155 -0
  114. package/src/lib/agents/generated/discordsh-agents-schema.ts +96 -0
  115. package/src/lib/agents/github/backfill.ts +126 -0
  116. package/src/lib/agents/github/events.ts +131 -0
  117. package/src/lib/agents/github/pat.ts +150 -0
  118. package/src/lib/agents/github/repoConfig.ts +240 -0
  119. package/src/lib/agents/github/tokens.ts +222 -0
  120. package/src/lib/agents/github/webhook.ts +349 -0
  121. package/src/lib/agents/index.ts +35 -0
  122. package/src/lib/agents/state/atoms.ts +122 -0
  123. package/src/lib/agents/types.ts +83 -0
  124. package/src/lib/api.ts +71 -0
  125. package/src/lib/droid.spec.ts +14 -19
  126. package/src/lib/droid.ts +48 -4
  127. package/src/lib/gateway/SupabaseGateway.ts +236 -0
  128. package/src/lib/gateway/WorkerCommunication.ts +132 -0
  129. package/src/lib/gateway/WorkerPool.ts +304 -0
  130. package/src/lib/gateway/capabilities.spec.ts +144 -0
  131. package/src/lib/gateway/capabilities.ts +80 -0
  132. package/src/lib/gateway/index.ts +15 -0
  133. package/src/lib/gateway/strategies/DirectStrategy.ts +443 -0
  134. package/src/lib/gateway/strategies/SharedWorkerStrategy.ts +278 -0
  135. package/src/lib/gateway/strategies/WebWorkerStrategy.ts +278 -0
  136. package/src/lib/gateway/types.ts +139 -0
  137. package/src/lib/mod/mod-manager.ts +13 -8
  138. package/src/lib/mod/module/bento/mod-bento.worker.ts +1 -1
  139. package/src/lib/mod/module/supabase/mod-supabase.spec.ts +21 -25
  140. package/src/lib/mod/module/supabase/mod-supabase.ts +73 -0
  141. package/src/lib/mod/module/supabase/mod-supabase.worker.ts +1 -56
  142. package/src/lib/state/auth.spec.ts +58 -0
  143. package/src/lib/state/auth.ts +148 -0
  144. package/src/lib/state/bento.spec.ts +76 -0
  145. package/src/lib/state/bento.ts +51 -0
  146. package/src/lib/state/index.ts +98 -0
  147. package/src/lib/state/overlay-manager.ts +125 -0
  148. package/src/lib/state/profile-sync.ts +214 -0
  149. package/src/lib/state/profile.ts +155 -0
  150. package/src/lib/state/router.ts +24 -0
  151. package/src/lib/state/staff.ts +128 -0
  152. package/src/lib/state/sync-bus.ts +109 -0
  153. package/src/lib/state/theme-sync.ts +75 -0
  154. package/src/lib/state/toasts.spec.ts +106 -0
  155. package/src/lib/state/toasts.ts +34 -0
  156. package/src/lib/state/ui.spec.ts +148 -0
  157. package/src/lib/state/ui.ts +45 -0
  158. package/src/lib/state/welcome-toast.spec.ts +101 -0
  159. package/src/lib/state/welcome-toast.ts +76 -0
  160. package/src/lib/sw-recovery.spec.ts +165 -0
  161. package/src/lib/sw-recovery.ts +141 -0
  162. package/src/lib/types/bento.spec.ts +116 -0
  163. package/src/lib/types/bento.ts +94 -55
  164. package/src/lib/types/event-schemas.spec.ts +120 -0
  165. package/src/lib/types/event-types.spec.ts +96 -0
  166. package/src/lib/types/event-types.ts +113 -3
  167. package/src/lib/types/modules.ts +12 -5
  168. package/src/lib/types/ui-event-types.ts +66 -0
  169. package/src/lib/workers/canvas-ui-renderer.ts +266 -0
  170. package/src/lib/workers/canvas-worker.ts +94 -9
  171. package/src/lib/workers/data.ts +64 -37
  172. package/src/lib/workers/db-worker.ts +105 -32
  173. package/src/lib/workers/events.spec.ts +208 -0
  174. package/src/lib/workers/events.ts +27 -14
  175. package/src/lib/workers/flexbuilder.ts +2 -2
  176. package/src/lib/workers/init.ts +25 -17
  177. package/src/lib/workers/main.ts +506 -327
  178. package/src/lib/workers/supabase-db-worker.ts +243 -0
  179. package/src/lib/workers/supabase-shared-worker.ts +607 -0
  180. package/src/lib/workers/validate.ts +64 -0
  181. package/src/lib/workers/ws-worker.spec.ts +41 -0
  182. package/src/lib/workers/ws-worker.ts +255 -31
  183. package/src/setup-vitest.ts +4 -2
  184. package/src/types.ts +30 -0
  185. package/src/vite-env.d.ts +1 -0
  186. package/workers/main.js +2 -1125
  187. package/comlink.js +0 -253
  188. package/index.js +0 -2972
  189. package/reference.js +0 -259
  190. package/src/types.d.ts +0 -31
@@ -1,73 +1,297 @@
1
- import { wrap, expose, type Remote } from 'comlink';
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: any) => void) | null = null;
14
9
 
10
+ // ---------------------------------------------------------------------------
11
+ // Transport channels
12
+ //
13
+ // `kbve_ws_data` — raw WebSocket payloads for the db-worker to persist.
14
+ // Payload: { type: 'ws.store', format, data, ts }
15
+ //
16
+ // `kbve_ws_events` — status + message events for UI consumers (chat service,
17
+ // presence, overlays, etc.).
18
+ // Payload:
19
+ // { type: 'status', status: string }
20
+ // { type: 'message', format: 'text', data: string }
21
+ // { type: 'message', format: 'binary', data: Uint8Array }
22
+ //
23
+ // Keeping persistence and UI on separate channels means each consumer only
24
+ // sees what it cares about, and a new subscriber (e.g. cross-tab presence)
25
+ // drops in without filtering db-bound payloads.
26
+ //
27
+ // Historical note: an earlier design exposed onMessage(cb) / onStatus(cb)
28
+ // through Comlink. That failed with DataCloneError because Comlink forwards
29
+ // method args via postMessage, and functions are not structured-cloneable.
30
+ // If a future strategy wants a different transport (SharedArrayBuffer,
31
+ // MessagePort, proxied-Comlink callbacks), add it alongside — don't remove
32
+ // the BroadcastChannel path, it's the fallback that works everywhere.
33
+ // ---------------------------------------------------------------------------
34
+ const dbChannel =
35
+ typeof BroadcastChannel !== 'undefined'
36
+ ? new BroadcastChannel('kbve_ws_data')
37
+ : null;
38
+
39
+ const eventsChannel =
40
+ typeof BroadcastChannel !== 'undefined'
41
+ ? new BroadcastChannel('kbve_ws_events')
42
+ : null;
43
+
44
+ // Heartbeat
45
+ let heartbeatTimer: ReturnType<typeof setInterval> | null = null;
46
+ let lastPongTime = 0;
47
+ const HEARTBEAT_INTERVAL_MS = 30000;
48
+ const HEARTBEAT_TIMEOUT_MS = 60000;
49
+
50
+ let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
51
+ let reconnectAttempts = 0;
52
+ let lastUrl: string | null = null;
53
+ const MAX_RECONNECT_ATTEMPTS = 5;
54
+ const RECONNECT_BASE_MS = 1000;
55
+ const RECONNECT_MAX_MS = 30000;
56
+ const RECONNECT_JITTER_MS = 500;
57
+
58
+ export function reconnectDelayMs(attempt: number): number {
59
+ const exp = Math.min(
60
+ RECONNECT_MAX_MS,
61
+ RECONNECT_BASE_MS * 2 ** Math.max(0, attempt - 1),
62
+ );
63
+ const jitter = Math.floor(Math.random() * RECONNECT_JITTER_MS);
64
+ return exp + jitter;
65
+ }
66
+
67
+ function startHeartbeat() {
68
+ stopHeartbeat();
69
+ heartbeatTimer = setInterval(() => {
70
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
71
+ stopHeartbeat();
72
+ return;
73
+ }
74
+ if (
75
+ lastPongTime > 0 &&
76
+ Date.now() - lastPongTime > HEARTBEAT_TIMEOUT_MS
77
+ ) {
78
+ console.warn('[WS] Heartbeat timeout — closing connection');
79
+ stopHeartbeat();
80
+ ws.close(1001, 'Heartbeat timeout');
81
+ return;
82
+ }
83
+ try {
84
+ ws.send(JSON.stringify({ type: 'ping' }));
85
+ } catch (err) {
86
+ console.error('[WS] Failed to send heartbeat:', err);
87
+ }
88
+ }, HEARTBEAT_INTERVAL_MS);
89
+ }
90
+
91
+ function stopHeartbeat() {
92
+ if (heartbeatTimer) {
93
+ clearInterval(heartbeatTimer);
94
+ heartbeatTimer = null;
95
+ }
96
+ }
97
+
98
+ function broadcastStatus(
99
+ status: string,
100
+ detail?: { code?: number; reason?: string; wasClean?: boolean },
101
+ ) {
102
+ eventsChannel?.postMessage({ type: 'status', status, ...detail });
103
+ }
104
+
105
+ function attemptReconnect() {
106
+ if (!lastUrl || reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
107
+ if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
108
+ console.error(
109
+ `[WS] Max reconnect attempts (${MAX_RECONNECT_ATTEMPTS}) reached`,
110
+ );
111
+ broadcastStatus('failed');
112
+ }
113
+ return;
114
+ }
115
+
116
+ reconnectAttempts++;
117
+ const delay = reconnectDelayMs(reconnectAttempts);
118
+ console.log(
119
+ `[WS] Reconnecting (${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS}) in ${delay}ms...`,
120
+ );
121
+ broadcastStatus('reconnecting');
122
+
123
+ reconnectTimer = setTimeout(() => {
124
+ if (lastUrl) wsInstanceAPI.connect(lastUrl);
125
+ }, delay);
126
+ }
15
127
 
16
- // --- WebSocket API ---
128
+ // ---------------------------------------------------------------------------
129
+ // WebSocket API exposed via Comlink
130
+ //
131
+ // Only commands that carry structured-cloneable data cross this bridge
132
+ // (strings, typed arrays). Event subscription is deliberately NOT here —
133
+ // it lives on the BroadcastChannel side to avoid DataCloneError when a
134
+ // caller passes a raw function.
135
+ // ---------------------------------------------------------------------------
17
136
  const wsInstanceAPI = {
18
137
  async connect(url: string) {
19
- if (ws) return;
138
+ if (ws && ws.readyState === WebSocket.OPEN) return;
20
139
 
140
+ // Clean up any existing connection
141
+ if (ws) {
142
+ ws.onclose = null;
143
+ ws.close();
144
+ ws = null;
145
+ }
146
+
147
+ lastUrl = url;
148
+ const safeUrl = url.replace(/(token=)[^&]+/i, '$1<redacted>');
149
+ console.log('[WS] Connecting to', safeUrl);
21
150
  ws = new WebSocket(url);
22
151
  ws.binaryType = 'arraybuffer';
23
152
 
24
- ws.onopen = () => console.log('[WS] Connected:', url);
153
+ ws.onopen = () => {
154
+ console.log('[WS] Connected:', safeUrl);
155
+ reconnectAttempts = 0;
156
+ lastPongTime = Date.now();
157
+ startHeartbeat();
158
+ broadcastStatus('connected');
159
+ };
160
+
161
+ ws.onmessage = (e) => {
162
+ try {
163
+ // Handle JSON pong responses
164
+ if (typeof e.data === 'string') {
165
+ try {
166
+ const parsed = JSON.parse(e.data);
167
+ if (parsed.type === 'pong') {
168
+ lastPongTime = Date.now();
169
+ return;
170
+ }
171
+ } catch {
172
+ // Not JSON, pass through
173
+ }
174
+ }
25
175
 
26
- ws.onmessage = (e) => {
27
- try {
28
- console.log('[WS] Received binary message');
29
-
30
- if (e.data instanceof ArrayBuffer) {
31
- onMessageCallback?.(e.data);
176
+ // Fan out to db-worker (persistence pipeline).
177
+ // Structured-cloneable payloads only — strings and
178
+ // Uint8Array are both safe across BroadcastChannel.
179
+ if (dbChannel) {
180
+ if (typeof e.data === 'string') {
181
+ dbChannel.postMessage({
182
+ type: 'ws.store',
183
+ format: 'text',
184
+ data: e.data,
185
+ ts: Date.now(),
186
+ });
187
+ } else if (e.data instanceof ArrayBuffer) {
188
+ dbChannel.postMessage({
189
+ type: 'ws.store',
190
+ format: 'binary',
191
+ data: new Uint8Array(e.data),
192
+ ts: Date.now(),
193
+ });
194
+ }
32
195
  }
33
- } catch (err) {
34
- console.error('[WS] Failed to forward message', err);
35
- }
36
- };
37
-
38
-
39
- ws.onerror = (e) => console.error('[WS] Error:', e);
40
- ws.onclose = () => {
41
- console.log('[WS] Disconnected');
196
+
197
+ // Fan out to UI consumers (chat service, presence, etc.).
198
+ // Same structured-cloneable constraint applies.
199
+ if (eventsChannel) {
200
+ if (typeof e.data === 'string') {
201
+ eventsChannel.postMessage({
202
+ type: 'message',
203
+ format: 'text',
204
+ data: e.data,
205
+ });
206
+ } else if (e.data instanceof ArrayBuffer) {
207
+ eventsChannel.postMessage({
208
+ type: 'message',
209
+ format: 'binary',
210
+ data: new Uint8Array(e.data),
211
+ });
212
+ }
213
+ }
214
+ } catch (err) {
215
+ console.error('[WS] Failed to forward message', err);
216
+ }
217
+ };
218
+
219
+ ws.onerror = (e) => {
220
+ console.error('[WS] Error event:', e);
221
+ broadcastStatus('error', {
222
+ reason: 'WebSocket error event (no detail in browser API)',
223
+ });
224
+ };
225
+
226
+ ws.onclose = (event) => {
227
+ console.log(
228
+ `[WS] Disconnected code=${event.code} reason="${event.reason}" wasClean=${event.wasClean}`,
229
+ );
42
230
  ws = null;
231
+ stopHeartbeat();
232
+ broadcastStatus('disconnected', {
233
+ code: event.code,
234
+ reason: event.reason,
235
+ wasClean: event.wasClean,
236
+ });
237
+
238
+ if (event.code !== 1000) {
239
+ attemptReconnect();
240
+ }
43
241
  };
44
242
  },
45
243
 
46
244
  async send(payload: Uint8Array) {
47
245
  if (ws?.readyState === WebSocket.OPEN) {
48
- ws.send(payload);
246
+ // Cast narrows Uint8Array<ArrayBufferLike> to BufferSource for
247
+ // WebSocket.send. Newer TS DOM lib parameterizes Uint8Array over
248
+ // ArrayBuffer | SharedArrayBuffer, but send() only accepts
249
+ // ArrayBuffer-backed views. Every caller here posts a freshly
250
+ // encoded payload (Uint8Array from TextEncoder or similar), so
251
+ // the backing buffer is always a plain ArrayBuffer.
252
+ ws.send(payload as BufferSource);
49
253
  } else {
50
254
  console.warn('[WS] Tried to send while disconnected');
51
255
  }
52
256
  },
53
257
 
54
258
  async close() {
55
- ws?.close();
259
+ if (reconnectTimer) {
260
+ clearTimeout(reconnectTimer);
261
+ reconnectTimer = null;
262
+ }
263
+ stopHeartbeat();
264
+ reconnectAttempts = 0;
265
+ lastUrl = null;
266
+ ws?.close(1000, 'Client request');
56
267
  ws = null;
268
+ broadcastStatus('disconnected');
57
269
  },
58
270
 
59
- onMessage(callback: (data: any) => void) {
60
- onMessageCallback = callback;
271
+ async getStatus(): Promise<string> {
272
+ if (!ws) return 'disconnected';
273
+ const map: Record<number, string> = {
274
+ [WebSocket.CONNECTING]: 'connecting',
275
+ [WebSocket.OPEN]: 'connected',
276
+ [WebSocket.CLOSING]: 'closing',
277
+ [WebSocket.CLOSED]: 'disconnected',
278
+ };
279
+ return map[ws.readyState] || 'unknown';
61
280
  },
62
-
63
-
64
281
  };
65
282
 
66
283
  export type WSInstance = typeof wsInstanceAPI;
67
284
 
285
+ const ports = new Set<MessagePort>();
286
+
68
287
  self.onconnect = (event: MessageEvent) => {
69
288
  const port = event.ports[0];
289
+ const isFirst = ports.size === 0;
290
+ ports.add(port);
70
291
  port.start();
292
+ port.postMessage({ type: isFirst ? 'first-connect' : 'reconnect' });
293
+ port.addEventListener('message', (e: MessageEvent) => {
294
+ if (e.data?.type === 'close') ports.delete(port);
295
+ });
71
296
  expose(wsInstanceAPI, port);
72
297
  };
73
-
@@ -1,2 +1,4 @@
1
- import '@vitest/web-worker';
2
- import 'fake-indexeddb/auto';
1
+ import { defineWebWorkers } from '@vitest/web-worker/pure';
2
+ import 'fake-indexeddb/auto';
3
+
4
+ defineWebWorkers({ clone: 'native' });
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" />