Skip to content

Commit

Permalink
feat: Added HtmlTimeout error when timeouts happens
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurfiorette committed Apr 3, 2024
1 parent fbcb4e8 commit 4f663f8
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 27 deletions.
5 changes: 5 additions & 0 deletions .changeset/rotten-fans-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kitajs/html': minor
---

Added HtmlTimeout error when timeouts happens'
11 changes: 4 additions & 7 deletions packages/html/error-boundary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@ import type { Children } from '.';
/** A component that adds an error boundary to catch any inner promise rejection. */
export function ErrorBoundary(props: ErrorBoundaryProps): JSX.Element;

/**
* Checks if the error is a timeout error thrown by the ErrorBoundary's `timeout`
* property.
*
* @param error The error to check.
*/
export function isTimeoutError(error: unknown): error is Error & { message: 'timeout' };
/** An error thrown by the ErrorBoundary's `timeout` property. */
export class HtmlTimeout extends Error {}

/**
* The props for the `ErrorBoundary` component.
Expand All @@ -25,6 +20,8 @@ export interface ErrorBoundaryProps {
*
* The error will be string `timeout` if the rejection was caused by the `timeout`
* property.
*
* If the timeout gets triggered, it will throw an {@linkcode HtmlTimeout} error.
*/
catch: JSX.Element | ((error: unknown) => JSX.Element);

Expand Down
30 changes: 12 additions & 18 deletions packages/html/error-boundary.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
const { contentsToString } = require('./index');
const { setTimeout } = require('timers/promises');

const TIMEOUT_SYMBOL = Symbol.for('kHtmlTimeout');

/** @type {import('./error-boundary').isTimeoutError} */
function isTimeoutError(error) {
// @ts-expect-error
return error && error[TIMEOUT_SYMBOL];
}
const { contentToString } = require('./index');
const { setTimeout } = require('node:timers/promises');

/** @type {import('./error-boundary').ErrorBoundary} */
function ErrorBoundary(props) {
// Joins the content into a string or promise of string
let children = contentsToString([props.children]);
let children = contentToString(props.children);

// Sync children, just render them
if (typeof children === 'string') {
Expand All @@ -23,12 +15,7 @@ function ErrorBoundary(props) {
if (props.timeout) {
children = Promise.race([
children,
setTimeout(props.timeout).then(function reject() {
const error = new Error('Children timed out.');
// @ts-expect-error - should be internal
error[TIMEOUT_SYMBOL] = true;
throw error;
})
setTimeout(props.timeout).then(HtmlTimeout.reject)
]);
}

Expand All @@ -43,5 +30,12 @@ function ErrorBoundary(props) {
});
}

class HtmlTimeout extends Error {
/** @returns {string} */
static reject() {
throw new HtmlTimeout('Children timed out.');
}
}

module.exports.ErrorBoundary = ErrorBoundary;
module.exports.isTimeoutError = isTimeoutError;
module.exports.HtmlTimeout = HtmlTimeout;
4 changes: 2 additions & 2 deletions packages/html/test/error-boundary.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from 'node:assert';
import { describe, it } from 'node:test';
import { setTimeout } from 'timers/promises';
import { ErrorBoundary, isTimeoutError } from '../error-boundary';
import { ErrorBoundary, HtmlTimeout } from '../error-boundary';

describe('Error Boundary', () => {
it('should render error boundary', async () => {
Expand Down Expand Up @@ -68,7 +68,7 @@ describe('Error Boundary', () => {
<>
<ErrorBoundary
catch={(err) => {
assert.ok(isTimeoutError(err));
assert.ok(err instanceof HtmlTimeout);
return <div>1</div>;
}}
timeout={10}
Expand Down

0 comments on commit 4f663f8

Please sign in to comment.