@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.
Files changed (108) hide show
  1. package/comlink.js +1 -7
  2. package/droid.mjs +191 -61
  3. package/index.d.ts +29 -0
  4. package/index.js +9054 -2763
  5. package/lib/gateway/SupabaseGateway.d.ts +38 -0
  6. package/lib/gateway/SupabaseGateway.d.ts.map +1 -0
  7. package/lib/gateway/WorkerCommunication.d.ts +39 -0
  8. package/lib/gateway/WorkerCommunication.d.ts.map +1 -0
  9. package/lib/gateway/WorkerPool.d.ts +55 -0
  10. package/lib/gateway/WorkerPool.d.ts.map +1 -0
  11. package/lib/gateway/capabilities.d.ts +23 -0
  12. package/lib/gateway/capabilities.d.ts.map +1 -0
  13. package/lib/gateway/index.d.ts +9 -0
  14. package/lib/gateway/index.d.ts.map +1 -0
  15. package/lib/gateway/strategies/DirectStrategy.d.ts +52 -0
  16. package/lib/gateway/strategies/DirectStrategy.d.ts.map +1 -0
  17. package/lib/gateway/strategies/SharedWorkerStrategy.d.ts +46 -0
  18. package/lib/gateway/strategies/SharedWorkerStrategy.d.ts.map +1 -0
  19. package/lib/gateway/strategies/WebWorkerStrategy.d.ts +45 -0
  20. package/lib/gateway/strategies/WebWorkerStrategy.d.ts.map +1 -0
  21. package/lib/gateway/types.d.ts +81 -0
  22. package/lib/gateway/types.d.ts.map +1 -0
  23. package/lib/workers/canvas-ui-renderer.d.ts +25 -0
  24. package/lib/workers/canvas-ui-renderer.d.ts.map +1 -0
  25. package/lib/workers/canvas-worker.d.ts +14 -0
  26. package/lib/workers/canvas-worker.d.ts.map +1 -0
  27. package/lib/workers/canvas-worker.js +291 -145
  28. package/lib/workers/data.d.ts +40 -0
  29. package/lib/workers/data.d.ts.map +1 -0
  30. package/lib/workers/db-worker.d.ts +69 -0
  31. package/lib/workers/db-worker.d.ts.map +1 -0
  32. package/lib/workers/db-worker.js +2680 -2147
  33. package/lib/workers/events.d.ts +11 -0
  34. package/lib/workers/events.d.ts.map +1 -0
  35. package/lib/workers/flexbuilder.d.ts +4 -0
  36. package/lib/workers/flexbuilder.d.ts.map +1 -0
  37. package/lib/workers/init.d.ts +11 -0
  38. package/lib/workers/init.d.ts.map +1 -0
  39. package/lib/workers/main.d.ts +107 -0
  40. package/lib/workers/main.d.ts.map +1 -0
  41. package/lib/workers/supabase-db-worker.d.ts +2 -0
  42. package/lib/workers/supabase-db-worker.d.ts.map +1 -0
  43. package/lib/workers/supabase-db-worker.js +9337 -0
  44. package/lib/workers/supabase-shared-worker.d.ts +2 -0
  45. package/lib/workers/supabase-shared-worker.d.ts.map +1 -0
  46. package/lib/workers/supabase-shared-worker.js +12635 -0
  47. package/lib/workers/tools.d.ts +4 -0
  48. package/lib/workers/tools.d.ts.map +1 -0
  49. package/lib/workers/validate.d.ts +15 -0
  50. package/lib/workers/validate.d.ts.map +1 -0
  51. package/lib/workers/ws-worker.d.ts +11 -0
  52. package/lib/workers/ws-worker.d.ts.map +1 -0
  53. package/lib/workers/ws-worker.js +174 -115
  54. package/main.js +4875 -0
  55. package/package.json +17 -6
  56. package/reference.js +688 -228
  57. package/src/index.ts +38 -13
  58. package/src/lib/droid.spec.ts +14 -19
  59. package/src/lib/droid.ts +48 -4
  60. package/src/lib/gateway/SupabaseGateway.ts +183 -0
  61. package/src/lib/gateway/WorkerCommunication.ts +132 -0
  62. package/src/lib/gateway/WorkerPool.ts +304 -0
  63. package/src/lib/gateway/capabilities.ts +80 -0
  64. package/src/lib/gateway/index.ts +15 -0
  65. package/src/lib/gateway/strategies/DirectStrategy.ts +443 -0
  66. package/src/lib/gateway/strategies/SharedWorkerStrategy.ts +278 -0
  67. package/src/lib/gateway/strategies/WebWorkerStrategy.ts +278 -0
  68. package/src/lib/gateway/types.ts +112 -0
  69. package/src/lib/mod/mod-manager.ts +13 -8
  70. package/src/lib/mod/module/bento/mod-bento.worker.ts +1 -1
  71. package/src/lib/mod/module/supabase/mod-supabase.spec.ts +21 -25
  72. package/src/lib/mod/module/supabase/mod-supabase.ts +68 -0
  73. package/src/lib/mod/module/supabase/mod-supabase.worker.ts +1 -56
  74. package/src/lib/state/auth.spec.ts +58 -0
  75. package/src/lib/state/auth.ts +30 -0
  76. package/src/lib/state/index.ts +34 -0
  77. package/src/lib/state/overlay-manager.ts +125 -0
  78. package/src/lib/state/router.ts +24 -0
  79. package/src/lib/state/theme-sync.ts +75 -0
  80. package/src/lib/state/toasts.spec.ts +106 -0
  81. package/src/lib/state/toasts.ts +34 -0
  82. package/src/lib/state/ui.spec.ts +148 -0
  83. package/src/lib/state/ui.ts +45 -0
  84. package/src/lib/state/welcome-toast.ts +76 -0
  85. package/src/lib/types/bento.spec.ts +116 -0
  86. package/src/lib/types/bento.ts +94 -55
  87. package/src/lib/types/event-types.spec.ts +93 -0
  88. package/src/lib/types/event-types.ts +39 -3
  89. package/src/lib/types/modules.ts +12 -5
  90. package/src/lib/types/ui-event-types.ts +66 -0
  91. package/src/lib/workers/canvas-ui-renderer.ts +266 -0
  92. package/src/lib/workers/canvas-worker.ts +94 -9
  93. package/src/lib/workers/data.ts +59 -36
  94. package/src/lib/workers/db-worker.ts +79 -32
  95. package/src/lib/workers/events.spec.ts +208 -0
  96. package/src/lib/workers/events.ts +27 -14
  97. package/src/lib/workers/flexbuilder.ts +2 -2
  98. package/src/lib/workers/init.ts +25 -17
  99. package/src/lib/workers/main.ts +510 -316
  100. package/src/lib/workers/supabase-db-worker.ts +221 -0
  101. package/src/lib/workers/supabase-shared-worker.ts +572 -0
  102. package/src/lib/workers/validate.ts +64 -0
  103. package/src/lib/workers/ws-worker.ts +156 -25
  104. package/src/setup-vitest.ts +4 -2
  105. package/src/types.ts +30 -0
  106. package/src/vite-env.d.ts +1 -0
  107. package/workers/main.js +10 -1123
  108. package/src/types.d.ts +0 -31
@@ -0,0 +1,266 @@
1
+ import type {
2
+ ToastPayload,
3
+ TooltipPayload,
4
+ ModalPayload,
5
+ } from '../types/ui-event-types';
6
+
7
+ interface ThemeColors {
8
+ accent: string;
9
+ accentLow: string;
10
+ accentHigh: string;
11
+ bg: string;
12
+ bgAccent: string;
13
+ text: string;
14
+ textAccent: string;
15
+ border: string;
16
+ white: string;
17
+ black: string;
18
+ mode: 'light' | 'dark';
19
+ }
20
+
21
+ const SEVERITY_COLORS: Record<
22
+ string,
23
+ { bg: string; border: string; text: string }
24
+ > = {
25
+ success: { bg: '#065f46', border: '#10b981', text: '#d1fae5' },
26
+ warning: { bg: '#78350f', border: '#f59e0b', text: '#fef3c7' },
27
+ error: { bg: '#7f1d1d', border: '#ef4444', text: '#fee2e2' },
28
+ info: { bg: '#1e3a5f', border: '#3b82f6', text: '#dbeafe' },
29
+ };
30
+
31
+ interface ActiveToast extends ToastPayload {
32
+ createdAt: number;
33
+ opacity: number;
34
+ y: number;
35
+ targetY: number;
36
+ }
37
+
38
+ export class CanvasUIRenderer {
39
+ private ctx: OffscreenCanvasRenderingContext2D | null = null;
40
+ private canvas: OffscreenCanvas | null = null;
41
+ private toasts: ActiveToast[] = [];
42
+ private tooltip: TooltipPayload | null = null;
43
+ private modal: ModalPayload | null = null;
44
+ private theme: ThemeColors = {
45
+ accent: '#8b5cf6',
46
+ accentLow: '#1e1033',
47
+ accentHigh: '#c4b5fd',
48
+ bg: '#0a0a0a',
49
+ bgAccent: '#3b1f6e',
50
+ text: '#e0e0e0',
51
+ textAccent: '#a78bfa',
52
+ border: '#4c1d95',
53
+ white: '#ffffff',
54
+ black: '#000000',
55
+ mode: 'dark',
56
+ };
57
+ private animFrame: number | null = null;
58
+ private dbGet: ((key: string) => Promise<string | null>) | null = null;
59
+
60
+ async bind(
61
+ canvas: OffscreenCanvas,
62
+ dbGet: (key: string) => Promise<string | null>,
63
+ ): Promise<void> {
64
+ this.canvas = canvas;
65
+ this.ctx = canvas.getContext('2d');
66
+ this.dbGet = dbGet;
67
+ await this.refreshTheme();
68
+ this.startLoop();
69
+ }
70
+
71
+ async refreshTheme(): Promise<void> {
72
+ if (!this.dbGet) return;
73
+ this.theme = {
74
+ accent: (await this.dbGet('theme:accent')) ?? '#8b5cf6',
75
+ accentLow: (await this.dbGet('theme:accent-low')) ?? '#1e1033',
76
+ accentHigh: (await this.dbGet('theme:accent-high')) ?? '#c4b5fd',
77
+ bg: (await this.dbGet('theme:bg')) ?? '#0a0a0a',
78
+ bgAccent: (await this.dbGet('theme:bg-accent')) ?? '#3b1f6e',
79
+ text: (await this.dbGet('theme:text')) ?? '#e0e0e0',
80
+ textAccent: (await this.dbGet('theme:text-accent')) ?? '#a78bfa',
81
+ border: (await this.dbGet('theme:border')) ?? '#4c1d95',
82
+ white: (await this.dbGet('theme:white')) ?? '#ffffff',
83
+ black: (await this.dbGet('theme:black')) ?? '#000000',
84
+ mode:
85
+ ((await this.dbGet('theme:mode')) as 'light' | 'dark') ??
86
+ 'dark',
87
+ };
88
+ }
89
+
90
+ addToast(payload: ToastPayload): void {
91
+ const yOffset = 20 + this.toasts.length * 80;
92
+ this.toasts.push({
93
+ ...payload,
94
+ createdAt: Date.now(),
95
+ opacity: 0,
96
+ y: yOffset - 20,
97
+ targetY: yOffset,
98
+ });
99
+ }
100
+
101
+ removeToast(id: string): void {
102
+ const idx = this.toasts.findIndex((t) => t.id === id);
103
+ if (idx !== -1) this.toasts.splice(idx, 1);
104
+ this.recalcPositions();
105
+ }
106
+
107
+ showTooltip(payload: TooltipPayload | null): void {
108
+ this.tooltip = payload;
109
+ }
110
+
111
+ showModal(payload: ModalPayload | null): void {
112
+ this.modal = payload;
113
+ }
114
+
115
+ private recalcPositions(): void {
116
+ this.toasts.forEach((t, i) => {
117
+ t.targetY = 20 + i * 80;
118
+ });
119
+ }
120
+
121
+ private startLoop(): void {
122
+ const draw = () => {
123
+ this.render();
124
+ this.animFrame = requestAnimationFrame(draw);
125
+ };
126
+ draw();
127
+ }
128
+
129
+ private render(): void {
130
+ if (!this.ctx || !this.canvas) return;
131
+ const { width, height } = this.canvas;
132
+ this.ctx.clearRect(0, 0, width, height);
133
+
134
+ // Auto-dismiss expired toasts
135
+ const now = Date.now();
136
+ this.toasts = this.toasts.filter((t) => {
137
+ if (
138
+ t.duration &&
139
+ t.duration > 0 &&
140
+ now - t.createdAt > t.duration
141
+ ) {
142
+ return false;
143
+ }
144
+ return true;
145
+ });
146
+ this.recalcPositions();
147
+
148
+ // Animate toasts
149
+ for (const toast of this.toasts) {
150
+ if (toast.opacity < 1)
151
+ toast.opacity = Math.min(1, toast.opacity + 0.05);
152
+ toast.y += (toast.targetY - toast.y) * 0.15;
153
+ this.drawToast(toast, width);
154
+ }
155
+
156
+ // Draw modal backdrop + content
157
+ if (this.modal) {
158
+ this.drawModal(width, height);
159
+ }
160
+ }
161
+
162
+ private drawToast(toast: ActiveToast, canvasWidth: number): void {
163
+ if (!this.ctx) return;
164
+ const ctx = this.ctx;
165
+ const w = 320;
166
+ const h = 64;
167
+ const x = canvasWidth - w - 20;
168
+ const y = toast.y;
169
+ const colors =
170
+ SEVERITY_COLORS[toast.severity] ?? SEVERITY_COLORS['info'];
171
+
172
+ ctx.globalAlpha = toast.opacity;
173
+
174
+ // Background
175
+ ctx.fillStyle = colors.bg;
176
+ this.roundRect(ctx, x, y, w, h, 8);
177
+ ctx.fill();
178
+
179
+ // Border
180
+ ctx.strokeStyle = colors.border;
181
+ ctx.lineWidth = 1.5;
182
+ this.roundRect(ctx, x, y, w, h, 8);
183
+ ctx.stroke();
184
+
185
+ // Text
186
+ ctx.fillStyle = colors.text;
187
+ ctx.font = '14px system-ui, -apple-system, sans-serif';
188
+ ctx.fillText(toast.message, x + 12, y + 24, w - 24);
189
+
190
+ // Severity label
191
+ ctx.font = 'bold 10px system-ui, sans-serif';
192
+ ctx.fillStyle = colors.border;
193
+ ctx.fillText(toast.severity.toUpperCase(), x + 12, y + 48);
194
+
195
+ ctx.globalAlpha = 1;
196
+ }
197
+
198
+ private drawModal(canvasWidth: number, canvasHeight: number): void {
199
+ if (!this.ctx || !this.modal) return;
200
+ const ctx = this.ctx;
201
+
202
+ // Backdrop
203
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
204
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
205
+
206
+ // Modal box
207
+ const w = Math.min(500, canvasWidth - 40);
208
+ const h = 300;
209
+ const x = (canvasWidth - w) / 2;
210
+ const y = (canvasHeight - h) / 2;
211
+
212
+ ctx.fillStyle = this.theme.bg;
213
+ this.roundRect(ctx, x, y, w, h, 12);
214
+ ctx.fill();
215
+
216
+ ctx.strokeStyle = this.theme.border;
217
+ ctx.lineWidth = 1;
218
+ this.roundRect(ctx, x, y, w, h, 12);
219
+ ctx.stroke();
220
+
221
+ // Title
222
+ if (this.modal.title) {
223
+ ctx.fillStyle = this.theme.text;
224
+ ctx.font = 'bold 18px system-ui, sans-serif';
225
+ ctx.fillText(this.modal.title, x + 20, y + 36, w - 40);
226
+ }
227
+
228
+ // ID label
229
+ ctx.fillStyle = this.theme.textAccent;
230
+ ctx.font = '12px system-ui, sans-serif';
231
+ ctx.fillText(this.modal.id, x + 20, y + 60, w - 40);
232
+ }
233
+
234
+ private roundRect(
235
+ ctx: OffscreenCanvasRenderingContext2D,
236
+ x: number,
237
+ y: number,
238
+ w: number,
239
+ h: number,
240
+ r: number,
241
+ ): void {
242
+ ctx.beginPath();
243
+ ctx.moveTo(x + r, y);
244
+ ctx.lineTo(x + w - r, y);
245
+ ctx.quadraticCurveTo(x + w, y, x + w, y + r);
246
+ ctx.lineTo(x + w, y + h - r);
247
+ ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
248
+ ctx.lineTo(x + r, y + h);
249
+ ctx.quadraticCurveTo(x, y + h, x, y + h - r);
250
+ ctx.lineTo(x, y + r);
251
+ ctx.quadraticCurveTo(x, y, x + r, y);
252
+ ctx.closePath();
253
+ }
254
+
255
+ unbind(): void {
256
+ if (this.animFrame !== null) {
257
+ cancelAnimationFrame(this.animFrame);
258
+ this.animFrame = null;
259
+ }
260
+ this.ctx = null;
261
+ this.canvas = null;
262
+ this.toasts = [];
263
+ this.tooltip = null;
264
+ this.modal = null;
265
+ }
266
+ }
@@ -1,8 +1,28 @@
1
1
  import { expose } from 'comlink';
2
+ import { CanvasUIRenderer } from './canvas-ui-renderer';
3
+ import type {
4
+ ToastPayload,
5
+ TooltipPayload,
6
+ ModalPayload,
7
+ } from '../types/ui-event-types';
2
8
 
3
9
  export interface CanvasWorkerAPI {
4
- bindCanvas(panelId: string, canvas: OffscreenCanvas, mode?: CanvasDrawMode): Promise<void>;
10
+ bindCanvas(
11
+ panelId: string,
12
+ canvas: OffscreenCanvas,
13
+ mode?: CanvasDrawMode,
14
+ ): Promise<void>;
5
15
  unbindCanvas(panelId: string): Promise<void>;
16
+ bindUICanvas(
17
+ canvas: OffscreenCanvas,
18
+ dbGet: (key: string) => Promise<string | null>,
19
+ ): Promise<void>;
20
+ unbindUICanvas(): void;
21
+ addCanvasToast(payload: ToastPayload): void;
22
+ removeCanvasToast(id: string): void;
23
+ showCanvasTooltip(payload: TooltipPayload | null): void;
24
+ showCanvasModal(payload: ModalPayload | null): void;
25
+ refreshUITheme(): Promise<void>;
6
26
  }
7
27
 
8
28
  interface CanvasBinding {
@@ -15,18 +35,38 @@ interface CanvasBinding {
15
35
 
16
36
  export type CanvasDrawMode = 'static' | 'animated' | 'dynamic';
17
37
 
38
+ const uiRenderer = new CanvasUIRenderer();
39
+
40
+ // Listen for theme changes from main thread
41
+ try {
42
+ const bc = new BroadcastChannel('kbve_theme');
43
+ bc.onmessage = () => {
44
+ void uiRenderer.refreshTheme();
45
+ };
46
+ } catch {
47
+ // BroadcastChannel unavailable in this context
48
+ }
49
+
18
50
  const CanvasManager = {
19
51
  bindings: new Map<string, CanvasBinding>(),
20
52
 
21
- async bindCanvas(panelId: string, canvas: OffscreenCanvas, mode: CanvasDrawMode = 'animated') {
53
+ async bindCanvas(
54
+ panelId: string,
55
+ canvas: OffscreenCanvas,
56
+ mode: CanvasDrawMode = 'animated',
57
+ ) {
22
58
  const ctx = canvas.getContext('2d');
23
59
 
24
60
  if (!ctx) {
25
- console.error(`[CanvasWorker] Failed to get 2D context for panel ${panelId}`);
61
+ console.error(
62
+ `[CanvasWorker] Failed to get 2D context for panel ${panelId}`,
63
+ );
26
64
  return;
27
65
  }
28
66
 
29
- console.log(`[CanvasWorker] Successfully bound canvas for panel ${panelId} with mode ${mode}`);
67
+ console.log(
68
+ `[CanvasWorker] Successfully bound canvas for panel ${panelId} with mode ${mode}`,
69
+ );
30
70
 
31
71
  this.bindings.set(panelId, { ctx, canvas, panelId, mode });
32
72
 
@@ -48,7 +88,9 @@ const CanvasManager = {
48
88
  this.drawDynamic(binding);
49
89
  break;
50
90
  default:
51
- console.warn(`[CanvasWorker] Unknown draw mode for panel ${panelId}`);
91
+ console.warn(
92
+ `[CanvasWorker] Unknown draw mode for panel ${panelId}`,
93
+ );
52
94
  }
53
95
  },
54
96
 
@@ -63,7 +105,12 @@ const CanvasManager = {
63
105
  const drawFrame = () => {
64
106
  hue = (hue + 1) % 360;
65
107
  binding.ctx.fillStyle = `hsl(${hue}, 100%, 50%)`;
66
- binding.ctx.fillRect(0, 0, binding.canvas.width, binding.canvas.height);
108
+ binding.ctx.fillRect(
109
+ 0,
110
+ 0,
111
+ binding.canvas.width,
112
+ binding.canvas.height,
113
+ );
67
114
 
68
115
  binding.animationFrame = requestAnimationFrame(drawFrame);
69
116
  };
@@ -76,18 +123,23 @@ const CanvasManager = {
76
123
 
77
124
  const drawFrame = () => {
78
125
  time += 0.05;
79
- binding.ctx.clearRect(0, 0, binding.canvas.width, binding.canvas.height);
126
+ binding.ctx.clearRect(
127
+ 0,
128
+ 0,
129
+ binding.canvas.width,
130
+ binding.canvas.height,
131
+ );
80
132
  binding.ctx.beginPath();
81
133
  binding.ctx.arc(
82
134
  binding.canvas.width / 2 + Math.sin(time) * 50,
83
135
  binding.canvas.height / 2 + Math.cos(time) * 50,
84
136
  30,
85
137
  0,
86
- Math.PI * 2
138
+ Math.PI * 2,
87
139
  );
88
140
  binding.ctx.fillStyle = 'orange';
89
141
  binding.ctx.fill();
90
-
142
+
91
143
  binding.animationFrame = requestAnimationFrame(drawFrame);
92
144
  };
93
145
 
@@ -102,6 +154,39 @@ const CanvasManager = {
102
154
  this.bindings.delete(panelId);
103
155
  console.log(`[CanvasWorker] Unbound canvas for panel ${panelId}`);
104
156
  },
157
+
158
+ // ── UI Overlay Canvas ──
159
+
160
+ async bindUICanvas(
161
+ canvas: OffscreenCanvas,
162
+ dbGet: (key: string) => Promise<string | null>,
163
+ ) {
164
+ await uiRenderer.bind(canvas, dbGet);
165
+ },
166
+
167
+ unbindUICanvas() {
168
+ uiRenderer.unbind();
169
+ },
170
+
171
+ addCanvasToast(payload: ToastPayload) {
172
+ uiRenderer.addToast(payload);
173
+ },
174
+
175
+ removeCanvasToast(id: string) {
176
+ uiRenderer.removeToast(id);
177
+ },
178
+
179
+ showCanvasTooltip(payload: TooltipPayload | null) {
180
+ uiRenderer.showTooltip(payload);
181
+ },
182
+
183
+ showCanvasModal(payload: ModalPayload | null) {
184
+ uiRenderer.showModal(payload);
185
+ },
186
+
187
+ refreshUITheme() {
188
+ return uiRenderer.refreshTheme();
189
+ },
105
190
  };
106
191
 
107
192
  expose(CanvasManager);
@@ -1,8 +1,9 @@
1
1
  import { PayloadFormat, JediEnvelopeFlex, MessageKind } from '../types/jedi';
2
2
  import { builder, toReference } from './flexbuilder';
3
3
 
4
-
5
- function buildFlexPayload<T extends Record<string, any>>(payload: T): Uint8Array {
4
+ function buildFlexPayload<T extends Record<string, unknown>>(
5
+ payload: T,
6
+ ): Uint8Array {
6
7
  const b = builder();
7
8
  b.startMap();
8
9
 
@@ -15,7 +16,7 @@ function buildFlexPayload<T extends Record<string, any>>(payload: T): Uint8Array
15
16
  return b.finish();
16
17
  }
17
18
 
18
- export function wrapEnvelope<T extends Record<string, any>>(
19
+ export function wrapEnvelope<T extends Record<string, unknown>>(
19
20
  payload: T,
20
21
  kind: number,
21
22
  format: PayloadFormat,
@@ -34,22 +35,30 @@ export function wrapEnvelope<T extends Record<string, any>>(
34
35
 
35
36
  const b = builder();
36
37
  b.startMap();
37
- b.addKey('version'); b.add(version);
38
- b.addKey('kind'); b.add(kind);
39
- b.addKey('format'); b.add(format);
40
- b.addKey('payload'); b.add(serializedPayload);
41
- b.addKey('metadata'); b.add(metadata ?? new Uint8Array());
38
+ b.addKey('version');
39
+ b.add(version);
40
+ b.addKey('kind');
41
+ b.add(kind);
42
+ b.addKey('format');
43
+ b.add(format);
44
+ b.addKey('payload');
45
+ b.add(serializedPayload);
46
+ b.addKey('metadata');
47
+ b.add(metadata ?? new Uint8Array());
42
48
  b.end();
43
49
 
44
50
  return b.finish();
45
51
  }
46
52
 
47
53
  export function unwrapEnvelope<T = unknown>(
48
- buffer: Uint8Array | ArrayBuffer
54
+ buffer: Uint8Array | ArrayBuffer,
49
55
  ): { envelope: JediEnvelopeFlex; payload: T } {
50
56
  const view = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
51
57
 
52
- const root = toReference(view.buffer as ArrayBuffer).toObject() as Record<string, any>;
58
+ const root = toReference(view.buffer as ArrayBuffer).toObject() as Record<
59
+ string,
60
+ unknown
61
+ >;
53
62
 
54
63
  if (
55
64
  typeof root['version'] !== 'number' ||
@@ -65,8 +74,10 @@ export function unwrapEnvelope<T = unknown>(
65
74
  version: root['version'],
66
75
  kind: root['kind'],
67
76
  format: root['format'],
68
- payload: new Uint8Array(root['payload']),
69
- metadata: root['metadata'] ? new Uint8Array(root['metadata']) : undefined,
77
+ payload: new Uint8Array(root['payload'] as ArrayLike<number>),
78
+ metadata: root['metadata']
79
+ ? new Uint8Array(root['metadata'] as ArrayLike<number>)
80
+ : undefined,
70
81
  };
71
82
 
72
83
  let parsedPayload: T;
@@ -75,9 +86,13 @@ export function unwrapEnvelope<T = unknown>(
75
86
  const ref = toReference(envelope.payload.buffer as ArrayBuffer);
76
87
  parsedPayload = ref.toObject() as T;
77
88
  } else if (envelope.format === PayloadFormat.JSON) {
78
- parsedPayload = JSON.parse(new TextDecoder().decode(envelope.payload)) as T;
89
+ parsedPayload = JSON.parse(
90
+ new TextDecoder().decode(envelope.payload),
91
+ ) as T;
79
92
  } else {
80
- throw new Error(`[unwrapEnvelope] Unsupported format: ${envelope.format}`);
93
+ throw new Error(
94
+ `[unwrapEnvelope] Unsupported format: ${envelope.format}`,
95
+ );
81
96
  }
82
97
 
83
98
  return { envelope, payload: parsedPayload };
@@ -89,7 +104,8 @@ export function unwrapFlexToJson(buffer: Uint8Array) {
89
104
 
90
105
  export function inspectFlex(buffer: Uint8Array | ArrayBuffer): void {
91
106
  try {
92
- const view = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
107
+ const view =
108
+ buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
93
109
  const obj = unwrapFlexToJson(view);
94
110
  console.log('[FlexObject]', JSON.stringify(obj, null, 2));
95
111
  } catch (err) {
@@ -101,14 +117,13 @@ export function hasKind(kind: number, flag: number): boolean {
101
117
  return (kind & flag) === flag;
102
118
  }
103
119
 
104
-
105
120
  // Redis Helpers
106
121
 
107
122
  export function wrapRedisSet(key: string, value: string): Uint8Array {
108
123
  return wrapEnvelope(
109
124
  { key, value },
110
125
  MessageKind.SET | MessageKind.REDIS,
111
- PayloadFormat.FLEX
126
+ PayloadFormat.FLEX,
112
127
  );
113
128
  }
114
129
 
@@ -116,7 +131,7 @@ export function wrapRedisGet(key: string): Uint8Array {
116
131
  return wrapEnvelope(
117
132
  { key },
118
133
  MessageKind.GET | MessageKind.REDIS,
119
- PayloadFormat.FLEX
134
+ PayloadFormat.FLEX,
120
135
  );
121
136
  }
122
137
 
@@ -124,11 +139,13 @@ export function wrapRedisDel(key: string): Uint8Array {
124
139
  return wrapEnvelope(
125
140
  { key },
126
141
  MessageKind.DEL | MessageKind.REDIS,
127
- PayloadFormat.FLEX
142
+ PayloadFormat.FLEX,
128
143
  );
129
144
  }
130
145
 
131
- export function parseRedisPayload<T = unknown>(envelopeBytes: Uint8Array): {
146
+ export function parseRedisPayload<T = unknown>(
147
+ envelopeBytes: Uint8Array,
148
+ ): {
132
149
  envelope: JediEnvelopeFlex;
133
150
  payload: T;
134
151
  } {
@@ -156,25 +173,28 @@ export function wrapRedisXRead(
156
173
  count?: number,
157
174
  block?: number,
158
175
  ): Uint8Array {
159
-
160
176
  const inner = builder();
161
177
  inner.startMap();
162
178
 
163
179
  inner.addKey('streams');
164
- inner.startVector();
180
+ inner.startVector();
165
181
  for (const { stream, id } of streams) {
166
182
  inner.startMap();
167
- inner.addKey('stream'); inner.add(stream);
168
- inner.addKey('id'); inner.add(id);
183
+ inner.addKey('stream');
184
+ inner.add(stream);
185
+ inner.addKey('id');
186
+ inner.add(id);
169
187
  inner.end();
170
- }
188
+ }
171
189
  inner.end();
172
190
 
173
191
  if (count !== undefined) {
174
- inner.addKey('count'); inner.add(count);
192
+ inner.addKey('count');
193
+ inner.add(count);
175
194
  }
176
195
  if (block !== undefined) {
177
- inner.addKey('block'); inner.add(block);
196
+ inner.addKey('block');
197
+ inner.add(block);
178
198
  }
179
199
 
180
200
  inner.end();
@@ -182,18 +202,21 @@ export function wrapRedisXRead(
182
202
 
183
203
  const b = builder();
184
204
  b.startMap();
185
- b.addKey('version'); b.add(1);
186
- b.addKey('kind'); b.add(MessageKind.READ | MessageKind.STREAM | MessageKind.REDIS);
187
- b.addKey('format'); b.add(PayloadFormat.FLEX);
188
- b.addKey('payload'); b.add(serializedPayload);
189
- b.addKey('metadata'); b.add(new Uint8Array());
205
+ b.addKey('version');
206
+ b.add(1);
207
+ b.addKey('kind');
208
+ b.add(MessageKind.READ | MessageKind.STREAM | MessageKind.REDIS);
209
+ b.addKey('format');
210
+ b.add(PayloadFormat.FLEX);
211
+ b.addKey('payload');
212
+ b.add(serializedPayload);
213
+ b.addKey('metadata');
214
+ b.add(new Uint8Array());
190
215
  b.end();
191
216
 
192
217
  return b.finish();
193
218
  }
194
219
 
195
-
196
-
197
220
  export const scopeData = {
198
221
  wrapEnvelope,
199
222
  unwrapEnvelope,
@@ -202,14 +225,14 @@ export const scopeData = {
202
225
  unwrapFlexToJson,
203
226
  inspectFlex,
204
227
  hasKind,
205
- redis: {
228
+ redis: {
206
229
  wrapRedisSet,
207
230
  wrapRedisGet,
208
231
  wrapRedisDel,
209
232
  wrapRedisXAdd,
210
233
  wrapRedisXRead,
211
234
  parseRedisPayload,
212
- }
235
+ },
213
236
  };
214
237
 
215
238
  export type FlexDataAPI = typeof scopeData;