braid-text 0.2.50 → 0.2.52
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 +19 -8
- package/package.json +1 -1
- package/simpleton-client.js +9 -1
- package/test/test.html +81 -0
package/index.js
CHANGED
|
@@ -70,8 +70,7 @@ braid_text.serve = async (req, res, options = {}) => {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
var get_current_version = () => ascii_ify(
|
|
73
|
-
resource.
|
|
74
|
-
.map(x => JSON.stringify(x)).join(", "))
|
|
73
|
+
resource.version.map(x => JSON.stringify(x)).join(", "))
|
|
75
74
|
|
|
76
75
|
if (req.method == "GET" || req.method == "HEAD") {
|
|
77
76
|
// make sure we have the necessary version and parents
|
|
@@ -133,7 +132,17 @@ braid_text.serve = async (req, res, options = {}) => {
|
|
|
133
132
|
accept_encoding:
|
|
134
133
|
req.headers['x-accept-encoding'] ??
|
|
135
134
|
req.headers['accept-encoding'],
|
|
136
|
-
subscribe: x =>
|
|
135
|
+
subscribe: x => {
|
|
136
|
+
|
|
137
|
+
// this is a sanity/rhobustness check..
|
|
138
|
+
// ..this digest is checked on the client..
|
|
139
|
+
// ..it is not strictly necessary
|
|
140
|
+
if (x.version && v_eq(x.version, resource.version)) {
|
|
141
|
+
x["Repr-Digest"] = `sha-256=:${require('crypto').createHash('sha256').update(Buffer.from(resource.val, "utf8")).digest('base64')}:`
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
res.sendVersion(x)
|
|
145
|
+
},
|
|
137
146
|
write: (x) => res.write(x)
|
|
138
147
|
}
|
|
139
148
|
|
|
@@ -233,7 +242,7 @@ braid_text.get = async (key, options) => {
|
|
|
233
242
|
if (options.parents) validate_version_array(options.parents)
|
|
234
243
|
|
|
235
244
|
let resource = (typeof key == 'string') ? await get_resource(key) : key
|
|
236
|
-
var version = resource.
|
|
245
|
+
var version = resource.version
|
|
237
246
|
|
|
238
247
|
if (!options.subscribe) {
|
|
239
248
|
if (options.transfer_encoding === 'dt') {
|
|
@@ -390,7 +399,7 @@ braid_text.put = async (key, options) => {
|
|
|
390
399
|
}
|
|
391
400
|
}
|
|
392
401
|
|
|
393
|
-
let parents = resource.
|
|
402
|
+
let parents = resource.version
|
|
394
403
|
let og_parents = options_parents || parents
|
|
395
404
|
|
|
396
405
|
let max_pos = resource.length_cache.get('' + og_parents) ??
|
|
@@ -526,6 +535,7 @@ braid_text.put = async (key, options) => {
|
|
|
526
535
|
|
|
527
536
|
for (let b of bytes) resource.doc.mergeBytes(b)
|
|
528
537
|
resource.val = resource.doc.get()
|
|
538
|
+
resource.version = resource.doc.getRemoteVersion().map(x => x.join("-")).sort()
|
|
529
539
|
|
|
530
540
|
var post_commit_updates = []
|
|
531
541
|
|
|
@@ -533,7 +543,7 @@ braid_text.put = async (key, options) => {
|
|
|
533
543
|
patches = get_xf_patches(resource.doc, v_before)
|
|
534
544
|
if (braid_text.verbose) console.log(JSON.stringify({ patches }))
|
|
535
545
|
|
|
536
|
-
let version = resource.
|
|
546
|
+
let version = resource.version
|
|
537
547
|
|
|
538
548
|
for (let client of resource.simpleton_clients) {
|
|
539
549
|
if (peer && client.peer === peer) {
|
|
@@ -546,7 +556,7 @@ braid_text.put = async (key, options) => {
|
|
|
546
556
|
// if the doc has been freed, exit early
|
|
547
557
|
if (resource.doc.__wbg_ptr === 0) return
|
|
548
558
|
|
|
549
|
-
let version = resource.
|
|
559
|
+
let version = resource.version
|
|
550
560
|
let x = { version }
|
|
551
561
|
x.parents = client.my_last_seen_version
|
|
552
562
|
|
|
@@ -609,7 +619,7 @@ braid_text.put = async (key, options) => {
|
|
|
609
619
|
}
|
|
610
620
|
} else {
|
|
611
621
|
if (resource.simpleton_clients.size) {
|
|
612
|
-
let version = resource.
|
|
622
|
+
let version = resource.version
|
|
613
623
|
patches = get_xf_patches(resource.doc, v_before)
|
|
614
624
|
let x = { version, parents, patches }
|
|
615
625
|
if (braid_text.verbose) console.log(`sending: ${JSON.stringify(x)}`)
|
|
@@ -681,6 +691,7 @@ async function get_resource(key) {
|
|
|
681
691
|
})
|
|
682
692
|
|
|
683
693
|
resource.val = resource.doc.get()
|
|
694
|
+
resource.version = resource.doc.getRemoteVersion().map(x => x.join("-")).sort()
|
|
684
695
|
|
|
685
696
|
resource.length_cache = createSimpleCache(braid_text.length_cache_size)
|
|
686
697
|
|
package/package.json
CHANGED
package/simpleton-client.js
CHANGED
|
@@ -65,7 +65,7 @@ function simpleton_client(url, {
|
|
|
65
65
|
signal: ac.signal
|
|
66
66
|
}).then(res => {
|
|
67
67
|
if (on_res) on_res(res)
|
|
68
|
-
res.subscribe(update => {
|
|
68
|
+
res.subscribe(async update => {
|
|
69
69
|
// Only accept the update if its parents == our current version
|
|
70
70
|
update.parents.sort()
|
|
71
71
|
if (current_version.length === update.parents.length
|
|
@@ -110,6 +110,14 @@ function simpleton_client(url, {
|
|
|
110
110
|
} else prev_state = apply_patches(prev_state, patches)
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// if the server gave us a digest,
|
|
114
|
+
// go ahead and check it against our new state..
|
|
115
|
+
if (update.extra_headers &&
|
|
116
|
+
update.extra_headers["repr-digest"] &&
|
|
117
|
+
update.extra_headers["repr-digest"].startsWith('sha-256=') &&
|
|
118
|
+
update.extra_headers["repr-digest"] !== `sha-256=:${btoa(String.fromCharCode(...new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(prev_state)))))}:`)
|
|
119
|
+
throw new Error('repr-digest mismatch')
|
|
120
|
+
|
|
113
121
|
if (on_state) on_state(prev_state)
|
|
114
122
|
}
|
|
115
123
|
}, on_error)
|
package/test/test.html
CHANGED
|
@@ -96,6 +96,87 @@ async function runTest(testName, testFunction, expectedResult) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
runTest(
|
|
100
|
+
"test subscribing and verifying digests [simpleton]",
|
|
101
|
+
async () => {
|
|
102
|
+
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
103
|
+
|
|
104
|
+
let r = await braid_fetch(`/${key}`, {
|
|
105
|
+
method: 'PUT',
|
|
106
|
+
version: ['hi-1'],
|
|
107
|
+
parents: [],
|
|
108
|
+
body: 'xx'
|
|
109
|
+
})
|
|
110
|
+
if (!r.ok) throw 'got: ' + r.statusCode
|
|
111
|
+
|
|
112
|
+
let r2 = await braid_fetch(`/${key}`, {
|
|
113
|
+
version: ['hi-0'],
|
|
114
|
+
subscribe: true
|
|
115
|
+
})
|
|
116
|
+
var parts = []
|
|
117
|
+
var p = new Promise(async (done, fail) => {
|
|
118
|
+
r2.subscribe(update => {
|
|
119
|
+
parts.push(update.extra_headers['repr-digest'])
|
|
120
|
+
if (parts.length > 1) done()
|
|
121
|
+
}, fail)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
await new Promise(done => setTimeout(done, 300))
|
|
125
|
+
let rr = await braid_fetch(`/${key}`, {
|
|
126
|
+
method: 'PUT',
|
|
127
|
+
version: ['hi-2'],
|
|
128
|
+
parents: ['hi-1'],
|
|
129
|
+
patches: [{unit: "text", range: "[1:1]", content: "Y"}]
|
|
130
|
+
})
|
|
131
|
+
if (!rr.ok) throw 'got: ' + rr.statusCode
|
|
132
|
+
|
|
133
|
+
await p
|
|
134
|
+
return JSON.stringify(parts)
|
|
135
|
+
},
|
|
136
|
+
'["sha-256=:Xd6JaIf2dUybFb/jpEGuSAbfL96UABMR4IvxEGIuC74=:","sha-256=:77cl3INcGEtczN0zK3eOgW/YWYAOm8ub73LkVcF2/rA=:"]'
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
runTest(
|
|
140
|
+
"test subscribing and verifying digests [dt]",
|
|
141
|
+
async () => {
|
|
142
|
+
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
143
|
+
|
|
144
|
+
let r = await braid_fetch(`/${key}`, {
|
|
145
|
+
method: 'PUT',
|
|
146
|
+
version: ['hi-1'],
|
|
147
|
+
parents: [],
|
|
148
|
+
body: 'xx'
|
|
149
|
+
})
|
|
150
|
+
if (!r.ok) throw 'got: ' + r.statusCode
|
|
151
|
+
|
|
152
|
+
let r2 = await braid_fetch(`/${key}`, {
|
|
153
|
+
version: ['hi-0'],
|
|
154
|
+
headers: { 'merge-type': 'dt' },
|
|
155
|
+
subscribe: true
|
|
156
|
+
})
|
|
157
|
+
var parts = []
|
|
158
|
+
var p = new Promise(async (done, fail) => {
|
|
159
|
+
r2.subscribe(update => {
|
|
160
|
+
parts.push(update.extra_headers['repr-digest'])
|
|
161
|
+
if (parts.length > 1) done()
|
|
162
|
+
}, fail)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
await new Promise(done => setTimeout(done, 300))
|
|
166
|
+
let rr = await braid_fetch(`/${key}`, {
|
|
167
|
+
method: 'PUT',
|
|
168
|
+
version: ['hi-2'],
|
|
169
|
+
parents: ['hi-1'],
|
|
170
|
+
patches: [{unit: "text", range: "[2:2]", content: "Y"}]
|
|
171
|
+
})
|
|
172
|
+
if (!rr.ok) throw 'got: ' + rr.statusCode
|
|
173
|
+
|
|
174
|
+
await p
|
|
175
|
+
return JSON.stringify(parts)
|
|
176
|
+
},
|
|
177
|
+
'["sha-256=:Xd6JaIf2dUybFb/jpEGuSAbfL96UABMR4IvxEGIuC74=:","sha-256=:QknHazou37wCCwv3JXnCoAvXcKszP6xBTxLIiUAETgI=:"]'
|
|
178
|
+
)
|
|
179
|
+
|
|
99
180
|
runTest(
|
|
100
181
|
"test PUTing a version that the server already has",
|
|
101
182
|
async () => {
|