@kbve/droid 0.0.1 → 0.0.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.
- package/LICENSE +1 -0
- package/README.md +5 -1
- package/assets/canvas-worker-DbsoY2Xv.js +5 -0
- package/assets/db-worker-CjXS52DQ.js +14 -0
- package/assets/ws-worker-FssAQgaD.js +5 -0
- package/droid.cjs.js +1 -1
- package/droid.es.js +1 -1
- package/index-DSyyyiLP.js +3034 -0
- package/main-BYzQVPCs.js +1455 -0
- package/package.json +8 -2
- package/src/index.ts +3 -0
- package/src/lib/droid.spec.ts +26 -0
- package/src/lib/droid.ts +5 -0
- package/src/lib/mod/mod-manager.ts +72 -0
- package/src/lib/mod/mod-urls.ts +3 -0
- package/src/lib/mod/module/bento/mod-bento.worker.ts +128 -0
- package/src/lib/mod/module/phaser/mod-phaser.ts +0 -0
- package/src/lib/mod/module/supabase/mod-supabase.spec.ts +30 -0
- package/src/lib/mod/module/supabase/mod-supabase.worker.ts +59 -0
- package/src/lib/types/bento.ts +80 -0
- package/src/lib/types/discord.ts +40 -0
- package/src/lib/types/event-types.ts +35 -0
- package/src/lib/types/jedi.ts +66 -0
- package/src/lib/types/modules.ts +46 -0
- package/src/lib/types/panel-types.ts +18 -0
- package/src/lib/types/supabase-esm.d.ts +4 -0
- package/src/lib/workers/canvas-worker.ts +107 -0
- package/src/lib/workers/data.ts +215 -0
- package/src/lib/workers/db-worker.ts +203 -0
- package/src/lib/workers/events.ts +52 -0
- package/src/lib/workers/flexbuilder.ts +6 -0
- package/src/lib/workers/init.ts +40 -0
- package/src/lib/workers/main.ts +356 -0
- package/src/lib/workers/tools.ts +60 -0
- package/src/lib/workers/ws-worker.ts +73 -0
- package/src/setup-vitest.ts +2 -0
- package/src/types.d.ts +31 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kbve/droid",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "A manager for web, shared and service workers, aimming to make it as modular and upgradable.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"workers",
|
|
@@ -27,9 +27,15 @@
|
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
|
+
"assets/",
|
|
31
|
+
"src/",
|
|
30
32
|
"droid.*.js",
|
|
33
|
+
"main-*.js",
|
|
34
|
+
"index-*.js",
|
|
31
35
|
"index.d.ts",
|
|
32
|
-
"*.md"
|
|
36
|
+
"*.md",
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"*.json"
|
|
33
39
|
],
|
|
34
40
|
"dependencies": {
|
|
35
41
|
"tslib": "^2.3.0",
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { droid } from './droid';
|
|
3
|
+
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
delete (window as any).kbve;
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
describe('droid', () => {
|
|
9
|
+
it(
|
|
10
|
+
'should initialize and attach to window.kbve',
|
|
11
|
+
async () => {
|
|
12
|
+
const result = await droid();
|
|
13
|
+
|
|
14
|
+
expect(result).toEqual({ initialized: true });
|
|
15
|
+
expect(window.kbve).toBeDefined();
|
|
16
|
+
expect(window.kbve?.api).toBeDefined();
|
|
17
|
+
expect(window.kbve?.i18n).toBeDefined();
|
|
18
|
+
expect(window.kbve?.uiux).toBeDefined();
|
|
19
|
+
expect(window.kbve?.ws).toBeDefined();
|
|
20
|
+
expect(window.kbve?.data).toBeDefined();
|
|
21
|
+
expect(window.kbve?.mod).toBeDefined();
|
|
22
|
+
|
|
23
|
+
},
|
|
24
|
+
10_000,
|
|
25
|
+
);
|
|
26
|
+
});
|
package/src/lib/droid.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { wrap, proxy } from 'comlink';
|
|
2
|
+
import type { Remote } from 'comlink';
|
|
3
|
+
import type { ModManager, ModHandle, ModMeta, BaseModAPI } from '../types/modules';
|
|
4
|
+
import type { KBVEGlobal } from '../../types';
|
|
5
|
+
|
|
6
|
+
let _modManager: ModManager | null = null;
|
|
7
|
+
|
|
8
|
+
export async function getModManager(): Promise<ModManager> {
|
|
9
|
+
if (_modManager) return _modManager;
|
|
10
|
+
|
|
11
|
+
const registry: Record<string, ModHandle> = {};
|
|
12
|
+
|
|
13
|
+
async function load(url: string): Promise<ModHandle> {
|
|
14
|
+
const worker = new Worker(url, { type: 'module' });
|
|
15
|
+
const instance = wrap<BaseModAPI>(worker);
|
|
16
|
+
|
|
17
|
+
const meta: ModMeta = await instance.getMeta?.() ?? {
|
|
18
|
+
name: 'unknown',
|
|
19
|
+
version: '0.0.1',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const id = `${meta.name}@${meta.version}`;
|
|
23
|
+
console.log(`[mod-manager] ${id} is loaded.`);
|
|
24
|
+
|
|
25
|
+
// const modEventName = `kbve:droid-${meta.name}-ready`;
|
|
26
|
+
// const event = new CustomEvent(modEventName, {
|
|
27
|
+
// detail: {
|
|
28
|
+
// meta,
|
|
29
|
+
// timestamp: Date.now(),
|
|
30
|
+
// },
|
|
31
|
+
// });
|
|
32
|
+
// window.dispatchEvent(event);
|
|
33
|
+
|
|
34
|
+
// const camelName = meta.name.replace(/[-_](\w)/g, (_, c) => c.toUpperCase());
|
|
35
|
+
// if (!window.kbve) {
|
|
36
|
+
// window.kbve = {} as KBVEGlobal;
|
|
37
|
+
// }
|
|
38
|
+
// window.kbve[`droid${camelName[0].toUpperCase()}${camelName.slice(1)}Ready`] = true;
|
|
39
|
+
|
|
40
|
+
const handle: ModHandle = { id, worker, instance, meta, url };
|
|
41
|
+
registry[id] = handle;
|
|
42
|
+
return handle;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function unload(id: string) {
|
|
46
|
+
if (registry[id]) {
|
|
47
|
+
registry[id].worker.terminate();
|
|
48
|
+
delete registry[id];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function list() {
|
|
53
|
+
return Object.values(registry).map(m => m.meta);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function reload(id: string): Promise<ModHandle> {
|
|
57
|
+
const mod = registry[id];
|
|
58
|
+
if (!mod) throw new Error(`Mod "${id}" not found`);
|
|
59
|
+
unload(id);
|
|
60
|
+
return load(mod.url);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_modManager = {
|
|
64
|
+
registry,
|
|
65
|
+
load,
|
|
66
|
+
unload,
|
|
67
|
+
list,
|
|
68
|
+
reload,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return _modManager;
|
|
72
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { expose } from 'comlink';
|
|
2
|
+
import type { BaseModAPI, VirtualNode } from '../../../types/modules';
|
|
3
|
+
import {
|
|
4
|
+
BentoTileSchema,
|
|
5
|
+
type BentoTile,
|
|
6
|
+
BENTO_BADGE_CLASS_MAP,
|
|
7
|
+
BENTO_ANIMATION_CLASS_MAP,
|
|
8
|
+
BENTO_VARIANT_CLASS_MAP,
|
|
9
|
+
} from '../../../types/bento';
|
|
10
|
+
|
|
11
|
+
let emitToMain: ((msg: any) => void) | undefined;
|
|
12
|
+
|
|
13
|
+
function createVNodeFromTile(tile: BentoTile): VirtualNode {
|
|
14
|
+
const variant = tile.variant ?? 'default';
|
|
15
|
+
const animationClass = tile.animation
|
|
16
|
+
? BENTO_ANIMATION_CLASS_MAP[tile.animation]
|
|
17
|
+
: '';
|
|
18
|
+
const variantBase = BENTO_VARIANT_CLASS_MAP[variant]?.base ?? '';
|
|
19
|
+
const variantHover = BENTO_VARIANT_CLASS_MAP[variant]?.hover ?? '';
|
|
20
|
+
|
|
21
|
+
const rootClasses = [
|
|
22
|
+
'bento-item',
|
|
23
|
+
'col-span-1',
|
|
24
|
+
'row-span-1',
|
|
25
|
+
tile.span ?? 'md:col-span-2 md:row-span-1',
|
|
26
|
+
'bg-gradient-to-br',
|
|
27
|
+
tile.primaryColor ? `from-${tile.primaryColor}` : '',
|
|
28
|
+
tile.secondaryColor ? `to-${tile.secondaryColor}` : '',
|
|
29
|
+
'rounded-2xl overflow-hidden shadow-2xl',
|
|
30
|
+
variantBase,
|
|
31
|
+
variantHover ? `hover:${variantHover}` : '',
|
|
32
|
+
animationClass,
|
|
33
|
+
tile.className ?? '',
|
|
34
|
+
]
|
|
35
|
+
.filter(Boolean)
|
|
36
|
+
.join(' ');
|
|
37
|
+
|
|
38
|
+
const datasetAttrs = tile.dataset
|
|
39
|
+
? Object.fromEntries(
|
|
40
|
+
Object.entries(tile.dataset).map(([k, v]) => [`data-${k}`, v]),
|
|
41
|
+
)
|
|
42
|
+
: {};
|
|
43
|
+
|
|
44
|
+
const wrapper: VirtualNode = {
|
|
45
|
+
tag: tile.href ? 'a' : 'div',
|
|
46
|
+
class: rootClasses,
|
|
47
|
+
attrs: {
|
|
48
|
+
...(tile.href
|
|
49
|
+
? { href: tile.href, target: tile.target ?? '_self' }
|
|
50
|
+
: {}),
|
|
51
|
+
...(tile.onclick ? { onclick: tile.onclick } : {}),
|
|
52
|
+
...(tile.ariaLabel ? { 'aria-label': tile.ariaLabel } : {}),
|
|
53
|
+
...(tile.role ? { role: tile.role } : {}),
|
|
54
|
+
...datasetAttrs,
|
|
55
|
+
},
|
|
56
|
+
children: [
|
|
57
|
+
tile.badge && {
|
|
58
|
+
tag: 'span',
|
|
59
|
+
class: `absolute top-2 right-2 px-2 py-1 text-xs rounded z-10 ${BENTO_BADGE_CLASS_MAP[tile.badgeType ?? 'default']}`,
|
|
60
|
+
children: [tile.badge],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
tag: 'div',
|
|
64
|
+
class: 'p-4 flex flex-col justify-between h-full',
|
|
65
|
+
children: [
|
|
66
|
+
{
|
|
67
|
+
tag: 'div',
|
|
68
|
+
class: 'flex items-center gap-3',
|
|
69
|
+
children: [
|
|
70
|
+
tile.icon && {
|
|
71
|
+
tag: 'div',
|
|
72
|
+
class: 'text-2xl bg-white/20 rounded-full p-2 text-white',
|
|
73
|
+
children: [tile.icon],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
tag: 'h3',
|
|
77
|
+
class: 'text-white text-lg font-bold',
|
|
78
|
+
children: [tile.title],
|
|
79
|
+
},
|
|
80
|
+
].filter(Boolean) as VirtualNode[],
|
|
81
|
+
},
|
|
82
|
+
tile.subtitle && {
|
|
83
|
+
tag: 'p',
|
|
84
|
+
class: 'text-sm text-white/80 mt-2',
|
|
85
|
+
children: [tile.subtitle],
|
|
86
|
+
},
|
|
87
|
+
tile.description && {
|
|
88
|
+
tag: 'p',
|
|
89
|
+
class: 'text-xs text-white/60 mt-1',
|
|
90
|
+
children: [tile.description],
|
|
91
|
+
},
|
|
92
|
+
].filter(Boolean) as VirtualNode[],
|
|
93
|
+
},
|
|
94
|
+
].filter(Boolean) as VirtualNode[],
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return wrapper;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const api: BaseModAPI = {
|
|
101
|
+
async getMeta() {
|
|
102
|
+
return {
|
|
103
|
+
name: 'bento',
|
|
104
|
+
version: '0.1.0',
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
async init(context) {
|
|
109
|
+
emitToMain = context?.emitFromWorker;
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
async run(data: unknown) {
|
|
113
|
+
if (!emitToMain) {
|
|
114
|
+
console.warn('[mod-bento] emitFromWorker not defined');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const tile = BentoTileSchema.parse(data);
|
|
120
|
+
const vnode = createVNodeFromTile(tile);
|
|
121
|
+
emitToMain({ type: 'injectVNode', vnode });
|
|
122
|
+
} catch (err) {
|
|
123
|
+
console.error('[mod-bento] Invalid BentoTile data:', err);
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
expose(api);
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll } from 'vitest';
|
|
2
|
+
import { droid } from '../../../droid';
|
|
3
|
+
import type { Remote } from 'comlink';
|
|
4
|
+
import type { ModHandle, SupabaseModAPI } from '../../../types/modules';
|
|
5
|
+
|
|
6
|
+
console.log('[spec] Starting mod-supabase test file...');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
let mod: Remote<SupabaseModAPI>;
|
|
10
|
+
let meta: { name: string; version: string };
|
|
11
|
+
describe('mod-supabase', () => {
|
|
12
|
+
it('should have meta info', async () => {
|
|
13
|
+
await droid();
|
|
14
|
+
if (!window.kbve?.mod) {
|
|
15
|
+
throw new Error('Mod manager not available');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log('[test] Loading Supabase mod...');
|
|
19
|
+
const modURL = new URL('./mod-supabase.worker.ts', import.meta.url);
|
|
20
|
+
console.log('Resolved worker URL:', modURL.href);
|
|
21
|
+
|
|
22
|
+
const handle = await window.kbve.mod.load(modURL.href);
|
|
23
|
+
const mod: Remote<SupabaseModAPI> = handle.instance;
|
|
24
|
+
const meta = handle.meta;
|
|
25
|
+
|
|
26
|
+
console.log('[test] Supabase mod loaded:', meta);
|
|
27
|
+
expect(meta.name).toBe('supabase');
|
|
28
|
+
expect(meta.version).toBeDefined();
|
|
29
|
+
}, 30_000);
|
|
30
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { expose } from 'comlink';
|
|
2
|
+
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
3
|
+
|
|
4
|
+
let supabase: SupabaseClient | null = null;
|
|
5
|
+
let initialized = false;
|
|
6
|
+
|
|
7
|
+
const state = {
|
|
8
|
+
ctx: null as any,
|
|
9
|
+
url: '',
|
|
10
|
+
key: '',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const mod = {
|
|
14
|
+
getMeta: () => ({
|
|
15
|
+
name: 'supabase',
|
|
16
|
+
version: '1.0.0',
|
|
17
|
+
description: 'Supabase mod for async DB access',
|
|
18
|
+
author: 'kbve',
|
|
19
|
+
}),
|
|
20
|
+
|
|
21
|
+
init(ctx: any) {
|
|
22
|
+
state.ctx = ctx;
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
async loadSupabaseClient() {
|
|
26
|
+
try {
|
|
27
|
+
const supabaseModule = await import('https://cdn.jsdelivr.net/npm/@supabase/supabase-js/+esm');
|
|
28
|
+
console.log('[mod-supabase] Supabase module loaded');
|
|
29
|
+
return supabaseModule.createClient;
|
|
30
|
+
} catch (err) {
|
|
31
|
+
console.error('[mod-supabase] Failed to load Supabase:', err);
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
async configure(url: string, key: string) {
|
|
37
|
+
if (!initialized) {
|
|
38
|
+
const createClient = await this.loadSupabaseClient();
|
|
39
|
+
supabase = createClient(url, key);
|
|
40
|
+
state.url = url;
|
|
41
|
+
state.key = key;
|
|
42
|
+
initialized = true;
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
async queryTestTable() {
|
|
47
|
+
if (!supabase) throw new Error('Supabase not configured. Call `configure()` first.');
|
|
48
|
+
const { data, error } = await supabase.from('test').select('*');
|
|
49
|
+
return { data, error };
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
async insertTest(payload: Record<string, any>) {
|
|
53
|
+
if (!supabase) throw new Error('Supabase not configured. Call `configure()` first.');
|
|
54
|
+
const { data, error } = await supabase.from('test').insert(payload).select();
|
|
55
|
+
return { data, error };
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
expose(mod);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// Enums
|
|
4
|
+
export const BENTO_VARIANTS = ['default', 'minimal', 'image-heavy'] as const;
|
|
5
|
+
export const BENTO_ANIMATIONS = ['fade-in', 'slide-up', 'none'] as const;
|
|
6
|
+
export const BENTO_TARGETS = ['_self', '_blank', '_parent', '_top'] as const;
|
|
7
|
+
export const BENTO_ROLES = ['button', 'link', 'region', 'article'] as const;
|
|
8
|
+
export const BENTO_BADGE_TYPES = ['default', 'success', 'warning', 'error'] as const;
|
|
9
|
+
|
|
10
|
+
// Regex validators
|
|
11
|
+
const tailwindColorRegex = /^[a-z]+-(100|200|300|400|500|600|700|800|900)$/;
|
|
12
|
+
const spanRegex = /^(?:(?:[a-z]+:)?(col|row)-span-\d+\s*)+$/;
|
|
13
|
+
const ulidRegex = /^01[0-9A-HJKMNP-TV-Z]{24}$/;
|
|
14
|
+
|
|
15
|
+
// Schema
|
|
16
|
+
export const BentoTileSchema = z.object({
|
|
17
|
+
id: z.string().regex(ulidRegex, 'Invalid ULID format').optional(),
|
|
18
|
+
|
|
19
|
+
title: z.string().min(1, 'Title is required'),
|
|
20
|
+
subtitle: z.string().optional(),
|
|
21
|
+
description: z.string().optional(),
|
|
22
|
+
span: z.string().regex(spanRegex, 'Invalid span format (e.g., col-span-2, row-span-1)').optional(),
|
|
23
|
+
|
|
24
|
+
primaryColor: z.string().regex(tailwindColorRegex, 'Invalid Tailwind color format (e.g., blue-500)'),
|
|
25
|
+
secondaryColor: z.string().regex(tailwindColorRegex, 'Invalid Tailwind color format (e.g., blue-500)'),
|
|
26
|
+
|
|
27
|
+
icon: z.string().optional(),
|
|
28
|
+
backgroundImage: z.string().url().optional(),
|
|
29
|
+
|
|
30
|
+
onclick: z.string().optional(),
|
|
31
|
+
href: z.string().url().optional(),
|
|
32
|
+
target: z.enum(BENTO_TARGETS).optional(),
|
|
33
|
+
|
|
34
|
+
ariaLabel: z.string().optional(),
|
|
35
|
+
role: z.enum(BENTO_ROLES).optional(),
|
|
36
|
+
|
|
37
|
+
variant: z.enum(BENTO_VARIANTS).optional(),
|
|
38
|
+
animation: z.enum(BENTO_ANIMATIONS).optional(),
|
|
39
|
+
|
|
40
|
+
badge: z.string().optional(),
|
|
41
|
+
badgeType: z.enum(BENTO_BADGE_TYPES).optional(),
|
|
42
|
+
|
|
43
|
+
priority: z.number().int().min(0).optional(),
|
|
44
|
+
tooltip: z.string().optional(),
|
|
45
|
+
disabled: z.boolean().optional(),
|
|
46
|
+
|
|
47
|
+
meta: z.record(z.any()).optional(),
|
|
48
|
+
dataset: z.record(z.string()).optional(),
|
|
49
|
+
className: z.string().optional(),
|
|
50
|
+
}).refine(
|
|
51
|
+
(data) => !data.href || (data.href && data.target),
|
|
52
|
+
{ message: 'target is required when href is provided', path: ['target'] }
|
|
53
|
+
).refine(
|
|
54
|
+
(data) => !data.badgeType || (data.badge && data.badge.length > 0),
|
|
55
|
+
{ message: 'badge must be provided if badgeType is set', path: ['badge'] }
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// Types
|
|
59
|
+
export type BentoTile = z.infer<typeof BentoTileSchema>;
|
|
60
|
+
export type BentoVariantClass = { base: string; hover?: string };
|
|
61
|
+
|
|
62
|
+
// Mappings
|
|
63
|
+
export const BENTO_VARIANT_CLASS_MAP: Record<(typeof BENTO_VARIANTS)[number], BentoVariantClass> = {
|
|
64
|
+
default: { base: 'p-4 flex flex-col justify-between' },
|
|
65
|
+
minimal: { base: 'p-2 bg-opacity-30 backdrop-blur-sm', hover: 'bg-opacity-50' },
|
|
66
|
+
'image-heavy': { base: 'p-0 overflow-hidden', hover: 'scale-105' },
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const BENTO_ANIMATION_CLASS_MAP: Record<(typeof BENTO_ANIMATIONS)[number], string> = {
|
|
70
|
+
'fade-in': 'animate-fade-in',
|
|
71
|
+
'slide-up': 'animate-slide-up',
|
|
72
|
+
none: '',
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const BENTO_BADGE_CLASS_MAP: Record<(typeof BENTO_BADGE_TYPES)[number], string> = {
|
|
76
|
+
default: 'bg-white/30 text-white',
|
|
77
|
+
success: 'bg-green-500/80 text-white',
|
|
78
|
+
warning: 'bg-yellow-500/80 text-black',
|
|
79
|
+
error: 'bg-red-500/80 text-white',
|
|
80
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const DiscordServerSchema = z.object({
|
|
4
|
+
server_id: z.string(),
|
|
5
|
+
owner_id: z.string(),
|
|
6
|
+
lang: z.number(),
|
|
7
|
+
status: z.number(),
|
|
8
|
+
invite: z.string(),
|
|
9
|
+
name: z.string(),
|
|
10
|
+
summary: z.string(),
|
|
11
|
+
description: z.string().nullable().optional(),
|
|
12
|
+
website: z.string().nullable().optional(),
|
|
13
|
+
logo: z.string().nullable().optional(),
|
|
14
|
+
banner: z.string().nullable().optional(),
|
|
15
|
+
video: z.string().nullable().optional(),
|
|
16
|
+
categories: z.number(),
|
|
17
|
+
updated_at: z.string(),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export type DiscordServer = z.infer<typeof DiscordServerSchema>;
|
|
21
|
+
|
|
22
|
+
export const DiscordTagSchema = z.object({
|
|
23
|
+
tag_id: z.string(),
|
|
24
|
+
name: z.string(),
|
|
25
|
+
status: z.number(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export type DiscordTag = z.infer<typeof DiscordTagSchema>;
|
|
29
|
+
|
|
30
|
+
export const ProfileSchema = z.object({
|
|
31
|
+
profile_id: z.string(),
|
|
32
|
+
user_id: z.string(),
|
|
33
|
+
username: z.string(),
|
|
34
|
+
avatar: z.string().url().optional(),
|
|
35
|
+
bio: z.string().optional(),
|
|
36
|
+
joined_at: z.string(),
|
|
37
|
+
status: z.number(),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export type Profile = z.infer<typeof ProfileSchema>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { PanelIdSchema } from './panel-types';
|
|
3
|
+
|
|
4
|
+
export const ModMetaSchema = z.object({
|
|
5
|
+
name: z.string(),
|
|
6
|
+
version: z.string().optional(),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const DroidModReadySchema = z.object({
|
|
10
|
+
meta: ModMetaSchema.optional(),
|
|
11
|
+
timestamp: z.number(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const PanelEventSchema = z.object({
|
|
15
|
+
id: PanelIdSchema,
|
|
16
|
+
payload: z.any().optional(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const DroidReadySchema = z.object({
|
|
20
|
+
timestamp: z.number(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const DroidEventSchemas = {
|
|
24
|
+
'droid-ready': DroidReadySchema,
|
|
25
|
+
'droid-mod-ready': DroidModReadySchema,
|
|
26
|
+
'panel-open': PanelEventSchema,
|
|
27
|
+
'panel-close': PanelEventSchema,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type DroidEventMap = {
|
|
31
|
+
[K in keyof typeof DroidEventSchemas]: z.infer<(typeof DroidEventSchemas)[K]>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type EventKey = keyof DroidEventMap;
|
|
35
|
+
export type EventHandler<K extends EventKey> = (payload: DroidEventMap[K]) => void;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
|
|
2
|
+
export type FieldMap = Record<string, string>;
|
|
3
|
+
export type StreamRequest = { stream: string; id: string };
|
|
4
|
+
|
|
5
|
+
export enum PayloadFormat {
|
|
6
|
+
PAYLOAD_UNKNOWN = 0,
|
|
7
|
+
JSON = 1,
|
|
8
|
+
FLEX = 2,
|
|
9
|
+
PROTOBUF = 3,
|
|
10
|
+
FLATBUFFER = 4,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface JediEnvelopeFlex {
|
|
14
|
+
version: number;
|
|
15
|
+
kind: number;
|
|
16
|
+
format: number;
|
|
17
|
+
payload: Uint8Array;
|
|
18
|
+
metadata?: Uint8Array;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export enum MessageKind {
|
|
22
|
+
// Verbs (Bits 0–7)
|
|
23
|
+
UNKNOWN = 0,
|
|
24
|
+
ADD = 1 << 0,
|
|
25
|
+
READ = 1 << 1,
|
|
26
|
+
GET = 1 << 2,
|
|
27
|
+
SET = 1 << 3,
|
|
28
|
+
DEL = 1 << 4,
|
|
29
|
+
STREAM = 1 << 5,
|
|
30
|
+
GROUP = 1 << 6,
|
|
31
|
+
LIST = 1 << 7,
|
|
32
|
+
|
|
33
|
+
// Intent (Bits 8–15)
|
|
34
|
+
ACTION = 1 << 8,
|
|
35
|
+
MESSAGE = 1 << 9,
|
|
36
|
+
INFO = 1 << 10,
|
|
37
|
+
DEBUG = 1 << 11,
|
|
38
|
+
ERROR = 1 << 12,
|
|
39
|
+
AUTH = 1 << 13,
|
|
40
|
+
HEARTBEAT = 1 << 14,
|
|
41
|
+
|
|
42
|
+
// Targets (Bits 16–23)
|
|
43
|
+
CONFIG_UPDATE = 1 << 15,
|
|
44
|
+
REDIS = 1 << 16,
|
|
45
|
+
SUPABASE = 1 << 17,
|
|
46
|
+
FILESYSTEM = 1 << 18,
|
|
47
|
+
WEBSOCKET = 1 << 19,
|
|
48
|
+
HTTP_API = 1 << 20,
|
|
49
|
+
LOCAL_CACHE = 1 << 21,
|
|
50
|
+
AI = 1 << 22,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const MultiMessageKind = {
|
|
54
|
+
RGET: MessageKind.REDIS | MessageKind.GET,
|
|
55
|
+
RSET: MessageKind.REDIS | MessageKind.SET,
|
|
56
|
+
RDEL: MessageKind.REDIS | MessageKind.DEL,
|
|
57
|
+
XADD: MessageKind.REDIS | MessageKind.STREAM | MessageKind.ADD,
|
|
58
|
+
XREAD: MessageKind.REDIS | MessageKind.STREAM | MessageKind.READ,
|
|
59
|
+
WATCH: MessageKind.REDIS | MessageKind.HEARTBEAT | MessageKind.READ | MessageKind.INFO,
|
|
60
|
+
UNWATCH: MessageKind.REDIS | MessageKind.HEARTBEAT | MessageKind.DEL | MessageKind.INFO,
|
|
61
|
+
PUBLISH: MessageKind.REDIS | MessageKind.MESSAGE | MessageKind.ACTION,
|
|
62
|
+
SUBSCRIBE: MessageKind.REDIS | MessageKind.MESSAGE | MessageKind.READ,
|
|
63
|
+
} as const;
|
|
64
|
+
|
|
65
|
+
export type MultiMessageKindKey = keyof typeof MultiMessageKind;
|
|
66
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Remote } from 'comlink';
|
|
2
|
+
|
|
3
|
+
export interface BaseModAPI {
|
|
4
|
+
getMeta(): Promise<ModMeta>;
|
|
5
|
+
init?(ctx: any): void | Promise<void>;
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ModMeta {
|
|
10
|
+
name: string;
|
|
11
|
+
version: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
author?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ModHandle {
|
|
17
|
+
id: string;
|
|
18
|
+
worker: Worker;
|
|
19
|
+
instance: Remote<BaseModAPI>;
|
|
20
|
+
meta: ModMeta;
|
|
21
|
+
url: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ModManager {
|
|
25
|
+
registry: Record<string, ModHandle>;
|
|
26
|
+
load: (url: string) => Promise<ModHandle>;
|
|
27
|
+
unload: (id: string) => void;
|
|
28
|
+
list: () => ModMeta[];
|
|
29
|
+
reload: (id: string) => Promise<ModHandle>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface SupabaseModAPI extends BaseModAPI {
|
|
33
|
+
configure(url: string, key: string): Promise<void>;
|
|
34
|
+
queryTestTable(): Promise<{ data: any; error: any }>;
|
|
35
|
+
insertTest(payload: Record<string, any>): Promise<{ data: any; error: any }>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type VirtualNode = {
|
|
39
|
+
tag: string;
|
|
40
|
+
id?: string;
|
|
41
|
+
key?: string;
|
|
42
|
+
class?: string;
|
|
43
|
+
attrs?: Record<string, any>;
|
|
44
|
+
style?: Partial<CSSStyleDeclaration>;
|
|
45
|
+
children?: (string | VirtualNode)[];
|
|
46
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const PanelIdSchema = z.enum(['top', 'right', 'bottom', 'left']);
|
|
4
|
+
export type PanelId = z.infer<typeof PanelIdSchema>;
|
|
5
|
+
|
|
6
|
+
export const CanvasOptionsSchema = z.object({
|
|
7
|
+
width: z.number(),
|
|
8
|
+
height: z.number(),
|
|
9
|
+
mode: z.enum(['static', 'animated', 'dynamic']).optional(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const PanelPayloadSchema = z.object({
|
|
13
|
+
rawHtml: z.string().optional(),
|
|
14
|
+
needsCanvas: z.boolean().optional(),
|
|
15
|
+
canvasOptions: CanvasOptionsSchema.optional(),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export type PanelPayload = z.infer<typeof PanelPayloadSchema>;
|