@couch-kit/devtools 0.2.8 → 0.2.10

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @couch-kit/devtools
2
2
 
3
+ ## 0.2.10
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies []:
8
+ - @couch-kit/client@0.8.9
9
+
10
+ ## 0.2.9
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies []:
15
+ - @couch-kit/client@0.8.8
16
+
3
17
  ## 0.2.8
4
18
 
5
19
  ### Patch Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @couch-kit/devtools
2
2
 
3
- Developer tooling and debug overlay for Couch Kit games.
3
+ Debug overlay component for Couch Kit web controllers. Displays connection status, game state, and action history in a collapsible panel.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,17 +8,37 @@ Developer tooling and debug overlay for Couch Kit games.
8
8
  bun add @couch-kit/devtools
9
9
  ```
10
10
 
11
+ Requires `@couch-kit/client` as a peer dependency (provides the `useDebugPanel` hook that feeds data to the overlay).
12
+
11
13
  ## Usage
12
14
 
15
+ Wire `useDebugPanel` (from `@couch-kit/client`) to the `DebugOverlay` component:
16
+
13
17
  ```tsx
18
+ import { useGameClient, useDebugPanel } from "@couch-kit/client";
14
19
  import { DebugOverlay } from "@couch-kit/devtools";
20
+ import { gameReducer, initialState } from "./shared/types";
15
21
 
16
22
  function App() {
23
+ const client = useGameClient({ reducer: gameReducer, initialState });
24
+ const debugData = useDebugPanel(client);
25
+
17
26
  return (
18
27
  <div>
19
- <Game />
20
- <DebugOverlay />
28
+ <Game {...client} />
29
+ {import.meta.env.DEV && <DebugOverlay data={debugData} />}
21
30
  </div>
22
31
  );
23
32
  }
24
33
  ```
34
+
35
+ ## Props
36
+
37
+ | Prop | Type | Default | Description |
38
+ | ------------------ | ------------------------------------------------------------- | --------------- | ---------------------------------------- |
39
+ | `data` | `DebugPanelData` (from `@couch-kit/client`) | **required** | Debug data from `useDebugPanel` |
40
+ | `defaultCollapsed` | `boolean` | `false` | Start collapsed |
41
+ | `position` | `"top-left" \| "top-right" \| "bottom-left" \| "bottom-right"` | `"bottom-right"` | Screen corner to anchor the panel |
42
+ | `maxHeight` | `number` | `400` | Maximum pixel height of the panel body |
43
+
44
+ ```
package/dist/index.js CHANGED
@@ -1,372 +1,3 @@
1
- // src/DebugOverlay.tsx
2
- import { useState, useCallback, useRef } from "react";
3
- import { jsxDEV } from "react/jsx-dev-runtime";
4
- var STATUS_COLORS = {
5
- connected: "#4ade80",
6
- connecting: "#facc15",
7
- reconnecting: "#facc15",
8
- disconnected: "#f87171",
9
- error: "#f87171"
10
- };
11
- function formatTimestamp(ts) {
12
- const date = new Date(ts);
13
- return date.toLocaleTimeString("en-US", {
14
- hour12: false,
15
- hour: "2-digit",
16
- minute: "2-digit",
17
- second: "2-digit"
18
- }) + "." + String(date.getMilliseconds()).padStart(3, "0");
19
- }
20
- function JsonTree({ data, depth = 0 }) {
21
- if (data === null || data === undefined) {
22
- return /* @__PURE__ */ jsxDEV("span", {
23
- style: { color: "#9ca3af" },
24
- children: String(data)
25
- }, undefined, false, undefined, this);
26
- }
27
- if (typeof data === "boolean") {
28
- return /* @__PURE__ */ jsxDEV("span", {
29
- style: { color: "#c084fc" },
30
- children: String(data)
31
- }, undefined, false, undefined, this);
32
- }
33
- if (typeof data === "number") {
34
- return /* @__PURE__ */ jsxDEV("span", {
35
- style: { color: "#60a5fa" },
36
- children: data
37
- }, undefined, false, undefined, this);
38
- }
39
- if (typeof data === "string") {
40
- return /* @__PURE__ */ jsxDEV("span", {
41
- style: { color: "#4ade80" },
42
- children: [
43
- '"',
44
- data,
45
- '"'
46
- ]
47
- }, undefined, true, undefined, this);
48
- }
49
- if (Array.isArray(data)) {
50
- if (data.length === 0)
51
- return /* @__PURE__ */ jsxDEV("span", {
52
- children: "[]"
53
- }, undefined, false, undefined, this);
54
- return /* @__PURE__ */ jsxDEV("span", {
55
- children: [
56
- `[
57
- `,
58
- data.map((item, i) => /* @__PURE__ */ jsxDEV("span", {
59
- children: [
60
- " ".repeat(depth + 1),
61
- /* @__PURE__ */ jsxDEV(JsonTree, {
62
- data: item,
63
- depth: depth + 1
64
- }, undefined, false, undefined, this),
65
- i < data.length - 1 ? "," : "",
66
- `
67
- `
68
- ]
69
- }, i, true, undefined, this)),
70
- " ".repeat(depth),
71
- "]"
72
- ]
73
- }, undefined, true, undefined, this);
74
- }
75
- if (typeof data === "object") {
76
- const entries = Object.entries(data);
77
- if (entries.length === 0)
78
- return /* @__PURE__ */ jsxDEV("span", {
79
- children: "{}"
80
- }, undefined, false, undefined, this);
81
- return /* @__PURE__ */ jsxDEV("span", {
82
- children: [
83
- `{
84
- `,
85
- entries.map(([key, value], i) => /* @__PURE__ */ jsxDEV("span", {
86
- children: [
87
- " ".repeat(depth + 1),
88
- /* @__PURE__ */ jsxDEV("span", {
89
- style: { color: "#93c5fd" },
90
- children: key
91
- }, undefined, false, undefined, this),
92
- ": ",
93
- /* @__PURE__ */ jsxDEV(JsonTree, {
94
- data: value,
95
- depth: depth + 1
96
- }, undefined, false, undefined, this),
97
- i < entries.length - 1 ? "," : "",
98
- `
99
- `
100
- ]
101
- }, key, true, undefined, this)),
102
- " ".repeat(depth),
103
- "}"
104
- ]
105
- }, undefined, true, undefined, this);
106
- }
107
- return /* @__PURE__ */ jsxDEV("span", {
108
- children: String(data)
109
- }, undefined, false, undefined, this);
110
- }
111
- function DebugOverlay({
112
- data,
113
- defaultCollapsed = true,
114
- position = "bottom-right",
115
- maxHeight = 400
116
- }) {
117
- const [collapsed, setCollapsed] = useState(defaultCollapsed);
118
- const [activeTab, setActiveTab] = useState("actions");
119
- const tapCountRef = useRef(0);
120
- const tapTimerRef = useRef(null);
121
- const handleToggle = useCallback(() => {
122
- tapCountRef.current++;
123
- if (tapTimerRef.current) {
124
- clearTimeout(tapTimerRef.current);
125
- }
126
- tapTimerRef.current = setTimeout(() => {
127
- tapCountRef.current = 0;
128
- }, 300);
129
- setCollapsed((prev) => !prev);
130
- }, []);
131
- if (!data.enabled)
132
- return null;
133
- const positionStyles = {
134
- position: "fixed",
135
- zIndex: 99999,
136
- ...position.includes("top") ? { top: 8 } : { bottom: 8 },
137
- ...position.includes("left") ? { left: 8 } : { right: 8 }
138
- };
139
- const statusColor = STATUS_COLORS[data.connectionStatus] ?? "#9ca3af";
140
- const panelStyle = {
141
- ...positionStyles,
142
- fontFamily: "'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace",
143
- fontSize: 11,
144
- lineHeight: 1.4,
145
- color: "#e5e7eb",
146
- backgroundColor: "rgba(17, 24, 39, 0.95)",
147
- border: "1px solid rgba(75, 85, 99, 0.6)",
148
- borderRadius: 8,
149
- overflow: "hidden",
150
- width: collapsed ? "auto" : 360,
151
- backdropFilter: "blur(8px)",
152
- boxShadow: "0 4px 24px rgba(0, 0, 0, 0.4)"
153
- };
154
- const buttonStyle = {
155
- background: "none",
156
- border: "none",
157
- color: "#e5e7eb",
158
- cursor: "pointer",
159
- padding: "6px 10px",
160
- fontSize: 11,
161
- fontFamily: "inherit"
162
- };
163
- const tabStyle = (isActive) => ({
164
- ...buttonStyle,
165
- borderBottom: isActive ? "2px solid #60a5fa" : "2px solid transparent",
166
- color: isActive ? "#60a5fa" : "#9ca3af",
167
- paddingBottom: 4
168
- });
169
- if (collapsed) {
170
- return /* @__PURE__ */ jsxDEV("div", {
171
- style: positionStyles,
172
- children: /* @__PURE__ */ jsxDEV("button", {
173
- onClick: handleToggle,
174
- style: {
175
- ...buttonStyle,
176
- backgroundColor: "rgba(17, 24, 39, 0.95)",
177
- border: "1px solid rgba(75, 85, 99, 0.6)",
178
- borderRadius: 8,
179
- display: "flex",
180
- alignItems: "center",
181
- gap: 6,
182
- padding: "6px 12px",
183
- backdropFilter: "blur(8px)",
184
- boxShadow: "0 2px 12px rgba(0, 0, 0, 0.3)"
185
- },
186
- children: [
187
- /* @__PURE__ */ jsxDEV("span", {
188
- style: {
189
- width: 8,
190
- height: 8,
191
- borderRadius: "50%",
192
- backgroundColor: statusColor,
193
- display: "inline-block"
194
- }
195
- }, undefined, false, undefined, this),
196
- /* @__PURE__ */ jsxDEV("span", {
197
- children: "Debug"
198
- }, undefined, false, undefined, this),
199
- data.rtt !== null && /* @__PURE__ */ jsxDEV("span", {
200
- style: { color: "#9ca3af" },
201
- children: [
202
- data.rtt,
203
- "ms"
204
- ]
205
- }, undefined, true, undefined, this)
206
- ]
207
- }, undefined, true, undefined, this)
208
- }, undefined, false, undefined, this);
209
- }
210
- const latestState = data.stateHistory.length > 0 ? data.stateHistory[data.stateHistory.length - 1]?.state : null;
211
- return /* @__PURE__ */ jsxDEV("div", {
212
- style: panelStyle,
213
- children: [
214
- /* @__PURE__ */ jsxDEV("div", {
215
- style: {
216
- display: "flex",
217
- alignItems: "center",
218
- justifyContent: "space-between",
219
- padding: "6px 10px",
220
- borderBottom: "1px solid rgba(75, 85, 99, 0.4)"
221
- },
222
- children: [
223
- /* @__PURE__ */ jsxDEV("div", {
224
- style: { display: "flex", alignItems: "center", gap: 6 },
225
- children: [
226
- /* @__PURE__ */ jsxDEV("span", {
227
- style: {
228
- width: 8,
229
- height: 8,
230
- borderRadius: "50%",
231
- backgroundColor: statusColor,
232
- display: "inline-block"
233
- }
234
- }, undefined, false, undefined, this),
235
- /* @__PURE__ */ jsxDEV("span", {
236
- style: { fontWeight: 600 },
237
- children: "Debug"
238
- }, undefined, false, undefined, this),
239
- /* @__PURE__ */ jsxDEV("span", {
240
- style: { color: "#9ca3af" },
241
- children: [
242
- data.connectionStatus,
243
- data.rtt !== null ? ` · ${data.rtt}ms` : ""
244
- ]
245
- }, undefined, true, undefined, this)
246
- ]
247
- }, undefined, true, undefined, this),
248
- /* @__PURE__ */ jsxDEV("div", {
249
- style: { display: "flex", gap: 4 },
250
- children: [
251
- /* @__PURE__ */ jsxDEV("button", {
252
- onClick: data.clearHistory,
253
- style: buttonStyle,
254
- title: "Clear",
255
- children: "✕"
256
- }, undefined, false, undefined, this),
257
- /* @__PURE__ */ jsxDEV("button", {
258
- onClick: handleToggle,
259
- style: buttonStyle,
260
- title: "Collapse",
261
- children: "▾"
262
- }, undefined, false, undefined, this)
263
- ]
264
- }, undefined, true, undefined, this)
265
- ]
266
- }, undefined, true, undefined, this),
267
- /* @__PURE__ */ jsxDEV("div", {
268
- style: {
269
- display: "flex",
270
- gap: 0,
271
- borderBottom: "1px solid rgba(75, 85, 99, 0.4)",
272
- padding: "0 6px"
273
- },
274
- children: [
275
- /* @__PURE__ */ jsxDEV("button", {
276
- onClick: () => setActiveTab("actions"),
277
- style: tabStyle(activeTab === "actions"),
278
- children: [
279
- "Actions (",
280
- data.actionLog.length,
281
- ")"
282
- ]
283
- }, undefined, true, undefined, this),
284
- /* @__PURE__ */ jsxDEV("button", {
285
- onClick: () => setActiveTab("state"),
286
- style: tabStyle(activeTab === "state"),
287
- children: "State"
288
- }, undefined, false, undefined, this)
289
- ]
290
- }, undefined, true, undefined, this),
291
- /* @__PURE__ */ jsxDEV("div", {
292
- style: {
293
- maxHeight,
294
- overflowY: "auto",
295
- padding: 8
296
- },
297
- children: [
298
- activeTab === "actions" && /* @__PURE__ */ jsxDEV("div", {
299
- children: data.actionLog.length === 0 ? /* @__PURE__ */ jsxDEV("div", {
300
- style: {
301
- color: "#6b7280",
302
- textAlign: "center",
303
- padding: 16
304
- },
305
- children: "No actions recorded"
306
- }, undefined, false, undefined, this) : data.actionLog.slice().reverse().map((entry) => /* @__PURE__ */ jsxDEV("div", {
307
- style: {
308
- padding: "4px 6px",
309
- borderBottom: "1px solid rgba(75, 85, 99, 0.2)",
310
- display: "flex",
311
- flexDirection: "column",
312
- gap: 2
313
- },
314
- children: [
315
- /* @__PURE__ */ jsxDEV("div", {
316
- style: {
317
- display: "flex",
318
- justifyContent: "space-between",
319
- alignItems: "center"
320
- },
321
- children: [
322
- /* @__PURE__ */ jsxDEV("span", {
323
- style: {
324
- color: entry.source === "local" ? "#60a5fa" : "#4ade80",
325
- fontSize: 10,
326
- textTransform: "uppercase"
327
- },
328
- children: entry.source
329
- }, undefined, false, undefined, this),
330
- /* @__PURE__ */ jsxDEV("span", {
331
- style: { color: "#6b7280", fontSize: 10 },
332
- children: formatTimestamp(entry.timestamp)
333
- }, undefined, false, undefined, this)
334
- ]
335
- }, undefined, true, undefined, this),
336
- /* @__PURE__ */ jsxDEV("pre", {
337
- style: {
338
- margin: 0,
339
- fontSize: 10,
340
- color: "#d1d5db",
341
- whiteSpace: "pre-wrap",
342
- wordBreak: "break-all"
343
- },
344
- children: /* @__PURE__ */ jsxDEV(JsonTree, {
345
- data: entry.action
346
- }, undefined, false, undefined, this)
347
- }, undefined, false, undefined, this)
348
- ]
349
- }, entry.id, true, undefined, this))
350
- }, undefined, false, undefined, this),
351
- activeTab === "state" && /* @__PURE__ */ jsxDEV("pre", {
352
- style: {
353
- margin: 0,
354
- fontSize: 10,
355
- whiteSpace: "pre-wrap",
356
- wordBreak: "break-all"
357
- },
358
- children: latestState !== null ? /* @__PURE__ */ jsxDEV(JsonTree, {
359
- data: latestState
360
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV("span", {
361
- style: { color: "#6b7280" },
362
- children: "No state captured"
363
- }, undefined, false, undefined, this)
364
- }, undefined, false, undefined, this)
365
- ]
366
- }, undefined, true, undefined, this)
367
- ]
368
- }, undefined, true, undefined, this);
369
- }
370
1
  export {
371
2
  DebugOverlay
372
3
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@couch-kit/devtools",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "Developer tooling and debug overlay for Couch Kit games",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -28,14 +28,19 @@
28
28
  ],
29
29
  "dependencies": {},
30
30
  "devDependencies": {
31
- "@couch-kit/client": "0.8.7",
32
- "@couch-kit/core": "0.9.1",
33
- "@types/react": "^19.1.1",
34
- "react": "^18.2.0",
35
- "typescript": "^5.4.0"
31
+ "@couch-kit/client": "0.8.9",
32
+ "@couch-kit/core": "0.9.3",
33
+ "@happy-dom/global-registrator": "^20.10.6",
34
+ "@testing-library/dom": "^10.4.1",
35
+ "@testing-library/react": "^16.3.2",
36
+ "@types/react": "^19.2.17",
37
+ "@types/react-dom": "^19",
38
+ "react": "^19.0.0",
39
+ "react-dom": "^19.0.0",
40
+ "typescript": "^6.0.0"
36
41
  },
37
42
  "peerDependencies": {
38
- "@couch-kit/client": "0.8.7",
43
+ "@couch-kit/client": "0.8.9",
39
44
  "react": ">=18.0.0"
40
45
  },
41
46
  "publishConfig": {