@cosmicdrift/kumiko-renderer 0.365.1 → 0.366.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.
@@ -23,7 +23,7 @@
23
23
  // // feature.ts (server-only — imports defineFeature)
24
24
  // import { taskEntity, editScreen, ... } from "./feature-schema.js";
25
25
  // export const taskFeature = defineFeature("tasks", (r) => {
26
- // r.entity("task", taskEntity);
26
+ // r.entity({ name: "task", ...taskEntity });
27
27
  // r.writeHandler(...);
28
28
  // r.screen(editScreen);
29
29
  // ...
@@ -0,0 +1,25 @@
1
+ import { Component, type ErrorInfo, type ReactNode } from "react";
2
+ export type ErrorBoundaryFallbackProps = {
3
+ readonly error: Error;
4
+ readonly reset: () => void;
5
+ };
6
+ export type ErrorBoundaryProps = {
7
+ readonly children: ReactNode;
8
+ readonly fallback: (props: ErrorBoundaryFallbackProps) => ReactNode;
9
+ /** Prefix for the logged message, e.g. "screen" or "root". */
10
+ readonly scope: string;
11
+ /** Called after the default console.error log, e.g. to forward to telemetry. */
12
+ readonly onError?: (error: Error, info: ErrorInfo) => void;
13
+ };
14
+ type ErrorBoundaryState = {
15
+ readonly error: Error | undefined;
16
+ };
17
+ export declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
18
+ state: ErrorBoundaryState;
19
+ static getDerivedStateFromError(thrown: unknown): ErrorBoundaryState;
20
+ componentDidCatch(thrown: unknown, info: ErrorInfo): void;
21
+ private logCaught;
22
+ private reset;
23
+ render(): ReactNode;
24
+ }
25
+ export {};
@@ -0,0 +1,35 @@
1
+ import { ERROR_BOUNDARY_LOG_MARKER } from "@cosmicdrift/kumiko-types/error-boundary";
2
+ import { Component } from "react";
3
+ function toError(thrown) {
4
+ return thrown instanceof Error ? thrown : new Error(String(thrown));
5
+ }
6
+ export class ErrorBoundary extends Component {
7
+ state = { error: undefined };
8
+ static getDerivedStateFromError(thrown) {
9
+ return { error: toError(thrown) };
10
+ }
11
+ componentDidCatch(thrown, info) {
12
+ const error = toError(thrown);
13
+ this.logCaught(error, info.componentStack);
14
+ try {
15
+ this.props.onError?.(error, info);
16
+ }
17
+ catch (handlerError) {
18
+ // A throw escaping componentDidCatch hands the error to the next boundary up, so a broken telemetry hook would replace the screen card with the root fallback.
19
+ this.logCaught(toError(handlerError), "onError handler threw");
20
+ }
21
+ }
22
+ logCaught(error, detail) {
23
+ // biome-ignore lint/suspicious/noConsole: the client has no logger and the boundary must not swallow the error; the e2e fixture detects boundary failures via this exact console.error line
24
+ console.error(`[kumiko] ${this.props.scope} ${ERROR_BOUNDARY_LOG_MARKER}:`, error, detail);
25
+ }
26
+ reset = () => {
27
+ this.setState({ error: undefined });
28
+ };
29
+ render() {
30
+ const { error } = this.state;
31
+ if (error === undefined)
32
+ return this.props.children;
33
+ return this.props.fallback({ error, reset: this.reset });
34
+ }
35
+ }
@@ -135,6 +135,9 @@ export const kumikoDefaultTranslations = {
135
135
  "kumiko.app-boot.no-open-screen": "This app has no screen that's accessible without a role restriction.",
136
136
  "kumiko.widget.loading": "Loading…",
137
137
  "kumiko.widget.error.title": "Couldn't load.",
138
+ "kumiko.screen-error.title": "This screen failed to render.",
139
+ "kumiko.screen-error.detail": "Screen: {screen}. {message}",
140
+ "kumiko.screen-error.screen": "Screen: {screen}",
138
141
  "kumiko.widget.upload.uploading": "Uploading…",
139
142
  "kumiko.widget.upload.done": "Uploaded",
140
143
  "kumiko.widget.upload.error": "Failed",
package/dist/index.d.ts CHANGED
@@ -33,6 +33,8 @@ export type { VariableChipsProps } from "./app/variable-chips.js";
33
33
  export { VariableChips } from "./app/variable-chips.js";
34
34
  export { evalVisibleWhen, type VisibleWhenVerdict } from "./app/visible-when.js";
35
35
  export { dispatcherErrorText, WriteFailedError } from "./app/write-failed-error.js";
36
+ export type { ErrorBoundaryFallbackProps, ErrorBoundaryProps, } from "./components/error-boundary.js";
37
+ export { ErrorBoundary } from "./components/error-boundary.js";
36
38
  export { RelatedListSection } from "./components/related-list-section.js";
37
39
  export type { RenderEditAction, RenderEditChangeState, RenderEditControls, RenderEditProps, } from "./components/render-edit.js";
38
40
  export { RenderEdit } from "./components/render-edit.js";
package/dist/index.js CHANGED
@@ -28,6 +28,7 @@ export { useEmbeddedScreen } from "./app/use-embedded-screen.js";
28
28
  export { VariableChips } from "./app/variable-chips.js";
29
29
  export { evalVisibleWhen } from "./app/visible-when.js";
30
30
  export { dispatcherErrorText, WriteFailedError } from "./app/write-failed-error.js";
31
+ export { ErrorBoundary } from "./components/error-boundary.js";
31
32
  export { RelatedListSection } from "./components/related-list-section.js";
32
33
  export { RenderEdit } from "./components/render-edit.js";
33
34
  export { needsActionConfirm } from "./components/render-edit-action-button.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-renderer",
3
- "version": "0.365.1",
3
+ "version": "0.366.0",
4
4
  "description": "Platform-agnostic React renderer for Kumiko screens. Contains the shared logic — primitives-contract, hooks, KumikoScreen, navigation & SSE abstractions — that any platform-specific renderer (web, native) composes. No DOM, no EventSource, no react-dom.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -15,9 +15,9 @@
15
15
  }
16
16
  },
17
17
  "dependencies": {
18
- "@cosmicdrift/kumiko-framework": "0.365.1",
19
- "@cosmicdrift/kumiko-headless": "0.365.1",
20
- "@cosmicdrift/kumiko-types": "0.365.1",
18
+ "@cosmicdrift/kumiko-framework": "0.366.0",
19
+ "@cosmicdrift/kumiko-headless": "0.366.0",
20
+ "@cosmicdrift/kumiko-types": "0.366.0",
21
21
  "react": "^19.2.6",
22
22
  "temporal-polyfill": "^0.3.2",
23
23
  "zod": "^4.4.3"
@@ -28,7 +28,7 @@
28
28
  "@types/react-dom": "^19.2.3",
29
29
  "jsdom": "^29.1.1",
30
30
  "react-dom": "^19.2.6",
31
- "@cosmicdrift/kumiko-locale-de": "0.365.1"
31
+ "@cosmicdrift/kumiko-locale-de": "0.366.0"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",