@guuey/chat 0.16.8 → 0.16.10

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/README.md CHANGED
@@ -44,8 +44,29 @@ jump-to-latest release, windowed rendering for long transcripts,
44
44
  `aria-live`/keyboard/focus accessibility, sanitized markdown (typed AST —
45
45
  raw HTML is unrepresentable, links are scheme-allowlisted), generative-UI
46
46
  views mounting through `@guuey/mcp-apps-host`'s sandboxed host, and theming
47
- from the `GuueyChatTheme` token schema (`--guuey-chat-*` custom properties;
48
- `GUUEY_CHAT_THEME` ships beside the neutral default).
47
+ from the `GuueyChatTheme` token schema (`GUUEY_CHAT_THEME` ships beside the
48
+ neutral default).
49
+
50
+ **Looking native is the default, not a theming project.** The unthemed kit
51
+ is monochrome — ink, no vendor accent — so a zero-config embed disappears
52
+ into your product. Two knobs cover most brand work before any theme
53
+ exists:
54
+
55
+ ```tsx
56
+ <GuueyChat surface="bare" … /> // no message cards — transcript sits on YOUR background
57
+ <GuueyChat composer={false} … /> // bring your own input; drive sends via the ref handle
58
+ ```
59
+
60
+ The two theming channels **compose** — set any `--guuey-chat-*` CSS custom
61
+ property on an ancestor and it wins per-token over the resolved `theme`
62
+ prop (the kit stamps its resolved tokens under internal `--_guuey-chat-*`
63
+ names and reads `var(--guuey-chat-<t>, var(--_guuey-chat-<t>))`):
64
+
65
+ ```css
66
+ .my-app-chat {
67
+ --guuey-chat-accent: var(--brand);
68
+ }
69
+ ```
49
70
 
50
71
  Override one row without forfeiting the rest:
51
72
 
package/dist/index.d.ts CHANGED
@@ -16,6 +16,6 @@ export { defaultChatStrings, humanizeToolName, type ChatStrings, } from "./strin
16
16
  export { transcriptInputsFromHistory } from "./history-inputs.js";
17
17
  export { buildHitlAnswer, grantModeDisplay, hitlPromptsFromFold, type HitlAnswerRecord, type HitlPromptAction, } from "./hitl.js";
18
18
  export { OAUTH_LINK_PARAMS, OAUTH_RETURN_PARAMS, OAUTH_SCHEME, oauthAuthorizeAsk, oauthAuthorizeHref, parseOAuthReturn, stripOAuthReturn, type OAuthAuthorizeAsk, type OAuthReturn, } from "./oauth.js";
19
- export { DEFAULT_CHAT_THEME, GUUEY_CHAT_THEME, GuueyChatAccentRamp, GuueyChatErrorRamp, GuueyChatPalette, GuueyChatRamps, GuueyChatRampSet, GuueyChatTheme, GuueyChatToneRamp, resolveTheme, } from "./theme.js";
19
+ export { DEFAULT_CHAT_THEME, GUUEY_CHAT_THEME, GuueyChatAccentRamp, GuueyChatErrorRamp, GuueyChatPalette, GuueyChatRamps, GuueyChatRampSet, GuueyChatTheme, GuueyChatToneRamp, resolveTheme, resolveCourtTheme, } from "./theme.js";
20
20
  export type { ChatDebugEvent, CitationsItem, CodeItem, CompactionItem, DataResultItem, DisplayItem, ErrorItem, HistoryBoundaryItem, ItemKey, HitlPromptInput, HitlPromptItem, MediaItem, NoticeItem, ProfilePromptInput, ProfilePromptItem, PromptItem, PromptItemInput, ReasoningItem, StatusLineItem, TextItem, ToolGroupItem, ToolItem, TranscriptInputs, TranscriptMessage, TranscriptOverrides, TranscriptPlan, PlanViewSummary, UnknownItem, UserMessageItem, ViewMountItem, ViewRefItem, } from "./types.js";
21
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,aAAa,EACb,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,UAAU,EACV,KAAK,yBAAyB,EAC9B,WAAW,EACX,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACtB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,cAAc,EACd,aAAa,EACb,QAAQ,EACR,cAAc,EACd,cAAc,EACd,WAAW,EACX,SAAS,EACT,mBAAmB,EACnB,OAAO,EACP,eAAe,EACf,cAAc,EACd,SAAS,EACT,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,cAAc,EACd,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,WAAW,EACX,eAAe,EACf,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,aAAa,EACb,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,UAAU,EACV,KAAK,yBAAyB,EAC9B,WAAW,EACX,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACtB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,cAAc,EACd,aAAa,EACb,QAAQ,EACR,cAAc,EACd,cAAc,EACd,WAAW,EACX,SAAS,EACT,mBAAmB,EACnB,OAAO,EACP,eAAe,EACf,cAAc,EACd,SAAS,EACT,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,cAAc,EACd,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,WAAW,EACX,eAAe,EACf,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -16,4 +16,4 @@ export { defaultChatStrings, humanizeToolName, } from "./strings.js";
16
16
  export { transcriptInputsFromHistory } from "./history-inputs.js";
17
17
  export { buildHitlAnswer, grantModeDisplay, hitlPromptsFromFold, } from "./hitl.js";
18
18
  export { OAUTH_LINK_PARAMS, OAUTH_RETURN_PARAMS, OAUTH_SCHEME, oauthAuthorizeAsk, oauthAuthorizeHref, parseOAuthReturn, stripOAuthReturn, } from "./oauth.js";
19
- export { DEFAULT_CHAT_THEME, GUUEY_CHAT_THEME, GuueyChatAccentRamp, GuueyChatErrorRamp, GuueyChatPalette, GuueyChatRamps, GuueyChatRampSet, GuueyChatTheme, GuueyChatToneRamp, resolveTheme, } from "./theme.js";
19
+ export { DEFAULT_CHAT_THEME, GUUEY_CHAT_THEME, GuueyChatAccentRamp, GuueyChatErrorRamp, GuueyChatPalette, GuueyChatRamps, GuueyChatRampSet, GuueyChatTheme, GuueyChatToneRamp, resolveTheme, resolveCourtTheme, } from "./theme.js";
@@ -1 +1 @@
1
- {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AAkCA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,OAAO,KAAK,EAUV,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EAIf,MAAM,YAAY,CAAC;AAuqBpB,uCAAuC;AACvC,wBAAgB,cAAc,CAC5B,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,gBAAgB,EACxB,SAAS,GAAE,mBAAwB,GAClC,cAAc,CA+VhB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,GAAG,cAAc,CAAC,GACxD;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;CAAE,GAAG,SAAS,CAiB5D"}
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AAkCA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,OAAO,KAAK,EAUV,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EAIf,MAAM,YAAY,CAAC;AAuqBpB,uCAAuC;AACvC,wBAAgB,cAAc,CAC5B,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,gBAAgB,EACxB,SAAS,GAAE,mBAAwB,GAClC,cAAc,CAkXhB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,GAAG,cAAc,CAAC,GACxD;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;CAAE,GAAG,SAAS,CAiB5D"}
package/dist/plan.js CHANGED
@@ -760,14 +760,35 @@ export function planTranscript(inputs, policy, overrides = {}) {
760
760
  liveViewScopes.add(item.actionScope);
761
761
  }
762
762
  const cards = [...(inputs.historyCards ?? [])].sort((a, b) => a.seq - b.seq);
763
- for (const card of cards) {
764
- const key = `card.${card.seq}`;
763
+ // guuey#535: ONE render session = ONE surface. Multiple history cards
764
+ // sharing an actionScope are the same surface referenced across turns
765
+ // (ggui SPEC §7.1.2.1 makes the amend result's {sessionId, resourceUri}
766
+ // the normative re-anchor reference — ggui#652; the stamp rides the
767
+ // existing locator persistence lane untouched). The LATEST reference
768
+ // anchors the surface; earlier references emit nothing — and latest
769
+ // wins even when it is locator-only, because the locator re-fetch
770
+ // restores CURRENT session state, better than an older frozen snapshot.
771
+ const scopes = cards.map((card) => {
765
772
  const mount = snapshotViewMount(card.cardSnapshot);
766
- const scope = mount === undefined
767
- ? null
768
- : mount.channel === "locator"
769
- ? mount.resourceUri
770
- : mount.resource.uri;
773
+ return {
774
+ card,
775
+ mount,
776
+ scope: mount === undefined
777
+ ? null
778
+ : mount.channel === "locator"
779
+ ? mount.resourceUri
780
+ : mount.resource.uri,
781
+ };
782
+ });
783
+ const latestSeqByScope = new Map();
784
+ for (const { card, scope } of scopes) {
785
+ if (scope !== null)
786
+ latestSeqByScope.set(scope, card.seq);
787
+ }
788
+ for (const { card, mount, scope } of scopes) {
789
+ const key = `card.${card.seq}`;
790
+ if (scope !== null && latestSeqByScope.get(scope) !== card.seq)
791
+ continue; // a later turn re-anchored it
771
792
  if (scope !== null && liveViewScopes.has(scope))
772
793
  continue; // live mount owns it
773
794
  const view = {
@@ -69,7 +69,7 @@ export interface TranscriptItemContext {
69
69
  viewProps?: ViewSlotProps | ((item: ViewMountItem, mount: ResolvedViewMount) => ViewSlotProps);
70
70
  }
71
71
  /** The per-view slice of `GuueyViewProps` a transcript may configure. */
72
- export type ViewSlotProps = Pick<GuueyViewProps, "hostCapabilities" | "hostInfo" | "hostContext" | "onCallTool" | "onUpdateModelContext" | "onUserMessage" | "onReadResource" | "onSizeChanged" | "negotiationTimeoutMs" | "dangerouslyAddSandboxFlags" | "allow" | "sandboxPageUrl" | "autoResize" | "cspOrigins">;
72
+ export type ViewSlotProps = Pick<GuueyViewProps, "hostCapabilities" | "hostInfo" | "hostContext" | "onCallTool" | "onUpdateModelContext" | "onUserMessage" | "onOpenLink" | "onReadResource" | "onSizeChanged" | "negotiationTimeoutMs" | "dangerouslyAddSandboxFlags" | "allow" | "sandboxPageUrl" | "autoResize" | "cspOrigins">;
73
73
  interface ItemProps<T> {
74
74
  item: T;
75
75
  ctx: TranscriptItemContext;
@@ -1 +1 @@
1
- {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/react/components.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/react/components.tsx"],"names":[],"mappings":"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"}
@@ -61,7 +61,7 @@ import type { TranscriptComponents, TranscriptItemContext, ViewSlotProps } from
61
61
  * `hostContext` key wins field-by-field; `theme` is only filled in.
62
62
  * Exported for tests; not part of the package surface.
63
63
  */
64
- export declare function viewPropsWithThemeAnnounce(viewProps: TranscriptItemContext["viewProps"], mode: ThemeMode, defaults?: Pick<ViewSlotProps, "onCallTool" | "onUpdateModelContext" | "onUserMessage">): TranscriptItemContext["viewProps"];
64
+ export declare function viewPropsWithThemeAnnounce(viewProps: TranscriptItemContext["viewProps"], mode: ThemeMode, defaults?: Pick<ViewSlotProps, "onCallTool" | "onUpdateModelContext" | "onUserMessage" | "onOpenLink">): TranscriptItemContext["viewProps"];
65
65
  /**
66
66
  * The imperative seam (guuey#210): programmatic send/prefill/focus for
67
67
  * hosts that stay on the batteries-included path (suggested-prompt chips
@@ -118,6 +118,28 @@ export interface GuueyChatHandle {
118
118
  * to the transcript).
119
119
  */
120
120
  viewSlotProps(): ViewSlotProps;
121
+ /**
122
+ * Forget this conversation (guuey#526 — the public-computer story).
123
+ *
124
+ * Local half, unconditional and immediate: aborts any in-flight turn
125
+ * FIRST (a completing turn can re-persist its own rows), drops the
126
+ * durable thread pointer AND its persisted storage key, wipes the
127
+ * visible transcript, clears the typed draft and any pending link ask —
128
+ * the next send mints a fresh thread.
129
+ *
130
+ * Server half, best-effort: when the surface has a platform door
131
+ * (`apiBaseUrl`) and a minted thread, fires
132
+ * `DELETE /v1/threads/:threadId` with the SAME identity the thread was
133
+ * created under (captured before any rotation) — real, child-first
134
+ * server-side erasure. A denied or failed delete still clears the
135
+ * device (the contract's unlinkability fallback) and surfaces nothing
136
+ * louder than the `thread-delete` debug event.
137
+ *
138
+ * Afterwards `onGuestSecretRotate` fires (when wired), so the identity
139
+ * owner mints a fresh guest secret — even an orphaned server row is
140
+ * unreachable from a rotated identity.
141
+ */
142
+ clearConversation(): void;
121
143
  }
122
144
  export interface GuueyChatProps {
123
145
  /** Pod base URL (with or without `/agent/invoke`). `null` disables chat. */
@@ -167,6 +189,19 @@ export interface GuueyChatProps {
167
189
  strings?: Partial<ChatStrings>;
168
190
  theme?: GuueyChatTheme;
169
191
  mode?: ThemeMode;
192
+ /**
193
+ * Message-surface presentation (guuey#521). `"card"` (default) keeps
194
+ * assistant text on its own card; `"bare"` sits the transcript directly
195
+ * on the host's background so the embed reads native to the page.
196
+ */
197
+ surface?: "card" | "bare";
198
+ /**
199
+ * Render the built-in composer (default `true`). `false` hides it for
200
+ * hosts that drive the conversation through the imperative handle
201
+ * (guuey#210 `ask`/`compose`) or their own input — pairs with the
202
+ * handle instead of forcing a CSS hide (guuey#521).
203
+ */
204
+ composer?: boolean;
170
205
  /** DOM windowing (§3.2). `false` renders everything. */
171
206
  window?: TranscriptWindowing | false;
172
207
  /**
@@ -175,6 +210,39 @@ export interface GuueyChatProps {
175
210
  * pod door) when omitted; an explicit reader always wins.
176
211
  */
177
212
  reader?: UiResourceReader;
213
+ /**
214
+ * The forget-this-device affordance (guuey#526 — the public-computer
215
+ * story): a quiet "Clear conversation" control with a two-tap confirm,
216
+ * wired to {@link GuueyChatHandle.clearConversation}. Default: ON when
217
+ * the surface runs GUEST identity (`getGuestSecret` present — the
218
+ * founder's seamless principle; a signed-in surface has account-level
219
+ * recourse), OFF otherwise; pass a boolean to override either way.
220
+ */
221
+ clearAffordance?: boolean;
222
+ /**
223
+ * Guest-secret rotation hook (guuey#526): called at the END of every
224
+ * {@link GuueyChatHandle.clearConversation} — after the server delete
225
+ * has been dispatched with the OLD identity — so the owner of the
226
+ * secret's storage (the kit never stores it; `getGuestSecret` is a
227
+ * getter) mints a fresh one. Rotation is what makes even an orphaned
228
+ * server row unreachable: the new identity is a stranger to it. Guest
229
+ * KV state is (user,mcp)-scoped and is orphaned by rotation, by design.
230
+ */
231
+ onGuestSecretRotate?: () => void;
232
+ /**
233
+ * Suggestion chips (guuey#533 — declared content, the one-truth design):
234
+ * rendered on the EMPTY transcript only (they retire the moment a
235
+ * message exists — live send or restored history both count), one tap
236
+ * SENDS the chip text verbatim through exactly the Send button's gate.
237
+ * Default-ON when content exists; `false` opts the surface out. The kit
238
+ * mirrors the card projection's caps render-side (4 shown, ≤80 chars
239
+ * each, blank-rejected) — a direct consumer bypassing the platform's
240
+ * emit gate gets the same bounds. Content is the host's (the widget
241
+ * passes the card's `suggestions`; a direct consumer passes its own);
242
+ * the kit never invents chips — an honest empty state beats invented
243
+ * questions in the builder's voice.
244
+ */
245
+ suggestions?: readonly string[] | false;
178
246
  /** The debug sink (spec §5) — fires only under the debug policy. */
179
247
  onDebugEvent?: (event: ChatDebugEvent) => void;
180
248
  /** R6 pass-through (relay hook, sandbox page/flags, host context…). */
@@ -1 +1 @@
1
- {"version":3,"file":"guuey-chat.d.ts","sourceRoot":"","sources":["../../src/react/guuey-chat.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"guuey-chat.d.ts","sourceRoot":"","sources":["../../src/react/guuey-chat.tsx"],"names":[],"mappings":"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"}
@@ -46,7 +46,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
46
46
  * native GuueyChat, so there is no native surface to put a handle on yet.
47
47
  */
48
48
  import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useMemo, useRef, useState, } from "react";
49
- import { createUiActionRelay, createUiResourceReader, createWebAdapters, } from "@guuey/agent-client";
49
+ import { createUiActionRelay, createUiResourceReader, createWebAdapters, deleteThread, } from "@guuey/agent-client";
50
50
  import { useAgentInvoke } from "@guuey/agent-client/react";
51
51
  import { unavailableToolCallResult } from "@guuey/mcp-apps-host";
52
52
  import { calmPolicy, debugPolicy } from "../policy.js";
@@ -85,7 +85,7 @@ const PROMPT_STATE = {
85
85
  dismiss: "dismissed",
86
86
  };
87
87
  export const GuueyChat = forwardRef(function GuueyChat(props, ref) {
88
- const { endpointUrl, appId, apiBaseUrl, getAccessToken, getGuestSecret, adapters: adaptersProp, preset = "calm", policy: policyOverrides, components, strings: stringOverrides, theme = DEFAULT_CHAT_THEME, mode = "light", window: windowing, reader, onDebugEvent, viewProps, promotedViewKey, onViewRef, onViewsChange, onPromptAction, onHitlAnswer, oauthReturnTo, onOAuthAuthorize, onErrorAction, onActivity, onReady, onThread, className, style, } = props;
88
+ const { endpointUrl, appId, apiBaseUrl, getAccessToken, getGuestSecret, adapters: adaptersProp, preset = "calm", policy: policyOverrides, components, strings: stringOverrides, theme = DEFAULT_CHAT_THEME, mode = "light", surface = "card", composer = true, window: windowing, reader, onDebugEvent, viewProps, promotedViewKey, onViewRef, onViewsChange, onPromptAction, onHitlAnswer, oauthReturnTo, onOAuthAuthorize, onErrorAction, clearAffordance, onGuestSecretRotate, suggestions, onActivity, onReady, onThread, className, style, } = props;
89
89
  // Identity stabilization (guuey#303 QA — the template's own chat-rail
90
90
  // shipped the failure): hosts pass inline literals and arrows, so prop
91
91
  // IDENTITY is noise. The getter props route through refs (presence, not
@@ -96,8 +96,14 @@ export const GuueyChat = forwardRef(function GuueyChat(props, ref) {
96
96
  // host back → setState → re-render → "Maximum update depth exceeded".
97
97
  const getAccessTokenRef = useRef(getAccessToken);
98
98
  getAccessTokenRef.current = getAccessToken;
99
+ // The handle is created once ([] deps) but must read the LIVE base —
100
+ // same ref discipline as every other handle-read value in this file.
101
+ const apiBaseUrlRef = useRef(apiBaseUrl);
102
+ apiBaseUrlRef.current = apiBaseUrl;
99
103
  const getGuestSecretRef = useRef(getGuestSecret);
100
104
  getGuestSecretRef.current = getGuestSecret;
105
+ const onGuestSecretRotateRef = useRef(onGuestSecretRotate);
106
+ onGuestSecretRotateRef.current = onGuestSecretRotate;
101
107
  const hasAccessToken = getAccessToken !== undefined;
102
108
  const hasGuestSecret = getGuestSecret !== undefined;
103
109
  const adapters = useMemo(() => adaptersProp ??
@@ -350,11 +356,63 @@ export const GuueyChat = forwardRef(function GuueyChat(props, ref) {
350
356
  }
351
357
  void live.invoke.send(next).catch(() => { });
352
358
  }, [busy]);
359
+ // guuey#522: the kit default for `ui/open-link` NEVER navigates
360
+ // sight-unseen — the ask surfaces as a disclosure affordance (host +
361
+ // full URL + Open/Dismiss) and the OPEN is the human's own anchor
362
+ // click, so the browser's activation gate and the review posture agree
363
+ // by construction. ONE pending ask at a time, newest replaces (a
364
+ // card spamming asks can never grow an unbounded stack).
365
+ const [pendingLink, setPendingLink] = useState(null);
366
+ // guuey#526: the two-tap confirm window for the clear affordance (an
367
+ // accidental tap must not nuke a conversation; a second tap within the
368
+ // window does — the state auto-expires).
369
+ const [clearArmed, setClearArmed] = useState(false);
370
+ useEffect(() => {
371
+ if (!clearArmed)
372
+ return;
373
+ const timer = setTimeout(() => setClearArmed(false), 4000);
374
+ return () => clearTimeout(timer);
375
+ }, [clearArmed]);
376
+ const showClearAffordance = clearAffordance ?? getGuestSecret !== undefined;
377
+ // guuey#533: the render-side mirror of the card projection's emit caps
378
+ // (4 shown / <=80 chars / blank-rejected) — same defense posture as the
379
+ // table normalizer: the kit is public npm and cannot assume every host
380
+ // routed content through platform's write gate.
381
+ const chips = useMemo(() => {
382
+ if (suggestions === false || suggestions === undefined)
383
+ return [];
384
+ return suggestions
385
+ .map((c) => c.trim())
386
+ .filter((c) => c.length > 0 && c.length <= 80)
387
+ .slice(0, 4);
388
+ }, [suggestions]);
389
+ const sendSuggestion = useCallback((text) => {
390
+ const live = liveRef.current;
391
+ // Exactly the Send button's gate (the #210 rule): unavailable, busy,
392
+ // or blank -> the tap is a no-op, never a bypass. The typed draft is
393
+ // left untouched (a chip send must not eat a half-typed message).
394
+ if (!live.available || live.busy || text.trim() === "")
395
+ return;
396
+ void live.invoke.send(text).catch(() => {
397
+ // Same contract as submit: the hook owns failure surfacing.
398
+ });
399
+ }, []);
400
+ const defaultOnOpenLink = useCallback((url) => {
401
+ setPendingLink(url);
402
+ }, []);
353
403
  const effectiveViewProps = useMemo(() => viewPropsWithThemeAnnounce(viewProps, mode, {
354
404
  ...(stagedDefaultOnCallTool !== undefined ? { onCallTool: stagedDefaultOnCallTool } : {}),
355
405
  onUpdateModelContext: defaultOnUpdateModelContext,
356
406
  onUserMessage: defaultOnUserMessage,
357
- }), [viewProps, mode, stagedDefaultOnCallTool, defaultOnUpdateModelContext, defaultOnUserMessage]);
407
+ onOpenLink: defaultOnOpenLink,
408
+ }), [
409
+ viewProps,
410
+ mode,
411
+ stagedDefaultOnCallTool,
412
+ defaultOnUpdateModelContext,
413
+ defaultOnUserMessage,
414
+ defaultOnOpenLink,
415
+ ]);
358
416
  // The canvas-host door (guuey#335): a host mounting views DIRECTLY from
359
417
  // the roster (the chat-rail shell) needs the SAME slot wiring the kit's
360
418
  // inline mounts get — theme announce, action relay, context sink. Read
@@ -368,6 +426,7 @@ export const GuueyChat = forwardRef(function GuueyChat(props, ref) {
368
426
  ...(stagedDefaultOnCallTool !== undefined ? { onCallTool: stagedDefaultOnCallTool } : {}),
369
427
  onUpdateModelContext: defaultOnUpdateModelContext,
370
428
  onUserMessage: defaultOnUserMessage,
429
+ onOpenLink: defaultOnOpenLink,
371
430
  hostContext: { theme: mode },
372
431
  }
373
432
  : (effectiveViewProps ?? {});
@@ -394,6 +453,49 @@ export const GuueyChat = forwardRef(function GuueyChat(props, ref) {
394
453
  focusComposer: () => {
395
454
  inputRef.current?.focus();
396
455
  },
456
+ clearConversation: () => {
457
+ const live = liveRef.current;
458
+ // Contract ordering (guuey#526, platform's frozen comment): abort
459
+ // FIRST — a completing turn can re-persist its own rows after the
460
+ // delete. Capture the id + guest secret BEFORE anything clears or
461
+ // rotates them: the delete must authenticate as the identity that
462
+ // OWNS the thread.
463
+ live.invoke.abort();
464
+ const threadId = threadIdRef.current;
465
+ const getGuest = getGuestSecretRef.current;
466
+ const guestSecret = getGuest !== undefined ? getGuest() : null;
467
+ if (apiBaseUrlRef.current !== undefined && threadId !== null) {
468
+ // Best-effort server erasure — fire-and-forget, never blocks the
469
+ // local clear. 200 and 404 are both "deleted" (idempotent by
470
+ // contract); denied/failed still cleared locally below (the
471
+ // unlinkability fallback) and surface ONLY as a debug line.
472
+ void deleteThread({
473
+ apiBaseUrl: apiBaseUrlRef.current,
474
+ threadId,
475
+ ...(getAccessTokenRef.current !== undefined
476
+ ? { getAccessToken: getAccessTokenRef.current }
477
+ : {}),
478
+ guestSecret,
479
+ }).then((outcome) => {
480
+ onDebugEventRef.current?.({ type: "thread-delete", threadId, outcome });
481
+ });
482
+ }
483
+ else {
484
+ onDebugEventRef.current?.({ type: "thread-delete", threadId, outcome: "skipped" });
485
+ }
486
+ // The hook's reset owns the durable local half (pointer + storage
487
+ // key, transcript/fold/cards); the kit clears ITS OWN residue —
488
+ // the typed draft, a pending link ask, queued doorbells — so the
489
+ // device holds nothing of the conversation.
490
+ live.invoke.reset();
491
+ setInput("");
492
+ setPendingLink(null);
493
+ pendingDoorbellsRef.current = [];
494
+ // Rotation LAST: the delete above already captured the old
495
+ // identity, so the fresh secret is a stranger to even an orphaned
496
+ // server row.
497
+ onGuestSecretRotateRef.current?.();
498
+ },
397
499
  // A getter, not a captured value: the handle is created once, but the
398
500
  // thread hydrates after mount and can change — reads go through the
399
501
  // same ref the default reader uses, so it is always the live id.
@@ -472,9 +574,17 @@ export const GuueyChat = forwardRef(function GuueyChat(props, ref) {
472
574
  onPromptAction?.(item, action);
473
575
  }, [resolvePrompt, answerHitlPrompt, onHitlAnswer, onPromptAction, oauthReturnTo, onOAuthAuthorize]);
474
576
  const strings = policy.strings;
475
- return (_jsxs("div", { className: `guuey-chat-surface${className !== undefined ? ` ${className}` : ""}`, style: style, children: [_jsx(Transcript, { plan: plan, strings: strings, theme: theme, mode: mode, ...(windowing !== undefined ? { window: windowing } : {}), ...(components !== undefined ? { components } : {}), onToggle: toggle, onRetry: handleRetry, onPromptAction: handlePromptAction, ...(onErrorAction !== undefined ? { onErrorAction } : {}), resolvedMounts: resolvedMounts, onViewPhase: onViewPhase, onViewDiagnosis: onViewDiagnosis, ...(onViewRef !== undefined ? { onViewRef } : {}), viewProps: effectiveViewProps }), oauthReturn.notice !== null && (_jsxs("p", { role: "status", className: `guuey-chat-oauth-notice guuey-chat-oauth-${oauthReturn.notice.kind}`, children: [oauthReturn.notice.kind === "connected"
577
+ return (_jsxs("div", { className: `guuey-chat-surface${className !== undefined ? ` ${className}` : ""}`, style: style, children: [_jsx(Transcript, { plan: plan, strings: strings, theme: theme, mode: mode, surface: surface, ...(windowing !== undefined ? { window: windowing } : {}), ...(components !== undefined ? { components } : {}), onToggle: toggle, onRetry: handleRetry, onPromptAction: handlePromptAction, ...(onErrorAction !== undefined ? { onErrorAction } : {}), resolvedMounts: resolvedMounts, onViewPhase: onViewPhase, onViewDiagnosis: onViewDiagnosis, ...(onViewRef !== undefined ? { onViewRef } : {}), viewProps: effectiveViewProps }), chips.length > 0 && inputs.messages.length === 0 && (_jsx("nav", { className: "guuey-chat-chips-row", "aria-label": strings.suggestionsLabel, children: chips.map((chip) => (_jsx("button", { type: "button", className: "guuey-chat-chip", onClick: () => sendSuggestion(chip), children: chip }, chip))) })), showClearAffordance && inputs.messages.length > 0 && (_jsx("div", { className: "guuey-chat-clear-row", children: _jsx("button", { type: "button", className: `guuey-chat-clear${clearArmed ? " guuey-chat-clear-armed" : ""}`, onClick: () => {
578
+ if (clearArmed) {
579
+ setClearArmed(false);
580
+ handle.clearConversation();
581
+ }
582
+ else {
583
+ setClearArmed(true);
584
+ }
585
+ }, children: clearArmed ? strings.clearConversationConfirm : strings.clearConversationLabel }) })), pendingLink !== null && (_jsxs("div", { role: "status", className: "guuey-chat-link-ask", children: [_jsx("span", { className: "guuey-chat-link-ask-label", children: strings.linkAskLabel(new URL(pendingLink).host) }), _jsx("span", { className: "guuey-chat-link-ask-url", children: pendingLink }), _jsx("a", { className: "guuey-chat-link-ask-open", href: pendingLink, target: "_blank", rel: "noopener noreferrer", onClick: () => setPendingLink(null), children: strings.linkOpen }), _jsx("button", { type: "button", className: "guuey-chat-link-ask-dismiss", onClick: () => setPendingLink(null), children: strings.linkDismiss })] })), oauthReturn.notice !== null && (_jsxs("p", { role: "status", className: `guuey-chat-oauth-notice guuey-chat-oauth-${oauthReturn.notice.kind}`, children: [oauthReturn.notice.kind === "connected"
476
586
  ? strings.oauthConnected(oauthReturn.notice.serverName)
477
- : strings.oauthFailed(oauthReturn.notice.reason), _jsx("button", { type: "button", className: "guuey-chat-oauth-dismiss", onClick: oauthReturn.dismiss, children: strings.promptDismissed })] })), _jsxs("form", { className: "guuey-chat-composer", onSubmit: (e) => {
587
+ : strings.oauthFailed(oauthReturn.notice.reason), _jsx("button", { type: "button", className: "guuey-chat-oauth-dismiss", onClick: oauthReturn.dismiss, children: strings.promptDismissed })] })), composer && (_jsxs("form", { className: "guuey-chat-composer", onSubmit: (e) => {
478
588
  e.preventDefault();
479
589
  submit();
480
590
  }, children: [_jsx("textarea", { ref: inputRef, id: composerId, name: "message", className: "guuey-chat-composer-input", rows: 1, value: input, onChange: (e) => setInput(e.target.value), onKeyDown: (e) => {
@@ -484,5 +594,5 @@ export const GuueyChat = forwardRef(function GuueyChat(props, ref) {
484
594
  e.preventDefault();
485
595
  submit();
486
596
  }
487
- }, disabled: !available, "aria-label": strings.composerLabel, placeholder: available ? strings.composerPlaceholder : strings.composerUnavailable }), busy ? (_jsx("button", { type: "button", className: "guuey-chat-composer-stop", onClick: () => invoke.abort(), children: strings.stop })) : (_jsx("button", { type: "submit", className: "guuey-chat-composer-send", disabled: !canSend, children: strings.send }))] })] }));
597
+ }, disabled: !available, "aria-label": strings.composerLabel, placeholder: available ? strings.composerPlaceholder : strings.composerUnavailable }), busy ? (_jsx("button", { type: "button", className: "guuey-chat-composer-stop", onClick: () => invoke.abort(), children: strings.stop })) : (_jsx("button", { type: "submit", className: "guuey-chat-composer-send", disabled: !canSend, children: strings.send }))] }))] }));
488
598
  });
@@ -1,29 +1,3 @@
1
- /**
2
- * The R1 markdown surface — the ONE place `@guuey/chat` renders
3
- * agent-influenced content in the embedder's origin, and therefore the
4
- * package's sanitizer boundary (spec §3.1).
5
- *
6
- * The pipeline is `@silverprotocol/richtext`: markdown → a TYPED AST in
7
- * which raw HTML is structurally unrepresentable (no HTML node type
8
- * exists; angle brackets can only ever be literal text) → React elements.
9
- * That is deliberately STRONGER than the spec's letter (markdown → HTML →
10
- * sanitize): there is no HTML string at any point, so there is nothing to
11
- * sanitize incorrectly — no `dangerouslySetInnerHTML` anywhere in this
12
- * package.
13
- *
14
- * Safety properties, each pinned by a test:
15
- * - raw HTML (`<img onerror=…>`, `<script>`) renders as literal text;
16
- * - link `href` is populated upstream ONLY for http/https/mailto —
17
- * `javascript:`, `data:`, `vbscript:`, and relative targets parse as
18
- * styled text with NO anchor `href` (richtext's `SAFE_HREF` allowlist);
19
- * - navigable links carry `rel="noopener noreferrer" target="_blank"`;
20
- * - there is NO image syntax in the node vocabulary at all — the spec's
21
- * F5 ruling (markdown images off; R7 media blocks are the sanctioned
22
- * image path) holds structurally, not by configuration.
23
- *
24
- * Streaming-tolerant by upstream design: unclosed emphasis mid-delta
25
- * renders as formatted-so-far.
26
- */
27
1
  import type { ReactNode } from "react";
28
2
  import { type RichTextTableBlock } from "../richtext-table.js";
29
3
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/react/markdown.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,OAAO,EAAqB,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AA0ClF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,kBAAkB,CAAA;CAAE,GAAG,SAAS,CA4B9E;AAmCD,qEAAqE;AACrE,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQ9D"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/react/markdown.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,OAAO,EAAqB,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AA0GlF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,kBAAkB,CAAA;CAAE,GAAG,SAAS,CA4B9E;AAwED,qEAAqE;AACrE,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQ9D"}
@@ -1,11 +1,102 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * The R1 markdown surface — the ONE place `@guuey/chat` renders
4
+ * agent-influenced content in the embedder's origin, and therefore the
5
+ * package's sanitizer boundary (spec §3.1).
6
+ *
7
+ * The pipeline is `@silverprotocol/richtext`: markdown → a TYPED AST in
8
+ * which raw HTML is structurally unrepresentable (no HTML node type
9
+ * exists; angle brackets can only ever be literal text) → React elements.
10
+ * That is deliberately STRONGER than the spec's letter (markdown → HTML →
11
+ * sanitize): there is no HTML string at any point, so there is nothing to
12
+ * sanitize incorrectly — no `dangerouslySetInnerHTML` anywhere in this
13
+ * package.
14
+ *
15
+ * Safety properties, each pinned by a test:
16
+ * - raw HTML (`<img onerror=…>`, `<script>`) renders as literal text;
17
+ * - link `href` is populated upstream ONLY for http/https/mailto —
18
+ * `javascript:`, `data:`, `vbscript:`, and relative targets parse as
19
+ * styled text with NO anchor `href` (richtext's `SAFE_HREF` allowlist);
20
+ * - navigable links carry `rel="noopener noreferrer" target="_blank"`;
21
+ * - there is NO image syntax in the node vocabulary at all — the spec's
22
+ * F5 ruling (markdown images off; R7 media blocks are the sanctioned
23
+ * image path) holds structurally, not by configuration.
24
+ *
25
+ * Streaming-tolerant by upstream design: unclosed emphasis mid-delta
26
+ * renders as formatted-so-far.
27
+ */
28
+ import { useState } from "react";
2
29
  import { parseRichText, } from "@silverprotocol/richtext";
3
30
  import { normalizeTableRow } from "../richtext-table.js";
31
+ /**
32
+ * Bare-URL autolink (guuey#515): richtext mints `link` nodes only from
33
+ * explicit `[text](url)` markdown, so a plain "https://…" in agent prose
34
+ * parses as a text node and rendered as untappable static text — on a
35
+ * phone that means retyping a URL out of a chat bubble. Linkify at the
36
+ * render boundary, conservatively:
37
+ * - the scheme is part of the match (http/https only), so no
38
+ * `javascript:`/`data:` target can ever qualify — the SAFE_HREF
39
+ * property holds by construction;
40
+ * - built as React elements (no HTML string exists to inject into),
41
+ * same `rel`/`target` contract as explicit links;
42
+ * - trailing punctuation stays prose ("see https://guuey.com." must not
43
+ * link the dot), while a balanced closing paren/bracket stays in the
44
+ * URL (wiki-style paths);
45
+ * - schemeless "www.foo.com" is deliberately NOT linkified — guessing
46
+ * schemes is how autolinkers start lying;
47
+ * - code spans are untouched (they render `node.code`, not this path).
48
+ */
49
+ const BARE_URL = /https?:\/\/[^\s<>]+/g;
50
+ function trimTrailingPunctuation(url) {
51
+ for (;;) {
52
+ const last = url[url.length - 1];
53
+ if (last === undefined)
54
+ return url;
55
+ if (last === ")" || last === "]") {
56
+ const open = last === ")" ? "(" : "[";
57
+ const opens = url.split(open).length - 1;
58
+ const closes = url.split(last).length - 1;
59
+ if (closes > opens) {
60
+ url = url.slice(0, -1);
61
+ continue;
62
+ }
63
+ return url;
64
+ }
65
+ if (".,;:!?'\"»›".includes(last)) {
66
+ url = url.slice(0, -1);
67
+ continue;
68
+ }
69
+ return url;
70
+ }
71
+ }
72
+ function linkify(text) {
73
+ if (!text.includes("http"))
74
+ return text;
75
+ const out = [];
76
+ let consumed = 0;
77
+ for (const match of text.matchAll(BARE_URL)) {
78
+ const start = match.index;
79
+ if (start === undefined)
80
+ continue;
81
+ const url = trimTrailingPunctuation(match[0]);
82
+ if (url.length === 0)
83
+ continue;
84
+ if (start > consumed)
85
+ out.push(text.slice(consumed, start));
86
+ out.push(_jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", children: url }, `url-${start}`));
87
+ consumed = start + url.length;
88
+ }
89
+ if (out.length === 0)
90
+ return text;
91
+ if (consumed < text.length)
92
+ out.push(text.slice(consumed));
93
+ return out;
94
+ }
4
95
  function Inline({ nodes }) {
5
96
  return nodes.map((node, i) => {
6
97
  switch (node.type) {
7
98
  case "text":
8
- return _jsx("span", { children: node.text }, i);
99
+ return _jsx("span", { children: linkify(node.text) }, i);
9
100
  case "break":
10
101
  return _jsx("br", {}, i);
11
102
  case "strong":
@@ -39,13 +130,35 @@ function Block({ block }) {
39
130
  case "heading":
40
131
  return (_jsx("p", { className: `guuey-chat-heading${block.level <= 3 ? " guuey-chat-heading-major" : ""}`, children: _jsx(Inline, { nodes: block.children }) }));
41
132
  case "code-fence":
42
- return _jsx("pre", { className: "guuey-chat-code-fence", children: block.code });
133
+ return _jsx(CodeFence, { code: block.code });
43
134
  case "list": {
44
135
  const Tag = block.ordered ? "ol" : "ul";
45
136
  return (_jsx(Tag, { ...(block.ordered && block.start !== undefined ? { start: block.start } : {}), children: block.items.map((item, j) => (_jsx("li", { children: _jsx(Inline, { nodes: item.children }) }, j))) }));
46
137
  }
47
138
  }
48
139
  }
140
+ /**
141
+ * A fenced code block with its copy affordance (guuey#529 — the
142
+ * seamless-default family: every embedder's visitors get it with zero
143
+ * setup). The button lives in a wrapper DIV so the `<pre>` holds ONLY the
144
+ * code (select-all inside the fence never picks up UI text); the
145
+ * transcript's sibling-margin rules name the wrapper class alongside
146
+ * `pre`. Copy failure is shown truthfully: the label simply stays "Copy"
147
+ * (clipboard access needs a secure context + the iframe's
148
+ * clipboard-write grant — manual selection always still works).
149
+ */
150
+ function CodeFence({ code }) {
151
+ const [copied, setCopied] = useState(false);
152
+ return (_jsxs("div", { className: "guuey-chat-code-wrap", children: [_jsx("pre", { className: "guuey-chat-code-fence", children: code }), _jsx("button", { type: "button", className: "guuey-chat-code-copy", "aria-label": copied ? "Copied" : "Copy code", onClick: () => {
153
+ const clipboard = navigator.clipboard;
154
+ if (clipboard === undefined)
155
+ return;
156
+ clipboard.writeText(code).then(() => {
157
+ setCopied(true);
158
+ setTimeout(() => setCopied(false), 1600);
159
+ }, () => setCopied(false));
160
+ }, children: copied ? "Copied" : "Copy" })] }));
161
+ }
49
162
  /** Sanitized markdown → React elements (see the module docblock). */
50
163
  export function Markdown({ text }) {
51
164
  return (_jsx(_Fragment, { children: parseRichText(text).map((block, i) => (_jsx(Block, { block: block }, i))) }));