@trustgraph/react-state 1.5.2 → 1.5.3

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/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { SocketProvider, SocketContext, ConnectionStateContext, } from "@trustgraph/react-provider";
2
2
  export type { SocketProviderProps } from "@trustgraph/react-provider";
3
- export type { BaseApi, Triple, Term, IriTerm, BlankTerm, LiteralTerm, TripleTerm, ConnectionState, StreamingMetadata, RowEmbeddingsMatch, } from "@trustgraph/client";
3
+ export type { BaseApi, Triple, Term, IriTerm, BlankTerm, LiteralTerm, TripleTerm, ConnectionState, StreamingMetadata, RowEmbeddingsMatch, ChunkedUploadDocumentMetadata, UploadSession, } from "@trustgraph/client";
4
4
  export { NotificationProvider } from "./NotificationProvider";
5
5
  export type { NotificationProviderProps } from "./NotificationProvider";
6
6
  export type { NotificationHandler } from "./types";
@@ -49,6 +49,11 @@ export { useLLMModels } from "./state/llm-models";
49
49
  export { useFlowBlueprints, generateFlowBlueprintId } from "./state/flow-blueprints";
50
50
  export { useFlowParameters, useParameterValidation, } from "./state/flow-parameters";
51
51
  export { useNodeDetails } from "./state/node-details";
52
+ export { useChunkedUpload } from "./state/chunked-upload";
53
+ export type { UploadStatus, UploadProgress, ChunkedUploadOptions, ChunkedUploadParams, ResumeUploadParams, } from "./state/chunked-upload";
54
+ export { useChunkedDownload } from "./state/chunked-download";
55
+ export type { DownloadStatus, DownloadProgress, ChunkedDownloadOptions, DownloadParams, } from "./state/chunked-download";
56
+ export type { StreamDocumentResponse } from "@trustgraph/client";
52
57
  export type { Entity } from "./model/entity";
53
58
  export type { Message } from "./model/message";
54
59
  export type { Settings } from "./model/settings-types";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { useSocket, useConnectionState } from '@trustgraph/react-provider';
2
2
  export { ConnectionStateContext, SocketContext, SocketProvider } from '@trustgraph/react-provider';
3
3
  import { jsx } from 'react/jsx-runtime';
4
- import { createContext, useContext, useEffect, useState, useMemo } from 'react';
4
+ import { createContext, useContext, useEffect, useState, useMemo, useRef, useCallback } from 'react';
5
5
  import { create } from 'zustand';
6
6
  import { useQueryClient, useQuery, useMutation } from '@tanstack/react-query';
7
7
  import { v4 } from 'uuid';
@@ -4641,5 +4641,551 @@ const useNodeDetails = (nodeId, flowId) => {
4641
4641
  };
4642
4642
  };
4643
4643
 
4644
- export { DEFAULT_SETTINGS, NotificationProvider, RDFS_LABEL, SETTINGS_STORAGE_KEY, createDocId, fileToBase64, generateFlowBlueprintId, getTermValue$2 as getTermValue, getTriples, prepareMetadata, textToBase64, useActivity, useAgentTools, useChat, useChatSession, useCollections, useConversation, useDocumentEmbeddingsQuery, useEmbeddings, useEntityDetail, useFlowBlueprints, useFlowParameters, useFlows, useGraphEmbeddings, useGraphSubgraph, useInference, useKnowledgeCores, useLLMModels, useLibrary, useLoadStateStore, useMcpTools, useNlpQuery, useNodeDetails, useNotification, useOntologies, useParameterValidation, useProcessing, useProgressStateStore, usePrompts, useRowEmbeddingsQuery, useRowsQuery, useSchemas, useSearchStateStore, useSessionStore, useSettings, useStructuredQuery, useTokenCosts, useTriples, useVectorSearch, useWorkbenchStateStore, vectorSearch };
4644
+ // Default chunk size: 5MB (matches backend default)
4645
+ const DEFAULT_CHUNK_SIZE$1 = 5 * 1024 * 1024;
4646
+ // Maximum parallel chunk uploads
4647
+ const DEFAULT_PARALLEL_UPLOADS = 3;
4648
+ /**
4649
+ * Hook for managing chunked document uploads with progress tracking
4650
+ *
4651
+ * Features:
4652
+ * - Automatic chunking of large files
4653
+ * - Parallel chunk uploads for performance
4654
+ * - Progress tracking (bytes, percentage, chunks)
4655
+ * - Pause/resume support
4656
+ * - Cancel support
4657
+ * - Resumability after interruption
4658
+ *
4659
+ * @param options - Configuration options for the upload
4660
+ * @returns Upload state and control methods
4661
+ */
4662
+ const useChunkedUpload = (options = {}) => {
4663
+ const { chunkSize = DEFAULT_CHUNK_SIZE$1, parallelUploads = DEFAULT_PARALLEL_UPLOADS, onProgress, onComplete, onError, } = options;
4664
+ const socket = useSocket();
4665
+ const connectionState = useConnectionState();
4666
+ const queryClient = useQueryClient();
4667
+ const notify = useNotification();
4668
+ // Upload state
4669
+ const [progress, setProgress] = useState({
4670
+ totalBytes: 0,
4671
+ bytesUploaded: 0,
4672
+ percentage: 0,
4673
+ totalChunks: 0,
4674
+ chunksUploaded: 0,
4675
+ pendingChunks: [],
4676
+ status: "idle",
4677
+ });
4678
+ // Refs for managing upload lifecycle
4679
+ const abortControllerRef = useRef(null);
4680
+ const isPausedRef = useRef(false);
4681
+ const currentFileRef = useRef(null);
4682
+ const uploadIdRef = useRef(null);
4683
+ // Update progress and notify callback
4684
+ const updateProgress = useCallback((updates) => {
4685
+ setProgress((prev) => {
4686
+ const next = { ...prev, ...updates };
4687
+ onProgress?.(next);
4688
+ return next;
4689
+ });
4690
+ }, [onProgress]);
4691
+ // Read a chunk from the file as base64
4692
+ const readChunkAsBase64 = useCallback(async (file, chunkIndex, chunkSz) => {
4693
+ const start = chunkIndex * chunkSz;
4694
+ const end = Math.min(start + chunkSz, file.size);
4695
+ const blob = file.slice(start, end);
4696
+ return new Promise((resolve, reject) => {
4697
+ const reader = new FileReader();
4698
+ reader.onloadend = () => {
4699
+ const dataUrl = reader.result;
4700
+ // Extract base64 from data URL
4701
+ const base64 = dataUrl.replace(/^data:[^;]+;base64,/, "");
4702
+ resolve(base64);
4703
+ };
4704
+ reader.onerror = () => reject(new Error("Failed to read file chunk"));
4705
+ reader.readAsDataURL(blob);
4706
+ });
4707
+ }, []);
4708
+ // Upload chunks in parallel with concurrency limit
4709
+ const uploadChunks = useCallback(async (file, uploadId, pendingChunks, chunkSz, totalChunks) => {
4710
+ const remaining = [...pendingChunks];
4711
+ let completedCount = totalChunks - remaining.length;
4712
+ let bytesUploaded = completedCount * chunkSz;
4713
+ // Process chunks with limited parallelism
4714
+ const uploadNextBatch = async () => {
4715
+ while (remaining.length > 0 && !abortControllerRef.current?.signal.aborted) {
4716
+ // Wait if paused
4717
+ if (isPausedRef.current) {
4718
+ await new Promise((resolve) => setTimeout(resolve, 100));
4719
+ continue;
4720
+ }
4721
+ // Take up to parallelUploads chunks
4722
+ const batch = remaining.splice(0, parallelUploads);
4723
+ // Upload batch in parallel
4724
+ const results = await Promise.allSettled(batch.map(async (chunkIndex) => {
4725
+ const content = await readChunkAsBase64(file, chunkIndex, chunkSz);
4726
+ await socket.librarian().uploadChunk(uploadId, chunkIndex, content);
4727
+ return chunkIndex;
4728
+ }));
4729
+ // Process results
4730
+ for (const result of results) {
4731
+ if (result.status === "fulfilled") {
4732
+ completedCount++;
4733
+ // Calculate actual bytes for this chunk
4734
+ const chunkIdx = result.value;
4735
+ const chunkStart = chunkIdx * chunkSz;
4736
+ const chunkEnd = Math.min(chunkStart + chunkSz, file.size);
4737
+ bytesUploaded += chunkEnd - chunkStart;
4738
+ updateProgress({
4739
+ chunksUploaded: completedCount,
4740
+ bytesUploaded,
4741
+ percentage: Math.round((bytesUploaded / file.size) * 100),
4742
+ pendingChunks: [...remaining],
4743
+ });
4744
+ }
4745
+ else {
4746
+ // Re-add failed chunk to retry
4747
+ const failedIndex = batch[results.indexOf(result)];
4748
+ remaining.push(failedIndex);
4749
+ console.warn(`Chunk ${failedIndex} failed, will retry:`, result.reason);
4750
+ }
4751
+ }
4752
+ }
4753
+ };
4754
+ await uploadNextBatch();
4755
+ }, [socket, parallelUploads, readChunkAsBase64, updateProgress]);
4756
+ /**
4757
+ * Start a new chunked upload
4758
+ */
4759
+ const upload = useCallback(async (params) => {
4760
+ const { file, title, comments = "", tags = [], collection, documentId } = params;
4761
+ // Validate connection
4762
+ if (connectionState?.status !== "authenticated" &&
4763
+ connectionState?.status !== "unauthenticated") {
4764
+ const error = "Not connected to server";
4765
+ updateProgress({ status: "error", error });
4766
+ onError?.(error);
4767
+ return null;
4768
+ }
4769
+ // Reset state
4770
+ abortControllerRef.current = new AbortController();
4771
+ isPausedRef.current = false;
4772
+ currentFileRef.current = file;
4773
+ const docId = documentId || createDocId();
4774
+ const totalChunks = Math.ceil(file.size / chunkSize);
4775
+ const pendingChunks = Array.from({ length: totalChunks }, (_, i) => i);
4776
+ updateProgress({
4777
+ totalBytes: file.size,
4778
+ bytesUploaded: 0,
4779
+ percentage: 0,
4780
+ totalChunks,
4781
+ chunksUploaded: 0,
4782
+ pendingChunks,
4783
+ status: "preparing",
4784
+ error: undefined,
4785
+ uploadId: undefined,
4786
+ documentId: undefined,
4787
+ });
4788
+ try {
4789
+ // Initialize upload session
4790
+ const metadata = {
4791
+ id: docId,
4792
+ time: Math.floor(Date.now() / 1000),
4793
+ kind: file.type || "application/octet-stream",
4794
+ title,
4795
+ comments,
4796
+ user: "trustgraph", // Will be set by server based on auth
4797
+ collection: collection || "default",
4798
+ tags,
4799
+ };
4800
+ const beginResponse = await socket
4801
+ .librarian()
4802
+ .beginUpload(metadata, file.size, chunkSize);
4803
+ const uploadId = beginResponse["upload-id"];
4804
+ uploadIdRef.current = uploadId;
4805
+ updateProgress({
4806
+ status: "uploading",
4807
+ uploadId,
4808
+ });
4809
+ // Upload all chunks
4810
+ await uploadChunks(file, uploadId, pendingChunks, chunkSize, totalChunks);
4811
+ // Check if cancelled
4812
+ if (abortControllerRef.current?.signal.aborted) {
4813
+ return null;
4814
+ }
4815
+ // Complete the upload
4816
+ updateProgress({ status: "completing" });
4817
+ const completeResponse = await socket.librarian().completeUpload(uploadId);
4818
+ const finalDocId = completeResponse["document-id"];
4819
+ updateProgress({
4820
+ status: "completed",
4821
+ documentId: finalDocId,
4822
+ percentage: 100,
4823
+ });
4824
+ // Invalidate documents cache
4825
+ queryClient.invalidateQueries({ queryKey: ["documents"] });
4826
+ notify.success(`Upload complete: ${title}`);
4827
+ onComplete?.(finalDocId);
4828
+ return finalDocId;
4829
+ }
4830
+ catch (err) {
4831
+ const errorMsg = err instanceof Error ? err.message : String(err);
4832
+ updateProgress({ status: "error", error: errorMsg });
4833
+ notify.error(`Upload failed: ${errorMsg}`);
4834
+ onError?.(errorMsg);
4835
+ return null;
4836
+ }
4837
+ }, [
4838
+ socket,
4839
+ connectionState,
4840
+ chunkSize,
4841
+ queryClient,
4842
+ notify,
4843
+ updateProgress,
4844
+ uploadChunks,
4845
+ onComplete,
4846
+ onError,
4847
+ ]);
4848
+ /**
4849
+ * Resume an interrupted upload
4850
+ */
4851
+ const resume = useCallback(async (params) => {
4852
+ const { uploadId, file } = params;
4853
+ // Validate connection
4854
+ if (connectionState?.status !== "authenticated" &&
4855
+ connectionState?.status !== "unauthenticated") {
4856
+ const error = "Not connected to server";
4857
+ updateProgress({ status: "error", error });
4858
+ onError?.(error);
4859
+ return null;
4860
+ }
4861
+ abortControllerRef.current = new AbortController();
4862
+ isPausedRef.current = false;
4863
+ currentFileRef.current = file;
4864
+ uploadIdRef.current = uploadId;
4865
+ updateProgress({
4866
+ status: "preparing",
4867
+ uploadId,
4868
+ });
4869
+ try {
4870
+ // Get current upload status
4871
+ const status = await socket.librarian().getUploadStatus(uploadId);
4872
+ if (status["upload-state"] === "completed") {
4873
+ updateProgress({ status: "completed" });
4874
+ return null;
4875
+ }
4876
+ if (status["upload-state"] === "expired") {
4877
+ throw new Error("Upload session has expired");
4878
+ }
4879
+ const totalChunks = status["total-chunks"];
4880
+ const missingChunks = status["missing-chunks"];
4881
+ const bytesReceived = status["bytes-received"];
4882
+ const totalBytes = status["total-bytes"];
4883
+ updateProgress({
4884
+ totalBytes,
4885
+ bytesUploaded: bytesReceived,
4886
+ percentage: Math.round((bytesReceived / totalBytes) * 100),
4887
+ totalChunks,
4888
+ chunksUploaded: totalChunks - missingChunks.length,
4889
+ pendingChunks: missingChunks,
4890
+ status: "uploading",
4891
+ });
4892
+ // Upload missing chunks
4893
+ const effectiveChunkSize = status["chunk-size"] || chunkSize;
4894
+ await uploadChunks(file, uploadId, missingChunks, effectiveChunkSize, totalChunks);
4895
+ // Check if cancelled
4896
+ if (abortControllerRef.current?.signal.aborted) {
4897
+ return null;
4898
+ }
4899
+ // Complete the upload
4900
+ updateProgress({ status: "completing" });
4901
+ const completeResponse = await socket.librarian().completeUpload(uploadId);
4902
+ const finalDocId = completeResponse["document-id"];
4903
+ updateProgress({
4904
+ status: "completed",
4905
+ documentId: finalDocId,
4906
+ percentage: 100,
4907
+ });
4908
+ // Invalidate documents cache
4909
+ queryClient.invalidateQueries({ queryKey: ["documents"] });
4910
+ notify.success("Upload resumed and completed");
4911
+ onComplete?.(finalDocId);
4912
+ return finalDocId;
4913
+ }
4914
+ catch (err) {
4915
+ const errorMsg = err instanceof Error ? err.message : String(err);
4916
+ updateProgress({ status: "error", error: errorMsg });
4917
+ notify.error(`Resume failed: ${errorMsg}`);
4918
+ onError?.(errorMsg);
4919
+ return null;
4920
+ }
4921
+ }, [
4922
+ socket,
4923
+ connectionState,
4924
+ chunkSize,
4925
+ queryClient,
4926
+ notify,
4927
+ updateProgress,
4928
+ uploadChunks,
4929
+ onComplete,
4930
+ onError,
4931
+ ]);
4932
+ /**
4933
+ * Pause the current upload
4934
+ */
4935
+ const pause = useCallback(() => {
4936
+ if (progress.status === "uploading") {
4937
+ isPausedRef.current = true;
4938
+ updateProgress({ status: "paused" });
4939
+ }
4940
+ }, [progress.status, updateProgress]);
4941
+ /**
4942
+ * Resume a paused upload (not to be confused with resuming an interrupted upload)
4943
+ */
4944
+ const unpause = useCallback(() => {
4945
+ if (progress.status === "paused") {
4946
+ isPausedRef.current = false;
4947
+ updateProgress({ status: "uploading" });
4948
+ }
4949
+ }, [progress.status, updateProgress]);
4950
+ /**
4951
+ * Cancel the current upload
4952
+ */
4953
+ const cancel = useCallback(async () => {
4954
+ abortControllerRef.current?.abort();
4955
+ if (uploadIdRef.current) {
4956
+ try {
4957
+ await socket.librarian().abortUpload(uploadIdRef.current);
4958
+ }
4959
+ catch (err) {
4960
+ console.warn("Failed to abort upload on server:", err);
4961
+ }
4962
+ }
4963
+ updateProgress({
4964
+ status: "cancelled",
4965
+ pendingChunks: [],
4966
+ });
4967
+ uploadIdRef.current = null;
4968
+ currentFileRef.current = null;
4969
+ }, [socket, updateProgress]);
4970
+ /**
4971
+ * Reset the upload state to idle
4972
+ */
4973
+ const reset = useCallback(() => {
4974
+ abortControllerRef.current?.abort();
4975
+ uploadIdRef.current = null;
4976
+ currentFileRef.current = null;
4977
+ isPausedRef.current = false;
4978
+ setProgress({
4979
+ totalBytes: 0,
4980
+ bytesUploaded: 0,
4981
+ percentage: 0,
4982
+ totalChunks: 0,
4983
+ chunksUploaded: 0,
4984
+ pendingChunks: [],
4985
+ status: "idle",
4986
+ });
4987
+ }, []);
4988
+ return {
4989
+ // Current progress state
4990
+ progress,
4991
+ // Control methods
4992
+ upload,
4993
+ resume,
4994
+ pause,
4995
+ unpause,
4996
+ cancel,
4997
+ reset,
4998
+ // Convenience flags
4999
+ isIdle: progress.status === "idle",
5000
+ isUploading: progress.status === "uploading",
5001
+ isPaused: progress.status === "paused",
5002
+ isCompleted: progress.status === "completed",
5003
+ isError: progress.status === "error",
5004
+ };
5005
+ };
5006
+
5007
+ // Default chunk size for downloads: 1MB
5008
+ const DEFAULT_CHUNK_SIZE = 1024 * 1024;
5009
+ /**
5010
+ * Decode base64 string to Uint8Array
5011
+ */
5012
+ const base64ToUint8Array = (base64) => {
5013
+ const binaryString = atob(base64);
5014
+ const bytes = new Uint8Array(binaryString.length);
5015
+ for (let i = 0; i < binaryString.length; i++) {
5016
+ bytes[i] = binaryString.charCodeAt(i);
5017
+ }
5018
+ return bytes;
5019
+ };
5020
+ /**
5021
+ * Trigger browser download of a Blob
5022
+ */
5023
+ const triggerBrowserDownload = (blob, filename) => {
5024
+ const url = URL.createObjectURL(blob);
5025
+ const link = document.createElement("a");
5026
+ link.href = url;
5027
+ link.download = filename;
5028
+ document.body.appendChild(link);
5029
+ link.click();
5030
+ document.body.removeChild(link);
5031
+ URL.revokeObjectURL(url);
5032
+ };
5033
+ /**
5034
+ * Hook for managing streamed document downloads with progress tracking
5035
+ *
5036
+ * Features:
5037
+ * - Streams large documents via WebSocket streaming response
5038
+ * - Progress tracking (chunks received, percentage)
5039
+ * - Cancel support
5040
+ * - Returns Blob or triggers browser download
5041
+ *
5042
+ * @param options - Configuration options for the download
5043
+ * @returns Download state and control methods
5044
+ */
5045
+ const useChunkedDownload = (options = {}) => {
5046
+ const { chunkSize = DEFAULT_CHUNK_SIZE, onProgress, onComplete, onError, } = options;
5047
+ const socket = useSocket();
5048
+ const connectionState = useConnectionState();
5049
+ const notify = useNotification();
5050
+ // Download state
5051
+ const [progress, setProgress] = useState({
5052
+ totalChunks: 0,
5053
+ chunksReceived: 0,
5054
+ percentage: 0,
5055
+ status: "idle",
5056
+ });
5057
+ // Refs for managing download lifecycle
5058
+ const cancelledRef = useRef(false);
5059
+ const chunksRef = useRef(new Map());
5060
+ // Update progress and notify callback
5061
+ const updateProgress = useCallback((updates) => {
5062
+ setProgress((prev) => {
5063
+ const next = { ...prev, ...updates };
5064
+ onProgress?.(next);
5065
+ return next;
5066
+ });
5067
+ }, [onProgress]);
5068
+ /**
5069
+ * Download a document via streaming and return as Blob
5070
+ */
5071
+ const download = useCallback((params) => {
5072
+ const { documentId, mimeType = "application/octet-stream", filename } = params;
5073
+ // Validate connection
5074
+ if (connectionState?.status !== "authenticated" &&
5075
+ connectionState?.status !== "unauthenticated") {
5076
+ const error = "Not connected to server";
5077
+ updateProgress({ status: "error", error });
5078
+ onError?.(error);
5079
+ return Promise.resolve(null);
5080
+ }
5081
+ // Reset state
5082
+ cancelledRef.current = false;
5083
+ chunksRef.current = new Map();
5084
+ updateProgress({
5085
+ totalChunks: 0,
5086
+ chunksReceived: 0,
5087
+ percentage: 0,
5088
+ status: "downloading",
5089
+ error: undefined,
5090
+ documentId,
5091
+ });
5092
+ return new Promise((resolve) => {
5093
+ const onChunk = (content, chunkIndex, totalChunks, complete) => {
5094
+ // Check for cancellation
5095
+ if (cancelledRef.current) {
5096
+ return;
5097
+ }
5098
+ // Store chunk
5099
+ const chunkData = base64ToUint8Array(content);
5100
+ chunksRef.current.set(chunkIndex, chunkData);
5101
+ const chunksReceived = chunksRef.current.size;
5102
+ const percentage = totalChunks > 0
5103
+ ? Math.round((chunksReceived / totalChunks) * 100)
5104
+ : 0;
5105
+ updateProgress({
5106
+ totalChunks,
5107
+ chunksReceived,
5108
+ percentage,
5109
+ });
5110
+ // If complete, reassemble and return
5111
+ if (complete) {
5112
+ if (cancelledRef.current) {
5113
+ resolve(null);
5114
+ return;
5115
+ }
5116
+ // Reassemble chunks in order
5117
+ const orderedChunks = [];
5118
+ for (let i = 0; i < totalChunks; i++) {
5119
+ const chunk = chunksRef.current.get(i);
5120
+ if (chunk) {
5121
+ orderedChunks.push(chunk);
5122
+ }
5123
+ }
5124
+ const blob = new Blob(orderedChunks, { type: mimeType });
5125
+ updateProgress({
5126
+ status: "completed",
5127
+ percentage: 100,
5128
+ chunksReceived: totalChunks,
5129
+ });
5130
+ // Trigger browser download if filename provided
5131
+ if (filename) {
5132
+ triggerBrowserDownload(blob, filename);
5133
+ }
5134
+ notify.success("Download complete");
5135
+ onComplete?.(blob, documentId);
5136
+ resolve(blob);
5137
+ }
5138
+ };
5139
+ const onStreamError = (error) => {
5140
+ if (cancelledRef.current) {
5141
+ return;
5142
+ }
5143
+ updateProgress({ status: "error", error });
5144
+ notify.error(`Download failed: ${error}`);
5145
+ onError?.(error);
5146
+ resolve(null);
5147
+ };
5148
+ // Start streaming download
5149
+ socket.librarian().streamDocument(documentId, onChunk, onStreamError, chunkSize);
5150
+ });
5151
+ }, [socket, connectionState, chunkSize, notify, updateProgress, onComplete, onError]);
5152
+ /**
5153
+ * Cancel the current download
5154
+ */
5155
+ const cancel = useCallback(() => {
5156
+ cancelledRef.current = true;
5157
+ chunksRef.current = new Map();
5158
+ updateProgress({
5159
+ status: "cancelled",
5160
+ });
5161
+ }, [updateProgress]);
5162
+ /**
5163
+ * Reset the download state to idle
5164
+ */
5165
+ const reset = useCallback(() => {
5166
+ cancelledRef.current = true;
5167
+ chunksRef.current = new Map();
5168
+ setProgress({
5169
+ totalChunks: 0,
5170
+ chunksReceived: 0,
5171
+ percentage: 0,
5172
+ status: "idle",
5173
+ });
5174
+ }, []);
5175
+ return {
5176
+ // Current progress state
5177
+ progress,
5178
+ // Control methods
5179
+ download,
5180
+ cancel,
5181
+ reset,
5182
+ // Convenience flags
5183
+ isIdle: progress.status === "idle",
5184
+ isDownloading: progress.status === "downloading",
5185
+ isCompleted: progress.status === "completed",
5186
+ isError: progress.status === "error",
5187
+ };
5188
+ };
5189
+
5190
+ export { DEFAULT_SETTINGS, NotificationProvider, RDFS_LABEL, SETTINGS_STORAGE_KEY, createDocId, fileToBase64, generateFlowBlueprintId, getTermValue$2 as getTermValue, getTriples, prepareMetadata, textToBase64, useActivity, useAgentTools, useChat, useChatSession, useChunkedDownload, useChunkedUpload, useCollections, useConversation, useDocumentEmbeddingsQuery, useEmbeddings, useEntityDetail, useFlowBlueprints, useFlowParameters, useFlows, useGraphEmbeddings, useGraphSubgraph, useInference, useKnowledgeCores, useLLMModels, useLibrary, useLoadStateStore, useMcpTools, useNlpQuery, useNodeDetails, useNotification, useOntologies, useParameterValidation, useProcessing, useProgressStateStore, usePrompts, useRowEmbeddingsQuery, useRowsQuery, useSchemas, useSearchStateStore, useSessionStore, useSettings, useStructuredQuery, useTokenCosts, useTriples, useVectorSearch, useWorkbenchStateStore, vectorSearch };
4645
5191
  //# sourceMappingURL=index.esm.js.map