braid-text 0.2.84 → 0.2.86
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 +16 -6
- package/package.json +1 -1
- package/test/test.js +15 -0
- package/test/tests.js +136 -2
package/index.js
CHANGED
|
@@ -108,7 +108,7 @@ function create_braid_text() {
|
|
|
108
108
|
|
|
109
109
|
connect()
|
|
110
110
|
async function connect() {
|
|
111
|
-
if (options.
|
|
111
|
+
if (options.on_pre_connect) await options.on_pre_connect()
|
|
112
112
|
|
|
113
113
|
if (closed) return
|
|
114
114
|
|
|
@@ -165,13 +165,18 @@ function create_braid_text() {
|
|
|
165
165
|
signal: ac.signal,
|
|
166
166
|
subscribe: update => {
|
|
167
167
|
update.signal = ac.signal
|
|
168
|
+
update.dont_retry = true
|
|
168
169
|
braid_text.put(b, update).then((x) => {
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
if (x.ok) {
|
|
171
|
+
local_first_put()
|
|
172
|
+
extend_fork_point(update)
|
|
173
|
+
} else if (x.status === 401 || x.status === 403) {
|
|
174
|
+
options.on_unauthorized?.()
|
|
175
|
+
} else throw new Error('failed to PUT: ' + x.status)
|
|
171
176
|
}).catch(e => {
|
|
172
177
|
if (e.name === 'AbortError') {
|
|
173
178
|
// ignore
|
|
174
|
-
} else
|
|
179
|
+
} else handle_error(e)
|
|
175
180
|
})
|
|
176
181
|
}
|
|
177
182
|
}
|
|
@@ -187,7 +192,10 @@ function create_braid_text() {
|
|
|
187
192
|
await braid_text.put(a, update)
|
|
188
193
|
extend_fork_point(update)
|
|
189
194
|
},
|
|
190
|
-
on_error:
|
|
195
|
+
on_error: e => {
|
|
196
|
+
options.on_disconnect?.()
|
|
197
|
+
handle_error(e)
|
|
198
|
+
}
|
|
191
199
|
}
|
|
192
200
|
// Handle case where remote doesn't exist yet - wait for local to create it
|
|
193
201
|
var remote_result = await braid_text.get(b, b_ops)
|
|
@@ -196,6 +204,7 @@ function create_braid_text() {
|
|
|
196
204
|
await local_first_put_promise
|
|
197
205
|
disconnect()
|
|
198
206
|
connect()
|
|
207
|
+
return
|
|
199
208
|
}
|
|
200
209
|
options.on_res?.(remote_result)
|
|
201
210
|
// on_error will call handle_error when connection drops
|
|
@@ -702,8 +711,9 @@ function create_braid_text() {
|
|
|
702
711
|
var params = {
|
|
703
712
|
method: 'PUT',
|
|
704
713
|
signal: options.signal,
|
|
705
|
-
retry: () => true,
|
|
706
714
|
}
|
|
715
|
+
if (!options.dont_retry)
|
|
716
|
+
params.retry = () => true
|
|
707
717
|
for (var x of ['headers', 'parents', 'version', 'peer', 'body', 'patches'])
|
|
708
718
|
if (options[x] != null) params[x] = options[x]
|
|
709
719
|
|
package/package.json
CHANGED
package/test/test.js
CHANGED
|
@@ -69,6 +69,21 @@ function createTestServer(options = {}) {
|
|
|
69
69
|
return res.end('error')
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
if (req.url.startsWith('/unauthorized') && req.method === 'PUT') {
|
|
73
|
+
res.statusCode = 401
|
|
74
|
+
return res.end('Unauthorized')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (req.url.startsWith('/forbidden') && req.method === 'PUT') {
|
|
78
|
+
res.statusCode = 403
|
|
79
|
+
return res.end('Forbidden')
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (req.url.startsWith('/server_error') && req.method === 'PUT') {
|
|
83
|
+
res.statusCode = 500
|
|
84
|
+
return res.end('Internal Server Error')
|
|
85
|
+
}
|
|
86
|
+
|
|
72
87
|
if (req.url.startsWith('/404')) {
|
|
73
88
|
res.statusCode = 404
|
|
74
89
|
return res.end('Not Found')
|
package/test/tests.js
CHANGED
|
@@ -46,7 +46,7 @@ runTest(
|
|
|
46
46
|
var ac = new AbortController()
|
|
47
47
|
braid_text.sync('/${key}', new URL('http://localhost:8889/have_error'), {
|
|
48
48
|
signal: ac.signal,
|
|
49
|
-
|
|
49
|
+
on_pre_connect: () => {
|
|
50
50
|
count++
|
|
51
51
|
if (count === 2) {
|
|
52
52
|
res.end('it reconnected!')
|
|
@@ -198,7 +198,7 @@ runTest(
|
|
|
198
198
|
var ac = new AbortController()
|
|
199
199
|
braid_text.sync('/${key_a}', new URL('http://localhost:8889/have_error'), {
|
|
200
200
|
signal: ac.signal,
|
|
201
|
-
|
|
201
|
+
on_pre_connect: () => {
|
|
202
202
|
count++
|
|
203
203
|
if (count === 2) {
|
|
204
204
|
res.end('it reconnected!')
|
|
@@ -2066,6 +2066,140 @@ runTest(
|
|
|
2066
2066
|
'on_res called'
|
|
2067
2067
|
)
|
|
2068
2068
|
|
|
2069
|
+
runTest(
|
|
2070
|
+
"test braid_text.sync reconnects when inner put fails with non-200 status",
|
|
2071
|
+
async () => {
|
|
2072
|
+
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
2073
|
+
|
|
2074
|
+
// Create a local resource with content
|
|
2075
|
+
var r = await braid_fetch(`/${key}`, {
|
|
2076
|
+
method: 'PUT',
|
|
2077
|
+
body: 'initial'
|
|
2078
|
+
})
|
|
2079
|
+
if (!r.ok) return 'initial put failed: ' + r.status
|
|
2080
|
+
|
|
2081
|
+
var r = await braid_fetch(`/eval`, {
|
|
2082
|
+
method: 'PUT',
|
|
2083
|
+
body: `void (async () => {
|
|
2084
|
+
var connect_count = 0
|
|
2085
|
+
var ac = new AbortController()
|
|
2086
|
+
|
|
2087
|
+
braid_text.sync('/${key}', new URL('http://localhost:8889/server_error'), {
|
|
2088
|
+
signal: ac.signal,
|
|
2089
|
+
on_pre_connect: () => {
|
|
2090
|
+
connect_count++
|
|
2091
|
+
if (connect_count >= 2) {
|
|
2092
|
+
ac.abort()
|
|
2093
|
+
res.end('reconnected after put failure')
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
})
|
|
2097
|
+
|
|
2098
|
+
// Trigger a local put which will fail when synced to the error endpoint
|
|
2099
|
+
await new Promise(done => setTimeout(done, 100))
|
|
2100
|
+
await braid_text.put('/${key}', { body: 'trigger sync' })
|
|
2101
|
+
|
|
2102
|
+
// Wait for reconnect attempt
|
|
2103
|
+
await new Promise(done => setTimeout(done, 2000))
|
|
2104
|
+
ac.abort()
|
|
2105
|
+
res.end('did not reconnect')
|
|
2106
|
+
})()`
|
|
2107
|
+
})
|
|
2108
|
+
if (!r.ok) return 'eval failed: ' + r.status
|
|
2109
|
+
|
|
2110
|
+
return await r.text()
|
|
2111
|
+
},
|
|
2112
|
+
'reconnected after put failure'
|
|
2113
|
+
)
|
|
2114
|
+
|
|
2115
|
+
runTest(
|
|
2116
|
+
"test braid_text.sync on_unauthorized callback for 401",
|
|
2117
|
+
async () => {
|
|
2118
|
+
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
2119
|
+
|
|
2120
|
+
// Create a local resource with content
|
|
2121
|
+
var r = await braid_fetch(`/${key}`, {
|
|
2122
|
+
method: 'PUT',
|
|
2123
|
+
body: 'initial'
|
|
2124
|
+
})
|
|
2125
|
+
if (!r.ok) return 'initial put failed: ' + r.status
|
|
2126
|
+
|
|
2127
|
+
var r = await braid_fetch(`/eval`, {
|
|
2128
|
+
method: 'PUT',
|
|
2129
|
+
body: `void (async () => {
|
|
2130
|
+
var unauthorized_called = false
|
|
2131
|
+
var ac = new AbortController()
|
|
2132
|
+
|
|
2133
|
+
braid_text.sync('/${key}', new URL('http://localhost:8889/unauthorized'), {
|
|
2134
|
+
signal: ac.signal,
|
|
2135
|
+
on_unauthorized: () => {
|
|
2136
|
+
unauthorized_called = true
|
|
2137
|
+
ac.abort()
|
|
2138
|
+
res.end('on_unauthorized called')
|
|
2139
|
+
}
|
|
2140
|
+
})
|
|
2141
|
+
|
|
2142
|
+
// Trigger a local put which will get 401 when synced
|
|
2143
|
+
await new Promise(done => setTimeout(done, 100))
|
|
2144
|
+
await braid_text.put('/${key}', { body: 'trigger sync' })
|
|
2145
|
+
|
|
2146
|
+
// Wait for callback
|
|
2147
|
+
await new Promise(done => setTimeout(done, 2000))
|
|
2148
|
+
ac.abort()
|
|
2149
|
+
res.end('on_unauthorized not called')
|
|
2150
|
+
})()`
|
|
2151
|
+
})
|
|
2152
|
+
if (!r.ok) return 'eval failed: ' + r.status
|
|
2153
|
+
|
|
2154
|
+
return await r.text()
|
|
2155
|
+
},
|
|
2156
|
+
'on_unauthorized called'
|
|
2157
|
+
)
|
|
2158
|
+
|
|
2159
|
+
runTest(
|
|
2160
|
+
"test braid_text.sync on_unauthorized callback for 403",
|
|
2161
|
+
async () => {
|
|
2162
|
+
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
2163
|
+
|
|
2164
|
+
// Create a local resource with content
|
|
2165
|
+
var r = await braid_fetch(`/${key}`, {
|
|
2166
|
+
method: 'PUT',
|
|
2167
|
+
body: 'initial'
|
|
2168
|
+
})
|
|
2169
|
+
if (!r.ok) return 'initial put failed: ' + r.status
|
|
2170
|
+
|
|
2171
|
+
var r = await braid_fetch(`/eval`, {
|
|
2172
|
+
method: 'PUT',
|
|
2173
|
+
body: `void (async () => {
|
|
2174
|
+
var unauthorized_called = false
|
|
2175
|
+
var ac = new AbortController()
|
|
2176
|
+
|
|
2177
|
+
braid_text.sync('/${key}', new URL('http://localhost:8889/forbidden'), {
|
|
2178
|
+
signal: ac.signal,
|
|
2179
|
+
on_unauthorized: () => {
|
|
2180
|
+
unauthorized_called = true
|
|
2181
|
+
ac.abort()
|
|
2182
|
+
res.end('on_unauthorized called')
|
|
2183
|
+
}
|
|
2184
|
+
})
|
|
2185
|
+
|
|
2186
|
+
// Trigger a local put which will get 403 when synced
|
|
2187
|
+
await new Promise(done => setTimeout(done, 100))
|
|
2188
|
+
await braid_text.put('/${key}', { body: 'trigger sync' })
|
|
2189
|
+
|
|
2190
|
+
// Wait for callback
|
|
2191
|
+
await new Promise(done => setTimeout(done, 2000))
|
|
2192
|
+
ac.abort()
|
|
2193
|
+
res.end('on_unauthorized not called')
|
|
2194
|
+
})()`
|
|
2195
|
+
})
|
|
2196
|
+
if (!r.ok) return 'eval failed: ' + r.status
|
|
2197
|
+
|
|
2198
|
+
return await r.text()
|
|
2199
|
+
},
|
|
2200
|
+
'on_unauthorized called'
|
|
2201
|
+
)
|
|
2202
|
+
|
|
2069
2203
|
runTest(
|
|
2070
2204
|
"test getting a binary update from a subscription",
|
|
2071
2205
|
async () => {
|