@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.
- package/README.md +86 -0
- package/dist/src/context.d.ts +28 -0
- package/dist/src/context.d.ts.map +1 -0
- package/dist/src/context.js +45 -0
- package/dist/src/context.js.map +1 -0
- package/dist/src/hooks/use_automerge_doc.d.ts +29 -0
- package/dist/src/hooks/use_automerge_doc.d.ts.map +1 -0
- package/dist/src/hooks/use_automerge_doc.js +93 -0
- package/dist/src/hooks/use_automerge_doc.js.map +1 -0
- package/dist/src/hooks/use_awareness.d.ts +12 -0
- package/dist/src/hooks/use_awareness.d.ts.map +1 -0
- package/dist/src/hooks/use_awareness.js +47 -0
- package/dist/src/hooks/use_awareness.js.map +1 -0
- package/dist/src/hooks/use_collab_doc.d.ts +17 -0
- package/dist/src/hooks/use_collab_doc.d.ts.map +1 -0
- package/dist/src/hooks/use_collab_doc.js +24 -0
- package/dist/src/hooks/use_collab_doc.js.map +1 -0
- package/dist/src/hooks/use_comments.d.ts +21 -0
- package/dist/src/hooks/use_comments.d.ts.map +1 -0
- package/dist/src/hooks/use_comments.js +66 -0
- package/dist/src/hooks/use_comments.js.map +1 -0
- package/dist/src/hooks/use_versions.d.ts +18 -0
- package/dist/src/hooks/use_versions.d.ts.map +1 -0
- package/dist/src/hooks/use_versions.js +58 -0
- package/dist/src/hooks/use_versions.js.map +1 -0
- package/dist/src/index.d.ts +20 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +13 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/rest_client.d.ts +27 -0
- package/dist/src/rest_client.d.ts.map +1 -0
- package/dist/src/rest_client.js +89 -0
- package/dist/src/rest_client.js.map +1 -0
- package/dist/src/session.d.ts +26 -0
- package/dist/src/session.d.ts.map +1 -0
- package/dist/src/session.js +129 -0
- package/dist/src/session.js.map +1 -0
- package/dist/src/transports/hocuspocus.d.ts +20 -0
- package/dist/src/transports/hocuspocus.d.ts.map +1 -0
- package/dist/src/transports/hocuspocus.js +45 -0
- package/dist/src/transports/hocuspocus.js.map +1 -0
- package/dist/src/transports/index.d.ts +4 -0
- package/dist/src/transports/index.d.ts.map +1 -0
- package/dist/src/transports/index.js +16 -0
- package/dist/src/transports/index.js.map +1 -0
- package/dist/src/transports/normalize_status.d.ts +7 -0
- package/dist/src/transports/normalize_status.d.ts.map +1 -0
- package/dist/src/transports/normalize_status.js +12 -0
- package/dist/src/transports/normalize_status.js.map +1 -0
- package/dist/src/transports/partykit.d.ts +15 -0
- package/dist/src/transports/partykit.d.ts.map +1 -0
- package/dist/src/transports/partykit.js +63 -0
- package/dist/src/transports/partykit.js.map +1 -0
- package/dist/src/transports/partyserver.d.ts +15 -0
- package/dist/src/transports/partyserver.d.ts.map +1 -0
- package/dist/src/transports/partyserver.js +61 -0
- package/dist/src/transports/partyserver.js.map +1 -0
- package/dist/src/types.d.ts +85 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- 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
|