Compare commits

...

14 Commits

Author SHA1 Message Date
ItzCrazyKns
b450d0e668 Merge branch 'canary' 2025-12-27 20:52:56 +05:30
ItzCrazyKns
0987ee4370 Update next.config.mjs 2025-12-27 20:29:11 +05:30
ItzCrazyKns
d1bd22786d Update package.json 2025-12-27 20:15:34 +05:30
ItzCrazyKns
bb7b7170ca feat(media, suggestions): handle chat history correctly 2025-12-27 20:03:34 +05:30
ItzCrazyKns
be7bd62a74 feat(prompts): update media 2025-12-27 20:02:49 +05:30
ItzCrazyKns
a691f3bab0 feat(chat-hook): fix history saving delay (async state), add delay before media search to allow component refresh 2025-12-27 20:02:36 +05:30
ItzCrazyKns
f1c9fa0e33 feat(package): bump version 2025-12-27 18:56:16 +05:30
ItzCrazyKns
d872cf5009 feat(chat-hook): prevent duplicate blocks 2025-12-27 18:36:13 +05:30
ItzCrazyKns
fdef718980 feat(transformer-provider): specify dtype 2025-12-27 18:36:01 +05:30
ItzCrazyKns
19dde42f22 feat(app): fix build errors, use webpack 2025-12-27 18:35:30 +05:30
ItzCrazyKns
c9f6893d99 feat(pdf-parse): fix DOMMatrix issues 2025-12-27 14:54:46 +05:30
ItzCrazyKns
53e9859b6c Update README.md 2025-12-27 13:35:47 +05:30
Kushagra Srivastava
53e39cd985 Merge pull request #950 from ItzCrazyKns/feat/improve-search-architecture
feat: improve search architecture, write custom API classes (remove langchain), add deep research & more
2025-12-27 13:33:54 +05:30
ItzCrazyKns
fdaa2f0646 feat(openai): update model list 2025-12-12 00:22:59 +05:30
16 changed files with 209 additions and 60 deletions

View File

@@ -239,8 +239,8 @@ Perplexica runs on Next.js and handles all API requests. It works right away on
## Upcoming Features
- [] Adding more widgets, integrations, search sources
- [] Adding authentication
- [ ] Adding more widgets, integrations, search sources
- [ ] Adding authentication
## Support Us

View File

@@ -11,6 +11,13 @@ const nextConfig = {
],
},
serverExternalPackages: ['pdf-parse'],
outputFileTracingIncludes: {
'/api/**': [
'./node_modules/@napi-rs/canvas/**',
'./node_modules/@napi-rs/canvas-linux-x64-gnu/**',
'./node_modules/@napi-rs/canvas-linux-x64-musl/**',
],
},
env: {
NEXT_PUBLIC_VERSION: pkg.version,
},

View File

@@ -1,11 +1,11 @@
{
"name": "perplexica-frontend",
"version": "1.11.2",
"name": "perplexica",
"version": "1.12.0",
"license": "MIT",
"author": "ItzCrazyKns",
"scripts": {
"dev": "next dev",
"build": "next build",
"dev": "next dev --webpack",
"build": "next build --webpack",
"start": "next start",
"lint": "next lint",
"format:write": "prettier . --write"
@@ -19,7 +19,6 @@
"@phosphor-icons/react": "^2.1.10",
"@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/typography": "^0.5.12",
"@types/jspdf": "^2.0.0",
"axios": "^1.8.3",
"better-sqlite3": "^11.9.1",
"clsx": "^2.1.0",
@@ -54,6 +53,7 @@
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.12",
"@types/jspdf": "^2.0.0",
"@types/node": "^24.8.1",
"@types/pdf-parse": "^1.1.4",
"@types/react": "^18",
@@ -68,5 +68,8 @@
"prettier": "^3.2.5",
"tailwindcss": "^3.3.0",
"typescript": "^5.9.3"
},
"optionalDependencies": {
"@napi-rs/canvas": "^0.1.87"
}
}

View File

@@ -21,7 +21,10 @@ export const POST = async (req: Request) => {
const images = await searchImages(
{
chatHistory: body.chatHistory,
chatHistory: body.chatHistory.map(([role, content]) => ({
role: role === 'human' ? 'user' : 'assistant',
content,
})),
query: body.query,
},
llm,

View File

@@ -20,7 +20,10 @@ export const POST = async (req: Request) => {
const suggestions = await generateSuggestions(
{
chatHistory: body.chatHistory,
chatHistory: body.chatHistory.map(([role, content]) => ({
role: role === 'human' ? 'user' : 'assistant',
content,
})),
},
llm,
);

View File

@@ -21,7 +21,10 @@ export const POST = async (req: Request) => {
const videos = await handleVideoSearch(
{
chatHistory: body.chatHistory,
chatHistory: body.chatHistory.map(([role, content]) => ({
role: role === 'human' ? 'user' : 'assistant',
content,
})),
query: body.query,
},
llm,

View File

@@ -50,7 +50,14 @@ const MessageBox = ({
dividerRef?: MutableRefObject<HTMLDivElement | null>;
isLast: boolean;
}) => {
const { loading, sendMessage, rewrite, messages, researchEnded } = useChat();
const {
loading,
sendMessage,
rewrite,
messages,
researchEnded,
chatHistory,
} = useChat();
const parsedMessage = section.parsedTextBlocks.join('\n\n');
const speechMessage = section.speechMessage || '';
@@ -265,11 +272,11 @@ const MessageBox = ({
<div className="lg:sticky lg:top-20 flex flex-col items-center space-y-3 w-full lg:w-3/12 z-30 h-full pb-4">
<SearchImages
query={section.message.query}
chatHistory={messages}
chatHistory={chatHistory}
messageId={section.message.messageId}
/>
<SearchVideos
chatHistory={messages}
chatHistory={chatHistory}
query={section.message.query}
messageId={section.message.messageId}
/>

View File

@@ -17,7 +17,7 @@ const SearchImages = ({
messageId,
}: {
query: string;
chatHistory: Message[];
chatHistory: [string, string][];
messageId: string;
}) => {
const [images, setImages] = useState<Image[] | null>(null);

View File

@@ -30,7 +30,7 @@ const Searchvideos = ({
messageId,
}: {
query: string;
chatHistory: Message[];
chatHistory: [string, string][];
messageId: string;
}) => {
const [videos, setVideos] = useState<Video[] | null>(null);

View File

@@ -175,7 +175,7 @@ const loadMessages = async (
chatId: string,
setMessages: (messages: Message[]) => void,
setIsMessagesLoaded: (loaded: boolean) => void,
setChatHistory: (history: [string, string][]) => void,
chatHistory: React.MutableRefObject<[string, string][]>,
setSources: (sources: string[]) => void,
setNotFound: (notFound: boolean) => void,
setFiles: (files: File[]) => void,
@@ -233,7 +233,7 @@ const loadMessages = async (
setFiles(files);
setFileIds(files.map((file: File) => file.fileId));
setChatHistory(history);
chatHistory.current = history;
setSources(data.chat.sources);
setIsMessagesLoaded(true);
};
@@ -281,7 +281,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
const [researchEnded, setResearchEnded] = useState(false);
const [chatHistory, setChatHistory] = useState<[string, string][]>([]);
const chatHistory = useRef<[string, string][]>([]);
const [messages, setMessages] = useState<Message[]>([]);
const [files, setFiles] = useState<File[]>([]);
@@ -402,7 +402,12 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
});
}, [messages]);
const isReconnectingRef = useRef(false);
const handledMessageEndRef = useRef<Set<string>>(new Set());
const checkReconnect = async () => {
if (isReconnectingRef.current) return;
setIsReady(true);
console.debug(new Date(), 'app:ready');
@@ -414,6 +419,8 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
setResearchEnded(false);
setMessageAppeared(false);
isReconnectingRef.current = true;
const res = await fetch(`/api/reconnect/${lastMsg.backendId}`, {
method: 'POST',
});
@@ -427,23 +434,27 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
const messageHandler = getMessageHandler(lastMsg);
while (true) {
const { value, done } = await reader.read();
if (done) break;
try {
while (true) {
const { value, done } = await reader.read();
if (done) break;
partialChunk += decoder.decode(value, { stream: true });
partialChunk += decoder.decode(value, { stream: true });
try {
const messages = partialChunk.split('\n');
for (const msg of messages) {
if (!msg.trim()) continue;
const json = JSON.parse(msg);
messageHandler(json);
try {
const messages = partialChunk.split('\n');
for (const msg of messages) {
if (!msg.trim()) continue;
const json = JSON.parse(msg);
messageHandler(json);
}
partialChunk = '';
} catch (error) {
console.warn('Incomplete JSON, waiting for next chunk...');
}
partialChunk = '';
} catch (error) {
console.warn('Incomplete JSON, waiting for next chunk...');
}
} finally {
isReconnectingRef.current = false;
}
}
}
@@ -463,7 +474,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
if (params.chatId && params.chatId !== chatId) {
setChatId(params.chatId);
setMessages([]);
setChatHistory([]);
chatHistory.current = [];
setFiles([]);
setFileIds([]);
setIsMessagesLoaded(false);
@@ -483,7 +494,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
chatId,
setMessages,
setIsMessagesLoaded,
setChatHistory,
chatHistory,
setSources,
setNotFound,
setFiles,
@@ -519,9 +530,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
setMessages((prev) => prev.slice(0, index));
setChatHistory((prev) => {
return prev.slice(0, index * 2);
});
chatHistory.current = chatHistory.current.slice(0, index * 2);
const messageToRewrite = messages[index];
sendMessage(messageToRewrite.query, messageToRewrite.messageId, true);
@@ -570,6 +579,20 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
setMessages((prev) =>
prev.map((msg) => {
if (msg.messageId === messageId) {
const exists = msg.responseBlocks.findIndex(
(b) => b.id === data.block.id,
);
if (exists !== -1) {
const existingBlocks = [...msg.responseBlocks];
existingBlocks[exists] = data.block;
return {
...msg,
responseBlocks: existingBlocks,
};
}
return {
...msg,
responseBlocks: [...msg.responseBlocks, data.block],
@@ -607,12 +630,18 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
}
if (data.type === 'messageEnd') {
if (handledMessageEndRef.current.has(messageId)) {
return;
}
handledMessageEndRef.current.add(messageId);
const currentMsg = messagesRef.current.find(
(msg) => msg.messageId === messageId,
);
const newHistory: [string, string][] = [
...chatHistory,
...chatHistory.current,
['human', message.query],
[
'assistant',
@@ -621,7 +650,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
],
];
setChatHistory(newHistory);
chatHistory.current = newHistory;
setMessages((prev) =>
prev.map((msg) =>
@@ -638,13 +667,15 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
const autoMediaSearch = getAutoMediaSearch();
if (autoMediaSearch) {
document
.getElementById(`search-images-${lastMsg.messageId}`)
?.click();
setTimeout(() => {
document
.getElementById(`search-images-${lastMsg.messageId}`)
?.click();
document
.getElementById(`search-videos-${lastMsg.messageId}`)
?.click();
document
.getElementById(`search-videos-${lastMsg.messageId}`)
?.click();
}, 200);
}
// Check if there are sources and no suggestions
@@ -728,8 +759,11 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
sources: sources,
optimizationMode: optimizationMode,
history: rewrite
? chatHistory.slice(0, messageIndex === -1 ? undefined : messageIndex)
: chatHistory,
? chatHistory.current.slice(
0,
messageIndex === -1 ? undefined : messageIndex,
)
: chatHistory.current,
chatModel: {
key: chatModelProvider.key,
providerId: chatModelProvider.providerId,
@@ -776,7 +810,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
value={{
messages,
sections,
chatHistory,
chatHistory: chatHistory.current,
files,
fileIds,
sources,

View File

@@ -61,6 +61,22 @@ const defaultChatModels: Model[] = [
name: 'GPT 5 Mini',
key: 'gpt-5-mini',
},
{
name: 'GPT 5 Pro',
key: 'gpt-5-pro',
},
{
name: 'GPT 5.1',
key: 'gpt-5.1',
},
{
name: 'GPT 5.2',
key: 'gpt-5.2',
},
{
name: 'GPT 5.2 Pro',
key: 'gpt-5.2-pro',
},
{
name: 'o1',
key: 'o1',

View File

@@ -1,6 +1,6 @@
import { Chunk } from '@/lib/types';
import BaseEmbedding from '../../base/embedding';
import { FeatureExtractionPipeline, pipeline } from '@huggingface/transformers';
import { FeatureExtractionPipeline } from '@huggingface/transformers';
type TransformerConfig = {
model: string;
@@ -21,21 +21,19 @@ class TransformerEmbedding extends BaseEmbedding<TransformerConfig> {
return this.embed(chunks.map((c) => c.content));
}
async embed(texts: string[]): Promise<number[][]> {
private async embed(texts: string[]) {
if (!this.pipelinePromise) {
this.pipelinePromise = (async () => {
const transformers = await import('@huggingface/transformers');
return (await transformers.pipeline(
'feature-extraction',
this.config.model,
)) as unknown as FeatureExtractionPipeline;
const { pipeline } = await import('@huggingface/transformers');
const result = await pipeline('feature-extraction', this.config.model, {
dtype: 'fp32',
});
return result as FeatureExtractionPipeline;
})();
}
const pipeline = await this.pipelinePromise;
const output = await pipeline(texts, { pooling: 'mean', normalize: true });
const pipe = await this.pipelinePromise;
const output = await pipe(texts, { pooling: 'mean', normalize: true });
return output.tolist() as number[][];
}
}

View File

@@ -3,6 +3,7 @@ import { ChatTurnMessage } from '@/lib/types';
export const imageSearchPrompt = `
You will be given a conversation below and a follow up question. You need to rephrase the follow-up question so it is a standalone question that can be used by the LLM to search the web for images.
You need to make sure the rephrased question agrees with the conversation and is relevant to the conversation.
Make sure to make the querey standalone and not something very broad, use context from the answers in the conversation to make it specific so user can get best image search results.
Output only the rephrased query in query key JSON format. Do not include any explanation or additional text.
`;

View File

@@ -3,6 +3,7 @@ import { ChatTurnMessage } from '@/lib/types';
export const videoSearchPrompt = `
You will be given a conversation below and a follow up question. You need to rephrase the follow-up question so it is a standalone question that can be used by the LLM to search Youtube for videos.
You need to make sure the rephrased question agrees with the conversation and is relevant to the conversation.
Make sure to make the querey standalone and not something very broad, use context from the answers in the conversation to make it specific so user can get best video search results.
Output only the rephrased query in query key JSON format. Do not include any explanation or additional text.
`;

View File

@@ -4,8 +4,8 @@ import crypto from "crypto"
import fs from 'fs';
import { splitText } from "../utils/splitText";
import { PDFParse } from 'pdf-parse';
import { CanvasFactory } from 'pdf-parse/worker';
import officeParser from 'officeparser'
import { Chunk } from "../types";
const supportedMimeTypes = ['application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'text/plain'] as const
@@ -116,7 +116,8 @@ class UploadManager {
const pdfBuffer = fs.readFileSync(filePath);
const parser = new PDFParse({
data: pdfBuffer
data: pdfBuffer,
CanvasFactory
})
const pdfText = await parser.getText().then(res => res.text)

View File

@@ -797,6 +797,11 @@
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.84.tgz#7b476e3003be0aca08ab27962fd0d6e803939bec"
integrity sha512-pdvuqvj3qtwVryqgpAGornJLV6Ezpk39V6wT4JCnRVGy8I3Tk1au8qOalFGrx/r0Ig87hWslysPpHBxVpBMIww==
"@napi-rs/canvas-android-arm64@0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.87.tgz#6adce7741baa56e75dcf72076e4bf249f9bc4b8e"
integrity sha512-uW7NxJXPvZft9fers4oBhdCsBRVe77DLQS3eXEOxndFzGKiwmjIbZpQqj4QPvrg3I0FM3UfHatz1+17P5SeCOQ==
"@napi-rs/canvas-darwin-arm64@0.1.80":
version "0.1.80"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.80.tgz#638eaa2d0a2a373c7d15748743182718dcd95c4b"
@@ -807,6 +812,11 @@
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.84.tgz#0f131722f9f66316cea5f5ed7cfb9ad1290683cd"
integrity sha512-A8IND3Hnv0R6abc6qCcCaOCujTLMmGxtucMTZ5vbQUrEN/scxi378MyTLtyWg+MRr6bwQJ6v/orqMS9datIcww==
"@napi-rs/canvas-darwin-arm64@0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.87.tgz#54f82dc0cd032f85e770abcddbeafc855005931a"
integrity sha512-S6YbpXwajDKLTsYftEqR+Ne1lHpeC78okI3IqctVdFexN31Taprn6mdV4CkPY/4S8eGNuReBHvXNyWbGqBZ1eQ==
"@napi-rs/canvas-darwin-x64@0.1.80":
version "0.1.80"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.80.tgz#bd6bc048dbd4b02b9620d9d07117ed93e6970978"
@@ -817,6 +827,11 @@
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.84.tgz#e6ab8c534172d8a8d434fa090da8a205359d8769"
integrity sha512-AUW45lJhYWwnA74LaNeqhvqYKK/2hNnBBBl03KRdqeCD4tKneUSrxUqIv8d22CBweOvrAASyKN3W87WO2zEr/A==
"@napi-rs/canvas-darwin-x64@0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.87.tgz#54c2be73ce69a65e70f3d94fb879907479cc12c5"
integrity sha512-OJLwP2WIUmRSqWTyV/NZ2TnvBzUsbNqQu6IL7oshwfxYg4BELPV279wrfQ/xZFqzr7wybfIzKaPF4du5ZdA2Cg==
"@napi-rs/canvas-linux-arm-gnueabihf@0.1.80":
version "0.1.80"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.80.tgz#ce6bfbeb19d9234c42df5c384e5989aa7d734789"
@@ -827,6 +842,11 @@
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.84.tgz#5898daa3050a8ba4619c1d6cea3a3217d46c5ffd"
integrity sha512-8zs5ZqOrdgs4FioTxSBrkl/wHZB56bJNBqaIsfPL4ZkEQCinOkrFF7xIcXiHiKp93J3wUtbIzeVrhTIaWwqk+A==
"@napi-rs/canvas-linux-arm-gnueabihf@0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.87.tgz#1bc3c9280db381cc3893c3d13d7320666ce47ebe"
integrity sha512-Io3tY6ogc+oyvIGK9rQlnfH4gKiS35P7W6s22x3WCrLFR0dXzZP2IBBoEFEHd6FY6FR1ky5u9cRmADaiLRdX3g==
"@napi-rs/canvas-linux-arm64-gnu@0.1.80":
version "0.1.80"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.80.tgz#3b7a7832fef763826fa5fb740d5757204e52607d"
@@ -837,6 +857,11 @@
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.84.tgz#fbbde94c04278259f1f40b4c199dfd9f95c82e66"
integrity sha512-i204vtowOglJUpbAFWU5mqsJgH0lVpNk/Ml4mQtB4Lndd86oF+Otr6Mr5KQnZHqYGhlSIKiU2SYnUbhO28zGQA==
"@napi-rs/canvas-linux-arm64-gnu@0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.87.tgz#70af2d77d58d65559a43c55f6c37906c220af39e"
integrity sha512-Zq7h/PQzs37gaSR/gNRZOAaCC1kGt6NmDjA1PcqpONITh/rAfAwAeP98emrbBJ4FDoPkYRkxmxHlmXNLlsQIBw==
"@napi-rs/canvas-linux-arm64-musl@0.1.80":
version "0.1.80"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.80.tgz#d8ccd91f31d70760628623cd575134ada17690a3"
@@ -847,6 +872,11 @@
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.84.tgz#8b02c46c5dbb0a58de87885c61ca1681b1199697"
integrity sha512-VyZq0EEw+OILnWk7G3ZgLLPaz1ERaPP++jLjeyLMbFOF+Tr4zHzWKiKDsEV/cT7btLPZbVoR3VX+T9/QubnURQ==
"@napi-rs/canvas-linux-arm64-musl@0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.87.tgz#31355f0debf35848851be97aa1136905db9cef2a"
integrity sha512-CUa5YJjpsFcUxJbtfoQ4bqO/Rq+JU/2RfTNFxx07q1AjuDjCM8+MOOLCvVOV1z3qhl6nKAtjJT0pA0J8EbnK8Q==
"@napi-rs/canvas-linux-riscv64-gnu@0.1.80":
version "0.1.80"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.80.tgz#927a3b859a0e3c691beaf52a19bc4736c4ffc9b8"
@@ -857,6 +887,11 @@
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.84.tgz#787c9c207f69aaa51b852c7063a6eed2985b7fca"
integrity sha512-PSMTh8DiThvLRsbtc/a065I/ceZk17EXAATv9uNvHgkgo7wdEfTh2C3aveNkBMGByVO3tvnvD5v/YFtZL07cIg==
"@napi-rs/canvas-linux-riscv64-gnu@0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.87.tgz#031d3d30cf667586ad742c5846a0e086c7ada950"
integrity sha512-5KM4dBFEzFMNkJV2rheIQWpd+mRZA7VNDnxTT7nsCEf6DUjUnf6Hssq9bAwjVYTe4jqraDHbWRbF4uXLBLRFJg==
"@napi-rs/canvas-linux-x64-gnu@0.1.80":
version "0.1.80"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.80.tgz#25c0416bcedd6fadc15295e9afa8d9697232050c"
@@ -867,6 +902,11 @@
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.84.tgz#fb6eaea81ce679575b5004bc2177ce2d9222642b"
integrity sha512-N1GY3noO1oqgEo3rYQIwY44kfM11vA0lDbN0orTOHfCSUZTUyiYCY0nZ197QMahZBm1aR/vYgsWpV74MMMDuNA==
"@napi-rs/canvas-linux-x64-gnu@0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.87.tgz#9fcc1dd2574aebe7e57797196712106665948dd0"
integrity sha512-zSv+ozz9elT5YhocyogX5LwVYURChO4QGD6CQIW6OnuNA0UOMDD/b4wDzlJiMphISy3EVTntlKFhe4W3EuKcxw==
"@napi-rs/canvas-linux-x64-musl@0.1.80":
version "0.1.80"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.80.tgz#de85d644e09120a60996bbe165cc2efee804551b"
@@ -877,6 +917,16 @@
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.84.tgz#54a37352a0be7f2a7218b6f11d8ae9b5cdbb3d6c"
integrity sha512-vUZmua6ADqTWyHyei81aXIt9wp0yjeNwTH0KdhdeoBb6azHmFR8uKTukZMXfLCC3bnsW0t4lW7K78KNMknmtjg==
"@napi-rs/canvas-linux-x64-musl@0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.87.tgz#170b7fe76f1b52a947bc287cd3c84f15d210b863"
integrity sha512-jTNmicAZQ70X+cbjZz6G6w8lmORwxRBmj/U20ECNYvcWVLshgyCKWPFL2I0Z6pkJve0vZWls6oZ15iccm1sv8w==
"@napi-rs/canvas-win32-arm64-msvc@0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.87.tgz#6536946c5a1796b0781700ee6b39ac18fc0e96b2"
integrity sha512-p6J7UNAxKHYc7AL0glEtYuW/E0OLLUNnLti8dA2OT51p08Il4T7yZCl+iNo6f73HntFP+dgOHh2cTXUhmk8GuA==
"@napi-rs/canvas-win32-x64-msvc@0.1.80":
version "0.1.80"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.80.tgz#6bb95885d9377912d71f1372fc1916fb54d6ef0a"
@@ -887,6 +937,11 @@
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.84.tgz#e0039b89f8e04287c77bd1fb5e6fa671d6c9d3c8"
integrity sha512-YSs8ncurc1xzegUMNnQUTYrdrAuaXdPMOa+iYYyAxydOtg0ppV386hyYMsy00Yip1NlTgLCseRG4sHSnjQx6og==
"@napi-rs/canvas-win32-x64-msvc@0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.87.tgz#058b13a9dd3a6180bdfa976b7c8814cfb9df9c8f"
integrity sha512-WrwfETMLBRFWkGU8fXU50gCpA2eIjR4NE9JyTKl86Kz5g6SDp0CcuqS2phYtB66TI2HDUhTPbNrk4V7Qf1FOLA==
"@napi-rs/canvas@0.1.80":
version "0.1.80"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas/-/canvas-0.1.80.tgz#53615bea56fd94e07331ab13caa7a39efc4914ab"
@@ -919,6 +974,23 @@
"@napi-rs/canvas-linux-x64-musl" "0.1.84"
"@napi-rs/canvas-win32-x64-msvc" "0.1.84"
"@napi-rs/canvas@^0.1.87":
version "0.1.87"
resolved "https://registry.yarnpkg.com/@napi-rs/canvas/-/canvas-0.1.87.tgz#028e581af4499ee4ca569eb10cb5705526fee68d"
integrity sha512-Zb5tePmPMOYBcuNW3NQaVM1sIkvIfel39euiOab/XMjC5Oc/AnPJLa/BacJcToGyIvehecS6eqcsF7i0Wqe1Sw==
optionalDependencies:
"@napi-rs/canvas-android-arm64" "0.1.87"
"@napi-rs/canvas-darwin-arm64" "0.1.87"
"@napi-rs/canvas-darwin-x64" "0.1.87"
"@napi-rs/canvas-linux-arm-gnueabihf" "0.1.87"
"@napi-rs/canvas-linux-arm64-gnu" "0.1.87"
"@napi-rs/canvas-linux-arm64-musl" "0.1.87"
"@napi-rs/canvas-linux-riscv64-gnu" "0.1.87"
"@napi-rs/canvas-linux-x64-gnu" "0.1.87"
"@napi-rs/canvas-linux-x64-musl" "0.1.87"
"@napi-rs/canvas-win32-arm64-msvc" "0.1.87"
"@napi-rs/canvas-win32-x64-msvc" "0.1.87"
"@next/env@16.0.7":
version "16.0.7"
resolved "https://registry.yarnpkg.com/@next/env/-/env-16.0.7.tgz#eda56377a865d890d25122257d2b8a85b81d6d3d"