@aganzefelicite/responsekit-react 0.2.0 → 0.3.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 +767 -766
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -2
- package/dist/index.d.ts +8 -2
- package/dist/index.js +475 -474
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,304 +1,8 @@
|
|
|
1
1
|
import { __export, formatValue, isDev, rowsToCsv } from './chunk-3FSZRQQU.js';
|
|
2
|
+
import { lazy, Suspense, Component, useMemo, useReducer, useState, useRef, useCallback, useEffect } from 'react';
|
|
2
3
|
import ReactMarkdown from 'react-markdown';
|
|
3
4
|
import remarkGfm from 'remark-gfm';
|
|
4
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
|
-
import { lazy, Suspense, Component, useReducer, useState, useRef, useCallback, useEffect } from 'react';
|
|
6
|
-
|
|
7
|
-
// src/actions.ts
|
|
8
|
-
var noopAction = () => {
|
|
9
|
-
};
|
|
10
|
-
function Markdown({ children, className }) {
|
|
11
|
-
return /* @__PURE__ */ jsx("div", { className: className ?? "rk-markdown", children: /* @__PURE__ */ jsx(
|
|
12
|
-
ReactMarkdown,
|
|
13
|
-
{
|
|
14
|
-
remarkPlugins: [remarkGfm],
|
|
15
|
-
components: {
|
|
16
|
-
a: ({ node: _node, ...props }) => /* @__PURE__ */ jsx("a", { ...props, target: "_blank", rel: "noopener noreferrer" })
|
|
17
|
-
},
|
|
18
|
-
children
|
|
19
|
-
}
|
|
20
|
-
) });
|
|
21
|
-
}
|
|
22
|
-
function TextBlock({ block }) {
|
|
23
|
-
return /* @__PURE__ */ jsx("div", { className: "rk-block rk-block-text", children: /* @__PURE__ */ jsx(Markdown, { children: block.content }) });
|
|
24
|
-
}
|
|
25
|
-
var TREND_GLYPH = { UP: "\u25B2", DOWN: "\u25BC", STABLE: "\u2192" };
|
|
26
|
-
function KpiBlock({ block }) {
|
|
27
|
-
const items = Array.isArray(block.items) ? block.items : [];
|
|
28
|
-
return /* @__PURE__ */ jsxs("section", { className: "rk-block rk-block-kpi", "aria-label": block.title ?? "KPIs", children: [
|
|
29
|
-
block.title ? /* @__PURE__ */ jsx("h3", { className: "rk-block-title", children: block.title }) : null,
|
|
30
|
-
/* @__PURE__ */ jsx("div", { className: "rk-kpi-grid", children: items.map((item, i) => {
|
|
31
|
-
const display = item.formattedValue ?? formatValue(item.value);
|
|
32
|
-
const trend = item.trend;
|
|
33
|
-
return /* @__PURE__ */ jsxs("div", { className: "rk-kpi-item", children: [
|
|
34
|
-
/* @__PURE__ */ jsx("div", { className: "rk-kpi-label", children: item.label }),
|
|
35
|
-
/* @__PURE__ */ jsx("div", { className: "rk-kpi-value", children: display }),
|
|
36
|
-
trend || typeof item.percentageChange === "number" ? /* @__PURE__ */ jsxs(
|
|
37
|
-
"div",
|
|
38
|
-
{
|
|
39
|
-
className: `rk-kpi-trend rk-kpi-trend-${(trend ?? "STABLE").toLowerCase()}`,
|
|
40
|
-
children: [
|
|
41
|
-
trend ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: TREND_GLYPH[trend] }) : null,
|
|
42
|
-
typeof item.percentageChange === "number" ? /* @__PURE__ */ jsxs("span", { children: [
|
|
43
|
-
item.percentageChange > 0 ? "+" : "",
|
|
44
|
-
item.percentageChange,
|
|
45
|
-
"%"
|
|
46
|
-
] }) : null
|
|
47
|
-
]
|
|
48
|
-
}
|
|
49
|
-
) : null
|
|
50
|
-
] }, `${item.label}-${i}`);
|
|
51
|
-
}) })
|
|
52
|
-
] });
|
|
53
|
-
}
|
|
54
|
-
var ChartRenderer = lazy(() => import('./ChartRenderer-URPZESVN.js'));
|
|
55
|
-
function ChartBlock({ block }) {
|
|
56
|
-
return /* @__PURE__ */ jsxs("section", { className: "rk-block rk-block-chart", children: [
|
|
57
|
-
block.title ? /* @__PURE__ */ jsx("h3", { className: "rk-block-title", children: block.title }) : null,
|
|
58
|
-
/* @__PURE__ */ jsx(
|
|
59
|
-
Suspense,
|
|
60
|
-
{
|
|
61
|
-
fallback: /* @__PURE__ */ jsx("div", { className: "rk-chart-placeholder", "aria-busy": "true", children: "Loading chart\u2026" }),
|
|
62
|
-
children: /* @__PURE__ */ jsx(ChartRenderer, { block })
|
|
63
|
-
}
|
|
64
|
-
)
|
|
65
|
-
] });
|
|
66
|
-
}
|
|
67
|
-
function TableBlock({ block, onAction }) {
|
|
68
|
-
const columns = Array.isArray(block.columns) ? block.columns : [];
|
|
69
|
-
const rows = Array.isArray(block.rows) ? block.rows : [];
|
|
70
|
-
const download = () => onAction({
|
|
71
|
-
type: "DOWNLOAD",
|
|
72
|
-
format: "CSV",
|
|
73
|
-
filename: `${block.title ?? "table"}.csv`,
|
|
74
|
-
data: rowsToCsv(columns, rows),
|
|
75
|
-
blockId: block.id
|
|
76
|
-
});
|
|
77
|
-
return /* @__PURE__ */ jsxs("section", { className: "rk-block rk-block-table", children: [
|
|
78
|
-
/* @__PURE__ */ jsxs("div", { className: "rk-block-header", children: [
|
|
79
|
-
block.title ? /* @__PURE__ */ jsx("h3", { className: "rk-block-title", children: block.title }) : null,
|
|
80
|
-
rows.length > 0 ? /* @__PURE__ */ jsx("button", { type: "button", className: "rk-action", onClick: download, children: "Download CSV" }) : null
|
|
81
|
-
] }),
|
|
82
|
-
/* @__PURE__ */ jsxs("div", { className: "rk-table-scroll", children: [
|
|
83
|
-
/* @__PURE__ */ jsxs("table", { className: "rk-table", children: [
|
|
84
|
-
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsx("th", { scope: "col", children: col.label }, col.key)) }) }),
|
|
85
|
-
/* @__PURE__ */ jsx("tbody", { children: rows.map((row, r) => /* @__PURE__ */ jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsx("td", { children: formatValue(row[col.key]) }, col.key)) }, r)) })
|
|
86
|
-
] }),
|
|
87
|
-
rows.length === 0 ? /* @__PURE__ */ jsx("p", { className: "rk-empty", children: "No data." }) : null
|
|
88
|
-
] })
|
|
89
|
-
] });
|
|
90
|
-
}
|
|
91
|
-
var SEVERITY_GLYPH = {
|
|
92
|
-
INFO: "\u2139",
|
|
93
|
-
SUCCESS: "\u2713",
|
|
94
|
-
WARNING: "\u26A0",
|
|
95
|
-
CRITICAL: "\u2715"
|
|
96
|
-
};
|
|
97
|
-
function InsightBlock({ block }) {
|
|
98
|
-
const severity = ["INFO", "SUCCESS", "WARNING", "CRITICAL"].includes(
|
|
99
|
-
block.severity
|
|
100
|
-
) ? block.severity : "INFO";
|
|
101
|
-
return /* @__PURE__ */ jsxs(
|
|
102
|
-
"aside",
|
|
103
|
-
{
|
|
104
|
-
className: `rk-block rk-block-insight rk-severity-${severity.toLowerCase()}`,
|
|
105
|
-
role: "note",
|
|
106
|
-
children: [
|
|
107
|
-
/* @__PURE__ */ jsx("span", { className: "rk-insight-icon", "aria-hidden": true, children: SEVERITY_GLYPH[severity] }),
|
|
108
|
-
/* @__PURE__ */ jsxs("div", { className: "rk-insight-body", children: [
|
|
109
|
-
/* @__PURE__ */ jsx("div", { className: "rk-insight-title", children: block.title }),
|
|
110
|
-
/* @__PURE__ */ jsx("div", { className: "rk-insight-desc", children: block.description })
|
|
111
|
-
] })
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
function RecommendationBlock({
|
|
117
|
-
block
|
|
118
|
-
}) {
|
|
119
|
-
const items = Array.isArray(block.items) ? block.items : [];
|
|
120
|
-
return /* @__PURE__ */ jsx("section", { className: "rk-block rk-block-recommendation", children: /* @__PURE__ */ jsx("ul", { className: "rk-recommendation-list", children: items.map((item, i) => /* @__PURE__ */ jsxs("li", { className: "rk-recommendation-item", children: [
|
|
121
|
-
/* @__PURE__ */ jsx("div", { className: "rk-recommendation-title", children: item.title }),
|
|
122
|
-
/* @__PURE__ */ jsx("div", { className: "rk-recommendation-desc", children: item.description })
|
|
123
|
-
] }, `${item.title}-${i}`)) }) });
|
|
124
|
-
}
|
|
125
|
-
function FilterControl({ filter }) {
|
|
126
|
-
const options = Array.isArray(filter.options) ? filter.options : [];
|
|
127
|
-
switch (filter.filterType) {
|
|
128
|
-
case "SELECT":
|
|
129
|
-
case "MULTI_SELECT":
|
|
130
|
-
return /* @__PURE__ */ jsx("select", { disabled: true, multiple: filter.filterType === "MULTI_SELECT", "aria-label": filter.label, children: options.map((o) => /* @__PURE__ */ jsx("option", { value: o, children: o }, o)) });
|
|
131
|
-
case "DATE_RANGE":
|
|
132
|
-
return /* @__PURE__ */ jsxs("span", { className: "rk-filter-range", children: [
|
|
133
|
-
/* @__PURE__ */ jsx("input", { type: "date", disabled: true, "aria-label": `${filter.label} from` }),
|
|
134
|
-
/* @__PURE__ */ jsx("input", { type: "date", disabled: true, "aria-label": `${filter.label} to` })
|
|
135
|
-
] });
|
|
136
|
-
case "NUMBER_RANGE":
|
|
137
|
-
return /* @__PURE__ */ jsxs("span", { className: "rk-filter-range", children: [
|
|
138
|
-
/* @__PURE__ */ jsx("input", { type: "number", disabled: true, "aria-label": `${filter.label} min`, placeholder: "min" }),
|
|
139
|
-
/* @__PURE__ */ jsx("input", { type: "number", disabled: true, "aria-label": `${filter.label} max`, placeholder: "max" })
|
|
140
|
-
] });
|
|
141
|
-
case "SEARCH":
|
|
142
|
-
default:
|
|
143
|
-
return /* @__PURE__ */ jsx("input", { type: "search", disabled: true, "aria-label": filter.label, placeholder: "Search\u2026" });
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
function FilterBlock({ block }) {
|
|
147
|
-
const filters = Array.isArray(block.filters) ? block.filters : [];
|
|
148
|
-
return /* @__PURE__ */ jsx("section", { className: "rk-block rk-block-filter", "aria-label": "Filters (read-only)", children: /* @__PURE__ */ jsx("div", { className: "rk-filter-row", children: filters.map((filter, i) => /* @__PURE__ */ jsxs("label", { className: "rk-filter", children: [
|
|
149
|
-
/* @__PURE__ */ jsx("span", { className: "rk-filter-label", children: filter.label }),
|
|
150
|
-
/* @__PURE__ */ jsx(FilterControl, { filter })
|
|
151
|
-
] }, `${filter.field}-${i}`)) }) });
|
|
152
|
-
}
|
|
153
|
-
function FallbackBlock({ block }) {
|
|
154
|
-
const type = typeof block?.type === "string" ? block.type : "unknown";
|
|
155
|
-
return /* @__PURE__ */ jsxs("div", { className: "rk-block rk-block-fallback", role: "note", children: [
|
|
156
|
-
/* @__PURE__ */ jsxs("div", { className: "rk-fallback-label", children: [
|
|
157
|
-
"Unsupported block: ",
|
|
158
|
-
type
|
|
159
|
-
] }),
|
|
160
|
-
isDev() ? /* @__PURE__ */ jsxs("details", { className: "rk-fallback-raw", children: [
|
|
161
|
-
/* @__PURE__ */ jsx("summary", { children: "Raw payload (dev only)" }),
|
|
162
|
-
/* @__PURE__ */ jsx("pre", { children: safeStringify(block) })
|
|
163
|
-
] }) : null
|
|
164
|
-
] });
|
|
165
|
-
}
|
|
166
|
-
function safeStringify(value) {
|
|
167
|
-
try {
|
|
168
|
-
return JSON.stringify(value, null, 2);
|
|
169
|
-
} catch {
|
|
170
|
-
return String(value);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// src/blocks/index.ts
|
|
175
|
-
var defaultBlockComponents = {
|
|
176
|
-
TEXT: TextBlock,
|
|
177
|
-
KPI: KpiBlock,
|
|
178
|
-
CHART: ChartBlock,
|
|
179
|
-
TABLE: TableBlock,
|
|
180
|
-
INSIGHT: InsightBlock,
|
|
181
|
-
RECOMMENDATION: RecommendationBlock,
|
|
182
|
-
FILTER: FilterBlock
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
// src/registry.ts
|
|
186
|
-
var globalRegistry = /* @__PURE__ */ new Map();
|
|
187
|
-
function registerBlock(options) {
|
|
188
|
-
if (!options.override && globalRegistry.has(options.type)) return;
|
|
189
|
-
globalRegistry.set(options.type, options.component);
|
|
190
|
-
}
|
|
191
|
-
function unregisterBlock(type) {
|
|
192
|
-
globalRegistry.delete(type);
|
|
193
|
-
}
|
|
194
|
-
function registeredBlockTypes() {
|
|
195
|
-
return [...globalRegistry.keys()];
|
|
196
|
-
}
|
|
197
|
-
function resolveBlockComponent(type, overrides) {
|
|
198
|
-
return overrides?.[type] ?? globalRegistry.get(type) ?? defaultBlockComponents[type] ?? FallbackBlock;
|
|
199
|
-
}
|
|
200
|
-
var ErrorBoundary = class extends Component {
|
|
201
|
-
constructor() {
|
|
202
|
-
super(...arguments);
|
|
203
|
-
this.state = { error: null };
|
|
204
|
-
}
|
|
205
|
-
static getDerivedStateFromError(error) {
|
|
206
|
-
return { error };
|
|
207
|
-
}
|
|
208
|
-
componentDidCatch(error, info) {
|
|
209
|
-
this.props.onError?.(error, info);
|
|
210
|
-
}
|
|
211
|
-
render() {
|
|
212
|
-
if (this.state.error) return this.props.fallback(this.state.error);
|
|
213
|
-
return this.props.children;
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
function AiRenderer({
|
|
217
|
-
response,
|
|
218
|
-
components,
|
|
219
|
-
onAction = noopAction,
|
|
220
|
-
className
|
|
221
|
-
}) {
|
|
222
|
-
if (!response || typeof response !== "object" || !("type" in response)) {
|
|
223
|
-
return /* @__PURE__ */ jsx(ErrorView, { message: "No response to display." });
|
|
224
|
-
}
|
|
225
|
-
return /* @__PURE__ */ jsxs("div", { className: className ?? "rk-response", "data-response-type": response.type, children: [
|
|
226
|
-
renderBody(response, components, onAction),
|
|
227
|
-
/* @__PURE__ */ jsx(MetadataFooter, { metadata: response.metadata, onAction, responseId: response.id })
|
|
228
|
-
] });
|
|
229
|
-
}
|
|
230
|
-
function renderBody(response, components, onAction) {
|
|
231
|
-
switch (response.type) {
|
|
232
|
-
case "TEXT": {
|
|
233
|
-
const { format, value } = response.content;
|
|
234
|
-
return format === "MARKDOWN" ? /* @__PURE__ */ jsx(Markdown, { children: value }) : /* @__PURE__ */ jsx("p", { className: "rk-text-plain", children: value });
|
|
235
|
-
}
|
|
236
|
-
case "ANALYTICS": {
|
|
237
|
-
const { title, blocks } = response.content;
|
|
238
|
-
const list = Array.isArray(blocks) ? blocks : [];
|
|
239
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
240
|
-
title ? /* @__PURE__ */ jsx("h2", { className: "rk-response-title", children: title }) : null,
|
|
241
|
-
/* @__PURE__ */ jsx("div", { className: "rk-blocks", children: list.map((block, i) => /* @__PURE__ */ jsx(
|
|
242
|
-
BlockSlot,
|
|
243
|
-
{
|
|
244
|
-
block,
|
|
245
|
-
components,
|
|
246
|
-
onAction
|
|
247
|
-
},
|
|
248
|
-
blockKey(block, i)
|
|
249
|
-
)) })
|
|
250
|
-
] });
|
|
251
|
-
}
|
|
252
|
-
case "ERROR":
|
|
253
|
-
return /* @__PURE__ */ jsx(ErrorView, { message: response.content.message });
|
|
254
|
-
default:
|
|
255
|
-
return /* @__PURE__ */ jsx(ErrorView, { message: "Unsupported response type." });
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
function BlockSlot({
|
|
259
|
-
block,
|
|
260
|
-
components,
|
|
261
|
-
onAction
|
|
262
|
-
}) {
|
|
263
|
-
const type = typeof block?.type === "string" ? block.type : "UNKNOWN";
|
|
264
|
-
const Component2 = resolveBlockComponent(type, components);
|
|
265
|
-
return /* @__PURE__ */ jsx(ErrorBoundary, { fallback: () => /* @__PURE__ */ jsx(FallbackBlock, { block, onAction }), children: /* @__PURE__ */ jsx(Component2, { block, onAction }) });
|
|
266
|
-
}
|
|
267
|
-
function ErrorView({ message }) {
|
|
268
|
-
return /* @__PURE__ */ jsxs("div", { className: "rk-block rk-error", role: "alert", children: [
|
|
269
|
-
/* @__PURE__ */ jsx("span", { className: "rk-error-icon", "aria-hidden": true, children: "\u2715" }),
|
|
270
|
-
/* @__PURE__ */ jsx("span", { className: "rk-error-message", children: message })
|
|
271
|
-
] });
|
|
272
|
-
}
|
|
273
|
-
function MetadataFooter({
|
|
274
|
-
metadata,
|
|
275
|
-
onAction,
|
|
276
|
-
responseId
|
|
277
|
-
}) {
|
|
278
|
-
if (!metadata) return null;
|
|
279
|
-
const { generatedAt, dataSource, refreshable } = metadata;
|
|
280
|
-
if (!generatedAt && !dataSource && !refreshable) return null;
|
|
281
|
-
return /* @__PURE__ */ jsxs("footer", { className: "rk-meta", children: [
|
|
282
|
-
generatedAt ? /* @__PURE__ */ jsx("span", { className: "rk-meta-time", children: formatTime(generatedAt) }) : null,
|
|
283
|
-
dataSource ? /* @__PURE__ */ jsx("span", { className: "rk-meta-source", children: dataSource }) : null,
|
|
284
|
-
refreshable ? /* @__PURE__ */ jsx(
|
|
285
|
-
"button",
|
|
286
|
-
{
|
|
287
|
-
type: "button",
|
|
288
|
-
className: "rk-action rk-meta-refresh",
|
|
289
|
-
onClick: () => onAction({ type: "REFRESH", responseId }),
|
|
290
|
-
children: "Refresh"
|
|
291
|
-
}
|
|
292
|
-
) : null
|
|
293
|
-
] });
|
|
294
|
-
}
|
|
295
|
-
function formatTime(iso) {
|
|
296
|
-
const d = new Date(iso);
|
|
297
|
-
return Number.isNaN(d.getTime()) ? iso : d.toLocaleString();
|
|
298
|
-
}
|
|
299
|
-
function blockKey(block, index) {
|
|
300
|
-
return typeof block?.id === "string" && block.id ? block.id : `block-${index}`;
|
|
301
|
-
}
|
|
302
6
|
|
|
303
7
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
304
8
|
var external_exports = {};
|
|
@@ -4453,198 +4157,495 @@ var toUnknownBlock = (raw) => {
|
|
|
4453
4157
|
type: typeof obj.type === "string" ? obj.type : "UNKNOWN"
|
|
4454
4158
|
};
|
|
4455
4159
|
};
|
|
4456
|
-
var blockSchema = external_exports.union([
|
|
4457
|
-
knownBlockSchema,
|
|
4458
|
-
external_exports.any().transform(toUnknownBlock)
|
|
4459
|
-
]);
|
|
4460
|
-
var textResponseSchema = external_exports.object({
|
|
4461
|
-
id: external_exports.string(),
|
|
4462
|
-
type: external_exports.literal("TEXT"),
|
|
4463
|
-
content: external_exports.object({ format: textFormatSchema, value: external_exports.string() }),
|
|
4464
|
-
metadata: responseMetadataSchema.optional()
|
|
4465
|
-
});
|
|
4466
|
-
var analyticsResponseSchema = external_exports.object({
|
|
4467
|
-
id: external_exports.string(),
|
|
4468
|
-
type: external_exports.literal("ANALYTICS"),
|
|
4469
|
-
content: external_exports.object({
|
|
4470
|
-
title: external_exports.string().optional(),
|
|
4471
|
-
// Use the lenient block schema so one malformed block can't sink the whole response.
|
|
4472
|
-
blocks: external_exports.array(blockSchema)
|
|
4473
|
-
}),
|
|
4474
|
-
metadata: responseMetadataSchema.optional()
|
|
4475
|
-
});
|
|
4476
|
-
var errorResponseSchema = external_exports.object({
|
|
4477
|
-
id: external_exports.string(),
|
|
4478
|
-
type: external_exports.literal("ERROR"),
|
|
4479
|
-
content: external_exports.object({ message: external_exports.string() }),
|
|
4480
|
-
metadata: responseMetadataSchema.optional()
|
|
4481
|
-
});
|
|
4482
|
-
var aiResponseSchema = external_exports.discriminatedUnion("type", [
|
|
4483
|
-
textResponseSchema,
|
|
4484
|
-
analyticsResponseSchema,
|
|
4485
|
-
errorResponseSchema
|
|
4486
|
-
]);
|
|
4487
|
-
var makeErrorResponse = (message, id) => ({
|
|
4488
|
-
id: id ?? genId("error"),
|
|
4489
|
-
type: "ERROR",
|
|
4490
|
-
content: { message }
|
|
4491
|
-
});
|
|
4492
|
-
function parseAiResponse(input) {
|
|
4493
|
-
const result = aiResponseSchema.safeParse(input);
|
|
4494
|
-
if (result.success) return result.data;
|
|
4495
|
-
return makeErrorResponse(
|
|
4496
|
-
"The response could not be displayed (it did not match the expected format)."
|
|
4160
|
+
var blockSchema = external_exports.union([
|
|
4161
|
+
knownBlockSchema,
|
|
4162
|
+
external_exports.any().transform(toUnknownBlock)
|
|
4163
|
+
]);
|
|
4164
|
+
var textResponseSchema = external_exports.object({
|
|
4165
|
+
id: external_exports.string(),
|
|
4166
|
+
type: external_exports.literal("TEXT"),
|
|
4167
|
+
content: external_exports.object({ format: textFormatSchema, value: external_exports.string() }),
|
|
4168
|
+
metadata: responseMetadataSchema.optional()
|
|
4169
|
+
});
|
|
4170
|
+
var analyticsResponseSchema = external_exports.object({
|
|
4171
|
+
id: external_exports.string(),
|
|
4172
|
+
type: external_exports.literal("ANALYTICS"),
|
|
4173
|
+
content: external_exports.object({
|
|
4174
|
+
title: external_exports.string().optional(),
|
|
4175
|
+
// Use the lenient block schema so one malformed block can't sink the whole response.
|
|
4176
|
+
blocks: external_exports.array(blockSchema)
|
|
4177
|
+
}),
|
|
4178
|
+
metadata: responseMetadataSchema.optional()
|
|
4179
|
+
});
|
|
4180
|
+
var errorResponseSchema = external_exports.object({
|
|
4181
|
+
id: external_exports.string(),
|
|
4182
|
+
type: external_exports.literal("ERROR"),
|
|
4183
|
+
content: external_exports.object({ message: external_exports.string() }),
|
|
4184
|
+
metadata: responseMetadataSchema.optional()
|
|
4185
|
+
});
|
|
4186
|
+
var aiResponseSchema = external_exports.discriminatedUnion("type", [
|
|
4187
|
+
textResponseSchema,
|
|
4188
|
+
analyticsResponseSchema,
|
|
4189
|
+
errorResponseSchema
|
|
4190
|
+
]);
|
|
4191
|
+
var makeErrorResponse = (message, id) => ({
|
|
4192
|
+
id: id ?? genId("error"),
|
|
4193
|
+
type: "ERROR",
|
|
4194
|
+
content: { message }
|
|
4195
|
+
});
|
|
4196
|
+
function parseAiResponse(input) {
|
|
4197
|
+
const result = aiResponseSchema.safeParse(input);
|
|
4198
|
+
if (result.success) return result.data;
|
|
4199
|
+
return makeErrorResponse(
|
|
4200
|
+
"The response could not be displayed (it did not match the expected format)."
|
|
4201
|
+
);
|
|
4202
|
+
}
|
|
4203
|
+
function safeParseAiResponse(input) {
|
|
4204
|
+
return aiResponseSchema.safeParse(input);
|
|
4205
|
+
}
|
|
4206
|
+
function parseBlock(input) {
|
|
4207
|
+
return blockSchema.parse(input);
|
|
4208
|
+
}
|
|
4209
|
+
var progressEventSchema = external_exports.object({
|
|
4210
|
+
phase: progressPhaseSchema,
|
|
4211
|
+
message: external_exports.string().optional(),
|
|
4212
|
+
tool: external_exports.string().optional()
|
|
4213
|
+
});
|
|
4214
|
+
var responseStartSchema = external_exports.object({
|
|
4215
|
+
id: external_exports.string(),
|
|
4216
|
+
type: responseTypeSchema,
|
|
4217
|
+
metadata: responseMetadataSchema.optional(),
|
|
4218
|
+
title: external_exports.string().optional()
|
|
4219
|
+
});
|
|
4220
|
+
var contentEventSchema = external_exports.object({
|
|
4221
|
+
format: textFormatSchema.optional(),
|
|
4222
|
+
value: external_exports.string().optional(),
|
|
4223
|
+
message: external_exports.string().optional()
|
|
4224
|
+
});
|
|
4225
|
+
var responseEndSchema = external_exports.object({
|
|
4226
|
+
status: external_exports.enum(["COMPLETED", "ERROR"])
|
|
4227
|
+
});
|
|
4228
|
+
var errorEventSchema = external_exports.object({
|
|
4229
|
+
message: external_exports.string().optional()
|
|
4230
|
+
});
|
|
4231
|
+
function parseSseEvent(eventName, raw) {
|
|
4232
|
+
let json;
|
|
4233
|
+
try {
|
|
4234
|
+
json = raw.length ? JSON.parse(raw) : {};
|
|
4235
|
+
} catch {
|
|
4236
|
+
return { event: "error", data: { message: "Malformed event payload from server." } };
|
|
4237
|
+
}
|
|
4238
|
+
switch (eventName) {
|
|
4239
|
+
case "progress": {
|
|
4240
|
+
const r = progressEventSchema.safeParse(json);
|
|
4241
|
+
return r.success ? { event: "progress", data: r.data } : { event: "progress", data: { phase: "THINKING" } };
|
|
4242
|
+
}
|
|
4243
|
+
case "response_start": {
|
|
4244
|
+
const r = responseStartSchema.safeParse(json);
|
|
4245
|
+
return r.success ? { event: "response_start", data: r.data } : { event: "error", data: { message: "Invalid response_start event." } };
|
|
4246
|
+
}
|
|
4247
|
+
case "content": {
|
|
4248
|
+
const r = contentEventSchema.safeParse(json);
|
|
4249
|
+
return r.success ? { event: "content", data: r.data } : { event: "content", data: {} };
|
|
4250
|
+
}
|
|
4251
|
+
case "block":
|
|
4252
|
+
return { event: "block", data: blockSchema.parse(json) };
|
|
4253
|
+
case "response_end": {
|
|
4254
|
+
const r = responseEndSchema.safeParse(json);
|
|
4255
|
+
return r.success ? { event: "response_end", data: r.data } : { event: "response_end", data: { status: "COMPLETED" } };
|
|
4256
|
+
}
|
|
4257
|
+
case "error":
|
|
4258
|
+
default: {
|
|
4259
|
+
const r = errorEventSchema.safeParse(json);
|
|
4260
|
+
return { event: "error", data: r.success ? r.data : {} };
|
|
4261
|
+
}
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
var initialStreamState = { phase: "idle" };
|
|
4265
|
+
function startResponse(data) {
|
|
4266
|
+
const type = data.type;
|
|
4267
|
+
const base = { id: data.id, metadata: data.metadata };
|
|
4268
|
+
switch (type) {
|
|
4269
|
+
case "ANALYTICS":
|
|
4270
|
+
return { ...base, type: "ANALYTICS", content: { title: data.title, blocks: [] } };
|
|
4271
|
+
case "ERROR":
|
|
4272
|
+
return { ...base, type: "ERROR", content: { message: "" } };
|
|
4273
|
+
case "TEXT":
|
|
4274
|
+
default:
|
|
4275
|
+
return { ...base, type: "TEXT", content: { format: "PLAIN_TEXT", value: "" } };
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4278
|
+
function streamReducer(state, event) {
|
|
4279
|
+
switch (event.event) {
|
|
4280
|
+
case "progress":
|
|
4281
|
+
return {
|
|
4282
|
+
...state,
|
|
4283
|
+
phase: event.data.phase,
|
|
4284
|
+
progressMessage: event.data.message ?? state.progressMessage,
|
|
4285
|
+
tool: event.data.tool
|
|
4286
|
+
};
|
|
4287
|
+
case "response_start":
|
|
4288
|
+
return {
|
|
4289
|
+
...state,
|
|
4290
|
+
phase: "COMPOSING",
|
|
4291
|
+
tool: void 0,
|
|
4292
|
+
response: startResponse(event.data),
|
|
4293
|
+
error: void 0
|
|
4294
|
+
};
|
|
4295
|
+
case "content": {
|
|
4296
|
+
const response = state.response;
|
|
4297
|
+
if (!response) return state;
|
|
4298
|
+
if (response.type === "TEXT") {
|
|
4299
|
+
return {
|
|
4300
|
+
...state,
|
|
4301
|
+
response: {
|
|
4302
|
+
...response,
|
|
4303
|
+
content: {
|
|
4304
|
+
format: event.data.format ?? response.content.format,
|
|
4305
|
+
value: event.data.value ?? response.content.value
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
};
|
|
4309
|
+
}
|
|
4310
|
+
if (response.type === "ERROR") {
|
|
4311
|
+
return {
|
|
4312
|
+
...state,
|
|
4313
|
+
response: {
|
|
4314
|
+
...response,
|
|
4315
|
+
content: { message: event.data.message ?? response.content.message }
|
|
4316
|
+
}
|
|
4317
|
+
};
|
|
4318
|
+
}
|
|
4319
|
+
return state;
|
|
4320
|
+
}
|
|
4321
|
+
case "block": {
|
|
4322
|
+
const response = state.response;
|
|
4323
|
+
if (!response || response.type !== "ANALYTICS") return state;
|
|
4324
|
+
return {
|
|
4325
|
+
...state,
|
|
4326
|
+
response: {
|
|
4327
|
+
...response,
|
|
4328
|
+
content: {
|
|
4329
|
+
...response.content,
|
|
4330
|
+
blocks: [...response.content.blocks, event.data]
|
|
4331
|
+
}
|
|
4332
|
+
}
|
|
4333
|
+
};
|
|
4334
|
+
}
|
|
4335
|
+
case "response_end": {
|
|
4336
|
+
if (event.data.status === "ERROR") {
|
|
4337
|
+
const message = state.response?.type === "ERROR" && state.response.content.message || state.error || "The request failed.";
|
|
4338
|
+
return { ...state, phase: "error", error: message };
|
|
4339
|
+
}
|
|
4340
|
+
return { ...state, phase: "done", progressMessage: void 0, tool: void 0 };
|
|
4341
|
+
}
|
|
4342
|
+
case "error":
|
|
4343
|
+
return {
|
|
4344
|
+
...state,
|
|
4345
|
+
phase: "error",
|
|
4346
|
+
error: event.data.message ?? "The stream encountered a fatal error."
|
|
4347
|
+
};
|
|
4348
|
+
default:
|
|
4349
|
+
return state;
|
|
4350
|
+
}
|
|
4351
|
+
}
|
|
4352
|
+
|
|
4353
|
+
// src/actions.ts
|
|
4354
|
+
var noopAction = () => {
|
|
4355
|
+
};
|
|
4356
|
+
function Markdown({ children, className }) {
|
|
4357
|
+
return /* @__PURE__ */ jsx("div", { className: className ?? "rk-markdown", children: /* @__PURE__ */ jsx(
|
|
4358
|
+
ReactMarkdown,
|
|
4359
|
+
{
|
|
4360
|
+
remarkPlugins: [remarkGfm],
|
|
4361
|
+
components: {
|
|
4362
|
+
a: ({ node: _node, ...props }) => /* @__PURE__ */ jsx("a", { ...props, target: "_blank", rel: "noopener noreferrer" })
|
|
4363
|
+
},
|
|
4364
|
+
children
|
|
4365
|
+
}
|
|
4366
|
+
) });
|
|
4367
|
+
}
|
|
4368
|
+
function TextBlock({ block }) {
|
|
4369
|
+
return /* @__PURE__ */ jsx("div", { className: "rk-block rk-block-text", children: /* @__PURE__ */ jsx(Markdown, { children: block.content }) });
|
|
4370
|
+
}
|
|
4371
|
+
var TREND_GLYPH = { UP: "\u25B2", DOWN: "\u25BC", STABLE: "\u2192" };
|
|
4372
|
+
function KpiBlock({ block }) {
|
|
4373
|
+
const items = Array.isArray(block.items) ? block.items : [];
|
|
4374
|
+
return /* @__PURE__ */ jsxs("section", { className: "rk-block rk-block-kpi", "aria-label": block.title ?? "KPIs", children: [
|
|
4375
|
+
block.title ? /* @__PURE__ */ jsx("h3", { className: "rk-block-title", children: block.title }) : null,
|
|
4376
|
+
/* @__PURE__ */ jsx("div", { className: "rk-kpi-grid", children: items.map((item, i) => {
|
|
4377
|
+
const display = item.formattedValue ?? formatValue(item.value);
|
|
4378
|
+
const trend = item.trend;
|
|
4379
|
+
return /* @__PURE__ */ jsxs("div", { className: "rk-kpi-item", children: [
|
|
4380
|
+
/* @__PURE__ */ jsx("div", { className: "rk-kpi-label", children: item.label }),
|
|
4381
|
+
/* @__PURE__ */ jsx("div", { className: "rk-kpi-value", children: display }),
|
|
4382
|
+
trend || typeof item.percentageChange === "number" ? /* @__PURE__ */ jsxs(
|
|
4383
|
+
"div",
|
|
4384
|
+
{
|
|
4385
|
+
className: `rk-kpi-trend rk-kpi-trend-${(trend ?? "STABLE").toLowerCase()}`,
|
|
4386
|
+
children: [
|
|
4387
|
+
trend ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: TREND_GLYPH[trend] }) : null,
|
|
4388
|
+
typeof item.percentageChange === "number" ? /* @__PURE__ */ jsxs("span", { children: [
|
|
4389
|
+
item.percentageChange > 0 ? "+" : "",
|
|
4390
|
+
item.percentageChange,
|
|
4391
|
+
"%"
|
|
4392
|
+
] }) : null
|
|
4393
|
+
]
|
|
4394
|
+
}
|
|
4395
|
+
) : null
|
|
4396
|
+
] }, `${item.label}-${i}`);
|
|
4397
|
+
}) })
|
|
4398
|
+
] });
|
|
4399
|
+
}
|
|
4400
|
+
var ChartRenderer = lazy(() => import('./ChartRenderer-URPZESVN.js'));
|
|
4401
|
+
function ChartBlock({ block }) {
|
|
4402
|
+
return /* @__PURE__ */ jsxs("section", { className: "rk-block rk-block-chart", children: [
|
|
4403
|
+
block.title ? /* @__PURE__ */ jsx("h3", { className: "rk-block-title", children: block.title }) : null,
|
|
4404
|
+
/* @__PURE__ */ jsx(
|
|
4405
|
+
Suspense,
|
|
4406
|
+
{
|
|
4407
|
+
fallback: /* @__PURE__ */ jsx("div", { className: "rk-chart-placeholder", "aria-busy": "true", children: "Loading chart\u2026" }),
|
|
4408
|
+
children: /* @__PURE__ */ jsx(ChartRenderer, { block })
|
|
4409
|
+
}
|
|
4410
|
+
)
|
|
4411
|
+
] });
|
|
4412
|
+
}
|
|
4413
|
+
function TableBlock({ block, onAction }) {
|
|
4414
|
+
const columns = Array.isArray(block.columns) ? block.columns : [];
|
|
4415
|
+
const rows = Array.isArray(block.rows) ? block.rows : [];
|
|
4416
|
+
const download = () => onAction({
|
|
4417
|
+
type: "DOWNLOAD",
|
|
4418
|
+
format: "CSV",
|
|
4419
|
+
filename: `${block.title ?? "table"}.csv`,
|
|
4420
|
+
data: rowsToCsv(columns, rows),
|
|
4421
|
+
blockId: block.id
|
|
4422
|
+
});
|
|
4423
|
+
return /* @__PURE__ */ jsxs("section", { className: "rk-block rk-block-table", children: [
|
|
4424
|
+
/* @__PURE__ */ jsxs("div", { className: "rk-block-header", children: [
|
|
4425
|
+
block.title ? /* @__PURE__ */ jsx("h3", { className: "rk-block-title", children: block.title }) : null,
|
|
4426
|
+
rows.length > 0 ? /* @__PURE__ */ jsx("button", { type: "button", className: "rk-action", onClick: download, children: "Download CSV" }) : null
|
|
4427
|
+
] }),
|
|
4428
|
+
/* @__PURE__ */ jsxs("div", { className: "rk-table-scroll", children: [
|
|
4429
|
+
/* @__PURE__ */ jsxs("table", { className: "rk-table", children: [
|
|
4430
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsx("th", { scope: "col", children: col.label }, col.key)) }) }),
|
|
4431
|
+
/* @__PURE__ */ jsx("tbody", { children: rows.map((row, r) => /* @__PURE__ */ jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsx("td", { children: formatValue(row[col.key]) }, col.key)) }, r)) })
|
|
4432
|
+
] }),
|
|
4433
|
+
rows.length === 0 ? /* @__PURE__ */ jsx("p", { className: "rk-empty", children: "No data." }) : null
|
|
4434
|
+
] })
|
|
4435
|
+
] });
|
|
4436
|
+
}
|
|
4437
|
+
var SEVERITY_GLYPH = {
|
|
4438
|
+
INFO: "\u2139",
|
|
4439
|
+
SUCCESS: "\u2713",
|
|
4440
|
+
WARNING: "\u26A0",
|
|
4441
|
+
CRITICAL: "\u2715"
|
|
4442
|
+
};
|
|
4443
|
+
function InsightBlock({ block }) {
|
|
4444
|
+
const severity = ["INFO", "SUCCESS", "WARNING", "CRITICAL"].includes(
|
|
4445
|
+
block.severity
|
|
4446
|
+
) ? block.severity : "INFO";
|
|
4447
|
+
return /* @__PURE__ */ jsxs(
|
|
4448
|
+
"aside",
|
|
4449
|
+
{
|
|
4450
|
+
className: `rk-block rk-block-insight rk-severity-${severity.toLowerCase()}`,
|
|
4451
|
+
role: "note",
|
|
4452
|
+
children: [
|
|
4453
|
+
/* @__PURE__ */ jsx("span", { className: "rk-insight-icon", "aria-hidden": true, children: SEVERITY_GLYPH[severity] }),
|
|
4454
|
+
/* @__PURE__ */ jsxs("div", { className: "rk-insight-body", children: [
|
|
4455
|
+
/* @__PURE__ */ jsx("div", { className: "rk-insight-title", children: block.title }),
|
|
4456
|
+
/* @__PURE__ */ jsx("div", { className: "rk-insight-desc", children: block.description })
|
|
4457
|
+
] })
|
|
4458
|
+
]
|
|
4459
|
+
}
|
|
4497
4460
|
);
|
|
4498
4461
|
}
|
|
4499
|
-
function
|
|
4500
|
-
|
|
4462
|
+
function RecommendationBlock({
|
|
4463
|
+
block
|
|
4464
|
+
}) {
|
|
4465
|
+
const items = Array.isArray(block.items) ? block.items : [];
|
|
4466
|
+
return /* @__PURE__ */ jsx("section", { className: "rk-block rk-block-recommendation", children: /* @__PURE__ */ jsx("ul", { className: "rk-recommendation-list", children: items.map((item, i) => /* @__PURE__ */ jsxs("li", { className: "rk-recommendation-item", children: [
|
|
4467
|
+
/* @__PURE__ */ jsx("div", { className: "rk-recommendation-title", children: item.title }),
|
|
4468
|
+
/* @__PURE__ */ jsx("div", { className: "rk-recommendation-desc", children: item.description })
|
|
4469
|
+
] }, `${item.title}-${i}`)) }) });
|
|
4501
4470
|
}
|
|
4502
|
-
function
|
|
4503
|
-
|
|
4471
|
+
function FilterControl({ filter }) {
|
|
4472
|
+
const options = Array.isArray(filter.options) ? filter.options : [];
|
|
4473
|
+
switch (filter.filterType) {
|
|
4474
|
+
case "SELECT":
|
|
4475
|
+
case "MULTI_SELECT":
|
|
4476
|
+
return /* @__PURE__ */ jsx("select", { disabled: true, multiple: filter.filterType === "MULTI_SELECT", "aria-label": filter.label, children: options.map((o) => /* @__PURE__ */ jsx("option", { value: o, children: o }, o)) });
|
|
4477
|
+
case "DATE_RANGE":
|
|
4478
|
+
return /* @__PURE__ */ jsxs("span", { className: "rk-filter-range", children: [
|
|
4479
|
+
/* @__PURE__ */ jsx("input", { type: "date", disabled: true, "aria-label": `${filter.label} from` }),
|
|
4480
|
+
/* @__PURE__ */ jsx("input", { type: "date", disabled: true, "aria-label": `${filter.label} to` })
|
|
4481
|
+
] });
|
|
4482
|
+
case "NUMBER_RANGE":
|
|
4483
|
+
return /* @__PURE__ */ jsxs("span", { className: "rk-filter-range", children: [
|
|
4484
|
+
/* @__PURE__ */ jsx("input", { type: "number", disabled: true, "aria-label": `${filter.label} min`, placeholder: "min" }),
|
|
4485
|
+
/* @__PURE__ */ jsx("input", { type: "number", disabled: true, "aria-label": `${filter.label} max`, placeholder: "max" })
|
|
4486
|
+
] });
|
|
4487
|
+
case "SEARCH":
|
|
4488
|
+
default:
|
|
4489
|
+
return /* @__PURE__ */ jsx("input", { type: "search", disabled: true, "aria-label": filter.label, placeholder: "Search\u2026" });
|
|
4490
|
+
}
|
|
4491
|
+
}
|
|
4492
|
+
function FilterBlock({ block }) {
|
|
4493
|
+
const filters = Array.isArray(block.filters) ? block.filters : [];
|
|
4494
|
+
return /* @__PURE__ */ jsx("section", { className: "rk-block rk-block-filter", "aria-label": "Filters (read-only)", children: /* @__PURE__ */ jsx("div", { className: "rk-filter-row", children: filters.map((filter, i) => /* @__PURE__ */ jsxs("label", { className: "rk-filter", children: [
|
|
4495
|
+
/* @__PURE__ */ jsx("span", { className: "rk-filter-label", children: filter.label }),
|
|
4496
|
+
/* @__PURE__ */ jsx(FilterControl, { filter })
|
|
4497
|
+
] }, `${filter.field}-${i}`)) }) });
|
|
4498
|
+
}
|
|
4499
|
+
function FallbackBlock({ block }) {
|
|
4500
|
+
const type = typeof block?.type === "string" ? block.type : "unknown";
|
|
4501
|
+
return /* @__PURE__ */ jsxs("div", { className: "rk-block rk-block-fallback", role: "note", children: [
|
|
4502
|
+
/* @__PURE__ */ jsxs("div", { className: "rk-fallback-label", children: [
|
|
4503
|
+
"Unsupported block: ",
|
|
4504
|
+
type
|
|
4505
|
+
] }),
|
|
4506
|
+
isDev() ? /* @__PURE__ */ jsxs("details", { className: "rk-fallback-raw", children: [
|
|
4507
|
+
/* @__PURE__ */ jsx("summary", { children: "Raw payload (dev only)" }),
|
|
4508
|
+
/* @__PURE__ */ jsx("pre", { children: safeStringify(block) })
|
|
4509
|
+
] }) : null
|
|
4510
|
+
] });
|
|
4504
4511
|
}
|
|
4505
|
-
|
|
4506
|
-
phase: progressPhaseSchema,
|
|
4507
|
-
message: external_exports.string().optional(),
|
|
4508
|
-
tool: external_exports.string().optional()
|
|
4509
|
-
});
|
|
4510
|
-
var responseStartSchema = external_exports.object({
|
|
4511
|
-
id: external_exports.string(),
|
|
4512
|
-
type: responseTypeSchema,
|
|
4513
|
-
metadata: responseMetadataSchema.optional(),
|
|
4514
|
-
title: external_exports.string().optional()
|
|
4515
|
-
});
|
|
4516
|
-
var contentEventSchema = external_exports.object({
|
|
4517
|
-
format: textFormatSchema.optional(),
|
|
4518
|
-
value: external_exports.string().optional(),
|
|
4519
|
-
message: external_exports.string().optional()
|
|
4520
|
-
});
|
|
4521
|
-
var responseEndSchema = external_exports.object({
|
|
4522
|
-
status: external_exports.enum(["COMPLETED", "ERROR"])
|
|
4523
|
-
});
|
|
4524
|
-
var errorEventSchema = external_exports.object({
|
|
4525
|
-
message: external_exports.string().optional()
|
|
4526
|
-
});
|
|
4527
|
-
function parseSseEvent(eventName, raw) {
|
|
4528
|
-
let json;
|
|
4512
|
+
function safeStringify(value) {
|
|
4529
4513
|
try {
|
|
4530
|
-
|
|
4514
|
+
return JSON.stringify(value, null, 2);
|
|
4531
4515
|
} catch {
|
|
4532
|
-
return
|
|
4533
|
-
}
|
|
4534
|
-
switch (eventName) {
|
|
4535
|
-
case "progress": {
|
|
4536
|
-
const r = progressEventSchema.safeParse(json);
|
|
4537
|
-
return r.success ? { event: "progress", data: r.data } : { event: "progress", data: { phase: "THINKING" } };
|
|
4538
|
-
}
|
|
4539
|
-
case "response_start": {
|
|
4540
|
-
const r = responseStartSchema.safeParse(json);
|
|
4541
|
-
return r.success ? { event: "response_start", data: r.data } : { event: "error", data: { message: "Invalid response_start event." } };
|
|
4542
|
-
}
|
|
4543
|
-
case "content": {
|
|
4544
|
-
const r = contentEventSchema.safeParse(json);
|
|
4545
|
-
return r.success ? { event: "content", data: r.data } : { event: "content", data: {} };
|
|
4546
|
-
}
|
|
4547
|
-
case "block":
|
|
4548
|
-
return { event: "block", data: blockSchema.parse(json) };
|
|
4549
|
-
case "response_end": {
|
|
4550
|
-
const r = responseEndSchema.safeParse(json);
|
|
4551
|
-
return r.success ? { event: "response_end", data: r.data } : { event: "response_end", data: { status: "COMPLETED" } };
|
|
4552
|
-
}
|
|
4553
|
-
case "error":
|
|
4554
|
-
default: {
|
|
4555
|
-
const r = errorEventSchema.safeParse(json);
|
|
4556
|
-
return { event: "error", data: r.success ? r.data : {} };
|
|
4557
|
-
}
|
|
4516
|
+
return String(value);
|
|
4558
4517
|
}
|
|
4559
4518
|
}
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4519
|
+
|
|
4520
|
+
// src/blocks/index.ts
|
|
4521
|
+
var defaultBlockComponents = {
|
|
4522
|
+
TEXT: TextBlock,
|
|
4523
|
+
KPI: KpiBlock,
|
|
4524
|
+
CHART: ChartBlock,
|
|
4525
|
+
TABLE: TableBlock,
|
|
4526
|
+
INSIGHT: InsightBlock,
|
|
4527
|
+
RECOMMENDATION: RecommendationBlock,
|
|
4528
|
+
FILTER: FilterBlock
|
|
4529
|
+
};
|
|
4530
|
+
|
|
4531
|
+
// src/registry.ts
|
|
4532
|
+
var globalRegistry = /* @__PURE__ */ new Map();
|
|
4533
|
+
function registerBlock(options) {
|
|
4534
|
+
if (!options.override && globalRegistry.has(options.type)) return;
|
|
4535
|
+
globalRegistry.set(options.type, options.component);
|
|
4536
|
+
}
|
|
4537
|
+
function unregisterBlock(type) {
|
|
4538
|
+
globalRegistry.delete(type);
|
|
4539
|
+
}
|
|
4540
|
+
function registeredBlockTypes() {
|
|
4541
|
+
return [...globalRegistry.keys()];
|
|
4542
|
+
}
|
|
4543
|
+
function resolveBlockComponent(type, overrides) {
|
|
4544
|
+
return overrides?.[type] ?? globalRegistry.get(type) ?? defaultBlockComponents[type] ?? FallbackBlock;
|
|
4545
|
+
}
|
|
4546
|
+
var ErrorBoundary = class extends Component {
|
|
4547
|
+
constructor() {
|
|
4548
|
+
super(...arguments);
|
|
4549
|
+
this.state = { error: null };
|
|
4550
|
+
}
|
|
4551
|
+
static getDerivedStateFromError(error) {
|
|
4552
|
+
return { error };
|
|
4553
|
+
}
|
|
4554
|
+
componentDidCatch(error, info) {
|
|
4555
|
+
this.props.onError?.(error, info);
|
|
4556
|
+
}
|
|
4557
|
+
render() {
|
|
4558
|
+
if (this.state.error) return this.props.fallback(this.state.error);
|
|
4559
|
+
return this.props.children;
|
|
4560
|
+
}
|
|
4561
|
+
};
|
|
4562
|
+
function AiRenderer({
|
|
4563
|
+
response,
|
|
4564
|
+
components,
|
|
4565
|
+
onAction = noopAction,
|
|
4566
|
+
className
|
|
4567
|
+
}) {
|
|
4568
|
+
const parsed = useMemo(() => parseAiResponse(response), [response]);
|
|
4569
|
+
if (response == null) {
|
|
4570
|
+
return /* @__PURE__ */ jsx(ErrorView, { message: "No response to display." });
|
|
4572
4571
|
}
|
|
4572
|
+
return /* @__PURE__ */ jsxs("div", { className: className ?? "rk-response", "data-response-type": parsed.type, children: [
|
|
4573
|
+
renderBody(parsed, components, onAction),
|
|
4574
|
+
/* @__PURE__ */ jsx(MetadataFooter, { metadata: parsed.metadata, onAction, responseId: parsed.id })
|
|
4575
|
+
] });
|
|
4573
4576
|
}
|
|
4574
|
-
function
|
|
4575
|
-
switch (
|
|
4576
|
-
case "
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
phase: event.data.phase,
|
|
4580
|
-
progressMessage: event.data.message ?? state.progressMessage,
|
|
4581
|
-
tool: event.data.tool
|
|
4582
|
-
};
|
|
4583
|
-
case "response_start":
|
|
4584
|
-
return {
|
|
4585
|
-
...state,
|
|
4586
|
-
phase: "COMPOSING",
|
|
4587
|
-
tool: void 0,
|
|
4588
|
-
response: startResponse(event.data),
|
|
4589
|
-
error: void 0
|
|
4590
|
-
};
|
|
4591
|
-
case "content": {
|
|
4592
|
-
const response = state.response;
|
|
4593
|
-
if (!response) return state;
|
|
4594
|
-
if (response.type === "TEXT") {
|
|
4595
|
-
return {
|
|
4596
|
-
...state,
|
|
4597
|
-
response: {
|
|
4598
|
-
...response,
|
|
4599
|
-
content: {
|
|
4600
|
-
format: event.data.format ?? response.content.format,
|
|
4601
|
-
value: event.data.value ?? response.content.value
|
|
4602
|
-
}
|
|
4603
|
-
}
|
|
4604
|
-
};
|
|
4605
|
-
}
|
|
4606
|
-
if (response.type === "ERROR") {
|
|
4607
|
-
return {
|
|
4608
|
-
...state,
|
|
4609
|
-
response: {
|
|
4610
|
-
...response,
|
|
4611
|
-
content: { message: event.data.message ?? response.content.message }
|
|
4612
|
-
}
|
|
4613
|
-
};
|
|
4614
|
-
}
|
|
4615
|
-
return state;
|
|
4616
|
-
}
|
|
4617
|
-
case "block": {
|
|
4618
|
-
const response = state.response;
|
|
4619
|
-
if (!response || response.type !== "ANALYTICS") return state;
|
|
4620
|
-
return {
|
|
4621
|
-
...state,
|
|
4622
|
-
response: {
|
|
4623
|
-
...response,
|
|
4624
|
-
content: {
|
|
4625
|
-
...response.content,
|
|
4626
|
-
blocks: [...response.content.blocks, event.data]
|
|
4627
|
-
}
|
|
4628
|
-
}
|
|
4629
|
-
};
|
|
4577
|
+
function renderBody(response, components, onAction) {
|
|
4578
|
+
switch (response.type) {
|
|
4579
|
+
case "TEXT": {
|
|
4580
|
+
const { format, value } = response.content;
|
|
4581
|
+
return format === "MARKDOWN" ? /* @__PURE__ */ jsx(Markdown, { children: value }) : /* @__PURE__ */ jsx("p", { className: "rk-text-plain", children: value });
|
|
4630
4582
|
}
|
|
4631
|
-
case "
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4583
|
+
case "ANALYTICS": {
|
|
4584
|
+
const { title, blocks } = response.content;
|
|
4585
|
+
const list = Array.isArray(blocks) ? blocks : [];
|
|
4586
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4587
|
+
title ? /* @__PURE__ */ jsx("h2", { className: "rk-response-title", children: title }) : null,
|
|
4588
|
+
/* @__PURE__ */ jsx("div", { className: "rk-blocks", children: list.map((block, i) => /* @__PURE__ */ jsx(
|
|
4589
|
+
BlockSlot,
|
|
4590
|
+
{
|
|
4591
|
+
block,
|
|
4592
|
+
components,
|
|
4593
|
+
onAction
|
|
4594
|
+
},
|
|
4595
|
+
blockKey(block, i)
|
|
4596
|
+
)) })
|
|
4597
|
+
] });
|
|
4637
4598
|
}
|
|
4638
|
-
case "
|
|
4639
|
-
return {
|
|
4640
|
-
...state,
|
|
4641
|
-
phase: "error",
|
|
4642
|
-
error: event.data.message ?? "The stream encountered a fatal error."
|
|
4643
|
-
};
|
|
4599
|
+
case "ERROR":
|
|
4600
|
+
return /* @__PURE__ */ jsx(ErrorView, { message: response.content.message });
|
|
4644
4601
|
default:
|
|
4645
|
-
return
|
|
4602
|
+
return /* @__PURE__ */ jsx(ErrorView, { message: "Unsupported response type." });
|
|
4646
4603
|
}
|
|
4647
4604
|
}
|
|
4605
|
+
function BlockSlot({
|
|
4606
|
+
block,
|
|
4607
|
+
components,
|
|
4608
|
+
onAction
|
|
4609
|
+
}) {
|
|
4610
|
+
const type = typeof block?.type === "string" ? block.type : "UNKNOWN";
|
|
4611
|
+
const Component2 = resolveBlockComponent(type, components);
|
|
4612
|
+
return /* @__PURE__ */ jsx(ErrorBoundary, { fallback: () => /* @__PURE__ */ jsx(FallbackBlock, { block, onAction }), children: /* @__PURE__ */ jsx(Component2, { block, onAction }) });
|
|
4613
|
+
}
|
|
4614
|
+
function ErrorView({ message }) {
|
|
4615
|
+
return /* @__PURE__ */ jsxs("div", { className: "rk-block rk-error", role: "alert", children: [
|
|
4616
|
+
/* @__PURE__ */ jsx("span", { className: "rk-error-icon", "aria-hidden": true, children: "\u2715" }),
|
|
4617
|
+
/* @__PURE__ */ jsx("span", { className: "rk-error-message", children: message })
|
|
4618
|
+
] });
|
|
4619
|
+
}
|
|
4620
|
+
function MetadataFooter({
|
|
4621
|
+
metadata,
|
|
4622
|
+
onAction,
|
|
4623
|
+
responseId
|
|
4624
|
+
}) {
|
|
4625
|
+
if (!metadata) return null;
|
|
4626
|
+
const { generatedAt, dataSource, refreshable } = metadata;
|
|
4627
|
+
if (!generatedAt && !dataSource && !refreshable) return null;
|
|
4628
|
+
return /* @__PURE__ */ jsxs("footer", { className: "rk-meta", children: [
|
|
4629
|
+
generatedAt ? /* @__PURE__ */ jsx("span", { className: "rk-meta-time", children: formatTime(generatedAt) }) : null,
|
|
4630
|
+
dataSource ? /* @__PURE__ */ jsx("span", { className: "rk-meta-source", children: dataSource }) : null,
|
|
4631
|
+
refreshable ? /* @__PURE__ */ jsx(
|
|
4632
|
+
"button",
|
|
4633
|
+
{
|
|
4634
|
+
type: "button",
|
|
4635
|
+
className: "rk-action rk-meta-refresh",
|
|
4636
|
+
onClick: () => onAction({ type: "REFRESH", responseId }),
|
|
4637
|
+
children: "Refresh"
|
|
4638
|
+
}
|
|
4639
|
+
) : null
|
|
4640
|
+
] });
|
|
4641
|
+
}
|
|
4642
|
+
function formatTime(iso) {
|
|
4643
|
+
const d = new Date(iso);
|
|
4644
|
+
return Number.isNaN(d.getTime()) ? iso : d.toLocaleString();
|
|
4645
|
+
}
|
|
4646
|
+
function blockKey(block, index) {
|
|
4647
|
+
return typeof block?.id === "string" && block.id ? block.id : `block-${index}`;
|
|
4648
|
+
}
|
|
4648
4649
|
|
|
4649
4650
|
// src/sse.ts
|
|
4650
4651
|
var trimTrailingSlash = (s) => s.replace(/\/+$/, "");
|