@qvac/registry-client 0.4.0 → 0.4.1

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
package/index.d.ts CHANGED
@@ -66,6 +66,7 @@ export interface QVACRegistryClientOptions {
66
66
  storage?: string
67
67
  registryCoreKey?: string
68
68
  logger?: any
69
+ corestoreOpts?: { wait?: boolean }
69
70
  }
70
71
 
71
72
  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')
@@ -257,7 +260,15 @@ class QVACRegistryClient extends ReadyResource {
257
260
 
258
261
  let artifact
259
262
  if (options.outputFile) {
260
- await this._streamBlobToFile(blobs, core, model.blobBinding, options.outputFile, options)
263
+ await withRetry(
264
+ () => this._streamBlobToFile(blobs, core, model.blobBinding, options.outputFile, options),
265
+ {
266
+ maxRetries: options.maxRetries != null ? options.maxRetries : DEFAULT_DOWNLOAD_MAX_RETRIES,
267
+ retryCodes: RETRIABLE_DOWNLOAD_CODES,
268
+ onRetry: () => fs.promises.unlink(options.outputFile).catch(() => {}),
269
+ logger: this.logger
270
+ }
271
+ )
261
272
  artifact = { path: options.outputFile, totalSize }
262
273
 
263
274
  rangeDownload.destroy()
@@ -381,7 +392,15 @@ class QVACRegistryClient extends ReadyResource {
381
392
 
382
393
  let artifact
383
394
  if (options.outputFile) {
384
- await this._streamBlobToFile(blobs, core, pointer, options.outputFile, options)
395
+ await withRetry(
396
+ () => this._streamBlobToFile(blobs, core, pointer, options.outputFile, options),
397
+ {
398
+ maxRetries: options.maxRetries != null ? options.maxRetries : DEFAULT_DOWNLOAD_MAX_RETRIES,
399
+ retryCodes: RETRIABLE_DOWNLOAD_CODES,
400
+ onRetry: () => fs.promises.unlink(options.outputFile).catch(() => {}),
401
+ logger: this.logger
402
+ }
403
+ )
385
404
  artifact = { path: options.outputFile, totalSize }
386
405
 
387
406
  rangeDownload.destroy()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qvac/registry-client",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "QVAC Registry client library for read-only queries via Hyperswarm",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
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 }