@vzn/vx-reapi 0.0.594 → 0.0.596
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 +6 -5
- package/package.json +2 -2
- package/src/cache.ts +12 -12
- package/src/executor.ts +45 -80
- package/src/merkle.ts +2 -2
- package/src/wire.ts +6 -2
package/README.md
CHANGED
|
@@ -223,11 +223,12 @@ through; a Tree file's setuid and setgid bits are dropped.
|
|
|
223
223
|
## Artifacts stream
|
|
224
224
|
|
|
225
225
|
An artifact up to 256 KiB is read whole and sent in one batch, with no
|
|
226
|
-
probe first.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
226
|
+
probe first. Up to the batch limit (about 4 MiB) it is read whole once,
|
|
227
|
+
probed with `FindMissingBlobs`, and those bytes sent. Past that the cache
|
|
228
|
+
layer never holds an artifact whole: `put` digests the file-backed `Blob`
|
|
229
|
+
vx hands it in one pass over its stream, asks `FindMissingBlobs`, and
|
|
230
|
+
uploads from a second pass, read `chunkBytes` at a time as the ByteStream
|
|
231
|
+
write drains, identity-encoded (the artifact is zstd already). `get` returns the ByteStream read as a
|
|
231
232
|
`Response`, each message taken from the call as vx writes the previous one
|
|
232
233
|
to disk.
|
|
233
234
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx-reapi",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.596",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Bazel Remote Execution API plugin for vx — remote cache (ActionCache + CAS) against NativeLink, BuildBuddy, Buildbarn or bazel-remote.",
|
|
6
6
|
"keywords": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@vzn/vx": "^0.0.
|
|
42
|
+
"@vzn/vx": "^0.0.596"
|
|
43
43
|
},
|
|
44
44
|
"repository": {
|
|
45
45
|
"type": "git",
|
package/src/cache.ts
CHANGED
|
@@ -159,32 +159,32 @@ export class ReapiRemoteCache {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
/**
|
|
162
|
-
*
|
|
163
|
-
* digest first (the CAS address must be known
|
|
164
|
-
* then the upload from a second read of the
|
|
162
|
+
* An artifact past `writeBlob`'s whole read takes two passes over `body`,
|
|
163
|
+
* never one in memory: the digest first (the CAS address must be known
|
|
164
|
+
* before the server is asked), then the upload from a second read of the
|
|
165
|
+
* stream.
|
|
165
166
|
*/
|
|
166
167
|
async put(hash: string, body: Blob, meta: { durationMs: number }): Promise<void> {
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
// Read once, and those bytes hashed and sent, wherever `writeBlob` would
|
|
169
|
+
// read the Blob whole anyway: a second writer of the key renames its
|
|
170
|
+
// artifact over the file, and two reads sent its bytes under this one's
|
|
171
|
+
// digest (F-50).
|
|
172
|
+
const data = body.size <= this.client.wholeWriteBytes ? await body.bytes() : undefined
|
|
173
|
+
const digest = data === undefined ? await streamedDigestOf(body) : digestOf(data)
|
|
174
|
+
if (data !== undefined && data.length <= SMALL_PUT_BYTES) {
|
|
169
175
|
// A small artifact is sent in one batch without asking first: the
|
|
170
176
|
// probe was a round trip of its own to save an upload no larger than
|
|
171
177
|
// it (102 → 71 ms per save at 15 ms one-way, F-26). Content-addressed,
|
|
172
178
|
// so a re-send is harmless.
|
|
173
|
-
// Read once, and those bytes hashed and sent: a second writer of the
|
|
174
|
-
// key renames its artifact over the file, and two reads sent its bytes
|
|
175
|
-
// under this one's digest (F-50).
|
|
176
179
|
// A server whose batch limit is smaller refuses it; stream instead.
|
|
177
|
-
const data = await body.bytes()
|
|
178
|
-
digest = digestOf(data)
|
|
179
180
|
await this.client
|
|
180
181
|
.batchUpdateBlobs([{ digest, data }])
|
|
181
182
|
.catch(() => this.client.writeBlob(digest, data))
|
|
182
183
|
} else {
|
|
183
|
-
digest = await streamedDigestOf(body)
|
|
184
184
|
// Upload only what the server lacks: for a large artifact the probe is
|
|
185
185
|
// cheap next to the bytes it can skip.
|
|
186
186
|
const missing = await this.client.findMissingBlobs([digest])
|
|
187
|
-
if (missing.length > 0) await this.client.writeBlob(digest, body)
|
|
187
|
+
if (missing.length > 0) await this.client.writeBlob(digest, data ?? body)
|
|
188
188
|
}
|
|
189
189
|
await this.client.updateActionResult(actionDigestFor(hash), {
|
|
190
190
|
exit_code: 0,
|
package/src/executor.ts
CHANGED
|
@@ -12,16 +12,25 @@
|
|
|
12
12
|
import { mkdir, writeFile, chmod, readlink, realpath, rm, symlink, unlink } from 'node:fs/promises'
|
|
13
13
|
import { constants, existsSync } from 'node:fs'
|
|
14
14
|
import path from 'node:path'
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
executorFallback,
|
|
17
|
+
isLiteralPattern,
|
|
18
|
+
isUserError,
|
|
19
|
+
normalizeGlob,
|
|
20
|
+
UserError,
|
|
21
|
+
withForwardArgs,
|
|
22
|
+
} from '@vzn/vx'
|
|
16
23
|
import type { ExecuteRequest, ExecuteResult, TaskExecutor, TaskPlacement } from '@vzn/vx'
|
|
17
24
|
import {
|
|
18
25
|
buildInputTree,
|
|
26
|
+
decodeDigestBytes,
|
|
19
27
|
decodeTreeWithBytes,
|
|
20
28
|
digestWith,
|
|
21
29
|
encodeAction,
|
|
22
30
|
encodeCommand,
|
|
23
31
|
encodeTree,
|
|
24
32
|
mapBounded,
|
|
33
|
+
readVarintAt,
|
|
25
34
|
sha256,
|
|
26
35
|
type Blob,
|
|
27
36
|
type FileGraft,
|
|
@@ -196,12 +205,12 @@ export function decodeExecuteResponseBytes(buf: Uint8Array): DecodedExecuteRespo
|
|
|
196
205
|
const out: DecodedExecuteResponse = { serverLogs: [] }
|
|
197
206
|
let i = 0
|
|
198
207
|
while (i < buf.length) {
|
|
199
|
-
const [key, k] =
|
|
208
|
+
const [key, k] = readVarintAt(buf, i)
|
|
200
209
|
i = k
|
|
201
210
|
const field = key >>> 3
|
|
202
211
|
const wire = key & 7
|
|
203
212
|
if (wire === 2) {
|
|
204
|
-
const [len, l] =
|
|
213
|
+
const [len, l] = readVarintAt(buf, i)
|
|
205
214
|
i = l
|
|
206
215
|
const slice = buf.subarray(i, i + len)
|
|
207
216
|
i += len
|
|
@@ -212,7 +221,7 @@ export function decodeExecuteResponseBytes(buf: Uint8Array): DecodedExecuteRespo
|
|
|
212
221
|
if (entry !== undefined) out.serverLogs.push(entry)
|
|
213
222
|
} else if (field === 5) out.message = new TextDecoder().decode(slice)
|
|
214
223
|
} else if (wire === 0) {
|
|
215
|
-
const [v, n] =
|
|
224
|
+
const [v, n] = readVarintAt(buf, i)
|
|
216
225
|
i = n
|
|
217
226
|
if (field === 2) out.cachedResult = v === 1
|
|
218
227
|
} else if (wire === 5) i += 4
|
|
@@ -227,16 +236,16 @@ function decodeRpcStatus(buf: Uint8Array): { code: number; message: string } {
|
|
|
227
236
|
const st = { code: 0, message: '' }
|
|
228
237
|
let i = 0
|
|
229
238
|
while (i < buf.length) {
|
|
230
|
-
const [key, k] =
|
|
239
|
+
const [key, k] = readVarintAt(buf, i)
|
|
231
240
|
i = k
|
|
232
241
|
const field = key >>> 3
|
|
233
242
|
const wire = key & 7
|
|
234
243
|
if (wire === 0) {
|
|
235
|
-
const [v, n] =
|
|
244
|
+
const [v, n] = readVarintAt(buf, i)
|
|
236
245
|
i = n
|
|
237
246
|
if (field === 1) st.code = v
|
|
238
247
|
} else if (wire === 2) {
|
|
239
|
-
const [len, l] =
|
|
248
|
+
const [len, l] = readVarintAt(buf, i)
|
|
240
249
|
i = l
|
|
241
250
|
if (field === 2) st.message = new TextDecoder().decode(buf.subarray(i, i + len))
|
|
242
251
|
i += len
|
|
@@ -254,10 +263,10 @@ function decodeLogEntry(
|
|
|
254
263
|
let humanReadable = false
|
|
255
264
|
let i = 0
|
|
256
265
|
while (i < buf.length) {
|
|
257
|
-
const [key, k] =
|
|
266
|
+
const [key, k] = readVarintAt(buf, i)
|
|
258
267
|
i = k
|
|
259
268
|
if ((key & 7) !== 2) break
|
|
260
|
-
const [len, l] =
|
|
269
|
+
const [len, l] = readVarintAt(buf, i)
|
|
261
270
|
i = l
|
|
262
271
|
const slice = buf.subarray(i, i + len)
|
|
263
272
|
i += len
|
|
@@ -265,15 +274,15 @@ function decodeLogEntry(
|
|
|
265
274
|
else if (key >>> 3 === 2) {
|
|
266
275
|
let j = 0
|
|
267
276
|
while (j < slice.length) {
|
|
268
|
-
const [k2, j2] =
|
|
277
|
+
const [k2, j2] = readVarintAt(slice, j)
|
|
269
278
|
j = j2
|
|
270
279
|
if ((k2 & 7) === 2) {
|
|
271
|
-
const [len2, j3] =
|
|
280
|
+
const [len2, j3] = readVarintAt(slice, j)
|
|
272
281
|
j = j3
|
|
273
|
-
if (k2 >>> 3 === 1) digest =
|
|
282
|
+
if (k2 >>> 3 === 1) digest = decodeDigestBytes(slice.subarray(j, j + len2))
|
|
274
283
|
j += len2
|
|
275
284
|
} else if ((k2 & 7) === 0) {
|
|
276
|
-
const [v, j3] =
|
|
285
|
+
const [v, j3] = readVarintAt(slice, j)
|
|
277
286
|
j = j3
|
|
278
287
|
if (k2 >>> 3 === 2) humanReadable = v === 1
|
|
279
288
|
} else break
|
|
@@ -288,16 +297,16 @@ function decodeActionResult(buf: Uint8Array): ActionResult {
|
|
|
288
297
|
const legacyLinks: { path: string; target: string }[] = []
|
|
289
298
|
let i = 0
|
|
290
299
|
while (i < buf.length) {
|
|
291
|
-
const [key, k] =
|
|
300
|
+
const [key, k] = readVarintAt(buf, i)
|
|
292
301
|
i = k
|
|
293
302
|
const field = key >>> 3
|
|
294
303
|
const wire = key & 7
|
|
295
304
|
if (wire === 0) {
|
|
296
|
-
const [v, n] =
|
|
305
|
+
const [v, n] = readVarintAt(buf, i)
|
|
297
306
|
i = n
|
|
298
307
|
if (field === 4) res.exit_code = v | 0
|
|
299
308
|
} else if (wire === 2) {
|
|
300
|
-
const [len, l] =
|
|
309
|
+
const [len, l] = readVarintAt(buf, i)
|
|
301
310
|
i = l
|
|
302
311
|
const slice = buf.subarray(i, i + len)
|
|
303
312
|
i += len
|
|
@@ -308,9 +317,9 @@ function decodeActionResult(buf: Uint8Array): ActionResult {
|
|
|
308
317
|
if (field === 2) (res.output_files ??= []).push(decodeOutputFile(slice))
|
|
309
318
|
else if (field === 3) (res.output_directories ??= []).push(decodeOutputDirectory(slice))
|
|
310
319
|
else if (field === 5) res.stdout_raw = slice
|
|
311
|
-
else if (field === 6) res.stdout_digest =
|
|
320
|
+
else if (field === 6) res.stdout_digest = decodeDigestBytes(slice)
|
|
312
321
|
else if (field === 7) res.stderr_raw = slice
|
|
313
|
-
else if (field === 8) res.stderr_digest =
|
|
322
|
+
else if (field === 8) res.stderr_digest = decodeDigestBytes(slice)
|
|
314
323
|
else if (field === 9) res.execution_metadata = decodeExecutedActionMetadata(slice)
|
|
315
324
|
else if (field === 12) (res.output_symlinks ??= []).push(decodeOutputSymlink(slice))
|
|
316
325
|
// output_file_symlinks (10) and output_directory_symlinks (11): all a
|
|
@@ -340,20 +349,20 @@ function decodeOutputFile(buf: Uint8Array): {
|
|
|
340
349
|
}
|
|
341
350
|
let i = 0
|
|
342
351
|
while (i < buf.length) {
|
|
343
|
-
const [key, k] =
|
|
352
|
+
const [key, k] = readVarintAt(buf, i)
|
|
344
353
|
i = k
|
|
345
354
|
const field = key >>> 3
|
|
346
355
|
const wire = key & 7
|
|
347
356
|
if (wire === 2) {
|
|
348
|
-
const [len, l] =
|
|
357
|
+
const [len, l] = readVarintAt(buf, i)
|
|
349
358
|
i = l
|
|
350
359
|
const slice = buf.subarray(i, i + len)
|
|
351
360
|
i += len
|
|
352
361
|
if (field === 1) out.path = PATH_UTF8.decode(slice)
|
|
353
|
-
else if (field === 2) out.digest =
|
|
362
|
+
else if (field === 2) out.digest = decodeDigestBytes(slice)
|
|
354
363
|
else if (field === 5 && len > 0) out.contents = slice
|
|
355
364
|
} else if (wire === 0) {
|
|
356
|
-
const [v, n] =
|
|
365
|
+
const [v, n] = readVarintAt(buf, i)
|
|
357
366
|
i = n
|
|
358
367
|
if (field === 4) out.is_executable = v === 1
|
|
359
368
|
} else break
|
|
@@ -366,10 +375,10 @@ function decodeOutputSymlink(buf: Uint8Array): { path: string; target: string }
|
|
|
366
375
|
const out = { path: '', target: '' }
|
|
367
376
|
let i = 0
|
|
368
377
|
while (i < buf.length) {
|
|
369
|
-
const [key, k] =
|
|
378
|
+
const [key, k] = readVarintAt(buf, i)
|
|
370
379
|
i = k
|
|
371
380
|
if ((key & 7) !== 2) break
|
|
372
|
-
const [len, l] =
|
|
381
|
+
const [len, l] = readVarintAt(buf, i)
|
|
373
382
|
i = l
|
|
374
383
|
const slice = buf.subarray(i, i + len)
|
|
375
384
|
i += len
|
|
@@ -391,12 +400,12 @@ function decodeExecutedActionMetadata(
|
|
|
391
400
|
const meta: NonNullable<ActionResult['execution_metadata']> = {}
|
|
392
401
|
let i = 0
|
|
393
402
|
while (i < buf.length) {
|
|
394
|
-
const [key, k] =
|
|
403
|
+
const [key, k] = readVarintAt(buf, i)
|
|
395
404
|
i = k
|
|
396
405
|
const field = key >>> 3
|
|
397
406
|
const wire = key & 7
|
|
398
407
|
if (wire === 2) {
|
|
399
|
-
const [len, l] =
|
|
408
|
+
const [len, l] = readVarintAt(buf, i)
|
|
400
409
|
i = l
|
|
401
410
|
const slice = buf.subarray(i, i + len)
|
|
402
411
|
i += len
|
|
@@ -404,7 +413,7 @@ function decodeExecutedActionMetadata(
|
|
|
404
413
|
else if (field === 7) meta.execution_start_timestamp = decodeTimestamp(slice)
|
|
405
414
|
else if (field === 8) meta.execution_completed_timestamp = decodeTimestamp(slice)
|
|
406
415
|
} else if (wire === 0) {
|
|
407
|
-
const [, n] =
|
|
416
|
+
const [, n] = readVarintAt(buf, i)
|
|
408
417
|
i = n
|
|
409
418
|
} else break
|
|
410
419
|
}
|
|
@@ -416,10 +425,10 @@ function decodeTimestamp(buf: Uint8Array): { seconds?: string; nanos?: number }
|
|
|
416
425
|
const ts: { seconds?: string; nanos?: number } = {}
|
|
417
426
|
let i = 0
|
|
418
427
|
while (i < buf.length) {
|
|
419
|
-
const [key, k] =
|
|
428
|
+
const [key, k] = readVarintAt(buf, i)
|
|
420
429
|
i = k
|
|
421
430
|
if ((key & 7) !== 0) break
|
|
422
|
-
const [v, n] =
|
|
431
|
+
const [v, n] = readVarintAt(buf, i)
|
|
423
432
|
i = n
|
|
424
433
|
if (key >>> 3 === 1) ts.seconds = String(v)
|
|
425
434
|
else if (key >>> 3 === 2) ts.nanos = v
|
|
@@ -434,67 +443,26 @@ function decodeOutputDirectory(buf: Uint8Array): { path: string; tree_digest: Di
|
|
|
434
443
|
const out = { path: '', tree_digest: { hash: '', size_bytes: 0 } }
|
|
435
444
|
let i = 0
|
|
436
445
|
while (i < buf.length) {
|
|
437
|
-
const [key, k] =
|
|
446
|
+
const [key, k] = readVarintAt(buf, i)
|
|
438
447
|
i = k
|
|
439
448
|
const field = key >>> 3
|
|
440
449
|
const wire = key & 7
|
|
441
450
|
if (wire === 0) {
|
|
442
|
-
const [, n] =
|
|
451
|
+
const [, n] = readVarintAt(buf, i)
|
|
443
452
|
i = n
|
|
444
453
|
continue
|
|
445
454
|
}
|
|
446
455
|
if (wire !== 2) break
|
|
447
|
-
const [len, l] =
|
|
456
|
+
const [len, l] = readVarintAt(buf, i)
|
|
448
457
|
i = l
|
|
449
458
|
const slice = buf.subarray(i, i + len)
|
|
450
459
|
i += len
|
|
451
460
|
if (field === 1) out.path = PATH_UTF8.decode(slice)
|
|
452
|
-
else if (field === 3) out.tree_digest =
|
|
461
|
+
else if (field === 3) out.tree_digest = decodeDigestBytes(slice)
|
|
453
462
|
}
|
|
454
463
|
return out
|
|
455
464
|
}
|
|
456
465
|
|
|
457
|
-
function decodeDigest(buf: Uint8Array): Digest {
|
|
458
|
-
const d: Digest = { hash: '', size_bytes: 0 }
|
|
459
|
-
let i = 0
|
|
460
|
-
while (i < buf.length) {
|
|
461
|
-
const [key, k] = readVarint(buf, i)
|
|
462
|
-
i = k
|
|
463
|
-
const field = key >>> 3
|
|
464
|
-
const wire = key & 7
|
|
465
|
-
if (wire === 2) {
|
|
466
|
-
const [len, l] = readVarint(buf, i)
|
|
467
|
-
i = l
|
|
468
|
-
if (field === 1) d.hash = new TextDecoder().decode(buf.subarray(i, i + len))
|
|
469
|
-
i += len
|
|
470
|
-
} else if (wire === 0) {
|
|
471
|
-
const [v, n] = readVarint(buf, i)
|
|
472
|
-
i = n
|
|
473
|
-
if (field === 2) d.size_bytes = v
|
|
474
|
-
} else break
|
|
475
|
-
}
|
|
476
|
-
return d
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
function readVarint(buf: Uint8Array, at: number): [number, number] {
|
|
480
|
-
let result = 0
|
|
481
|
-
let low = 0
|
|
482
|
-
let shift = 0
|
|
483
|
-
let i = at
|
|
484
|
-
for (;;) {
|
|
485
|
-
const byte = buf[i++]
|
|
486
|
-
if (byte === undefined) break
|
|
487
|
-
// Added, not OR-ed: a size of 4 GiB or more wrapped to 32 bits (F-43).
|
|
488
|
-
// Past 2^53 the value is a negative int32 sent as ten bytes (an exit
|
|
489
|
-
// code): its low 32 bits, which `| 0` reads back as the negative.
|
|
490
|
-
result += (byte & 0x7f) * 2 ** shift
|
|
491
|
-
if (shift < 32) low |= (byte & 0x7f) << shift
|
|
492
|
-
if ((byte & 0x80) === 0) break
|
|
493
|
-
shift += 7
|
|
494
|
-
}
|
|
495
|
-
return [result <= Number.MAX_SAFE_INTEGER ? result : low >>> 0, i]
|
|
496
|
-
}
|
|
497
|
-
|
|
498
466
|
/**
|
|
499
467
|
* Backstop for an action the server never finishes. Generous on purpose: it
|
|
500
468
|
* exists so a wedged remote cannot hang a run forever, not to police slow
|
|
@@ -1252,12 +1220,9 @@ async function this_readStream(
|
|
|
1252
1220
|
return ''
|
|
1253
1221
|
}
|
|
1254
1222
|
|
|
1255
|
-
/** Forwarded args are
|
|
1223
|
+
/** Forwarded args are placed by core's own `withForwardArgs`, as the local executor's are. */
|
|
1256
1224
|
function fullCommand(req: ExecuteRequest, cdInto: string, projectRel: string): string {
|
|
1257
|
-
const
|
|
1258
|
-
req.forwardArgs.length === 0
|
|
1259
|
-
? req.command
|
|
1260
|
-
: `${req.command} ${req.forwardArgs.map((a) => `'${a.replaceAll("'", `'\\''`)}'`).join(' ')}`
|
|
1225
|
+
const command = withForwardArgs(req.command, req.forwardArgs)
|
|
1261
1226
|
// A remote action gets NO PATH from this machine — sending one would put a
|
|
1262
1227
|
// host path in the action digest and split every laptop from every runner.
|
|
1263
1228
|
// But a task's command is normally a package binary (`oxlint`, `tsc`), and
|
|
@@ -1285,7 +1250,7 @@ function fullCommand(req: ExecuteRequest, cdInto: string, projectRel: string): s
|
|
|
1285
1250
|
return (
|
|
1286
1251
|
`VX_ROOT=${root}; ${cd}` +
|
|
1287
1252
|
`export PATH="$VX_ROOT/node_modules/.bin:$PWD/node_modules/.bin:$PATH"; ` +
|
|
1288
|
-
|
|
1253
|
+
command
|
|
1289
1254
|
)
|
|
1290
1255
|
}
|
|
1291
1256
|
|
package/src/merkle.ts
CHANGED
|
@@ -828,7 +828,7 @@ function decodeSymlinkNode(buf: Uint8Array): SymlinkNode {
|
|
|
828
828
|
return sl
|
|
829
829
|
}
|
|
830
830
|
|
|
831
|
-
function decodeDigestBytes(buf: Uint8Array): Digest {
|
|
831
|
+
export function decodeDigestBytes(buf: Uint8Array): Digest {
|
|
832
832
|
const d: Digest = { hash: '', size_bytes: 0 }
|
|
833
833
|
let i = 0
|
|
834
834
|
while (i < buf.length) {
|
|
@@ -850,7 +850,7 @@ function decodeDigestBytes(buf: Uint8Array): Digest {
|
|
|
850
850
|
return d
|
|
851
851
|
}
|
|
852
852
|
|
|
853
|
-
function readVarintAt(buf: Uint8Array, at: number): [number, number] {
|
|
853
|
+
export function readVarintAt(buf: Uint8Array, at: number): [number, number] {
|
|
854
854
|
let result = 0
|
|
855
855
|
let low = 0
|
|
856
856
|
let shift = 0
|
package/src/wire.ts
CHANGED
|
@@ -1002,6 +1002,11 @@ export class ReapiClient {
|
|
|
1002
1002
|
)
|
|
1003
1003
|
}
|
|
1004
1004
|
|
|
1005
|
+
/** The largest `Blob` `writeBlob` reads whole rather than streams. */
|
|
1006
|
+
get wholeWriteBytes(): number {
|
|
1007
|
+
return this.negotiatedBatchBytes || SAFE_BATCH_BYTES
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1005
1010
|
/**
|
|
1006
1011
|
* Upload a blob via ByteStream, chunked at `chunkBytes`, RESUMING an
|
|
1007
1012
|
* interrupted identity upload from the server's committed offset
|
|
@@ -1017,8 +1022,7 @@ export class ReapiClient {
|
|
|
1017
1022
|
* zstd artifact already. A Blob under the limit is small enough to read.
|
|
1018
1023
|
*/
|
|
1019
1024
|
async writeBlob(digest: Digest, source: Uint8Array | Blob): Promise<void> {
|
|
1020
|
-
const streamed =
|
|
1021
|
-
source instanceof Blob && source.size > (this.negotiatedBatchBytes || SAFE_BATCH_BYTES)
|
|
1025
|
+
const streamed = source instanceof Blob && source.size > this.wholeWriteBytes
|
|
1022
1026
|
const body = source instanceof Blob && !streamed ? await source.bytes() : source
|
|
1023
1027
|
const compressed = this.compression && body instanceof Uint8Array
|
|
1024
1028
|
// REAPI carries compression in the RESOURCE NAME:
|