From eecd9a2fb9e77764d02bdca508d3310f9c8e28e4 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 15 Oct 2025 08:51:58 +0000
Subject: [PATCH 1/6] Initial plan
From e381c6dc94b0d824b6d17233dd49c831cc61765d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 15 Oct 2025 09:02:31 +0000
Subject: [PATCH 2/6] Initial exploration and analysis of ErrorBoundary
non-Error handling
Co-authored-by: manudeli <61593290+manudeli@users.noreply.github.com>
---
.../tsconfig.tsbuildinfo | 2 +-
.../react/src/test-non-error-manual.spec.tsx | 78 +++++++++++++++++++
2 files changed, 79 insertions(+), 1 deletion(-)
create mode 100644 packages/react/src/test-non-error-manual.spec.tsx
diff --git a/examples/vite-react-18-suspense-prerender-siblings-problem/tsconfig.tsbuildinfo b/examples/vite-react-18-suspense-prerender-siblings-problem/tsconfig.tsbuildinfo
index 832ae3958..6270cb2ff 100644
--- a/examples/vite-react-18-suspense-prerender-siblings-problem/tsconfig.tsbuildinfo
+++ b/examples/vite-react-18-suspense-prerender-siblings-problem/tsconfig.tsbuildinfo
@@ -1 +1 @@
-{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./vite.config.ts"],"version":"5.8.3"}
\ No newline at end of file
+{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./vite.config.ts"],"version":"5.9.2"}
\ No newline at end of file
diff --git a/packages/react/src/test-non-error-manual.spec.tsx b/packages/react/src/test-non-error-manual.spec.tsx
new file mode 100644
index 000000000..eac632c17
--- /dev/null
+++ b/packages/react/src/test-non-error-manual.spec.tsx
@@ -0,0 +1,78 @@
+import { render, screen } from '@testing-library/react'
+import { createElement } from 'react'
+import { describe, it, expect, vi } from 'vitest'
+import { ErrorBoundary } from './ErrorBoundary'
+
+describe('ErrorBoundary with non-Error objects thrown', () => {
+ it('should convert null to Error', () => {
+ const fallbackFn = vi.fn<[{ error: Error }], JSX.Element>()
+ fallbackFn.mockImplementation(({ error }) =>
error: {error instanceof Error ? 'Error' : typeof error}
)
+
+ render(
+
+ {createElement(() => {
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
+ throw null
+ })}
+
+ )
+
+ expect(fallbackFn).toHaveBeenCalled()
+ const error = fallbackFn.mock.calls[0][0].error
+ console.log('null thrown - error:', error, 'instanceof Error:', error instanceof Error)
+ })
+
+ it('should convert string to Error', () => {
+ const fallbackFn = vi.fn<[{ error: Error }], JSX.Element>()
+ fallbackFn.mockImplementation(({ error }) => error: {error instanceof Error ? 'Error' : typeof error}
)
+
+ render(
+
+ {createElement(() => {
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
+ throw 'string error'
+ })}
+
+ )
+
+ expect(fallbackFn).toHaveBeenCalled()
+ const error = fallbackFn.mock.calls[0][0].error
+ console.log('string thrown - error:', error, 'instanceof Error:', error instanceof Error)
+ })
+
+ it('should convert number to Error', () => {
+ const fallbackFn = vi.fn<[{ error: Error }], JSX.Element>()
+ fallbackFn.mockImplementation(({ error }) => error: {error instanceof Error ? 'Error' : typeof error}
)
+
+ render(
+
+ {createElement(() => {
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
+ throw 42
+ })}
+
+ )
+
+ expect(fallbackFn).toHaveBeenCalled()
+ const error = fallbackFn.mock.calls[0][0].error
+ console.log('number thrown - error:', error, 'instanceof Error:', error instanceof Error)
+ })
+
+ it('should convert object to Error', () => {
+ const fallbackFn = vi.fn<[{ error: Error }], JSX.Element>()
+ fallbackFn.mockImplementation(({ error }) => error: {error instanceof Error ? 'Error' : typeof error}
)
+
+ render(
+
+ {createElement(() => {
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
+ throw { message: 'object error' }
+ })}
+
+ )
+
+ expect(fallbackFn).toHaveBeenCalled()
+ const error = fallbackFn.mock.calls[0][0].error
+ console.log('object thrown - error:', error, 'instanceof Error:', error instanceof Error)
+ })
+})
From 7e6204fba02b732bc691fd701949abc828d088d0 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 15 Oct 2025 09:07:53 +0000
Subject: [PATCH 3/6] Convert non-Error objects to Error instances in
ErrorBoundary
Co-authored-by: manudeli <61593290+manudeli@users.noreply.github.com>
---
packages/react/src/ErrorBoundary.spec.tsx | 97 ++++++++++++++++++-
packages/react/src/ErrorBoundary.tsx | 2 +-
.../react/src/test-non-error-manual.spec.tsx | 78 ---------------
3 files changed, 97 insertions(+), 80 deletions(-)
delete mode 100644 packages/react/src/test-non-error-manual.spec.tsx
diff --git a/packages/react/src/ErrorBoundary.spec.tsx b/packages/react/src/ErrorBoundary.spec.tsx
index 3ea52a297..114a4ff61 100644
--- a/packages/react/src/ErrorBoundary.spec.tsx
+++ b/packages/react/src/ErrorBoundary.spec.tsx
@@ -1,6 +1,6 @@
import { act, render, screen } from '@testing-library/react'
import { userEvent } from '@testing-library/user-event'
-import { type ComponentRef, createElement, createRef } from 'react'
+import { type ComponentRef, type ReactNode, createElement, createRef } from 'react'
import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary'
import {
ErrorBoundary,
@@ -84,6 +84,101 @@ describe(' ', () => {
expect(onError).toHaveBeenCalledTimes(1)
})
+ it('should convert null to Error instance', () => {
+ const fallbackFn = vi.fn<(props: ErrorBoundaryFallbackProps) => ReactNode>()
+ fallbackFn.mockImplementation(({ error }) => {error.message}
)
+
+ render(
+
+ {createElement(() => {
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
+ throw null
+ })}
+
+ )
+
+ expect(fallbackFn).toHaveBeenCalled()
+ const error = fallbackFn.mock.calls[0][0].error
+ expect(error).toBeInstanceOf(Error)
+ expect(error.message).toBe('null')
+ })
+
+ it('should convert string to Error instance', () => {
+ const fallbackFn = vi.fn<(props: ErrorBoundaryFallbackProps) => ReactNode>()
+ fallbackFn.mockImplementation(({ error }) => {error.message}
)
+
+ render(
+
+ {createElement(() => {
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
+ throw 'string error'
+ })}
+
+ )
+
+ expect(fallbackFn).toHaveBeenCalled()
+ const error = fallbackFn.mock.calls[0][0].error
+ expect(error).toBeInstanceOf(Error)
+ expect(error.message).toBe('string error')
+ })
+
+ it('should convert number to Error instance', () => {
+ const fallbackFn = vi.fn<(props: ErrorBoundaryFallbackProps) => ReactNode>()
+ fallbackFn.mockImplementation(({ error }) => {error.message}
)
+
+ render(
+
+ {createElement(() => {
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
+ throw 42
+ })}
+
+ )
+
+ expect(fallbackFn).toHaveBeenCalled()
+ const error = fallbackFn.mock.calls[0][0].error
+ expect(error).toBeInstanceOf(Error)
+ expect(error.message).toBe('42')
+ })
+
+ it('should convert plain object to Error instance', () => {
+ const fallbackFn = vi.fn<(props: ErrorBoundaryFallbackProps) => ReactNode>()
+ fallbackFn.mockImplementation(({ error }) => {error.message}
)
+
+ render(
+
+ {createElement(() => {
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
+ throw { message: 'object error' }
+ })}
+
+ )
+
+ expect(fallbackFn).toHaveBeenCalled()
+ const error = fallbackFn.mock.calls[0][0].error
+ expect(error).toBeInstanceOf(Error)
+ expect(error.message).toBe('[object Object]')
+ })
+
+ it('should keep Error instance as-is when Error is thrown', () => {
+ const fallbackFn = vi.fn<(props: ErrorBoundaryFallbackProps) => ReactNode>()
+ fallbackFn.mockImplementation(({ error }) => {error.message}
)
+ const originalError = new Error('original error')
+
+ render(
+
+ {createElement(() => {
+ throw originalError
+ })}
+
+ )
+
+ expect(fallbackFn).toHaveBeenCalled()
+ const error = fallbackFn.mock.calls[0][0].error
+ expect(error).toBeInstanceOf(Error)
+ expect(error).toBe(originalError)
+ })
+
it('should be reset by items of resetKeys, and call onReset', async () => {
const onReset = vi.fn()
diff --git a/packages/react/src/ErrorBoundary.tsx b/packages/react/src/ErrorBoundary.tsx
index a93683c9f..3a7c2b43f 100644
--- a/packages/react/src/ErrorBoundary.tsx
+++ b/packages/react/src/ErrorBoundary.tsx
@@ -133,7 +133,7 @@ class BaseErrorBoundary extends Component<
ErrorBoundaryState
> {
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
- return { isError: true, error }
+ return { isError: true, error: error instanceof Error ? error : new Error(String(error)) }
}
state = initialErrorBoundaryState
diff --git a/packages/react/src/test-non-error-manual.spec.tsx b/packages/react/src/test-non-error-manual.spec.tsx
deleted file mode 100644
index eac632c17..000000000
--- a/packages/react/src/test-non-error-manual.spec.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import { render, screen } from '@testing-library/react'
-import { createElement } from 'react'
-import { describe, it, expect, vi } from 'vitest'
-import { ErrorBoundary } from './ErrorBoundary'
-
-describe('ErrorBoundary with non-Error objects thrown', () => {
- it('should convert null to Error', () => {
- const fallbackFn = vi.fn<[{ error: Error }], JSX.Element>()
- fallbackFn.mockImplementation(({ error }) => error: {error instanceof Error ? 'Error' : typeof error}
)
-
- render(
-
- {createElement(() => {
- // eslint-disable-next-line @typescript-eslint/only-throw-error
- throw null
- })}
-
- )
-
- expect(fallbackFn).toHaveBeenCalled()
- const error = fallbackFn.mock.calls[0][0].error
- console.log('null thrown - error:', error, 'instanceof Error:', error instanceof Error)
- })
-
- it('should convert string to Error', () => {
- const fallbackFn = vi.fn<[{ error: Error }], JSX.Element>()
- fallbackFn.mockImplementation(({ error }) => error: {error instanceof Error ? 'Error' : typeof error}
)
-
- render(
-
- {createElement(() => {
- // eslint-disable-next-line @typescript-eslint/only-throw-error
- throw 'string error'
- })}
-
- )
-
- expect(fallbackFn).toHaveBeenCalled()
- const error = fallbackFn.mock.calls[0][0].error
- console.log('string thrown - error:', error, 'instanceof Error:', error instanceof Error)
- })
-
- it('should convert number to Error', () => {
- const fallbackFn = vi.fn<[{ error: Error }], JSX.Element>()
- fallbackFn.mockImplementation(({ error }) => error: {error instanceof Error ? 'Error' : typeof error}
)
-
- render(
-
- {createElement(() => {
- // eslint-disable-next-line @typescript-eslint/only-throw-error
- throw 42
- })}
-
- )
-
- expect(fallbackFn).toHaveBeenCalled()
- const error = fallbackFn.mock.calls[0][0].error
- console.log('number thrown - error:', error, 'instanceof Error:', error instanceof Error)
- })
-
- it('should convert object to Error', () => {
- const fallbackFn = vi.fn<[{ error: Error }], JSX.Element>()
- fallbackFn.mockImplementation(({ error }) => error: {error instanceof Error ? 'Error' : typeof error}
)
-
- render(
-
- {createElement(() => {
- // eslint-disable-next-line @typescript-eslint/only-throw-error
- throw { message: 'object error' }
- })}
-
- )
-
- expect(fallbackFn).toHaveBeenCalled()
- const error = fallbackFn.mock.calls[0][0].error
- console.log('object thrown - error:', error, 'instanceof Error:', error instanceof Error)
- })
-})
From a7796640fb16541dfa87a09cdb2314a4fa8b0977 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 15 Oct 2025 09:11:43 +0000
Subject: [PATCH 4/6] Also convert non-Error objects in componentDidCatch for
onError callback
Co-authored-by: manudeli <61593290+manudeli@users.noreply.github.com>
---
packages/react/src/ErrorBoundary.spec.tsx | 54 +++++++++++++++++++++++
packages/react/src/ErrorBoundary.tsx | 8 +++-
2 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/ErrorBoundary.spec.tsx b/packages/react/src/ErrorBoundary.spec.tsx
index 114a4ff61..de297a559 100644
--- a/packages/react/src/ErrorBoundary.spec.tsx
+++ b/packages/react/src/ErrorBoundary.spec.tsx
@@ -179,6 +179,60 @@ describe(' ', () => {
expect(error).toBe(originalError)
})
+ it('should pass Error instance to onError callback when null is thrown', () => {
+ const onError = vi.fn()
+
+ render(
+ fallback} onError={onError}>
+ {createElement(() => {
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
+ throw null
+ })}
+
+ )
+
+ expect(onError).toHaveBeenCalled()
+ const error = onError.mock.calls[0][0]
+ expect(error).toBeInstanceOf(Error)
+ expect(error.message).toBe('null')
+ })
+
+ it('should pass Error instance to onError callback when string is thrown', () => {
+ const onError = vi.fn()
+
+ render(
+ fallback} onError={onError}>
+ {createElement(() => {
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
+ throw 'string error'
+ })}
+
+ )
+
+ expect(onError).toHaveBeenCalled()
+ const error = onError.mock.calls[0][0]
+ expect(error).toBeInstanceOf(Error)
+ expect(error.message).toBe('string error')
+ })
+
+ it('should pass Error instance to onError callback when number is thrown', () => {
+ const onError = vi.fn()
+
+ render(
+ fallback} onError={onError}>
+ {createElement(() => {
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
+ throw 42
+ })}
+
+ )
+
+ expect(onError).toHaveBeenCalled()
+ const error = onError.mock.calls[0][0]
+ expect(error).toBeInstanceOf(Error)
+ expect(error.message).toBe('42')
+ })
+
it('should be reset by items of resetKeys, and call onReset', async () => {
const onReset = vi.fn()
diff --git a/packages/react/src/ErrorBoundary.tsx b/packages/react/src/ErrorBoundary.tsx
index 3a7c2b43f..a03da3a47 100644
--- a/packages/react/src/ErrorBoundary.tsx
+++ b/packages/react/src/ErrorBoundary.tsx
@@ -128,12 +128,16 @@ const initialErrorBoundaryState: ErrorBoundaryState = {
error: null,
}
+const convertToError = (error: unknown): Error => {
+ return error instanceof Error ? error : new Error(String(error))
+}
+
class BaseErrorBoundary extends Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
- return { isError: true, error: error instanceof Error ? error : new Error(String(error)) }
+ return { isError: true, error: convertToError(error) }
}
state = initialErrorBoundaryState
@@ -147,7 +151,7 @@ class BaseErrorBoundary extends Component<
}
componentDidCatch(error: InferError, info: ErrorInfo) {
- this.props.onError?.(error, info)
+ this.props.onError?.(convertToError(error) as InferError, info)
}
reset = () => {
From 109a5c0607127bb3bcfb9929668f2e1836e59f38 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 15 Oct 2025 09:22:12 +0000
Subject: [PATCH 5/6] Accept any type for error parameters following Sentry's
approach
Co-authored-by: manudeli <61593290+manudeli@users.noreply.github.com>
---
packages/react/src/ErrorBoundary.tsx | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/ErrorBoundary.tsx b/packages/react/src/ErrorBoundary.tsx
index a03da3a47..a292b1dcb 100644
--- a/packages/react/src/ErrorBoundary.tsx
+++ b/packages/react/src/ErrorBoundary.tsx
@@ -128,6 +128,9 @@ const initialErrorBoundaryState: ErrorBoundaryState = {
error: null,
}
+// Although `componentDidCatch` and `getDerivedStateFromError` are typed to accept an `Error` object,
+// they can also be invoked with non-error objects. This is why we need to convert them to Error instances.
+// See: https://github.com/getsentry/sentry-javascript/issues/6167
const convertToError = (error: unknown): Error => {
return error instanceof Error ? error : new Error(String(error))
}
@@ -136,7 +139,8 @@ class BaseErrorBoundary extends Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
- static getDerivedStateFromError(error: Error): ErrorBoundaryState {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ static getDerivedStateFromError(error: any): ErrorBoundaryState {
return { isError: true, error: convertToError(error) }
}
@@ -150,7 +154,8 @@ class BaseErrorBoundary extends Component<
}
}
- componentDidCatch(error: InferError, info: ErrorInfo) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ componentDidCatch(error: any, info: ErrorInfo) {
this.props.onError?.(convertToError(error) as InferError, info)
}
From 7f72a40a68f01a69852f710e5c94430177300868 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 30 Mar 2026 14:30:38 +0000
Subject: [PATCH 6/6] rebase: sync with latest main and improve convertToError
for transpiled errors
Agent-Logs-Url: https://github.com/toss/suspensive/sessions/756980dc-448c-442f-ab4c-ac285ee7b39e
---
.changeset/config.json | 8 +-
.github/CODEOWNERS | 2 +-
.github/ISSUE_TEMPLATE/bug.yml | 3 +-
.github/ISSUE_TEMPLATE/feature_request.yml | 3 +-
.github/actions/pnpm-setup-node/action.yml | 4 +-
.github/labeler.yml | 46 +-
.github/workflows/autofix.yml | 6 +-
.github/workflows/broken-link-checker.yml | 2 +-
.github/workflows/ci.yml | 8 +-
.github/workflows/graph.yml | 8 +-
.github/workflows/knip.yml | 2 +-
.github/workflows/labeler.yml | 6 +-
.github/workflows/release.yml | 13 +-
.gitignore | 15 +-
.lintstagedrc | 2 +-
.nvmrc | 2 +-
.vscode/extensions.json | 7 +-
.vscode/settings.json | 17 +-
README.md | 76 +-
codecov.yml | 8 -
configs/eslint-config/index.js | 8 +-
configs/eslint-config/package.json | 19 +-
configs/tsconfig/base.json | 2 +-
configs/tsdown/package.json | 21 +-
configs/tsdown/src/index.ts | 12 +-
docs/suspensive.org/.gitignore | 6 +
docs/suspensive.org/package.json | 24 +-
docs/suspensive.org/public/favicon.ico | Bin 0 -> 14532 bytes
docs/suspensive.org/public/img/logo_dark.svg | 128 +
.../next-streaming-react-query-example.gif | Bin 0 -> 978547 bytes
.../scripts/llms-txt/builders.ts | 72 +
.../suspensive.org/scripts/llms-txt/config.ts | 3 +
.../scripts/llms-txt/document-processor.ts | 116 +
.../scripts/llms-txt/generate-llms-txt.ts | 38 +
.../scripts/llms-txt/meta-parser.ts | 43 +
.../scripts/llms-txt/nextra-transform.ts | 65 +
docs/suspensive.org/scripts/llms-txt/types.ts | 13 +
.../src/app/[lang]/Providers.tsx | 15 +
.../src/app/[lang]/[[...mdxPath]]/page.tsx | 47 +-
.../src/app/[lang]/_components/Logo.tsx | 30 +-
docs/suspensive.org/src/app/[lang]/layout.tsx | 117 +-
docs/suspensive.org/src/app/[lang]/styles.css | 102 +-
docs/suspensive.org/src/app/api/og/route.tsx | 59 +
docs/suspensive.org/src/app/robots.ts | 12 +
docs/suspensive.org/src/app/sitemap.ts | 84 +
.../src/components/BubbleChart.tsx | 2 +-
.../src/components/CallToAction.tsx | 86 +
.../src/components/ComparisonTable.tsx | 178 +
.../src/components/FeatureGrid.tsx | 275 +
.../src/components/HomePage.tsx | 250 +-
docs/suspensive.org/src/components/Logo.tsx | 22 +-
.../src/components/NpmInstallCopyButton.tsx | 18 +-
.../src/components/Sandpack/baseTemplate.ts | 13 +-
.../src/components/Sandpack/index.tsx | 6 +-
.../src/components/Scrollycoding.tsx | 49 +-
.../src/components/SectionText.tsx | 6 +-
.../src/components/TrustedBy.tsx | 214 +-
docs/suspensive.org/src/components/index.ts | 4 +
docs/suspensive.org/src/constants.ts | 3 +
docs/suspensive.org/src/content/en/_meta.tsx | 13 +-
.../src/content/en/docs/_meta.tsx | 3 +-
.../src/content/en/docs/changelogs.mdx | 8 +-
.../src/content/en/docs/codemods/_meta.tsx | 2 +-
.../migrateQueryClientConsumerProps.mdx | 4 +
.../en/docs/codemods/migrateWithAPI.mdx | 4 +
.../content/en/docs/codemods/motivation.mdx | 10 +-
.../en/docs/codemods/removeNetworkmode.mdx | 4 +
.../en/docs/codemods/tanstackQueryImport.mdx | 4 +
.../src/content/en/docs/codemods/usage.mdx | 6 +-
.../src/content/en/docs/contributors.mdx | 29 +-
.../src/content/en/docs/introduction.mdx | 301 +-
.../src/content/en/docs/jotai/Atom.mdx | 4 +
.../src/content/en/docs/jotai/AtomValue.mdx | 4 +
.../src/content/en/docs/jotai/SetAtom.mdx | 4 +
.../src/content/en/docs/jotai/_meta.tsx | 2 +-
.../content/en/docs/jotai/installation.mdx | 6 +-
.../src/content/en/docs/jotai/motivation.mdx | 48 +-
.../src/content/en/docs/links.mdx | 4 +
.../en/docs/migration/migrate-to-v3.mdx | 1 -
.../en/docs/react-query/IsFetching.mdx | 4 +
.../content/en/docs/react-query/Mutation.mdx | 4 +
.../react-query/PrefetchInfiniteQuery.mdx | 43 +-
.../en/docs/react-query/PrefetchQuery.mdx | 43 +-
.../en/docs/react-query/QueriesHydration.mdx | 710 +
.../docs/react-query/QueryClientConsumer.mdx | 4 +
.../react-query/SuspenseInfiniteQuery.mdx | 4 +
.../en/docs/react-query/SuspenseQueries.mdx | 4 +
.../en/docs/react-query/SuspenseQuery.mdx | 30 +-
.../src/content/en/docs/react-query/_meta.tsx | 19 +-
.../docs/react-query/createGetQueryClient.mdx | 406 +
.../docs/react-query/infiniteQueryOptions.mdx | 5 +
.../en/docs/react-query/installation.mdx | 29 +-
.../react-query/migration/migrate-to-v2.mdx | 26 +-
.../en/docs/react-query/motivation.mdx | 48 +-
.../en/docs/react-query/mutationOptions.mdx | 4 +
.../en/docs/react-query/queryOptions.mdx | 5 +
.../react-query/usePrefetchInfiniteQuery.mdx | 4 +
.../en/docs/react-query/usePrefetchQuery.mdx | 4 +
.../react-query/useSuspenseInfiniteQuery.mdx | 13 +-
.../docs/react-query/useSuspenseQueries.mdx | 7 +-
.../en/docs/react-query/useSuspenseQuery.mdx | 9 +-
.../src/content/en/docs/react/ClientOnly.mdx | 33 +
.../en/docs/react/DefaultPropsProvider.mdx | 4 +
.../src/content/en/docs/react/Delay.mdx | 37 +
.../content/en/docs/react/ErrorBoundary.mdx | 539 +-
.../en/docs/react/ErrorBoundaryGroup.mdx | 6 +-
.../src/content/en/docs/react/Suspense.mdx | 60 +-
.../src/content/en/docs/react/_meta.tsx | 10 +-
.../src/content/en/docs/react/comparison.mdx | 279 +
.../content/en/docs/react/getting-started.mdx | 91 +
.../content/en/docs/react/installation.mdx | 6 +-
.../src/content/en/docs/react/lazy.mdx | 4 +
.../en/docs/react/migration/migrate-to-v2.mdx | 4 +-
.../src/content/en/docs/react/motivation.mdx | 40 +-
.../src/content/en/docs/react/useIsClient.mdx | 4 +
docs/suspensive.org/src/content/en/index.mdx | 810 +-
docs/suspensive.org/src/content/ko/_meta.tsx | 13 +-
.../src/content/ko/docs/_meta.tsx | 1 -
.../src/content/ko/docs/changelogs.mdx | 8 +-
.../src/content/ko/docs/codemods/_meta.tsx | 2 +-
.../migrateQueryClientConsumerProps.mdx | 4 +
.../ko/docs/codemods/migrateWithAPI.mdx | 4 +
.../content/ko/docs/codemods/motivation.mdx | 10 +-
.../ko/docs/codemods/removeNetworkmode.mdx | 4 +
.../ko/docs/codemods/tanstackQueryImport.mdx | 4 +
.../src/content/ko/docs/codemods/usage.mdx | 6 +-
.../src/content/ko/docs/contributors.mdx | 29 +-
.../src/content/ko/docs/introduction.mdx | 305 +-
.../src/content/ko/docs/jotai/Atom.mdx | 4 +
.../src/content/ko/docs/jotai/AtomValue.mdx | 4 +
.../src/content/ko/docs/jotai/SetAtom.mdx | 4 +
.../src/content/ko/docs/jotai/_meta.tsx | 2 +-
.../content/ko/docs/jotai/installation.mdx | 8 +-
.../src/content/ko/docs/jotai/motivation.mdx | 48 +-
.../src/content/ko/docs/links.mdx | 4 +
.../ko/docs/migration/migrate-to-v3.mdx | 1 -
.../ko/docs/react-query/IsFetching.mdx | 4 +
.../content/ko/docs/react-query/Mutation.mdx | 4 +
.../react-query/PrefetchInfiniteQuery.mdx | 43 +-
.../ko/docs/react-query/PrefetchQuery.mdx | 43 +-
.../ko/docs/react-query/QueriesHydration.mdx | 710 +
.../docs/react-query/QueryClientConsumer.mdx | 4 +
.../react-query/SuspenseInfiniteQuery.mdx | 4 +
.../ko/docs/react-query/SuspenseQueries.mdx | 4 +
.../ko/docs/react-query/SuspenseQuery.mdx | 4 +
.../src/content/ko/docs/react-query/_meta.tsx | 19 +-
.../docs/react-query/createGetQueryClient.mdx | 406 +
.../docs/react-query/infiniteQueryOptions.mdx | 4 +
.../ko/docs/react-query/installation.mdx | 31 +-
.../ko/docs/react-query/motivation.mdx | 48 +-
.../ko/docs/react-query/mutationOptions.mdx | 4 +
.../ko/docs/react-query/queryOptions.mdx | 4 +
.../react-query/usePrefetchInfiniteQuery.mdx | 4 +
.../ko/docs/react-query/usePrefetchQuery.mdx | 4 +
.../react-query/useSuspenseInfiniteQuery.mdx | 6 +-
.../docs/react-query/useSuspenseQueries.mdx | 6 +-
.../ko/docs/react-query/useSuspenseQuery.mdx | 6 +-
.../src/content/ko/docs/react/ClientOnly.mdx | 33 +
.../ko/docs/react/DefaultPropsProvider.mdx | 4 +
.../src/content/ko/docs/react/Delay.mdx | 37 +
.../content/ko/docs/react/ErrorBoundary.mdx | 531 +-
.../ko/docs/react/ErrorBoundaryGroup.mdx | 4 +
.../src/content/ko/docs/react/Suspense.mdx | 54 +-
.../src/content/ko/docs/react/_meta.tsx | 10 +-
.../src/content/ko/docs/react/comparison.mdx | 279 +
.../content/ko/docs/react/getting-started.mdx | 91 +
.../content/ko/docs/react/installation.mdx | 8 +-
.../src/content/ko/docs/react/lazy.mdx | 4 +
.../ko/docs/react/migration/migrate-to-v2.mdx | 2 +-
.../src/content/ko/docs/react/motivation.mdx | 39 +-
.../src/content/ko/docs/react/useIsClient.mdx | 4 +
docs/suspensive.org/src/content/ko/index.mdx | 805 +-
docs/suspensive.org/src/proxy.ts | 31 +
docs/suspensive.org/tsconfig.json | 7 +-
.../next-streaming-react-query/package.json | 5 +-
.../public/favicon.ico | Bin 0 -> 39535 bytes
.../public/img/banner.png | Bin 0 -> 38266 bytes
.../src/app/_components/Boxes.tsx | 12 +
.../src/app/_components/Buttons.tsx | 37 +
.../src/app/_components/Nav.tsx | 18 +
.../app/_components/ReactClientComponent.tsx | 16 +
.../src/app/api/text/route.ts | 22 +-
.../src/app/get-query-client.ts | 3 +
.../src/app/globals.css | 14 -
.../src/app/layout.tsx | 9 +-
.../src/app/page.tsx | 177 +-
.../src/app/providers.tsx | 20 +-
.../src/app/test/page.tsx | 57 +-
.../src/query/index.ts | 59 +-
.../next-streaming-react-query/tsconfig.json | 10 +-
examples/react-native-playground/.gitignore | 38 -
examples/react-native-playground/README.md | 50 -
examples/react-native-playground/app.json | 30 -
.../app/+not-found.tsx | 10 -
.../react-native-playground/app/_layout.tsx | 6 -
.../react-native-playground/app/index.tsx | 12 -
.../assets/images/adaptive-icon.png | Bin 17547 -> 0 bytes
.../assets/images/favicon.png | Bin 1466 -> 0 bytes
.../assets/images/icon.png | Bin 22380 -> 0 bytes
.../assets/images/splash-icon.png | Bin 17547 -> 0 bytes
examples/react-native-playground/package.json | 42 -
.../react-native-playground/tsconfig.json | 10 -
examples/visualization/package.json | 9 +-
examples/visualization/public/favicon.ico | Bin 0 -> 14532 bytes
examples/visualization/src/app/layout.tsx | 11 -
.../src/app/react/zodSearchParams/page.tsx | 58 +-
examples/visualization/tsconfig.json | 10 +-
.../package.json | 4 +-
knip.json | 30 +-
oxfmt.config.ts | 42 +
package.json | 46 +-
packages/codemods/CHANGELOG.md | 60 +
packages/codemods/package.json | 2 +-
packages/codemods/src/bin/transformRunner.ts | 2 +-
.../src/transforms/tanstack-query-import.ts | 2 +-
packages/codemods/tsconfig.json | 1 +
packages/codemods/tsdown.config.ts | 2 +
packages/jotai/CHANGELOG.md | 67 +
packages/jotai/README.md | 2 -
packages/jotai/package.json | 10 +-
packages/jotai/src/Atom.tsx | 1 +
packages/jotai/src/AtomValue.tsx | 1 +
packages/jotai/src/SetAtom.tsx | 1 +
packages/next/CHANGELOG.md | 43 +
packages/{react-dom => next}/LICENSE | 0
.../next}/eslint.config.mjs | 0
packages/{react-dom => next}/package.json | 33 +-
packages/next/src/index.ts | 17 +
packages/next/src/react-server.ts | 12 +
packages/{react-dom => next}/tsconfig.json | 2 +-
packages/{react-dom => next}/tsdown.config.ts | 0
packages/next/vitest.config.ts | 14 +
packages/{react-dom => next}/vitest.setup.ts | 1 +
packages/react-dom/CHANGELOG.md | 262 -
packages/react-dom/eslint.config.mjs | 15 -
packages/react-dom/src/FadeIn.spec.tsx | 42 -
packages/react-dom/src/FadeIn.test-d.tsx | 20 -
packages/react-dom/src/FadeIn.tsx | 23 -
packages/react-dom/src/InView.spec.tsx | 71 -
packages/react-dom/src/InView.tsx | 13 -
.../react-dom/src/browser/browser.spec.tsx | 43 -
packages/react-dom/src/index.ts | 4 -
packages/react-dom/src/test-utils/index.ts | 181 -
packages/react-dom/src/useFadeIn.spec.tsx | 25 -
packages/react-dom/src/useFadeIn.ts | 54 -
packages/react-dom/src/useInView.spec.tsx | 348 -
packages/react-dom/src/useInView.tsx | 89 -
.../src/utility-types/OmitKeyof.test-d.ts | 176 -
.../react-dom/src/utility-types/OmitKeyof.ts | 11 -
packages/react-dom/src/utils/observe.spec.ts | 209 -
packages/react-dom/src/utils/observe.ts | 128 -
packages/react-dom/vitest.config.ts | 41 -
packages/react-native/CHANGELOG.md | 182 -
packages/react-native/LICENSE | 21 -
packages/react-native/babel.config.cjs | 7 -
packages/react-native/eslint.config.mjs | 15 -
packages/react-native/jest.config.ts | 11 -
packages/react-native/jest.setup.ts | 1 -
packages/react-native/package.json | 70 -
packages/react-native/src/TestText.spec.tsx | 11 -
packages/react-native/src/TestText.tsx | 3 -
packages/react-native/src/index.ts | 1 -
packages/react-native/tsconfig.json | 7 -
packages/react-native/tsdown.config.ts | 4 -
packages/react-query-4/CHANGELOG.md | 104 +
packages/react-query-4/package.json | 10 +-
.../react-query-4/src/IsFetching.spec.tsx | 34 +
packages/react-query-4/src/IsFetching.tsx | 5 +-
packages/react-query-4/src/Mutation.tsx | 1 +
.../src/PrefetchInfiniteQuery.tsx | 1 +
packages/react-query-4/src/PrefetchQuery.tsx | 1 +
.../src/QueriesHydration.spec.tsx | 543 +
.../src/QueriesHydration.test-d.tsx | 90 +
.../react-query-4/src/QueriesHydration.tsx | 149 +
.../react-query-4/src/QueryClientConsumer.tsx | 1 +
.../src/SuspenseInfiniteQuery.tsx | 1 +
.../react-query-4/src/SuspenseQueries.tsx | 1 +
packages/react-query-4/src/SuspenseQuery.tsx | 1 +
.../src/components/ClientOnly.tsx | 12 +
.../src/createGetQueryClient.spec.tsx | 66 +
.../src/createGetQueryClient.test-d.tsx | 14 +
.../react-query-4/src/createGetQueryClient.ts | 78 +
packages/react-query-4/src/index.ts | 2 +
.../src/usePrefetchInfiniteQuery.ts | 1 +
.../react-query-4/src/usePrefetchQuery.ts | 1 +
.../src/useSuspenseInfiniteQuery.ts | 1 +
.../react-query-4/src/useSuspenseQueries.ts | 1 +
.../react-query-4/src/useSuspenseQuery.ts | 1 +
packages/react-query-5/CHANGELOG.md | 102 +
packages/react-query-5/package.json | 10 +-
packages/react-query-5/src/IsFetching.tsx | 1 +
packages/react-query-5/src/Mutation.tsx | 1 +
.../src/PrefetchInfiniteQuery.tsx | 1 +
packages/react-query-5/src/PrefetchQuery.tsx | 1 +
.../src/QueriesHydration.spec.tsx | 546 +
.../src/QueriesHydration.test-d.tsx | 91 +
.../react-query-5/src/QueriesHydration.tsx | 145 +
.../react-query-5/src/QueryClientConsumer.tsx | 1 +
.../src/SuspenseInfiniteQuery.tsx | 1 +
.../react-query-5/src/SuspenseQueries.tsx | 1 +
packages/react-query-5/src/SuspenseQuery.tsx | 1 +
.../src/components/ClientOnly.tsx | 12 +
.../src/createGetQueryClient.spec.tsx | 66 +
.../src/createGetQueryClient.test-d.tsx | 14 +
.../react-query-5/src/createGetQueryClient.ts | 78 +
packages/react-query-5/src/index.ts | 2 +
.../src/usePrefetchInfiniteQuery.ts | 1 +
.../react-query-5/src/usePrefetchQuery.ts | 1 +
.../src/useSuspenseInfiniteQuery.ts | 1 +
.../react-query-5/src/useSuspenseQueries.ts | 1 +
.../react-query-5/src/useSuspenseQuery.ts | 1 +
packages/react-query/CHANGELOG.md | 208 +
packages/react-query/README.md | 21 +-
packages/react-query/package.json | 16 +-
packages/react-query/src/bin/cli.spec.ts | 12 +-
packages/react-query/src/bin/cli.ts | 2 +
.../react-query/src/bin/postinstall.spec.ts | 13 +-
packages/react-query/src/bin/postinstall.ts | 9 +-
.../src/bin/utils/commands.spec.ts | 6 +-
.../react-query/src/bin/utils/copy.spec.ts | 2 +-
.../src/bin/utils/deprecationWarning.ts | 29 +
packages/react-query/src/bin/utils/logger.ts | 1 +
.../react-query/src/bin/utils/package.spec.ts | 87 +-
packages/react-query/src/bin/utils/package.ts | 6 +-
packages/react-query/src/index.ts | 2 +
packages/react-query/src/v4.ts | 2 +
packages/react-query/src/v5.ts | 2 +
packages/react/CHANGELOG.md | 79 +
packages/react/README.md | 4 -
packages/react/package.json | 14 +-
packages/react/src/ClientOnly.tsx | 1 +
packages/react/src/DefaultProps.spec.tsx | 22 +-
packages/react/src/DefaultProps.tsx | 1 +
packages/react/src/Delay.spec.tsx | 14 +-
packages/react/src/Delay.tsx | 5 +-
packages/react/src/ErrorBoundary.spec.tsx | 100 +-
packages/react/src/ErrorBoundary.tsx | 38 +-
.../react/src/ErrorBoundaryGroup.spec.tsx | 28 +-
packages/react/src/ErrorBoundaryGroup.tsx | 7 +-
packages/react/src/Suspense.spec.tsx | 4 +-
packages/react/src/Suspense.tsx | 5 +-
packages/react/src/lazy.spec.tsx | 144 +
packages/react/src/lazy.ts | 1 +
.../react/src/models/SuspensiveError.spec.tsx | 12 +-
packages/react/src/useIsClient.ts | 1 +
pnpm-lock.yaml | 12638 ++++++----------
pnpm-workspace.yaml | 39 +-
turbo.json | 5 +-
348 files changed, 16547 insertions(+), 12442 deletions(-)
create mode 100644 docs/suspensive.org/public/favicon.ico
create mode 100644 docs/suspensive.org/public/img/logo_dark.svg
create mode 100644 docs/suspensive.org/public/img/next-streaming-react-query-example.gif
create mode 100644 docs/suspensive.org/scripts/llms-txt/builders.ts
create mode 100644 docs/suspensive.org/scripts/llms-txt/config.ts
create mode 100644 docs/suspensive.org/scripts/llms-txt/document-processor.ts
create mode 100644 docs/suspensive.org/scripts/llms-txt/generate-llms-txt.ts
create mode 100644 docs/suspensive.org/scripts/llms-txt/meta-parser.ts
create mode 100644 docs/suspensive.org/scripts/llms-txt/nextra-transform.ts
create mode 100644 docs/suspensive.org/scripts/llms-txt/types.ts
create mode 100644 docs/suspensive.org/src/app/[lang]/Providers.tsx
create mode 100644 docs/suspensive.org/src/app/api/og/route.tsx
create mode 100644 docs/suspensive.org/src/app/robots.ts
create mode 100644 docs/suspensive.org/src/app/sitemap.ts
create mode 100644 docs/suspensive.org/src/components/CallToAction.tsx
create mode 100644 docs/suspensive.org/src/components/ComparisonTable.tsx
create mode 100644 docs/suspensive.org/src/components/FeatureGrid.tsx
create mode 100644 docs/suspensive.org/src/constants.ts
create mode 100644 docs/suspensive.org/src/content/en/docs/react-query/QueriesHydration.mdx
create mode 100644 docs/suspensive.org/src/content/en/docs/react-query/createGetQueryClient.mdx
create mode 100644 docs/suspensive.org/src/content/en/docs/react/comparison.mdx
create mode 100644 docs/suspensive.org/src/content/en/docs/react/getting-started.mdx
create mode 100644 docs/suspensive.org/src/content/ko/docs/react-query/QueriesHydration.mdx
create mode 100644 docs/suspensive.org/src/content/ko/docs/react-query/createGetQueryClient.mdx
create mode 100644 docs/suspensive.org/src/content/ko/docs/react/comparison.mdx
create mode 100644 docs/suspensive.org/src/content/ko/docs/react/getting-started.mdx
create mode 100644 docs/suspensive.org/src/proxy.ts
create mode 100644 examples/next-streaming-react-query/public/favicon.ico
create mode 100644 examples/next-streaming-react-query/public/img/banner.png
create mode 100644 examples/next-streaming-react-query/src/app/_components/Boxes.tsx
create mode 100644 examples/next-streaming-react-query/src/app/_components/Buttons.tsx
create mode 100644 examples/next-streaming-react-query/src/app/_components/Nav.tsx
create mode 100644 examples/next-streaming-react-query/src/app/_components/ReactClientComponent.tsx
create mode 100644 examples/next-streaming-react-query/src/app/get-query-client.ts
delete mode 100644 examples/react-native-playground/.gitignore
delete mode 100644 examples/react-native-playground/README.md
delete mode 100644 examples/react-native-playground/app.json
delete mode 100644 examples/react-native-playground/app/+not-found.tsx
delete mode 100644 examples/react-native-playground/app/_layout.tsx
delete mode 100644 examples/react-native-playground/app/index.tsx
delete mode 100644 examples/react-native-playground/assets/images/adaptive-icon.png
delete mode 100644 examples/react-native-playground/assets/images/favicon.png
delete mode 100644 examples/react-native-playground/assets/images/icon.png
delete mode 100644 examples/react-native-playground/assets/images/splash-icon.png
delete mode 100644 examples/react-native-playground/package.json
delete mode 100644 examples/react-native-playground/tsconfig.json
create mode 100644 examples/visualization/public/favicon.ico
create mode 100644 oxfmt.config.ts
create mode 100644 packages/next/CHANGELOG.md
rename packages/{react-dom => next}/LICENSE (100%)
rename {examples/react-native-playground => packages/next}/eslint.config.mjs (100%)
rename packages/{react-dom => next}/package.json (60%)
create mode 100644 packages/next/src/index.ts
create mode 100644 packages/next/src/react-server.ts
rename packages/{react-dom => next}/tsconfig.json (79%)
rename packages/{react-dom => next}/tsdown.config.ts (100%)
create mode 100644 packages/next/vitest.config.ts
rename packages/{react-dom => next}/vitest.setup.ts (76%)
delete mode 100644 packages/react-dom/CHANGELOG.md
delete mode 100644 packages/react-dom/eslint.config.mjs
delete mode 100644 packages/react-dom/src/FadeIn.spec.tsx
delete mode 100644 packages/react-dom/src/FadeIn.test-d.tsx
delete mode 100644 packages/react-dom/src/FadeIn.tsx
delete mode 100644 packages/react-dom/src/InView.spec.tsx
delete mode 100644 packages/react-dom/src/InView.tsx
delete mode 100644 packages/react-dom/src/browser/browser.spec.tsx
delete mode 100644 packages/react-dom/src/index.ts
delete mode 100644 packages/react-dom/src/test-utils/index.ts
delete mode 100644 packages/react-dom/src/useFadeIn.spec.tsx
delete mode 100644 packages/react-dom/src/useFadeIn.ts
delete mode 100644 packages/react-dom/src/useInView.spec.tsx
delete mode 100644 packages/react-dom/src/useInView.tsx
delete mode 100644 packages/react-dom/src/utility-types/OmitKeyof.test-d.ts
delete mode 100644 packages/react-dom/src/utility-types/OmitKeyof.ts
delete mode 100644 packages/react-dom/src/utils/observe.spec.ts
delete mode 100644 packages/react-dom/src/utils/observe.ts
delete mode 100644 packages/react-dom/vitest.config.ts
delete mode 100644 packages/react-native/CHANGELOG.md
delete mode 100644 packages/react-native/LICENSE
delete mode 100644 packages/react-native/babel.config.cjs
delete mode 100644 packages/react-native/eslint.config.mjs
delete mode 100644 packages/react-native/jest.config.ts
delete mode 100644 packages/react-native/jest.setup.ts
delete mode 100644 packages/react-native/package.json
delete mode 100644 packages/react-native/src/TestText.spec.tsx
delete mode 100644 packages/react-native/src/TestText.tsx
delete mode 100644 packages/react-native/src/index.ts
delete mode 100644 packages/react-native/tsconfig.json
delete mode 100644 packages/react-native/tsdown.config.ts
create mode 100644 packages/react-query-4/src/IsFetching.spec.tsx
create mode 100644 packages/react-query-4/src/QueriesHydration.spec.tsx
create mode 100644 packages/react-query-4/src/QueriesHydration.test-d.tsx
create mode 100644 packages/react-query-4/src/QueriesHydration.tsx
create mode 100644 packages/react-query-4/src/components/ClientOnly.tsx
create mode 100644 packages/react-query-4/src/createGetQueryClient.spec.tsx
create mode 100644 packages/react-query-4/src/createGetQueryClient.test-d.tsx
create mode 100644 packages/react-query-4/src/createGetQueryClient.ts
create mode 100644 packages/react-query-5/src/QueriesHydration.spec.tsx
create mode 100644 packages/react-query-5/src/QueriesHydration.test-d.tsx
create mode 100644 packages/react-query-5/src/QueriesHydration.tsx
create mode 100644 packages/react-query-5/src/components/ClientOnly.tsx
create mode 100644 packages/react-query-5/src/createGetQueryClient.spec.tsx
create mode 100644 packages/react-query-5/src/createGetQueryClient.test-d.tsx
create mode 100644 packages/react-query-5/src/createGetQueryClient.ts
create mode 100644 packages/react-query/src/bin/utils/deprecationWarning.ts
diff --git a/.changeset/config.json b/.changeset/config.json
index e7afb4d38..9e5d4c896 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -5,7 +5,6 @@
"fixed": [
[
"@suspensive/react",
- "@suspensive/react-dom",
"@suspensive/react-query",
"@suspensive/react-query-4",
"@suspensive/react-query-5",
@@ -13,12 +12,7 @@
"@suspensive/codemods"
]
],
- "ignore": [
- "@suspensive/suspensive.org",
- "@suspensive/next-streaming-react-query",
- "@suspensive/react-native-playground",
- "@suspensive/visualization"
- ],
+ "ignore": ["@suspensive/suspensive.org", "@suspensive/next-streaming-react-query", "@suspensive/visualization"],
"linked": [],
"access": "restricted",
"baseBranch": "main",
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index d3cff7a65..c70d23e93 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1 +1 @@
-* @manudeli
+* @manudeli @kangju2000
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index 834597bd3..019fc8747 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -11,12 +11,11 @@ body:
multiple: true
options:
- '@suspensive/react'
- - '@suspensive/react-dom'
- - '@suspensive/react-native'
- '@suspensive/react-query'
- '@suspensive/react-query-4'
- '@suspensive/react-query-5'
- '@suspensive/jotai'
+ - '@suspensive/next'
- '@suspensive/codemods'
- etc
validations:
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index a0926ece0..766e43eab 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -11,12 +11,11 @@ body:
multiple: true
options:
- '@suspensive/react'
- - '@suspensive/react-dom'
- - '@suspensive/react-native'
- '@suspensive/react-query'
- '@suspensive/react-query-4'
- '@suspensive/react-query-5'
- '@suspensive/jotai'
+ - '@suspensive/next'
- '@suspensive/codemods'
- etc
validations:
diff --git a/.github/actions/pnpm-setup-node/action.yml b/.github/actions/pnpm-setup-node/action.yml
index a2e240be5..c1ce79ed7 100644
--- a/.github/actions/pnpm-setup-node/action.yml
+++ b/.github/actions/pnpm-setup-node/action.yml
@@ -3,8 +3,8 @@ description: setup pnpm & node
runs:
using: composite
steps:
- - uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v5
+ - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
+ - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: '.nvmrc'
cache: 'pnpm'
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 60b7d1617..2f0db7244 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -1,30 +1,40 @@
'@suspensive/react':
- - 'packages/react/**/*'
-'@suspensive/react-dom':
- - 'packages/react-dom/**/*'
-'@suspensive/react-native':
- - 'packages/react-native/**/*'
+ - changed-files:
+ - any-glob-to-any-file: 'packages/react/**/*'
'@suspensive/react-query':
- - 'packages/react-query/**/*'
+ - changed-files:
+ - any-glob-to-any-file: 'packages/react-query/**/*'
'@suspensive/react-query-4':
- - 'packages/react-query-4/**/*'
+ - changed-files:
+ - any-glob-to-any-file: 'packages/react-query-4/**/*'
'@suspensive/react-query-5':
- - 'packages/react-query-5/**/*'
+ - changed-files:
+ - any-glob-to-any-file: 'packages/react-query-5/**/*'
'@suspensive/jotai':
- - 'packages/jotai/**/*'
+ - changed-files:
+ - any-glob-to-any-file: 'packages/jotai/**/*'
'@suspensive/codemods':
- - 'packages/codemods/**/*'
+ - changed-files:
+ - any-glob-to-any-file: 'packages/codemods/**/*'
'suspensive.org':
- - 'docs/suspensive.org/**/*'
+ - changed-files:
+ - any-glob-to-any-file: 'docs/suspensive.org/**/*'
'examples':
- - 'examples/**/*'
+ - changed-files:
+ - any-glob-to-any-file: 'examples/**/*'
'eslint':
- - 'configs/eslint/**/*'
- - '**/.eslint*'
+ - changed-files:
+ - any-glob-to-any-file:
+ - 'configs/eslint/**/*'
+ - '**/.eslint*'
'tsconfig':
- - 'configs/tsconfig/**/*'
- - '**/.tsconfig*'
+ - changed-files:
+ - any-glob-to-any-file:
+ - 'configs/tsconfig/**/*'
+ - '**/.tsconfig*'
'dependencies':
- - 'pnpm-lock.yaml'
+ - changed-files:
+ - any-glob-to-any-file: 'pnpm-lock.yaml'
'workflows':
- - '.github/workflows/**/*'
+ - changed-files:
+ - any-glob-to-any-file: '.github/workflows/**/*'
diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml
index 3a98e6e81..b369afc0e 100644
--- a/.github/workflows/autofix.yml
+++ b/.github/workflows/autofix.yml
@@ -17,9 +17,9 @@ jobs:
autofix:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/pnpm-setup-node
- run: pnpm install
- - run: pnpm prettier --write .
+ - run: pnpm oxfmt --write .
- run: pnpm run packlint
- - uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27
+ - uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27 # v1.3.2
diff --git a/.github/workflows/broken-link-checker.yml b/.github/workflows/broken-link-checker.yml
index 38f357fc7..45a1cbade 100644
--- a/.github/workflows/broken-link-checker.yml
+++ b/.github/workflows/broken-link-checker.yml
@@ -10,7 +10,7 @@ jobs:
if: github.repository == 'toss/suspensive'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/pnpm-setup-node
- run: pnpm install
- run: pnpm run blc:suspensive.org
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 973625afc..116f0b2b9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -18,18 +18,16 @@ jobs:
matrix:
command: ['ci:test', 'ci:eslint', 'ci:sherif', 'ci:type', 'build']
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/pnpm-setup-node
- run: pnpm install
- - if: matrix.command == 'ci:test'
- run: pnpm playwright install
- run: pnpm run ${{ matrix.command }}
- if: matrix.command == 'ci:test'
- uses: codecov/codecov-action@v5
+ uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- if: matrix.command == 'build'
- uses: preactjs/compressed-size-action@v2
+ uses: preactjs/compressed-size-action@8518045ed95e94e971b83333085e1cb99aa18aa8 # v2.9.0
with:
pattern: 'packages/**/dist/*.{js,cjs,mjs}'
exclude: '{**/*.map,**/node_modules/**}'
diff --git a/.github/workflows/graph.yml b/.github/workflows/graph.yml
index 3b669ac95..8a7703a9a 100644
--- a/.github/workflows/graph.yml
+++ b/.github/workflows/graph.yml
@@ -19,16 +19,16 @@ jobs:
if: github.repository == 'toss/suspensive'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/pnpm-setup-node
- name: Setup Pages
- uses: actions/configure-pages@v5
+ uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
- name: Install dependencies
run: pnpm install
- name: Build with Turbo graph
run: pnpm run graph
- name: Upload artifact
- uses: actions/upload-pages-artifact@v4
+ uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0
with:
path: ./graph
@@ -42,4 +42,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
- uses: actions/deploy-pages@v4.0.5
+ uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e #v4.0.5
diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml
index ff761c356..6749c9255 100644
--- a/.github/workflows/knip.yml
+++ b/.github/workflows/knip.yml
@@ -16,7 +16,7 @@ jobs:
name: Knip
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/pnpm-setup-node
- run: pnpm install
- run: pnpm run ci:knip
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index af72f1466..4fe7a3e8b 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -7,10 +7,14 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
+permissions:
+ contents: read
+ pull-requests: write
+
jobs:
triage:
runs-on: ubuntu-latest
steps:
- - uses: actions/labeler@v4
+ - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 8de2acb9d..b22ce641d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -2,7 +2,7 @@ name: Changesets PR or Publish
on:
push:
- branches: [main, beta, next]
+ branches: [v2, v3, v4, main, beta, next]
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
@@ -14,22 +14,19 @@ jobs:
permissions:
id-token: write
contents: write
+ pull-requests: write
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/pnpm-setup-node
- run: pnpm install
- - run: |
- git config --global user.name "Jonghyeon Ko"
- git config --global user.email "jonghyeon@toss.im"
- name: Create Changesets Pull Request or Publish to NPM
id: changesets
- uses: changesets/action@v1
+ uses: changesets/action@c48e67d110a68bc90ccf1098e9646092baacaa87 # v1.6.0
with:
title: 'chore: version packages'
commit: 'chore: version packages'
version: pnpm run changeset:version
publish: pnpm run changeset:publish
- setupGitUser: false
env:
- GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_CONFIG_PROVENANCE: true
diff --git a/.gitignore b/.gitignore
index aa0a24ff3..006f573b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
# dependencies
node_modules
+package-lock.json
# testing
coverage
@@ -39,16 +40,8 @@ esm
# graph
graph/
-# react-native
-expo-env.d.ts
-.expo/
-*.jks
-*.p8
-*.p12
-*.key
-*.mobileprovision
-*.orig.*
-web-build/
-
# macOS
.DS_Store
+*.tsbuildinfo
+
+.claude/settings.local.json
diff --git a/.lintstagedrc b/.lintstagedrc
index f0dd16979..1d7afa9da 100644
--- a/.lintstagedrc
+++ b/.lintstagedrc
@@ -1,3 +1,3 @@
{
- "*.{ts,tsx}": ["prettier --write --ignore-unknown"]
+ "*.{ts,tsx}": ["pnpm oxfmt --no-error-on-unmatched-pattern --write"]
}
diff --git a/.nvmrc b/.nvmrc
index 567eb4429..821e3957b 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-v24.8.0
+v24.12.0
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 2c0c41914..fa9c61a15 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,8 +1,3 @@
{
- "recommendations": [
- "dbaeumer.vscode-eslint",
- "esbenp.prettier-vscode",
- "antfu.pnpm-catalog-lens",
- "unifiedjs.vscode-mdx"
- ]
+ "recommendations": ["dbaeumer.vscode-eslint", "oxc.oxc-vscode", "antfu.pnpm-catalog-lens", "unifiedjs.vscode-mdx"]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 4401a4ced..26fd24a43 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,5 @@
{
- "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.defaultFormatter": "oxc.oxc-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
@@ -7,7 +7,16 @@
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "mdx"],
"eslint.workingDirectories": [{ "mode": "auto" }],
"vitest.disableWorkspaceWarning": true,
- "[yaml]": {
- "editor.defaultFormatter": "esbenp.prettier-vscode"
- }
+ "[javascript]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
+ "[javascriptreact]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
+ "[typescript]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
+ "[typescriptreact]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
+ "[json]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
+ "[jsonc]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
+ "[yaml]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
+ "[markdown]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
+ "[mdx]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
+ "[html]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
+ "[css]": { "editor.defaultFormatter": "oxc.oxc-vscode" },
+ "[scss]": { "editor.defaultFormatter": "oxc.oxc-vscode" }
}
diff --git a/README.md b/README.md
index c4cf5307d..2e5c8bca3 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,79 @@
-
+## What is Suspensive?
-[](https://github.com/toss/suspensive/blob/main/LICENSE) [](https://coauthors.me) [](https://codecov.io/gh/toss/suspensive) [](https://codspeed.io/toss/suspensive)  [](https://discord.gg/RFcR9WWmCH)
+React gives you Suspense, lazy, and an interface to build Error Boundaries — but using them in real applications reveals gaps. **Suspensive fills those gaps** with declarative components and hooks.
-
+```tsx
+import { Delay, ErrorBoundary, ErrorBoundaryGroup, Suspense } from '@suspensive/react'
-## Visit [suspensive.org](https://suspensive.org) for docs, guides, API and more!
+const Page = () => (
+
+
+ {({ reset }) => Reset All }
+
+ }
+ >
+
+ {({ isDelayed }) => }
+
+ }
+ >
+
+
+
+
+)
+```
-[English](https://suspensive.org/en) | [한국어](https://suspensive.org/ko)
+- **`shouldCatch`** — catch only specific error types, let others propagate
+- **`ErrorBoundaryGroup`** — reset multiple error boundaries at once, no prop drilling
+- **`clientOnly`** — SSR-safe Suspense that avoids hydration mismatches in Next.js
+- **`Delay`** — prevent flash-of-loading-state with render props for smooth fade-in
+- **`reset`** — built into the fallback props, no external state needed
-
+## Packages
+
+| Package | Description | Version |
+| ----------------------------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [@suspensive/react](https://suspensive.org/docs/react/motivation) | Suspense, ErrorBoundary, ErrorBoundaryGroup, Delay, ClientOnly | [](https://www.npmjs.com/package/@suspensive/react) |
+| [@suspensive/react-query](https://suspensive.org/docs/react-query/motivation) | SuspenseQuery, SuspenseInfiniteQuery, Mutation, PrefetchQuery | [](https://www.npmjs.com/package/@suspensive/react-query) |
+| [@suspensive/jotai](https://suspensive.org/docs/jotai/motivation) | Atom, AtomValue, SetAtom for Jotai integration | [](https://www.npmjs.com/package/@suspensive/jotai) |
+| [@suspensive/codemods](https://suspensive.org/docs/codemods/motivation) | Automated migration codemods | [](https://www.npmjs.com/package/@suspensive/codemods) |
+
+## Key Features
+
+- **` `** with `shouldCatch` — catch only the errors you want ([comparison with react-error-boundary](https://suspensive.org/docs/react/comparison))
+- **` `** — reset multiple error boundaries at once, no prop drilling
+- **` `** with `clientOnly` — SSR-safe Suspense that just works in Next.js
+- **` `** — declarative data fetching as JSX, no hook constraints
+- **` `** — prevent flash-of-loading-state UX issues
+- **` `** — set global default fallbacks for all components
+
+## Getting Started
+
+```bash
+npm install @suspensive/react
+```
+
+Visit **[suspensive.org](https://suspensive.org)** for full documentation.
+
+[English](https://suspensive.org/en) | [한국어](https://suspensive.org/ko)
## Contributors
@@ -26,7 +83,6 @@ Read our [Contributing Guide](./CONTRIBUTING.md) to familiarize yourself with Su
-
diff --git a/codecov.yml b/codecov.yml
index 09c42ddb9..b5cc14924 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -24,14 +24,6 @@ component_management:
name: '@suspensive/react'
paths:
- packages/react/**
- - component_id: react-dom
- name: '@suspensive/react-dom'
- paths:
- - packages/react-dom/**
- - component_id: react-native
- name: '@suspensive/react-native'
- paths:
- - packages/react-native/**
- component_id: react-query
name: '@suspensive/react-query'
paths:
diff --git a/configs/eslint-config/index.js b/configs/eslint-config/index.js
index 75996e58c..a444b130e 100644
--- a/configs/eslint-config/index.js
+++ b/configs/eslint-config/index.js
@@ -4,14 +4,14 @@ import importPlugin from 'eslint-plugin-import'
import jsdoc from 'eslint-plugin-jsdoc'
import reactHooks from 'eslint-plugin-react-hooks'
import tseslint from 'typescript-eslint'
-import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
import next from '@next/eslint-plugin-next'
import cspellConfigs from '@cspell/eslint-plugin/configs'
import vitest from '@vitest/eslint-plugin'
import jestDom from 'eslint-plugin-jest-dom'
import * as mdx from 'eslint-plugin-mdx'
+import stylistic from '@stylistic/eslint-plugin'
-const ignores = ['**/.next/**', '**/build/**', '**/coverage/**', '**/dist/**']
+const ignores = ['**/.next/**', '**/build/**', '**/coverage/**', '**/dist/**', 'next-env.d.ts']
export const suspensiveTypeScriptConfig = defineConfig([
{
@@ -36,6 +36,7 @@ export const suspensiveTypeScriptConfig = defineConfig([
plugins: {
jsdoc: jsdoc,
'@typescript-eslint': tseslint.plugin,
+ '@stylistic': stylistic,
},
rules: {
'@cspell/spellchecker': [
@@ -78,7 +79,7 @@ export const suspensiveTypeScriptConfig = defineConfig([
'@typescript-eslint/restrict-template-expressions': 'off',
'@typescript-eslint/no-deprecated': 'warn',
'@typescript-eslint/no-empty-function': 'warn',
- '@typescript-eslint/no-extra-semi': 'warn',
+ '@stylistic/no-extra-semi': 'warn',
'@typescript-eslint/no-empty-interface': 'warn',
'@typescript-eslint/ban-ts-comment': ['error', { minimumDescriptionLength: 3 }],
'@typescript-eslint/triple-slash-reference': 'warn',
@@ -109,7 +110,6 @@ export const suspensiveTypeScriptConfig = defineConfig([
],
},
},
- eslintPluginPrettierRecommended,
])
export const suspensiveReactTypeScriptConfig = defineConfig([
diff --git a/configs/eslint-config/package.json b/configs/eslint-config/package.json
index ec4dcc9f0..730b8dcdc 100644
--- a/configs/eslint-config/package.json
+++ b/configs/eslint-config/package.json
@@ -11,17 +11,16 @@
"clean": "rimraf ./dist ./coverage ./node_modules"
},
"dependencies": {
- "@cspell/eslint-plugin": "^9.2.0",
- "@eslint-react/eslint-plugin": "^1.48.4",
+ "@cspell/eslint-plugin": "^9.4.0",
+ "@eslint-react/eslint-plugin": "^2.3.13",
"@next/eslint-plugin-next": "catalog:",
- "@vitest/eslint-plugin": "^1.1.43",
- "eslint-config-prettier": "^10.1.2",
- "eslint-plugin-import": "^2.31.0",
+ "@stylistic/eslint-plugin": "^5.10.0",
+ "@vitest/eslint-plugin": "^1.6.12",
+ "eslint-plugin-import": "^2.32.0",
"eslint-plugin-jest-dom": "^5.5.0",
- "eslint-plugin-jsdoc": "^50.6.9",
- "eslint-plugin-mdx": "^3.4.1",
- "eslint-plugin-prettier": "^5.5.4",
- "eslint-plugin-react-hooks": "^7.0.0",
- "typescript-eslint": "^8.43.0"
+ "eslint-plugin-jsdoc": "^61.5.0",
+ "eslint-plugin-mdx": "^3.6.2",
+ "eslint-plugin-react-hooks": "^7.0.1",
+ "typescript-eslint": "^8.50.0"
}
}
diff --git a/configs/tsconfig/base.json b/configs/tsconfig/base.json
index 5fde1699c..b39872e3d 100644
--- a/configs/tsconfig/base.json
+++ b/configs/tsconfig/base.json
@@ -9,7 +9,7 @@
"forceConsistentCasingInFileNames": true,
"inlineSources": false,
"isolatedModules": true,
- "moduleResolution": "node",
+ "moduleResolution": "bundler",
"noUnusedLocals": false,
"noUnusedParameters": false,
"preserveWatchOutput": true,
diff --git a/configs/tsdown/package.json b/configs/tsdown/package.json
index 2de2ce569..34f4d3b00 100644
--- a/configs/tsdown/package.json
+++ b/configs/tsdown/package.json
@@ -5,27 +5,10 @@
"author": "Jonghyeon Ko ",
"sideEffects": false,
"type": "module",
- "exports": {
- ".": {
- "import": {
- "types": "./dist/index.d.ts",
- "default": "./dist/index.js"
- },
- "require": {
- "types": "./dist/index.d.cts",
- "default": "./dist/index.cjs"
- }
- },
- "./package.json": "./package.json"
- },
- "main": "dist/index.cjs",
- "module": "dist/index.js",
- "types": "dist/index.d.ts",
+ "main": "src/index.ts",
"scripts": {
- "build": "tsdown",
"ci:eslint": "eslint \"**/*.{ts,tsx,cts,mts}\"",
- "ci:type": "tsc --noEmit",
- "clean": "rimraf ./dist ./coverage ./node_modules"
+ "ci:type": "tsc --noEmit"
},
"devDependencies": {
"@suspensive/eslint-config": "workspace:*",
diff --git a/configs/tsdown/src/index.ts b/configs/tsdown/src/index.ts
index f0a916c12..d75205765 100644
--- a/configs/tsdown/src/index.ts
+++ b/configs/tsdown/src/index.ts
@@ -1,7 +1,6 @@
-import type { Options } from 'tsdown'
+import { defineConfig } from 'tsdown'
-export const options: Options = {
- banner: { js: '"use client"' },
+export const options = defineConfig({
format: ['cjs', 'esm'],
target: ['chrome51', 'firefox53', 'edge18', 'safari11', 'ios11', 'opera38', 'es6', 'node14'],
entry: ['src/*.{ts,tsx}', '!**/*.{spec,test,test-d}.*'],
@@ -12,9 +11,10 @@ export const options: Options = {
attw: true,
publint: true,
clean: true,
-}
+ unbundle: true,
+})
-export const scriptOptions: Options = {
+export const scriptOptions = defineConfig({
format: 'cjs',
target: ['node18'],
entry: ['src/bin/*.{ts,tsx}', '!**/*.{spec,test,test-d}.*'],
@@ -22,4 +22,4 @@ export const scriptOptions: Options = {
attw: true,
publint: true,
clean: true,
-}
+})
diff --git a/docs/suspensive.org/.gitignore b/docs/suspensive.org/.gitignore
index c24670fb2..e265da64d 100644
--- a/docs/suspensive.org/.gitignore
+++ b/docs/suspensive.org/.gitignore
@@ -35,3 +35,9 @@ yarn-error.log*
next-env.d.ts
_pagefind/
+
+
+# LLMs.txt generated files
+/public/llms.txt
+/public/llms-full.txt
+/public/docs/
diff --git a/docs/suspensive.org/package.json b/docs/suspensive.org/package.json
index f01c5a9aa..8b17014f5 100644
--- a/docs/suspensive.org/package.json
+++ b/docs/suspensive.org/package.json
@@ -14,33 +14,33 @@
"author": "Jonghyeon Ko ",
"type": "module",
"scripts": {
- "build": "next build && pagefind --site .next/server/app --output-path public/_pagefind",
+ "build": "next build --webpack && pagefind --site .next/server/app --output-path .next/output/static/_pagefind && node scripts/llms-txt/generate-llms-txt.ts",
"ci:eslint": "eslint \"**/*.{ts,tsx,cts,mts,mdx}\"",
"ci:type": "tsc --noEmit",
"clean": "rimraf ./.next ./node_modules",
- "dev": "next dev -p 4000",
+ "dev": "next dev -p 4000 --webpack",
"start": "next start -p 4000"
},
"dependencies": {
"@codesandbox/sandpack-react": "^2.20.0",
"@next/third-parties": "catalog:",
"@suspensive/react": "workspace:*",
- "@suspensive/react-query-4": "workspace:*",
- "@tanstack/react-query": "catalog:react-query4",
- "@tanstack/react-query-devtools": "catalog:react-query4",
+ "@suspensive/react-query-5": "workspace:*",
+ "@tanstack/react-query": "catalog:react-query5",
+ "@tanstack/react-query-devtools": "catalog:react-query5",
"clsx": "catalog:",
- "codehike": "^1.0.7",
+ "codehike": "^1.1.0",
"d3": "^7.9.0",
- "lucide-react": "^0.511.0",
- "motion": "^12.15.0",
+ "lucide-react": "^0.577.0",
+ "motion": "^12.38.0",
"next": "catalog:",
- "nextra": "^4.5.0",
- "nextra-theme-docs": "^4.5.0",
+ "nextra": "^4.6.1",
+ "nextra-theme-docs": "^4.6.1",
"react": "catalog:react19",
"react-dom": "catalog:react19",
"remark-sandpack": "^0.0.5",
"sharp": "catalog:",
- "zod": "^3.25.47"
+ "zod": "3.22.4"
},
"devDependencies": {
"@suspensive/eslint-config": "workspace:*",
@@ -48,7 +48,7 @@
"@types/d3": "^7.4.3",
"@types/react": "catalog:react19",
"@types/react-dom": "catalog:react19",
- "pagefind": "^1.3.0",
+ "pagefind": "^1.4.0",
"tailwindcss": "catalog:"
}
}
diff --git a/docs/suspensive.org/public/favicon.ico b/docs/suspensive.org/public/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..b74ec18cdfeff3df22d6c4913fa7a98bae945c01
GIT binary patch
literal 14532
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
literal 0
HcmV?d00001
diff --git a/docs/suspensive.org/public/img/logo_dark.svg b/docs/suspensive.org/public/img/logo_dark.svg
new file mode 100644
index 000000000..9d11dfbcb
--- /dev/null
+++ b/docs/suspensive.org/public/img/logo_dark.svg
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/suspensive.org/public/img/next-streaming-react-query-example.gif b/docs/suspensive.org/public/img/next-streaming-react-query-example.gif
new file mode 100644
index 0000000000000000000000000000000000000000..65f394126d62fb03a89ec0b4b88b65e974562258
GIT binary patch
literal 978547
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