@kbve/droid 0.0.2 → 0.0.4
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/README.md +17 -7
- package/comlink.js +253 -0
- package/package.json +8 -4
- package/src/index.ts +18 -0
- package/src/lib/droid.ts +5 -3
- package/src/lib/mod/mod-manager.ts +3 -2
- package/src/lib/workers/main.ts +256 -81
- package/workers/main.js +1091 -0
- package/assets/canvas-worker-DbsoY2Xv.js +0 -5
- package/assets/db-worker-CjXS52DQ.js +0 -14
- package/assets/ws-worker-FssAQgaD.js +0 -5
- package/droid.cjs.js +0 -1
- package/droid.es.js +0 -14
- package/index-DSyyyiLP.js +0 -3034
- package/main-BYzQVPCs.js +0 -1455
package/src/lib/workers/main.ts
CHANGED
|
@@ -9,12 +9,25 @@ import { getModManager } from '../mod/mod-manager';
|
|
|
9
9
|
import { scopeData } from './data';
|
|
10
10
|
import { dispatchAsync, renderVNode } from './tools';
|
|
11
11
|
import type { PanelPayload, PanelId } from '../types/panel-types';
|
|
12
|
-
import { DroidEvents } from './events';
|
|
12
|
+
import { DroidEvents } from './events';
|
|
13
13
|
|
|
14
14
|
const EXPECTED_DB_VERSION = '1.0.3';
|
|
15
|
+
let initialized = false;
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
export function resolveWorkerURL(name: string, fallback?: string): string {
|
|
18
|
+
if (!name)
|
|
19
|
+
throw new Error('[resolveWorkerURL] Worker name must be defined');
|
|
20
|
+
|
|
21
|
+
if (typeof window !== 'undefined') {
|
|
22
|
+
const globalMap = (window as any).kbveWorkerURLs;
|
|
23
|
+
if (globalMap?.[name]) return globalMap[name];
|
|
24
|
+
}
|
|
17
25
|
|
|
26
|
+
// No bundler-specific resolution: just return fallback or root-relative
|
|
27
|
+
return fallback ?? `/workers/${name}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// * DeepProxy
|
|
18
31
|
function deepProxy<T>(obj: T): T {
|
|
19
32
|
if (typeof obj === 'function') return proxy(obj) as T;
|
|
20
33
|
|
|
@@ -29,21 +42,69 @@ function deepProxy<T>(obj: T): T {
|
|
|
29
42
|
return obj;
|
|
30
43
|
}
|
|
31
44
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
async function initWsComlink(opts?: {
|
|
46
|
+
workerRef?: SharedWorker;
|
|
47
|
+
workerURL?: string;
|
|
48
|
+
}): Promise<Remote<WSInstance>> {
|
|
49
|
+
let api: Remote<WSInstance> | null = null;
|
|
50
|
+
|
|
51
|
+
// 1. Try Vite-style import
|
|
52
|
+
try {
|
|
53
|
+
const worker = new SharedWorker(new URL('./ws-worker.ts', import.meta.url), {
|
|
54
|
+
type: 'module',
|
|
55
|
+
});
|
|
56
|
+
worker.port.start();
|
|
57
|
+
api = wrap<WSInstance>(worker.port);
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.warn('[DROID] ws-worker import.meta fallback failed:', err);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 2. Try hardcoded path
|
|
63
|
+
if (!api) {
|
|
64
|
+
try {
|
|
65
|
+
const worker = new SharedWorker('/ws-worker.js', { type: 'module' });
|
|
66
|
+
worker.port.start();
|
|
67
|
+
api = wrap<WSInstance>(worker.port);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.warn('[DROID] ws-worker hardcoded fallback failed:', err);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 3. Try provided SharedWorker reference
|
|
74
|
+
if (!api && opts?.workerRef) {
|
|
75
|
+
try {
|
|
76
|
+
opts.workerRef.port.start();
|
|
77
|
+
api = wrap<WSInstance>(opts.workerRef.port);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
console.warn('[DROID] ws-worker workerRef failed:', err);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 4. Try provided URL
|
|
84
|
+
if (!api && opts?.workerURL) {
|
|
85
|
+
try {
|
|
86
|
+
const worker = new SharedWorker(opts.workerURL, { type: 'module' });
|
|
87
|
+
worker.port.start();
|
|
88
|
+
api = wrap<WSInstance>(worker.port);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.warn('[DROID] ws-worker workerURL failed:', err);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 5. Final failure
|
|
95
|
+
if (!api) {
|
|
96
|
+
console.error('[DROID] No WS Worker Comlink Initialized');
|
|
97
|
+
throw new Error('[DROID] Failed to initialize ws-worker');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return api;
|
|
39
101
|
}
|
|
40
102
|
|
|
41
|
-
// * Interface -> Moved to the panels.ts
|
|
42
103
|
|
|
43
104
|
// * UIUX
|
|
44
|
-
|
|
45
105
|
const uiuxState = persistentMap<{
|
|
46
|
-
panelManager: Record<
|
|
106
|
+
panelManager: Record<
|
|
107
|
+
PanelId,
|
|
47
108
|
{
|
|
48
109
|
open: boolean;
|
|
49
110
|
payload?: PanelPayload;
|
|
@@ -71,13 +132,55 @@ const uiuxState = persistentMap<{
|
|
|
71
132
|
},
|
|
72
133
|
);
|
|
73
134
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
135
|
+
async function initCanvasComlink(opts?: {
|
|
136
|
+
workerRef?: Worker;
|
|
137
|
+
workerURL?: string;
|
|
138
|
+
}): Promise<Remote<CanvasWorkerAPI>> {
|
|
139
|
+
// 1. Try Vite-style import resolution
|
|
140
|
+
try {
|
|
141
|
+
const worker = new Worker(
|
|
142
|
+
new URL('./canvas-worker.ts', import.meta.url),
|
|
143
|
+
{ type: 'module' },
|
|
144
|
+
);
|
|
145
|
+
return wrap<CanvasWorkerAPI>(worker);
|
|
146
|
+
} catch (err) {
|
|
147
|
+
console.warn('[DROID] Vite-style canvas-worker import failed:', err);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 2. Try hardcoded path fallback
|
|
151
|
+
try {
|
|
152
|
+
const worker = new Worker('./canvas-worker.js', { type: 'module' });
|
|
153
|
+
return wrap<CanvasWorkerAPI>(worker);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
console.warn('[DROID] Fallback /canvas-worker.js failed:', err);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 3. Try direct Worker instance
|
|
159
|
+
if (opts?.workerRef) {
|
|
160
|
+
try {
|
|
161
|
+
return wrap<CanvasWorkerAPI>(opts.workerRef);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
console.warn('[DROID] Provided workerRef failed:', err);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 4. Try provided URL
|
|
168
|
+
if (opts?.workerURL) {
|
|
169
|
+
try {
|
|
170
|
+
const worker = new Worker(opts.workerURL, { type: 'module' });
|
|
171
|
+
return wrap<CanvasWorkerAPI>(worker);
|
|
172
|
+
} catch (err) {
|
|
173
|
+
console.warn('[DROID] Provided workerURL failed:', err);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 5. Failure
|
|
178
|
+
console.error('[DROID] No Canvas Comlink Initialized');
|
|
179
|
+
throw new Error('[DROID] Failed to initialize canvas worker');
|
|
180
|
+
}
|
|
77
181
|
|
|
78
182
|
export const uiux = {
|
|
79
183
|
state: uiuxState,
|
|
80
|
-
worker: canvasWorker,
|
|
81
184
|
openPanel(id: PanelId, payload?: PanelPayload) {
|
|
82
185
|
const panels = { ...uiuxState.get().panelManager };
|
|
83
186
|
panels[id] = { open: true, payload };
|
|
@@ -90,10 +193,7 @@ export const uiux = {
|
|
|
90
193
|
uiuxState.setKey('panelManager', panels);
|
|
91
194
|
},
|
|
92
195
|
|
|
93
|
-
togglePanel(
|
|
94
|
-
id: PanelId,
|
|
95
|
-
payload?: PanelPayload,
|
|
96
|
-
) {
|
|
196
|
+
togglePanel(id: PanelId, payload?: PanelPayload) {
|
|
97
197
|
const panels = { ...uiuxState.get().panelManager };
|
|
98
198
|
const isOpen = panels[id]?.open ?? false;
|
|
99
199
|
panels[id] = { open: !isOpen, payload: !isOpen ? payload : undefined };
|
|
@@ -114,23 +214,20 @@ export const uiux = {
|
|
|
114
214
|
delete toasts[id];
|
|
115
215
|
uiuxState.setKey('toastManager', toasts);
|
|
116
216
|
},
|
|
117
|
-
|
|
118
217
|
async dispatchCanvasRequest(
|
|
119
218
|
panelId: PanelId,
|
|
120
219
|
canvasEl: HTMLCanvasElement,
|
|
121
220
|
mode: 'static' | 'animated' | 'dynamic' = 'animated',
|
|
122
221
|
) {
|
|
123
222
|
const offscreen = canvasEl.transferControlToOffscreen();
|
|
124
|
-
await
|
|
223
|
+
await window.kbve?.uiux?.worker?.bindCanvas(panelId, offscreen, mode);
|
|
125
224
|
},
|
|
126
225
|
|
|
127
226
|
closeAllPanels() {
|
|
128
227
|
const panels = { ...uiuxState.get().panelManager };
|
|
129
228
|
console.log('error panel is closing');
|
|
130
229
|
|
|
131
|
-
for (const id of Object.keys(panels) as Array<
|
|
132
|
-
PanelId
|
|
133
|
-
>) {
|
|
230
|
+
for (const id of Object.keys(panels) as Array<PanelId>) {
|
|
134
231
|
panels[id] = { open: false, payload: undefined };
|
|
135
232
|
}
|
|
136
233
|
|
|
@@ -235,12 +332,64 @@ function initSWComlink() {
|
|
|
235
332
|
channel.port1.start();
|
|
236
333
|
}
|
|
237
334
|
|
|
238
|
-
async function initStorageComlink(
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
335
|
+
async function initStorageComlink(opts?: {
|
|
336
|
+
workerRef?: SharedWorker;
|
|
337
|
+
workerURL?: string;
|
|
338
|
+
}): Promise<Remote<LocalStorageAPI>> {
|
|
339
|
+
let api: Remote<LocalStorageAPI> | null = null;
|
|
340
|
+
// 1. Try Vite-style import
|
|
341
|
+
try {
|
|
342
|
+
const worker = new SharedWorker(
|
|
343
|
+
new URL('./db-worker.ts', import.meta.url),
|
|
344
|
+
{
|
|
345
|
+
type: 'module',
|
|
346
|
+
},
|
|
347
|
+
);
|
|
348
|
+
worker.port.start();
|
|
349
|
+
api = wrap<LocalStorageAPI>(worker.port);
|
|
350
|
+
} catch (err) {
|
|
351
|
+
console.warn('[DROID] db-worker import.meta fallback failed:', err);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// 2. Try hardcoded path
|
|
355
|
+
if (!api) {
|
|
356
|
+
try {
|
|
357
|
+
const worker = new SharedWorker('/db-worker.js', {
|
|
358
|
+
type: 'module',
|
|
359
|
+
});
|
|
360
|
+
worker.port.start();
|
|
361
|
+
api = wrap<LocalStorageAPI>(worker.port);
|
|
362
|
+
} catch (err) {
|
|
363
|
+
console.warn('[DROID] db-worker hardcoded fallback failed:', err);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// 3. Try provided SharedWorker reference
|
|
368
|
+
if (!api && opts?.workerRef) {
|
|
369
|
+
try {
|
|
370
|
+
opts.workerRef.port.start();
|
|
371
|
+
api = wrap<LocalStorageAPI>(opts.workerRef.port);
|
|
372
|
+
} catch (err) {
|
|
373
|
+
console.warn('[DROID] db-worker workerRef failed:', err);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// 4. Try provided URL
|
|
378
|
+
if (!api && opts?.workerURL) {
|
|
379
|
+
try {
|
|
380
|
+
const worker = new SharedWorker(opts.workerURL, { type: 'module' });
|
|
381
|
+
worker.port.start();
|
|
382
|
+
api = wrap<LocalStorageAPI>(worker.port);
|
|
383
|
+
} catch (err) {
|
|
384
|
+
console.warn('[DROID] db-worker workerURL failed:', err);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// 5. Final failure
|
|
389
|
+
if (!api) {
|
|
390
|
+
console.error('[DROID] No DB Worker Comlink Initialized');
|
|
391
|
+
throw new Error('[DROID] Failed to initialize db-worker');
|
|
392
|
+
}
|
|
244
393
|
|
|
245
394
|
const version = await api.getVersion();
|
|
246
395
|
if (version !== EXPECTED_DB_VERSION) {
|
|
@@ -255,8 +404,6 @@ async function initStorageComlink(): Promise<Remote<LocalStorageAPI>> {
|
|
|
255
404
|
return api;
|
|
256
405
|
}
|
|
257
406
|
|
|
258
|
-
let initialized = false;
|
|
259
|
-
|
|
260
407
|
// * Bridge
|
|
261
408
|
export function bridgeWsToDb(
|
|
262
409
|
ws: Remote<WSInstance>,
|
|
@@ -273,7 +420,16 @@ export function bridgeWsToDb(
|
|
|
273
420
|
}
|
|
274
421
|
|
|
275
422
|
// * MAIN
|
|
276
|
-
export async function main(
|
|
423
|
+
export async function main(opts?: {
|
|
424
|
+
workerURLs?: Record<string, string>;
|
|
425
|
+
workerRefs?: {
|
|
426
|
+
canvasWorker?: Worker;
|
|
427
|
+
dbWorker?: SharedWorker;
|
|
428
|
+
wsWorker?: SharedWorker;
|
|
429
|
+
};
|
|
430
|
+
}) {
|
|
431
|
+
console.log('[DROID]: Main<T>');
|
|
432
|
+
|
|
277
433
|
if (!initialized) {
|
|
278
434
|
initialized = true;
|
|
279
435
|
|
|
@@ -288,68 +444,87 @@ export async function main() {
|
|
|
288
444
|
}
|
|
289
445
|
}
|
|
290
446
|
|
|
447
|
+
console.log('[DROID] Main<T> => Worker URLs', opts?.workerURLs);
|
|
448
|
+
|
|
291
449
|
const needsInit =
|
|
292
450
|
!window.kbve?.api || !window.kbve?.i18n || !window.kbve?.uiux;
|
|
293
451
|
|
|
294
452
|
if (needsInit) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
for (const handle of Object.values(mod.registry)) {
|
|
301
|
-
if (typeof handle.instance.init === 'function') {
|
|
302
|
-
await handle.instance.init({
|
|
303
|
-
emitFromWorker: uiux.emitFromWorker,
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
console.log('[Event] -> Fire Mod Ready');
|
|
307
|
-
events.emit('droid-mod-ready', {
|
|
308
|
-
meta: handle.meta,
|
|
309
|
-
timestamp: Date.now(),
|
|
453
|
+
try {
|
|
454
|
+
console.log('[DROID] Main<T> => Worker => CanvasComlink');
|
|
455
|
+
const canvas = await initCanvasComlink({
|
|
456
|
+
workerRef: opts?.workerRefs?.canvasWorker,
|
|
457
|
+
workerURL: opts?.workerURLs?.['canvasWorker'],
|
|
310
458
|
});
|
|
311
|
-
|
|
459
|
+
console.log('[DROID] Main<T> => Worker => StorageComlink');
|
|
460
|
+
const api = await initStorageComlink({
|
|
461
|
+
workerURL: typeof opts?.workerURLs?.['dbWorker'] === 'string'
|
|
462
|
+
? opts.workerURLs['dbWorker']
|
|
463
|
+
: undefined,
|
|
464
|
+
workerRef: opts?.workerRefs?.dbWorker,
|
|
465
|
+
});
|
|
466
|
+
console.log('[DROID] Main<T> => Worker => WsComlink');
|
|
467
|
+
const ws = await initWsComlink({
|
|
468
|
+
workerRef: opts?.workerRefs?.wsWorker,
|
|
469
|
+
workerURL: opts?.workerURLs?.['wsWorker'],
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
console.log('[DROID] Main<T> => Worker => ModManager');
|
|
473
|
+
const mod = await getModManager(
|
|
474
|
+
(url) => opts?.workerURLs?.[url] ?? url,
|
|
475
|
+
);
|
|
476
|
+
const events = DroidEvents;
|
|
312
477
|
|
|
313
|
-
|
|
478
|
+
for (const handle of Object.values(mod.registry)) {
|
|
479
|
+
if (typeof handle.instance.init === 'function') {
|
|
480
|
+
await handle.instance.init({
|
|
481
|
+
emitFromWorker: uiux.emitFromWorker,
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
console.log('[Event] -> Fire Mod Ready');
|
|
485
|
+
events.emit('droid-mod-ready', {
|
|
486
|
+
meta: handle.meta,
|
|
487
|
+
timestamp: Date.now(),
|
|
488
|
+
});
|
|
489
|
+
}
|
|
314
490
|
|
|
315
|
-
|
|
316
|
-
i18n.api = api;
|
|
317
|
-
i18n.ready = i18n.hydrateLocale('en');
|
|
491
|
+
bridgeWsToDb(ws, api);
|
|
318
492
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
i18n,
|
|
323
|
-
uiux,
|
|
324
|
-
ws,
|
|
325
|
-
data,
|
|
326
|
-
mod,
|
|
327
|
-
events,
|
|
328
|
-
};
|
|
493
|
+
const data = scopeData;
|
|
494
|
+
i18n.api = api;
|
|
495
|
+
i18n.ready = i18n.hydrateLocale('en');
|
|
329
496
|
|
|
330
|
-
|
|
497
|
+
window.kbve = {
|
|
498
|
+
...(window.kbve || {}),
|
|
499
|
+
api,
|
|
500
|
+
i18n,
|
|
501
|
+
uiux: { ...uiux, worker: canvas },
|
|
502
|
+
ws,
|
|
503
|
+
data,
|
|
504
|
+
mod,
|
|
505
|
+
events,
|
|
506
|
+
};
|
|
331
507
|
|
|
332
|
-
|
|
508
|
+
await i18n.ready;
|
|
333
509
|
|
|
334
|
-
|
|
335
|
-
timestamp: Date.now(),
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
document.addEventListener('astro:page-load', () => {
|
|
339
|
-
console.debug('[KBVE] Re-dispatched droid-ready after astro:page-load');
|
|
340
|
-
window.kbve?.events.emit('droid-ready', {
|
|
510
|
+
window.kbve.events.emit('droid-ready', {
|
|
341
511
|
timestamp: Date.now(),
|
|
342
512
|
});
|
|
343
|
-
});
|
|
344
513
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
514
|
+
document.addEventListener('astro:page-load', () => {
|
|
515
|
+
console.debug(
|
|
516
|
+
'[KBVE] Re-dispatched droid-ready after astro:page-load',
|
|
517
|
+
);
|
|
518
|
+
window.kbve?.events.emit('droid-ready', {
|
|
519
|
+
timestamp: Date.now(),
|
|
520
|
+
});
|
|
521
|
+
});
|
|
351
522
|
|
|
352
|
-
|
|
523
|
+
console.log('[KBVE] Global API ready');
|
|
524
|
+
} catch (err) {
|
|
525
|
+
console.error('[DROID] Initialization error:', err);
|
|
526
|
+
throw err;
|
|
527
|
+
}
|
|
353
528
|
} else {
|
|
354
529
|
console.log('[KBVE] Already initialized');
|
|
355
530
|
}
|