fauxbase-devtools 0.4.0
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/dist/index.cjs +447 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +35 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +444 -0
- package/dist/index.js.map +1 -0
- package/package.json +40 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
|
|
6
|
+
// src/devtools.tsx
|
|
7
|
+
|
|
8
|
+
// src/request-logger.ts
|
|
9
|
+
var idCounter = 0;
|
|
10
|
+
function createRequestLogger(maxEntries = 100) {
|
|
11
|
+
const entries = [];
|
|
12
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
13
|
+
function addEntry(entry) {
|
|
14
|
+
entries.unshift(entry);
|
|
15
|
+
if (entries.length > maxEntries) {
|
|
16
|
+
entries.pop();
|
|
17
|
+
}
|
|
18
|
+
listeners.forEach((fn) => fn());
|
|
19
|
+
}
|
|
20
|
+
function getEntries() {
|
|
21
|
+
return entries;
|
|
22
|
+
}
|
|
23
|
+
function clear() {
|
|
24
|
+
entries.length = 0;
|
|
25
|
+
listeners.forEach((fn) => fn());
|
|
26
|
+
}
|
|
27
|
+
function subscribe(fn) {
|
|
28
|
+
listeners.add(fn);
|
|
29
|
+
return () => listeners.delete(fn);
|
|
30
|
+
}
|
|
31
|
+
function wrapService(service, serviceName) {
|
|
32
|
+
return new Proxy(service, {
|
|
33
|
+
get(target, prop, receiver) {
|
|
34
|
+
const value = Reflect.get(target, prop, receiver);
|
|
35
|
+
if (typeof value !== "function") return value;
|
|
36
|
+
if (typeof prop === "string" && prop.startsWith("_")) return value;
|
|
37
|
+
return async function(...args) {
|
|
38
|
+
const entry = {
|
|
39
|
+
id: `log_${++idCounter}`,
|
|
40
|
+
timestamp: Date.now(),
|
|
41
|
+
service: serviceName,
|
|
42
|
+
method: prop,
|
|
43
|
+
args,
|
|
44
|
+
duration: 0
|
|
45
|
+
};
|
|
46
|
+
const start = performance.now();
|
|
47
|
+
try {
|
|
48
|
+
const result = await value.apply(target, args);
|
|
49
|
+
entry.result = result;
|
|
50
|
+
entry.duration = Math.round(performance.now() - start);
|
|
51
|
+
addEntry(entry);
|
|
52
|
+
return result;
|
|
53
|
+
} catch (err) {
|
|
54
|
+
entry.error = err.message ?? String(err);
|
|
55
|
+
entry.duration = Math.round(performance.now() - start);
|
|
56
|
+
addEntry(entry);
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return { addEntry, getEntries, clear, subscribe, wrapService };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/styles.ts
|
|
67
|
+
var STYLES = {
|
|
68
|
+
container: {
|
|
69
|
+
position: "fixed",
|
|
70
|
+
bottom: "16px",
|
|
71
|
+
right: "16px",
|
|
72
|
+
zIndex: 99999,
|
|
73
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace',
|
|
74
|
+
fontSize: "13px",
|
|
75
|
+
color: "#e4e4e7"
|
|
76
|
+
},
|
|
77
|
+
containerLeft: {
|
|
78
|
+
right: "auto",
|
|
79
|
+
left: "16px"
|
|
80
|
+
},
|
|
81
|
+
toggleButton: {
|
|
82
|
+
width: "40px",
|
|
83
|
+
height: "40px",
|
|
84
|
+
borderRadius: "8px",
|
|
85
|
+
border: "1px solid #3f3f46",
|
|
86
|
+
background: "#18181b",
|
|
87
|
+
color: "#a1a1aa",
|
|
88
|
+
cursor: "pointer",
|
|
89
|
+
display: "flex",
|
|
90
|
+
alignItems: "center",
|
|
91
|
+
justifyContent: "center",
|
|
92
|
+
fontSize: "18px",
|
|
93
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.4)"
|
|
94
|
+
},
|
|
95
|
+
panel: {
|
|
96
|
+
width: "480px",
|
|
97
|
+
maxHeight: "400px",
|
|
98
|
+
background: "#18181b",
|
|
99
|
+
border: "1px solid #3f3f46",
|
|
100
|
+
borderRadius: "8px",
|
|
101
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.5)",
|
|
102
|
+
overflow: "hidden",
|
|
103
|
+
display: "flex",
|
|
104
|
+
flexDirection: "column"
|
|
105
|
+
},
|
|
106
|
+
tabBar: {
|
|
107
|
+
display: "flex",
|
|
108
|
+
borderBottom: "1px solid #3f3f46",
|
|
109
|
+
background: "#09090b"
|
|
110
|
+
},
|
|
111
|
+
tab: {
|
|
112
|
+
padding: "8px 16px",
|
|
113
|
+
border: "none",
|
|
114
|
+
background: "transparent",
|
|
115
|
+
color: "#71717a",
|
|
116
|
+
cursor: "pointer",
|
|
117
|
+
fontSize: "12px",
|
|
118
|
+
fontWeight: 500,
|
|
119
|
+
borderBottom: "2px solid transparent"
|
|
120
|
+
},
|
|
121
|
+
tabActive: {
|
|
122
|
+
color: "#e4e4e7",
|
|
123
|
+
borderBottomColor: "#3b82f6"
|
|
124
|
+
},
|
|
125
|
+
panelContent: {
|
|
126
|
+
padding: "12px",
|
|
127
|
+
overflowY: "auto",
|
|
128
|
+
maxHeight: "340px",
|
|
129
|
+
flex: 1
|
|
130
|
+
},
|
|
131
|
+
table: {
|
|
132
|
+
width: "100%",
|
|
133
|
+
borderCollapse: "collapse",
|
|
134
|
+
fontSize: "12px"
|
|
135
|
+
},
|
|
136
|
+
th: {
|
|
137
|
+
textAlign: "left",
|
|
138
|
+
padding: "6px 8px",
|
|
139
|
+
borderBottom: "1px solid #27272a",
|
|
140
|
+
color: "#a1a1aa",
|
|
141
|
+
fontWeight: 600
|
|
142
|
+
},
|
|
143
|
+
td: {
|
|
144
|
+
padding: "6px 8px",
|
|
145
|
+
borderBottom: "1px solid #27272a",
|
|
146
|
+
maxWidth: "160px",
|
|
147
|
+
overflow: "hidden",
|
|
148
|
+
textOverflow: "ellipsis",
|
|
149
|
+
whiteSpace: "nowrap"
|
|
150
|
+
},
|
|
151
|
+
button: {
|
|
152
|
+
padding: "6px 12px",
|
|
153
|
+
borderRadius: "4px",
|
|
154
|
+
border: "1px solid #3f3f46",
|
|
155
|
+
background: "#27272a",
|
|
156
|
+
color: "#e4e4e7",
|
|
157
|
+
cursor: "pointer",
|
|
158
|
+
fontSize: "12px"
|
|
159
|
+
},
|
|
160
|
+
buttonDanger: {
|
|
161
|
+
background: "#7f1d1d",
|
|
162
|
+
borderColor: "#991b1b"
|
|
163
|
+
},
|
|
164
|
+
badge: {
|
|
165
|
+
display: "inline-block",
|
|
166
|
+
padding: "2px 6px",
|
|
167
|
+
borderRadius: "4px",
|
|
168
|
+
fontSize: "11px",
|
|
169
|
+
fontWeight: 600
|
|
170
|
+
},
|
|
171
|
+
badgeSuccess: {
|
|
172
|
+
background: "#14532d",
|
|
173
|
+
color: "#4ade80"
|
|
174
|
+
},
|
|
175
|
+
badgeError: {
|
|
176
|
+
background: "#7f1d1d",
|
|
177
|
+
color: "#f87171"
|
|
178
|
+
},
|
|
179
|
+
emptyState: {
|
|
180
|
+
color: "#71717a",
|
|
181
|
+
textAlign: "center",
|
|
182
|
+
padding: "24px",
|
|
183
|
+
fontSize: "12px"
|
|
184
|
+
},
|
|
185
|
+
label: {
|
|
186
|
+
color: "#a1a1aa",
|
|
187
|
+
fontSize: "11px",
|
|
188
|
+
marginBottom: "4px"
|
|
189
|
+
},
|
|
190
|
+
value: {
|
|
191
|
+
color: "#e4e4e7",
|
|
192
|
+
fontSize: "13px",
|
|
193
|
+
marginBottom: "12px",
|
|
194
|
+
wordBreak: "break-all"
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
function DataInspector({ client }) {
|
|
198
|
+
const [selected, setSelected] = react.useState(null);
|
|
199
|
+
const [records, setRecords] = react.useState([]);
|
|
200
|
+
const serviceNames = Object.keys(client).filter(
|
|
201
|
+
(k) => k !== "auth" && client[k] && typeof client[k].list === "function"
|
|
202
|
+
);
|
|
203
|
+
react.useEffect(() => {
|
|
204
|
+
if (!selected && serviceNames.length > 0) {
|
|
205
|
+
setSelected(serviceNames[0]);
|
|
206
|
+
}
|
|
207
|
+
}, [serviceNames.length]);
|
|
208
|
+
react.useEffect(() => {
|
|
209
|
+
if (!selected) return;
|
|
210
|
+
const service = client[selected];
|
|
211
|
+
if (!service) return;
|
|
212
|
+
service.list({ size: 50 }).then((res) => setRecords(res.items ?? [])).catch(() => setRecords([]));
|
|
213
|
+
}, [selected]);
|
|
214
|
+
if (serviceNames.length === 0) {
|
|
215
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: STYLES.emptyState, children: "No services registered" });
|
|
216
|
+
}
|
|
217
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
218
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: "4px", marginBottom: "8px", flexWrap: "wrap" }, children: serviceNames.map((name) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
219
|
+
"button",
|
|
220
|
+
{
|
|
221
|
+
onClick: () => setSelected(name),
|
|
222
|
+
style: {
|
|
223
|
+
...STYLES.button,
|
|
224
|
+
...selected === name ? { background: "#3b82f6", borderColor: "#3b82f6" } : {}
|
|
225
|
+
},
|
|
226
|
+
children: name
|
|
227
|
+
},
|
|
228
|
+
name
|
|
229
|
+
)) }),
|
|
230
|
+
records.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: STYLES.emptyState, children: [
|
|
231
|
+
"No records in ",
|
|
232
|
+
selected
|
|
233
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("table", { style: STYLES.table, children: [
|
|
234
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
235
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { style: STYLES.th, children: "id" }),
|
|
236
|
+
Object.keys(records[0]).filter((k) => k !== "id" && !k.endsWith("At") && !k.endsWith("Id") && !k.endsWith("Name") && k !== "version" && k !== "password").slice(0, 3).map((k) => /* @__PURE__ */ jsxRuntime.jsx("th", { style: STYLES.th, children: k }, k))
|
|
237
|
+
] }) }),
|
|
238
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: records.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
239
|
+
/* @__PURE__ */ jsxRuntime.jsxs("td", { style: STYLES.td, children: [
|
|
240
|
+
r.id?.substring(0, 12),
|
|
241
|
+
"..."
|
|
242
|
+
] }),
|
|
243
|
+
Object.keys(records[0]).filter((k) => k !== "id" && !k.endsWith("At") && !k.endsWith("Id") && !k.endsWith("Name") && k !== "version" && k !== "password").slice(0, 3).map((k) => /* @__PURE__ */ jsxRuntime.jsx("td", { style: STYLES.td, children: String(r[k] ?? "") }, k))
|
|
244
|
+
] }, r.id)) })
|
|
245
|
+
] })
|
|
246
|
+
] });
|
|
247
|
+
}
|
|
248
|
+
function AuthInspector({ client }) {
|
|
249
|
+
const auth = client.auth;
|
|
250
|
+
if (!auth) {
|
|
251
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: STYLES.emptyState, children: "Auth not configured" });
|
|
252
|
+
}
|
|
253
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
254
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: STYLES.label, children: "Status" }),
|
|
255
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...STYLES.value, display: "flex", alignItems: "center", gap: "8px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
256
|
+
"span",
|
|
257
|
+
{
|
|
258
|
+
style: {
|
|
259
|
+
...STYLES.badge,
|
|
260
|
+
...auth.isLoggedIn ? STYLES.badgeSuccess : STYLES.badgeError
|
|
261
|
+
},
|
|
262
|
+
children: auth.isLoggedIn ? "Logged In" : "Logged Out"
|
|
263
|
+
}
|
|
264
|
+
) }),
|
|
265
|
+
auth.isLoggedIn && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
266
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: STYLES.label, children: "User" }),
|
|
267
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: STYLES.value, children: auth.currentUser?.email ?? auth.currentUser?.id ?? "Unknown" }),
|
|
268
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: STYLES.label, children: "Token" }),
|
|
269
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...STYLES.value, fontSize: "11px", fontFamily: "monospace" }, children: [
|
|
270
|
+
auth.token?.substring(0, 40),
|
|
271
|
+
"..."
|
|
272
|
+
] }),
|
|
273
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
274
|
+
"button",
|
|
275
|
+
{
|
|
276
|
+
style: { ...STYLES.button, ...STYLES.buttonDanger },
|
|
277
|
+
onClick: () => {
|
|
278
|
+
auth.logout();
|
|
279
|
+
window.dispatchEvent(new Event("fauxbase:auth-change"));
|
|
280
|
+
},
|
|
281
|
+
children: "Logout"
|
|
282
|
+
}
|
|
283
|
+
)
|
|
284
|
+
] })
|
|
285
|
+
] });
|
|
286
|
+
}
|
|
287
|
+
function RequestLog({ entries, onClear }) {
|
|
288
|
+
if (entries.length === 0) {
|
|
289
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: STYLES.emptyState, children: "No requests logged yet" });
|
|
290
|
+
}
|
|
291
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
292
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "8px" }, children: [
|
|
293
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: STYLES.label, children: [
|
|
294
|
+
entries.length,
|
|
295
|
+
" requests"
|
|
296
|
+
] }),
|
|
297
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { style: STYLES.button, onClick: onClear, children: "Clear" })
|
|
298
|
+
] }),
|
|
299
|
+
/* @__PURE__ */ jsxRuntime.jsxs("table", { style: STYLES.table, children: [
|
|
300
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
301
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { style: STYLES.th, children: "Service" }),
|
|
302
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { style: STYLES.th, children: "Method" }),
|
|
303
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { style: STYLES.th, children: "Status" }),
|
|
304
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { style: STYLES.th, children: "Time" })
|
|
305
|
+
] }) }),
|
|
306
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: entries.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
307
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { style: STYLES.td, children: entry.service }),
|
|
308
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { style: STYLES.td, children: entry.method }),
|
|
309
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { style: STYLES.td, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
310
|
+
"span",
|
|
311
|
+
{
|
|
312
|
+
style: {
|
|
313
|
+
...STYLES.badge,
|
|
314
|
+
...entry.error ? STYLES.badgeError : STYLES.badgeSuccess
|
|
315
|
+
},
|
|
316
|
+
children: entry.error ? "ERR" : "OK"
|
|
317
|
+
}
|
|
318
|
+
) }),
|
|
319
|
+
/* @__PURE__ */ jsxRuntime.jsxs("td", { style: STYLES.td, children: [
|
|
320
|
+
entry.duration,
|
|
321
|
+
"ms"
|
|
322
|
+
] })
|
|
323
|
+
] }, entry.id)) })
|
|
324
|
+
] })
|
|
325
|
+
] });
|
|
326
|
+
}
|
|
327
|
+
function SeedManager({ client }) {
|
|
328
|
+
const [resetting, setResetting] = react.useState(false);
|
|
329
|
+
const serviceNames = Object.keys(client).filter(
|
|
330
|
+
(k) => k !== "auth" && client[k] && typeof client[k].list === "function"
|
|
331
|
+
);
|
|
332
|
+
const handleReset = async (name) => {
|
|
333
|
+
setResetting(true);
|
|
334
|
+
try {
|
|
335
|
+
const service = client[name];
|
|
336
|
+
if (service?.driver?.clear) {
|
|
337
|
+
service.driver.clear(name);
|
|
338
|
+
}
|
|
339
|
+
} finally {
|
|
340
|
+
setResetting(false);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
if (serviceNames.length === 0) {
|
|
344
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: STYLES.emptyState, children: "No services registered" });
|
|
345
|
+
}
|
|
346
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
347
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...STYLES.label, marginBottom: "12px" }, children: "Reset seed data for individual resources (LocalDriver only)" }),
|
|
348
|
+
serviceNames.map((name) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "8px" }, children: [
|
|
349
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: name }),
|
|
350
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
351
|
+
"button",
|
|
352
|
+
{
|
|
353
|
+
style: { ...STYLES.button, ...STYLES.buttonDanger },
|
|
354
|
+
onClick: () => handleReset(name),
|
|
355
|
+
disabled: resetting,
|
|
356
|
+
children: "Reset"
|
|
357
|
+
}
|
|
358
|
+
)
|
|
359
|
+
] }, name))
|
|
360
|
+
] });
|
|
361
|
+
}
|
|
362
|
+
var TABS = [
|
|
363
|
+
{ key: "data", label: "Data" },
|
|
364
|
+
{ key: "auth", label: "Auth" },
|
|
365
|
+
{ key: "requests", label: "Requests" },
|
|
366
|
+
{ key: "seeds", label: "Seeds" }
|
|
367
|
+
];
|
|
368
|
+
function FauxbaseDevtools({ client, config = {} }) {
|
|
369
|
+
const [open, setOpen] = react.useState(config.defaultOpen ?? false);
|
|
370
|
+
const [activeTab, setActiveTab] = react.useState("data");
|
|
371
|
+
const [logger] = react.useState(() => createRequestLogger(config.maxLogEntries ?? 100));
|
|
372
|
+
const [, setTick] = react.useState(0);
|
|
373
|
+
react.useEffect(() => {
|
|
374
|
+
return logger.subscribe(() => setTick((t) => t + 1));
|
|
375
|
+
}, [logger]);
|
|
376
|
+
const [wrappedClient] = react.useState(() => {
|
|
377
|
+
const wrapped = { ...client };
|
|
378
|
+
for (const [name, service] of Object.entries(client)) {
|
|
379
|
+
if (name !== "auth" && service && typeof service.list === "function") {
|
|
380
|
+
wrapped[name] = logger.wrapService(service, name);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return wrapped;
|
|
384
|
+
});
|
|
385
|
+
const position = config.position ?? "bottom-right";
|
|
386
|
+
const isLeft = position === "bottom-left";
|
|
387
|
+
const containerStyle = {
|
|
388
|
+
...STYLES.container,
|
|
389
|
+
...isLeft ? STYLES.containerLeft : {}
|
|
390
|
+
};
|
|
391
|
+
if (!open) {
|
|
392
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: containerStyle, "data-testid": "fauxbase-devtools", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
393
|
+
"button",
|
|
394
|
+
{
|
|
395
|
+
style: STYLES.toggleButton,
|
|
396
|
+
onClick: () => setOpen(true),
|
|
397
|
+
"aria-label": "Open Fauxbase DevTools",
|
|
398
|
+
"data-testid": "devtools-toggle",
|
|
399
|
+
children: "{ }"
|
|
400
|
+
}
|
|
401
|
+
) });
|
|
402
|
+
}
|
|
403
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: containerStyle, "data-testid": "fauxbase-devtools", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: STYLES.panel, children: [
|
|
404
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: STYLES.tabBar, children: [
|
|
405
|
+
TABS.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
406
|
+
"button",
|
|
407
|
+
{
|
|
408
|
+
style: {
|
|
409
|
+
...STYLES.tab,
|
|
410
|
+
...activeTab === tab.key ? STYLES.tabActive : {}
|
|
411
|
+
},
|
|
412
|
+
onClick: () => setActiveTab(tab.key),
|
|
413
|
+
"data-testid": `tab-${tab.key}`,
|
|
414
|
+
children: tab.label
|
|
415
|
+
},
|
|
416
|
+
tab.key
|
|
417
|
+
)),
|
|
418
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
419
|
+
"button",
|
|
420
|
+
{
|
|
421
|
+
style: { ...STYLES.tab, marginLeft: "auto" },
|
|
422
|
+
onClick: () => setOpen(false),
|
|
423
|
+
"aria-label": "Close DevTools",
|
|
424
|
+
"data-testid": "devtools-close",
|
|
425
|
+
children: "x"
|
|
426
|
+
}
|
|
427
|
+
)
|
|
428
|
+
] }),
|
|
429
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: STYLES.panelContent, children: [
|
|
430
|
+
activeTab === "data" && /* @__PURE__ */ jsxRuntime.jsx(DataInspector, { client: wrappedClient }),
|
|
431
|
+
activeTab === "auth" && /* @__PURE__ */ jsxRuntime.jsx(AuthInspector, { client }),
|
|
432
|
+
activeTab === "requests" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
433
|
+
RequestLog,
|
|
434
|
+
{
|
|
435
|
+
entries: logger.getEntries(),
|
|
436
|
+
onClear: () => logger.clear()
|
|
437
|
+
}
|
|
438
|
+
),
|
|
439
|
+
activeTab === "seeds" && /* @__PURE__ */ jsxRuntime.jsx(SeedManager, { client })
|
|
440
|
+
] })
|
|
441
|
+
] }) });
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
exports.FauxbaseDevtools = FauxbaseDevtools;
|
|
445
|
+
exports.createRequestLogger = createRequestLogger;
|
|
446
|
+
//# sourceMappingURL=index.cjs.map
|
|
447
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/request-logger.ts","../src/styles.ts","../src/panels/data-inspector.tsx","../src/panels/auth-inspector.tsx","../src/panels/request-log.tsx","../src/panels/seed-manager.tsx","../src/devtools.tsx"],"names":["useState","useEffect","jsx","jsxs","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { RequestLogEntry } from './types';\n\nlet idCounter = 0;\n\nexport function createRequestLogger(maxEntries = 100) {\n const entries: RequestLogEntry[] = [];\n const listeners = new Set<() => void>();\n\n function addEntry(entry: RequestLogEntry): void {\n entries.unshift(entry);\n if (entries.length > maxEntries) {\n entries.pop();\n }\n listeners.forEach(fn => fn());\n }\n\n function getEntries(): RequestLogEntry[] {\n return entries;\n }\n\n function clear(): void {\n entries.length = 0;\n listeners.forEach(fn => fn());\n }\n\n function subscribe(fn: () => void): () => void {\n listeners.add(fn);\n return () => listeners.delete(fn);\n }\n\n /**\n * Wraps a service instance with a Proxy that logs all method calls.\n * Zero changes to the Service class.\n */\n function wrapService<T extends object>(service: T, serviceName: string): T {\n return new Proxy(service, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n if (typeof value !== 'function') return value;\n\n // Skip internal methods\n if (typeof prop === 'string' && prop.startsWith('_')) return value;\n\n return async function (this: any, ...args: any[]) {\n const entry: RequestLogEntry = {\n id: `log_${++idCounter}`,\n timestamp: Date.now(),\n service: serviceName,\n method: prop as string,\n args,\n duration: 0,\n };\n\n const start = performance.now();\n try {\n const result = await value.apply(target, args);\n entry.result = result;\n entry.duration = Math.round(performance.now() - start);\n addEntry(entry);\n return result;\n } catch (err: any) {\n entry.error = err.message ?? String(err);\n entry.duration = Math.round(performance.now() - start);\n addEntry(entry);\n throw err;\n }\n };\n },\n });\n }\n\n return { addEntry, getEntries, clear, subscribe, wrapService };\n}\n\nexport type RequestLogger = ReturnType<typeof createRequestLogger>;\n","export const STYLES = {\n container: {\n position: 'fixed' as const,\n bottom: '16px',\n right: '16px',\n zIndex: 99999,\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, monospace',\n fontSize: '13px',\n color: '#e4e4e7',\n },\n containerLeft: {\n right: 'auto',\n left: '16px',\n },\n toggleButton: {\n width: '40px',\n height: '40px',\n borderRadius: '8px',\n border: '1px solid #3f3f46',\n background: '#18181b',\n color: '#a1a1aa',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '18px',\n boxShadow: '0 4px 12px rgba(0,0,0,0.4)',\n },\n panel: {\n width: '480px',\n maxHeight: '400px',\n background: '#18181b',\n border: '1px solid #3f3f46',\n borderRadius: '8px',\n boxShadow: '0 8px 24px rgba(0,0,0,0.5)',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column' as const,\n },\n tabBar: {\n display: 'flex',\n borderBottom: '1px solid #3f3f46',\n background: '#09090b',\n },\n tab: {\n padding: '8px 16px',\n border: 'none',\n background: 'transparent',\n color: '#71717a',\n cursor: 'pointer',\n fontSize: '12px',\n fontWeight: 500,\n borderBottom: '2px solid transparent',\n },\n tabActive: {\n color: '#e4e4e7',\n borderBottomColor: '#3b82f6',\n },\n panelContent: {\n padding: '12px',\n overflowY: 'auto' as const,\n maxHeight: '340px',\n flex: 1,\n },\n table: {\n width: '100%',\n borderCollapse: 'collapse' as const,\n fontSize: '12px',\n },\n th: {\n textAlign: 'left' as const,\n padding: '6px 8px',\n borderBottom: '1px solid #27272a',\n color: '#a1a1aa',\n fontWeight: 600,\n },\n td: {\n padding: '6px 8px',\n borderBottom: '1px solid #27272a',\n maxWidth: '160px',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap' as const,\n },\n button: {\n padding: '6px 12px',\n borderRadius: '4px',\n border: '1px solid #3f3f46',\n background: '#27272a',\n color: '#e4e4e7',\n cursor: 'pointer',\n fontSize: '12px',\n },\n buttonDanger: {\n background: '#7f1d1d',\n borderColor: '#991b1b',\n },\n badge: {\n display: 'inline-block',\n padding: '2px 6px',\n borderRadius: '4px',\n fontSize: '11px',\n fontWeight: 600,\n },\n badgeSuccess: {\n background: '#14532d',\n color: '#4ade80',\n },\n badgeError: {\n background: '#7f1d1d',\n color: '#f87171',\n },\n emptyState: {\n color: '#71717a',\n textAlign: 'center' as const,\n padding: '24px',\n fontSize: '12px',\n },\n label: {\n color: '#a1a1aa',\n fontSize: '11px',\n marginBottom: '4px',\n },\n value: {\n color: '#e4e4e7',\n fontSize: '13px',\n marginBottom: '12px',\n wordBreak: 'break-all' as const,\n },\n};\n","import React, { useEffect, useState } from 'react';\nimport { STYLES } from '../styles';\n\ninterface DataInspectorProps {\n client: any;\n}\n\nexport function DataInspector({ client }: DataInspectorProps) {\n const [selected, setSelected] = useState<string | null>(null);\n const [records, setRecords] = useState<any[]>([]);\n\n const serviceNames = Object.keys(client).filter(\n k => k !== 'auth' && client[k] && typeof client[k].list === 'function',\n );\n\n useEffect(() => {\n if (!selected && serviceNames.length > 0) {\n setSelected(serviceNames[0]);\n }\n }, [serviceNames.length]);\n\n useEffect(() => {\n if (!selected) return;\n const service = client[selected];\n if (!service) return;\n service.list({ size: 50 }).then((res: any) => setRecords(res.items ?? [])).catch(() => setRecords([]));\n }, [selected]);\n\n if (serviceNames.length === 0) {\n return <div style={STYLES.emptyState}>No services registered</div>;\n }\n\n return (\n <div>\n <div style={{ display: 'flex', gap: '4px', marginBottom: '8px', flexWrap: 'wrap' }}>\n {serviceNames.map(name => (\n <button\n key={name}\n onClick={() => setSelected(name)}\n style={{\n ...STYLES.button,\n ...(selected === name ? { background: '#3b82f6', borderColor: '#3b82f6' } : {}),\n }}\n >\n {name}\n </button>\n ))}\n </div>\n\n {records.length === 0 ? (\n <div style={STYLES.emptyState}>No records in {selected}</div>\n ) : (\n <table style={STYLES.table}>\n <thead>\n <tr>\n <th style={STYLES.th}>id</th>\n {Object.keys(records[0])\n .filter(k => k !== 'id' && !k.endsWith('At') && !k.endsWith('Id') && !k.endsWith('Name') && k !== 'version' && k !== 'password')\n .slice(0, 3)\n .map(k => (\n <th key={k} style={STYLES.th}>{k}</th>\n ))}\n </tr>\n </thead>\n <tbody>\n {records.map((r: any) => (\n <tr key={r.id}>\n <td style={STYLES.td}>{r.id?.substring(0, 12)}...</td>\n {Object.keys(records[0])\n .filter(k => k !== 'id' && !k.endsWith('At') && !k.endsWith('Id') && !k.endsWith('Name') && k !== 'version' && k !== 'password')\n .slice(0, 3)\n .map(k => (\n <td key={k} style={STYLES.td}>{String(r[k] ?? '')}</td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </div>\n );\n}\n","import React from 'react';\nimport { STYLES } from '../styles';\n\ninterface AuthInspectorProps {\n client: any;\n}\n\nexport function AuthInspector({ client }: AuthInspectorProps) {\n const auth = client.auth;\n\n if (!auth) {\n return <div style={STYLES.emptyState}>Auth not configured</div>;\n }\n\n return (\n <div>\n <div style={STYLES.label}>Status</div>\n <div style={{ ...STYLES.value, display: 'flex', alignItems: 'center', gap: '8px' }}>\n <span\n style={{\n ...STYLES.badge,\n ...(auth.isLoggedIn ? STYLES.badgeSuccess : STYLES.badgeError),\n }}\n >\n {auth.isLoggedIn ? 'Logged In' : 'Logged Out'}\n </span>\n </div>\n\n {auth.isLoggedIn && (\n <>\n <div style={STYLES.label}>User</div>\n <div style={STYLES.value}>\n {auth.currentUser?.email ?? auth.currentUser?.id ?? 'Unknown'}\n </div>\n\n <div style={STYLES.label}>Token</div>\n <div style={{ ...STYLES.value, fontSize: '11px', fontFamily: 'monospace' }}>\n {auth.token?.substring(0, 40)}...\n </div>\n\n <button\n style={{ ...STYLES.button, ...STYLES.buttonDanger }}\n onClick={() => {\n auth.logout();\n // Force re-render\n window.dispatchEvent(new Event('fauxbase:auth-change'));\n }}\n >\n Logout\n </button>\n </>\n )}\n </div>\n );\n}\n","import React from 'react';\nimport type { RequestLogEntry } from '../types';\nimport { STYLES } from '../styles';\n\ninterface RequestLogProps {\n entries: RequestLogEntry[];\n onClear: () => void;\n}\n\nexport function RequestLog({ entries, onClear }: RequestLogProps) {\n if (entries.length === 0) {\n return <div style={STYLES.emptyState}>No requests logged yet</div>;\n }\n\n return (\n <div>\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '8px' }}>\n <span style={STYLES.label}>{entries.length} requests</span>\n <button style={STYLES.button} onClick={onClear}>Clear</button>\n </div>\n <table style={STYLES.table}>\n <thead>\n <tr>\n <th style={STYLES.th}>Service</th>\n <th style={STYLES.th}>Method</th>\n <th style={STYLES.th}>Status</th>\n <th style={STYLES.th}>Time</th>\n </tr>\n </thead>\n <tbody>\n {entries.map(entry => (\n <tr key={entry.id}>\n <td style={STYLES.td}>{entry.service}</td>\n <td style={STYLES.td}>{entry.method}</td>\n <td style={STYLES.td}>\n <span\n style={{\n ...STYLES.badge,\n ...(entry.error ? STYLES.badgeError : STYLES.badgeSuccess),\n }}\n >\n {entry.error ? 'ERR' : 'OK'}\n </span>\n </td>\n <td style={STYLES.td}>{entry.duration}ms</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n","import React, { useState } from 'react';\nimport { STYLES } from '../styles';\n\ninterface SeedManagerProps {\n client: any;\n}\n\nexport function SeedManager({ client }: SeedManagerProps) {\n const [resetting, setResetting] = useState(false);\n\n const serviceNames = Object.keys(client).filter(\n k => k !== 'auth' && client[k] && typeof client[k].list === 'function',\n );\n\n const handleReset = async (name: string) => {\n setResetting(true);\n try {\n // Check if the driver has a clear method (LocalDriver only)\n const service = client[name];\n if (service?.driver?.clear) {\n service.driver.clear(name);\n }\n } finally {\n setResetting(false);\n }\n };\n\n if (serviceNames.length === 0) {\n return <div style={STYLES.emptyState}>No services registered</div>;\n }\n\n return (\n <div>\n <div style={{ ...STYLES.label, marginBottom: '12px' }}>\n Reset seed data for individual resources (LocalDriver only)\n </div>\n {serviceNames.map(name => (\n <div key={name} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>\n <span>{name}</span>\n <button\n style={{ ...STYLES.button, ...STYLES.buttonDanger }}\n onClick={() => handleReset(name)}\n disabled={resetting}\n >\n Reset\n </button>\n </div>\n ))}\n </div>\n );\n}\n","import React, { useState, useEffect, useCallback } from 'react';\nimport type { PanelTab, DevtoolsConfig } from './types';\nimport { createRequestLogger, type RequestLogger } from './request-logger';\nimport { DataInspector } from './panels/data-inspector';\nimport { AuthInspector } from './panels/auth-inspector';\nimport { RequestLog } from './panels/request-log';\nimport { SeedManager } from './panels/seed-manager';\nimport { STYLES } from './styles';\n\ninterface FauxbaseDevtoolsProps {\n client: any;\n config?: DevtoolsConfig;\n}\n\nconst TABS: { key: PanelTab; label: string }[] = [\n { key: 'data', label: 'Data' },\n { key: 'auth', label: 'Auth' },\n { key: 'requests', label: 'Requests' },\n { key: 'seeds', label: 'Seeds' },\n];\n\nexport function FauxbaseDevtools({ client, config = {} }: FauxbaseDevtoolsProps) {\n const [open, setOpen] = useState(config.defaultOpen ?? false);\n const [activeTab, setActiveTab] = useState<PanelTab>('data');\n const [logger] = useState<RequestLogger>(() => createRequestLogger(config.maxLogEntries ?? 100));\n const [, setTick] = useState(0);\n\n // Subscribe to logger updates for re-render\n useEffect(() => {\n return logger.subscribe(() => setTick(t => t + 1));\n }, [logger]);\n\n // Wrap services with proxy logger\n const [wrappedClient] = useState(() => {\n const wrapped = { ...client };\n for (const [name, service] of Object.entries(client)) {\n if (name !== 'auth' && service && typeof (service as any).list === 'function') {\n wrapped[name] = logger.wrapService(service as object, name);\n }\n }\n return wrapped;\n });\n\n const position = config.position ?? 'bottom-right';\n const isLeft = position === 'bottom-left';\n\n const containerStyle = {\n ...STYLES.container,\n ...(isLeft ? STYLES.containerLeft : {}),\n };\n\n if (!open) {\n return (\n <div style={containerStyle} data-testid=\"fauxbase-devtools\">\n <button\n style={STYLES.toggleButton}\n onClick={() => setOpen(true)}\n aria-label=\"Open Fauxbase DevTools\"\n data-testid=\"devtools-toggle\"\n >\n {'{ }'}\n </button>\n </div>\n );\n }\n\n return (\n <div style={containerStyle} data-testid=\"fauxbase-devtools\">\n <div style={STYLES.panel}>\n <div style={STYLES.tabBar}>\n {TABS.map(tab => (\n <button\n key={tab.key}\n style={{\n ...STYLES.tab,\n ...(activeTab === tab.key ? STYLES.tabActive : {}),\n }}\n onClick={() => setActiveTab(tab.key)}\n data-testid={`tab-${tab.key}`}\n >\n {tab.label}\n </button>\n ))}\n <button\n style={{ ...STYLES.tab, marginLeft: 'auto' }}\n onClick={() => setOpen(false)}\n aria-label=\"Close DevTools\"\n data-testid=\"devtools-close\"\n >\n x\n </button>\n </div>\n <div style={STYLES.panelContent}>\n {activeTab === 'data' && <DataInspector client={wrappedClient} />}\n {activeTab === 'auth' && <AuthInspector client={client} />}\n {activeTab === 'requests' && (\n <RequestLog\n entries={logger.getEntries()}\n onClear={() => logger.clear()}\n />\n )}\n {activeTab === 'seeds' && <SeedManager client={client} />}\n </div>\n </div>\n </div>\n );\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface RequestLogEntry {
|
|
4
|
+
id: string;
|
|
5
|
+
timestamp: number;
|
|
6
|
+
service: string;
|
|
7
|
+
method: string;
|
|
8
|
+
args: any[];
|
|
9
|
+
result?: any;
|
|
10
|
+
error?: string;
|
|
11
|
+
duration: number;
|
|
12
|
+
}
|
|
13
|
+
type PanelTab = 'data' | 'auth' | 'requests' | 'seeds';
|
|
14
|
+
interface DevtoolsConfig {
|
|
15
|
+
position?: 'bottom-right' | 'bottom-left';
|
|
16
|
+
defaultOpen?: boolean;
|
|
17
|
+
maxLogEntries?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface FauxbaseDevtoolsProps {
|
|
21
|
+
client: any;
|
|
22
|
+
config?: DevtoolsConfig;
|
|
23
|
+
}
|
|
24
|
+
declare function FauxbaseDevtools({ client, config }: FauxbaseDevtoolsProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
|
|
26
|
+
declare function createRequestLogger(maxEntries?: number): {
|
|
27
|
+
addEntry: (entry: RequestLogEntry) => void;
|
|
28
|
+
getEntries: () => RequestLogEntry[];
|
|
29
|
+
clear: () => void;
|
|
30
|
+
subscribe: (fn: () => void) => () => void;
|
|
31
|
+
wrapService: <T extends object>(service: T, serviceName: string) => T;
|
|
32
|
+
};
|
|
33
|
+
type RequestLogger = ReturnType<typeof createRequestLogger>;
|
|
34
|
+
|
|
35
|
+
export { type DevtoolsConfig, FauxbaseDevtools, type PanelTab, type RequestLogEntry, type RequestLogger, createRequestLogger };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface RequestLogEntry {
|
|
4
|
+
id: string;
|
|
5
|
+
timestamp: number;
|
|
6
|
+
service: string;
|
|
7
|
+
method: string;
|
|
8
|
+
args: any[];
|
|
9
|
+
result?: any;
|
|
10
|
+
error?: string;
|
|
11
|
+
duration: number;
|
|
12
|
+
}
|
|
13
|
+
type PanelTab = 'data' | 'auth' | 'requests' | 'seeds';
|
|
14
|
+
interface DevtoolsConfig {
|
|
15
|
+
position?: 'bottom-right' | 'bottom-left';
|
|
16
|
+
defaultOpen?: boolean;
|
|
17
|
+
maxLogEntries?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface FauxbaseDevtoolsProps {
|
|
21
|
+
client: any;
|
|
22
|
+
config?: DevtoolsConfig;
|
|
23
|
+
}
|
|
24
|
+
declare function FauxbaseDevtools({ client, config }: FauxbaseDevtoolsProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
|
|
26
|
+
declare function createRequestLogger(maxEntries?: number): {
|
|
27
|
+
addEntry: (entry: RequestLogEntry) => void;
|
|
28
|
+
getEntries: () => RequestLogEntry[];
|
|
29
|
+
clear: () => void;
|
|
30
|
+
subscribe: (fn: () => void) => () => void;
|
|
31
|
+
wrapService: <T extends object>(service: T, serviceName: string) => T;
|
|
32
|
+
};
|
|
33
|
+
type RequestLogger = ReturnType<typeof createRequestLogger>;
|
|
34
|
+
|
|
35
|
+
export { type DevtoolsConfig, FauxbaseDevtools, type PanelTab, type RequestLogEntry, type RequestLogger, createRequestLogger };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
// src/devtools.tsx
|
|
5
|
+
|
|
6
|
+
// src/request-logger.ts
|
|
7
|
+
var idCounter = 0;
|
|
8
|
+
function createRequestLogger(maxEntries = 100) {
|
|
9
|
+
const entries = [];
|
|
10
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
11
|
+
function addEntry(entry) {
|
|
12
|
+
entries.unshift(entry);
|
|
13
|
+
if (entries.length > maxEntries) {
|
|
14
|
+
entries.pop();
|
|
15
|
+
}
|
|
16
|
+
listeners.forEach((fn) => fn());
|
|
17
|
+
}
|
|
18
|
+
function getEntries() {
|
|
19
|
+
return entries;
|
|
20
|
+
}
|
|
21
|
+
function clear() {
|
|
22
|
+
entries.length = 0;
|
|
23
|
+
listeners.forEach((fn) => fn());
|
|
24
|
+
}
|
|
25
|
+
function subscribe(fn) {
|
|
26
|
+
listeners.add(fn);
|
|
27
|
+
return () => listeners.delete(fn);
|
|
28
|
+
}
|
|
29
|
+
function wrapService(service, serviceName) {
|
|
30
|
+
return new Proxy(service, {
|
|
31
|
+
get(target, prop, receiver) {
|
|
32
|
+
const value = Reflect.get(target, prop, receiver);
|
|
33
|
+
if (typeof value !== "function") return value;
|
|
34
|
+
if (typeof prop === "string" && prop.startsWith("_")) return value;
|
|
35
|
+
return async function(...args) {
|
|
36
|
+
const entry = {
|
|
37
|
+
id: `log_${++idCounter}`,
|
|
38
|
+
timestamp: Date.now(),
|
|
39
|
+
service: serviceName,
|
|
40
|
+
method: prop,
|
|
41
|
+
args,
|
|
42
|
+
duration: 0
|
|
43
|
+
};
|
|
44
|
+
const start = performance.now();
|
|
45
|
+
try {
|
|
46
|
+
const result = await value.apply(target, args);
|
|
47
|
+
entry.result = result;
|
|
48
|
+
entry.duration = Math.round(performance.now() - start);
|
|
49
|
+
addEntry(entry);
|
|
50
|
+
return result;
|
|
51
|
+
} catch (err) {
|
|
52
|
+
entry.error = err.message ?? String(err);
|
|
53
|
+
entry.duration = Math.round(performance.now() - start);
|
|
54
|
+
addEntry(entry);
|
|
55
|
+
throw err;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return { addEntry, getEntries, clear, subscribe, wrapService };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/styles.ts
|
|
65
|
+
var STYLES = {
|
|
66
|
+
container: {
|
|
67
|
+
position: "fixed",
|
|
68
|
+
bottom: "16px",
|
|
69
|
+
right: "16px",
|
|
70
|
+
zIndex: 99999,
|
|
71
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace',
|
|
72
|
+
fontSize: "13px",
|
|
73
|
+
color: "#e4e4e7"
|
|
74
|
+
},
|
|
75
|
+
containerLeft: {
|
|
76
|
+
right: "auto",
|
|
77
|
+
left: "16px"
|
|
78
|
+
},
|
|
79
|
+
toggleButton: {
|
|
80
|
+
width: "40px",
|
|
81
|
+
height: "40px",
|
|
82
|
+
borderRadius: "8px",
|
|
83
|
+
border: "1px solid #3f3f46",
|
|
84
|
+
background: "#18181b",
|
|
85
|
+
color: "#a1a1aa",
|
|
86
|
+
cursor: "pointer",
|
|
87
|
+
display: "flex",
|
|
88
|
+
alignItems: "center",
|
|
89
|
+
justifyContent: "center",
|
|
90
|
+
fontSize: "18px",
|
|
91
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.4)"
|
|
92
|
+
},
|
|
93
|
+
panel: {
|
|
94
|
+
width: "480px",
|
|
95
|
+
maxHeight: "400px",
|
|
96
|
+
background: "#18181b",
|
|
97
|
+
border: "1px solid #3f3f46",
|
|
98
|
+
borderRadius: "8px",
|
|
99
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.5)",
|
|
100
|
+
overflow: "hidden",
|
|
101
|
+
display: "flex",
|
|
102
|
+
flexDirection: "column"
|
|
103
|
+
},
|
|
104
|
+
tabBar: {
|
|
105
|
+
display: "flex",
|
|
106
|
+
borderBottom: "1px solid #3f3f46",
|
|
107
|
+
background: "#09090b"
|
|
108
|
+
},
|
|
109
|
+
tab: {
|
|
110
|
+
padding: "8px 16px",
|
|
111
|
+
border: "none",
|
|
112
|
+
background: "transparent",
|
|
113
|
+
color: "#71717a",
|
|
114
|
+
cursor: "pointer",
|
|
115
|
+
fontSize: "12px",
|
|
116
|
+
fontWeight: 500,
|
|
117
|
+
borderBottom: "2px solid transparent"
|
|
118
|
+
},
|
|
119
|
+
tabActive: {
|
|
120
|
+
color: "#e4e4e7",
|
|
121
|
+
borderBottomColor: "#3b82f6"
|
|
122
|
+
},
|
|
123
|
+
panelContent: {
|
|
124
|
+
padding: "12px",
|
|
125
|
+
overflowY: "auto",
|
|
126
|
+
maxHeight: "340px",
|
|
127
|
+
flex: 1
|
|
128
|
+
},
|
|
129
|
+
table: {
|
|
130
|
+
width: "100%",
|
|
131
|
+
borderCollapse: "collapse",
|
|
132
|
+
fontSize: "12px"
|
|
133
|
+
},
|
|
134
|
+
th: {
|
|
135
|
+
textAlign: "left",
|
|
136
|
+
padding: "6px 8px",
|
|
137
|
+
borderBottom: "1px solid #27272a",
|
|
138
|
+
color: "#a1a1aa",
|
|
139
|
+
fontWeight: 600
|
|
140
|
+
},
|
|
141
|
+
td: {
|
|
142
|
+
padding: "6px 8px",
|
|
143
|
+
borderBottom: "1px solid #27272a",
|
|
144
|
+
maxWidth: "160px",
|
|
145
|
+
overflow: "hidden",
|
|
146
|
+
textOverflow: "ellipsis",
|
|
147
|
+
whiteSpace: "nowrap"
|
|
148
|
+
},
|
|
149
|
+
button: {
|
|
150
|
+
padding: "6px 12px",
|
|
151
|
+
borderRadius: "4px",
|
|
152
|
+
border: "1px solid #3f3f46",
|
|
153
|
+
background: "#27272a",
|
|
154
|
+
color: "#e4e4e7",
|
|
155
|
+
cursor: "pointer",
|
|
156
|
+
fontSize: "12px"
|
|
157
|
+
},
|
|
158
|
+
buttonDanger: {
|
|
159
|
+
background: "#7f1d1d",
|
|
160
|
+
borderColor: "#991b1b"
|
|
161
|
+
},
|
|
162
|
+
badge: {
|
|
163
|
+
display: "inline-block",
|
|
164
|
+
padding: "2px 6px",
|
|
165
|
+
borderRadius: "4px",
|
|
166
|
+
fontSize: "11px",
|
|
167
|
+
fontWeight: 600
|
|
168
|
+
},
|
|
169
|
+
badgeSuccess: {
|
|
170
|
+
background: "#14532d",
|
|
171
|
+
color: "#4ade80"
|
|
172
|
+
},
|
|
173
|
+
badgeError: {
|
|
174
|
+
background: "#7f1d1d",
|
|
175
|
+
color: "#f87171"
|
|
176
|
+
},
|
|
177
|
+
emptyState: {
|
|
178
|
+
color: "#71717a",
|
|
179
|
+
textAlign: "center",
|
|
180
|
+
padding: "24px",
|
|
181
|
+
fontSize: "12px"
|
|
182
|
+
},
|
|
183
|
+
label: {
|
|
184
|
+
color: "#a1a1aa",
|
|
185
|
+
fontSize: "11px",
|
|
186
|
+
marginBottom: "4px"
|
|
187
|
+
},
|
|
188
|
+
value: {
|
|
189
|
+
color: "#e4e4e7",
|
|
190
|
+
fontSize: "13px",
|
|
191
|
+
marginBottom: "12px",
|
|
192
|
+
wordBreak: "break-all"
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
function DataInspector({ client }) {
|
|
196
|
+
const [selected, setSelected] = useState(null);
|
|
197
|
+
const [records, setRecords] = useState([]);
|
|
198
|
+
const serviceNames = Object.keys(client).filter(
|
|
199
|
+
(k) => k !== "auth" && client[k] && typeof client[k].list === "function"
|
|
200
|
+
);
|
|
201
|
+
useEffect(() => {
|
|
202
|
+
if (!selected && serviceNames.length > 0) {
|
|
203
|
+
setSelected(serviceNames[0]);
|
|
204
|
+
}
|
|
205
|
+
}, [serviceNames.length]);
|
|
206
|
+
useEffect(() => {
|
|
207
|
+
if (!selected) return;
|
|
208
|
+
const service = client[selected];
|
|
209
|
+
if (!service) return;
|
|
210
|
+
service.list({ size: 50 }).then((res) => setRecords(res.items ?? [])).catch(() => setRecords([]));
|
|
211
|
+
}, [selected]);
|
|
212
|
+
if (serviceNames.length === 0) {
|
|
213
|
+
return /* @__PURE__ */ jsx("div", { style: STYLES.emptyState, children: "No services registered" });
|
|
214
|
+
}
|
|
215
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
216
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "4px", marginBottom: "8px", flexWrap: "wrap" }, children: serviceNames.map((name) => /* @__PURE__ */ jsx(
|
|
217
|
+
"button",
|
|
218
|
+
{
|
|
219
|
+
onClick: () => setSelected(name),
|
|
220
|
+
style: {
|
|
221
|
+
...STYLES.button,
|
|
222
|
+
...selected === name ? { background: "#3b82f6", borderColor: "#3b82f6" } : {}
|
|
223
|
+
},
|
|
224
|
+
children: name
|
|
225
|
+
},
|
|
226
|
+
name
|
|
227
|
+
)) }),
|
|
228
|
+
records.length === 0 ? /* @__PURE__ */ jsxs("div", { style: STYLES.emptyState, children: [
|
|
229
|
+
"No records in ",
|
|
230
|
+
selected
|
|
231
|
+
] }) : /* @__PURE__ */ jsxs("table", { style: STYLES.table, children: [
|
|
232
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
233
|
+
/* @__PURE__ */ jsx("th", { style: STYLES.th, children: "id" }),
|
|
234
|
+
Object.keys(records[0]).filter((k) => k !== "id" && !k.endsWith("At") && !k.endsWith("Id") && !k.endsWith("Name") && k !== "version" && k !== "password").slice(0, 3).map((k) => /* @__PURE__ */ jsx("th", { style: STYLES.th, children: k }, k))
|
|
235
|
+
] }) }),
|
|
236
|
+
/* @__PURE__ */ jsx("tbody", { children: records.map((r) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
237
|
+
/* @__PURE__ */ jsxs("td", { style: STYLES.td, children: [
|
|
238
|
+
r.id?.substring(0, 12),
|
|
239
|
+
"..."
|
|
240
|
+
] }),
|
|
241
|
+
Object.keys(records[0]).filter((k) => k !== "id" && !k.endsWith("At") && !k.endsWith("Id") && !k.endsWith("Name") && k !== "version" && k !== "password").slice(0, 3).map((k) => /* @__PURE__ */ jsx("td", { style: STYLES.td, children: String(r[k] ?? "") }, k))
|
|
242
|
+
] }, r.id)) })
|
|
243
|
+
] })
|
|
244
|
+
] });
|
|
245
|
+
}
|
|
246
|
+
function AuthInspector({ client }) {
|
|
247
|
+
const auth = client.auth;
|
|
248
|
+
if (!auth) {
|
|
249
|
+
return /* @__PURE__ */ jsx("div", { style: STYLES.emptyState, children: "Auth not configured" });
|
|
250
|
+
}
|
|
251
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
252
|
+
/* @__PURE__ */ jsx("div", { style: STYLES.label, children: "Status" }),
|
|
253
|
+
/* @__PURE__ */ jsx("div", { style: { ...STYLES.value, display: "flex", alignItems: "center", gap: "8px" }, children: /* @__PURE__ */ jsx(
|
|
254
|
+
"span",
|
|
255
|
+
{
|
|
256
|
+
style: {
|
|
257
|
+
...STYLES.badge,
|
|
258
|
+
...auth.isLoggedIn ? STYLES.badgeSuccess : STYLES.badgeError
|
|
259
|
+
},
|
|
260
|
+
children: auth.isLoggedIn ? "Logged In" : "Logged Out"
|
|
261
|
+
}
|
|
262
|
+
) }),
|
|
263
|
+
auth.isLoggedIn && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
264
|
+
/* @__PURE__ */ jsx("div", { style: STYLES.label, children: "User" }),
|
|
265
|
+
/* @__PURE__ */ jsx("div", { style: STYLES.value, children: auth.currentUser?.email ?? auth.currentUser?.id ?? "Unknown" }),
|
|
266
|
+
/* @__PURE__ */ jsx("div", { style: STYLES.label, children: "Token" }),
|
|
267
|
+
/* @__PURE__ */ jsxs("div", { style: { ...STYLES.value, fontSize: "11px", fontFamily: "monospace" }, children: [
|
|
268
|
+
auth.token?.substring(0, 40),
|
|
269
|
+
"..."
|
|
270
|
+
] }),
|
|
271
|
+
/* @__PURE__ */ jsx(
|
|
272
|
+
"button",
|
|
273
|
+
{
|
|
274
|
+
style: { ...STYLES.button, ...STYLES.buttonDanger },
|
|
275
|
+
onClick: () => {
|
|
276
|
+
auth.logout();
|
|
277
|
+
window.dispatchEvent(new Event("fauxbase:auth-change"));
|
|
278
|
+
},
|
|
279
|
+
children: "Logout"
|
|
280
|
+
}
|
|
281
|
+
)
|
|
282
|
+
] })
|
|
283
|
+
] });
|
|
284
|
+
}
|
|
285
|
+
function RequestLog({ entries, onClear }) {
|
|
286
|
+
if (entries.length === 0) {
|
|
287
|
+
return /* @__PURE__ */ jsx("div", { style: STYLES.emptyState, children: "No requests logged yet" });
|
|
288
|
+
}
|
|
289
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
290
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "8px" }, children: [
|
|
291
|
+
/* @__PURE__ */ jsxs("span", { style: STYLES.label, children: [
|
|
292
|
+
entries.length,
|
|
293
|
+
" requests"
|
|
294
|
+
] }),
|
|
295
|
+
/* @__PURE__ */ jsx("button", { style: STYLES.button, onClick: onClear, children: "Clear" })
|
|
296
|
+
] }),
|
|
297
|
+
/* @__PURE__ */ jsxs("table", { style: STYLES.table, children: [
|
|
298
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
299
|
+
/* @__PURE__ */ jsx("th", { style: STYLES.th, children: "Service" }),
|
|
300
|
+
/* @__PURE__ */ jsx("th", { style: STYLES.th, children: "Method" }),
|
|
301
|
+
/* @__PURE__ */ jsx("th", { style: STYLES.th, children: "Status" }),
|
|
302
|
+
/* @__PURE__ */ jsx("th", { style: STYLES.th, children: "Time" })
|
|
303
|
+
] }) }),
|
|
304
|
+
/* @__PURE__ */ jsx("tbody", { children: entries.map((entry) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
305
|
+
/* @__PURE__ */ jsx("td", { style: STYLES.td, children: entry.service }),
|
|
306
|
+
/* @__PURE__ */ jsx("td", { style: STYLES.td, children: entry.method }),
|
|
307
|
+
/* @__PURE__ */ jsx("td", { style: STYLES.td, children: /* @__PURE__ */ jsx(
|
|
308
|
+
"span",
|
|
309
|
+
{
|
|
310
|
+
style: {
|
|
311
|
+
...STYLES.badge,
|
|
312
|
+
...entry.error ? STYLES.badgeError : STYLES.badgeSuccess
|
|
313
|
+
},
|
|
314
|
+
children: entry.error ? "ERR" : "OK"
|
|
315
|
+
}
|
|
316
|
+
) }),
|
|
317
|
+
/* @__PURE__ */ jsxs("td", { style: STYLES.td, children: [
|
|
318
|
+
entry.duration,
|
|
319
|
+
"ms"
|
|
320
|
+
] })
|
|
321
|
+
] }, entry.id)) })
|
|
322
|
+
] })
|
|
323
|
+
] });
|
|
324
|
+
}
|
|
325
|
+
function SeedManager({ client }) {
|
|
326
|
+
const [resetting, setResetting] = useState(false);
|
|
327
|
+
const serviceNames = Object.keys(client).filter(
|
|
328
|
+
(k) => k !== "auth" && client[k] && typeof client[k].list === "function"
|
|
329
|
+
);
|
|
330
|
+
const handleReset = async (name) => {
|
|
331
|
+
setResetting(true);
|
|
332
|
+
try {
|
|
333
|
+
const service = client[name];
|
|
334
|
+
if (service?.driver?.clear) {
|
|
335
|
+
service.driver.clear(name);
|
|
336
|
+
}
|
|
337
|
+
} finally {
|
|
338
|
+
setResetting(false);
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
if (serviceNames.length === 0) {
|
|
342
|
+
return /* @__PURE__ */ jsx("div", { style: STYLES.emptyState, children: "No services registered" });
|
|
343
|
+
}
|
|
344
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
345
|
+
/* @__PURE__ */ jsx("div", { style: { ...STYLES.label, marginBottom: "12px" }, children: "Reset seed data for individual resources (LocalDriver only)" }),
|
|
346
|
+
serviceNames.map((name) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "8px" }, children: [
|
|
347
|
+
/* @__PURE__ */ jsx("span", { children: name }),
|
|
348
|
+
/* @__PURE__ */ jsx(
|
|
349
|
+
"button",
|
|
350
|
+
{
|
|
351
|
+
style: { ...STYLES.button, ...STYLES.buttonDanger },
|
|
352
|
+
onClick: () => handleReset(name),
|
|
353
|
+
disabled: resetting,
|
|
354
|
+
children: "Reset"
|
|
355
|
+
}
|
|
356
|
+
)
|
|
357
|
+
] }, name))
|
|
358
|
+
] });
|
|
359
|
+
}
|
|
360
|
+
var TABS = [
|
|
361
|
+
{ key: "data", label: "Data" },
|
|
362
|
+
{ key: "auth", label: "Auth" },
|
|
363
|
+
{ key: "requests", label: "Requests" },
|
|
364
|
+
{ key: "seeds", label: "Seeds" }
|
|
365
|
+
];
|
|
366
|
+
function FauxbaseDevtools({ client, config = {} }) {
|
|
367
|
+
const [open, setOpen] = useState(config.defaultOpen ?? false);
|
|
368
|
+
const [activeTab, setActiveTab] = useState("data");
|
|
369
|
+
const [logger] = useState(() => createRequestLogger(config.maxLogEntries ?? 100));
|
|
370
|
+
const [, setTick] = useState(0);
|
|
371
|
+
useEffect(() => {
|
|
372
|
+
return logger.subscribe(() => setTick((t) => t + 1));
|
|
373
|
+
}, [logger]);
|
|
374
|
+
const [wrappedClient] = useState(() => {
|
|
375
|
+
const wrapped = { ...client };
|
|
376
|
+
for (const [name, service] of Object.entries(client)) {
|
|
377
|
+
if (name !== "auth" && service && typeof service.list === "function") {
|
|
378
|
+
wrapped[name] = logger.wrapService(service, name);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return wrapped;
|
|
382
|
+
});
|
|
383
|
+
const position = config.position ?? "bottom-right";
|
|
384
|
+
const isLeft = position === "bottom-left";
|
|
385
|
+
const containerStyle = {
|
|
386
|
+
...STYLES.container,
|
|
387
|
+
...isLeft ? STYLES.containerLeft : {}
|
|
388
|
+
};
|
|
389
|
+
if (!open) {
|
|
390
|
+
return /* @__PURE__ */ jsx("div", { style: containerStyle, "data-testid": "fauxbase-devtools", children: /* @__PURE__ */ jsx(
|
|
391
|
+
"button",
|
|
392
|
+
{
|
|
393
|
+
style: STYLES.toggleButton,
|
|
394
|
+
onClick: () => setOpen(true),
|
|
395
|
+
"aria-label": "Open Fauxbase DevTools",
|
|
396
|
+
"data-testid": "devtools-toggle",
|
|
397
|
+
children: "{ }"
|
|
398
|
+
}
|
|
399
|
+
) });
|
|
400
|
+
}
|
|
401
|
+
return /* @__PURE__ */ jsx("div", { style: containerStyle, "data-testid": "fauxbase-devtools", children: /* @__PURE__ */ jsxs("div", { style: STYLES.panel, children: [
|
|
402
|
+
/* @__PURE__ */ jsxs("div", { style: STYLES.tabBar, children: [
|
|
403
|
+
TABS.map((tab) => /* @__PURE__ */ jsx(
|
|
404
|
+
"button",
|
|
405
|
+
{
|
|
406
|
+
style: {
|
|
407
|
+
...STYLES.tab,
|
|
408
|
+
...activeTab === tab.key ? STYLES.tabActive : {}
|
|
409
|
+
},
|
|
410
|
+
onClick: () => setActiveTab(tab.key),
|
|
411
|
+
"data-testid": `tab-${tab.key}`,
|
|
412
|
+
children: tab.label
|
|
413
|
+
},
|
|
414
|
+
tab.key
|
|
415
|
+
)),
|
|
416
|
+
/* @__PURE__ */ jsx(
|
|
417
|
+
"button",
|
|
418
|
+
{
|
|
419
|
+
style: { ...STYLES.tab, marginLeft: "auto" },
|
|
420
|
+
onClick: () => setOpen(false),
|
|
421
|
+
"aria-label": "Close DevTools",
|
|
422
|
+
"data-testid": "devtools-close",
|
|
423
|
+
children: "x"
|
|
424
|
+
}
|
|
425
|
+
)
|
|
426
|
+
] }),
|
|
427
|
+
/* @__PURE__ */ jsxs("div", { style: STYLES.panelContent, children: [
|
|
428
|
+
activeTab === "data" && /* @__PURE__ */ jsx(DataInspector, { client: wrappedClient }),
|
|
429
|
+
activeTab === "auth" && /* @__PURE__ */ jsx(AuthInspector, { client }),
|
|
430
|
+
activeTab === "requests" && /* @__PURE__ */ jsx(
|
|
431
|
+
RequestLog,
|
|
432
|
+
{
|
|
433
|
+
entries: logger.getEntries(),
|
|
434
|
+
onClear: () => logger.clear()
|
|
435
|
+
}
|
|
436
|
+
),
|
|
437
|
+
activeTab === "seeds" && /* @__PURE__ */ jsx(SeedManager, { client })
|
|
438
|
+
] })
|
|
439
|
+
] }) });
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
export { FauxbaseDevtools, createRequestLogger };
|
|
443
|
+
//# sourceMappingURL=index.js.map
|
|
444
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/request-logger.ts","../src/styles.ts","../src/panels/data-inspector.tsx","../src/panels/auth-inspector.tsx","../src/panels/request-log.tsx","../src/panels/seed-manager.tsx","../src/devtools.tsx"],"names":["jsx","jsxs","useState","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import type { RequestLogEntry } from './types';\n\nlet idCounter = 0;\n\nexport function createRequestLogger(maxEntries = 100) {\n const entries: RequestLogEntry[] = [];\n const listeners = new Set<() => void>();\n\n function addEntry(entry: RequestLogEntry): void {\n entries.unshift(entry);\n if (entries.length > maxEntries) {\n entries.pop();\n }\n listeners.forEach(fn => fn());\n }\n\n function getEntries(): RequestLogEntry[] {\n return entries;\n }\n\n function clear(): void {\n entries.length = 0;\n listeners.forEach(fn => fn());\n }\n\n function subscribe(fn: () => void): () => void {\n listeners.add(fn);\n return () => listeners.delete(fn);\n }\n\n /**\n * Wraps a service instance with a Proxy that logs all method calls.\n * Zero changes to the Service class.\n */\n function wrapService<T extends object>(service: T, serviceName: string): T {\n return new Proxy(service, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n if (typeof value !== 'function') return value;\n\n // Skip internal methods\n if (typeof prop === 'string' && prop.startsWith('_')) return value;\n\n return async function (this: any, ...args: any[]) {\n const entry: RequestLogEntry = {\n id: `log_${++idCounter}`,\n timestamp: Date.now(),\n service: serviceName,\n method: prop as string,\n args,\n duration: 0,\n };\n\n const start = performance.now();\n try {\n const result = await value.apply(target, args);\n entry.result = result;\n entry.duration = Math.round(performance.now() - start);\n addEntry(entry);\n return result;\n } catch (err: any) {\n entry.error = err.message ?? String(err);\n entry.duration = Math.round(performance.now() - start);\n addEntry(entry);\n throw err;\n }\n };\n },\n });\n }\n\n return { addEntry, getEntries, clear, subscribe, wrapService };\n}\n\nexport type RequestLogger = ReturnType<typeof createRequestLogger>;\n","export const STYLES = {\n container: {\n position: 'fixed' as const,\n bottom: '16px',\n right: '16px',\n zIndex: 99999,\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, monospace',\n fontSize: '13px',\n color: '#e4e4e7',\n },\n containerLeft: {\n right: 'auto',\n left: '16px',\n },\n toggleButton: {\n width: '40px',\n height: '40px',\n borderRadius: '8px',\n border: '1px solid #3f3f46',\n background: '#18181b',\n color: '#a1a1aa',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '18px',\n boxShadow: '0 4px 12px rgba(0,0,0,0.4)',\n },\n panel: {\n width: '480px',\n maxHeight: '400px',\n background: '#18181b',\n border: '1px solid #3f3f46',\n borderRadius: '8px',\n boxShadow: '0 8px 24px rgba(0,0,0,0.5)',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column' as const,\n },\n tabBar: {\n display: 'flex',\n borderBottom: '1px solid #3f3f46',\n background: '#09090b',\n },\n tab: {\n padding: '8px 16px',\n border: 'none',\n background: 'transparent',\n color: '#71717a',\n cursor: 'pointer',\n fontSize: '12px',\n fontWeight: 500,\n borderBottom: '2px solid transparent',\n },\n tabActive: {\n color: '#e4e4e7',\n borderBottomColor: '#3b82f6',\n },\n panelContent: {\n padding: '12px',\n overflowY: 'auto' as const,\n maxHeight: '340px',\n flex: 1,\n },\n table: {\n width: '100%',\n borderCollapse: 'collapse' as const,\n fontSize: '12px',\n },\n th: {\n textAlign: 'left' as const,\n padding: '6px 8px',\n borderBottom: '1px solid #27272a',\n color: '#a1a1aa',\n fontWeight: 600,\n },\n td: {\n padding: '6px 8px',\n borderBottom: '1px solid #27272a',\n maxWidth: '160px',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap' as const,\n },\n button: {\n padding: '6px 12px',\n borderRadius: '4px',\n border: '1px solid #3f3f46',\n background: '#27272a',\n color: '#e4e4e7',\n cursor: 'pointer',\n fontSize: '12px',\n },\n buttonDanger: {\n background: '#7f1d1d',\n borderColor: '#991b1b',\n },\n badge: {\n display: 'inline-block',\n padding: '2px 6px',\n borderRadius: '4px',\n fontSize: '11px',\n fontWeight: 600,\n },\n badgeSuccess: {\n background: '#14532d',\n color: '#4ade80',\n },\n badgeError: {\n background: '#7f1d1d',\n color: '#f87171',\n },\n emptyState: {\n color: '#71717a',\n textAlign: 'center' as const,\n padding: '24px',\n fontSize: '12px',\n },\n label: {\n color: '#a1a1aa',\n fontSize: '11px',\n marginBottom: '4px',\n },\n value: {\n color: '#e4e4e7',\n fontSize: '13px',\n marginBottom: '12px',\n wordBreak: 'break-all' as const,\n },\n};\n","import React, { useEffect, useState } from 'react';\nimport { STYLES } from '../styles';\n\ninterface DataInspectorProps {\n client: any;\n}\n\nexport function DataInspector({ client }: DataInspectorProps) {\n const [selected, setSelected] = useState<string | null>(null);\n const [records, setRecords] = useState<any[]>([]);\n\n const serviceNames = Object.keys(client).filter(\n k => k !== 'auth' && client[k] && typeof client[k].list === 'function',\n );\n\n useEffect(() => {\n if (!selected && serviceNames.length > 0) {\n setSelected(serviceNames[0]);\n }\n }, [serviceNames.length]);\n\n useEffect(() => {\n if (!selected) return;\n const service = client[selected];\n if (!service) return;\n service.list({ size: 50 }).then((res: any) => setRecords(res.items ?? [])).catch(() => setRecords([]));\n }, [selected]);\n\n if (serviceNames.length === 0) {\n return <div style={STYLES.emptyState}>No services registered</div>;\n }\n\n return (\n <div>\n <div style={{ display: 'flex', gap: '4px', marginBottom: '8px', flexWrap: 'wrap' }}>\n {serviceNames.map(name => (\n <button\n key={name}\n onClick={() => setSelected(name)}\n style={{\n ...STYLES.button,\n ...(selected === name ? { background: '#3b82f6', borderColor: '#3b82f6' } : {}),\n }}\n >\n {name}\n </button>\n ))}\n </div>\n\n {records.length === 0 ? (\n <div style={STYLES.emptyState}>No records in {selected}</div>\n ) : (\n <table style={STYLES.table}>\n <thead>\n <tr>\n <th style={STYLES.th}>id</th>\n {Object.keys(records[0])\n .filter(k => k !== 'id' && !k.endsWith('At') && !k.endsWith('Id') && !k.endsWith('Name') && k !== 'version' && k !== 'password')\n .slice(0, 3)\n .map(k => (\n <th key={k} style={STYLES.th}>{k}</th>\n ))}\n </tr>\n </thead>\n <tbody>\n {records.map((r: any) => (\n <tr key={r.id}>\n <td style={STYLES.td}>{r.id?.substring(0, 12)}...</td>\n {Object.keys(records[0])\n .filter(k => k !== 'id' && !k.endsWith('At') && !k.endsWith('Id') && !k.endsWith('Name') && k !== 'version' && k !== 'password')\n .slice(0, 3)\n .map(k => (\n <td key={k} style={STYLES.td}>{String(r[k] ?? '')}</td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </div>\n );\n}\n","import React from 'react';\nimport { STYLES } from '../styles';\n\ninterface AuthInspectorProps {\n client: any;\n}\n\nexport function AuthInspector({ client }: AuthInspectorProps) {\n const auth = client.auth;\n\n if (!auth) {\n return <div style={STYLES.emptyState}>Auth not configured</div>;\n }\n\n return (\n <div>\n <div style={STYLES.label}>Status</div>\n <div style={{ ...STYLES.value, display: 'flex', alignItems: 'center', gap: '8px' }}>\n <span\n style={{\n ...STYLES.badge,\n ...(auth.isLoggedIn ? STYLES.badgeSuccess : STYLES.badgeError),\n }}\n >\n {auth.isLoggedIn ? 'Logged In' : 'Logged Out'}\n </span>\n </div>\n\n {auth.isLoggedIn && (\n <>\n <div style={STYLES.label}>User</div>\n <div style={STYLES.value}>\n {auth.currentUser?.email ?? auth.currentUser?.id ?? 'Unknown'}\n </div>\n\n <div style={STYLES.label}>Token</div>\n <div style={{ ...STYLES.value, fontSize: '11px', fontFamily: 'monospace' }}>\n {auth.token?.substring(0, 40)}...\n </div>\n\n <button\n style={{ ...STYLES.button, ...STYLES.buttonDanger }}\n onClick={() => {\n auth.logout();\n // Force re-render\n window.dispatchEvent(new Event('fauxbase:auth-change'));\n }}\n >\n Logout\n </button>\n </>\n )}\n </div>\n );\n}\n","import React from 'react';\nimport type { RequestLogEntry } from '../types';\nimport { STYLES } from '../styles';\n\ninterface RequestLogProps {\n entries: RequestLogEntry[];\n onClear: () => void;\n}\n\nexport function RequestLog({ entries, onClear }: RequestLogProps) {\n if (entries.length === 0) {\n return <div style={STYLES.emptyState}>No requests logged yet</div>;\n }\n\n return (\n <div>\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '8px' }}>\n <span style={STYLES.label}>{entries.length} requests</span>\n <button style={STYLES.button} onClick={onClear}>Clear</button>\n </div>\n <table style={STYLES.table}>\n <thead>\n <tr>\n <th style={STYLES.th}>Service</th>\n <th style={STYLES.th}>Method</th>\n <th style={STYLES.th}>Status</th>\n <th style={STYLES.th}>Time</th>\n </tr>\n </thead>\n <tbody>\n {entries.map(entry => (\n <tr key={entry.id}>\n <td style={STYLES.td}>{entry.service}</td>\n <td style={STYLES.td}>{entry.method}</td>\n <td style={STYLES.td}>\n <span\n style={{\n ...STYLES.badge,\n ...(entry.error ? STYLES.badgeError : STYLES.badgeSuccess),\n }}\n >\n {entry.error ? 'ERR' : 'OK'}\n </span>\n </td>\n <td style={STYLES.td}>{entry.duration}ms</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n","import React, { useState } from 'react';\nimport { STYLES } from '../styles';\n\ninterface SeedManagerProps {\n client: any;\n}\n\nexport function SeedManager({ client }: SeedManagerProps) {\n const [resetting, setResetting] = useState(false);\n\n const serviceNames = Object.keys(client).filter(\n k => k !== 'auth' && client[k] && typeof client[k].list === 'function',\n );\n\n const handleReset = async (name: string) => {\n setResetting(true);\n try {\n // Check if the driver has a clear method (LocalDriver only)\n const service = client[name];\n if (service?.driver?.clear) {\n service.driver.clear(name);\n }\n } finally {\n setResetting(false);\n }\n };\n\n if (serviceNames.length === 0) {\n return <div style={STYLES.emptyState}>No services registered</div>;\n }\n\n return (\n <div>\n <div style={{ ...STYLES.label, marginBottom: '12px' }}>\n Reset seed data for individual resources (LocalDriver only)\n </div>\n {serviceNames.map(name => (\n <div key={name} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>\n <span>{name}</span>\n <button\n style={{ ...STYLES.button, ...STYLES.buttonDanger }}\n onClick={() => handleReset(name)}\n disabled={resetting}\n >\n Reset\n </button>\n </div>\n ))}\n </div>\n );\n}\n","import React, { useState, useEffect, useCallback } from 'react';\nimport type { PanelTab, DevtoolsConfig } from './types';\nimport { createRequestLogger, type RequestLogger } from './request-logger';\nimport { DataInspector } from './panels/data-inspector';\nimport { AuthInspector } from './panels/auth-inspector';\nimport { RequestLog } from './panels/request-log';\nimport { SeedManager } from './panels/seed-manager';\nimport { STYLES } from './styles';\n\ninterface FauxbaseDevtoolsProps {\n client: any;\n config?: DevtoolsConfig;\n}\n\nconst TABS: { key: PanelTab; label: string }[] = [\n { key: 'data', label: 'Data' },\n { key: 'auth', label: 'Auth' },\n { key: 'requests', label: 'Requests' },\n { key: 'seeds', label: 'Seeds' },\n];\n\nexport function FauxbaseDevtools({ client, config = {} }: FauxbaseDevtoolsProps) {\n const [open, setOpen] = useState(config.defaultOpen ?? false);\n const [activeTab, setActiveTab] = useState<PanelTab>('data');\n const [logger] = useState<RequestLogger>(() => createRequestLogger(config.maxLogEntries ?? 100));\n const [, setTick] = useState(0);\n\n // Subscribe to logger updates for re-render\n useEffect(() => {\n return logger.subscribe(() => setTick(t => t + 1));\n }, [logger]);\n\n // Wrap services with proxy logger\n const [wrappedClient] = useState(() => {\n const wrapped = { ...client };\n for (const [name, service] of Object.entries(client)) {\n if (name !== 'auth' && service && typeof (service as any).list === 'function') {\n wrapped[name] = logger.wrapService(service as object, name);\n }\n }\n return wrapped;\n });\n\n const position = config.position ?? 'bottom-right';\n const isLeft = position === 'bottom-left';\n\n const containerStyle = {\n ...STYLES.container,\n ...(isLeft ? STYLES.containerLeft : {}),\n };\n\n if (!open) {\n return (\n <div style={containerStyle} data-testid=\"fauxbase-devtools\">\n <button\n style={STYLES.toggleButton}\n onClick={() => setOpen(true)}\n aria-label=\"Open Fauxbase DevTools\"\n data-testid=\"devtools-toggle\"\n >\n {'{ }'}\n </button>\n </div>\n );\n }\n\n return (\n <div style={containerStyle} data-testid=\"fauxbase-devtools\">\n <div style={STYLES.panel}>\n <div style={STYLES.tabBar}>\n {TABS.map(tab => (\n <button\n key={tab.key}\n style={{\n ...STYLES.tab,\n ...(activeTab === tab.key ? STYLES.tabActive : {}),\n }}\n onClick={() => setActiveTab(tab.key)}\n data-testid={`tab-${tab.key}`}\n >\n {tab.label}\n </button>\n ))}\n <button\n style={{ ...STYLES.tab, marginLeft: 'auto' }}\n onClick={() => setOpen(false)}\n aria-label=\"Close DevTools\"\n data-testid=\"devtools-close\"\n >\n x\n </button>\n </div>\n <div style={STYLES.panelContent}>\n {activeTab === 'data' && <DataInspector client={wrappedClient} />}\n {activeTab === 'auth' && <AuthInspector client={client} />}\n {activeTab === 'requests' && (\n <RequestLog\n entries={logger.getEntries()}\n onClear={() => logger.clear()}\n />\n )}\n {activeTab === 'seeds' && <SeedManager client={client} />}\n </div>\n </div>\n </div>\n );\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fauxbase-devtools",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist"],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"test:watch": "vitest",
|
|
20
|
+
"test:coverage": "vitest run --coverage",
|
|
21
|
+
"clean": "rm -rf dist"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"react": ">=18",
|
|
25
|
+
"fauxbase": ">=0.4.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"react": "^18.3.0",
|
|
29
|
+
"react-dom": "^18.3.0",
|
|
30
|
+
"@types/react": "^18.3.0",
|
|
31
|
+
"@types/react-dom": "^18.3.0",
|
|
32
|
+
"@testing-library/react": "^16.0.0",
|
|
33
|
+
"fauxbase": "workspace:*",
|
|
34
|
+
"jsdom": "^25.0.0",
|
|
35
|
+
"tsup": "^8.0.0",
|
|
36
|
+
"vitest": "^3.0.0",
|
|
37
|
+
"@vitest/coverage-v8": "^3.0.0",
|
|
38
|
+
"typescript": "^5.7.0"
|
|
39
|
+
}
|
|
40
|
+
}
|