diff --git a/clients/search-component/package.json b/clients/search-component/package.json index 7655d8e4c1..f938063896 100644 --- a/clients/search-component/package.json +++ b/clients/search-component/package.json @@ -65,7 +65,7 @@ "@r2wc/react-to-web-component": "^2.0.3", "@thumbmarkjs/thumbmarkjs": "^0.14.8", "react-markdown": "^9.0.1", - "react-pdf-spotlight": "^0.0.6", + "react-pdf-spotlight": "^0.0.7", "react-snap-carousel": "^0.5.0", "trieve-ts-sdk": "*" }, diff --git a/clients/search-component/src/TrieveModal/Search/PdfItem.tsx b/clients/search-component/src/TrieveModal/Search/PdfItem.tsx index 2a05830be3..2034f62ee3 100644 --- a/clients/search-component/src/TrieveModal/Search/PdfItem.tsx +++ b/clients/search-component/src/TrieveModal/Search/PdfItem.tsx @@ -1,5 +1,11 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import { PdfChunk } from "../../utils/types"; +import { useFileContext } from "../../utils/hooks/file-context"; +import { FileDTO } from "trieve-ts-sdk"; +import { useModalState } from "../../utils/hooks/modal-context"; +import { cached } from "../../utils/cache"; +import { PdfSpotlight } from "react-pdf-spotlight"; +import { file } from "bun"; type Props = { item: PdfChunk; @@ -14,12 +20,68 @@ function extractMarkedContent(text: string): string { return match ? match[1] : ""; } +const getPresignedUrl = async ( + baseUrl: string, + datasetId: string, + fileId: string, + apiKey: string, +) => { + const params = { + content_type: "application/pdf", + }; + const queryParams = new URLSearchParams(params).toString(); + const result = await fetch(`${baseUrl}/api/file/${fileId}?${queryParams}`, { + headers: { + "TR-Dataset": datasetId, + Authorization: `Bearer ${apiKey}`, + }, + }); + + if (!result.ok) { + throw new Error("Error fetching presigned url"); + } + + const presignedUrl = (await result.json()) as FileDTO; + + return presignedUrl.s3_url; +}; + export const PdfItem = (props: Props) => { + const [presigned, setPresigned] = useState(null); const toHighlight = extractMarkedContent(props.item.chunk.highlight || ""); + const fileCtx = useFileContext(); + const state = useModalState(); + + useEffect(() => { + const getPresigned = async () => { + const presignedUrlResult = await cached(() => { + return getPresignedUrl( + state.props.baseUrl || "http://localhost:8090", + state.props.datasetId, + fileCtx.files[props.item.chunk.metadata.file_name], + state.props.apiKey, + ); + }, `file-presigned:${props.item.chunk.metadata.file_name}`); + setPresigned(presignedUrlResult); + }; + + getPresigned(); + }, []); return (
-
Pdf item
+ {presigned && ( +
+ +
+ )}
); }; diff --git a/clients/search-component/src/TrieveModal/Search/SearchMode.tsx b/clients/search-component/src/TrieveModal/Search/SearchMode.tsx index 1a08dfdee3..bf7c86980e 100644 --- a/clients/search-component/src/TrieveModal/Search/SearchMode.tsx +++ b/clients/search-component/src/TrieveModal/Search/SearchMode.tsx @@ -38,7 +38,6 @@ export const SearchMode = () => { index: number, ) => { const isChunk = isChunkWithHighlights(result); - console.log(result); // Target non group pdf search if (isChunk && props.type === "pdf") { diff --git a/clients/search-component/src/utils/hooks/file-context.tsx b/clients/search-component/src/utils/hooks/file-context.tsx index e91e78d745..b325d3254f 100644 --- a/clients/search-component/src/utils/hooks/file-context.tsx +++ b/clients/search-component/src/utils/hooks/file-context.tsx @@ -12,10 +12,11 @@ export const FileContextProvider = (props: { children: ReactNode }) => { useEffect(() => { const getFiles = async () => { - const page = 1; + let page = 1; let done = false; const fileMapResult: Record = {}; - while (!done) { + let totalPages = Number.MAX_SAFE_INTEGER; + while (!done && page <= totalPages) { const files = await state.trieveSDK.trieve.fetch( "/api/dataset/files/{dataset_id}/{page}", "get", @@ -25,14 +26,18 @@ export const FileContextProvider = (props: { children: ReactNode }) => { }, ); - if (files.length) { - files.reduce((acc, file) => { - acc[file.file_name] = file.id; + totalPages = files.total_pages; + + if (files.file_and_group_ids.length) { + files.file_and_group_ids.reduce((acc, file) => { + acc[file.file.file_name] = file.file.id; return acc; }, fileMapResult); } else { done = true; } + + page += 1; } setFiles(fileMapResult); @@ -46,3 +51,7 @@ export const FileContextProvider = (props: { children: ReactNode }) => { ); }; + +export const useFileContext = () => { + return React.useContext(FileContext); +}; diff --git a/clients/search-component/src/utils/types.ts b/clients/search-component/src/utils/types.ts index 9f0aa638aa..997e528ce7 100644 --- a/clients/search-component/src/utils/types.ts +++ b/clients/search-component/src/utils/types.ts @@ -47,7 +47,6 @@ export type PdfChunk = { }; export function isPdfChunk(result: ChunkWithHighlights): result is PdfChunk { - console.log("testing", result); return (result as PdfChunk).chunk.metadata.file_name !== undefined; } diff --git a/clients/ts-sdk/openapi.json b/clients/ts-sdk/openapi.json index 47ad79979c..f27379c215 100644 --- a/clients/ts-sdk/openapi.json +++ b/clients/ts-sdk/openapi.json @@ -3671,10 +3671,7 @@ "content": { "application/json": { "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/File" - } + "$ref": "#/components/schemas/FileData" } } } @@ -4544,6 +4541,16 @@ "type": "string", "format": "uuid" } + }, + { + "name": "content_type", + "in": "query", + "description": "Optional field to override the presigned url's Content-Type header", + "required": false, + "schema": { + "type": "string", + "nullable": true + } } ], "responses": { @@ -10783,6 +10790,22 @@ "updated_at": "2021-01-01 00:00:00.000" } }, + "FileAndGroupId": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "$ref": "#/components/schemas/File" + }, + "group_id": { + "type": "string", + "format": "uuid", + "nullable": true + } + } + }, "FileDTO": { "type": "object", "required": [ @@ -10837,6 +10860,25 @@ "updated_at": "2021-01-01 00:00:00.000" } }, + "FileData": { + "type": "object", + "required": [ + "file_and_group_ids", + "total_pages" + ], + "properties": { + "file_and_group_ids": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileAndGroupId" + } + }, + "total_pages": { + "type": "integer", + "format": "int64" + } + } + }, "FullTextBoost": { "type": "object", "description": "Boost the presence of certain tokens for fulltext (SPLADE) and keyword (BM25) search. I.e. boosting title phrases to priortize title matches or making sure that the listing for AirBNB itself ranks higher than companies who make software for AirBNB hosts by boosting the in-document-frequency of the AirBNB token (AKA word) for its official listing. Conceptually it multiples the in-document-importance second value in the tuples of the SPLADE or BM25 sparse vector of the chunk_html innerText for all tokens present in the boost phrase by the boost factor like so: (token, in-document-importance) -> (token, in-document-importance*boost_factor).", diff --git a/clients/ts-sdk/src/functions/datasets/index.ts b/clients/ts-sdk/src/functions/datasets/index.ts index 9a58b58f33..263a2a4547 100644 --- a/clients/ts-sdk/src/functions/datasets/index.ts +++ b/clients/ts-sdk/src/functions/datasets/index.ts @@ -12,7 +12,7 @@ import { DatasetAndUsage, DatasetUsageCount, EventReturn, - File, + FileData, GetAllTagsReqPayload, GetAllTagsResponse, GetEventsData, @@ -34,7 +34,7 @@ export async function createDataset( /** @hidden */ this: TrieveSDK, props: CreateDatasetReqPayload, - signal?: AbortSignal + signal?: AbortSignal, ): Promise { if (!this.organizationId) { throw new Error("Organization ID is required to create a dataset"); @@ -47,7 +47,7 @@ export async function createDataset( data: props, organizationId: this.organizationId, }, - signal + signal, ) as Promise; } @@ -66,7 +66,7 @@ export async function updateDataset( /** @hidden */ this: TrieveSDK, props: UpdateDatasetReqPayload, - signal?: AbortSignal + signal?: AbortSignal, ): Promise { if (!this.organizationId) { throw new Error("Organization ID is required to update a dataset"); @@ -79,7 +79,7 @@ export async function updateDataset( data: props, organizationId: this.organizationId, }, - signal + signal, ) as Promise; } @@ -100,7 +100,7 @@ export async function batchCreateDatasets( /** @hidden */ this: TrieveSDK, props: CreateDatasetBatchReqPayload, - signal?: AbortSignal + signal?: AbortSignal, ): Promise { if (!this.organizationId) { throw new Error("Organization ID is required to create a dataset"); @@ -113,7 +113,7 @@ export async function batchCreateDatasets( data: props, organizationId: this.organizationId, }, - signal + signal, ) as Promise; } @@ -128,7 +128,7 @@ export async function clearDataset( /** @hidden */ this: TrieveSDK, datasetId: string, - signal?: AbortSignal + signal?: AbortSignal, ): Promise { return this.trieve.fetch( "/api/dataset/clear/{dataset_id}", @@ -136,7 +136,7 @@ export async function clearDataset( { datasetId, }, - signal + signal, ) as Promise; } @@ -145,7 +145,7 @@ export async function getDatasetEvents( this: TrieveSDK, props: GetEventsData, datasetId: string, - signal?: AbortSignal + signal?: AbortSignal, ): Promise { return this.trieve.fetch( "/api/dataset/events", @@ -154,7 +154,7 @@ export async function getDatasetEvents( datasetId, data: props, }, - signal + signal, ) as Promise; } @@ -163,8 +163,8 @@ export async function getDatasetFiles( this: TrieveSDK, datasetId: string, page: number, - signal?: AbortSignal -): Promise { + signal?: AbortSignal, +): Promise { return this.trieve.fetch( "/api/dataset/files/{dataset_id}/{page}", "get", @@ -172,8 +172,8 @@ export async function getDatasetFiles( datasetId, page, }, - signal - ) as Promise; + signal, + ) as Promise; } export async function getAllDatasetTags( @@ -181,7 +181,7 @@ export async function getAllDatasetTags( this: TrieveSDK, props: GetAllTagsReqPayload, datasetId: string, - signal?: AbortSignal + signal?: AbortSignal, ): Promise { return this.trieve.fetch( "/api/dataset/get_all_tags", @@ -190,7 +190,7 @@ export async function getAllDatasetTags( data: props, datasetId, }, - signal + signal, ) as Promise; } @@ -200,7 +200,7 @@ export async function getDatasetsFromOrganization( organizationId: string, limit?: number, offset?: number, - signal?: AbortSignal + signal?: AbortSignal, ): Promise { return this.trieve.fetch( "/api/dataset/organization/{organization_id}", @@ -210,7 +210,7 @@ export async function getDatasetsFromOrganization( limit, offset, }, - signal + signal, ) as Promise; } @@ -218,11 +218,11 @@ export async function getDatasetByTrackingId( /** @hidden */ this: TrieveSDK, trackingId: string, - signal?: AbortSignal + signal?: AbortSignal, ): Promise { if (!this.organizationId) { throw new Error( - "Organization ID is required to get a dataset by tracking ID" + "Organization ID is required to get a dataset by tracking ID", ); } @@ -233,7 +233,7 @@ export async function getDatasetByTrackingId( organizationId: this.organizationId, trackingId, }, - signal + signal, ) as Promise; } @@ -241,7 +241,7 @@ export async function getDatasetUsageById( /** @hidden */ this: TrieveSDK, datasetId: string, - signal?: AbortSignal + signal?: AbortSignal, ): Promise { return this.trieve.fetch( "/api/dataset/usage/{dataset_id}", @@ -249,7 +249,7 @@ export async function getDatasetUsageById( { datasetId, }, - signal + signal, ) as Promise; } @@ -257,7 +257,7 @@ export async function getDatasetById( /** @hidden */ this: TrieveSDK, datasetId: string, - signal?: AbortSignal + signal?: AbortSignal, ): Promise { return this.trieve.fetch( "/api/dataset/{dataset_id}", @@ -265,7 +265,7 @@ export async function getDatasetById( { datasetId, }, - signal + signal, ) as Promise; } @@ -273,7 +273,7 @@ export async function deleteDataset( /** @hidden */ this: TrieveSDK, datasetId: string, - signal?: AbortSignal + signal?: AbortSignal, ): Promise { return this.trieve.fetch( "/api/dataset/{dataset_id}", @@ -281,7 +281,7 @@ export async function deleteDataset( { datasetId, }, - signal + signal, ) as Promise; } diff --git a/clients/ts-sdk/src/functions/file/file.test.ts b/clients/ts-sdk/src/functions/file/file.test.ts index 4b29c5d9a0..f656ac8986 100644 --- a/clients/ts-sdk/src/functions/file/file.test.ts +++ b/clients/ts-sdk/src/functions/file/file.test.ts @@ -2,7 +2,7 @@ import { beforeAll, describe, expect, expectTypeOf } from "vitest"; import { TrieveSDK } from "../../sdk"; import { CreatePresignedUrlForCsvJsonResponseBody, - File, + FileData, FileDTO, UploadFileResponseBody, } from "../../types.gen"; @@ -56,12 +56,12 @@ describe("File Tests", async () => { ], }); expectTypeOf( - data + data, ).toEqualTypeOf(); const presignedPutUrl = data.presigned_put_url; const fileResponse = await fetch( - "https://trieve.b-cdn.net/csvjsonltesting/flipkart_com-ecommerce_sample.jsonl" + "https://trieve.b-cdn.net/csvjsonltesting/flipkart_com-ecommerce_sample.jsonl", ); const blob = await fileResponse.blob(); @@ -92,12 +92,12 @@ describe("File Tests", async () => { ], }); expectTypeOf( - data + data, ).toEqualTypeOf(); const presignedPutUrl = data.presigned_put_url; const fileResponse = await fetch( - "https://raw.githubusercontent.com/datasciencedojo/datasets/refs/heads/master/titanic.csv" + "https://raw.githubusercontent.com/datasciencedojo/datasets/refs/heads/master/titanic.csv", ); const blob = await fileResponse.blob(); @@ -116,7 +116,7 @@ describe("File Tests", async () => { const data = await trieve.getFilesForDataset({ page: 1, }); - expectTypeOf(data).toEqualTypeOf(); + expectTypeOf(data).toEqualTypeOf(); }); test("getFile", async () => { diff --git a/clients/ts-sdk/src/types.gen.ts b/clients/ts-sdk/src/types.gen.ts index 08c663ba6e..2c78b78e9e 100644 --- a/clients/ts-sdk/src/types.gen.ts +++ b/clients/ts-sdk/src/types.gen.ts @@ -1498,6 +1498,11 @@ export type File = { updated_at: string; }; +export type FileAndGroupId = { + file: File; + group_id?: (string) | null; +}; + export type FileDTO = { created_at: string; file_name: string; @@ -1509,6 +1514,11 @@ export type FileDTO = { updated_at: string; }; +export type FileData = { + file_and_group_ids: Array; + total_pages: number; +}; + /** * Boost the presence of certain tokens for fulltext (SPLADE) and keyword (BM25) search. I.e. boosting title phrases to priortize title matches or making sure that the listing for AirBNB itself ranks higher than companies who make software for AirBNB hosts by boosting the in-document-frequency of the AirBNB token (AKA word) for its official listing. Conceptually it multiples the in-document-importance second value in the tuples of the SPLADE or BM25 sparse vector of the chunk_html innerText for all tokens present in the boost phrase by the boost factor like so: (token, in-document-importance) -> (token, in-document-importance*boost_factor). */ @@ -4223,7 +4233,7 @@ export type GetDatasetFilesHandlerData = { trDataset: string; }; -export type GetDatasetFilesHandlerResponse = (Array); +export type GetDatasetFilesHandlerResponse = (FileData); export type GetAllTagsData = { /** @@ -4395,6 +4405,10 @@ export type UploadHtmlPageData = { export type UploadHtmlPageResponse = (void); export type GetFileHandlerData = { + /** + * Optional field to override the presigned url's Content-Type header + */ + contentType?: (string) | null; /** * The id of the file to fetch */ @@ -5697,7 +5711,7 @@ export type $OpenApiTs = { /** * JSON body representing the files in the current dataset */ - 200: Array; + 200: FileData; /** * Service error relating to getting the files in the current datase */ diff --git a/server/src/data/models.rs b/server/src/data/models.rs index e363d14345..78a6b9fb0e 100644 --- a/server/src/data/models.rs +++ b/server/src/data/models.rs @@ -1942,7 +1942,7 @@ impl File { } } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, ToSchema)] pub struct FileAndGroupId { pub file: File, pub group_id: Option, diff --git a/server/src/handlers/file_handler.rs b/server/src/handlers/file_handler.rs index 2d17431a68..dda3244e87 100644 --- a/server/src/handlers/file_handler.rs +++ b/server/src/handlers/file_handler.rs @@ -300,6 +300,11 @@ pub async fn upload_html_page( Ok(HttpResponse::NoContent().finish()) } +#[derive(Debug, Deserialize, Serialize, ToSchema, Default)] +pub struct FileSignedUrlOptions { + content_type: Option, +} + /// Get File Signed URL /// /// Get a signed s3 url corresponding to the file_id requested such that you can download the file. @@ -316,6 +321,7 @@ pub async fn upload_html_page( params( ("TR-Dataset" = uuid::Uuid, Header, description = "The dataset id or tracking_id to use for the request. We assume you intend to use an id if the value is a valid uuid."), ("file_id" = uuid::Uuid, description = "The id of the file to fetch"), + ("content_type" = Option, Query, description = "Optional field to override the presigned url's Content-Type header"), ), security( ("ApiKey" = ["readonly"]), @@ -326,8 +332,15 @@ pub async fn get_file_handler( pool: web::Data, _user: LoggedUser, dataset_org_plan_sub: DatasetAndOrgWithSubAndPlan, + options: web::Query, ) -> Result { - let file = get_file_query(file_id.into_inner(), dataset_org_plan_sub.dataset.id, pool).await?; + let file = get_file_query( + file_id.into_inner(), + dataset_org_plan_sub.dataset.id, + options.into_inner().content_type, + pool, + ) + .await?; Ok(HttpResponse::Ok().json(file)) } @@ -465,7 +478,7 @@ pub struct DatasetFileQuery { pub dataset_id: uuid::Uuid, pub page: u64, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, ToSchema)] pub struct FileData { pub file_and_group_ids: Vec, pub total_pages: i64, @@ -480,7 +493,7 @@ pub struct FileData { context_path = "/api", tag = "File", responses( - (status = 200, description = "JSON body representing the files in the current dataset", body = Vec), + (status = 200, description = "JSON body representing the files in the current dataset", body = FileData), (status = 400, description = "Service error relating to getting the files in the current datase", body = ErrorResponseBody), ), params( diff --git a/server/src/lib.rs b/server/src/lib.rs index 074370ea6e..30094af887 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -361,6 +361,7 @@ impl Modify for SecurityAddon { handlers::file_handler::CreatePresignedUrlForCsvJsonlReqPayload, handlers::file_handler::CreatePresignedUrlForCsvJsonResponseBody, handlers::file_handler::UploadHtmlPageReqPayload, + handlers::file_handler::FileData, handlers::file_handler::Pdf2MdOptions, handlers::invitation_handler::InvitationData, handlers::event_handler::GetEventsData, @@ -511,6 +512,7 @@ impl Modify for SecurityAddon { data::models::File, data::models::ChunkGroup, data::models::ChunkGroupAndFileId, + data::models::FileAndGroupId, data::models::FileDTO, data::models::Organization, data::models::OrganizationWithSubAndPlan, diff --git a/server/src/operators/file_operator.rs b/server/src/operators/file_operator.rs index 73cd3372d8..2f2bd03439 100644 --- a/server/src/operators/file_operator.rs +++ b/server/src/operators/file_operator.rs @@ -371,6 +371,7 @@ pub async fn create_file_chunks( pub async fn get_file_query( file_uuid: uuid::Uuid, dataset_id: uuid::Uuid, + content_type: Option, pool: web::Data, ) -> Result { use crate::data::schema::files::dsl as files_columns; @@ -392,10 +393,29 @@ pub async fn get_file_query( })?; let mut custom_queries = HashMap::new(); - custom_queries.insert( - "response-content-disposition".into(), - format!("attachment; filename=\"{}\"", file.file_name), - ); + + match content_type { + Some(content_type) => { + if content_type == "application/pdf" { + custom_queries.insert( + "response-content-disposition".into(), + format!("attachment; filename*=utf-8''{}", file.file_name), + ); + } else { + custom_queries.insert( + "response-content-disposition".into(), + format!("attachment; filename=\"{}\"", file.file_name), + ); + } + custom_queries.insert("response-content-type".into(), content_type.to_string()); + } + None => { + custom_queries.insert( + "response-content-disposition".into(), + format!("attachment; filename=\"{}\"", file.file_name), + ); + } + } let bucket = get_aws_bucket()?; let s3_url = bucket diff --git a/yarn.lock b/yarn.lock index cf3239ea86..4f83028c1c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -666,6 +666,72 @@ resolved "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz" integrity sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw== +"@napi-rs/canvas-android-arm64@0.1.65": + version "0.1.65" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.65.tgz#b42f2a2f67cb32ad6669e53561987d58384e791f" + integrity sha512-ZYwqFYEKcT5Zr8lbiaJNJj/poLaeK2TncolY914r+gD2TJNeP7ZqvE7A2SX/1C9MB4E3DQEwm3YhL3WEf0x3MQ== + +"@napi-rs/canvas-darwin-arm64@0.1.65": + version "0.1.65" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.65.tgz#8b1a8c2495816f640c1c0299e717de722b961608" + integrity sha512-Pg1pfiJEyDIsX+V0QaJPRWvXbw5zmWAk3bivFCvt/5pwZb37/sT6E/RqPHT9NnqpDyKW6SriwY9ypjljysUA1Q== + +"@napi-rs/canvas-darwin-x64@0.1.65": + version "0.1.65" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.65.tgz#c34da0605c6220ec4e42bbf4dd2ae594c19a4048" + integrity sha512-3Tr+/HjdJN7Z/VKIcsxV2DvDIibZCExgfYTgljCkUSFuoI7iNkOE6Dc1Q6j212EB9PeO8KmfrViBqHYT6IwWkA== + +"@napi-rs/canvas-linux-arm-gnueabihf@0.1.65": + version "0.1.65" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.65.tgz#83b618fe762190bbbfdb66e636f6de0ea940c0ec" + integrity sha512-3KP+dYObH7CVkZMZWwk1WX9jRjL+EKdQtD43H8MOI+illf+dwqLlecdQ4d9bQRIxELKJ8dyPWY4fOp/Ngufrdg== + +"@napi-rs/canvas-linux-arm64-gnu@0.1.65": + version "0.1.65" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.65.tgz#b267573eea3209c76d69c69f8fd040407720167d" + integrity sha512-Ka3StKz7Dq7kjTF3nNJCq43UN/VlANS7qGE3dWkn1d+tQNsCRy/wRmyt1TUFzIjRqcTFMQNRbgYq84+53UBA0A== + +"@napi-rs/canvas-linux-arm64-musl@0.1.65": + version "0.1.65" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.65.tgz#36896b8166f6e8752c0142c6114cb64cf235a649" + integrity sha512-O4xMASm2JrmqYoiDyxVWi+z5C14H+oVEag2rZ5iIA67dhWqYZB+iO7wCFpBYRj31JPBR29FOsu6X9zL+DwBFdw== + +"@napi-rs/canvas-linux-riscv64-gnu@0.1.65": + version "0.1.65" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.65.tgz#ab5059fae49769ccf726e8ded103f15e0a39e16c" + integrity sha512-dblWDaA59ZU8bPbkfM+riSke7sFbNZ70LEevUdI5rgiFEUzYUQlU34gSBzemTACj5rCWt1BYeu0GfkLSjNMBSw== + +"@napi-rs/canvas-linux-x64-gnu@0.1.65": + version "0.1.65" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.65.tgz#767b023c9d7d9d09be06afdfe37ed0549b5b7a6c" + integrity sha512-wsp+atutw13OJXGU3DDkdngtBDoEg01IuK5xMe0L6VFPV8maGkh17CXze078OD5QJOc6kFyw3DDscMLOPF8+oA== + +"@napi-rs/canvas-linux-x64-musl@0.1.65": + version "0.1.65" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.65.tgz#9551edca5b5f0e7abfe7d5fea97b1ce25aeed4ca" + integrity sha512-odX+nN+IozWzhdj31INcHz3Iy9+EckNw+VqsZcaUxZOTu7/3FmktRNI6aC1qe5minZNv1m05YOS1FVf7fvmjlA== + +"@napi-rs/canvas-win32-x64-msvc@0.1.65": + version "0.1.65" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.65.tgz#86b9209267a20df2c0044b650feb9abc8c85be3d" + integrity sha512-RZQX3luWnlNWgdMnLMQ1hyfQraeAn9lnxWWVCHuUM4tAWEV8UDdeb7cMwmJW7eyt8kAosmjeHt3cylQMHOxGFg== + +"@napi-rs/canvas@^0.1.64": + version "0.1.65" + resolved "https://registry.yarnpkg.com/@napi-rs/canvas/-/canvas-0.1.65.tgz#ef97a41b83aa03ae37862e789d124ec80eaf5b33" + integrity sha512-YcFhXQcp+b2d38zFOJNbpyPHnIL7KAEkhJQ+UeeKI5IpE9B8Cpf/M6RiHPQXSsSqnYbrfFylnW49dyh2oeSblQ== + optionalDependencies: + "@napi-rs/canvas-android-arm64" "0.1.65" + "@napi-rs/canvas-darwin-arm64" "0.1.65" + "@napi-rs/canvas-darwin-x64" "0.1.65" + "@napi-rs/canvas-linux-arm-gnueabihf" "0.1.65" + "@napi-rs/canvas-linux-arm64-gnu" "0.1.65" + "@napi-rs/canvas-linux-arm64-musl" "0.1.65" + "@napi-rs/canvas-linux-riscv64-gnu" "0.1.65" + "@napi-rs/canvas-linux-x64-gnu" "0.1.65" + "@napi-rs/canvas-linux-x64-musl" "0.1.65" + "@napi-rs/canvas-win32-x64-msvc" "0.1.65" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" @@ -5816,6 +5882,13 @@ pathval@^2.0.0: resolved "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz" integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== +pdfjs-dist@^4.9.155: + version "4.9.155" + resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-4.9.155.tgz#80c9fc7f5411a4cf00751cdea242ffd8b0f23a96" + integrity sha512-epRZn6DQQKCOEqbmFsxkiMBm1MHaNrnr6T4VBNP0bsDvdJdmrWcZbS5cgJXW68P0d3uJTlFhF6Wms2tlSgPYig== + optionalDependencies: + "@napi-rs/canvas" "^0.1.64" + perfect-debounce@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz" @@ -6123,6 +6196,13 @@ react-markdown@^9.0.1: unist-util-visit "^5.0.0" vfile "^6.0.0" +react-pdf-spotlight@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/react-pdf-spotlight/-/react-pdf-spotlight-0.0.7.tgz#09234574a804675f86037a8b3dd205b22b789f17" + integrity sha512-Eh7164w8jIcGyak6V1xHJ8JDiIpzTAkPU42RsqUOKLR+3y5Rd5UpB4lYlpE765SQDC/ryKH59bKUf/ySy1/Z4A== + dependencies: + pdfjs-dist "^4.9.155" + react-snap-carousel@^0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/react-snap-carousel/-/react-snap-carousel-0.5.0.tgz" @@ -6717,7 +6797,16 @@ stethoskop@1.0.0: dependencies: node-statsd "0.1.1" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -6828,7 +6917,14 @@ stringify-object@3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -7113,7 +7209,7 @@ totalist@^3.0.0: integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== "trieve-ts-sdk@file:clients/ts-sdk": - version "0.0.45" + version "0.0.49" trim-lines@^3.0.0: version "3.0.1" @@ -7743,7 +7839,16 @@ wordwrap@^1.0.0: resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==