@weirdscience/based-client 0.4.0 → 0.6.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/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  // src/types.ts
2
4
  class BasedError extends Error {
3
5
  code;
@@ -11,6 +13,20 @@ class BasedError extends Error {
11
13
  this.details = details;
12
14
  }
13
15
  }
16
+ function toHookError(err) {
17
+ if (err instanceof BasedError) {
18
+ return {
19
+ code: err.code,
20
+ message: err.message,
21
+ status: err.status,
22
+ details: err.details
23
+ };
24
+ }
25
+ return {
26
+ code: "NETWORK_ERROR",
27
+ message: err instanceof Error ? err.message : String(err)
28
+ };
29
+ }
14
30
 
15
31
  // src/client.ts
16
32
  var DEFAULT_STORAGE_KEY = "based.session";
@@ -49,6 +65,9 @@ function createClient(options) {
49
65
  function getState() {
50
66
  return state;
51
67
  }
68
+ function onAuthStateChange(callback) {
69
+ return subscribe(() => callback(state));
70
+ }
52
71
  async function persist() {
53
72
  if (!storage)
54
73
  return;
@@ -119,16 +138,22 @@ function createClient(options) {
119
138
  if (!headers.has("Content-Type") && init.body) {
120
139
  headers.set("Content-Type", "application/json");
121
140
  }
141
+ const tokenAtRequest = state.accessToken;
122
142
  let res = await fetch(`${baseUrl}${path}`, { ...init, headers });
123
143
  if (res.status === 401 && state.refreshToken) {
124
- const refreshed = await refreshSession();
125
- if (refreshed) {
144
+ const alreadyRefreshed = state.accessToken !== tokenAtRequest;
145
+ const refreshed = alreadyRefreshed ? true : await refreshSession();
146
+ if (refreshed && state.accessToken) {
126
147
  headers.set("Authorization", `Bearer ${state.accessToken}`);
127
148
  res = await fetch(`${baseUrl}${path}`, { ...init, headers });
128
149
  }
129
150
  }
130
151
  return res;
131
152
  }
153
+ async function authError(res, fallback) {
154
+ const json = await res.json().catch(() => null);
155
+ return new BasedError(json?.error?.code ?? "AUTH_ERROR", json?.error?.message || fallback, res.status, json?.error?.details);
156
+ }
132
157
  async function signUp(email, password) {
133
158
  const res = await fetch(`${baseUrl}/auth/signup`, {
134
159
  method: "POST",
@@ -136,8 +161,7 @@ function createClient(options) {
136
161
  body: JSON.stringify({ email, password })
137
162
  });
138
163
  if (!res.ok) {
139
- const json = await res.json().catch(() => null);
140
- throw new Error(json?.error?.message || "Sign up failed");
164
+ throw await authError(res, "Sign up failed");
141
165
  }
142
166
  const { data } = await res.json();
143
167
  setState({
@@ -155,8 +179,7 @@ function createClient(options) {
155
179
  body: JSON.stringify({ email, password })
156
180
  });
157
181
  if (!res.ok) {
158
- const json = await res.json().catch(() => null);
159
- throw new Error(json?.error?.message || "Sign in failed");
182
+ throw await authError(res, "Sign in failed");
160
183
  }
161
184
  const { data } = await res.json();
162
185
  setState({
@@ -178,7 +201,16 @@ function createClient(options) {
178
201
  }
179
202
  setState({ user: null, accessToken: null, refreshToken: null, isLoading: false });
180
203
  }
181
- async function refreshSession() {
204
+ let refreshInFlight = null;
205
+ function refreshSession() {
206
+ if (!refreshInFlight) {
207
+ refreshInFlight = doRefresh().finally(() => {
208
+ refreshInFlight = null;
209
+ });
210
+ }
211
+ return refreshInFlight;
212
+ }
213
+ async function doRefresh() {
182
214
  if (!state.refreshToken)
183
215
  return false;
184
216
  try {
@@ -215,7 +247,7 @@ function createClient(options) {
215
247
  return null;
216
248
  }
217
249
  const { data } = await res.json();
218
- const user = { id: data.id, email: data.email };
250
+ const user = { id: data.id, email: data.email, role: data.role };
219
251
  setState({ user });
220
252
  return user;
221
253
  } catch {
@@ -223,12 +255,12 @@ function createClient(options) {
223
255
  }
224
256
  }
225
257
  async function parseOrThrow(res, fallbackCode) {
226
- let json = null;
258
+ let json = {};
227
259
  try {
228
260
  json = await res.json();
229
261
  } catch {}
230
262
  if (!res.ok) {
231
- const err = json?.error;
263
+ const err = json.error;
232
264
  throw new BasedError(err?.code || fallbackCode, err?.message || `Request failed with status ${res.status}`, res.status, err?.details);
233
265
  }
234
266
  return json;
@@ -242,6 +274,8 @@ function createClient(options) {
242
274
  params.set("limit", String(opts.limit));
243
275
  if (opts?.offset !== undefined)
244
276
  params.set("offset", String(opts.offset));
277
+ if (opts?.order !== undefined)
278
+ params.set("order", opts.order);
245
279
  if (opts?.filter) {
246
280
  for (const [key, value] of Object.entries(opts.filter)) {
247
281
  if (value !== undefined)
@@ -269,22 +303,25 @@ function createClient(options) {
269
303
  return json.data;
270
304
  },
271
305
  async update(id, data) {
272
- const { id: _omit, ...rest } = data;
306
+ const body = { ...data };
307
+ delete body.id;
273
308
  const res = await fetchWithAuth(`${basePath}/${encodeURIComponent(id)}`, {
274
309
  method: "PUT",
275
- body: JSON.stringify(rest)
310
+ body: JSON.stringify(body)
276
311
  });
277
312
  const json = await parseOrThrow(res, "UPDATE_FAILED");
278
313
  return json.data;
279
314
  },
280
315
  async upsert(data) {
281
- const { id, ...rest } = data;
316
+ const body = { ...data };
317
+ const id = body.id;
282
318
  if (!id) {
283
319
  throw new BasedError("MISSING_ID", "upsert() requires `data.id`. Use insert() to let the server generate one.", 400);
284
320
  }
321
+ delete body.id;
285
322
  const res = await fetchWithAuth(`${basePath}/${encodeURIComponent(id)}`, {
286
323
  method: "PUT",
287
- body: JSON.stringify(rest)
324
+ body: JSON.stringify(body)
288
325
  });
289
326
  const json = await parseOrThrow(res, "UPSERT_FAILED");
290
327
  return json.data;
@@ -299,7 +336,7 @@ function createClient(options) {
299
336
  };
300
337
  }
301
338
  return {
302
- auth: { signUp, signIn, signOut, refreshSession, getUser },
339
+ auth: { signUp, signIn, signOut, refreshSession, getUser, onAuthStateChange },
303
340
  fetch: fetchWithAuth,
304
341
  from,
305
342
  subscribe,
@@ -310,6 +347,7 @@ function createClient(options) {
310
347
  // src/provider.tsx
311
348
  import { createContext, useContext } from "react";
312
349
  import { jsx } from "react/jsx-runtime";
350
+ "use client";
313
351
  var BasedContext = createContext(null);
314
352
  function BasedProvider({
315
353
  client,
@@ -329,9 +367,16 @@ function useBasedClient() {
329
367
  }
330
368
  // src/hooks/use-user.ts
331
369
  import { useSyncExternalStore } from "react";
370
+ "use client";
371
+ var SERVER_SNAPSHOT = Object.freeze({
372
+ user: null,
373
+ accessToken: null,
374
+ refreshToken: null,
375
+ isLoading: true
376
+ });
332
377
  function useUser() {
333
378
  const client = useBasedClient();
334
- const state = useSyncExternalStore(client.subscribe, () => client.getState(), () => client.getState());
379
+ const state = useSyncExternalStore(client.subscribe, () => client.getState(), () => SERVER_SNAPSHOT);
335
380
  return {
336
381
  user: state.user,
337
382
  isLoading: state.isLoading,
@@ -339,79 +384,134 @@ function useUser() {
339
384
  };
340
385
  }
341
386
  // src/hooks/use-query.ts
342
- import { useState, useEffect, useCallback } from "react";
387
+ import {
388
+ useState,
389
+ useEffect,
390
+ useCallback,
391
+ useMemo,
392
+ useRef,
393
+ useSyncExternalStore as useSyncExternalStore2
394
+ } from "react";
395
+ "use client";
396
+ function stableKey(value) {
397
+ if (value === undefined)
398
+ return "undefined";
399
+ if (value === null || typeof value !== "object")
400
+ return JSON.stringify(value);
401
+ if (Array.isArray(value))
402
+ return `[${value.map(stableKey).join(",")}]`;
403
+ const entries = Object.entries(value).filter(([, v]) => v !== undefined).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
404
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableKey(v)}`).join(",")}}`;
405
+ }
343
406
  function useQuery(table, options) {
344
407
  const client = useBasedClient();
345
408
  const enabled = options?.enabled !== false;
409
+ const authKey = useSyncExternalStore2(client.subscribe, () => client.getState().user?.id ?? null, () => null);
346
410
  const [data, setData] = useState(null);
347
411
  const [total, setTotal] = useState(0);
348
412
  const [isLoading, setIsLoading] = useState(enabled);
349
413
  const [error, setError] = useState(null);
350
- const fetchData = useCallback(async () => {
414
+ const optionsKey = stableKey(options);
415
+ const selectOptions = useMemo(() => ({
416
+ filter: options?.filter,
417
+ limit: options?.limit,
418
+ offset: options?.offset,
419
+ order: options?.order
420
+ }), [optionsKey]);
421
+ const latestRequest = useRef(0);
422
+ const runQuery = useCallback(async () => {
423
+ const requestId = ++latestRequest.current;
351
424
  setIsLoading(true);
352
425
  setError(null);
353
426
  try {
354
- const result = await client.from(table).select({ filter: options?.filter, limit: options?.limit, offset: options?.offset });
427
+ const result = await client.from(table).select(selectOptions);
428
+ if (latestRequest.current !== requestId)
429
+ return;
355
430
  setData(result.data);
356
431
  setTotal(result.total);
357
432
  } catch (err) {
358
- const code = err instanceof BasedError ? err.code : "NETWORK_ERROR";
359
- setError({ code, message: err.message });
433
+ if (latestRequest.current !== requestId)
434
+ return;
435
+ setError(toHookError(err));
360
436
  setData(null);
361
437
  setTotal(0);
362
438
  } finally {
363
- setIsLoading(false);
439
+ if (latestRequest.current === requestId)
440
+ setIsLoading(false);
364
441
  }
365
- }, [client, table, JSON.stringify(options)]);
442
+ }, [client, table, selectOptions]);
366
443
  useEffect(() => {
367
444
  if (!enabled) {
368
- setIsLoading(false);
445
+ latestRequest.current += 1;
369
446
  setData(null);
370
447
  setTotal(0);
371
448
  setError(null);
449
+ setIsLoading(false);
372
450
  return;
373
451
  }
374
- fetchData();
375
- }, [fetchData, enabled]);
376
- return { data, total, isLoading, error, refetch: fetchData };
452
+ runQuery();
453
+ return () => {
454
+ latestRequest.current += 1;
455
+ };
456
+ }, [enabled, authKey, runQuery]);
457
+ return { data, total, isLoading, error, refetch: runQuery };
377
458
  }
378
459
  // src/hooks/use-record.ts
379
- import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
460
+ import {
461
+ useState as useState2,
462
+ useEffect as useEffect2,
463
+ useCallback as useCallback2,
464
+ useRef as useRef2,
465
+ useSyncExternalStore as useSyncExternalStore3
466
+ } from "react";
467
+ "use client";
380
468
  function useRecord(table, id, options) {
381
469
  const client = useBasedClient();
382
470
  const enabled = options?.enabled !== false && !!id;
471
+ const authKey = useSyncExternalStore3(client.subscribe, () => client.getState().user?.id ?? null, () => null);
383
472
  const [data, setData] = useState2(null);
384
473
  const [isLoading, setIsLoading] = useState2(enabled);
385
474
  const [error, setError] = useState2(null);
386
- const fetchData = useCallback2(async () => {
475
+ const latestRequest = useRef2(0);
476
+ const runQuery = useCallback2(async () => {
387
477
  if (!id)
388
478
  return;
479
+ const requestId = ++latestRequest.current;
389
480
  setIsLoading(true);
390
481
  setError(null);
391
482
  try {
392
483
  const row = await client.from(table).get(id);
484
+ if (latestRequest.current !== requestId)
485
+ return;
393
486
  setData(row);
394
487
  } catch (err) {
395
- const code = err instanceof BasedError ? err.code : "NETWORK_ERROR";
396
- setError({ code, message: err.message });
488
+ if (latestRequest.current !== requestId)
489
+ return;
490
+ setError(toHookError(err));
397
491
  setData(null);
398
492
  } finally {
399
- setIsLoading(false);
493
+ if (latestRequest.current === requestId)
494
+ setIsLoading(false);
400
495
  }
401
496
  }, [client, table, id]);
402
497
  useEffect2(() => {
403
498
  if (!enabled) {
404
- setIsLoading(false);
499
+ latestRequest.current += 1;
405
500
  setData(null);
406
501
  setError(null);
502
+ setIsLoading(false);
407
503
  return;
408
504
  }
409
- fetchData();
410
- }, [fetchData, enabled]);
411
- return { data, isLoading, error, refetch: fetchData };
505
+ runQuery();
506
+ return () => {
507
+ latestRequest.current += 1;
508
+ };
509
+ }, [enabled, authKey, runQuery]);
510
+ return { data, isLoading, error, refetch: runQuery };
412
511
  }
413
512
  // src/hooks/use-mutation.ts
414
513
  import { useState as useState3, useCallback as useCallback3 } from "react";
514
+ "use client";
415
515
  function useMutation(table, operation) {
416
516
  const client = useBasedClient();
417
517
  const [isLoading, setIsLoading] = useState3(false);
@@ -427,8 +527,7 @@ function useMutation(table, operation) {
427
527
  case "update": {
428
528
  if (!data.id)
429
529
  throw new BasedError("MISSING_ID", "Update requires an 'id' field", 400);
430
- const { id, ...rest } = data;
431
- return await builder.update(String(id), rest);
530
+ return await builder.update(String(data.id), data);
432
531
  }
433
532
  case "upsert": {
434
533
  if (!data.id)
@@ -443,16 +542,17 @@ function useMutation(table, operation) {
443
542
  }
444
543
  }
445
544
  } catch (err) {
446
- const code = err instanceof BasedError ? err.code : "MUTATION_ERROR";
447
- const message = err.message;
448
- setError({ code, message });
449
- throw err;
545
+ setError(toHookError(err));
546
+ return null;
450
547
  } finally {
451
548
  setIsLoading(false);
452
549
  }
453
550
  }, [client, table, operation]);
454
551
  return { mutate, isLoading, error };
455
552
  }
553
+
554
+ // src/index.ts
555
+ "use client";
456
556
  export {
457
557
  useUser,
458
558
  useRecord,
@@ -1,8 +1,8 @@
1
1
  import { type ReactNode } from "react";
2
- import type { BasedClient } from "./types";
3
- export declare function BasedProvider({ client, children, }: {
4
- client: BasedClient;
2
+ import type { BasedClient, DefaultTables } from "./types";
3
+ export declare function BasedProvider<T extends Record<string, Record<string, unknown>> = DefaultTables>({ client, children, }: {
4
+ client: BasedClient<T>;
5
5
  children: ReactNode;
6
6
  }): import("react/jsx-runtime").JSX.Element;
7
- export declare function useBasedClient(): BasedClient;
7
+ export declare function useBasedClient<T extends Record<string, Record<string, unknown>> = DefaultTables>(): BasedClient<T>;
8
8
  //# sourceMappingURL=provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAI3C,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAIA;AAED,wBAAgB,cAAc,IAAI,WAAW,CAM5C"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAI1D,wBAAgB,aAAa,CAC3B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,aAAa,EACjE,EACA,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACvB,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAMA;AAED,wBAAgB,cAAc,CAC5B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,aAAa,KAC9D,WAAW,CAAC,CAAC,CAAC,CAMlB"}
package/dist/types.d.ts CHANGED
@@ -19,6 +19,11 @@ export interface BasedClientOptions {
19
19
  export interface AuthUser {
20
20
  id: string;
21
21
  email: string;
22
+ /**
23
+ * Workspace role as reported by the server. The first user to sign up is the
24
+ * `owner`; everyone after is a `member`.
25
+ */
26
+ role: "owner" | "member";
22
27
  }
23
28
  export interface AuthState {
24
29
  user: AuthUser | null;
@@ -40,6 +45,12 @@ export interface BasedClient<T extends Record<string, Record<string, unknown>> =
40
45
  * Returns the current authenticated user by calling `/auth/me`.
41
46
  */
42
47
  getUser(): Promise<AuthUser | null>;
48
+ /**
49
+ * Subscribe to auth state changes. The callback receives the new state on
50
+ * every change (sign in, sign out, refresh, rehydration). Returns an
51
+ * unsubscribe function. Sugar over `client.subscribe` + `client.getState`.
52
+ */
53
+ onAuthStateChange(callback: (state: AuthState) => void): () => void;
43
54
  };
44
55
  fetch(path: string, init?: RequestInit): Promise<Response>;
45
56
  /**
@@ -97,24 +108,41 @@ export declare class BasedError extends Error {
97
108
  details?: unknown;
98
109
  constructor(code: string, message: string, status: number, details?: unknown);
99
110
  }
111
+ /**
112
+ * Narrow anything thrown by the data builder into the hooks' error shape.
113
+ * Internal — not part of the public surface.
114
+ */
115
+ export declare function toHookError(err: unknown): HookError;
100
116
  export interface QueryOptions<T = Record<string, unknown>> {
101
117
  filter?: Partial<Record<keyof T, string | number | boolean>>;
102
118
  limit?: number;
103
119
  offset?: number;
120
+ /**
121
+ * Sort order, as `<column>.asc` or `<column>.desc`. Defaults to `id.asc`
122
+ * server-side so pagination is stable.
123
+ */
124
+ order?: `${string & keyof T}.asc` | `${string & keyof T}.desc`;
104
125
  /**
105
126
  * When false, the query won't fire. Useful for gating queries behind auth:
106
127
  * `useQuery("notes", { enabled: !!user })`. Defaults to true.
107
128
  */
108
129
  enabled?: boolean;
109
130
  }
131
+ /**
132
+ * The error shape the hooks expose. Mirrors `BasedError` without being an
133
+ * `Error` instance, so it survives React state and serialization.
134
+ */
135
+ export interface HookError {
136
+ code: string;
137
+ message: string;
138
+ status?: number;
139
+ details?: unknown;
140
+ }
110
141
  export interface QueryResult<T = unknown> {
111
142
  data: T[] | null;
112
143
  total: number;
113
144
  isLoading: boolean;
114
- error: {
115
- code: string;
116
- message: string;
117
- } | null;
145
+ error: HookError | null;
118
146
  refetch: () => void;
119
147
  }
120
148
  export interface RecordOptions {
@@ -126,19 +154,22 @@ export interface RecordOptions {
126
154
  export interface RecordResult<T = unknown> {
127
155
  data: T | null;
128
156
  isLoading: boolean;
129
- error: {
130
- code: string;
131
- message: string;
132
- } | null;
157
+ error: HookError | null;
133
158
  refetch: () => void;
134
159
  }
160
+ /**
161
+ * Which write the `useMutation` hook performs.
162
+ */
163
+ export type MutationOperation = "create" | "update" | "upsert" | "delete";
135
164
  export interface MutationResult<T = unknown> {
136
- mutate: (data: Partial<T> & Record<string, unknown>) => Promise<T>;
165
+ /**
166
+ * Performs the write. Never throws — on failure it resolves to `null` and
167
+ * populates `error`, so `onClick={() => mutate(...)}` can't produce an
168
+ * unhandled rejection.
169
+ */
170
+ mutate: (data: Partial<T> & Record<string, unknown>) => Promise<T | null>;
137
171
  isLoading: boolean;
138
- error: {
139
- code: string;
140
- message: string;
141
- } | null;
172
+ error: HookError | null;
142
173
  }
143
174
  export interface DefaultTables {
144
175
  [table: string]: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@weirdscience/based-client",
3
- "version": "0.4.0",
4
- "description": "React SDK for Based — a minimal self-hosted BaaS",
3
+ "version": "0.6.0",
4
+ "description": "SDK for Based — a minimal self-hosted BaaS. Typed client for any JavaScript app, plus React hooks.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -10,13 +10,20 @@
10
10
  },
11
11
  "homepage": "https://based.weirdscience.dev",
12
12
  "type": "module",
13
- "main": "./dist/index.js",
13
+ "main": "./dist/index.cjs",
14
14
  "module": "./dist/index.js",
15
15
  "types": "./dist/index.d.ts",
16
+ "sideEffects": false,
16
17
  "exports": {
17
18
  ".": {
18
19
  "types": "./dist/index.d.ts",
19
- "import": "./dist/index.js"
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs"
22
+ },
23
+ "./core": {
24
+ "types": "./dist/core.d.ts",
25
+ "import": "./dist/core.js",
26
+ "require": "./dist/core.cjs"
20
27
  }
21
28
  },
22
29
  "files": [
@@ -24,15 +31,27 @@
24
31
  "README.md"
25
32
  ],
26
33
  "scripts": {
27
- "build": "rm -rf dist && NODE_ENV=production bun build src/index.ts --outdir dist --target browser --format esm --external react --external react/jsx-runtime && bun x tsc --emitDeclarationOnly --declaration --outDir dist",
34
+ "build": "rm -rf dist && NODE_ENV=production bun build src/index.ts --outdir dist --target browser --format esm --external react --external react/jsx-runtime --banner '\"use client\";' && NODE_ENV=production bun build src/index.ts --outfile dist/index.cjs --target node --format cjs --external react --external react/jsx-runtime --banner '\"use client\";' && NODE_ENV=production bun build src/core.ts --outfile dist/core.js --target browser --format esm && NODE_ENV=production bun build src/core.ts --outfile dist/core.cjs --target node --format cjs && bun x tsc -p tsconfig.json",
28
35
  "prepublishOnly": "bun run build",
29
- "test": "bun test"
36
+ "test": "bun test",
37
+ "typecheck": "tsc --noEmit -p tsconfig.test.json"
30
38
  },
31
39
  "peerDependencies": {
32
40
  "react": "^18.0.0 || ^19.0.0"
33
41
  },
34
42
  "devDependencies": {
43
+ "@happy-dom/global-registrator": "^20.0.0",
44
+ "@testing-library/dom": "^10.4.1",
45
+ "@testing-library/react": "^16.0.0",
35
46
  "@types/react": "^19.0.0",
47
+ "@types/react-dom": "^19.0.0",
48
+ "react": "^19.0.0",
49
+ "react-dom": "^19.0.0",
36
50
  "typescript": "^5.0.0"
51
+ },
52
+ "peerDependenciesMeta": {
53
+ "react": {
54
+ "optional": true
55
+ }
37
56
  }
38
57
  }