@formadapter/tanstack-start 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ludicrous
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # `@formadapter/tanstack-start`
2
+
3
+ TanStack Start server-function integration for FormAdapter. It connects a
4
+ FormAdapter `onSubmit` callback to a POST server function while keeping parsing,
5
+ schema validation, and structured submission errors in `@formadapter/server`.
6
+
7
+ ```sh
8
+ bun add @formadapter/tanstack-start @formadapter/server @tanstack/react-start
9
+ ```
10
+
11
+ ## Server function
12
+
13
+ Build the reusable submission first, then place the thin TanStack Start boundary
14
+ around it:
15
+
16
+ ```ts
17
+ import { createServerFn } from "@tanstack/react-start";
18
+ import { createSubmissionHandler } from "@formadapter/server";
19
+ import {
20
+ formDataValidator,
21
+ tanstackStartHandler,
22
+ } from "@formadapter/tanstack-start/server";
23
+ import { profileSchema } from "./profile-schema";
24
+
25
+ const submission = createSubmissionHandler(
26
+ profileSchema,
27
+ async (profile) => database.profile.save(profile),
28
+ { config: profileConfig },
29
+ );
30
+
31
+ export const saveProfile = createServerFn({ method: "POST" })
32
+ .validator(formDataValidator)
33
+ .handler(tanstackStartHandler(submission));
34
+ ```
35
+
36
+ `formDataValidator` only verifies the transport shape. The reusable submission
37
+ performs authoritative schema and presentation-rule validation so failures come
38
+ back as FormAdapter's shared `SubmissionState` instead of escaping TanStack
39
+ Start's validator as generic errors. Pass the same form config when conditional
40
+ `hidden` or `requiredWhenVisible` rules must also be enforced on the server.
41
+
42
+ TanStack's handler context is forwarded into the submission context. Middleware
43
+ auth data is available as `context.context`; `method` and `serverFnMeta` are
44
+ preserved too. Treat that data as request context, and still perform
45
+ authorization in the business handler.
46
+
47
+ Use `createSubmissionHandlerFactory<TanStackStartSubmissionContext<AuthContext>>()`
48
+ when the business callback needs that middleware context inferred. The returned
49
+ context-bound submission requires its invocation context, and
50
+ `tanstackStartHandler` always supplies it.
51
+
52
+ ## Client form
53
+
54
+ Use the hook in the client component that renders the form:
55
+
56
+ ```tsx
57
+ "use client";
58
+
59
+ import { useTanStackStartSubmission } from "@formadapter/tanstack-start";
60
+ import { Profile } from "./profile-form";
61
+ import { saveProfile } from "./profile.functions";
62
+
63
+ export function ProfileEditor() {
64
+ const onSubmit = useTanStackStartSubmission(saveProfile);
65
+ return <Profile.Form onSubmit={onSubmit} />;
66
+ }
67
+ ```
68
+
69
+ The hook calls TanStack Start's redirect-aware `useServerFn`, sends the form's
70
+ schema-aware `context.formData`, forwards its `AbortSignal`, and returns the
71
+ server's shared submission state. Options can supply static/dynamic headers, a
72
+ custom fetch implementation, or an alternate `FormData` value. GET server
73
+ functions are rejected because submissions require POST.
74
+
75
+ `UseTanStackStartSubmissionOptions<Values, Input>` types the `headers` and
76
+ `getFormData` customization callbacks without changing server-result inference.
77
+
78
+ Client and server exports are intentionally separate. The package root and
79
+ `/client` contain the hook; `/server` contains only the validator and handler
80
+ adapter, so server integration code cannot leak into the client entry.
81
+
82
+ ## Progressive enhancement
83
+
84
+ TanStack Start exposes a server function's `.url` for raw HTML form actions.
85
+ `useTanStackStartSubmission` copies that URL from the original server function
86
+ onto the returned handler and exposes `{ url, method, encType }` as `metadata`.
87
+ TanStack's `useServerFn` callback itself does not retain this property.
88
+
89
+ The hook remains a JavaScript-enhanced submission path. Posting a raw HTML form
90
+ to `.url` can provide no-JavaScript transport, but FormAdapter's client-side
91
+ state mapping and inline structured errors do not run in that mode. Applications
92
+ that require full progressive enhancement should design the raw response and
93
+ redirect/error experience explicitly instead of assuming hook behavior applies.
@@ -0,0 +1,46 @@
1
+ import { SubmissionState } from "@formadapter/core";
2
+
3
+ //#region src/client.d.ts
4
+ interface FormAdapterSubmissionContext<Input = unknown> {
5
+ readonly input: Input;
6
+ readonly formData: FormData;
7
+ readonly signal: AbortSignal;
8
+ }
9
+ interface TanStackStartCallOptions {
10
+ readonly data: FormData;
11
+ readonly signal?: AbortSignal;
12
+ readonly headers?: HeadersInit;
13
+ readonly fetch?: typeof fetch;
14
+ }
15
+ /** The stable public surface used from a TanStack Start server function. */
16
+ type TanStackStartServerFn<Result extends SubmissionState = SubmissionState> = ((options: TanStackStartCallOptions) => Promise<Result>) & {
17
+ readonly url: string;
18
+ readonly method?: "GET" | "POST";
19
+ };
20
+ interface TanStackStartSubmissionMetadata {
21
+ readonly url: string;
22
+ readonly method: "post";
23
+ readonly encType: "multipart/form-data";
24
+ }
25
+ type HeadersOption<Values = unknown, Input = unknown> = HeadersInit | ((values: Values, context: FormAdapterSubmissionContext<Input>) => HeadersInit | undefined);
26
+ interface UseTanStackStartSubmissionOptions<Values = unknown, Input = unknown> {
27
+ /** Override the FormData sent to the server function. */
28
+ readonly getFormData?: (values: Values, context: FormAdapterSubmissionContext<Input>) => FormData;
29
+ readonly headers?: HeadersOption<Values, Input>;
30
+ readonly fetch?: typeof fetch;
31
+ }
32
+ type TanStackStartSubmissionHandler<Result extends SubmissionState = SubmissionState, Values = unknown, Input = unknown> = ((values: Values, context: FormAdapterSubmissionContext<Input>) => Promise<Result>) & {
33
+ /** Copied from the original server function, not the useServerFn callback. */readonly url: string;
34
+ readonly metadata: TanStackStartSubmissionMetadata;
35
+ };
36
+ declare function getTanStackStartSubmissionMetadata(serverFn: {
37
+ readonly url: string;
38
+ }): TanStackStartSubmissionMetadata;
39
+ /**
40
+ * Creates a FormAdapter `onSubmit` handler backed by TanStack Start's
41
+ * redirect-aware `useServerFn` invocation.
42
+ */
43
+ declare function useTanStackStartSubmission<Result extends SubmissionState, Values = unknown, Input = unknown>(serverFn: TanStackStartServerFn<Result>, options?: UseTanStackStartSubmissionOptions<Values, Input>): TanStackStartSubmissionHandler<Result, Values, Input>;
44
+ //#endregion
45
+ export { FormAdapterSubmissionContext, TanStackStartCallOptions, TanStackStartServerFn, TanStackStartSubmissionHandler, TanStackStartSubmissionMetadata, UseTanStackStartSubmissionOptions, getTanStackStartSubmissionMetadata, useTanStackStartSubmission };
46
+ //# sourceMappingURL=client.d.ts.map
package/dist/client.js ADDED
@@ -0,0 +1,48 @@
1
+ "use client";
2
+ import { useCallback, useMemo } from "react";
3
+ import { useServerFn } from "@tanstack/react-start";
4
+ //#region src/client.ts
5
+ function getTanStackStartSubmissionMetadata(serverFn) {
6
+ return {
7
+ encType: "multipart/form-data",
8
+ method: "post",
9
+ url: serverFn.url
10
+ };
11
+ }
12
+ /**
13
+ * Creates a FormAdapter `onSubmit` handler backed by TanStack Start's
14
+ * redirect-aware `useServerFn` invocation.
15
+ */
16
+ function useTanStackStartSubmission(serverFn, options = {}) {
17
+ if (serverFn.method !== void 0 && serverFn.method !== "POST") throw new Error("FormAdapter submissions require a TanStack Start POST server function.");
18
+ const invoke = useServerFn(serverFn);
19
+ const url = serverFn.url;
20
+ const { fetch: customFetch, getFormData, headers } = options;
21
+ const submit = useCallback(async (values, context) => {
22
+ const resolvedHeaders = typeof headers === "function" ? headers(values, context) : headers;
23
+ return invoke({
24
+ data: getFormData?.(values, context) ?? context.formData,
25
+ signal: context.signal,
26
+ ...resolvedHeaders !== void 0 ? { headers: resolvedHeaders } : {},
27
+ ...customFetch !== void 0 ? { fetch: customFetch } : {}
28
+ });
29
+ }, [
30
+ customFetch,
31
+ getFormData,
32
+ headers,
33
+ invoke
34
+ ]);
35
+ const metadata = useMemo(() => getTanStackStartSubmissionMetadata({ url }), [url]);
36
+ return useMemo(() => Object.assign(submit, {
37
+ metadata,
38
+ url
39
+ }), [
40
+ metadata,
41
+ submit,
42
+ url
43
+ ]);
44
+ }
45
+ //#endregion
46
+ export { getTanStackStartSubmissionMetadata, useTanStackStartSubmission };
47
+
48
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["\"use client\";\n\nimport {\n useCallback,\n useMemo,\n} from \"react\";\nimport { useServerFn } from \"@tanstack/react-start\";\n\nimport type { SubmissionState } from \"@formadapter/core\";\n\nexport interface FormAdapterSubmissionContext<Input = unknown> {\n readonly input: Input;\n readonly formData: FormData;\n readonly signal: AbortSignal;\n}\n\nexport interface TanStackStartCallOptions {\n readonly data: FormData;\n readonly signal?: AbortSignal;\n readonly headers?: HeadersInit;\n readonly fetch?: typeof fetch;\n}\n\n/** The stable public surface used from a TanStack Start server function. */\nexport type TanStackStartServerFn<\n Result extends SubmissionState = SubmissionState,\n> = ((options: TanStackStartCallOptions) => Promise<Result>) & {\n readonly url: string;\n readonly method?: \"GET\" | \"POST\";\n};\n\nexport interface TanStackStartSubmissionMetadata {\n readonly url: string;\n readonly method: \"post\";\n readonly encType: \"multipart/form-data\";\n}\n\ntype HeadersOption<Values = unknown, Input = unknown> =\n | HeadersInit\n | ((\n values: Values,\n context: FormAdapterSubmissionContext<Input>,\n ) => HeadersInit | undefined);\n\nexport interface UseTanStackStartSubmissionOptions<\n Values = unknown,\n Input = unknown,\n> {\n /** Override the FormData sent to the server function. */\n readonly getFormData?: (\n values: Values,\n context: FormAdapterSubmissionContext<Input>,\n ) => FormData;\n readonly headers?: HeadersOption<Values, Input>;\n readonly fetch?: typeof fetch;\n}\n\nexport type TanStackStartSubmissionHandler<\n Result extends SubmissionState = SubmissionState,\n Values = unknown,\n Input = unknown,\n> = ((\n values: Values,\n context: FormAdapterSubmissionContext<Input>,\n) => Promise<Result>) & {\n /** Copied from the original server function, not the useServerFn callback. */\n readonly url: string;\n readonly metadata: TanStackStartSubmissionMetadata;\n};\n\nexport function getTanStackStartSubmissionMetadata(\n serverFn: { readonly url: string },\n): TanStackStartSubmissionMetadata {\n return {\n encType: \"multipart/form-data\",\n method: \"post\",\n url: serverFn.url,\n };\n}\n\n/**\n * Creates a FormAdapter `onSubmit` handler backed by TanStack Start's\n * redirect-aware `useServerFn` invocation.\n */\nexport function useTanStackStartSubmission<\n Result extends SubmissionState,\n Values = unknown,\n Input = unknown,\n>(\n serverFn: TanStackStartServerFn<Result>,\n options: UseTanStackStartSubmissionOptions<Values, Input> = {},\n): TanStackStartSubmissionHandler<Result, Values, Input> {\n if (serverFn.method !== undefined && serverFn.method !== \"POST\") {\n throw new Error(\n \"FormAdapter submissions require a TanStack Start POST server function.\",\n );\n }\n\n const invoke = useServerFn(serverFn);\n const url = serverFn.url;\n const { fetch: customFetch, getFormData, headers } = options;\n const submit = useCallback(\n async (\n values: Values,\n context: FormAdapterSubmissionContext<Input>,\n ): Promise<Result> => {\n const resolvedHeaders = typeof headers === \"function\"\n ? headers(values, context)\n : headers;\n const call: TanStackStartCallOptions = {\n data: getFormData?.(values, context) ?? context.formData,\n signal: context.signal,\n ...(resolvedHeaders !== undefined ? { headers: resolvedHeaders } : {}),\n ...(customFetch !== undefined ? { fetch: customFetch } : {}),\n };\n return invoke(call);\n },\n [customFetch, getFormData, headers, invoke],\n );\n const metadata = useMemo(\n () => getTanStackStartSubmissionMetadata({ url }),\n [url],\n );\n\n return useMemo(\n () => Object.assign(submit, { metadata, url }),\n [metadata, submit, url],\n );\n}\n"],"mappings":";;;;AAsEA,SAAgB,mCACd,UACiC;AACjC,QAAO;EACL,SAAS;EACT,QAAQ;EACR,KAAK,SAAS;EACf;;;;;;AAOH,SAAgB,2BAKd,UACA,UAA4D,EAAE,EACP;AACvD,KAAI,SAAS,WAAW,KAAA,KAAa,SAAS,WAAW,OACvD,OAAM,IAAI,MACR,yEACD;CAGH,MAAM,SAAS,YAAY,SAAS;CACpC,MAAM,MAAM,SAAS;CACrB,MAAM,EAAE,OAAO,aAAa,aAAa,YAAY;CACrD,MAAM,SAAS,YACb,OACE,QACA,YACoB;EACpB,MAAM,kBAAkB,OAAO,YAAY,aACvC,QAAQ,QAAQ,QAAQ,GACxB;AAOJ,SAAO,OAAO;GALZ,MAAM,cAAc,QAAQ,QAAQ,IAAI,QAAQ;GAChD,QAAQ,QAAQ;GAChB,GAAI,oBAAoB,KAAA,IAAY,EAAE,SAAS,iBAAiB,GAAG,EAAE;GACrE,GAAI,gBAAgB,KAAA,IAAY,EAAE,OAAO,aAAa,GAAG,EAAE;GAE3C,CAAC;IAErB;EAAC;EAAa;EAAa;EAAS;EAAO,CAC5C;CACD,MAAM,WAAW,cACT,mCAAmC,EAAE,KAAK,CAAC,EACjD,CAAC,IAAI,CACN;AAED,QAAO,cACC,OAAO,OAAO,QAAQ;EAAE;EAAU;EAAK,CAAC,EAC9C;EAAC;EAAU;EAAQ;EAAI,CACxB"}
@@ -0,0 +1,2 @@
1
+ import { FormAdapterSubmissionContext, TanStackStartCallOptions, TanStackStartServerFn, TanStackStartSubmissionHandler, TanStackStartSubmissionMetadata, UseTanStackStartSubmissionOptions, getTanStackStartSubmissionMetadata, useTanStackStartSubmission } from "./client.js";
2
+ export { type FormAdapterSubmissionContext, type TanStackStartCallOptions, type TanStackStartServerFn, type TanStackStartSubmissionHandler, type TanStackStartSubmissionMetadata, type UseTanStackStartSubmissionOptions, getTanStackStartSubmissionMetadata, useTanStackStartSubmission };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ "use client";
2
+ import { getTanStackStartSubmissionMetadata, useTanStackStartSubmission } from "./client.js";
3
+ export { getTanStackStartSubmissionMetadata, useTanStackStartSubmission };
@@ -0,0 +1,24 @@
1
+ import { SubmissionState } from "@formadapter/core";
2
+
3
+ //#region src/server.d.ts
4
+ interface TanStackStartHandlerContext<Context = unknown> {
5
+ readonly data: FormData;
6
+ readonly context: Context;
7
+ readonly method: "POST";
8
+ readonly serverFnMeta: unknown;
9
+ }
10
+ type TanStackStartSubmissionContext<Context = unknown> = Omit<TanStackStartHandlerContext<Context>, "data">;
11
+ /** Structural shape of a prebuilt `@formadapter/server` submission. */
12
+ type FormAdapterSubmission<Result extends SubmissionState = SubmissionState, Context = unknown> = (payload: unknown, context: TanStackStartSubmissionContext<Context>) => Promise<Result>;
13
+ type TanStackStartHandler<Result extends SubmissionState = SubmissionState, Context = unknown> = (context: TanStackStartHandlerContext<Context>) => Promise<Result>;
14
+ /** A canonical TanStack Start `.validator(...)` for POSTed FormData. */
15
+ declare function formDataValidator(data: FormData): FormData;
16
+ /**
17
+ * Adapts a prebuilt FormAdapter submission to a TanStack Start `.handler(...)`.
18
+ * The remaining TanStack handler context is forwarded structurally as the
19
+ * submission's optional second argument.
20
+ */
21
+ declare function tanstackStartHandler<Result extends SubmissionState, Context = unknown>(submission: FormAdapterSubmission<Result, Context>): TanStackStartHandler<Result, Context>;
22
+ //#endregion
23
+ export { FormAdapterSubmission, TanStackStartHandler, TanStackStartHandlerContext, TanStackStartSubmissionContext, formDataValidator, tanstackStartHandler };
24
+ //# sourceMappingURL=server.d.ts.map
package/dist/server.js ADDED
@@ -0,0 +1,18 @@
1
+ //#region src/server.ts
2
+ /** A canonical TanStack Start `.validator(...)` for POSTed FormData. */
3
+ function formDataValidator(data) {
4
+ if (typeof FormData === "undefined" || !(data instanceof FormData)) throw new TypeError("Expected FormData from a TanStack Start POST server function.");
5
+ return data;
6
+ }
7
+ /**
8
+ * Adapts a prebuilt FormAdapter submission to a TanStack Start `.handler(...)`.
9
+ * The remaining TanStack handler context is forwarded structurally as the
10
+ * submission's optional second argument.
11
+ */
12
+ function tanstackStartHandler(submission) {
13
+ return async ({ data, ...context }) => submission(data, context);
14
+ }
15
+ //#endregion
16
+ export { formDataValidator, tanstackStartHandler };
17
+
18
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","names":[],"sources":["../src/server.ts"],"sourcesContent":["import type { SubmissionState } from \"@formadapter/core\";\n\nexport interface TanStackStartHandlerContext<Context = unknown> {\n readonly data: FormData;\n readonly context: Context;\n readonly method: \"POST\";\n readonly serverFnMeta: unknown;\n}\n\nexport type TanStackStartSubmissionContext<Context = unknown> = Omit<\n TanStackStartHandlerContext<Context>,\n \"data\"\n>;\n\n/** Structural shape of a prebuilt `@formadapter/server` submission. */\nexport type FormAdapterSubmission<\n Result extends SubmissionState = SubmissionState,\n Context = unknown,\n> = (\n payload: unknown,\n context: TanStackStartSubmissionContext<Context>,\n) => Promise<Result>;\n\nexport type TanStackStartHandler<\n Result extends SubmissionState = SubmissionState,\n Context = unknown,\n> = (context: TanStackStartHandlerContext<Context>) => Promise<Result>;\n\n/** A canonical TanStack Start `.validator(...)` for POSTed FormData. */\nexport function formDataValidator(data: FormData): FormData {\n if (typeof FormData === \"undefined\" || !(data instanceof FormData)) {\n throw new TypeError(\"Expected FormData from a TanStack Start POST server function.\");\n }\n return data;\n}\n\n/**\n * Adapts a prebuilt FormAdapter submission to a TanStack Start `.handler(...)`.\n * The remaining TanStack handler context is forwarded structurally as the\n * submission's optional second argument.\n */\nexport function tanstackStartHandler<\n Result extends SubmissionState,\n Context = unknown,\n>(\n submission: FormAdapterSubmission<Result, Context>,\n): TanStackStartHandler<Result, Context> {\n return async ({ data, ...context }): Promise<Result> =>\n submission(data, context);\n}\n"],"mappings":";;AA6BA,SAAgB,kBAAkB,MAA0B;AAC1D,KAAI,OAAO,aAAa,eAAe,EAAE,gBAAgB,UACvD,OAAM,IAAI,UAAU,gEAAgE;AAEtF,QAAO;;;;;;;AAQT,SAAgB,qBAId,YACuC;AACvC,QAAO,OAAO,EAAE,MAAM,GAAG,cACvB,WAAW,MAAM,QAAQ"}
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "@formadapter/tanstack-start",
3
+ "version": "0.0.0",
4
+ "description": "TanStack Start server-function integration for FormAdapter.",
5
+ "keywords": [
6
+ "forms",
7
+ "server-functions",
8
+ "tanstack-start",
9
+ "typescript"
10
+ ],
11
+ "homepage": "https://formadapter.com",
12
+ "bugs": {
13
+ "url": "https://github.com/ludicroushq/formadapter/issues"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/ludicroushq/formadapter.git",
18
+ "directory": "packages/tanstack-start"
19
+ },
20
+ "license": "MIT",
21
+ "author": "ludicrous",
22
+ "type": "module",
23
+ "sideEffects": false,
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
32
+ "main": "./dist/index.js",
33
+ "module": "./dist/index.js",
34
+ "types": "./dist/index.d.ts",
35
+ "exports": {
36
+ ".": {
37
+ "types": "./dist/index.d.ts",
38
+ "import": "./dist/index.js",
39
+ "default": "./dist/index.js"
40
+ },
41
+ "./client": {
42
+ "types": "./dist/client.d.ts",
43
+ "import": "./dist/client.js",
44
+ "default": "./dist/client.js"
45
+ },
46
+ "./server": {
47
+ "types": "./dist/server.d.ts",
48
+ "import": "./dist/server.js",
49
+ "default": "./dist/server.js"
50
+ },
51
+ "./package.json": "./package.json"
52
+ },
53
+ "dependencies": {
54
+ "@formadapter/core": "^0.0.0"
55
+ },
56
+ "peerDependencies": {
57
+ "@tanstack/react-start": ">=1.168.25 <2",
58
+ "react": "^18.2.0 || ^19.0.0"
59
+ },
60
+ "devDependencies": {
61
+ "@tanstack/react-start": "1.168.25",
62
+ "@types/react": "^19.2.17",
63
+ "@types/react-dom": "^19.2.3",
64
+ "react": "19.2.7",
65
+ "react-dom": "19.2.7"
66
+ },
67
+ "scripts": {
68
+ "build": "tsdown",
69
+ "clean": "rm -rf dist tsconfig.tsbuildinfo .turbo",
70
+ "dev": "tsdown --watch",
71
+ "test": "vitest run --config vitest.config.ts",
72
+ "test:coverage": "vitest run --config vitest.config.ts --coverage",
73
+ "typecheck": "tsc --project tsconfig.json --noEmit"
74
+ }
75
+ }