@qvac/registry-client 0.4.0 → 0.5.0

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/NOTICE CHANGED
@@ -51,42 +51,6 @@ Third-Party Model Licenses
51
51
  https://huggingface.co/personalizedrefrigerator/whisper-base-fr
52
52
  fr-tiny-ggml-model-f16
53
53
  https://huggingface.co/JaepaX/whisper-tiny-fr
54
- ggml-opus-ar-en
55
- https://huggingface.co/Helsinki-NLP/opus-mt-ar-en
56
- ggml-opus-de-en
57
- https://huggingface.co/Helsinki-NLP/opus-mt-de-en
58
- ggml-opus-de-fr
59
- https://huggingface.co/Helsinki-NLP/opus-mt-de-fr
60
- ggml-opus-en-ar
61
- https://huggingface.co/Helsinki-NLP/opus-mt-en-ar
62
- ggml-opus-en-es
63
- https://huggingface.co/Helsinki-NLP/opus-mt-en-es
64
- ggml-opus-en-fr
65
- https://huggingface.co/Helsinki-NLP/opus-mt-en-fr
66
- ggml-opus-en-it
67
- https://huggingface.co/Helsinki-NLP/opus-mt-en-it
68
- ggml-opus-en-ru
69
- https://huggingface.co/Helsinki-NLP/opus-mt-en-ru
70
- ggml-opus-en-zh
71
- https://huggingface.co/Helsinki-NLP/opus-mt-en-zh
72
- ggml-opus-es-en
73
- https://huggingface.co/Helsinki-NLP/opus-mt-es-en
74
- ggml-opus-es-fr
75
- https://huggingface.co/Helsinki-NLP/opus-mt-es-fr
76
- ggml-opus-fr-de
77
- https://huggingface.co/Helsinki-NLP/opus-mt-fr-de
78
- ggml-opus-fr-en
79
- https://huggingface.co/Helsinki-NLP/opus-mt-fr-en
80
- ggml-opus-fr-es
81
- https://huggingface.co/Helsinki-NLP/opus-mt-fr-es
82
- ggml-opus-it-en
83
- https://huggingface.co/Helsinki-NLP/opus-mt-it-en
84
- ggml-opus-ja-en
85
- https://huggingface.co/Helsinki-NLP/opus-mt-ja-en
86
- ggml-opus-mt-en-roa-f16
87
- https://huggingface.co/Helsinki-NLP/opus-mt-en-roa
88
- ggml-opus-mt-roa-en-f16
89
- https://huggingface.co/Helsinki-NLP/opus-mt-roa-en
90
54
  gpt-oss-20b-GGUF
91
55
  https://huggingface.co/unsloth/gpt-oss-20b-GGUF
92
56
  it-base-ggml-model-f16
@@ -128,17 +92,6 @@ Third-Party Model Licenses
128
92
  SmolVLM2-500M-Video-Instruct-GGUF
129
93
  https://huggingface.co/ggml-org/SmolVLM2-500M-Video-Instruct-GGUF
130
94
 
131
- --- cc-by-4.0 (Creative Commons Attribution 4.0 International) ---
132
-
133
- ggml-opus-en-de
134
- https://huggingface.co/Helsinki-NLP/opus-mt-en-de
135
- ggml-opus-en-pt
136
- https://huggingface.co/Helsinki-NLP/opus-mt-tc-big-en-pt
137
- ggml-opus-ru-en
138
- https://huggingface.co/Helsinki-NLP/opus-mt-ru-en
139
- ggml-opus-zh-en
140
- https://huggingface.co/Helsinki-NLP/opus-mt-zh-en
141
-
142
95
  --- gemma (Gemma Terms of Use) ---
143
96
 
144
97
  embeddinggemma-300m-GGUF
@@ -202,7 +155,7 @@ Third-Party Model Licenses
202
155
  lex.50.50.enfr.s2t
203
156
  https://github.com/mozilla/firefox-translations-models/tree/main/models/base-memory/enfr
204
157
  lex.50.50.enit.s2t
205
- https://github.com/mozilla/firefox-translations-models/tree/main/models/tiny/enit
158
+ https://github.com/mozilla/firefox-translations-models/tree/main/models/base-memory/enit
206
159
  lex.50.50.enja.s2t
207
160
  https://github.com/mozilla/firefox-translations-models/tree/main/models/base-memory/enja
208
161
  lex.50.50.enpt.s2t
@@ -212,7 +165,7 @@ Third-Party Model Licenses
212
165
  lex.50.50.enzh.s2t
213
166
  https://github.com/mozilla/firefox-translations-models/tree/main/models/base-memory/enzh
214
167
  lex.50.50.esen.s2t
215
- https://github.com/mozilla/firefox-translations-models/tree/main/models/tiny/esen
168
+ https://github.com/mozilla/firefox-translations-models/tree/main/models/base-memory/esen
216
169
  lex.50.50.fren.s2t
217
170
  https://github.com/mozilla/firefox-translations-models/tree/main/models/base-memory/fren
218
171
  lex.50.50.iten.s2t
package/index.d.ts CHANGED
@@ -46,6 +46,7 @@ export interface QVACDownloadResult {
46
46
  export interface QVACDownloadOptions {
47
47
  timeout?: number
48
48
  peerTimeout?: number
49
+ maxRetries?: number
49
50
  outputFile?: string
50
51
  onProgress?: (progress: { downloaded: number, total: number, cachedBlocks: number, totalBlocks: number }) => void
51
52
  signal?: AbortSignal
@@ -53,6 +54,7 @@ export interface QVACDownloadOptions {
53
54
 
54
55
  export interface QVACBlobDownloadOptions {
55
56
  timeout?: number
57
+ maxRetries?: number
56
58
  outputFile?: string
57
59
  onProgress?: (progress: { downloaded: number, total: number, cachedBlocks: number, totalBlocks: number }) => void
58
60
  signal?: AbortSignal
@@ -66,6 +68,7 @@ export interface QVACRegistryClientOptions {
66
68
  storage?: string
67
69
  registryCoreKey?: string
68
70
  logger?: any
71
+ corestoreOpts?: { wait?: boolean }
69
72
  }
70
73
 
71
74
  export interface QVACModelQuery {
package/lib/client.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { QvacErrorRegistryClient, ERR_CODES } = require('../utils/error')
4
+ const { withRetry } = require('../utils/retry')
4
5
  const RegistryConfig = require('./config')
5
6
  const { RegistryDatabase } = require('@qvac/registry-schema')
6
7
  const ReadyResource = require('ready-resource')
@@ -12,6 +13,9 @@ const IdEnc = require('hypercore-id-encoding')
12
13
  const path = require('#path')
13
14
  const fs = require('#fs')
14
15
 
16
+ const DEFAULT_DOWNLOAD_MAX_RETRIES = 3
17
+ const RETRIABLE_DOWNLOAD_CODES = ['REQUEST_TIMEOUT']
18
+
15
19
  class QVACRegistryClient extends ReadyResource {
16
20
  constructor (opts = {}) {
17
21
  super()
@@ -20,13 +24,13 @@ class QVACRegistryClient extends ReadyResource {
20
24
  this.registryConfig = new RegistryConfig({ logger: this.logger })
21
25
 
22
26
  this.db = null
23
- this.corestore = null
24
27
  this.hyperswarm = null
25
28
  this._connectionHandler = null
26
29
  this._metadataReady = null
27
30
 
28
31
  this.storage = this.registryConfig.getRegistryStorage(opts.storage)
29
32
  this.registryCoreKey = this.registryConfig.getRegistryCoreKey(opts.registryCoreKey)
33
+ this.corestore = new Corestore(this.storage, opts.corestoreOpts || {})
30
34
 
31
35
  this.logger.debug('Initializing QVAC Registry Client', {
32
36
  mode: 'read',
@@ -39,8 +43,7 @@ class QVACRegistryClient extends ReadyResource {
39
43
  async _open () {
40
44
  this.logger.debug('_open called')
41
45
 
42
- this.logger.debug('Creating corestore for open')
43
- this.corestore = new Corestore(this.storage)
46
+ this.logger.debug('Opening corestore')
44
47
  await this.corestore.ready()
45
48
 
46
49
  this.logger.debug('Creating Hyperswarm for open')
@@ -53,6 +56,7 @@ class QVACRegistryClient extends ReadyResource {
53
56
  this.hyperswarm.on('connection', this._connectionHandler)
54
57
 
55
58
  this._metadataReady = this._connectMetadataCore()
59
+ await this._metadataReady
56
60
  }
57
61
 
58
62
  async _connectMetadataCore () {
@@ -257,7 +261,15 @@ class QVACRegistryClient extends ReadyResource {
257
261
 
258
262
  let artifact
259
263
  if (options.outputFile) {
260
- await this._streamBlobToFile(blobs, core, model.blobBinding, options.outputFile, options)
264
+ await withRetry(
265
+ () => this._streamBlobToFile(blobs, core, model.blobBinding, options.outputFile, options),
266
+ {
267
+ maxRetries: options.maxRetries != null ? options.maxRetries : DEFAULT_DOWNLOAD_MAX_RETRIES,
268
+ retryCodes: RETRIABLE_DOWNLOAD_CODES,
269
+ onRetry: () => fs.promises.unlink(options.outputFile).catch(() => {}),
270
+ logger: this.logger
271
+ }
272
+ )
261
273
  artifact = { path: options.outputFile, totalSize }
262
274
 
263
275
  rangeDownload.destroy()
@@ -381,7 +393,15 @@ class QVACRegistryClient extends ReadyResource {
381
393
 
382
394
  let artifact
383
395
  if (options.outputFile) {
384
- await this._streamBlobToFile(blobs, core, pointer, options.outputFile, options)
396
+ await withRetry(
397
+ () => this._streamBlobToFile(blobs, core, pointer, options.outputFile, options),
398
+ {
399
+ maxRetries: options.maxRetries != null ? options.maxRetries : DEFAULT_DOWNLOAD_MAX_RETRIES,
400
+ retryCodes: RETRIABLE_DOWNLOAD_CODES,
401
+ onRetry: () => fs.promises.unlink(options.outputFile).catch(() => {}),
402
+ logger: this.logger
403
+ }
404
+ )
385
405
  artifact = { path: options.outputFile, totalSize }
386
406
 
387
407
  rangeDownload.destroy()
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@qvac/registry-client",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "QVAC Registry client library for read-only queries via Hyperswarm",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/tetherto/qvac.git",
9
- "directory": "packages/qvac-lib-registry-server/client"
9
+ "directory": "packages/registry-server/client"
10
10
  },
11
11
  "bugs": "https://github.com/tetherto/qvac/issues",
12
- "homepage": "https://github.com/tetherto/qvac/tree/main/packages/qvac-lib-registry-server/client#readme",
12
+ "homepage": "https://github.com/tetherto/qvac/tree/main/packages/registry-server/client#readme",
13
13
  "type": "commonjs",
14
14
  "main": "index.js",
15
15
  "bin": {
@@ -53,26 +53,32 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@qvac/error": "^0.1.0",
56
- "@qvac/registry-schema": "^0.1.2",
56
+ "@qvac/registry-schema": "^0.2.0",
57
57
  "b4a": "^1.6.7",
58
58
  "bare-fs": "^4.5.2",
59
59
  "bare-os": "^3.6.2",
60
60
  "bare-path": "^3.0.0",
61
61
  "bare-process": "^4.2.2",
62
- "corestore": "^7.4.5",
63
- "hyperblobs": "^2.8.0",
64
62
  "hypercore-id-encoding": "^1.3.0",
65
63
  "hypercore-stats": "^2.4.0",
66
- "hyperdb": "^4.16.1",
67
- "hyperswarm": "^4.14.0",
68
64
  "hyperswarm-stats": "^1.3.0",
69
65
  "paparam": "^1.10.0",
70
66
  "ready-resource": "^1.0.1",
71
67
  "tiny-byte-size": "^1.1.0"
72
68
  },
69
+ "peerDependencies": {
70
+ "corestore": "^7.4.5",
71
+ "hyperblobs": "^2.8.0",
72
+ "hyperdb": "^4.16.1",
73
+ "hyperswarm": "^4.14.0"
74
+ },
73
75
  "devDependencies": {
74
76
  "brittle": "^3.4.0",
77
+ "corestore": "^7.4.5",
75
78
  "dotenv": "^17.2.3",
79
+ "hyperblobs": "^2.8.0",
80
+ "hyperdb": "^4.16.1",
81
+ "hyperswarm": "^4.14.0",
76
82
  "standard": "^17.1.0",
77
83
  "test-tmp": "^1.4.0",
78
84
  "typescript": "^5.9.3"
package/utils/retry.js ADDED
@@ -0,0 +1,29 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * Executes an async function with automatic retry on specific error codes.
5
+ *
6
+ * @param {() => Promise<unknown>} fn - The async operation to attempt
7
+ * @param {object} opts
8
+ * @param {number} [opts.maxRetries=3] - Maximum number of attempts (including the first)
9
+ * @param {string[]} [opts.retryCodes=[]] - Error codes that trigger a retry
10
+ * @param {() => Promise<void>} [opts.onRetry] - Called before each retry attempt (e.g. cleanup)
11
+ * @param {{ warn: Function }} [opts.logger] - Logger instance for retry warnings
12
+ * @returns {Promise<unknown>}
13
+ */
14
+ async function withRetry (fn, opts = {}) {
15
+ const { maxRetries = 3, retryCodes = [], onRetry, logger } = opts
16
+
17
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
18
+ try {
19
+ return await fn()
20
+ } catch (err) {
21
+ const isRetriable = retryCodes.length > 0 && retryCodes.includes(err && err.code)
22
+ if (!isRetriable || attempt >= maxRetries) throw err
23
+ logger && logger.warn(`Retrying after ${err.code} (attempt ${attempt}/${maxRetries}): ${err.message}`)
24
+ if (onRetry) await onRetry()
25
+ }
26
+ }
27
+ }
28
+
29
+ module.exports = { withRetry }