@adonis-agora/collaboration-client 0.2.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.
Files changed (62) hide show
  1. package/README.md +86 -0
  2. package/dist/src/context.d.ts +28 -0
  3. package/dist/src/context.d.ts.map +1 -0
  4. package/dist/src/context.js +45 -0
  5. package/dist/src/context.js.map +1 -0
  6. package/dist/src/hooks/use_automerge_doc.d.ts +29 -0
  7. package/dist/src/hooks/use_automerge_doc.d.ts.map +1 -0
  8. package/dist/src/hooks/use_automerge_doc.js +93 -0
  9. package/dist/src/hooks/use_automerge_doc.js.map +1 -0
  10. package/dist/src/hooks/use_awareness.d.ts +12 -0
  11. package/dist/src/hooks/use_awareness.d.ts.map +1 -0
  12. package/dist/src/hooks/use_awareness.js +47 -0
  13. package/dist/src/hooks/use_awareness.js.map +1 -0
  14. package/dist/src/hooks/use_collab_doc.d.ts +17 -0
  15. package/dist/src/hooks/use_collab_doc.d.ts.map +1 -0
  16. package/dist/src/hooks/use_collab_doc.js +24 -0
  17. package/dist/src/hooks/use_collab_doc.js.map +1 -0
  18. package/dist/src/hooks/use_comments.d.ts +21 -0
  19. package/dist/src/hooks/use_comments.d.ts.map +1 -0
  20. package/dist/src/hooks/use_comments.js +66 -0
  21. package/dist/src/hooks/use_comments.js.map +1 -0
  22. package/dist/src/hooks/use_versions.d.ts +18 -0
  23. package/dist/src/hooks/use_versions.d.ts.map +1 -0
  24. package/dist/src/hooks/use_versions.js +58 -0
  25. package/dist/src/hooks/use_versions.js.map +1 -0
  26. package/dist/src/index.d.ts +20 -0
  27. package/dist/src/index.d.ts.map +1 -0
  28. package/dist/src/index.js +13 -0
  29. package/dist/src/index.js.map +1 -0
  30. package/dist/src/rest_client.d.ts +27 -0
  31. package/dist/src/rest_client.d.ts.map +1 -0
  32. package/dist/src/rest_client.js +89 -0
  33. package/dist/src/rest_client.js.map +1 -0
  34. package/dist/src/session.d.ts +26 -0
  35. package/dist/src/session.d.ts.map +1 -0
  36. package/dist/src/session.js +129 -0
  37. package/dist/src/session.js.map +1 -0
  38. package/dist/src/transports/hocuspocus.d.ts +20 -0
  39. package/dist/src/transports/hocuspocus.d.ts.map +1 -0
  40. package/dist/src/transports/hocuspocus.js +45 -0
  41. package/dist/src/transports/hocuspocus.js.map +1 -0
  42. package/dist/src/transports/index.d.ts +4 -0
  43. package/dist/src/transports/index.d.ts.map +1 -0
  44. package/dist/src/transports/index.js +16 -0
  45. package/dist/src/transports/index.js.map +1 -0
  46. package/dist/src/transports/normalize_status.d.ts +7 -0
  47. package/dist/src/transports/normalize_status.d.ts.map +1 -0
  48. package/dist/src/transports/normalize_status.js +12 -0
  49. package/dist/src/transports/normalize_status.js.map +1 -0
  50. package/dist/src/transports/partykit.d.ts +15 -0
  51. package/dist/src/transports/partykit.d.ts.map +1 -0
  52. package/dist/src/transports/partykit.js +63 -0
  53. package/dist/src/transports/partykit.js.map +1 -0
  54. package/dist/src/transports/partyserver.d.ts +15 -0
  55. package/dist/src/transports/partyserver.d.ts.map +1 -0
  56. package/dist/src/transports/partyserver.js +61 -0
  57. package/dist/src/transports/partyserver.js.map +1 -0
  58. package/dist/src/types.d.ts +85 -0
  59. package/dist/src/types.d.ts.map +1 -0
  60. package/dist/src/types.js +2 -0
  61. package/dist/src/types.js.map +1 -0
  62. package/package.json +77 -0
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # @adonis-agora/collaboration-client
2
+
3
+ React client hooks for [`@adonis-agora/collaboration`](https://github.com/DavideCarvalho/adonis-agora-collaboration) — collaborative documents, presence, anchored comments and version control with automatic transport selection (Hocuspocus self-hosted or PartyKit edge).
4
+
5
+ React 18/19 · zero dependencies beyond `yjs` stack · ESM.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ pnpm add @adonis-agora/collaboration-client
11
+ ```
12
+
13
+ Server side: install `@adonis-agora/collaboration` and run `node ace collaboration:init` to publish the REST routes these hooks consume.
14
+
15
+ ## Usage
16
+
17
+ Wrap your app once:
18
+
19
+ ```tsx
20
+ import { CollaborationProvider } from '@adonis-agora/collaboration-client'
21
+
22
+ <CollaborationProvider
23
+ baseUrl="https://api.app"
24
+ getHeaders={() => ({ cookie: sessionCookie })}
25
+ >
26
+ <App />
27
+ </CollaborationProvider>
28
+ ```
29
+
30
+ Then per collaborative view:
31
+
32
+ ```tsx
33
+ import {
34
+ useCollabDoc,
35
+ useAwareness,
36
+ useComments,
37
+ useVersions,
38
+ } from '@adonis-agora/collaboration-client'
39
+
40
+ function Writing({ docName }: { docName: string }) {
41
+ // Y.Doc shared per docName (cached across mounts), + connection status
42
+ const { doc, status, error } = useCollabDoc(docName)
43
+ const { peers } = useAwareness(docName) // who's online
44
+ const { comments, create, resolve, remove } = useComments(docName, 'text')
45
+ const { versions, create: createVersion, restore } = useVersions(docName)
46
+
47
+ if (status === 'error') return <p>{error?.message}</p>
48
+
49
+ return (
50
+ <>
51
+ {/* feed `doc` into Tiptap / ProseMirror / Monaco… */}
52
+ {peers.map((peer) => <Avatar key={peer.clientId} name={peer.name} />)}
53
+ </>
54
+ )
55
+ }
56
+ ```
57
+
58
+ ## How it works
59
+
60
+ 1. `useCollabDoc` fetches an ephemeral token from `GET {baseUrl}/collaboration/token?doc=<name>` (your auth middleware protects this route).
61
+ 2. The response's `engine` field picks the transport:
62
+ - `yjs` → `HocuspocusProvider` against the Adonis server (`wsUrl` path)
63
+ - `partykit` → `YPartyKitProvider` straight to the Cloudflare room
64
+ 3. Comments and versions are **REST**, not CRDT state — they live in your database via the server package's storage.
65
+ 4. Sessions survive component unmounts; one `Y.Doc` per document name per provider.
66
+
67
+ ## Custom transport
68
+
69
+ Bring your own sync engine by injecting a factory:
70
+
71
+ ```tsx
72
+ <CollaborationProvider baseUrl="…" createTransport={(info, doc, docName) => new MyTransport(info, doc)}>
73
+ ```
74
+
75
+ ## API
76
+
77
+ | Hook | Returns |
78
+ |---|---|
79
+ | `useCollabDoc(docName)` | `{ doc: Y.Doc, status: 'connecting'\|'connected'\|'disconnected'\|'error', error }` |
80
+ | `useAwareness(docName)` | `{ peers: CollabPeer[], status }` |
81
+ | `useComments(docName, space?)` | `{ comments, loading, error, refresh, create, resolve, remove }` |
82
+ | `useVersions(docName)` | `{ versions, loading, error, refresh, create, restore }` |
83
+
84
+ ## License
85
+
86
+ MIT
@@ -0,0 +1,28 @@
1
+ import { type ReactNode } from 'react';
2
+ import { DocSession } from './session.js';
3
+ import type { CollaborationClientConfig } from './types.js';
4
+ interface CollaborationContextValue {
5
+ /** Sempre retorna o config mais recente do render atual. */
6
+ getConfig(): CollaborationClientConfig;
7
+ sessions: Map<string, DocSession>;
8
+ }
9
+ export interface CollaborationProviderProps extends CollaborationClientConfig {
10
+ children: ReactNode;
11
+ }
12
+ /**
13
+ * Provider raiz. Uma sessão (Y.Doc + transporte) por docName — sobrevive a
14
+ * unmount de componentes individuais e é destruída junto com o provider.
15
+ *
16
+ * ```tsx
17
+ * <CollaborationProvider baseUrl="https://api.app" getHeaders={() => ({ cookie: ... })}>
18
+ * <Editor docName="researches/42/writing" />
19
+ * </CollaborationProvider>
20
+ * ```
21
+ */
22
+ export declare function CollaborationProvider({ children, ...config }: CollaborationProviderProps): import("react/jsx-runtime").JSX.Element;
23
+ /** Contexto interno — lança se usado fora do provider. */
24
+ export declare function useCollaborationContext(): CollaborationContextValue;
25
+ /** Pega ou cria a sessão do documento (1 Y.Doc por docName). */
26
+ export declare function getOrCreateSession(context: CollaborationContextValue, docName: string): DocSession;
27
+ export {};
28
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA8C,MAAM,OAAO,CAAC;AACnF,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE5D,UAAU,yBAAyB;IACjC,4DAA4D;IAC5D,SAAS,IAAI,yBAAyB,CAAC;IACvC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACnC;AAID,MAAM,WAAW,0BAA2B,SAAQ,yBAAyB;IAC3E,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,QAAQ,EAAE,GAAG,MAAM,EAAE,EAAE,0BAA0B,2CAkBxF;AAED,0DAA0D;AAC1D,wBAAgB,uBAAuB,IAAI,yBAAyB,CAMnE;AAED,gEAAgE;AAChE,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,yBAAyB,EAClC,OAAO,EAAE,MAAM,GACd,UAAU,CAOZ"}
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useMemo, useRef } from 'react';
3
+ import { DocSession } from './session.js';
4
+ const CollaborationContext = createContext(null);
5
+ /**
6
+ * Provider raiz. Uma sessão (Y.Doc + transporte) por docName — sobrevive a
7
+ * unmount de componentes individuais e é destruída junto com o provider.
8
+ *
9
+ * ```tsx
10
+ * <CollaborationProvider baseUrl="https://api.app" getHeaders={() => ({ cookie: ... })}>
11
+ * <Editor docName="researches/42/writing" />
12
+ * </CollaborationProvider>
13
+ * ```
14
+ */
15
+ export function CollaborationProvider({ children, ...config }) {
16
+ const sessionsRef = useRef(null);
17
+ if (sessionsRef.current === null) {
18
+ sessionsRef.current = new Map();
19
+ }
20
+ const configRef = useRef(config);
21
+ configRef.current = config;
22
+ const value = useMemo(() => ({
23
+ getConfig: () => configRef.current,
24
+ sessions: sessionsRef.current,
25
+ }), []);
26
+ return _jsx(CollaborationContext.Provider, { value: value, children: children });
27
+ }
28
+ /** Contexto interno — lança se usado fora do provider. */
29
+ export function useCollaborationContext() {
30
+ const context = useContext(CollaborationContext);
31
+ if (!context) {
32
+ throw new Error('useCollabDoc/useAwareness exigem <CollaborationProvider> no tree');
33
+ }
34
+ return context;
35
+ }
36
+ /** Pega ou cria a sessão do documento (1 Y.Doc por docName). */
37
+ export function getOrCreateSession(context, docName) {
38
+ let session = context.sessions.get(docName);
39
+ if (!session) {
40
+ session = new DocSession(docName, context.getConfig());
41
+ context.sessions.set(docName, session);
42
+ }
43
+ return session;
44
+ }
45
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/context.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAkB,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACnF,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAS1C,MAAM,oBAAoB,GAAG,aAAa,CAAmC,IAAI,CAAC,CAAC;AAMnF;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAE,QAAQ,EAAE,GAAG,MAAM,EAA8B;IACvF,MAAM,WAAW,GAAG,MAAM,CAAiC,IAAI,CAAC,CAAC;IACjE,IAAI,WAAW,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QACjC,WAAW,CAAC,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IACtD,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAA4B,MAAM,CAAC,CAAC;IAC5D,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAE3B,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC;QACL,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO;QAClC,QAAQ,EAAE,WAAW,CAAC,OAAkC;KACzD,CAAC,EACF,EAAE,CACH,CAAC;IAEF,OAAO,KAAC,oBAAoB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAiC,CAAC;AACjG,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,uBAAuB;IACrC,MAAM,OAAO,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,kBAAkB,CAChC,OAAkC,EAClC,OAAe;IAEf,IAAI,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,IAAI,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QACvD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,29 @@
1
+ import * as A from '@automerge/automerge';
2
+ import type { CollabStatus } from '../types.js';
3
+ /**
4
+ * Automerge client — deliberately OUTSIDE the Y.Doc-centric
5
+ * CollabTransport seam. Tiptap/awareness need a Y.Doc; Automerge documents
6
+ * are a different data structure, so this ships its own small hook instead
7
+ * of forcing both worlds behind one interface.
8
+ *
9
+ * Wire protocol mirrors the server's AutomergeDriver:
10
+ * 1. ws `${wsUrl}?doc=<name>&token=<token>` (token via fetchToken)
11
+ * 2. server sends the full `A.save(doc)` binary on connect
12
+ * 3. client sends its full saved doc after local changes (debounced)
13
+ * 4. incoming binaries are merged into the local doc and re-broadcast by
14
+ * the server to the other peers
15
+ */
16
+ export interface UseAutomergeDocResult<T extends Record<string, unknown>> {
17
+ /** Merged Automerge doc; null until the first server payload arrives. */
18
+ doc: A.Doc<T> | null;
19
+ status: CollabStatus;
20
+ error: Error | null;
21
+ /** Applies a local change and schedules the debounced send. */
22
+ change(cb: A.ChangeFn<T>): void;
23
+ }
24
+ interface Options {
25
+ WebSocketImpl?: typeof WebSocket;
26
+ }
27
+ export declare function useAutomergeDoc<T extends Record<string, unknown> = Record<string, unknown>>(docName: string, options?: Options): UseAutomergeDocResult<T>;
28
+ export {};
29
+ //# sourceMappingURL=use_automerge_doc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_automerge_doc.d.ts","sourceRoot":"","sources":["../../../src/hooks/use_automerge_doc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,sBAAsB,CAAC;AAI1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,qBAAqB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtE,yEAAyE;IACzE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CACjC;AAED,UAAU,OAAO;IACf,aAAa,CAAC,EAAE,OAAO,SAAS,CAAC;CAClC;AAID,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzF,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,OAAY,GACpB,qBAAqB,CAAC,CAAC,CAAC,CAiG1B"}
@@ -0,0 +1,93 @@
1
+ import * as A from '@automerge/automerge';
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
+ import { getOrCreateSession, useCollaborationContext } from '../context.js';
4
+ import { fetchToken } from '../rest_client.js';
5
+ const SEND_DEBOUNCE_MS = 200;
6
+ export function useAutomergeDoc(docName, options = {}) {
7
+ const context = useCollaborationContext();
8
+ const config = context.getConfig();
9
+ const { WebSocketImpl } = options;
10
+ // Keeps the shared session lifecycle alive (token endpoint + provider).
11
+ void getOrCreateSession(context, docName);
12
+ const [doc, setDoc] = useState(null);
13
+ const [status, setStatus] = useState('connecting');
14
+ const [error, setError] = useState(null);
15
+ const wsRef = useRef(null);
16
+ const localDocRef = useRef(null);
17
+ const sendTimerRef = useRef(undefined);
18
+ const aliveRef = useRef(true);
19
+ useEffect(() => {
20
+ aliveRef.current = true;
21
+ let cancelled = false;
22
+ (async () => {
23
+ try {
24
+ const info = await fetchToken(config, docName);
25
+ if (cancelled || info.engine !== 'automerge') {
26
+ if (!cancelled && info.engine !== 'automerge') {
27
+ throw new Error(`useAutomergeDoc requires engine=automerge (got ${info.engine})`);
28
+ }
29
+ return;
30
+ }
31
+ const base = config.baseUrl.replace(/\/$/, '');
32
+ const wsUrl = info.wsUrl.startsWith('ws')
33
+ ? `${info.wsUrl}?doc=${encodeURIComponent(docName)}&token=${encodeURIComponent(info.token)}`
34
+ : `${base.replace(/^http/, 'ws')}${info.wsUrl}?doc=${encodeURIComponent(docName)}&token=${encodeURIComponent(info.token)}`;
35
+ const ws = new (WebSocketImpl ?? globalThis.WebSocket)(wsUrl);
36
+ ws.binaryType = 'arraybuffer';
37
+ wsRef.current = ws;
38
+ ws.onopen = () => {
39
+ if (!cancelled)
40
+ setStatus('connected');
41
+ };
42
+ ws.onmessage = (event) => {
43
+ if (cancelled)
44
+ return;
45
+ const bytes = new Uint8Array(event.data);
46
+ const incoming = A.load(bytes);
47
+ const next = localDocRef.current ? A.merge(localDocRef.current, incoming) : incoming;
48
+ localDocRef.current = next;
49
+ setDoc(next);
50
+ };
51
+ ws.onerror = () => {
52
+ if (!cancelled)
53
+ setStatus('error');
54
+ };
55
+ ws.onclose = () => {
56
+ if (!cancelled)
57
+ setStatus('disconnected');
58
+ };
59
+ }
60
+ catch (cause) {
61
+ if (!cancelled) {
62
+ setStatus('error');
63
+ setError(cause instanceof Error ? cause : new Error(String(cause)));
64
+ }
65
+ }
66
+ })();
67
+ return () => {
68
+ cancelled = true;
69
+ aliveRef.current = false;
70
+ if (sendTimerRef.current)
71
+ clearTimeout(sendTimerRef.current);
72
+ wsRef.current?.close();
73
+ wsRef.current = null;
74
+ };
75
+ }, [docName, config, WebSocketImpl]);
76
+ const change = useCallback((cb) => {
77
+ if (!localDocRef.current)
78
+ return;
79
+ localDocRef.current = A.change(localDocRef.current, cb);
80
+ setDoc(localDocRef.current);
81
+ if (sendTimerRef.current)
82
+ clearTimeout(sendTimerRef.current);
83
+ sendTimerRef.current = setTimeout(() => {
84
+ const ws = wsRef.current;
85
+ if (ws?.readyState === (WebSocketImpl ?? globalThis.WebSocket).OPEN &&
86
+ localDocRef.current) {
87
+ ws.send(A.save(localDocRef.current));
88
+ }
89
+ }, SEND_DEBOUNCE_MS);
90
+ }, [WebSocketImpl]);
91
+ return { doc, status, error, change };
92
+ }
93
+ //# sourceMappingURL=use_automerge_doc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_automerge_doc.js","sourceRoot":"","sources":["../../../src/hooks/use_automerge_doc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { CollabPeer, CollabStatus } from '../types.js';
2
+ export interface UseAwarenessResult {
3
+ /** Peers conectados (sem o usuário local). */
4
+ peers: CollabPeer[];
5
+ status: CollabStatus;
6
+ }
7
+ /**
8
+ * Presença via awareness: quem está online no documento agora.
9
+ * Atualiza em mudança de awareness (entrar/sair/atualizar cursor).
10
+ */
11
+ export declare function useAwareness(docName: string): UseAwarenessResult;
12
+ //# sourceMappingURL=use_awareness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_awareness.d.ts","sourceRoot":"","sources":["../../../src/hooks/use_awareness.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IACjC,8CAA8C;IAC9C,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;CACtB;AAmBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,CA2BhE"}
@@ -0,0 +1,47 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { getOrCreateSession, useCollaborationContext } from '../context.js';
3
+ function snapshotPeers(awareness) {
4
+ const localId = awareness.clientID;
5
+ const peers = [];
6
+ for (const [clientId, state] of awareness.getStates()) {
7
+ if (clientId === localId)
8
+ continue;
9
+ const user = state
10
+ .user;
11
+ peers.push({
12
+ clientId,
13
+ userId: user?.userId,
14
+ name: user?.name,
15
+ avatarUrl: user?.avatarUrl ?? null,
16
+ });
17
+ }
18
+ return peers;
19
+ }
20
+ /**
21
+ * Presença via awareness: quem está online no documento agora.
22
+ * Atualiza em mudança de awareness (entrar/sair/atualizar cursor).
23
+ */
24
+ export function useAwareness(docName) {
25
+ const context = useCollaborationContext();
26
+ const session = getOrCreateSession(context, docName);
27
+ const [peers, setPeers] = useState([]);
28
+ const [status, setStatus] = useState(session.getStatus());
29
+ useEffect(() => {
30
+ const update = () => {
31
+ setStatus(session.getStatus());
32
+ if (session.transport?.awareness) {
33
+ setPeers(snapshotPeers(session.transport.awareness));
34
+ }
35
+ };
36
+ update();
37
+ const unsubscribe = session.subscribe(update);
38
+ const awareness = session.transport?.awareness;
39
+ awareness?.on('change', update);
40
+ return () => {
41
+ awareness?.off('change', update);
42
+ unsubscribe();
43
+ };
44
+ }, [session]);
45
+ return { peers, status };
46
+ }
47
+ //# sourceMappingURL=use_awareness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_awareness.js","sourceRoot":"","sources":["../../../src/hooks/use_awareness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAS5E,SAAS,aAAa,CAAC,SAAsC;IAC3D,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC;IACnC,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,SAAS,CAAC,SAAS,EAAE,EAAE,CAAC;QACtD,IAAI,QAAQ,KAAK,OAAO;YAAE,SAAS;QACnC,MAAM,IAAI,GAAI,KAAkF;aAC7F,IAAI,CAAC;QACR,KAAK,CAAC,IAAI,CAAC;YACT,QAAQ;YACR,MAAM,EAAE,IAAI,EAAE,MAAM;YACpB,IAAI,EAAE,IAAI,EAAE,IAAI;YAChB,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,IAAI;SACnC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,OAAO,GAAG,uBAAuB,EAAE,CAAC;IAC1C,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACrD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,EAAE,CAAC,CAAC;IACrD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAe,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAExE,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;YAC/B,IAAI,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC;gBACjC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;YACvD,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,EAAE,CAAC;QACT,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAE9C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC;QAC/C,SAAS,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAEhC,OAAO,GAAG,EAAE;YACV,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACjC,WAAW,EAAE,CAAC;QAChB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,17 @@
1
+ import * as Y from 'yjs';
2
+ import type { CollabStatus } from '../types.js';
3
+ export interface UseCollabDocResult {
4
+ /** Y.Doc compartilhado (estável enquanto o provider viver). */
5
+ doc: Y.Doc;
6
+ status: CollabStatus;
7
+ error: Error | null;
8
+ }
9
+ /**
10
+ * Conecta ao documento colaborativo e devolve o Y.Doc + status.
11
+ *
12
+ * ```tsx
13
+ * const { doc, status } = useCollabDoc('researches/42/writing')
14
+ * ```
15
+ */
16
+ export declare function useCollabDoc(docName: string): UseCollabDocResult;
17
+ //# sourceMappingURL=use_collab_doc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_collab_doc.d.ts","sourceRoot":"","sources":["../../../src/hooks/use_collab_doc.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,kBAAkB;IACjC,+DAA+D;IAC/D,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACX,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAoBhE"}
@@ -0,0 +1,24 @@
1
+ import { useEffect, useSyncExternalStore } from 'react';
2
+ import { getOrCreateSession, useCollaborationContext } from '../context.js';
3
+ /**
4
+ * Conecta ao documento colaborativo e devolve o Y.Doc + status.
5
+ *
6
+ * ```tsx
7
+ * const { doc, status } = useCollabDoc('researches/42/writing')
8
+ * ```
9
+ */
10
+ export function useCollabDoc(docName) {
11
+ const context = useCollaborationContext();
12
+ const session = getOrCreateSession(context, docName);
13
+ const status = useSyncExternalStore((onStoreChange) => session.subscribe(onStoreChange), () => session.getStatus(), () => 'connecting');
14
+ // Garante start mesmo sem re-render subsequente; sessão é cacheada no
15
+ // provider, então este efeito é barato em re-montagens.
16
+ useEffect(() => {
17
+ void session.start();
18
+ return () => {
19
+ // Sem destroy aqui: a sessão sobrevive ao unmount do componente.
20
+ };
21
+ }, [session]);
22
+ return { doc: session.doc, status, error: session.error };
23
+ }
24
+ //# sourceMappingURL=use_collab_doc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_collab_doc.js","sourceRoot":"","sources":["../../../src/hooks/use_collab_doc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAExD,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAU5E;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,OAAO,GAAG,uBAAuB,EAAE,CAAC;IAC1C,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG,oBAAoB,CACjC,CAAC,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC,EACnD,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EACzB,GAAG,EAAE,CAAC,YAA4B,CACnC,CAAC;IAEF,sEAAsE;IACtE,wDAAwD;IACxD,SAAS,CAAC,GAAG,EAAE;QACb,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,GAAG,EAAE;YACV,iEAAiE;QACnE,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { CollabComment } from '../types.js';
2
+ export interface UseCommentsResult {
3
+ comments: CollabComment[];
4
+ loading: boolean;
5
+ error: Error | null;
6
+ refresh(): Promise<void>;
7
+ create(input: Pick<CollabComment, 'space' | 'anchor' | 'body' | 'userId'> & {
8
+ authorName?: string | null;
9
+ }): Promise<CollabComment>;
10
+ resolve(commentId: string, resolved?: boolean): Promise<void>;
11
+ remove(commentId: string): Promise<void>;
12
+ }
13
+ /**
14
+ * Comentários ancorados de um documento (REST — dados relacionais no Adonis).
15
+ *
16
+ * ```tsx
17
+ * const { comments, create, resolve } = useComments('researches/42/writing', 'text')
18
+ * ```
19
+ */
20
+ export declare function useComments(docName: string, space?: string): UseCommentsResult;
21
+ //# sourceMappingURL=use_comments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_comments.d.ts","sourceRoot":"","sources":["../../../src/hooks/use_comments.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,CACJ,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC,GAAG;QACnE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,GACA,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1B,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAyE9E"}
@@ -0,0 +1,66 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { getOrCreateSession, useCollaborationContext } from '../context.js';
3
+ import { createComment as apiCreateComment, deleteComment as apiDeleteComment, listComments, resolveComment, } from '../rest_client.js';
4
+ /**
5
+ * Comentários ancorados de um documento (REST — dados relacionais no Adonis).
6
+ *
7
+ * ```tsx
8
+ * const { comments, create, resolve } = useComments('researches/42/writing', 'text')
9
+ * ```
10
+ */
11
+ export function useComments(docName, space) {
12
+ const context = useCollaborationContext();
13
+ const config = context.getConfig();
14
+ // Mantém a sessão viva (compartilha o ciclo do doc) sem exigir o WS pra
15
+ // comentários — REST funciona mesmo com engine offline.
16
+ void getOrCreateSession(context, docName);
17
+ const [comments, setComments] = useState([]);
18
+ const [loading, setLoading] = useState(true);
19
+ const [error, setError] = useState(null);
20
+ const mountedRef = useRef(true);
21
+ useEffect(() => {
22
+ mountedRef.current = true;
23
+ return () => {
24
+ mountedRef.current = false;
25
+ };
26
+ }, []);
27
+ const refresh = useCallback(async () => {
28
+ setLoading(true);
29
+ try {
30
+ const data = await listComments(config, docName, space);
31
+ if (mountedRef.current) {
32
+ setComments(data);
33
+ setError(null);
34
+ }
35
+ }
36
+ catch (cause) {
37
+ if (mountedRef.current) {
38
+ setError(cause instanceof Error ? cause : new Error(String(cause)));
39
+ }
40
+ }
41
+ finally {
42
+ if (mountedRef.current)
43
+ setLoading(false);
44
+ }
45
+ }, [config, docName, space]);
46
+ useEffect(() => {
47
+ void refresh();
48
+ }, [refresh]);
49
+ const create = useCallback(async (input) => {
50
+ const comment = await apiCreateComment(config, { ...input, documentName: docName });
51
+ await refresh();
52
+ return comment;
53
+ }, [config, docName, refresh]);
54
+ const resolve = useCallback(async (commentId, resolved = true) => {
55
+ await resolveComment(config, docName, commentId, resolved);
56
+ setComments((current) => current.map((comment) => comment.id === commentId
57
+ ? { ...comment, resolvedAt: resolved ? new Date().toISOString() : null }
58
+ : comment));
59
+ }, [config, docName]);
60
+ const remove = useCallback(async (commentId) => {
61
+ await apiDeleteComment(config, docName, commentId);
62
+ setComments((current) => current.filter((comment) => comment.id !== commentId));
63
+ }, [config, docName]);
64
+ return { comments, loading, error, refresh, create, resolve, remove };
65
+ }
66
+ //# sourceMappingURL=use_comments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_comments.js","sourceRoot":"","sources":["../../../src/hooks/use_comments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { CollabVersion } from '../types.js';
2
+ export interface UseVersionsResult {
3
+ versions: CollabVersion[];
4
+ loading: boolean;
5
+ error: Error | null;
6
+ refresh(): Promise<void>;
7
+ create(label?: string | null): Promise<CollabVersion>;
8
+ restore(versionId: string): Promise<void>;
9
+ }
10
+ /**
11
+ * Version control de um documento (REST — snapshots ficam no Adonis).
12
+ *
13
+ * ```tsx
14
+ * const { versions, create, restore } = useVersions('researches/42/writing')
15
+ * ```
16
+ */
17
+ export declare function useVersions(docName: string): UseVersionsResult;
18
+ //# sourceMappingURL=use_versions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_versions.d.ts","sourceRoot":"","sources":["../../../src/hooks/use_versions.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACtD,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAwD9D"}
@@ -0,0 +1,58 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { getOrCreateSession, useCollaborationContext } from '../context.js';
3
+ import { createVersion as apiCreateVersion, restoreVersion as apiRestoreVersion, listVersions, } from '../rest_client.js';
4
+ /**
5
+ * Version control de um documento (REST — snapshots ficam no Adonis).
6
+ *
7
+ * ```tsx
8
+ * const { versions, create, restore } = useVersions('researches/42/writing')
9
+ * ```
10
+ */
11
+ export function useVersions(docName) {
12
+ const context = useCollaborationContext();
13
+ const config = context.getConfig();
14
+ void getOrCreateSession(context, docName);
15
+ const [versions, setVersions] = useState([]);
16
+ const [loading, setLoading] = useState(true);
17
+ const [error, setError] = useState(null);
18
+ const mountedRef = useRef(true);
19
+ useEffect(() => {
20
+ mountedRef.current = true;
21
+ return () => {
22
+ mountedRef.current = false;
23
+ };
24
+ }, []);
25
+ const refresh = useCallback(async () => {
26
+ setLoading(true);
27
+ try {
28
+ const data = await listVersions(config, docName);
29
+ if (mountedRef.current) {
30
+ setVersions(data);
31
+ setError(null);
32
+ }
33
+ }
34
+ catch (cause) {
35
+ if (mountedRef.current) {
36
+ setError(cause instanceof Error ? cause : new Error(String(cause)));
37
+ }
38
+ }
39
+ finally {
40
+ if (mountedRef.current)
41
+ setLoading(false);
42
+ }
43
+ }, [config, docName]);
44
+ useEffect(() => {
45
+ void refresh();
46
+ }, [refresh]);
47
+ const create = useCallback(async (label = null) => {
48
+ const version = await apiCreateVersion(config, docName, label);
49
+ await refresh();
50
+ return version;
51
+ }, [config, docName, refresh]);
52
+ const restore = useCallback(async (versionId) => {
53
+ await apiRestoreVersion(config, docName, versionId);
54
+ await refresh();
55
+ }, [config, docName, refresh]);
56
+ return { versions, loading, error, refresh, create, restore };
57
+ }
58
+ //# sourceMappingURL=use_versions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_versions.js","sourceRoot":"","sources":["../../../src/hooks/use_versions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export { CollaborationProvider, useCollaborationContext } from './context.js';
2
+ export type { CollaborationProviderProps } from './context.js';
3
+ export { DocSession } from './session.js';
4
+ export { CollabRestError, collabFetch, createComment, createVersion, deleteComment, fetchToken, listComments, listVersions, resolveComment, restoreVersion, } from './rest_client.js';
5
+ export { defaultTransportFactory } from './transports/index.js';
6
+ export { HocuspocusCollabTransport } from './transports/hocuspocus.js';
7
+ export { PartyKitCollabTransport } from './transports/partykit.js';
8
+ export { PartyServerCollabTransport } from './transports/partyserver.js';
9
+ export { useCollabDoc } from './hooks/use_collab_doc.js';
10
+ export type { UseCollabDocResult } from './hooks/use_collab_doc.js';
11
+ export { useAwareness } from './hooks/use_awareness.js';
12
+ export type { UseAwarenessResult } from './hooks/use_awareness.js';
13
+ export { useComments } from './hooks/use_comments.js';
14
+ export type { UseCommentsResult } from './hooks/use_comments.js';
15
+ export { useVersions } from './hooks/use_versions.js';
16
+ export type { UseVersionsResult } from './hooks/use_versions.js';
17
+ export type { CollabComment, CollabPeer, CollabStatus, CollabTokenInfo, CollabTransport, CollabVersion, CollaborationClientConfig, TransportFactory, } from './types.js';
18
+ export { useAutomergeDoc } from './hooks/use_automerge_doc.js';
19
+ export type { UseAutomergeDocResult } from './hooks/use_automerge_doc.js';
20
+ //# sourceMappingURL=index.d.ts.map