braid-text 0.3.22 → 0.3.24

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 CHANGED
@@ -69,11 +69,13 @@ http_server.on("request", (req, res) => {
69
69
  - `res`: Outgoing HTTP response object.
70
70
  - `options`: <small style="color:lightgrey">[optional]</small> An object containing additional options:
71
71
  - `key`: <small style="color:lightgrey">[optional]</small> ID of text resource to sync with. Defaults to `req.url`.
72
- - `put_cb`: <small style="color:lightgrey">[optional]</small> Callback invoked after a PUT changes a resource. Signature: `(key, val, old_val, patches)` where:
72
+ - `put_cb`: <small style="color:lightgrey">[optional]</small> Callback invoked after a PUT changes a resource. Signature: `(key, val, {old_val, patches, version, parents})` where:
73
73
  - `key` - The resource key
74
74
  - `val` - The new document text after the PUT
75
75
  - `old_val` - The document text before the PUT
76
76
  - `patches` - Array of patches applied (each `{unit, range, content}`), or `null` for full-body replacements
77
+ - `version` - The version after the PUT
78
+ - `parents` - The version prior to the PUT
77
79
  - This is the main method of this library, and does all the work to handle Braid-HTTP `GET` and `PUT` requests concerned with a specific text resource.
78
80
 
79
81
  `await braid_text.get(key)`
@@ -297,7 +297,7 @@ function peer_bg_color(peer_id) {
297
297
  // cursors.on_edit(patches) // call after local edit; patches optional
298
298
  // cursors.destroy()
299
299
  //
300
- function cursor_highlights(textarea, url) {
300
+ function cursor_highlights(textarea, url, options) {
301
301
  var peer = Math.random().toString(36).slice(2)
302
302
  var hl = textarea_highlights(textarea)
303
303
  var applying_remote = false
@@ -307,6 +307,7 @@ function cursor_highlights(textarea, url) {
307
307
 
308
308
  cursor_client(url, {
309
309
  peer,
310
+ headers: options?.headers,
310
311
  get_text: () => textarea.value,
311
312
  on_change: (sels) => {
312
313
  for (var [id, ranges] of Object.entries(sels)) {
@@ -15,12 +15,12 @@
15
15
  // cursors.changed(patches)
16
16
  // cursors.destroy()
17
17
  //
18
- async function cursor_client(url, { peer, get_text, on_change }) {
18
+ async function cursor_client(url, { peer, get_text, on_change, headers: user_headers }) {
19
19
  // --- feature detection: HEAD probe ---
20
20
  try {
21
21
  var head_res = await braid_fetch(url, {
22
22
  method: 'HEAD',
23
- headers: { 'Accept': 'application/text-cursors+json' }
23
+ headers: { ...user_headers, 'Accept': 'application/text-cursors+json' }
24
24
  })
25
25
  var ct = head_res.headers.get('content-type') || ''
26
26
  if (!ct.includes('application/text-cursors+json')) return null
@@ -124,6 +124,7 @@ async function cursor_client(url, { peer, get_text, on_change }) {
124
124
  braid_fetch(url, {
125
125
  method: 'PUT',
126
126
  headers: {
127
+ ...user_headers,
127
128
  'Content-Type': 'application/text-cursors+json',
128
129
  Peer: peer,
129
130
  'Content-Range': 'json [' + JSON.stringify(peer) + ']',
@@ -155,6 +156,7 @@ async function cursor_client(url, { peer, get_text, on_change }) {
155
156
  }},
156
157
  peer,
157
158
  headers: {
159
+ ...user_headers,
158
160
  Accept: 'application/text-cursors+json',
159
161
  Heartbeats: '10',
160
162
  },
@@ -12,6 +12,8 @@
12
12
  //
13
13
  // url: resource endpoint
14
14
  //
15
+ // headers: custom headers that get forwarded through into the fetch
16
+ //
15
17
  // on_patches?: (patches) => void
16
18
  // processes incoming patches by applying them to the UI/textarea.
17
19
  // Patches are guaranteed to be in-order and non-overlapping.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-text",
3
- "version": "0.3.22",
3
+ "version": "0.3.24",
4
4
  "description": "Library for collaborative text over http using braid.",
5
5
  "author": "Braid Working Group",
6
6
  "repository": "braid-org/braid-text",
@@ -9,8 +9,10 @@
9
9
  "test": "node test/test.js"
10
10
  },
11
11
  "main": "server.js",
12
+ "types": "server.d.ts",
12
13
  "files": [
13
14
  "server.js",
15
+ "server.d.ts",
14
16
  "simpleton-client.js",
15
17
  "client/simpleton-sync.js",
16
18
  "client/cursor-sync.js",
package/server.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { IncomingMessage, ServerResponse } from 'http'
2
+
3
+ interface PutCallbackParams {
4
+ old_val: string
5
+ patches: Array<{ unit: string; range: string; content: string }> | null
6
+ version: string[]
7
+ parents: string[]
8
+ }
9
+
10
+ interface ServeOptions {
11
+ key?: string
12
+ put_cb?: (key: string, val: string, params: PutCallbackParams) => void
13
+ }
14
+
15
+ interface GetResult {
16
+ version: string[]
17
+ body: string | Uint8Array
18
+ }
19
+
20
+ interface Resource {
21
+ key: string
22
+ val: string
23
+ version: string[]
24
+ }
25
+
26
+ interface BraidText {
27
+ verbose: boolean
28
+ db_folder: string | null
29
+ cors: boolean
30
+ cache: Record<string, Promise<Resource>>
31
+
32
+ serve(req: IncomingMessage, res: ServerResponse, options?: ServeOptions): Promise<void>
33
+ get(key: string): Promise<string | null>
34
+ get(key: string, options: Record<string, any>): Promise<GetResult>
35
+ put(key: string, options: Record<string, any>): Promise<{ change_count: number }>
36
+ delete(key: string): Promise<void>
37
+ list(): Promise<string[]>
38
+ sync(a: string, b: string | URL, options?: Record<string, any>): Promise<void>
39
+ free_cors(res: ServerResponse): void
40
+ create_braid_text(): BraidText
41
+ }
42
+
43
+ declare const braidText: BraidText
44
+ export = braidText
package/server.js CHANGED
@@ -345,7 +345,7 @@ function create_braid_text() {
345
345
  braid_text.serve = async (req, res, options = {}) => {
346
346
  options = {
347
347
  key: req.url.split('?')[0], // Default key
348
- put_cb: (key, val, old_val, patches) => { }, // Default callback when a PUT changes a key
348
+ put_cb: (key, val, params) => { }, // Default callback when a PUT changes a key
349
349
  ...options // Override with all options passed in
350
350
  }
351
351
 
@@ -556,6 +556,7 @@ function create_braid_text() {
556
556
  }
557
557
 
558
558
  var old_val = resource.val
559
+ var old_version = resource.version
559
560
  var put_patches = patches ? patches.map(p => ({unit: p.unit, range: p.range, content: p.content})) : null
560
561
  var {change_count} = await braid_text.put(resource, { peer, version: req.version, parents: req.parents, patches, body, merge_type })
561
562
 
@@ -577,7 +578,9 @@ function create_braid_text() {
577
578
 
578
579
  res.setHeader("Version", get_current_version())
579
580
 
580
- options.put_cb(options.key, resource.val, old_val, put_patches)
581
+ options.put_cb(options.key, resource.val,
582
+ {old_val, patches: put_patches,
583
+ version: resource.version, parents: old_version})
581
584
  } catch (e) {
582
585
  console.log(`${req.method} ERROR: ${e.stack}`)
583
586
  return done_my_turn(500, "The server failed to apply this version. The error generated was: " + e)
@@ -3113,12 +3116,17 @@ async function handle_cursors(resource, req, res) {
3113
3116
  res.sendUpdate({ body: JSON.stringify(cursors.snapshot()) })
3114
3117
  }
3115
3118
  } else if (req.method === 'PUT' || req.method === 'POST' || req.method === 'PATCH') {
3116
- var raw_body = await new Promise((resolve, reject) => {
3117
- var chunks = []
3118
- req.on('data', chunk => chunks.push(chunk))
3119
- req.on('end', () => resolve(Buffer.concat(chunks).toString()))
3120
- req.on('error', reject)
3121
- })
3119
+ var raw_body
3120
+ if (req.already_buffered_body != null) {
3121
+ raw_body = req.already_buffered_body.toString()
3122
+ } else {
3123
+ raw_body = await new Promise((resolve, reject) => {
3124
+ var chunks = []
3125
+ req.on('data', chunk => chunks.push(chunk))
3126
+ req.on('end', () => resolve(Buffer.concat(chunks).toString()))
3127
+ req.on('error', reject)
3128
+ })
3129
+ }
3122
3130
  var range = req.headers['content-range']
3123
3131
  if (!range || !range.startsWith('json ')) {
3124
3132
  res.writeHead(400)