@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 +2 -49
- package/index.d.ts +3 -0
- package/lib/client.js +25 -5
- package/package.json +14 -8
- package/utils/retry.js +29 -0
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/
|
|
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/
|
|
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('
|
|
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
|
|
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
|
|
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.
|
|
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/
|
|
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/
|
|
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.
|
|
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 }
|