-
{e.type}
-
{new Date(e.ts).toISOString()}
+
+ {String(e.type ?? "")}
+ {safeFormatTimestamp(e.ts)}
-
- {JSON.stringify(e.payload, null, 2)}
+
+ {safeStringify(e.payload)}
))}
diff --git a/src/app/export/page.tsx b/src/app/export/page.tsx
index 1a161bb..a311556 100644
--- a/src/app/export/page.tsx
+++ b/src/app/export/page.tsx
@@ -1,5 +1,6 @@
-const API_BASE =
- process.env.NEXT_PUBLIC_AGENTPAY_API_BASE ?? "http://localhost:3001";
+import { resolveApiBase } from "@/lib/resolveApiBase";
+
+const API_BASE = resolveApiBase();
export const metadata = { title: "Export" };
diff --git a/src/app/usage/page.tsx b/src/app/usage/page.tsx
index 185ba27..8320672 100644
--- a/src/app/usage/page.tsx
+++ b/src/app/usage/page.tsx
@@ -1,6 +1,7 @@
"use client";
import { useState } from "react";
+import { resolveApiBase } from "@/lib/resolveApiBase";
type QueryResult = {
agent: string;
@@ -8,8 +9,7 @@ type QueryResult = {
total: number;
} | null;
-const API_BASE =
- process.env.NEXT_PUBLIC_AGENTPAY_API_BASE ?? "http://localhost:3001";
+const API_BASE = resolveApiBase();
export default function UsagePage() {
const [agent, setAgent] = useState("");
diff --git a/src/components/TextField.tsx b/src/components/TextField.tsx
index cbd82bc..283a5b1 100644
--- a/src/components/TextField.tsx
+++ b/src/components/TextField.tsx
@@ -1,11 +1,24 @@
import { type InputHTMLAttributes, type ReactNode, useId } from "react";
type TextFieldProps = InputHTMLAttributes & {
+ /** Visible label rendered above the input. */
label: ReactNode;
+ /** Optional helper text rendered beneath the input. Linked via aria-describedby. */
description?: ReactNode;
+ /** Optional error message; when present flips aria-invalid and exposes the message via aria-describedby. */
error?: ReactNode;
};
+/**
+ * Accessible text input with a label, optional description, and optional
+ * error message. Generates a stable internal id when none is supplied so the
+ * label, description, and error message all stay linked to the input via
+ * `htmlFor` / `id` / `aria-describedby` / `aria-invalid`.
+ *
+ * @example
+ *
+ *
+ */
export function TextField({
label,
description,
@@ -27,7 +40,7 @@ export function TextField({
diff --git a/src/components/__tests__/TextField.test.tsx b/src/components/__tests__/TextField.test.tsx
new file mode 100644
index 0000000..8fecfb3
--- /dev/null
+++ b/src/components/__tests__/TextField.test.tsx
@@ -0,0 +1,99 @@
+import { render, screen } from "@testing-library/react";
+import { TextField } from "../TextField";
+
+// Query through the accessible name (via