@carlonicora/nextjs-jsonapi 2.4.0 → 2.5.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/{BlockNoteEditor-7WGCH2KB.js → BlockNoteEditor-TIMGYKAA.js} +19 -19
- package/dist/{BlockNoteEditor-7WGCH2KB.js.map → BlockNoteEditor-TIMGYKAA.js.map} +1 -1
- package/dist/{BlockNoteEditor-GWAV5ESO.mjs → BlockNoteEditor-YFJMXJEU.mjs} +4 -4
- package/dist/billing/index.js +362 -362
- package/dist/billing/index.mjs +3 -3
- package/dist/{chunk-GYGMEDVS.js → chunk-7HKJNUW7.js} +755 -746
- package/dist/chunk-7HKJNUW7.js.map +1 -0
- package/dist/{chunk-3LVSA7IM.mjs → chunk-DJWNNV52.mjs} +2 -2
- package/dist/{chunk-LCCRUWWY.mjs → chunk-FS4RVV3K.mjs} +241 -1
- package/dist/chunk-FS4RVV3K.mjs.map +1 -0
- package/dist/{chunk-M2EGUO2F.mjs → chunk-G4YS52SO.mjs} +16 -7
- package/dist/chunk-G4YS52SO.mjs.map +1 -0
- package/dist/{chunk-TOKHHZSP.js → chunk-OTEDZ6YW.js} +7 -7
- package/dist/{chunk-TOKHHZSP.js.map → chunk-OTEDZ6YW.js.map} +1 -1
- package/dist/{chunk-V66AZWPG.js → chunk-RTOC53EZ.js} +246 -6
- package/dist/chunk-RTOC53EZ.js.map +1 -0
- package/dist/client/index.js +4 -4
- package/dist/client/index.mjs +3 -3
- package/dist/components/index.d.mts +16 -1
- package/dist/components/index.d.ts +16 -1
- package/dist/components/index.js +4 -4
- package/dist/components/index.mjs +3 -3
- package/dist/{tokenusage-admin.module-5wJ_tZTj.d.ts → config-BIjrg5wd.d.ts} +39 -1
- package/dist/{tokenusage-admin.module-DQVT4O4j.d.mts → config-BRUjtCd1.d.mts} +39 -1
- package/dist/contexts/index.js +4 -4
- package/dist/contexts/index.mjs +3 -3
- package/dist/core/index.d.mts +5 -2
- package/dist/core/index.d.ts +5 -2
- package/dist/core/index.js +8 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +7 -1
- package/dist/features/help/index.js +37 -37
- package/dist/features/help/index.mjs +3 -3
- package/dist/features/tokenusage/index.d.mts +413 -14
- package/dist/features/tokenusage/index.d.ts +413 -14
- package/dist/features/tokenusage/index.js +481 -120
- package/dist/features/tokenusage/index.js.map +1 -1
- package/dist/features/tokenusage/index.mjs +431 -70
- package/dist/features/tokenusage/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -2
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +1 -1
- package/package.json +1 -1
- package/src/core/index.ts +10 -0
- package/src/core/registry/ModuleRegistry.ts +4 -0
- package/src/features/tokenusage/components/TokenUsageAdminContainer.tsx +20 -4
- package/src/features/tokenusage/components/TokenUsageAdminTiles.tsx +31 -18
- package/src/features/tokenusage/components/TokenUsageBreakdownTable.tsx +13 -13
- package/src/features/tokenusage/components/TokenUsageRankedBar.tsx +24 -7
- package/src/features/tokenusage/components/TokenUsageReportContainer.tsx +102 -0
- package/src/features/tokenusage/components/TokenUsageReportFilterBar.tsx +34 -0
- package/src/features/tokenusage/components/TokenUsageReportTiles.tsx +161 -0
- package/src/features/tokenusage/components/TokenUsageTimelineChart.tsx +15 -13
- package/src/features/tokenusage/components/__tests__/TokenUsageAdminTiles.spec.tsx +4 -2
- package/src/features/tokenusage/components/__tests__/TokenUsageRankedBar.spec.tsx +3 -1
- package/src/features/tokenusage/contexts/TokenUsageAdminContext.tsx +6 -3
- package/src/features/tokenusage/contexts/TokenUsageReportContext.tsx +199 -0
- package/src/features/tokenusage/data/TokenUsageReportService.ts +65 -0
- package/src/features/tokenusage/data/index.ts +9 -0
- package/src/features/tokenusage/data/tokenusage-report-breakdown.interface.ts +12 -0
- package/src/features/tokenusage/data/tokenusage-report-breakdown.ts +94 -0
- package/src/features/tokenusage/data/tokenusage-report-summary.interface.ts +12 -0
- package/src/features/tokenusage/data/tokenusage-report-summary.ts +87 -0
- package/src/features/tokenusage/data/tokenusage-report-timeline.interface.ts +13 -0
- package/src/features/tokenusage/data/tokenusage-report-timeline.ts +94 -0
- package/src/features/tokenusage/data/tokenusage-report.types.ts +51 -0
- package/src/features/tokenusage/i18n-keys.ts +28 -0
- package/src/features/tokenusage/index.ts +18 -0
- package/src/features/tokenusage/lib/config.ts +22 -0
- package/src/features/tokenusage/lib/formatters.ts +100 -0
- package/src/features/tokenusage/lib/metrics.ts +8 -26
- package/src/features/tokenusage/lib/palette.ts +41 -14
- package/src/features/tokenusage/tokenusage-admin.module.ts +4 -0
- package/src/features/tokenusage/tokenusage.modules.ts +40 -0
- package/src/shadcnui/ui/chart.tsx +30 -3
- package/dist/chunk-GYGMEDVS.js.map +0 -1
- package/dist/chunk-LCCRUWWY.mjs.map +0 -1
- package/dist/chunk-M2EGUO2F.mjs.map +0 -1
- package/dist/chunk-V66AZWPG.js.map +0 -1
- /package/dist/{BlockNoteEditor-GWAV5ESO.mjs.map → BlockNoteEditor-YFJMXJEU.mjs.map} +0 -0
- /package/dist/{chunk-3LVSA7IM.mjs.map → chunk-DJWNNV52.mjs.map} +0 -0
|
@@ -3,16 +3,29 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Every value here is a documented step of the dataviz skill's reference ramps —
|
|
5
5
|
* nothing was eyeballed, nothing was hand-mixed. The palette was run through the
|
|
6
|
-
* skill's validator against THIS application's real chart surfaces
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* skill's validator against THIS application's real chart surfaces in both modes.
|
|
7
|
+
* The verbatim output is below.
|
|
8
|
+
*
|
|
9
|
+
* The surface is `--card`, NOT `--background`. Every chart that uses this palette
|
|
10
|
+
* is painted inside a `<Card>`, so the card is the surface the marks actually sit
|
|
11
|
+
* on — and in dark mode it is the *lighter* of the two (`oklch(0.205 0 0)` vs the
|
|
12
|
+
* background's `oklch(0.145 0 0)`), which is the harder case for contrast. Taken
|
|
13
|
+
* from `apps/web/src/app/globals.css` (narr8 declares two `:root`/`.dark` pairs;
|
|
14
|
+
* the LATER pair wins, and it is the one read here) — light `oklch(1 0 0)`, dark
|
|
15
|
+
* `oklch(0.205 0 0)`. a360ai declares the same two values.
|
|
16
|
+
*
|
|
17
|
+
* oklch→hex conversion: the algebraic inverse of the Björn Ottosson OKLab
|
|
18
|
+
* matrices — the same matrices the validator applies in the forward direction —
|
|
19
|
+
* giving light `#ffffff` and dark `#171717`. Cross-checked by feeding it the
|
|
20
|
+
* previously recorded background value, which it reproduces exactly:
|
|
21
|
+
* `oklch(0.145 0 0)` → `#0a0a0a`. ✓
|
|
9
22
|
*
|
|
10
23
|
* Light and dark are two SELECTED sets of steps, chosen for their own surface —
|
|
11
24
|
* never one set with its lightness flipped at runtime. Consumers pick a set from
|
|
12
25
|
* the resolved theme (`seriesColor(i, mode)` / `sequentialColor(i, mode)`).
|
|
13
26
|
*
|
|
14
27
|
* ---------------------------------------------------------------------------
|
|
15
|
-
* VALIDATOR OUTPUT — dataviz `scripts/validate_palette.js`, run 2026-08-
|
|
28
|
+
* VALIDATOR OUTPUT — dataviz `scripts/validate_palette.js`, run 2026-08-15
|
|
16
29
|
* ---------------------------------------------------------------------------
|
|
17
30
|
*
|
|
18
31
|
* $ node scripts/validate_palette.js "#2a78d6,#eb6834,#1baf7a,#eda100,#e87ba4,#008300,#4a3aa7" --mode light --surface "#ffffff"
|
|
@@ -27,9 +40,9 @@
|
|
|
27
40
|
* → ALL CHECKS PASS (CVD in the 6–8 floor band is legal ONLY with secondary encoding: direct labels, gaps, or texture)
|
|
28
41
|
* scope: categorical palettes only. For a lone status/text color check WCAG text contrast; for a sequential ramp, lightness monotonicity.
|
|
29
42
|
*
|
|
30
|
-
* $ node scripts/validate_palette.js "#3987e5,#d95926,#199e70,#c98500,#d55181,#008300,#9085e9" --mode dark --surface "#
|
|
43
|
+
* $ node scripts/validate_palette.js "#3987e5,#d95926,#199e70,#c98500,#d55181,#008300,#9085e9" --mode dark --surface "#171717"
|
|
31
44
|
*
|
|
32
|
-
* Palette (dark, surface #
|
|
45
|
+
* Palette (dark, surface #171717, categorical): 7 slots
|
|
33
46
|
* [PASS] Lightness band all 7 inside L 0.48–0.67
|
|
34
47
|
* [PASS] Chroma floor all 7 >= 0.1
|
|
35
48
|
* [PASS] CVD separation worst adjacent #c98500↔#199e70 ΔE 8.4 (protan) · tritan 8.7
|
|
@@ -49,29 +62,39 @@
|
|
|
49
62
|
*
|
|
50
63
|
* → ALL CHECKS PASS (ordinal: one hue, monotone L, visible step gaps, light end clears surface)
|
|
51
64
|
*
|
|
52
|
-
* $ node scripts/validate_palette.js "#9ec5f4,#6da7ec,#3987e5,#256abf,#184f95" --mode dark --surface "#
|
|
65
|
+
* $ node scripts/validate_palette.js "#9ec5f4,#6da7ec,#3987e5,#256abf,#184f95" --mode dark --surface "#171717" --ordinal
|
|
53
66
|
*
|
|
54
|
-
* Palette (dark, surface #
|
|
67
|
+
* Palette (dark, surface #171717, ordinal ramp): 5 slots
|
|
55
68
|
* [PASS] Lightness monotone steps read light→dark
|
|
56
69
|
* [PASS] Adjacent ΔL all gaps >= 0.06
|
|
57
|
-
* [PASS] Light-end contrast #184f95 at 2.
|
|
70
|
+
* [PASS] Light-end contrast #184f95 at 2.21:1 vs surface
|
|
58
71
|
* [PASS] Single hue hue spread 3°
|
|
59
72
|
*
|
|
60
73
|
* → ALL CHECKS PASS (ordinal: one hue, monotone L, visible step gaps, light end clears surface)
|
|
61
74
|
*
|
|
62
75
|
* OTHER_COLOR is achromatic, so the categorical checks (which gate hue identity)
|
|
63
76
|
* do not apply to it; it was gated on contrast alone with the validator's own
|
|
64
|
-
* `contrast()` export: 3.59:1 on `#ffffff`,
|
|
77
|
+
* `contrast()` export: 3.59:1 on `#ffffff`, 4.99:1 on `#171717` — both clear 3:1.
|
|
65
78
|
*
|
|
66
79
|
* ---------------------------------------------------------------------------
|
|
67
80
|
* WHAT THE RESULTS OBLIGE US TO DO
|
|
68
81
|
* ---------------------------------------------------------------------------
|
|
69
82
|
*
|
|
83
|
+
* - NO COLOUR VALUE CHANGED in the move from `--background` to `--card`. Every
|
|
84
|
+
* gate that passed on the background still passes on the card, so re-stepping
|
|
85
|
+
* a hue would have been churn, not a fix. Only the recorded surface, the
|
|
86
|
+
* recorded numbers and this prose changed.
|
|
87
|
+
* - The dark set still clears 3:1 on the LIGHTER card surface: the worst slot is
|
|
88
|
+
* green `#008300` at 3.63:1, and the ordinal ramp's surface-nearest step lands
|
|
89
|
+
* at 2.21:1 (down from 2.44:1 on the background) — still above the 2:1 gate.
|
|
90
|
+
* That headroom is thin, so a future card-surface lightening MUST re-run these
|
|
91
|
+
* four commands rather than assume the set still holds.
|
|
70
92
|
* - The light-mode contrast WARN is NOT dismissable. Three slots (aqua, yellow,
|
|
71
93
|
* magenta) sit below 3:1 on white, so every surface that paints with this
|
|
72
94
|
* palette MUST ship the relief channel: a visible legend, direct labels and a
|
|
73
95
|
* tooltip carrying the value in text. The timeline chart and the breakdown
|
|
74
|
-
* table both do.
|
|
96
|
+
* table both do. The light card is `#ffffff`, identical to the light
|
|
97
|
+
* background, so this WARN is unchanged rather than newly incurred.
|
|
75
98
|
* - CVD separation is measured on ADJACENT pairs, which is the correct pairlist
|
|
76
99
|
* for stacked bars, grouped bars and lines — the only forms this palette paints.
|
|
77
100
|
* A scatter / bubble / small-multiples chart would need `--pairs all`, which
|
|
@@ -82,10 +105,14 @@
|
|
|
82
105
|
/** Which surface the colours are being painted on. */
|
|
83
106
|
export type ChartMode = "light" | "dark";
|
|
84
107
|
|
|
85
|
-
/**
|
|
108
|
+
/**
|
|
109
|
+
* The chart surfaces the palette was validated against (globals.css `--card`).
|
|
110
|
+
*
|
|
111
|
+
* `--card`, never `--background`: the charts are painted inside a `<Card>`.
|
|
112
|
+
*/
|
|
86
113
|
export const CHART_SURFACE: Readonly<Record<ChartMode, string>> = {
|
|
87
114
|
light: "#ffffff",
|
|
88
|
-
dark: "#
|
|
115
|
+
dark: "#171717",
|
|
89
116
|
};
|
|
90
117
|
|
|
91
118
|
/**
|
|
@@ -133,7 +160,7 @@ export const CATEGORICAL_CEILING = CATEGORICAL_LIGHT.length;
|
|
|
133
160
|
/**
|
|
134
161
|
* The "other" rollup colour: deliberately achromatic so it reads as "not an
|
|
135
162
|
* identity" beside the seven hues. Same step in both modes — it clears 3:1 on
|
|
136
|
-
* both surfaces (3.59:1
|
|
163
|
+
* both card surfaces (3.59:1 on `#ffffff`, 4.99:1 on `#171717`).
|
|
137
164
|
*/
|
|
138
165
|
export const OTHER_COLOR = "#898781";
|
|
139
166
|
|
|
@@ -11,6 +11,10 @@ import { TokenUsageAdminTimeline } from "./data/tokenusage-admin-timeline";
|
|
|
11
11
|
* Distinct from the consuming app's own TokenUsage module (name "tokenusages",
|
|
12
12
|
* pageUrl "/tokenusage") — that one is an AppModuleDefinitions entry the package
|
|
13
13
|
* cannot reference, which is why these three exist.
|
|
14
|
+
*
|
|
15
|
+
* PREFER `tokenUsageModules(factory)` from `./tokenusage.modules` — it returns
|
|
16
|
+
* these three plus the three self-service report modules as one spreadable
|
|
17
|
+
* object. These individual factories are kept for backward compatibility.
|
|
14
18
|
*/
|
|
15
19
|
export const TokenUsageAdminSummaryModule = (factory: ModuleFactory) =>
|
|
16
20
|
factory({ name: "tokenusages/administration/summary", model: TokenUsageAdminSummary });
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ModuleFactory, ModuleWithPermissions } from "../../permissions";
|
|
2
|
+
import { TokenUsageAdminBreakdown } from "./data/tokenusage-admin-breakdown";
|
|
3
|
+
import { TokenUsageAdminSummary } from "./data/tokenusage-admin-summary";
|
|
4
|
+
import { TokenUsageAdminTimeline } from "./data/tokenusage-admin-timeline";
|
|
5
|
+
import { TokenUsageReportBreakdown } from "./data/tokenusage-report-breakdown";
|
|
6
|
+
import { TokenUsageReportSummary } from "./data/tokenusage-report-summary";
|
|
7
|
+
import { TokenUsageReportTimeline } from "./data/tokenusage-report-timeline";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Every read-only reporting resource behind the two token-usage pages, as one
|
|
11
|
+
* object a consuming app spreads into its `allModules`.
|
|
12
|
+
*
|
|
13
|
+
* A bundle rather than six separate factories because registration is the APP'S
|
|
14
|
+
* job — `allModules` is also the source of `AllModuleDefinitions` and what
|
|
15
|
+
* `DataClassRegistry.bootstrap()` reads, so the package cannot self-register.
|
|
16
|
+
* Six names is six chances to forget one, and a forgotten name is not a compile
|
|
17
|
+
* error: `FoundationModuleDefinitions` declares them all, so `Modules.X`
|
|
18
|
+
* typechecks and is `undefined` at runtime. One spread cannot be partially done.
|
|
19
|
+
*
|
|
20
|
+
* `name` is the endpoint path EndpointCreator builds URLs from. None has a
|
|
21
|
+
* pageUrl — these are not navigable resources.
|
|
22
|
+
*
|
|
23
|
+
* The return type is the six named keys, NOT `Record<string,
|
|
24
|
+
* ModuleWithPermissions>`: the consuming app derives `AllModuleDefinitions`
|
|
25
|
+
* from `typeof allModules`, so spreading an index-signature type in would give
|
|
26
|
+
* that object a string index signature and make every `Modules.<anything>`
|
|
27
|
+
* lookup typecheck. `satisfies` keeps the constraint without widening.
|
|
28
|
+
*/
|
|
29
|
+
export const tokenUsageModules = (factory: ModuleFactory) =>
|
|
30
|
+
({
|
|
31
|
+
TokenUsageAdminSummary: factory({ name: "tokenusages/administration/summary", model: TokenUsageAdminSummary }),
|
|
32
|
+
TokenUsageAdminTimeline: factory({ name: "tokenusages/administration/timeline", model: TokenUsageAdminTimeline }),
|
|
33
|
+
TokenUsageAdminBreakdown: factory({
|
|
34
|
+
name: "tokenusages/administration/breakdown",
|
|
35
|
+
model: TokenUsageAdminBreakdown,
|
|
36
|
+
}),
|
|
37
|
+
TokenUsageReportSummary: factory({ name: "tokenusages/reports/summary", model: TokenUsageReportSummary }),
|
|
38
|
+
TokenUsageReportTimeline: factory({ name: "tokenusages/reports/timeline", model: TokenUsageReportTimeline }),
|
|
39
|
+
TokenUsageReportBreakdown: factory({ name: "tokenusages/reports/breakdown", model: TokenUsageReportBreakdown }),
|
|
40
|
+
}) satisfies Record<string, ModuleWithPermissions>;
|
|
@@ -115,6 +115,8 @@ function ChartTooltipContent({
|
|
|
115
115
|
labelFormatter,
|
|
116
116
|
labelClassName,
|
|
117
117
|
formatter,
|
|
118
|
+
valueFormatter,
|
|
119
|
+
hideZeroValues = false,
|
|
118
120
|
color,
|
|
119
121
|
nameKey,
|
|
120
122
|
labelKey,
|
|
@@ -124,6 +126,21 @@ function ChartTooltipContent({
|
|
|
124
126
|
label?: string | number;
|
|
125
127
|
labelFormatter?: (label: unknown, payload: PayloadItem[]) => React.ReactNode;
|
|
126
128
|
formatter?: (value: unknown, name: string, item: PayloadItem, index: number, payload: unknown) => React.ReactNode;
|
|
129
|
+
/**
|
|
130
|
+
* Formats the VALUE half of a row while keeping the default layout — colour
|
|
131
|
+
* swatch, series name, alignment. `formatter` replaces the whole row, so it
|
|
132
|
+
* is the wrong tool when all a chart needs is its own number formatting.
|
|
133
|
+
* Defaults to `toLocaleString()`, which is what every existing caller gets.
|
|
134
|
+
*/
|
|
135
|
+
valueFormatter?: (value: number | string) => React.ReactNode;
|
|
136
|
+
/**
|
|
137
|
+
* Drops rows whose value is zero. On a stacked chart every series appears in
|
|
138
|
+
* every bucket's payload, so a bucket with one active series still lists all
|
|
139
|
+
* of them — the reader has to scan a column of zeros to find the one number
|
|
140
|
+
* that matters. Off by default: a chart comparing a fixed set of series may
|
|
141
|
+
* want the zeros visible.
|
|
142
|
+
*/
|
|
143
|
+
hideZeroValues?: boolean;
|
|
127
144
|
hideLabel?: boolean;
|
|
128
145
|
hideIndicator?: boolean;
|
|
129
146
|
indicator?: "line" | "dot" | "dashed";
|
|
@@ -173,6 +190,7 @@ function ChartTooltipContent({
|
|
|
173
190
|
<div className="grid gap-1.5">
|
|
174
191
|
{payload
|
|
175
192
|
.filter((item) => item.type !== "none")
|
|
193
|
+
.filter((item) => !hideZeroValues || Number(item.value) !== 0)
|
|
176
194
|
.map((item, index) => {
|
|
177
195
|
const key = `${nameKey || item.name || item.dataKey || "value"}`;
|
|
178
196
|
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
|
@@ -212,7 +230,11 @@ function ChartTooltipContent({
|
|
|
212
230
|
)}
|
|
213
231
|
<div
|
|
214
232
|
className={cn(
|
|
215
|
-
|
|
233
|
+
// gap-4 is load-bearing: without it a long series name
|
|
234
|
+
// runs straight into its value ("Decision suggestions0")
|
|
235
|
+
// because justify-between leaves no room once the row
|
|
236
|
+
// fills. The gap also widens the tooltip to fit.
|
|
237
|
+
"flex flex-1 justify-between gap-4 leading-none",
|
|
216
238
|
nestLabel ? "items-end" : "items-center",
|
|
217
239
|
)}
|
|
218
240
|
>
|
|
@@ -220,8 +242,13 @@ function ChartTooltipContent({
|
|
|
220
242
|
{nestLabel ? tooltipLabel : null}
|
|
221
243
|
<span className="text-muted-foreground">{itemConfig?.label || item.name}</span>
|
|
222
244
|
</div>
|
|
223
|
-
{item.value && (
|
|
224
|
-
|
|
245
|
+
{item.value !== undefined && item.value !== null && (
|
|
246
|
+
// Tested against undefined/null rather than truthiness:
|
|
247
|
+
// a value of exactly 0 is falsy, and the old guard
|
|
248
|
+
// dropped the number while still drawing its row.
|
|
249
|
+
<span className="text-foreground font-medium tabular-nums">
|
|
250
|
+
{valueFormatter ? valueFormatter(item.value) : item.value.toLocaleString()}
|
|
251
|
+
</span>
|
|
225
252
|
)}
|
|
226
253
|
</div>
|
|
227
254
|
</>
|