braid-text 0.2.44 → 0.2.46
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/index.js +55 -27
- package/package.json +1 -1
- package/test/test.html +151 -0
package/index.js
CHANGED
|
@@ -291,11 +291,6 @@ braid_text.get = async (key, options) => {
|
|
|
291
291
|
options.my_last_sent_version = x.version
|
|
292
292
|
resource.simpleton_clients.add(options)
|
|
293
293
|
} else {
|
|
294
|
-
if (resource.need_defrag) {
|
|
295
|
-
if (braid_text.verbose) console.log(`doing defrag..`)
|
|
296
|
-
resource.need_defrag = false
|
|
297
|
-
resource.doc = defrag_dt(resource.doc)
|
|
298
|
-
}
|
|
299
294
|
|
|
300
295
|
if (options.accept_encoding?.match(/updates\s*\((.*)\)/)?.[1].split(',').map(x=>x.trim()).includes('dt')) {
|
|
301
296
|
var bytes = resource.doc.toBytes()
|
|
@@ -431,7 +426,7 @@ braid_text.put = async (key, options) => {
|
|
|
431
426
|
// validate version: make sure we haven't seen it already
|
|
432
427
|
if (resource.actor_seqs[v[0]]?.has(v[1])) {
|
|
433
428
|
|
|
434
|
-
if (!options.validate_already_seen_versions) return
|
|
429
|
+
if (!options.validate_already_seen_versions) return { change_count }
|
|
435
430
|
|
|
436
431
|
// if we have seen it already, make sure it's the same as before
|
|
437
432
|
let updates = dt_get_patches(resource.doc, og_parents)
|
|
@@ -488,7 +483,7 @@ braid_text.put = async (key, options) => {
|
|
|
488
483
|
}
|
|
489
484
|
|
|
490
485
|
// we already have this version, so nothing left to do
|
|
491
|
-
return
|
|
486
|
+
return { change_count: change_count }
|
|
492
487
|
}
|
|
493
488
|
if (!resource.actor_seqs[v[0]]) resource.actor_seqs[v[0]] = new RangeSet()
|
|
494
489
|
resource.actor_seqs[v[0]].add_range(v[1] + 1 - change_count, v[1])
|
|
@@ -526,8 +521,6 @@ braid_text.put = async (key, options) => {
|
|
|
526
521
|
for (let b of bytes) resource.doc.mergeBytes(b)
|
|
527
522
|
resource.val = resource.doc.get()
|
|
528
523
|
|
|
529
|
-
resource.need_defrag = true
|
|
530
|
-
|
|
531
524
|
var post_commit_updates = []
|
|
532
525
|
|
|
533
526
|
if (options.merge_type != "dt") {
|
|
@@ -674,17 +667,12 @@ async function get_resource(key) {
|
|
|
674
667
|
|
|
675
668
|
resource.db_delta = change
|
|
676
669
|
|
|
677
|
-
resource.doc = defrag_dt(resource.doc)
|
|
678
|
-
resource.need_defrag = false
|
|
679
|
-
|
|
680
670
|
resource.actor_seqs = {}
|
|
681
671
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
resource.actor_seqs[v[0]].add_range(v[1], v[1])
|
|
687
|
-
}
|
|
672
|
+
dt_get_actor_seq_runs([...resource.doc.toBytes()], (actor, base, len) => {
|
|
673
|
+
if (!resource.actor_seqs[actor]) resource.actor_seqs[actor] = new RangeSet()
|
|
674
|
+
resource.actor_seqs[actor].add_range(base, base + len - 1)
|
|
675
|
+
})
|
|
688
676
|
|
|
689
677
|
resource.val = resource.doc.get()
|
|
690
678
|
|
|
@@ -1069,16 +1057,19 @@ function dt_get(doc, version, agent = null, anti_version = null) {
|
|
|
1069
1057
|
}
|
|
1070
1058
|
|
|
1071
1059
|
function dt_get_patches(doc, version = null) {
|
|
1060
|
+
if (version && v_eq(version,
|
|
1061
|
+
doc.getRemoteVersion().map((x) => x.join("-")).sort())) {
|
|
1062
|
+
// they want everything past the end, which is nothing
|
|
1063
|
+
return []
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1072
1066
|
let bytes = doc.toBytes()
|
|
1073
1067
|
doc = Doc.fromBytes(bytes)
|
|
1074
1068
|
|
|
1075
1069
|
let [_agents, versions, parentss] = dt_parse([...bytes])
|
|
1076
1070
|
|
|
1077
1071
|
let op_runs = []
|
|
1078
|
-
if (version
|
|
1079
|
-
doc.getRemoteVersion().map((x) => x.join("-")).sort())) {
|
|
1080
|
-
// they want everything past the end, which is nothing
|
|
1081
|
-
} else if (version?.length) {
|
|
1072
|
+
if (version?.length) {
|
|
1082
1073
|
let frontier = {}
|
|
1083
1074
|
version.forEach((x) => frontier[x] = true)
|
|
1084
1075
|
let local_version = []
|
|
@@ -1223,6 +1214,48 @@ function dt_parse(byte_array) {
|
|
|
1223
1214
|
return [agents, versions, parentss]
|
|
1224
1215
|
}
|
|
1225
1216
|
|
|
1217
|
+
function dt_get_actor_seq_runs(byte_array, cb) {
|
|
1218
|
+
if (new TextDecoder().decode(new Uint8Array(byte_array.splice(0, 8))) !== "DMNDTYPS") throw new Error("dt parse error, expected DMNDTYPS")
|
|
1219
|
+
|
|
1220
|
+
if (byte_array.shift() != 0) throw new Error("dt parse error, expected version 0")
|
|
1221
|
+
|
|
1222
|
+
let agents = []
|
|
1223
|
+
|
|
1224
|
+
while (byte_array.length) {
|
|
1225
|
+
let id = byte_array.shift()
|
|
1226
|
+
let len = dt_read_varint(byte_array)
|
|
1227
|
+
if (id == 1) {
|
|
1228
|
+
} else if (id == 3) {
|
|
1229
|
+
let goal = byte_array.length - len
|
|
1230
|
+
while (byte_array.length > goal) {
|
|
1231
|
+
agents.push(dt_read_string(byte_array))
|
|
1232
|
+
}
|
|
1233
|
+
} else if (id == 20) {
|
|
1234
|
+
} else if (id == 21) {
|
|
1235
|
+
let seqs = {}
|
|
1236
|
+
let goal = byte_array.length - len
|
|
1237
|
+
while (byte_array.length > goal) {
|
|
1238
|
+
let part0 = dt_read_varint(byte_array)
|
|
1239
|
+
let has_jump = part0 & 1
|
|
1240
|
+
let agent_i = (part0 >> 1) - 1
|
|
1241
|
+
let run_length = dt_read_varint(byte_array)
|
|
1242
|
+
let jump = 0
|
|
1243
|
+
if (has_jump) {
|
|
1244
|
+
let part2 = dt_read_varint(byte_array)
|
|
1245
|
+
jump = part2 >> 1
|
|
1246
|
+
if (part2 & 1) jump *= -1
|
|
1247
|
+
}
|
|
1248
|
+
let base = (seqs[agent_i] || 0) + jump
|
|
1249
|
+
|
|
1250
|
+
cb(agents[agent_i], base, run_length)
|
|
1251
|
+
seqs[agent_i] = base + run_length
|
|
1252
|
+
}
|
|
1253
|
+
} else {
|
|
1254
|
+
byte_array.splice(0, len)
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1226
1259
|
function dt_get_local_version(bytes, version) {
|
|
1227
1260
|
var looking_for = new Map()
|
|
1228
1261
|
for (var event of version) {
|
|
@@ -1492,11 +1525,6 @@ function dt_create_bytes(version, parents, pos, del, ins) {
|
|
|
1492
1525
|
return bytes
|
|
1493
1526
|
}
|
|
1494
1527
|
|
|
1495
|
-
function defrag_dt(doc) {
|
|
1496
|
-
let bytes = doc.toBytes()
|
|
1497
|
-
doc.free()
|
|
1498
|
-
return Doc.fromBytes(bytes, 'server')
|
|
1499
|
-
}
|
|
1500
1528
|
|
|
1501
1529
|
function OpLog_remote_to_local(doc, frontier) {
|
|
1502
1530
|
let map = Object.fromEntries(frontier.map((x) => [x, true]))
|
package/package.json
CHANGED
package/test/test.html
CHANGED
|
@@ -96,6 +96,157 @@ async function runTest(testName, testFunction, expectedResult) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
runTest(
|
|
100
|
+
"test PUTing a version that the server already has",
|
|
101
|
+
async () => {
|
|
102
|
+
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
103
|
+
|
|
104
|
+
var r1 = await braid_fetch(`/${key}`, {
|
|
105
|
+
method: 'PUT',
|
|
106
|
+
version: ['hi-0'],
|
|
107
|
+
parents: [],
|
|
108
|
+
body: 'x'
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
var r2 = await braid_fetch(`/${key}`, {
|
|
112
|
+
method: 'PUT',
|
|
113
|
+
version: ['hi-0'],
|
|
114
|
+
parents: [],
|
|
115
|
+
body: 'x'
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
return r1.status + " " + r2.status
|
|
119
|
+
},
|
|
120
|
+
'200 200'
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
runTest(
|
|
124
|
+
"test validate_already_seen_versions with same version",
|
|
125
|
+
async () => {
|
|
126
|
+
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
127
|
+
|
|
128
|
+
var r1 = await braid_fetch(`/eval`, {
|
|
129
|
+
method: 'PUT',
|
|
130
|
+
body: `void (async () => {
|
|
131
|
+
var resource = await braid_text.get_resource('/${key}')
|
|
132
|
+
|
|
133
|
+
var {change_count} = await braid_text.put(resource, { peer: "abc", version: ["hi-2"], parents: [], patches: [{unit: "text", range: "[0:0]", content: "XYZ"}], merge_type: "dt" })
|
|
134
|
+
|
|
135
|
+
res.end('' + change_count)
|
|
136
|
+
})()`
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
var r2 = await braid_fetch(`/eval`, {
|
|
140
|
+
method: 'PUT',
|
|
141
|
+
body: `void (async () => {
|
|
142
|
+
var resource = await braid_text.get_resource('/${key}')
|
|
143
|
+
|
|
144
|
+
var {change_count} = await braid_text.put(resource, { peer: "abc", version: ["hi-2"], parents: [], patches: [{unit: "text", range: "[0:0]", content: "XYZ"}], merge_type: "dt", validate_already_seen_versions: true })
|
|
145
|
+
|
|
146
|
+
res.end('' + change_count)
|
|
147
|
+
})()`
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
return (await r1.text()) + " " + (await r2.text())
|
|
151
|
+
},
|
|
152
|
+
'3 3'
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
runTest(
|
|
156
|
+
"test validate_already_seen_versions with modified version",
|
|
157
|
+
async () => {
|
|
158
|
+
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
159
|
+
|
|
160
|
+
var r1 = await braid_fetch(`/eval`, {
|
|
161
|
+
method: 'PUT',
|
|
162
|
+
body: `void (async () => {
|
|
163
|
+
var resource = await braid_text.get_resource('/${key}')
|
|
164
|
+
|
|
165
|
+
var {change_count} = await braid_text.put(resource, { peer: "abc", version: ["hi-2"], parents: [], patches: [{unit: "text", range: "[0:0]", content: "XYZ"}], merge_type: "dt" })
|
|
166
|
+
|
|
167
|
+
res.end('' + change_count)
|
|
168
|
+
})()`
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
var r2 = await braid_fetch(`/eval`, {
|
|
172
|
+
method: 'PUT',
|
|
173
|
+
body: `void (async () => {
|
|
174
|
+
var resource = await braid_text.get_resource('/${key}')
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
var {change_count} = await braid_text.put(resource, { peer: "abc", version: ["hi-2"], parents: [], patches: [{unit: "text", range: "[0:0]", content: "ABC"}], merge_type: "dt", validate_already_seen_versions: true })
|
|
178
|
+
|
|
179
|
+
res.end('' + change_count)
|
|
180
|
+
} catch (e) {
|
|
181
|
+
res.end(e.message)
|
|
182
|
+
}
|
|
183
|
+
})()`
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
return await r2.text()
|
|
187
|
+
},
|
|
188
|
+
'invalid update: different from previous update with same version'
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
runTest(
|
|
192
|
+
"test loading a previously saved resource",
|
|
193
|
+
async () => {
|
|
194
|
+
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
195
|
+
|
|
196
|
+
var f1 = await braid_fetch(`/${key}`, {
|
|
197
|
+
method: 'PUT',
|
|
198
|
+
version: ['hi-2'],
|
|
199
|
+
parents: [],
|
|
200
|
+
body: 'abc'
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
var f1 = await braid_fetch(`/eval`, {
|
|
204
|
+
method: 'PUT',
|
|
205
|
+
body: `
|
|
206
|
+
delete braid_text.cache['/${key}']
|
|
207
|
+
res.end()
|
|
208
|
+
`
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
var r = await braid_fetch(`/${key}`)
|
|
212
|
+
return await r.text()
|
|
213
|
+
},
|
|
214
|
+
'abc'
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
runTest(
|
|
218
|
+
"test non-contigous ids",
|
|
219
|
+
async () => {
|
|
220
|
+
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
221
|
+
|
|
222
|
+
var r = await braid_fetch(`/${key}`, {
|
|
223
|
+
method: 'PUT',
|
|
224
|
+
version: ['hi-10'],
|
|
225
|
+
parents: [],
|
|
226
|
+
body: 'abc'
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
var r = await braid_fetch(`/${key}`, {
|
|
230
|
+
method: 'PUT',
|
|
231
|
+
version: ['hi-20'],
|
|
232
|
+
parents: ['hi-10'],
|
|
233
|
+
body: 'ABC'
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
var f1 = await braid_fetch(`/eval`, {
|
|
237
|
+
method: 'PUT',
|
|
238
|
+
body: `
|
|
239
|
+
delete braid_text.cache['/${key}']
|
|
240
|
+
res.end()
|
|
241
|
+
`
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
var r = await braid_fetch(`/${key}`)
|
|
245
|
+
return await r.text()
|
|
246
|
+
},
|
|
247
|
+
'ABC'
|
|
248
|
+
)
|
|
249
|
+
|
|
99
250
|
runTest(
|
|
100
251
|
"test when PUT cache/buffer size fails",
|
|
101
252
|
async () => {
|