basalt-ui 1.23.1 → 1.24.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/AGENTS.md +11 -6
- package/CHANGELOG.md +14 -0
- package/MIGRATING.md +138 -4
- package/README.md +123 -32
- package/agent/rules/basalt-data.md +45 -13
- package/agent/rules/basalt-query.md +57 -0
- package/agent/skills/basalt-app/SKILL.md +7 -0
- package/dist/cli/index.d.ts +4 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +101 -17
- package/dist/dashboard/empty-state.d.ts +6 -2
- package/dist/dashboard/empty-state.d.ts.map +1 -1
- package/dist/dashboard/empty-state.js +1 -1
- package/dist/dashboard/index.d.ts +1 -0
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +8 -0
- package/dist/dashboard/query-state.d.ts +96 -0
- package/dist/dashboard/query-state.d.ts.map +1 -0
- package/dist/dashboard/query-state.js +123 -0
- package/dist/dashboard/query-state.test.d.ts +2 -0
- package/dist/dashboard/query-state.test.d.ts.map +1 -0
- package/dist/data/data-table.d.ts +61 -4
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +41 -4
- package/dist/data/data-table.test.d.ts +2 -0
- package/dist/data/data-table.test.d.ts.map +1 -0
- package/dist/data/table.d.ts +1 -1
- package/dist/data/table.d.ts.map +1 -1
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +21 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/query/error-message.d.ts +41 -0
- package/dist/query/error-message.d.ts.map +1 -0
- package/dist/query/error-message.js +30 -0
- package/dist/query/error-message.test.d.ts +2 -0
- package/dist/query/error-message.test.d.ts.map +1 -0
- package/dist/query/index.d.ts +1 -19
- package/dist/query/index.d.ts.map +1 -1
- package/dist/query/index.js +2 -14
- package/dist/surfaces.d.ts +1 -1
- package/dist/surfaces.js +1 -1
- package/llms.txt +3 -3
- package/package.json +1 -1
- package/src/cli/check-theme.test.ts +34 -0
- package/src/cli/index.ts +222 -44
- package/src/cli/tokens-css.test.ts +73 -6
- package/src/cli/toolchain-wiring.test.ts +146 -0
- package/src/dashboard/empty-state.tsx +9 -3
- package/src/dashboard/index.ts +11 -0
- package/src/dashboard/query-state.test.tsx +152 -0
- package/src/dashboard/query-state.tsx +272 -0
- package/src/data/data-table.test.tsx +158 -0
- package/src/data/data-table.tsx +123 -5
- package/src/data/table.ts +6 -1
- package/src/guard/check-source.test.ts +141 -0
- package/src/guard/index.ts +102 -8
- package/src/index.ts +9 -0
- package/src/query/error-message.test.ts +67 -0
- package/src/query/error-message.ts +70 -0
- package/src/query/index.ts +2 -34
- package/src/surfaces.ts +1 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport-agnostic error decoding. Deliberately a standalone module with NO
|
|
3
|
+
* `@tanstack/react-query` import — `dashboard/query-state.tsx` renders server messages and must
|
|
4
|
+
* not drag the query peer into the root barrel's graph to do it.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The HTTP status behind a thrown envelope (Eden Treaty's `{ status, value }`, a `Response`-shaped
|
|
9
|
+
* throw), when there is one. Use it to BRANCH — 404 → "not found" copy — rather than to build a
|
|
10
|
+
* message; `toErrorMessage` already folds the status into its text when the body says nothing.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* if (errorStatus(err) === 404) return <EmptyState title="Gone" />
|
|
14
|
+
*/
|
|
15
|
+
export function errorStatus(err: unknown): number | undefined {
|
|
16
|
+
if (err === null || typeof err !== 'object') return undefined
|
|
17
|
+
const status = (err as { status?: unknown }).status
|
|
18
|
+
return typeof status === 'number' ? status : undefined
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Strings that technically decoded but tell a reader nothing. `JSON.stringify` produces most. */
|
|
22
|
+
const UNUSABLE = new Set(['', '{}', '[]', 'null', 'undefined', '[object Object]'])
|
|
23
|
+
|
|
24
|
+
function decode(err: unknown): string {
|
|
25
|
+
if (err instanceof Error) return err.message
|
|
26
|
+
if (typeof err === 'string') return err
|
|
27
|
+
if (typeof err === 'object' && err !== null) {
|
|
28
|
+
const obj = err as Record<string, unknown>
|
|
29
|
+
if (typeof obj['message'] === 'string') return obj['message']
|
|
30
|
+
// Eden-style { value: ... } or { status, value } envelopes — unwrap one level.
|
|
31
|
+
if ('value' in obj) return decode(obj['value'])
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
return JSON.stringify(err) ?? ''
|
|
35
|
+
} catch {
|
|
36
|
+
return String(err)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Extract a human-readable message from an unknown thrown value (e.g. the raw Eden envelope
|
|
42
|
+
* thrown by `unwrap`). Removes the 8-line three-branch boilerplate consumers duplicate.
|
|
43
|
+
*
|
|
44
|
+
* Resolution order:
|
|
45
|
+
* 1. `Error` instance → err.message
|
|
46
|
+
* 2. `{ message: string }` → message (Eden / Elysia error shape)
|
|
47
|
+
* 3. `{ value: ... }` → recursively (Eden nested value envelope)
|
|
48
|
+
* 4. plain string → itself
|
|
49
|
+
* 5. anything else → `JSON.stringify`
|
|
50
|
+
*
|
|
51
|
+
* **If that yields nothing a human can read** (`''`, `'{}'`, `'[]'`, `'null'`, `'undefined'`,
|
|
52
|
+
* `'[object Object]'` — the shapes `JSON.stringify` produces for an opaque envelope) the `fallback`
|
|
53
|
+
* is returned instead, with `(HTTP <status>)` appended when the envelope carries one. Without that
|
|
54
|
+
* guard the caller renders a literal `{}` at the user, or — for `toErrorMessage(undefined)` —
|
|
55
|
+
* the actual value `undefined`, since `JSON.stringify(undefined)` is not a string at all.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* try {
|
|
59
|
+
* await unwrap(api.resource.post({ body }))
|
|
60
|
+
* } catch (e) {
|
|
61
|
+
* toast(toErrorMessage(e, 'Could not create share')) // → "slug already in use"
|
|
62
|
+
* // → "Could not create share (HTTP 502)"
|
|
63
|
+
* }
|
|
64
|
+
*/
|
|
65
|
+
export function toErrorMessage(err: unknown, fallback = 'The request failed.'): string {
|
|
66
|
+
const message = decode(err).trim()
|
|
67
|
+
if (!UNUSABLE.has(message)) return message
|
|
68
|
+
const status = errorStatus(err)
|
|
69
|
+
return status === undefined ? fallback : `${fallback} (HTTP ${status})`
|
|
70
|
+
}
|
package/src/query/index.ts
CHANGED
|
@@ -69,41 +69,9 @@ export async function unwrap<TData>(
|
|
|
69
69
|
return data as TData
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
// ──
|
|
72
|
+
// ── Error decoding ────────────────────────────────────────────────────────────────────────────────
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
* Extract a human-readable message from an unknown thrown value (e.g. the raw Eden envelope
|
|
76
|
-
* thrown by `unwrap`). Removes the 8-line three-branch boilerplate consumers duplicate.
|
|
77
|
-
*
|
|
78
|
-
* Resolution order:
|
|
79
|
-
* 1. `Error` instance → err.message
|
|
80
|
-
* 2. `{ message: string }` → message (Eden / Elysia error shape)
|
|
81
|
-
* 3. `{ value: ... }` → toErrorMessage(value) recursively (Eden nested value envelope)
|
|
82
|
-
* 4. plain string → itself
|
|
83
|
-
* 5. anything else → JSON.stringify with safe fallback to String()
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* try {
|
|
87
|
-
* await unwrap(api.resource.post({ body }))
|
|
88
|
-
* } catch (e) {
|
|
89
|
-
* toast(toErrorMessage(e))
|
|
90
|
-
* }
|
|
91
|
-
*/
|
|
92
|
-
export function toErrorMessage(err: unknown): string {
|
|
93
|
-
if (err instanceof Error) return err.message
|
|
94
|
-
if (typeof err === 'string') return err
|
|
95
|
-
if (typeof err === 'object' && err !== null) {
|
|
96
|
-
const obj = err as Record<string, unknown>
|
|
97
|
-
if (typeof obj['message'] === 'string') return obj['message']
|
|
98
|
-
// Eden-style { value: ... } or { status, value } envelopes — unwrap one level.
|
|
99
|
-
if ('value' in obj) return toErrorMessage(obj['value'])
|
|
100
|
-
}
|
|
101
|
-
try {
|
|
102
|
-
return JSON.stringify(err)
|
|
103
|
-
} catch {
|
|
104
|
-
return String(err)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
74
|
+
export { toErrorMessage, errorStatus } from './error-message'
|
|
107
75
|
|
|
108
76
|
// ── Re-exports from @tanstack/react-query ────────────────────────────────────────────────────────
|
|
109
77
|
|
package/src/surfaces.ts
CHANGED
|
@@ -194,7 +194,7 @@ export const SURFACES = {
|
|
|
194
194
|
'mantine-shade-index',
|
|
195
195
|
],
|
|
196
196
|
description:
|
|
197
|
-
'BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, NavCountBadge, ThemeToggle, ThreadWorkspace + thread-chat components, dashboard composites (DeltaBadge, StatCard with threshold tone, EmptyState, SettingsSection/SettingsRow/DangerZone)',
|
|
197
|
+
'BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, NavCountBadge, ThemeToggle, ThreadWorkspace + thread-chat components, dashboard composites (DeltaBadge, StatCard with threshold tone, EmptyState, QueryState/LoadingState/ErrorState, SettingsSection/SettingsRow/DangerZone)',
|
|
198
198
|
optionalPeers: [
|
|
199
199
|
'react-markdown',
|
|
200
200
|
'remark-gfm',
|