yrby 0.2.1-x86_64-linux → 0.3.0-x86_64-linux
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +69 -9
- data/README.md +36 -13
- data/lib/y/3.4/yrby.so +0 -0
- data/lib/y/4.0/yrby.so +0 -0
- data/lib/y/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1c679e136a706fb345dedc22c7b3e9da97919a16c827dc67fe0a5e06ab0ed414
|
|
4
|
+
data.tar.gz: df08be53339b8a833474f3ecd8234838e1aad5dd178fd1ae419d44adaf29637c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '0903a87fcf089ec17d8aafbe0feb39fdd05b1068ae85540167434c818b2542a8b4f252115fd79f3f3d01a1ac63ee1a0a54eabd28172600538154f195e330cb04'
|
|
7
|
+
data.tar.gz: 4f349abd4f2f62f662d8c988489a9a5b9b79892e5f78ce5790a4e0638217e4262b3c69d39d390c2f4d34bcf1b5a9ee981520ad178cd7b81c820ff08e7771fdc6
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,72 @@ to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.0] - 2026-07-01
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Sync no longer serves un-integrable pending structs.** When a doc holds a
|
|
14
|
+
*pending* struct (a gappy update whose causally-prior update is missing — e.g.
|
|
15
|
+
legacy data recorded before the `update_ready?` gate existed), its integrated
|
|
16
|
+
state vector is empty but `encode_state_as_update` merges the pending bytes back
|
|
17
|
+
in. Answering a peer's `SyncStep1` with that state handed the peer content it
|
|
18
|
+
couldn't integrate, so it parked the same pending forever and the empty-SV /
|
|
19
|
+
non-empty-content mismatch drove endless resync traffic (observed as a browser
|
|
20
|
+
re-sending frames several times a second). `handle_sync_message` now answers
|
|
21
|
+
`SyncStep1` with **integrated-only** state, so a server never serves a struct it
|
|
22
|
+
can't integrate itself. Neutralizes existing poisoned server state on deploy —
|
|
23
|
+
no migration needed. The server's own pending is untouched and still heals if
|
|
24
|
+
the missing dependency later arrives (only then does the content become
|
|
25
|
+
visible in sync). Live delta relay (`Update` frames) is unchanged.
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- `Doc#pending?` — true if the doc holds un-integrable pending structs or a
|
|
30
|
+
pending delete set (content waiting on a missing causally-prior update).
|
|
31
|
+
- `Doc#compacted_state_update` — like `encode_state_as_update` (full state) but
|
|
32
|
+
**gap-free**: excludes pending structs/delete set. Use it when persisting or
|
|
33
|
+
serving state other peers will apply. Non-destructive — the doc keeps its
|
|
34
|
+
pending (so it can still heal), and `encode_state_as_update` stays lossless for
|
|
35
|
+
raw-update recovery.
|
|
36
|
+
|
|
37
|
+
## [0.2.3] - 2026-07-01
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- `Doc#update_advances?` is now exact for **delete-bearing** updates, so an
|
|
42
|
+
already-applied pure-delete retry no longer reports as advancing. Previously any
|
|
43
|
+
update carrying a delete set returned `true` (record it) because deletes don't
|
|
44
|
+
move the state vector, so the cheap state-vector probe couldn't prove a
|
|
45
|
+
duplicate. A lost-ack retry of a deletion the server had already integrated was
|
|
46
|
+
therefore re-recorded and re-broadcast every time. For delete-bearing updates we
|
|
47
|
+
now compare the full encoded document state (which includes the delete set)
|
|
48
|
+
before vs. after a trial apply on an isolated probe: a genuinely new deletion
|
|
49
|
+
changes it (`true`); an already-applied retry re-encodes identically (`false`).
|
|
50
|
+
Insert/format-only updates keep the cheaper state-vector path, so only
|
|
51
|
+
delete-bearing frames — a minority — pay for the exact comparison. The exactly-
|
|
52
|
+
once guarantee is unchanged in the safe direction: a real deletion is never
|
|
53
|
+
dropped.
|
|
54
|
+
|
|
55
|
+
This lets `yrby-actioncable` (and any caller gating `on_change` on
|
|
56
|
+
`update_advances?`) settle a duplicate pure-delete frame as `:applied` — acked,
|
|
57
|
+
but not stored or relayed — so apps no longer need an app-level
|
|
58
|
+
encode-and-compare guard around their durable writes.
|
|
59
|
+
|
|
60
|
+
## [0.2.2] - 2026-06-30
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
|
|
64
|
+
- `Doc#read_xml` now recovers text from **nested** Lexical/Lexxy blocks. Lexical
|
|
65
|
+
embeds child blocks (list items, table cells, nested lists) as `Y.XmlText`
|
|
66
|
+
embeds that `get_string` silently drops, so lists and tables previously came
|
|
67
|
+
back empty. `read_xml` now walks the embeds: text runs build a line, inline
|
|
68
|
+
children (links) join it, and nested block children flush and recurse — so a
|
|
69
|
+
document with headings, formatted text, links, bullet/numbered/check/nested
|
|
70
|
+
lists, blockquotes, code blocks and tables extracts every piece of text.
|
|
71
|
+
Lexical decorator elements (horizontal rule, image) are skipped instead of
|
|
72
|
+
emitting their `<UNDEFINED …>` serialization. ProseMirror handling is
|
|
73
|
+
unchanged.
|
|
74
|
+
|
|
9
75
|
## [0.2.1] - 2026-06-29
|
|
10
76
|
|
|
11
77
|
### Changed
|
|
@@ -15,15 +81,9 @@ to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
15
81
|
|
|
16
82
|
## [0.2.0] - 2026-06-28
|
|
17
83
|
|
|
18
|
-
First release
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
### Changed
|
|
23
|
-
- **Renamed `yrb-lite` → `yrby`.** Module `YrbLite` → top-level `Y`
|
|
24
|
-
(`Y::Doc`, `Y::Error`, `Y::VERSION`). Require path `require "yrb_lite"` →
|
|
25
|
-
`require "y"`. (The native extension crate shipped as `y_ruby` in 0.2.0; see
|
|
26
|
-
0.2.1 for its rename to `yrby`.)
|
|
84
|
+
First release. The public Ruby interface is the top-level module **`Y`**
|
|
85
|
+
(`Y::Doc`, `Y::Error`, `Y::VERSION`), loaded with `require "y"` — mirroring the
|
|
86
|
+
`y-rb` gem's `Y::Doc` interface.
|
|
27
87
|
|
|
28
88
|
### Added
|
|
29
89
|
- Native `Doc#read_text` and `Doc#read_map` readers — reconstruct plain text and
|
data/README.md
CHANGED
|
@@ -41,23 +41,25 @@ npm install yrby-client
|
|
|
41
41
|
one-include ActionCable concern.
|
|
42
42
|
- Authoritative record-before-distribute semantics: each document change can be
|
|
43
43
|
recorded durably before it goes out to anyone.
|
|
44
|
-
-
|
|
44
|
+
- Optional server-side reads: `Doc#read_text` and `Doc#read_map` reconstruct a
|
|
45
|
+
document's contents in Ruby - no Node process - for search, exports, validation,
|
|
46
|
+
or server-side rendering.
|
|
45
47
|
|
|
46
|
-
##
|
|
48
|
+
## Scope
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
`yrby` binds just the part of `y-crdt` you need to *sync and persist* collaborative
|
|
51
|
+
documents - a `Doc`, awareness, and the y-websocket protocol primitives. By default
|
|
52
|
+
the Ruby side treats a document as opaque CRDT state: it applies updates, answers
|
|
53
|
+
sync handshakes, and records deltas without reaching into the contents - the browser
|
|
54
|
+
editor owns the document's shape. When you do need to look inside, `Doc#read_text`
|
|
55
|
+
and `Doc#read_map` reconstruct it server-side, in Ruby.
|
|
54
56
|
|
|
55
|
-
##
|
|
57
|
+
## Durability and delivery
|
|
56
58
|
|
|
57
|
-
The surface
|
|
59
|
+
The surface is intentionally small, but the focus is durability, resiliency, delivery
|
|
58
60
|
guarantees, correctness, and thread safety.
|
|
59
61
|
|
|
60
|
-
Towards that goal, `yrby` adds capabilities that
|
|
62
|
+
Towards that goal, `yrby` adds capabilities that stand out even in the Yjs ecosystem:
|
|
61
63
|
|
|
62
64
|
- Built-in update acknowledgement: the `ActionCableProvider` in `yrby-client` will continue to
|
|
63
65
|
send updates until an ack is received from the server. [`yrby-actioncable`](https://rubygems.org/gems/yrby-actioncable)
|
|
@@ -140,18 +142,39 @@ doc = Y::Doc.new(12345) # specific client ID (used for CRDT identity)
|
|
|
140
142
|
|
|
141
143
|
# Encoding
|
|
142
144
|
doc.encode_state_vector # => current state vector
|
|
143
|
-
doc.encode_state_as_update # => full update
|
|
145
|
+
doc.encode_state_as_update # => full update (lossless: keeps pending)
|
|
144
146
|
doc.encode_state_as_update(sv) # => update diff against state vector
|
|
147
|
+
doc.compacted_state_update # => full update, gap-free (excludes pending)
|
|
145
148
|
|
|
146
149
|
# Applying updates
|
|
147
150
|
doc.apply_update(update_bytes) # apply raw V1 update
|
|
151
|
+
doc.pending? # => true if holding un-integrable pending structs
|
|
148
152
|
|
|
149
153
|
# Sync protocol
|
|
150
154
|
doc.sync_step1 # => SyncStep1 message (this doc's state vector)
|
|
151
155
|
doc.handle_sync_message(data) # => [msg_type, sync_type, response]; answers a
|
|
152
|
-
# peer's SyncStep1 with
|
|
156
|
+
# peer's SyncStep1 with an integrated-only
|
|
157
|
+
# SyncStep2 (never serves pending structs)
|
|
153
158
|
```
|
|
154
159
|
|
|
160
|
+
### Pending structs and gap-free state
|
|
161
|
+
|
|
162
|
+
If a doc applies an update whose causally-prior update is missing (a "gappy"
|
|
163
|
+
update), yrs parks it as a **pending** struct: the integrated state vector stays
|
|
164
|
+
empty, but the pending block is held as a recovery buffer and heals if the
|
|
165
|
+
missing dependency later arrives. `Doc#pending?` reports this.
|
|
166
|
+
|
|
167
|
+
Pending structs are *not* document state, so they must not cross the sync
|
|
168
|
+
boundary — a peer that receives one can't integrate it and gets stuck. Two
|
|
169
|
+
guarantees keep serving safe:
|
|
170
|
+
|
|
171
|
+
- `handle_sync_message` answers `SyncStep1` with **integrated-only** state, so a
|
|
172
|
+
server never serves a struct it can't integrate itself (this is automatic).
|
|
173
|
+
- `Doc#compacted_state_update` gives you the same gap-free full-state update for
|
|
174
|
+
when you persist or hand off state yourself. It's non-destructive (the doc
|
|
175
|
+
keeps its pending), while `encode_state_as_update` stays lossless so you can
|
|
176
|
+
still preserve the raw pending bytes for recovery.
|
|
177
|
+
|
|
155
178
|
### Protocol codec (module functions)
|
|
156
179
|
|
|
157
180
|
Classifying and unwrapping wire frames is stateless, so it's exposed as
|
data/lib/y/3.4/yrby.so
CHANGED
|
Binary file
|
data/lib/y/4.0/yrby.so
CHANGED
|
Binary file
|
data/lib/y/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yrby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: x86_64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- JP Camara
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|