@weirdscience/based-client 0.2.0 → 0.3.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/README.md CHANGED
@@ -60,6 +60,41 @@ const { data, total, isLoading } = useQuery("posts", {
60
60
  });
61
61
  ```
62
62
 
63
+ Gate the query behind auth or any boolean with `enabled`:
64
+
65
+ ```tsx
66
+ const { user } = useUser();
67
+ const { data } = useQuery("notes", { enabled: !!user });
68
+ // Won't fire until `user` is truthy — avoids a 403 when signed out.
69
+ ```
70
+
71
+ ### `useRecord(table, id, options?)`
72
+
73
+ Fetch a single record by id via `GET /api/:table/:id`. Returns `{ data, isLoading, error, refetch }` — `data` is a single row, not an array.
74
+
75
+ ```tsx
76
+ import { useRecord } from "@weirdscience/based-client";
77
+
78
+ function Post({ id }: { id: string }) {
79
+ const { data: post, isLoading } = useRecord("posts", id);
80
+ if (isLoading) return <Spinner />;
81
+ if (!post) return <NotFound />;
82
+ return <h1>{post.title}</h1>;
83
+ }
84
+ ```
85
+
86
+ Pass `null`/`undefined` as the id to skip the query (same effect as `enabled: false`):
87
+
88
+ ```tsx
89
+ const { data } = useRecord("posts", selectedId); // no fetch until selectedId is set
90
+ ```
91
+
92
+ Perfect for deterministic keys like `${userId}:${key}`:
93
+
94
+ ```tsx
95
+ const { data: prefs } = useRecord("preferences", `${user.id}:theme`);
96
+ ```
97
+
63
98
  ### `useMutation(table, operation)`
64
99
 
65
100
  Write rows. `operation` is `"create" | "update" | "delete"`. Returns `{ mutate, isLoading, error }`.
@@ -1 +1 @@
1
- {"version":3,"file":"use-query.d.ts","sourceRoot":"","sources":["../../src/hooks/use-query.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzE,wBAAgB,QAAQ,CACtB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,aAAa,EACjE,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,EAE7C,KAAK,EAAE,CAAC,EACR,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAC3B,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAiDnB"}
1
+ {"version":3,"file":"use-query.d.ts","sourceRoot":"","sources":["../../src/hooks/use-query.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzE,wBAAgB,QAAQ,CACtB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,aAAa,EACjE,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,EAE7C,KAAK,EAAE,CAAC,EACR,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAC3B,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAyDnB"}
@@ -0,0 +1,3 @@
1
+ import type { RecordOptions, RecordResult, DefaultTables } from "../types";
2
+ export declare function useRecord<T extends Record<string, Record<string, unknown>> = DefaultTables, K extends string & keyof T = string & keyof T>(table: K, id: string | null | undefined, options?: RecordOptions): RecordResult<T[K]>;
3
+ //# sourceMappingURL=use-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-record.d.ts","sourceRoot":"","sources":["../../src/hooks/use-record.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE3E,wBAAgB,SAAS,CACvB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,aAAa,EACjE,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,EAE7C,KAAK,EAAE,CAAC,EACR,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC7B,OAAO,CAAC,EAAE,aAAa,GACtB,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CA8CpB"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { createClient } from "./client";
2
2
  export { BasedProvider, useBasedClient } from "./provider";
3
3
  export { useUser } from "./hooks/use-user";
4
4
  export { useQuery } from "./hooks/use-query";
5
+ export { useRecord } from "./hooks/use-record";
5
6
  export { useMutation } from "./hooks/use-mutation";
6
- export type { BasedClient, BasedClientOptions, AuthUser, AuthState, QueryOptions, QueryResult, MutationResult, DefaultTables, } from "./types";
7
+ export type { BasedClient, BasedClientOptions, StorageAdapter, AuthUser, AuthState, QueryOptions, QueryResult, RecordOptions, RecordResult, MutationResult, DefaultTables, } from "./types";
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,WAAW,EACX,cAAc,EACd,aAAa,GACd,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,WAAW,EACX,aAAa,EACb,YAAY,EACZ,cAAc,EACd,aAAa,GACd,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -251,9 +251,10 @@ function useUser() {
251
251
  import { useState, useEffect, useCallback } from "react";
252
252
  function useQuery(table, options) {
253
253
  const client = useBasedClient();
254
+ const enabled = options?.enabled !== false;
254
255
  const [data, setData] = useState(null);
255
256
  const [total, setTotal] = useState(0);
256
- const [isLoading, setIsLoading] = useState(true);
257
+ const [isLoading, setIsLoading] = useState(enabled);
257
258
  const [error, setError] = useState(null);
258
259
  const fetchData = useCallback(async () => {
259
260
  setIsLoading(true);
@@ -291,17 +292,69 @@ function useQuery(table, options) {
291
292
  }
292
293
  }, [client, table, JSON.stringify(options)]);
293
294
  useEffect(() => {
295
+ if (!enabled) {
296
+ setIsLoading(false);
297
+ setData(null);
298
+ setTotal(0);
299
+ setError(null);
300
+ return;
301
+ }
294
302
  fetchData();
295
- }, [fetchData]);
303
+ }, [fetchData, enabled]);
296
304
  return { data, total, isLoading, error, refetch: fetchData };
297
305
  }
306
+ // src/hooks/use-record.ts
307
+ import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
308
+ function useRecord(table, id, options) {
309
+ const client = useBasedClient();
310
+ const enabled = options?.enabled !== false && !!id;
311
+ const [data, setData] = useState2(null);
312
+ const [isLoading, setIsLoading] = useState2(enabled);
313
+ const [error, setError] = useState2(null);
314
+ const fetchData = useCallback2(async () => {
315
+ if (!id)
316
+ return;
317
+ setIsLoading(true);
318
+ setError(null);
319
+ try {
320
+ const res = await client.fetch(`/api/${table}/${encodeURIComponent(id)}`);
321
+ const json = await res.json();
322
+ if (!res.ok) {
323
+ if (res.status === 404) {
324
+ setData(null);
325
+ setError(null);
326
+ } else {
327
+ setError(json.error || { code: "UNKNOWN", message: "Request failed" });
328
+ setData(null);
329
+ }
330
+ } else {
331
+ setData(json.data);
332
+ }
333
+ } catch (err) {
334
+ setError({ code: "NETWORK_ERROR", message: err.message });
335
+ setData(null);
336
+ } finally {
337
+ setIsLoading(false);
338
+ }
339
+ }, [client, table, id]);
340
+ useEffect2(() => {
341
+ if (!enabled) {
342
+ setIsLoading(false);
343
+ setData(null);
344
+ setError(null);
345
+ return;
346
+ }
347
+ fetchData();
348
+ }, [fetchData, enabled]);
349
+ return { data, isLoading, error, refetch: fetchData };
350
+ }
298
351
  // src/hooks/use-mutation.ts
299
- import { useState as useState2, useCallback as useCallback2 } from "react";
352
+ import { useState as useState3, useCallback as useCallback3 } from "react";
300
353
  function useMutation(table, operation) {
301
354
  const client = useBasedClient();
302
- const [isLoading, setIsLoading] = useState2(false);
303
- const [error, setError] = useState2(null);
304
- const mutate = useCallback2(async (data) => {
355
+ const [isLoading, setIsLoading] = useState3(false);
356
+ const [error, setError] = useState3(null);
357
+ const mutate = useCallback3(async (data) => {
305
358
  setIsLoading(true);
306
359
  setError(null);
307
360
  try {
@@ -350,6 +403,7 @@ function useMutation(table, operation) {
350
403
  }
351
404
  export {
352
405
  useUser,
406
+ useRecord,
353
407
  useQuery,
354
408
  useMutation,
355
409
  useBasedClient,
package/dist/types.d.ts CHANGED
@@ -54,6 +54,11 @@ export interface QueryOptions<T = Record<string, unknown>> {
54
54
  filter?: Partial<Record<keyof T, string | number | boolean>>;
55
55
  limit?: number;
56
56
  offset?: number;
57
+ /**
58
+ * When false, the query won't fire. Useful for gating queries behind auth:
59
+ * `useQuery("notes", { enabled: !!user })`. Defaults to true.
60
+ */
61
+ enabled?: boolean;
57
62
  }
58
63
  export interface QueryResult<T = unknown> {
59
64
  data: T[] | null;
@@ -65,6 +70,21 @@ export interface QueryResult<T = unknown> {
65
70
  } | null;
66
71
  refetch: () => void;
67
72
  }
73
+ export interface RecordOptions {
74
+ /**
75
+ * When false, the query won't fire.
76
+ */
77
+ enabled?: boolean;
78
+ }
79
+ export interface RecordResult<T = unknown> {
80
+ data: T | null;
81
+ isLoading: boolean;
82
+ error: {
83
+ code: string;
84
+ message: string;
85
+ } | null;
86
+ refetch: () => void;
87
+ }
68
88
  export interface MutationResult<T = unknown> {
69
89
  mutate: (data: Partial<T> & Record<string, unknown>) => Promise<T>;
70
90
  isLoading: boolean;
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "@weirdscience/based-client",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "React SDK for Based — a minimal self-hosted BaaS",
5
5
  "license": "MIT",
6
6
  "repository": {