@noya-app/noya-api-client-react 0.1.35 → 0.1.36

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noya-app/noya-api-client-react",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -10,10 +10,10 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@legendapp/state": "^2.1.1",
13
- "@noya-app/noya-api": "0.1.35",
14
- "@noya-app/noya-utils": "0.1.5",
15
- "@noya-app/observable": "0.1.10",
16
- "@noya-app/observable-react": "0.1.20"
13
+ "@noya-app/noya-api": "0.1.36",
14
+ "@noya-app/noya-utils": "0.1.6",
15
+ "@noya-app/observable": "0.1.11",
16
+ "@noya-app/observable-react": "0.1.21"
17
17
  },
18
18
  "peerDependencies": {
19
19
  "react": "*",
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "@noya-app/noya-api";
2
2
  export * from "./react/context";
3
3
  export * from "./react/hooks";
4
+ export * from "./react/tableHooks";
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import { NoyaAPI } from "@noya-app/noya-api";
2
4
  import { createContext, useContext, useMemo } from "react";
3
5
 
@@ -31,11 +33,12 @@ export function useOptionalNoyaClient(): NoyaAPIContextValue | undefined {
31
33
  export function useNoyaClientOrFallback(): NoyaAPIContextValue {
32
34
  const value = useContext(NoyaAPIContext);
33
35
 
34
- const memoryClient = useMemo(() => {
35
- return new NoyaAPI.Client({
36
- networkClient: new NoyaAPI.MemoryClient(),
37
- });
38
- }, []);
39
-
40
- return value ?? memoryClient;
36
+ return useMemo(() => {
37
+ return (
38
+ value ??
39
+ new NoyaAPI.Client({
40
+ networkClient: new NoyaAPI.MemoryClient(),
41
+ })
42
+ );
43
+ }, [value]);
41
44
  }
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import { useSelector } from "@legendapp/state/react";
2
4
  import { GENERATED_PAGE_NAME_COUNT, NoyaAPI } from "@noya-app/noya-api";
3
5
  import { range } from "@noya-app/noya-utils";
@@ -9,52 +11,6 @@ import {
9
11
  useOptionalNoyaClient,
10
12
  } from "./context";
11
13
 
12
- export function useNoyaFiles(): {
13
- files: NoyaAPI.File[];
14
- loading: boolean;
15
- reload: () => Promise<void>;
16
- } {
17
- const client = useNoyaClientOrFallback();
18
- const files = useSelector(client.files$);
19
- const session = useSelector(useNoyaClient().session$);
20
-
21
- useEffect(() => {
22
- if (!session) return;
23
-
24
- if (
25
- files.loading === "notStarted" ||
26
- files.loading === "populatedOnServer"
27
- ) {
28
- client.files.refetch();
29
- }
30
- }, [client, files.loading, session]);
31
-
32
- const reload = useCallback(() => {
33
- return client.files.refetch();
34
- }, [client]);
35
-
36
- return {
37
- files: files.files,
38
- loading: !(
39
- files.loading === "loadedInClient" ||
40
- files.loading === "populatedOnServer"
41
- ),
42
- reload,
43
- };
44
- }
45
-
46
- export function useNoyaFile(fileId?: string) {
47
- const client = useNoyaClientOrFallback();
48
- const files = useSelector(client.files$);
49
- return files.files.find((file) => file.id === fileId);
50
- }
51
-
52
- export function useNoyaIsOwnFile(fileId?: string) {
53
- const file = useNoyaFile(fileId);
54
- const session = useNoyaSession();
55
- return file?.userId === session?.user.id;
56
- }
57
-
58
14
  export function useNoyaTools(initial?: NoyaAPI.Tool[]) {
59
15
  const didInitialize = useRef(false);
60
16
  const client = useNoyaClientOrFallback();
@@ -355,6 +311,15 @@ export function useNoyaWorkspaces() {
355
311
  return workspaces;
356
312
  }
357
313
 
314
+ export function useNoyaMultiplayerRoomToken(fileId: string) {
315
+ const client = useNoyaClientOrFallback();
316
+ const multiplayerRoomToken = useObservable(
317
+ client.multiplayerRoomTokens$,
318
+ useMemo(() => (tokens) => tokens[fileId]?.payload ?? undefined, [fileId])
319
+ );
320
+ return multiplayerRoomToken as { access: "read" | "write" } | undefined;
321
+ }
322
+
358
323
  export function useNoyaWorkspaceInvitations(workspaceId: string) {
359
324
  const client = useNoyaClientOrFallback();
360
325
  const workspaceInvitations = useSelector(
@@ -380,15 +345,15 @@ export function useNoyaWorkspaceInvitations(workspaceId: string) {
380
345
 
381
346
  const emptyObservedFileVersions: {
382
347
  fileVersions: NoyaAPI.FileVersion[];
383
- loading: NoyaAPI.DataLoadingState;
348
+ loading: NoyaAPI.FetchStatus;
384
349
  } = {
385
350
  fileVersions: [],
386
- loading: "notStarted",
351
+ loading: "idle",
387
352
  };
388
353
 
389
354
  export function useNoyaOwnedFileVersions(fileId: string): {
390
355
  fileVersions: NoyaAPI.FileVersion[];
391
- loading: NoyaAPI.DataLoadingState;
356
+ loading: NoyaAPI.FetchStatus;
392
357
  reload: () => Promise<void>;
393
358
  } {
394
359
  const client = useNoyaClientOrFallback();
@@ -396,7 +361,7 @@ export function useNoyaOwnedFileVersions(fileId: string): {
396
361
  const fileVersions = useObservable(client.ownedFileVersions$, path);
397
362
 
398
363
  useEffect(() => {
399
- if (!fileVersions || fileVersions.loading === "notStarted") {
364
+ if (!fileVersions || fileVersions.loading === "idle") {
400
365
  client.fileVersions.refetch({ fileId, type: "owned" });
401
366
  }
402
367
  }, [client, fileId, fileVersions, fileVersions?.loading]);
@@ -420,13 +385,13 @@ export function useNoyaTemplates() {
420
385
  const { templates, loading } = useSelector(client.templates$);
421
386
 
422
387
  useEffect(() => {
423
- if (loading === "notStarted" || loading === "populatedOnServer") {
388
+ if (loading === "idle") {
424
389
  client.templates.read();
425
390
  }
426
391
  }, [client, loading]);
427
392
 
428
393
  return {
429
394
  templates,
430
- loading: !(loading === "loadedInClient" || loading === "populatedOnServer"),
395
+ loading: loading === "fetching",
431
396
  };
432
397
  }
@@ -0,0 +1,102 @@
1
+ import { NoyaAPI, RefetchableObservable } from "@noya-app/noya-api";
2
+ import { useObservable } from "@noya-app/noya-multiplayer-react";
3
+ import { SelectConfig, SelectedShape } from "@noya-app/observable";
4
+ import { useMemo } from "react";
5
+ import { useNoyaClientOrFallback } from "./context";
6
+
7
+ type FileListTableOptions = {
8
+ policy?: NoyaAPI.FetchPolicy;
9
+ debug?: boolean;
10
+ };
11
+
12
+ function useFileListTable<Config extends SelectConfig<NoyaAPI.FileListItem>>(
13
+ { where, select }: { where?: { id?: string | null }; select: Config },
14
+ options: FileListTableOptions
15
+ ): {
16
+ status: NoyaAPI.FetchStatus;
17
+ data: SelectedShape<NoyaAPI.FileListItem, Config>[];
18
+ refetch: () => void;
19
+ } {
20
+ const client = useNoyaClientOrFallback();
21
+
22
+ const stableSelect = useMemo(() => {
23
+ return JSON.stringify(select);
24
+ }, [select]);
25
+
26
+ const observable = useMemo(() => {
27
+ if (where?.id === null) {
28
+ return new RefetchableObservable<{
29
+ status: NoyaAPI.FetchStatus;
30
+ data: SelectedShape<NoyaAPI.FileListItem, Config>[];
31
+ }>({
32
+ status: "success",
33
+ data: [],
34
+ });
35
+ }
36
+
37
+ const parsedSelect = JSON.parse(stableSelect) as typeof select;
38
+
39
+ return client.fileList$.query(
40
+ {
41
+ $where: { id: where?.id },
42
+ $select: parsedSelect,
43
+ },
44
+ {
45
+ policy: options.policy,
46
+ debug: options.debug,
47
+ }
48
+ );
49
+ }, [
50
+ client.fileList$,
51
+ options.policy,
52
+ stableSelect,
53
+ where?.id,
54
+ options.debug,
55
+ ]);
56
+
57
+ const { status, data } = useObservable(observable);
58
+
59
+ return useMemo(() => {
60
+ return {
61
+ status,
62
+ data,
63
+ refetch: observable.refetch,
64
+ };
65
+ }, [status, data, observable]);
66
+ }
67
+
68
+ export function useFileList<Config extends SelectConfig<NoyaAPI.FileListItem>>(
69
+ select: Config,
70
+ options: FileListTableOptions = {}
71
+ ): {
72
+ status: NoyaAPI.FetchStatus;
73
+ data: SelectedShape<NoyaAPI.FileListItem, Config>[];
74
+ refetch: () => void;
75
+ } {
76
+ return useFileListTable({ select }, options);
77
+ }
78
+
79
+ export function useFileListItem<
80
+ Config extends SelectConfig<NoyaAPI.FileListItem>,
81
+ >(
82
+ id: string | undefined,
83
+ select: Config,
84
+ options: FileListTableOptions = {}
85
+ ): {
86
+ status: NoyaAPI.FetchStatus;
87
+ data: SelectedShape<NoyaAPI.FileListItem, Config> | undefined;
88
+ refetch: () => void;
89
+ } {
90
+ const { status, data, refetch } = useFileListTable(
91
+ { where: { id: id ?? null }, select },
92
+ options
93
+ );
94
+
95
+ return useMemo(() => {
96
+ return {
97
+ data: data.at(0),
98
+ status,
99
+ refetch,
100
+ };
101
+ }, [data, status, refetch]);
102
+ }