@couch-kit/devtools 3.0.2 → 3.0.3

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,13 @@
1
1
  # @couch-kit/devtools
2
2
 
3
+ ## 3.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#206](https://github.com/faluciano/react-native-couch-kit/pull/206) [`cfe5bbb`](https://github.com/faluciano/react-native-couch-kit/commit/cfe5bbb1ac46eca0cb006b07473fbfab32e0182b) Thanks [@faluciano](https://github.com/faluciano)! - Publish a bundle that actually contains `DebugOverlay`.
8
+
9
+ Every previous release shipped a 27-byte `dist/index.js` that exported `DebugOverlay` without defining it: with `sideEffects: false`, the bundler tree-shook the named re-export of the package's only value. The build also targeted React's development JSX runtime, which does not work in a production build. The entry point now uses `export *`, the bundle is built against `react/jsx-runtime`, and the build fails if either regresses.
10
+
3
11
  ## 3.0.2
4
12
 
5
13
  ### Patch Changes
package/dist/index.js CHANGED
@@ -1,3 +1,372 @@
1
+ // src/DebugOverlay.tsx
2
+ import { useState, useCallback, useRef } from "react";
3
+ import { jsx, jsxs } from "react/jsx-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__ */ jsx("span", {
23
+ style: { color: "#9ca3af" },
24
+ children: String(data)
25
+ });
26
+ }
27
+ if (typeof data === "boolean") {
28
+ return /* @__PURE__ */ jsx("span", {
29
+ style: { color: "#c084fc" },
30
+ children: String(data)
31
+ });
32
+ }
33
+ if (typeof data === "number") {
34
+ return /* @__PURE__ */ jsx("span", {
35
+ style: { color: "#60a5fa" },
36
+ children: data
37
+ });
38
+ }
39
+ if (typeof data === "string") {
40
+ return /* @__PURE__ */ jsxs("span", {
41
+ style: { color: "#4ade80" },
42
+ children: [
43
+ '"',
44
+ data,
45
+ '"'
46
+ ]
47
+ });
48
+ }
49
+ if (Array.isArray(data)) {
50
+ if (data.length === 0)
51
+ return /* @__PURE__ */ jsx("span", {
52
+ children: "[]"
53
+ });
54
+ return /* @__PURE__ */ jsxs("span", {
55
+ children: [
56
+ `[
57
+ `,
58
+ data.map((item, i) => /* @__PURE__ */ jsxs("span", {
59
+ children: [
60
+ " ".repeat(depth + 1),
61
+ /* @__PURE__ */ jsx(JsonTree, {
62
+ data: item,
63
+ depth: depth + 1
64
+ }),
65
+ i < data.length - 1 ? "," : "",
66
+ `
67
+ `
68
+ ]
69
+ }, i)),
70
+ " ".repeat(depth),
71
+ "]"
72
+ ]
73
+ });
74
+ }
75
+ if (typeof data === "object") {
76
+ const entries = Object.entries(data);
77
+ if (entries.length === 0)
78
+ return /* @__PURE__ */ jsx("span", {
79
+ children: "{}"
80
+ });
81
+ return /* @__PURE__ */ jsxs("span", {
82
+ children: [
83
+ `{
84
+ `,
85
+ entries.map(([key, value], i) => /* @__PURE__ */ jsxs("span", {
86
+ children: [
87
+ " ".repeat(depth + 1),
88
+ /* @__PURE__ */ jsx("span", {
89
+ style: { color: "#93c5fd" },
90
+ children: key
91
+ }),
92
+ ": ",
93
+ /* @__PURE__ */ jsx(JsonTree, {
94
+ data: value,
95
+ depth: depth + 1
96
+ }),
97
+ i < entries.length - 1 ? "," : "",
98
+ `
99
+ `
100
+ ]
101
+ }, key)),
102
+ " ".repeat(depth),
103
+ "}"
104
+ ]
105
+ });
106
+ }
107
+ return /* @__PURE__ */ jsx("span", {
108
+ children: String(data)
109
+ });
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__ */ jsx("div", {
171
+ style: positionStyles,
172
+ children: /* @__PURE__ */ jsxs("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__ */ jsx("span", {
188
+ style: {
189
+ width: 8,
190
+ height: 8,
191
+ borderRadius: "50%",
192
+ backgroundColor: statusColor,
193
+ display: "inline-block"
194
+ }
195
+ }),
196
+ /* @__PURE__ */ jsx("span", {
197
+ children: "Debug"
198
+ }),
199
+ data.rtt !== null && /* @__PURE__ */ jsxs("span", {
200
+ style: { color: "#9ca3af" },
201
+ children: [
202
+ data.rtt,
203
+ "ms"
204
+ ]
205
+ })
206
+ ]
207
+ })
208
+ });
209
+ }
210
+ const latestState = data.stateHistory.length > 0 ? data.stateHistory[data.stateHistory.length - 1]?.state : null;
211
+ return /* @__PURE__ */ jsxs("div", {
212
+ style: panelStyle,
213
+ children: [
214
+ /* @__PURE__ */ jsxs("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__ */ jsxs("div", {
224
+ style: { display: "flex", alignItems: "center", gap: 6 },
225
+ children: [
226
+ /* @__PURE__ */ jsx("span", {
227
+ style: {
228
+ width: 8,
229
+ height: 8,
230
+ borderRadius: "50%",
231
+ backgroundColor: statusColor,
232
+ display: "inline-block"
233
+ }
234
+ }),
235
+ /* @__PURE__ */ jsx("span", {
236
+ style: { fontWeight: 600 },
237
+ children: "Debug"
238
+ }),
239
+ /* @__PURE__ */ jsxs("span", {
240
+ style: { color: "#9ca3af" },
241
+ children: [
242
+ data.connectionStatus,
243
+ data.rtt !== null ? ` · ${data.rtt}ms` : ""
244
+ ]
245
+ })
246
+ ]
247
+ }),
248
+ /* @__PURE__ */ jsxs("div", {
249
+ style: { display: "flex", gap: 4 },
250
+ children: [
251
+ /* @__PURE__ */ jsx("button", {
252
+ onClick: data.clearHistory,
253
+ style: buttonStyle,
254
+ title: "Clear",
255
+ children: "✕"
256
+ }),
257
+ /* @__PURE__ */ jsx("button", {
258
+ onClick: handleToggle,
259
+ style: buttonStyle,
260
+ title: "Collapse",
261
+ children: "▾"
262
+ })
263
+ ]
264
+ })
265
+ ]
266
+ }),
267
+ /* @__PURE__ */ jsxs("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__ */ jsxs("button", {
276
+ onClick: () => setActiveTab("actions"),
277
+ style: tabStyle(activeTab === "actions"),
278
+ children: [
279
+ "Actions (",
280
+ data.actionLog.length,
281
+ ")"
282
+ ]
283
+ }),
284
+ /* @__PURE__ */ jsx("button", {
285
+ onClick: () => setActiveTab("state"),
286
+ style: tabStyle(activeTab === "state"),
287
+ children: "State"
288
+ })
289
+ ]
290
+ }),
291
+ /* @__PURE__ */ jsxs("div", {
292
+ style: {
293
+ maxHeight,
294
+ overflowY: "auto",
295
+ padding: 8
296
+ },
297
+ children: [
298
+ activeTab === "actions" && /* @__PURE__ */ jsx("div", {
299
+ children: data.actionLog.length === 0 ? /* @__PURE__ */ jsx("div", {
300
+ style: {
301
+ color: "#6b7280",
302
+ textAlign: "center",
303
+ padding: 16
304
+ },
305
+ children: "No actions recorded"
306
+ }) : data.actionLog.slice().reverse().map((entry) => /* @__PURE__ */ jsxs("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__ */ jsxs("div", {
316
+ style: {
317
+ display: "flex",
318
+ justifyContent: "space-between",
319
+ alignItems: "center"
320
+ },
321
+ children: [
322
+ /* @__PURE__ */ jsx("span", {
323
+ style: {
324
+ color: entry.source === "local" ? "#60a5fa" : "#4ade80",
325
+ fontSize: 10,
326
+ textTransform: "uppercase"
327
+ },
328
+ children: entry.source
329
+ }),
330
+ /* @__PURE__ */ jsx("span", {
331
+ style: { color: "#6b7280", fontSize: 10 },
332
+ children: formatTimestamp(entry.timestamp)
333
+ })
334
+ ]
335
+ }),
336
+ /* @__PURE__ */ jsx("pre", {
337
+ style: {
338
+ margin: 0,
339
+ fontSize: 10,
340
+ color: "#d1d5db",
341
+ whiteSpace: "pre-wrap",
342
+ wordBreak: "break-all"
343
+ },
344
+ children: /* @__PURE__ */ jsx(JsonTree, {
345
+ data: entry.action
346
+ })
347
+ })
348
+ ]
349
+ }, entry.id))
350
+ }),
351
+ activeTab === "state" && /* @__PURE__ */ jsx("pre", {
352
+ style: {
353
+ margin: 0,
354
+ fontSize: 10,
355
+ whiteSpace: "pre-wrap",
356
+ wordBreak: "break-all"
357
+ },
358
+ children: latestState !== null ? /* @__PURE__ */ jsx(JsonTree, {
359
+ data: latestState
360
+ }) : /* @__PURE__ */ jsx("span", {
361
+ style: { color: "#6b7280" },
362
+ children: "No state captured"
363
+ })
364
+ })
365
+ ]
366
+ })
367
+ ]
368
+ });
369
+ }
1
370
  export {
2
371
  DebugOverlay
3
372
  };
package/lib/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- export { DebugOverlay } from "./DebugOverlay";
2
- export type { DebugOverlayProps } from "./DebugOverlay";
1
+ export * from "./DebugOverlay";
3
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@couch-kit/devtools",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
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",
@@ -13,7 +13,9 @@
13
13
  },
14
14
  "sideEffects": false,
15
15
  "scripts": {
16
- "build": "bun build ./src/index.ts --outdir ./dist --target browser --external react --external @couch-kit/client --external @couch-kit/core && tsc -p tsconfig.build.json",
16
+ "build": "NODE_ENV=production bun build ./src/index.ts --outdir ./dist --target browser --external react --external @couch-kit/client --external @couch-kit/core && tsc -p tsconfig.build.json && bun run verify-build",
17
+ "verify-build": "node -e \"const s=require('fs').readFileSync('./dist/index.js','utf8');if(!s.includes('function DebugOverlay'))throw new Error('dist/index.js is missing DebugOverlay — empty bundle');if(s.includes('jsx-dev-runtime'))throw new Error('dist/index.js uses react/jsx-dev-runtime — build with NODE_ENV=production');\"",
18
+ "prepublishOnly": "bun run build",
17
19
  "test": "bun test",
18
20
  "typecheck": "tsc --noEmit",
19
21
  "clean": "rm -rf dist lib"
@@ -27,8 +29,8 @@
27
29
  ],
28
30
  "dependencies": {},
29
31
  "devDependencies": {
30
- "@couch-kit/client": "0.11.0",
31
- "@couch-kit/core": "0.9.3",
32
+ "@couch-kit/client": "0.15.0",
33
+ "@couch-kit/core": "0.10.0",
32
34
  "@happy-dom/global-registrator": "^20.10.6",
33
35
  "@testing-library/dom": "^10.4.1",
34
36
  "@testing-library/react": "^16.3.2",
package/src/index.ts CHANGED
@@ -1,2 +1,5 @@
1
- export { DebugOverlay } from "./DebugOverlay";
2
- export type { DebugOverlayProps } from "./DebugOverlay";
1
+ // `export *`, not `export { DebugOverlay } from`: with `sideEffects: false`,
2
+ // bun tree-shakes a named re-export of the package's only value out of the
3
+ // bundle, publishing a `dist/index.js` that exports a binding it never defines.
4
+ // The build's `verify-build` step fails if that ever happens again.
5
+ export * from "./DebugOverlay";