@qvac/sdk 0.2.7-dev.1761566029.f834aa3 → 0.3.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/README.md CHANGED
@@ -79,7 +79,7 @@ npm i expo-file-system react-native-bare-kit
79
79
  ```js
80
80
  export default {
81
81
  expo: {
82
- plugins: ["qvac-sdk/expo-plugin"],
82
+ plugins: ["@qvac/sdk/expo-plugin"],
83
83
  },
84
84
  };
85
85
  ```
@@ -141,6 +141,7 @@ const cachedResponse = completion({
141
141
 
142
142
  // Unload model to free up system resources
143
143
  await unloadModel({ modelId });
144
+ process.exit();
144
145
  ```
145
146
 
146
147
  **For more on how to use QVAC SDK, see [SDK at QVAC documentation](https://tether-2.gitbook.io/qvac-by-tether-or-reference/y2AsIh94H9DJ1pIBCNj9/sdk)**.
@@ -161,10 +162,10 @@ bun run build # or `watch` for hotreload
161
162
  bun run build:pack
162
163
  ```
163
164
 
164
- This outputs a tarball under `dist/tetherto-qvac-sdk-{version}.tgz` that you can install in your project, e.g.:
165
+ This outputs a tarball under `dist/qvac-sdk-{version}.tgz` that you can install in your project, e.g.:
165
166
 
166
167
  ```bash
167
- npm i path/to/tetherto-qvac-sdk-0.0.1.tgz
168
+ npm i path/to/qvac-sdk-0.3.0.tgz
168
169
  ```
169
170
 
170
171
  ## Examples
@@ -10,5 +10,6 @@ export { embed } from "./embed";
10
10
  export { translate } from "./translate";
11
11
  export { cancel } from "./cancel";
12
12
  export { startQVACProvider } from "./provide";
13
+ export { stopQVACProvider } from "./stop-provider";
13
14
  export { ragSaveEmbeddings, ragSearch, ragDeleteEmbeddings } from "./rag";
14
15
  //# sourceMappingURL=index.d.ts.map
@@ -10,4 +10,5 @@ export { embed } from "./embed.js";
10
10
  export { translate } from "./translate.js";
11
11
  export { cancel } from "./cancel.js";
12
12
  export { startQVACProvider } from "./provide.js";
13
+ export { stopQVACProvider } from "./stop-provider.js";
13
14
  export { ragSaveEmbeddings, ragSearch, ragDeleteEmbeddings } from "./rag.js";
@@ -0,0 +1,15 @@
1
+ import { type StopProvideParams } from "../../schemas/index";
2
+ /**
3
+ * Stops a running provider service and leaves the specified topic.
4
+ *
5
+ * @param options - Options object with required topic
6
+ * @param options.topic - Topic hex string to leave
7
+ * @returns A promise that resolves to the stop provide response containing success status
8
+ * @throws {Error} When the response type is not "stopProvide" or the request fails
9
+ */
10
+ export declare function stopQVACProvider(params: StopProvideParams): Promise<{
11
+ type: "stopProvide";
12
+ success: boolean;
13
+ error?: string | undefined;
14
+ }>;
15
+ //# sourceMappingURL=stop-provider.d.ts.map
@@ -0,0 +1,24 @@
1
+ import {} from "../../schemas/index.js";
2
+ import { send } from "../rpc/rpc-client.js";
3
+ /**
4
+ * Stops a running provider service and leaves the specified topic.
5
+ *
6
+ * @param options - Options object with required topic
7
+ * @param options.topic - Topic hex string to leave
8
+ * @returns A promise that resolves to the stop provide response containing success status
9
+ * @throws {Error} When the response type is not "stopProvide" or the request fails
10
+ */
11
+ export async function stopQVACProvider(params) {
12
+ const request = {
13
+ type: "stopProvide",
14
+ topic: params.topic,
15
+ };
16
+ const response = await send(request);
17
+ if (response.type !== "stopProvide") {
18
+ throw new Error("Invalid response type");
19
+ }
20
+ if (response.error) {
21
+ throw new Error(response.error);
22
+ }
23
+ return response;
24
+ }
@@ -51,6 +51,10 @@ export declare function stream<T extends Request>(request: T): AsyncGenerator<{
51
51
  success: boolean;
52
52
  error?: string | undefined;
53
53
  publicKey?: string | undefined;
54
+ } | {
55
+ type: "stopProvide";
56
+ success: boolean;
57
+ error?: string | undefined;
54
58
  } | {
55
59
  type: "unloadModel";
56
60
  success: boolean;
@@ -2,6 +2,11 @@ import { requestSchema, responseSchema, } from "../../schemas/index.js";
2
2
  import { RPCError } from "./rpc-error.js";
3
3
  import { withTimeout, withTimeoutStream } from "../../utils/withTimeout.js";
4
4
  let rpcInstance = null;
5
+ let commandCounter = 0;
6
+ function getNextCommandId() {
7
+ commandCounter = (commandCounter + 1) % Number.MAX_SAFE_INTEGER;
8
+ return commandCounter;
9
+ }
5
10
  function checkAndThrowError(response) {
6
11
  if (response.type === "error") {
7
12
  throw new RPCError(response);
@@ -41,7 +46,7 @@ async function getRPC() {
41
46
  export async function send(request, rpc, options) {
42
47
  const parsedRequest = requestSchema.parse(request);
43
48
  const rpcInstance = rpc || (await getRPC());
44
- const req = rpcInstance.request(1);
49
+ const req = rpcInstance.request(getNextCommandId());
45
50
  // TODO temp for debugging, find a better solution to exclude large payloads
46
51
  // Log request type and basic info, avoid logging large payloads
47
52
  if (request.type === "transcribeStream") {
@@ -65,7 +70,7 @@ export async function send(request, rpc, options) {
65
70
  export async function* stream(request, rpc, options = {}) {
66
71
  const parsedRequest = requestSchema.parse(request);
67
72
  const rpcInstance = rpc || (await getRPC());
68
- const req = rpcInstance.request(1);
73
+ const req = rpcInstance.request(getNextCommandId());
69
74
  req.send(JSON.stringify(parsedRequest), "utf-8");
70
75
  const responseStream = req.createResponseStream({ encoding: "utf-8" });
71
76
  let buffer = "";
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { completion, deleteCache, loadModel, downloadAsset, ping, startQVACProvider, unloadModel, transcribe, transcribeStream, embed, translate, cancel, ragSaveEmbeddings, ragSearch, ragDeleteEmbeddings, } from "./client/api/index";
1
+ export { completion, deleteCache, loadModel, downloadAsset, ping, startQVACProvider, stopQVACProvider, unloadModel, transcribe, transcribeStream, embed, translate, cancel, ragSaveEmbeddings, ragSearch, ragDeleteEmbeddings, } from "./client/api/index";
2
2
  export { type ModelProgressUpdate, type LoadModelOptions, type DownloadAssetOptions, type Tool, VERBOSITY, type Attachment, type CompletionParams, type RagSearchResult, type RagSaveEmbeddingsResult, } from "./schemas/index";
3
3
  export * from "./models/hyperdrive/index";
4
4
  export { SUPPORTED_AUDIO_FORMATS } from "./constants/audio";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Public API exports only
2
- export { completion, deleteCache, loadModel, downloadAsset, ping, startQVACProvider, unloadModel, transcribe, transcribeStream, embed, translate, cancel, ragSaveEmbeddings, ragSearch, ragDeleteEmbeddings, } from "./client/api/index.js";
2
+ export { completion, deleteCache, loadModel, downloadAsset, ping, startQVACProvider, stopQVACProvider, unloadModel, transcribe, transcribeStream, embed, translate, cancel, ragSaveEmbeddings, ragSearch, ragDeleteEmbeddings, } from "./client/api/index.js";
3
3
  export { VERBOSITY, } from "./schemas/index.js";
4
4
  // Hyperdrive model constants
5
5
  export * from "./models/hyperdrive/index.js";
@@ -426,6 +426,13 @@ export declare const models: readonly [{
426
426
  readonly addon: "vad";
427
427
  readonly expectedSize: 885098;
428
428
  readonly sha256Checksum: "29940d98d42b91fbd05ce489f3ecf7c72f0a42f027e4875919a28fb4c04ea2cf";
429
+ }, {
430
+ readonly hyperdriveKey: "19aaf2bc2685d2be2e001af0abf2a5d07d13b78f1a234fb75bf9fc2d07ee7f1d";
431
+ readonly hyperbeeKey: "transcription:whisper-norwegian:tiny-ggml::::1.0.0:norwegian";
432
+ readonly modelId: "nb-tiny-ggml-model.bin";
433
+ readonly addon: "whisper";
434
+ readonly expectedSize: 77691730;
435
+ readonly sha256Checksum: "2f9dd799ee36b6a9c8d642e9b1df8ecf2135efdd5a91b1d9ca0b3c0decda535f";
429
436
  }, {
430
437
  readonly hyperdriveKey: "76fb36d7f16a430618962d3e78b0e22e61aa527a9e937335188d08858aaa9075";
431
438
  readonly hyperbeeKey: "transcription:whisper:large:3:::1.0.0:silero";
@@ -515,9 +522,10 @@ export declare const MARIAN_OPUS_RU_EN_Q4_0: "pear://47b2ec9c205a8624bb7460d9a7d
515
522
  export declare const MARIAN_OPUS_EN_JA_Q4F16_1: "pear://2e6e274e9bb86774a64880ccd89660d3d5d5901f0bf39116d460350b06adb3a3/ggml-opus-en-ja.bin";
516
523
  export declare const MARIAN_OPUS_JA_EN_Q4F16_1: "pear://0e795244ad5cf38dac6fe28deec8f97b37c95907d734a50f620670dc9d0a8e5b/ggml-opus-ja-en.bin";
517
524
  export declare const VAD_SILERO_5_1_2: "pear://60a19f1065c355df49c753b16cea075863ebbfdd330caca8b3ea6a337026fc7d/ggml-silero-v5.1.2.bin";
525
+ export declare const WHISPER_NORWEGIAN_TINY: "pear://19aaf2bc2685d2be2e001af0abf2a5d07d13b78f1a234fb75bf9fc2d07ee7f1d/nb-tiny-ggml-model.bin";
518
526
  export declare const WHISPER_LARGE_3: "pear://76fb36d7f16a430618962d3e78b0e22e61aa527a9e937335188d08858aaa9075/ggml-large-v3-turbo.bin";
519
527
  export declare const WHISPER_SMALL: "pear://c6a987fbb4ad8fba1526e446501f88ee45dfafbf1685410a7aeadb589fe18608/ggml-small.en-q8_0.bin";
520
528
  export declare const WHISPER_TINY: "pear://9281d61503593fdf3eaa9d5e5d44746c271ef930aed3b7f8ee9ce153c76399d6/ggml-tiny.bin";
521
529
  export declare const WHISPER_TINY_SILERO: "pear://ebfb94b378276da139554668f1ff737644eadff529c2ea0f2662d7df61fd86ca/ggml-tiny.bin";
522
- export declare function getModelBySrc(modelId: string, hyperdriveKey?: string): HyperdriveItem | undefined;
530
+ export declare function getModelBySrc(modelId: string, hyperdriveKey: string): HyperdriveItem | undefined;
523
531
  //# sourceMappingURL=models.d.ts.map
@@ -481,6 +481,14 @@ export const models = [
481
481
  expectedSize: 885098,
482
482
  sha256Checksum: "29940d98d42b91fbd05ce489f3ecf7c72f0a42f027e4875919a28fb4c04ea2cf",
483
483
  },
484
+ {
485
+ hyperdriveKey: "19aaf2bc2685d2be2e001af0abf2a5d07d13b78f1a234fb75bf9fc2d07ee7f1d",
486
+ hyperbeeKey: "transcription:whisper-norwegian:tiny-ggml::::1.0.0:norwegian",
487
+ modelId: "nb-tiny-ggml-model.bin",
488
+ addon: "whisper",
489
+ expectedSize: 77691730,
490
+ sha256Checksum: "2f9dd799ee36b6a9c8d642e9b1df8ecf2135efdd5a91b1d9ca0b3c0decda535f",
491
+ },
484
492
  {
485
493
  hyperdriveKey: "76fb36d7f16a430618962d3e78b0e22e61aa527a9e937335188d08858aaa9075",
486
494
  hyperbeeKey: "transcription:whisper:large:3:::1.0.0:silero",
@@ -575,14 +583,12 @@ export const MARIAN_OPUS_RU_EN_Q4_0 = `pear://${models[56].hyperdriveKey}/${mode
575
583
  export const MARIAN_OPUS_EN_JA_Q4F16_1 = `pear://${models[57].hyperdriveKey}/${models[57].modelId}`;
576
584
  export const MARIAN_OPUS_JA_EN_Q4F16_1 = `pear://${models[58].hyperdriveKey}/${models[58].modelId}`;
577
585
  export const VAD_SILERO_5_1_2 = `pear://${models[59].hyperdriveKey}/${models[59].modelId}`;
578
- export const WHISPER_LARGE_3 = `pear://${models[60].hyperdriveKey}/${models[60].modelId}`;
579
- export const WHISPER_SMALL = `pear://${models[61].hyperdriveKey}/${models[61].modelId}`;
580
- export const WHISPER_TINY = `pear://${models[62].hyperdriveKey}/${models[62].modelId}`;
581
- export const WHISPER_TINY_SILERO = `pear://${models[63].hyperdriveKey}/${models[63].modelId}`;
586
+ export const WHISPER_NORWEGIAN_TINY = `pear://${models[60].hyperdriveKey}/${models[60].modelId}`;
587
+ export const WHISPER_LARGE_3 = `pear://${models[61].hyperdriveKey}/${models[61].modelId}`;
588
+ export const WHISPER_SMALL = `pear://${models[62].hyperdriveKey}/${models[62].modelId}`;
589
+ export const WHISPER_TINY = `pear://${models[63].hyperdriveKey}/${models[63].modelId}`;
590
+ export const WHISPER_TINY_SILERO = `pear://${models[64].hyperdriveKey}/${models[64].modelId}`;
582
591
  // Helper function for our curated model list
583
592
  export function getModelBySrc(modelId, hyperdriveKey) {
584
- if (hyperdriveKey) {
585
- return models.find((model) => model.modelId === modelId && model.hyperdriveKey === hyperdriveKey);
586
- }
587
- return models.find((model) => model.modelId === modelId);
593
+ return models.find((model) => model.modelId === modelId && model.hyperdriveKey === hyperdriveKey);
588
594
  }
@@ -473,6 +473,9 @@ export declare const requestSchema: z.ZodUnion<readonly [z.ZodObject<{
473
473
  }>>;
474
474
  publicKeys: z.ZodDefault<z.ZodArray<z.ZodString>>;
475
475
  }, z.core.$strip>>;
476
+ }, z.core.$strict>, z.ZodObject<{
477
+ type: z.ZodLiteral<"stopProvide">;
478
+ topic: z.ZodString;
476
479
  }, z.core.$strict>, z.ZodDiscriminatedUnion<[z.ZodObject<{
477
480
  modelId: z.ZodString;
478
481
  workspace: z.ZodOptional<z.ZodString>;
@@ -591,6 +594,10 @@ export declare const responseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
591
594
  success: z.ZodBoolean;
592
595
  error: z.ZodOptional<z.ZodString>;
593
596
  publicKey: z.ZodOptional<z.ZodString>;
597
+ }, z.core.$strip>, z.ZodObject<{
598
+ type: z.ZodLiteral<"stopProvide">;
599
+ success: z.ZodBoolean;
600
+ error: z.ZodOptional<z.ZodString>;
594
601
  }, z.core.$strip>, z.ZodObject<{
595
602
  type: z.ZodLiteral<"error">;
596
603
  message: z.ZodString;
@@ -8,6 +8,7 @@ import { transcribeStreamRequestSchema, transcribeStreamResponseSchema, } from "
8
8
  import { embedRequestSchema, embedResponseSchema } from "./embed.js";
9
9
  import { cancelRequestSchema, cancelResponseSchema } from "./cancel.js";
10
10
  import { provideRequestSchema, provideResponseSchema } from "./provide.js";
11
+ import { stopProvideRequestSchema, stopProvideResponseSchema, } from "./stop-provide.js";
11
12
  import { translateRequestSchema, translateResponseSchema } from "./translate.js";
12
13
  import { loggingStreamRequestSchema, loggingStreamResponseSchema, } from "./logging-stream.js";
13
14
  import { errorResponseSchema } from "./error.js";
@@ -25,6 +26,7 @@ export const requestSchema = z.union([
25
26
  translateRequestSchema,
26
27
  cancelRequestSchema,
27
28
  provideRequestSchema,
29
+ stopProvideRequestSchema,
28
30
  ragRequestSchema,
29
31
  deleteCacheRequestSchema,
30
32
  ]);
@@ -41,6 +43,7 @@ export const responseSchema = z.discriminatedUnion("type", [
41
43
  translateResponseSchema,
42
44
  cancelResponseSchema,
43
45
  provideResponseSchema,
46
+ stopProvideResponseSchema,
44
47
  errorResponseSchema,
45
48
  ragResponseSchema,
46
49
  deleteCacheResponseSchema,
@@ -7,6 +7,7 @@ export * from "./embed";
7
7
  export * from "./load-model";
8
8
  export * from "./logging-stream";
9
9
  export * from "./provide";
10
+ export * from "./stop-provide";
10
11
  export * from "./unload-model";
11
12
  export * from "./ping";
12
13
  export * from "./common";
@@ -8,6 +8,7 @@ export * from "./embed.js";
8
8
  export * from "./load-model.js";
9
9
  export * from "./logging-stream.js";
10
10
  export * from "./provide.js";
11
+ export * from "./stop-provide.js";
11
12
  export * from "./unload-model.js";
12
13
  export * from "./ping.js";
13
14
  export * from "./common.js";
@@ -0,0 +1,17 @@
1
+ import { z } from "zod";
2
+ export declare const stopProvideParamsSchema: z.ZodObject<{
3
+ topic: z.ZodString;
4
+ }, z.core.$strict>;
5
+ export declare const stopProvideRequestSchema: z.ZodObject<{
6
+ type: z.ZodLiteral<"stopProvide">;
7
+ topic: z.ZodString;
8
+ }, z.core.$strict>;
9
+ export declare const stopProvideResponseSchema: z.ZodObject<{
10
+ type: z.ZodLiteral<"stopProvide">;
11
+ success: z.ZodBoolean;
12
+ error: z.ZodOptional<z.ZodString>;
13
+ }, z.core.$strip>;
14
+ export type StopProvideParams = z.infer<typeof stopProvideParamsSchema>;
15
+ export type StopProvideRequest = z.infer<typeof stopProvideRequestSchema>;
16
+ export type StopProvideResponse = z.infer<typeof stopProvideResponseSchema>;
17
+ //# sourceMappingURL=stop-provide.d.ts.map
@@ -0,0 +1,15 @@
1
+ import { z } from "zod";
2
+ export const stopProvideParamsSchema = z
3
+ .object({
4
+ topic: z.string(),
5
+ })
6
+ .strict();
7
+ export const stopProvideRequestSchema = stopProvideParamsSchema.extend({
8
+ type: z.literal("stopProvide"),
9
+ topic: z.string(),
10
+ });
11
+ export const stopProvideResponseSchema = z.object({
12
+ type: z.literal("stopProvide"),
13
+ success: z.boolean(),
14
+ error: z.string().optional(),
15
+ });
@@ -1,7 +1,6 @@
1
1
  import { RAG, HyperDBAdapter } from "@qvac/rag";
2
2
  import Corestore from "corestore";
3
3
  import path from "bare-path";
4
- import process from "bare-process";
5
4
  import { getEnv } from "../../worker.js";
6
5
  const ragInstances = new Map();
7
6
  const defaultWorkspace = "default";
@@ -48,14 +47,19 @@ export const closeRagInstance = async (workspace) => {
48
47
  ragInstances.delete(key);
49
48
  }
50
49
  };
50
+ let isCleaningUp = false;
51
51
  export const closeAllRagInstances = async () => {
52
- const closures = Array.from(ragInstances.entries()).map(async ([key, entry]) => {
53
- await entry.rag.close();
54
- ragInstances.delete(key);
55
- });
56
- await Promise.all(closures);
52
+ if (isCleaningUp)
53
+ return;
54
+ isCleaningUp = true;
55
+ try {
56
+ const closures = Array.from(ragInstances.entries()).map(async ([key, entry]) => {
57
+ await entry.rag.close();
58
+ ragInstances.delete(key);
59
+ });
60
+ await Promise.all(closures);
61
+ }
62
+ catch (error) {
63
+ console.error("❌ Error during RAG cleanup:", error);
64
+ }
57
65
  };
58
- // Ensure cleanup on process exit
59
- process.on("SIGINT", () => {
60
- void closeAllRagInstances();
61
- });
@@ -9,4 +9,5 @@ export declare function getLoggingStreamStats(): {
9
9
  modelIds: string[];
10
10
  totalStreams: number;
11
11
  };
12
+ export declare function clearAllLoggingStreams(): void;
12
13
  //# sourceMappingURL=logging-stream-registry.d.ts.map
@@ -44,3 +44,10 @@ export function getLoggingStreamStats() {
44
44
  totalStreams: Array.from(loggingStreams.values()).reduce((sum, streams) => sum + streams.size, 0),
45
45
  };
46
46
  }
47
+ export function clearAllLoggingStreams() {
48
+ const count = loggingStreams.size;
49
+ loggingStreams.clear();
50
+ if (count > 0) {
51
+ console.log(`🧹 Cleared logging streams for ${count} model(s)`);
52
+ }
53
+ }
@@ -12,6 +12,7 @@ import { handleTranslate } from "./handlers/translate.js";
12
12
  import { handleLoggingStream } from "./handlers/logging-stream.js";
13
13
  import { cancelHandler } from "./handlers/cancelHandler.js";
14
14
  import { provideHandler } from "./handlers/provideHandler.js";
15
+ import { stopProvideHandler } from "./handlers/stopProvideHandler.js";
15
16
  import { handleRag } from "./handlers/rag.js";
16
17
  import { handleDeleteCache } from "./handlers/delete-cache.js";
17
18
  import { sendErrorResponse, sendStreamErrorResponse } from "../error-handlers";
@@ -200,6 +201,11 @@ export async function handleRequest(req) {
200
201
  req.reply(JSON.stringify(responseSchema.parse(response)), "utf-8");
201
202
  break;
202
203
  }
204
+ case "stopProvide": {
205
+ const response = stopProvideHandler(request);
206
+ req.reply(JSON.stringify(responseSchema.parse(response)), "utf-8");
207
+ break;
208
+ }
203
209
  case "rag": {
204
210
  try {
205
211
  const response = await handleRag(request);
@@ -5,6 +5,7 @@ import { handleUnloadModel } from "./unload-model";
5
5
  import { handleEmbed } from "./embed";
6
6
  import { handleTranscribeStream } from "./transcribe-stream";
7
7
  import { provideHandler } from "./provideHandler";
8
+ import { stopProvideHandler } from "./stopProvideHandler";
8
9
  import { handleTranslate } from "./translate";
9
10
  import { handleLoggingStream } from "./logging-stream";
10
11
  import { handleRag } from "./rag";
@@ -19,6 +20,7 @@ export declare const handlers: {
19
20
  embed: typeof handleEmbed;
20
21
  transcribeStream: typeof handleTranscribeStream;
21
22
  provide: typeof provideHandler;
23
+ stopProvide: typeof stopProvideHandler;
22
24
  translate: typeof handleTranslate;
23
25
  loggingStream: typeof handleLoggingStream;
24
26
  rag: typeof handleRag;
@@ -5,6 +5,7 @@ import { handleUnloadModel } from "./unload-model.js";
5
5
  import { handleEmbed } from "./embed.js";
6
6
  import { handleTranscribeStream } from "./transcribe-stream.js";
7
7
  import { provideHandler } from "./provideHandler.js";
8
+ import { stopProvideHandler } from "./stopProvideHandler.js";
8
9
  import { handleTranslate } from "./translate.js";
9
10
  import { handleLoggingStream } from "./logging-stream.js";
10
11
  import { handleRag } from "./rag.js";
@@ -19,6 +20,7 @@ export const handlers = {
19
20
  embed: handleEmbed,
20
21
  transcribeStream: handleTranscribeStream,
21
22
  provide: provideHandler,
23
+ stopProvide: stopProvideHandler,
22
24
  translate: handleTranslate,
23
25
  loggingStream: handleLoggingStream,
24
26
  rag: handleRag,
@@ -9,4 +9,5 @@ export declare const shouldClearCache: (downloadKey: string) => boolean;
9
9
  export declare const clearClearCacheFlag: (downloadKey: string) => void;
10
10
  export declare const createCancelFunction: (downloadKey: string, clearCache?: boolean) => () => void;
11
11
  export declare const cancelAllDownloads: () => void;
12
+ export declare const cleanupDownloads: () => Promise<void>;
12
13
  //# sourceMappingURL=download-manager.d.ts.map
@@ -1,11 +1,9 @@
1
1
  import {} from "../../../../schemas/index.js";
2
- import process from "bare-process";
3
2
  const activeDownloads = new Map();
4
3
  const clearCacheFlags = new Map();
5
4
  export const getActiveDownload = (key) => activeDownloads.get(key);
6
5
  export const registerDownload = (key, entry) => {
7
6
  activeDownloads.set(key, entry);
8
- registerCleanupHandlers();
9
7
  };
10
8
  export const unregisterDownload = (key) => {
11
9
  activeDownloads.delete(key);
@@ -38,36 +36,19 @@ export const cancelAllDownloads = () => {
38
36
  console.log(`🧹 Cancelling ${activeDownloads.size} active downloads`);
39
37
  Array.from(activeDownloads.keys()).forEach((key) => createCancelFunction(key)());
40
38
  };
41
- // Register cleanup handlers for graceful shutdown
42
- let cleanupRegistered = false;
43
39
  let isCleaningUp = false;
44
- const registerCleanupHandlers = () => {
45
- if (cleanupRegistered)
40
+ export const cleanupDownloads = async () => {
41
+ if (isCleaningUp)
46
42
  return;
47
- cleanupRegistered = true;
48
- const cleanup = async () => {
49
- if (isCleaningUp)
50
- return;
51
- isCleaningUp = true;
52
- try {
53
- const downloadPromises = Array.from(activeDownloads.values()).map((entry) => entry.promise.catch(() => { }));
54
- cancelAllDownloads();
55
- if (downloadPromises.length > 0) {
56
- await Promise.allSettled(downloadPromises);
57
- }
43
+ isCleaningUp = true;
44
+ try {
45
+ const downloadPromises = Array.from(activeDownloads.values()).map((entry) => entry.promise.catch(() => { }));
46
+ cancelAllDownloads();
47
+ if (downloadPromises.length > 0) {
48
+ await Promise.allSettled(downloadPromises);
58
49
  }
59
- catch (error) {
60
- console.error("❌ Error during download cleanup:", error);
61
- }
62
- };
63
- let handlingExit = false;
64
- const exitHandler = async () => {
65
- if (handlingExit)
66
- return;
67
- handlingExit = true;
68
- await cleanup();
69
- process.exit(0);
70
- };
71
- process.once("SIGTERM", () => void exitHandler());
72
- process.once("SIGINT", () => void exitHandler());
50
+ }
51
+ catch (error) {
52
+ console.error("❌ Error during download cleanup:", error);
53
+ }
73
54
  };
@@ -1,46 +1,10 @@
1
- import { getModelBySrc, models } from "../../../../models/hyperdrive/models.js";
1
+ import { models } from "../../../../models/hyperdrive/models.js";
2
2
  import { hyperdriveUrlSchema } from "../../../../schemas/index.js";
3
3
  import { getModelsCacheDir } from "../../../utils/index.js";
4
4
  import { promises as fsPromises } from "bare-fs";
5
5
  import path from "bare-path";
6
6
  import { downloadModelFromHttp } from "./http.js";
7
7
  import { downloadModelFromHyperdrive } from "./hyperdrive.js";
8
- /**
9
- * Attempts to resolve a model from cache (without validation)
10
- * Validation will be handled by the hyperdrive download logic
11
- */
12
- async function tryResolveCachedModel(modelId) {
13
- const cacheDir = getModelsCacheDir();
14
- const cachedPath = path.join(cacheDir, modelId);
15
- try {
16
- await fsPromises.access(cachedPath);
17
- // File exists - return null to let hyperdrive validation handle size/checksum
18
- // This ensures partial downloads are properly resumed instead of being
19
- // incorrectly validated and deleted
20
- return null;
21
- }
22
- catch {
23
- // File doesn't exist
24
- return null;
25
- }
26
- }
27
- /**
28
- * Resolves a known model by ID from hyperdrive, checking cache first
29
- */
30
- async function resolveKnownModel(model, modelIdOrPath, progressCallback, seed) {
31
- if (!model) {
32
- throw new Error("Model is null");
33
- }
34
- console.log(`Loading model ID '${modelIdOrPath}' from hyperdrive`);
35
- // Try to resolve from cache first
36
- const cachedPath = await tryResolveCachedModel(model.modelId);
37
- if (cachedPath) {
38
- return cachedPath;
39
- }
40
- // Not cached or invalid, download from hyperdrive
41
- const downloadedPath = await downloadModelFromHyperdrive(model.hyperdriveKey, model.modelId, seed, progressCallback, model.sha256Checksum);
42
- return downloadedPath;
43
- }
44
8
  /**
45
9
  * Resolves a local file path or cached file
46
10
  */
@@ -84,10 +48,7 @@ export async function resolveModelPath(modelSrc, progressCallback, seed) {
84
48
  let actualPath;
85
49
  // Validate seeding is only used with hyperdrive models
86
50
  if (seed && !hyperdriveKey) {
87
- const model = getModelBySrc(actualModelSrc);
88
- if (!model) {
89
- throw new Error("Seeding is only supported for hyperdrive models");
90
- }
51
+ throw new Error("Seeding is only supported for hyperdrive models");
91
52
  }
92
53
  // Check if it's an HTTP/HTTPS URL
93
54
  if (actualModelSrc.startsWith("http://") ||
@@ -101,21 +62,13 @@ export async function resolveModelPath(modelSrc, progressCallback, seed) {
101
62
  console.log(`Loading from hyperdrive: ${hyperdriveKey}`);
102
63
  actualPath = await downloadModelFromHyperdrive(hyperdriveKey, actualModelSrc, seed, progressCallback);
103
64
  }
65
+ else if (actualModelSrc.includes("/") || actualModelSrc.includes("\\")) {
66
+ // Handle file paths (absolute or relative with slashes)
67
+ actualPath = actualModelSrc;
68
+ }
104
69
  else {
105
- // Try to resolve as a known model ID
106
- const model = getModelBySrc(actualModelSrc);
107
- if (model) {
108
- actualPath = await resolveKnownModel(model, actualModelSrc, progressCallback, seed);
109
- }
110
- else if (actualModelSrc.includes("/") || actualModelSrc.includes("\\")) {
111
- // Handle file paths (absolute or relative with slashes)
112
- console.log(`Loading from file: ${actualModelSrc}`);
113
- actualPath = actualModelSrc;
114
- }
115
- else {
116
- // Handle local files and cached files
117
- actualPath = await resolveLocalOrCachedFile(actualModelSrc);
118
- }
70
+ // Handle local files and cached files
71
+ actualPath = await resolveLocalOrCachedFile(actualModelSrc);
119
72
  }
120
73
  return actualPath;
121
74
  }
@@ -0,0 +1,3 @@
1
+ import type { StopProvideRequest, StopProvideResponse } from "../../../schemas/stop-provide";
2
+ export declare function stopProvideHandler(request: StopProvideRequest): StopProvideResponse;
3
+ //# sourceMappingURL=stopProvideHandler.d.ts.map
@@ -0,0 +1,20 @@
1
+ import { getSwarm } from "../../bare/hyperswarm.js";
2
+ export function stopProvideHandler(request) {
3
+ const swarm = getSwarm();
4
+ try {
5
+ const topic = Buffer.from(request.topic, "hex");
6
+ swarm.leave(topic);
7
+ return {
8
+ type: "stopProvide",
9
+ success: true,
10
+ };
11
+ }
12
+ catch (error) {
13
+ console.error("❌ Error in stop provide handler:", error);
14
+ return {
15
+ type: "stopProvide",
16
+ success: false,
17
+ error: error instanceof Error ? error.message : "Unknown error",
18
+ };
19
+ }
20
+ }
@@ -2,6 +2,10 @@ import process from "bare-process";
2
2
  import { createBareKitRPCServer, createIPCClient, } from "./rpc/create-server.js";
3
3
  import { z } from "zod";
4
4
  import { destroySwarm } from "./bare/hyperswarm.js";
5
+ import { closeAllRagInstances } from "./bare/rag-hyperdb/rag-manager.js";
6
+ import { cleanupDownloads } from "./rpc/handlers/load-model/download-manager.js";
7
+ import { unloadAllModels } from "./bare/registry/model-registry.js";
8
+ import { clearAllLoggingStreams } from "./bare/registry/logging-stream-registry.js";
5
9
  console.log("🐻 Hello from Bare");
6
10
  console.log("Arguments to worker:", process.argv);
7
11
  const defaultHomeDir = process.env["HOME"] || process.env["USERPROFILE"] || "/tmp";
@@ -65,13 +69,27 @@ if (hasRPCConfig) {
65
69
  else {
66
70
  console.log("Running in direct mode - RPC setup will be lazy");
67
71
  }
68
- process.on("SIGTERM", () => {
69
- console.log("🐻 Bare worker SIGTERM received, cleaning up...");
70
- destroySwarm()
71
- .then(() => {
72
- process.exit(0);
73
- })
74
- .catch((err) => {
75
- throw err;
76
- });
77
- });
72
+ // Centralized cleanup for graceful shutdown
73
+ let isShuttingDown = false;
74
+ const shutdownHandler = async () => {
75
+ if (isShuttingDown)
76
+ return;
77
+ isShuttingDown = true;
78
+ console.log("🐻 Bare worker shutdown signal received, cleaning up...");
79
+ try {
80
+ clearAllLoggingStreams();
81
+ await Promise.allSettled([
82
+ destroySwarm(),
83
+ closeAllRagInstances(),
84
+ cleanupDownloads(),
85
+ unloadAllModels(),
86
+ ]);
87
+ console.log("✅ Cleanup completed successfully");
88
+ }
89
+ catch (error) {
90
+ console.error("❌ Error during shutdown cleanup:", error);
91
+ }
92
+ process.exit(0);
93
+ };
94
+ process.once("SIGTERM", () => void shutdownHandler());
95
+ process.once("SIGINT", () => void shutdownHandler());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qvac/sdk",
3
- "version": "0.2.7-dev.1761566029.f834aa3",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -45,7 +45,7 @@
45
45
  "bare:ensureprebuilds:whispercpp": "cp -r node_modules/@qvac/transcription-whispercpp/prebuilds/android-arm64 node_modules/@qvac/transcription-whispercpp/prebuilds/android-ia32 && cp -r node_modules/@qvac/transcription-whispercpp/prebuilds/android-arm64 node_modules/@qvac/transcription-whispercpp/prebuilds/android-arm && cp -r node_modules/@qvac/transcription-whispercpp/prebuilds/android-arm64 node_modules/@qvac/transcription-whispercpp/prebuilds/android-x64",
46
46
  "bare:ensureprebuilds:embeddings": "cp -r node_modules/@qvac/embed-llamacpp/prebuilds/android-arm64 node_modules/@qvac/embed-llamacpp/prebuilds/android-ia32 && cp -r node_modules/@qvac/embed-llamacpp/prebuilds/android-arm64 node_modules/@qvac/embed-llamacpp/prebuilds/android-arm && cp -r node_modules/@qvac/embed-llamacpp/prebuilds/android-arm64 node_modules/@qvac/embed-llamacpp/prebuilds/android-x64",
47
47
  "bare:ensureprebuilds": "bun run bare:ensureprebuilds:llamacpp && bun run bare:ensureprebuilds:whispercpp && bun run bare:ensureprebuilds:embeddings",
48
- "prepare": "bun run husky",
48
+ "prepare:husky": "bun run husky",
49
49
  "bare:example": "./scripts/run-with-bare.sh",
50
50
  "docs_api:website": "typedoc --out ./docs/api/website --entryPoints index.ts --entryPointStrategy expand --readme none",
51
51
  "docs_api:markdown": "typedoc --plugin typedoc-plugin-markdown --out ./docs/api/markdown --entryPoints index.ts --entryPointStrategy expand --readme none && sed -i '1,4d' ./docs/api/markdown/README.md",
@@ -53,15 +53,15 @@
53
53
  "update-models": "node ./scripts/update-models.js"
54
54
  },
55
55
  "dependencies": {
56
- "@qvac/embed-llamacpp": "^0.3.1",
56
+ "@qvac/embed-llamacpp": "^0.4.0",
57
57
  "@qvac/llm-llamacpp": "^0.3.2",
58
58
  "@qvac/decoder-audio": "^0.1.0",
59
59
  "@qvac/error": "^0.1.0",
60
60
  "@qvac/langdetect-text": "^0.1.0",
61
61
  "@qvac/logging": "^0.1.0",
62
62
  "@qvac/rag": "^0.2.1",
63
- "@qvac/transcription-whispercpp": "^0.1.4",
64
- "@qvac/translation-nmtcpp": "^0.1.0",
63
+ "@qvac/transcription-whispercpp": "^0.1.8",
64
+ "@qvac/translation-nmtcpp": "^0.1.2",
65
65
  "fast-safe-stringify": "2.1.1",
66
66
  "zod": "^4.0.17"
67
67
  },
@@ -103,7 +103,7 @@
103
103
  "bare-path": "^3.0.0",
104
104
  "bare-process": "^4.2.1",
105
105
  "bare-rpc": "^0.2.11",
106
- "bare-runtime": "^1.22.1-0",
106
+ "bare-runtime": "^1.24.1",
107
107
  "bare-stream": "^2.6.5",
108
108
  "bare-subprocess": "^5.1.1",
109
109
  "corestore": "^7.4.5",
@@ -126,4 +126,4 @@
126
126
  "patchedDependencies": {
127
127
  "bare-rpc@0.2.11": "patches/bare-rpc@0.2.11.patch"
128
128
  }
129
- }
129
+ }