braid-text 0.2.61 → 0.2.63

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.
Files changed (3) hide show
  1. package/index.js +47 -1
  2. package/package.json +2 -2
  3. package/test/test.html +169 -1
package/index.js CHANGED
@@ -40,6 +40,52 @@ braid_text.serve = async (req, res, options = {}) => {
40
40
 
41
41
  let peer = req.headers["peer"]
42
42
 
43
+ // selection sharing prototype
44
+ if (req.headers['selection-sharing-prototype']) {
45
+ res.setHeader('Content-Type', 'application/json')
46
+
47
+ if (!resource.selections) resource.selections = {}
48
+ if (!resource.selection_clients) resource.selection_clients = new Set()
49
+
50
+ if (req.method === "GET" || req.method === "HEAD") {
51
+ if (!req.subscribe) {
52
+ return my_end(200, JSON.stringify(resource.selections))
53
+ } else {
54
+ var client = {peer, res}
55
+ resource.selection_clients.add(client)
56
+ res.startSubscription({
57
+ onClose: () => resource.selection_clients.delete(client)
58
+ })
59
+ res.sendUpdate({ body: JSON.stringify(resource.selections) })
60
+ return
61
+ }
62
+ } else if (req.method == "PUT" || req.method == "POST" || req.method == "PATCH") {
63
+ var body = (await req.patches())[0].content_text
64
+ var json = JSON.parse(body)
65
+
66
+ // only keep new selections if they are newer
67
+ for (var [user, selection] of Object.entries(json)) {
68
+ if (resource.selections[user] && resource.selections[user].time > selection.time) delete json[user]
69
+ else resource.selections[user] = selection
70
+ }
71
+
72
+ // remove old selections that are too old
73
+ var long_ago = Date.now() - 1000 * 60 * 5
74
+ for (var [user, selection] of Object.entries(resource.selections))
75
+ if (selection.time < long_ago) {
76
+ delete resource.selections[user]
77
+ delete json[user]
78
+ }
79
+
80
+ body = JSON.stringify(json)
81
+ if (body.length > 2)
82
+ for (let client of resource.selection_clients)
83
+ if (client.peer !== peer) client.res.sendUpdate({ body })
84
+
85
+ return my_end(200)
86
+ }
87
+ }
88
+
43
89
  let merge_type = req.headers["merge-type"]
44
90
  if (!merge_type) merge_type = 'simpleton'
45
91
  if (merge_type !== 'simpleton' && merge_type !== 'dt') return my_end(400, `Unknown merge type: ${merge_type}`)
@@ -201,7 +247,7 @@ braid_text.serve = async (req, res, options = {}) => {
201
247
  if (!resource.actor_seqs[actor]?.has(seq)) unknowns.push(event)
202
248
  }
203
249
  if (unknowns.length)
204
- return done_my_turn(309, '', "Version Unknown", {
250
+ return done_my_turn(309, '', "Version Unknown Here", {
205
251
  Version: ascii_ify(unknowns.map(e => JSON.stringify(e)).join(', ')),
206
252
  'Retry-After': '1'
207
253
  })
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "braid-text",
3
- "version": "0.2.61",
3
+ "version": "0.2.63",
4
4
  "description": "Library for collaborative text over http using braid.",
5
5
  "author": "Braid Working Group",
6
6
  "repository": "braid-org/braid-text",
7
7
  "homepage": "https://braid.org",
8
8
  "dependencies": {
9
9
  "@braid.org/diamond-types-node": "^2.0.0",
10
- "braid-http": "~1.3.79"
10
+ "braid-http": "~1.3.80"
11
11
  }
12
12
  }
package/test/test.html CHANGED
@@ -96,6 +96,174 @@ async function runTest(testName, testFunction, expectedResult) {
96
96
  }
97
97
  }
98
98
 
99
+ runTest(
100
+ "test selection-sharing-prototype PUT and GET",
101
+ async () => {
102
+ let key = 'test-' + Math.random().toString(36).slice(2)
103
+
104
+ let time = Date.now()
105
+
106
+ let r = await braid_fetch(`/${key}`, {
107
+ method: 'PUT',
108
+ body: JSON.stringify({
109
+ hello: {
110
+ yo: 'hi',
111
+ time
112
+ }
113
+ }),
114
+ headers: {
115
+ 'selection-sharing-prototype': 'true'
116
+ }
117
+ })
118
+ if (!r.ok) return 'got: ' + r.status
119
+
120
+ let r2 = await braid_fetch(`/${key}`, {
121
+ method: 'GET',
122
+ headers: {
123
+ 'selection-sharing-prototype': 'true'
124
+ }
125
+ })
126
+ if (!r2.ok) return 'got: ' + r2.status
127
+
128
+ let o = await r2.json()
129
+ return o.hello.time === time ? 'times match' : 'bad'
130
+ },
131
+ 'times match'
132
+ )
133
+
134
+ runTest(
135
+ "test selection-sharing-prototype GET/subscribe",
136
+ async () => {
137
+ let key = 'test-' + Math.random().toString(36).slice(2)
138
+
139
+ var a = new AbortController()
140
+ let r = await braid_fetch(`/${key}`, {
141
+ method: 'GET',
142
+ signal: a.signal,
143
+ subscribe: true,
144
+ peer: 'abc',
145
+ headers: {
146
+ 'selection-sharing-prototype': 'true'
147
+ }
148
+ })
149
+ if (!r.ok) return 'got: ' + r.status
150
+ var p = new Promise(done => {
151
+ r.subscribe(update => {
152
+ var body = update.body_text
153
+ if (body.length > 2) done(body)
154
+ })
155
+ })
156
+
157
+ var time = Date.now()
158
+
159
+ let r2 = await braid_fetch(`/${key}`, {
160
+ method: 'PUT',
161
+ peer: 'xyz',
162
+ body: JSON.stringify({
163
+ hello: {
164
+ yo: 'hi',
165
+ time
166
+ }
167
+ }),
168
+ headers: {
169
+ 'selection-sharing-prototype': 'true'
170
+ }
171
+ })
172
+ if (!r2.ok) return 'got: ' + r2.status
173
+
174
+ var ret_val = JSON.parse(await p).hello.time === time ? 'times match' : 'bad'
175
+
176
+ a.abort()
177
+
178
+ return ret_val
179
+ },
180
+ 'times match'
181
+ )
182
+
183
+ runTest(
184
+ "test selection-sharing-prototype PUT old cursor",
185
+ async () => {
186
+ let key = 'test-' + Math.random().toString(36).slice(2)
187
+
188
+ let time = Date.now()
189
+
190
+ let r = await braid_fetch(`/${key}`, {
191
+ method: 'PUT',
192
+ body: JSON.stringify({
193
+ hello: {
194
+ yo: 'hi',
195
+ time
196
+ }
197
+ }),
198
+ headers: {
199
+ 'selection-sharing-prototype': 'true'
200
+ }
201
+ })
202
+ if (!r.ok) return 'got: ' + r.status
203
+
204
+ let r3 = await braid_fetch(`/${key}`, {
205
+ method: 'PUT',
206
+ body: JSON.stringify({
207
+ hello: {
208
+ yo: 'hoop',
209
+ time: time - 5
210
+ }
211
+ }),
212
+ headers: {
213
+ 'selection-sharing-prototype': 'true'
214
+ }
215
+ })
216
+ if (!r3.ok) return 'got: ' + r3.status
217
+
218
+ let r2 = await braid_fetch(`/${key}`, {
219
+ method: 'GET',
220
+ headers: {
221
+ 'selection-sharing-prototype': 'true'
222
+ }
223
+ })
224
+ if (!r2.ok) return 'got: ' + r2.status
225
+
226
+ let o = await r2.json()
227
+ return o.hello.yo
228
+ },
229
+ 'hi'
230
+ )
231
+
232
+ runTest(
233
+ "test selection-sharing-prototype PUT really old cursor",
234
+ async () => {
235
+ let key = 'test-' + Math.random().toString(36).slice(2)
236
+
237
+ let time = Date.now() - 1000 * 60 * 60 * 24
238
+
239
+ let r = await braid_fetch(`/${key}`, {
240
+ method: 'PUT',
241
+ body: JSON.stringify({
242
+ hello: {
243
+ yo: 'hi',
244
+ time
245
+ }
246
+ }),
247
+ headers: {
248
+ 'selection-sharing-prototype': 'true'
249
+ }
250
+ })
251
+ if (!r.ok) return 'got: ' + r.status
252
+
253
+ let r2 = await braid_fetch(`/${key}`, {
254
+ method: 'GET',
255
+ headers: {
256
+ 'selection-sharing-prototype': 'true'
257
+ }
258
+ })
259
+ if (!r2.ok) return 'got: ' + r2.status
260
+
261
+ let o = await r2.json()
262
+ return JSON.stringify(o)
263
+ },
264
+ '{}'
265
+ )
266
+
99
267
  runTest(
100
268
  "test PUT digest (good)",
101
269
  async () => {
@@ -965,7 +1133,7 @@ runTest(
965
1133
  })
966
1134
  return r.status + ' ' + r.ok + ' ' + r.statusText + ' ' + r.headers.get('Version')
967
1135
  },
968
- '309 false Version Unknown "missing-0", "y\\ud83d\\ude00-0"'
1136
+ '309 false Version Unknown Here "missing-0", "y\\ud83d\\ude00-0"'
969
1137
  )
970
1138
 
971
1139
  runTest(