yrby-client 0.5.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/README.md +236 -36
- package/dist/actioncable_provider.d.ts +18 -11
- package/dist/actioncable_provider.d.ts.map +1 -1
- package/dist/actioncable_provider.js +286 -178
- package/dist/actioncable_provider.js.map +1 -1
- package/dist/cjs/actioncable_provider.d.ts +18 -11
- package/dist/cjs/actioncable_provider.js +287 -179
- package/dist/cjs/document_element.d.ts +24 -0
- package/dist/cjs/document_element.js +260 -0
- package/dist/cjs/document_session.d.ts +62 -0
- package/dist/cjs/document_session.js +335 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +4 -1
- package/dist/cjs/reliable_sync.d.ts +18 -31
- package/dist/cjs/reliable_sync.js +128 -98
- package/dist/cjs/turbo_adapter.d.ts +9 -0
- package/dist/cjs/turbo_adapter.js +81 -0
- package/dist/cjs/y_protocol_session.d.ts +6 -6
- package/dist/cjs/y_protocol_session.js +96 -81
- package/dist/document_element.d.ts +25 -0
- package/dist/document_element.d.ts.map +1 -0
- package/dist/document_element.js +225 -0
- package/dist/document_element.js.map +1 -0
- package/dist/document_session.d.ts +63 -0
- package/dist/document_session.d.ts.map +1 -0
- package/dist/document_session.js +296 -0
- package/dist/document_session.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/reliable_sync.d.ts +18 -31
- package/dist/reliable_sync.d.ts.map +1 -1
- package/dist/reliable_sync.js +128 -98
- package/dist/reliable_sync.js.map +1 -1
- package/dist/turbo_adapter.d.ts +10 -0
- package/dist/turbo_adapter.d.ts.map +1 -0
- package/dist/turbo_adapter.js +78 -0
- package/dist/turbo_adapter.js.map +1 -0
- package/dist/y_protocol_session.d.ts +6 -6
- package/dist/y_protocol_session.d.ts.map +1 -1
- package/dist/y_protocol_session.js +96 -81
- package/dist/y_protocol_session.js.map +1 -1
- package/package.json +29 -6
package/README.md
CHANGED
|
@@ -1,26 +1,85 @@
|
|
|
1
1
|
# yrby-client
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- **`YProtocolSession`**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
3
|
+
The JavaScript client for yrby's Yjs protocol. Most Rails apps import
|
|
4
|
+
`yrby-client/element` and bind an editor when it emits `yrby:synced`.
|
|
5
|
+
Applications that manage their own editor lifetime can use
|
|
6
|
+
`DocumentSessionStore` directly.
|
|
7
|
+
|
|
8
|
+
The client has five layers:
|
|
9
|
+
|
|
10
|
+
- **`<yrby-document>`** attaches an editor while its page is live, but not on a
|
|
11
|
+
Turbo or Turbolinks preview.
|
|
12
|
+
- **`DocumentSessionStore`** keeps a document and its pending work after an
|
|
13
|
+
editor detaches. Callers hold a session through a lease.
|
|
14
|
+
- **`ActionCableProvider`** manages one ActionCable or AnyCable subscription and
|
|
15
|
+
translates its JSON envelopes to protocol frames.
|
|
16
|
+
- **`YProtocolSession`** handles the Yjs handshake, frames, and awareness for
|
|
17
|
+
any transport.
|
|
18
|
+
- **`ReliableSync`** keeps local updates until the server acknowledges them and
|
|
19
|
+
replays the unacknowledged tail after a reconnect.
|
|
20
|
+
|
|
21
|
+
`<yrby-document>` builds on each layer below it, in that order. The provider,
|
|
22
|
+
protocol session, and zero-dependency delivery core also work on their own.
|
|
23
|
+
|
|
24
|
+
### How the classes relate
|
|
25
|
+
|
|
26
|
+
```mermaid
|
|
27
|
+
flowchart TD
|
|
28
|
+
Adapter["TurboAdapter<br/>one per page"]
|
|
29
|
+
Element["<yrby-document><br/>YrbyDocumentElement"]
|
|
30
|
+
Consumer["CableConsumer<br/>ActionCable or AnyCable, shared by the page"]
|
|
31
|
+
Store["DocumentSessionStore<br/>one per consumer"]
|
|
32
|
+
Session["DocumentSession<br/>one per document"]
|
|
33
|
+
Lease["DocumentLease<br/>one per holder"]
|
|
34
|
+
Doc["Y.Doc"]
|
|
35
|
+
Provider["ActionCableProvider"]
|
|
36
|
+
Awareness["Awareness<br/>presence"]
|
|
37
|
+
Subscription["Cable subscription<br/>one per connect()"]
|
|
38
|
+
Protocol["YProtocolSession"]
|
|
39
|
+
Delivery["ReliableSync"]
|
|
40
|
+
|
|
41
|
+
Adapter -->|"activate / deactivate"| Element
|
|
42
|
+
Element -->|"acquire()"| Store
|
|
43
|
+
Store -->|"finds or creates"| Session
|
|
44
|
+
Element -->|"holds while bound"| Lease
|
|
45
|
+
Lease -->|"holds"| Session
|
|
46
|
+
Session -->|"owns"| Doc
|
|
47
|
+
Session -->|"owns for its whole life"| Provider
|
|
48
|
+
Provider -->|"owns"| Awareness
|
|
49
|
+
Provider -->|"owns"| Protocol
|
|
50
|
+
Provider -->|"subscribes through"| Consumer
|
|
51
|
+
Consumer -->|"returns"| Subscription
|
|
52
|
+
Protocol -->|"owns"| Delivery
|
|
53
|
+
Protocol -.->|"listens for edits"| Doc
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Read each arrow as a sentence, such as "DocumentSession owns
|
|
57
|
+
ActionCableProvider for its whole life." Signals flow back up in the other
|
|
58
|
+
direction. The provider reports status and rejections to its session, and a
|
|
59
|
+
session that blocks or is discarded aborts its leases, which releases each
|
|
60
|
+
element's editor. Elements that name the same document share one session, and
|
|
61
|
+
that session keeps their pending edits after the last element is gone.
|
|
62
|
+
|
|
63
|
+
### How the element and session behave
|
|
64
|
+
|
|
65
|
+
Editor cleanup, status listeners, and `yrby:*` event listeners are your code,
|
|
66
|
+
and they can call back into the element or session while it's partway through
|
|
67
|
+
something. Both classes follow three rules to stay consistent:
|
|
68
|
+
|
|
69
|
+
1. Calls you make (`acquire`, `retry`, `discard`, and the element's
|
|
70
|
+
deactivate, retarget, and destroy) take effect right away. Turbo copies the
|
|
71
|
+
page as soon as `before-cache` returns, and a retargeted editor has to stop
|
|
72
|
+
writing to the old document immediately.
|
|
73
|
+
2. Callbacks and async results (provider status and errors, lease aborts, the
|
|
74
|
+
consumer loading, the first sync) record what happened and schedule a
|
|
75
|
+
settle. A settle runs as a microtask after the current call stack, compares
|
|
76
|
+
what should exist with what does, and fixes the difference. Each object has
|
|
77
|
+
at most one settle pending, and an extra one does no harm.
|
|
78
|
+
3. They update their own state before releasing any lease, because releasing a
|
|
79
|
+
lease runs your editor cleanup.
|
|
80
|
+
|
|
81
|
+
The session's allowed phase transitions live in the `PHASES` table in
|
|
82
|
+
`src/document_session.ts`.
|
|
24
83
|
|
|
25
84
|
## Install
|
|
26
85
|
|
|
@@ -28,15 +87,140 @@ Three layers, use whichever you need:
|
|
|
28
87
|
npm install yrby-client
|
|
29
88
|
```
|
|
30
89
|
|
|
31
|
-
`ActionCableProvider`
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
90
|
+
`ActionCableProvider` needs `yjs`, `y-protocols`, and an ActionCable/AnyCable
|
|
91
|
+
consumer. `YProtocolSession` needs `yjs` and `y-protocols`, but takes raw frames
|
|
92
|
+
from any transport. `ReliableSync` has **no dependencies**. If that's all you
|
|
93
|
+
want, import it from `yrby-client/reliable`.
|
|
35
94
|
|
|
36
95
|
Written in **TypeScript** and ships bundled type declarations, so TS projects get
|
|
37
96
|
full types (typed options, methods, and errors) with no `@types` package — and
|
|
38
97
|
plain-JS projects use the same compiled ESM with nothing extra to install.
|
|
39
98
|
|
|
99
|
+
## `<yrby-document>` (the easiest path)
|
|
100
|
+
|
|
101
|
+
yrby-rails' `collaborative_document_tag` renders this element with a signed
|
|
102
|
+
grant. Like `<turbo-cable-stream-source>` with `turbo_stream_from`, it connects
|
|
103
|
+
automatically once you import the element:
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
import "yrby-client/element";
|
|
107
|
+
|
|
108
|
+
document.addEventListener("yrby:synced", ({ target, detail }) => {
|
|
109
|
+
const editor = bindYourEditor(target, detail.doc, detail.provider);
|
|
110
|
+
detail.signal.addEventListener("abort", () => editor.destroy(), { once: true });
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`bindYourEditor` stands for your application's editor binding. Its cleanup
|
|
115
|
+
must detach Yjs listeners and disable or remove editor controls. It must not
|
|
116
|
+
destroy the document or provider, which belong to the session, or disconnect
|
|
117
|
+
the shared consumer. The abort signal fires before yrby checks whether a final
|
|
118
|
+
update still needs delivery, and you should handle it even if the editor has
|
|
119
|
+
already left the DOM.
|
|
120
|
+
|
|
121
|
+
A document session holds the `Y.Doc`, the provider, and any unacknowledged
|
|
122
|
+
edits, and the element attaches an editor to that session. Removing the last
|
|
123
|
+
editor clears presence and, if nothing is pending, releases the session. A
|
|
124
|
+
session with pending edits keeps delivering them under its original grant
|
|
125
|
+
until the server acknowledges them. A rejection stops the retries and keeps
|
|
126
|
+
the work in memory for recovery, but it does not count as an acknowledgment.
|
|
127
|
+
|
|
128
|
+
The element listens for both Turbo and Turbolinks 5 lifecycle events. A cached
|
|
129
|
+
preview is inert and creates no document or provider, and the cached markup
|
|
130
|
+
holds no CRDT snapshot. When you restore a page from history, the element
|
|
131
|
+
reattaches to a pending session if there is one, or loads the saved content
|
|
132
|
+
from Rails. A new grant gets its own session, and the previous session's edits
|
|
133
|
+
reach it through normal server sync. This all works within one tab and is not
|
|
134
|
+
offline storage, so closing or reloading the tab loses unacknowledged edits.
|
|
135
|
+
|
|
136
|
+
Moving the element within the same turn keeps its editor binding and document.
|
|
137
|
+
Remounting it after a delay reloads saved content, and the old `Y.Doc` and undo
|
|
138
|
+
stack are gone. Changing the grant, name, or channel aborts the old binding
|
|
139
|
+
immediately and acquires a session for the new combination. The old session
|
|
140
|
+
keeps any pending work under its original authorization.
|
|
141
|
+
|
|
142
|
+
The element exposes its current `session`, `doc`, and `provider`. These are
|
|
143
|
+
unavailable before the element acquires a session and while it is retargeting,
|
|
144
|
+
and reading them never creates a document. `whenSynced` is always a promise,
|
|
145
|
+
even before the consumer is initialized, and it resolves after the current
|
|
146
|
+
session's first catch-up. If the lease is abandoned, that promise never
|
|
147
|
+
resolves. The bubbling `yrby:synced` event fires once per lease and includes
|
|
148
|
+
`detail.signal` for cleanup. Being synced doesn't mean the connection is online
|
|
149
|
+
or that every edit has been acknowledged. Check `provider.synced` and
|
|
150
|
+
`session.hasPending` for those.
|
|
151
|
+
|
|
152
|
+
Import failures and subscription rejections emit `yrby:error` with
|
|
153
|
+
`detail.error`, and a rejection also includes `detail.session` for you to
|
|
154
|
+
retry. The element is inert while its session is blocked. After retrying the
|
|
155
|
+
session, call `element.activate()` or remount the element to attach again.
|
|
156
|
+
`element.destroy()` releases the lease and stops automatic binding until the
|
|
157
|
+
element is reinserted, without discarding pending edits.
|
|
158
|
+
|
|
159
|
+
The `refresh` attribute names a same-origin URL that returns a new grant for
|
|
160
|
+
this document as `{ "grant": "..." }`. When the server rejects the
|
|
161
|
+
subscription, typically because the grant expired, the session fetches that
|
|
162
|
+
URL once and resubscribes with the new grant, keeping its document and
|
|
163
|
+
pending edits. See [Grant lifetime and
|
|
164
|
+
refresh](https://github.com/jpcamara/yrby#grant-lifetime-and-refresh) in the
|
|
165
|
+
main README. The attribute is read when the session is acquired, so changing
|
|
166
|
+
it later doesn't rebind the editor.
|
|
167
|
+
|
|
168
|
+
The default element needs `@rails/actioncable`, `yjs`, and `y-protocols`. All
|
|
169
|
+
default elements share one consumer and one import of it while that import is
|
|
170
|
+
loading. For AnyCable, assign an ActionCable-compatible consumer before adding
|
|
171
|
+
any elements:
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
import { YrbyDocumentElement } from "yrby-client/element";
|
|
175
|
+
import { createConsumer } from "@anycable/web";
|
|
176
|
+
|
|
177
|
+
YrbyDocumentElement.consumer = createConsumer();
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Document sessions
|
|
181
|
+
|
|
182
|
+
Each consumer has its own store. Two acquisitions with the same
|
|
183
|
+
`{ channel, grant, name }` share one document and one queue.
|
|
184
|
+
|
|
185
|
+
A headless workflow can hold a lease for as long as it runs:
|
|
186
|
+
|
|
187
|
+
```js
|
|
188
|
+
import { DocumentSessionStore } from "yrby-client";
|
|
189
|
+
|
|
190
|
+
const store = DocumentSessionStore.for(consumer);
|
|
191
|
+
const lease = store.acquire({ grant, name: "body" });
|
|
192
|
+
const { session } = lease;
|
|
193
|
+
await session.whenSynced;
|
|
194
|
+
// Work with session.doc, and hold the lease until the workflow finishes.
|
|
195
|
+
lease.release(); // safe to call more than once, and pending work keeps sending
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Call `lease.setPresence(state)` when an editor gains focus and
|
|
199
|
+
`lease.setPresence(null)` when it blurs. All views of one session share one
|
|
200
|
+
presence, so the last call wins. An editor binding gets its lease from
|
|
201
|
+
`detail.lease` on `yrby:synced`.
|
|
202
|
+
|
|
203
|
+
`session.state` is `open`, `blocked`, or `closed`, independent of the
|
|
204
|
+
provider's transport status. The store emits `change` with the session in
|
|
205
|
+
`event.detail`, which you can use to report delivery failures after the page
|
|
206
|
+
that made the edits is gone.
|
|
207
|
+
|
|
208
|
+
```js
|
|
209
|
+
store.addEventListener("change", ({ detail: session }) => {
|
|
210
|
+
if (session.state === "blocked") reportDeliveryFailure(session.error, session);
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Sessions hold their queues while the consumer is down and deliver them when it
|
|
215
|
+
reconnects. A new consumer gets a new store and does not pick up another
|
|
216
|
+
consumer's queued work.
|
|
217
|
+
|
|
218
|
+
A blocked session holds its document and pending edits in memory. `retry()`
|
|
219
|
+
reconnects with the session's current grant, which is the original one or the
|
|
220
|
+
last one its `refresh` URL returned. `discard()` drops the work. A grant that arrives any other way,
|
|
221
|
+
such as a new element attribute, starts a separate session and leaves the
|
|
222
|
+
blocked one blocked.
|
|
223
|
+
|
|
40
224
|
## ActionCableProvider (the easy path)
|
|
41
225
|
|
|
42
226
|
```js
|
|
@@ -51,12 +235,14 @@ const provider = new ActionCableProvider(doc, consumer, "DocumentChannel", { id:
|
|
|
51
235
|
provider.connect(); // does not auto-connect — wire your editor binding first
|
|
52
236
|
|
|
53
237
|
// Observe the connection (one signal, no separate "sync" event):
|
|
54
|
-
provider.onStatusChange(({ status }) => render(status)); // returns an unsubscribe fn
|
|
238
|
+
provider.onStatusChange(({ status, pending }) => render(status, pending)); // returns an unsubscribe fn
|
|
55
239
|
// "connecting" -> subscription created, transport not up yet
|
|
56
240
|
// "connected" -> transport up, exchanging sync steps (show "syncing")
|
|
57
241
|
// "synced" -> caught up with the server
|
|
58
242
|
// "disconnected"-> torn down via disconnect()/destroy()
|
|
59
243
|
// (a dropped transport ActionCable will retry shows as "connecting")
|
|
244
|
+
// pending -> true while local edits await acknowledgment
|
|
245
|
+
// (listeners fire when status or pending changes)
|
|
60
246
|
|
|
61
247
|
// provider.status -> the current status (same union as above)
|
|
62
248
|
// provider.awareness -> the provider's Awareness instance (always a fresh one)
|
|
@@ -79,6 +265,10 @@ await provider.whenSynced; // resolves immediately if already synced
|
|
|
79
265
|
It resolves once, on the first catch-up, and stays resolved across later
|
|
80
266
|
reconnects. Use `onStatusChange` to track the live connection.
|
|
81
267
|
|
|
268
|
+
After `disconnect()` or `destroy()`, the provider ignores callbacks from the
|
|
269
|
+
old subscription. If a consumer invokes callbacks while it is still creating
|
|
270
|
+
the subscription, the provider holds them until creation returns.
|
|
271
|
+
|
|
82
272
|
On `disconnect()` / `destroy()` — and on browser `pagehide` — the provider
|
|
83
273
|
broadcasts a presence removal so peers drop your cursor immediately instead of
|
|
84
274
|
waiting for the awareness timeout. `destroy()` is synchronous (the unsubscribe is
|
|
@@ -87,8 +277,8 @@ deferred one microtask so that removal flushes first) and tears down the
|
|
|
87
277
|
your own `Awareness`, drop down to `YProtocolSession`, which leaves it for you to
|
|
88
278
|
own.)
|
|
89
279
|
|
|
90
|
-
On the server, include `Y::ActionCable
|
|
91
|
-
`DocumentChannel` (the [`yrby-
|
|
280
|
+
On the server, include `Y::ActionCable` in a channel named
|
|
281
|
+
`DocumentChannel` (the [`yrby-rails`](https://rubygems.org/gems/yrby-rails)
|
|
92
282
|
gem). The server subscribes document broadcasts and AnyCable awareness whispers
|
|
93
283
|
on separate streams, so the document stream is not whisper-enabled. Need a
|
|
94
284
|
different transport or framing? Drop down to `YProtocolSession` and supply your
|
|
@@ -124,10 +314,10 @@ const session = new YProtocolSession(doc, {
|
|
|
124
314
|
});
|
|
125
315
|
|
|
126
316
|
// wire your transport's callbacks:
|
|
127
|
-
subscription.connected = () => session.
|
|
128
|
-
subscription.disconnected = () => session.
|
|
317
|
+
subscription.connected = () => session.resume(); // handshake + replay
|
|
318
|
+
subscription.disconnected = () => session.pause(); // keep the queue, clear presence
|
|
129
319
|
subscription.received = (msg) => {
|
|
130
|
-
if (msg.ack !== undefined) return session.
|
|
320
|
+
if (msg.ack !== undefined) return session.acknowledge(msg.ack); // reliable ack envelope
|
|
131
321
|
const reply = session.receive(fromBase64(msg.update)); // decode + apply
|
|
132
322
|
if (reply) subscription.send({ update: toBase64(reply) }); // e.g. answer a SyncStep1
|
|
133
323
|
};
|
|
@@ -143,6 +333,11 @@ Pass `onError(error, context)` (on either `ActionCableProvider` or
|
|
|
143
333
|
is decoded defensively, dropped, and reported here rather than thrown into your
|
|
144
334
|
transport callback. Defaults to a `console.warn`.
|
|
145
335
|
|
|
336
|
+
The provider also sends failures from status listeners, awareness events, and
|
|
337
|
+
unsubscribe to `onError`. A failing awareness listener won't interrupt presence
|
|
338
|
+
removal or destruction, and if `onError` itself throws, the provider logs the
|
|
339
|
+
error and continues.
|
|
340
|
+
|
|
146
341
|
## ReliableSync (standalone)
|
|
147
342
|
|
|
148
343
|
```js
|
|
@@ -154,19 +349,24 @@ const rs = new ReliableSync({
|
|
|
154
349
|
merge: Y.mergeUpdates,
|
|
155
350
|
});
|
|
156
351
|
|
|
157
|
-
rs.enqueue(update);
|
|
158
|
-
rs.
|
|
159
|
-
rs.
|
|
160
|
-
rs.
|
|
352
|
+
rs.enqueue(update); // a local document update
|
|
353
|
+
rs.acknowledge(id); // an { ack: id } arrived
|
|
354
|
+
rs.resume(); // (re)connected, so replay the tail and keep retransmitting
|
|
355
|
+
rs.pause(); // dropped, so keep the queue and stop retransmitting
|
|
161
356
|
```
|
|
162
357
|
|
|
163
358
|
Pending updates are retained and replayed until the server acknowledges them.
|
|
359
|
+
Before each send, ReliableSync merges the unacknowledged tail into one causally
|
|
360
|
+
complete update, so a missed frame can't leave a gap. `enqueue` copies the bytes
|
|
361
|
+
it receives, so the caller can reuse its buffer. `pending` returns a snapshot
|
|
362
|
+
with copies of each update's bytes, and you can sort or edit that snapshot
|
|
363
|
+
without affecting delivery.
|
|
164
364
|
Document delivery stays queued and ack-tracked for the lifetime of the session.
|
|
165
365
|
|
|
166
366
|
## How it fits
|
|
167
367
|
|
|
168
368
|
The server counterpart — ack *generation*, gap detection, record-before-distribute
|
|
169
|
-
— is the `yrby-
|
|
369
|
+
— is the `yrby-rails` gem's `Y::ActionCable`. This package
|
|
170
370
|
is the client half of the same protocol.
|
|
171
371
|
|
|
172
372
|
## License
|
|
@@ -9,9 +9,11 @@ import type { Doc } from "yjs";
|
|
|
9
9
|
* will retry shows as "connecting", not "disconnected".
|
|
10
10
|
*/
|
|
11
11
|
export type ProviderStatus = "connecting" | "connected" | "synced" | "disconnected";
|
|
12
|
-
/** Payload passed to onStatusChange listeners. */
|
|
12
|
+
/** Payload passed to onStatusChange listeners, which run when either field changes. */
|
|
13
13
|
export interface StatusEvent {
|
|
14
14
|
status: ProviderStatus;
|
|
15
|
+
/** True while local edits await the server's acknowledgment. */
|
|
16
|
+
pending: boolean;
|
|
15
17
|
}
|
|
16
18
|
/** The minimal slice of an ActionCable/AnyCable subscription this provider uses. */
|
|
17
19
|
export interface CableSubscription {
|
|
@@ -45,9 +47,6 @@ export declare class ActionCableProvider {
|
|
|
45
47
|
readonly channelParams: object;
|
|
46
48
|
readonly awareness: Awareness;
|
|
47
49
|
readonly session: YProtocolSession;
|
|
48
|
-
constructor(doc: Doc, consumer: CableConsumer, channelName: string, channelParams?: object, opts?: ActionCableProviderOptions);
|
|
49
|
-
/** True once the document has caught up with the server (received a SyncStep2). */
|
|
50
|
-
get synced(): boolean;
|
|
51
50
|
/**
|
|
52
51
|
* Resolves once the document has first caught up with the server. Most
|
|
53
52
|
* editor bindings seed an empty document when they mount, so binding
|
|
@@ -58,14 +57,15 @@ export declare class ActionCableProvider {
|
|
|
58
57
|
* await provider.whenSynced;
|
|
59
58
|
* // now hand the doc to the editor binding
|
|
60
59
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* connection. If the provider is destroyed before the first sync, the
|
|
66
|
-
* promise never settles.
|
|
60
|
+
* It resolves on the first catch-up and remains resolved across later
|
|
61
|
+
* reconnects, even while `synced` is false during a re-handshake. Use
|
|
62
|
+
* `onStatusChange` to track the live connection. If the provider is
|
|
63
|
+
* destroyed before the first sync, it never resolves.
|
|
67
64
|
*/
|
|
68
|
-
|
|
65
|
+
readonly whenSynced: Promise<void>;
|
|
66
|
+
constructor(doc: Doc, consumer: CableConsumer, channelName: string, channelParams?: object, opts?: ActionCableProviderOptions);
|
|
67
|
+
/** True once the document has caught up with the server (received a SyncStep2). */
|
|
68
|
+
get synced(): boolean;
|
|
69
69
|
/** True while there are unacknowledged local document updates in flight. */
|
|
70
70
|
get hasPending(): boolean;
|
|
71
71
|
/**
|
|
@@ -87,6 +87,13 @@ export declare class ActionCableProvider {
|
|
|
87
87
|
onStatusChange(listener: (event: StatusEvent) => void): () => void;
|
|
88
88
|
connect(): void;
|
|
89
89
|
disconnect(): void;
|
|
90
|
+
/**
|
|
91
|
+
* Resubscribes with updated channel params, such as a renewed grant. This
|
|
92
|
+
* replaces only the cable subscription and keeps the doc, the delivery
|
|
93
|
+
* queue, awareness, and this provider's ack route. Does nothing after
|
|
94
|
+
* destroy().
|
|
95
|
+
*/
|
|
96
|
+
renew(params: object): void;
|
|
90
97
|
destroy(): void;
|
|
91
98
|
}
|
|
92
99
|
//# sourceMappingURL=actioncable_provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actioncable_provider.d.ts","sourceRoot":"","sources":["../src/actioncable_provider.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,gBAAgB,EAAe,KAAK,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAEtG,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,cAAc,CAAC;AAEpF,
|
|
1
|
+
{"version":3,"file":"actioncable_provider.d.ts","sourceRoot":"","sources":["../src/actioncable_provider.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,gBAAgB,EAAe,KAAK,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAEtG,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,cAAc,CAAC;AAEpF,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,cAAc,CAAC;IACvB,gEAAgE;IAChE,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,oFAAoF;AACpF,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IAC7B,wEAAwE;IACxE,OAAO,CAAC,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACjC,sEAAsE;IACtE,WAAW,CAAC,IAAI,IAAI,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE;QACb,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC;KACrE,CAAC;CACH;AAED,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAAC,uBAAuB,EAAE,gBAAgB,GAAG,SAAS,CAAC,CAAC;AAoBrG,qBAAa,mBAAmB;;IAC9B,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IAUnC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,UAAU,gBAAsE;gBAGvF,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,aAAa,EACvB,WAAW,EAAE,MAAM,EACnB,aAAa,GAAE,MAAW,EAC1B,IAAI,GAAE,0BAA+B;IAuBvC,mFAAmF;IACnF,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,4EAA4E;IAC5E,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;;;;;;;;;;OAWG;IACH,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAI3C,6DAA6D;IAC7D,IAAI,MAAM,IAAI,cAAc,CAE3B;IAED,oEAAoE;IACpE,cAAc,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI;IAKlE,OAAO,IAAI,IAAI;IAoCf,UAAU,IAAI,IAAI;IAElB;;;;;OAKG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO3B,OAAO,IAAI,IAAI;CA6LhB"}
|