Compare commits

...

26 Commits

Author SHA1 Message Date
ItzCrazyKns
4ee3173368 feat(config): add setupComplete 2025-10-15 09:04:48 +05:30
ItzCrazyKns
6d61528347 feat(configManager): add update & removal methods 2025-10-14 13:33:14 +05:30
ItzCrazyKns
c02e535f4c feat(openAiProvider): use find instead of filter 2025-10-14 13:05:56 +05:30
ItzCrazyKns
a375de73cc feat(openAiProvider): load models from config as well 2025-10-14 13:05:19 +05:30
ItzCrazyKns
87226957f1 feat(serverRegistry): add server-side config opts 2025-10-14 13:04:26 +05:30
ItzCrazyKns
77743949c7 feat(configManager): fix circular import issues 2025-10-14 13:04:06 +05:30
ItzCrazyKns
64c4514cad feat(models): add id & name fields, move getUIConfigSection to seperate file 2025-10-14 13:03:17 +05:30
ItzCrazyKns
999553877d feat(app): lint & beautify 2025-10-14 10:05:31 +05:30
ItzCrazyKns
e45a9af9ff feat(config): add client side and server side config registries 2025-10-13 22:01:17 +05:30
ItzCrazyKns
e7fbab12ed feat(config): add getConfig method 2025-10-13 21:58:30 +05:30
ItzCrazyKns
387da5dbdd feat(instrumentation): run config migrations 2025-10-11 18:00:31 +05:30
ItzCrazyKns
3003d44544 feat(app): initialize new config management 2025-10-11 18:00:06 +05:30
ItzCrazyKns
f1e6aa9c1a feat(app): add serverUtils, create hashObj util 2025-10-11 17:59:45 +05:30
ItzCrazyKns
f39638fe02 feat(app): initialize new model management 2025-10-11 17:59:27 +05:30
ItzCrazyKns
535c0b9897 feat(app): use instrumentation for migrations 2025-10-11 17:35:27 +05:30
ItzCrazyKns
47350b34ec feat(ui): make ui more reactive 2025-10-08 22:19:58 +05:30
ItzCrazyKns
7c97df98c7 Update perplexica-screenshot.png 2025-10-07 16:45:55 +05:30
ItzCrazyKns
b084c42aca Update perplexica-screenshot.png 2025-10-07 16:21:31 +05:30
ItzCrazyKns
fdfa2f3ea6 Update perplexica-screenshot.png 2025-10-07 16:13:56 +05:30
ItzCrazyKns
3323e7a0ed feat(package): bump version, update screenshot 2025-10-07 16:11:10 +05:30
ItzCrazyKns
d4f9da34c6 feat(tailwind-config): update theme 2025-10-07 15:07:26 +05:30
ItzCrazyKns
10ed67c753 feat(workflow): build images for canary 2025-10-06 20:00:31 +05:30
ItzCrazyKns
cf3cc4e638 feat(migrator): use DATA_DIR env var 2025-10-06 10:13:34 +05:30
ItzCrazyKns
46b9e41100 feat(db-table): add default values for createdAt 2025-10-06 08:59:01 +05:30
sjiampojamarn
02adafbd4b Handling double stringify JSON parsing 2025-10-05 10:46:01 -07:00
ItzCrazyKns
f141d4719c feat(assets): update preview image 2025-10-05 22:32:17 +05:30
20 changed files with 859 additions and 26 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 KiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@@ -4,6 +4,7 @@ on:
push: push:
branches: branches:
- master - master
- canary
release: release:
types: [published] types: [published]
@@ -43,6 +44,19 @@ jobs:
-t itzcrazykns1337/${IMAGE_NAME}:amd64 \ -t itzcrazykns1337/${IMAGE_NAME}:amd64 \
--push . --push .
- name: Build and push AMD64 Canary Docker image
if: github.ref == 'refs/heads/canary' && github.event_name == 'push'
run: |
DOCKERFILE=app.dockerfile
IMAGE_NAME=perplexica
docker buildx build --platform linux/amd64 \
--cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:canary-amd64 \
--cache-to=type=inline \
--provenance false \
-f $DOCKERFILE \
-t itzcrazykns1337/${IMAGE_NAME}:canary-amd64 \
--push .
- name: Build and push AMD64 release Docker image - name: Build and push AMD64 release Docker image
if: github.event_name == 'release' if: github.event_name == 'release'
run: | run: |
@@ -91,6 +105,19 @@ jobs:
-t itzcrazykns1337/${IMAGE_NAME}:arm64 \ -t itzcrazykns1337/${IMAGE_NAME}:arm64 \
--push . --push .
- name: Build and push ARM64 Canary Docker image
if: github.ref == 'refs/heads/canary' && github.event_name == 'push'
run: |
DOCKERFILE=app.dockerfile
IMAGE_NAME=perplexica
docker buildx build --platform linux/arm64 \
--cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:canary-arm64 \
--cache-to=type=inline \
--provenance false \
-f $DOCKERFILE \
-t itzcrazykns1337/${IMAGE_NAME}:canary-arm64 \
--push .
- name: Build and push ARM64 release Docker image - name: Build and push ARM64 release Docker image
if: github.event_name == 'release' if: github.event_name == 'release'
run: | run: |
@@ -128,6 +155,15 @@ jobs:
--amend itzcrazykns1337/${IMAGE_NAME}:arm64 --amend itzcrazykns1337/${IMAGE_NAME}:arm64
docker manifest push itzcrazykns1337/${IMAGE_NAME}:main docker manifest push itzcrazykns1337/${IMAGE_NAME}:main
- name: Create and push multi-arch manifest for canary
if: github.ref == 'refs/heads/canary' && github.event_name == 'push'
run: |
IMAGE_NAME=perplexica
docker manifest create itzcrazykns1337/${IMAGE_NAME}:canary \
--amend itzcrazykns1337/${IMAGE_NAME}:canary-amd64 \
--amend itzcrazykns1337/${IMAGE_NAME}:canary-arm64
docker manifest push itzcrazykns1337/${IMAGE_NAME}:canary
- name: Create and push multi-arch manifest for releases - name: Create and push multi-arch manifest for releases
if: github.event_name == 'release' if: github.event_name == 'release'
run: | run: |

View File

@@ -15,9 +15,6 @@ COPY drizzle ./drizzle
RUN mkdir -p /home/perplexica/data RUN mkdir -p /home/perplexica/data
RUN yarn build RUN yarn build
RUN yarn add --dev @vercel/ncc
RUN yarn ncc build ./src/lib/db/migrate.ts -o migrator
FROM node:24.5.0-slim FROM node:24.5.0-slim
RUN apt-get update && apt-get install -y python3 python3-pip sqlite3 && rm -rf /var/lib/apt/lists/* RUN apt-get update && apt-get install -y python3 python3-pip sqlite3 && rm -rf /var/lib/apt/lists/*
@@ -30,8 +27,6 @@ COPY --from=builder /home/perplexica/.next/static ./public/_next/static
COPY --from=builder /home/perplexica/.next/standalone ./ COPY --from=builder /home/perplexica/.next/standalone ./
COPY --from=builder /home/perplexica/data ./data COPY --from=builder /home/perplexica/data ./data
COPY drizzle ./drizzle COPY drizzle ./drizzle
COPY --from=builder /home/perplexica/migrator/build ./build
COPY --from=builder /home/perplexica/migrator/index.js ./migrate.js
RUN mkdir /home/perplexica/uploads RUN mkdir /home/perplexica/uploads

View File

@@ -1,6 +1,4 @@
#!/bin/sh #!/bin/sh
set -e set -e
node migrate.js
exec node server.js exec node server.js

View File

@@ -1,18 +1,18 @@
{ {
"name": "perplexica-frontend", "name": "perplexica-frontend",
"version": "1.11.0-rc2", "version": "1.11.0-rc3",
"license": "MIT", "license": "MIT",
"author": "ItzCrazyKns", "author": "ItzCrazyKns",
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "npm run db:migrate && next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"format:write": "prettier . --write", "format:write": "prettier . --write"
"db:migrate": "node ./src/lib/db/migrate.ts"
}, },
"dependencies": { "dependencies": {
"@headlessui/react": "^2.2.0", "@headlessui/react": "^2.2.0",
"@headlessui/tailwindcss": "^0.2.2",
"@iarna/toml": "^2.2.5", "@iarna/toml": "^2.2.5",
"@icons-pack/react-simple-icons": "^12.3.0", "@icons-pack/react-simple-icons": "^12.3.0",
"@langchain/anthropic": "^0.3.24", "@langchain/anthropic": "^0.3.24",
@@ -65,6 +65,7 @@
"postcss": "^8", "postcss": "^8",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"tailwindcss": "^3.3.0", "tailwindcss": "^3.3.0",
"ts-node": "^10.9.2",
"typescript": "^5" "typescript": "^5"
} }
} }

View File

@@ -63,7 +63,7 @@ const Focus = () => {
<Popover className="relative w-full max-w-[15rem] md:max-w-md lg:max-w-lg mt-[6.5px]"> <Popover className="relative w-full max-w-[15rem] md:max-w-md lg:max-w-lg mt-[6.5px]">
<PopoverButton <PopoverButton
type="button" type="button"
className=" text-black/50 dark:text-white/50 rounded-xl hover:bg-light-secondary dark:hover:bg-dark-secondary active:scale-95 transition duration-200 hover:text-black dark:hover:text-white" className="active:border-none headless-open:text-black dark:headless-open:text-white text-black/50 dark:text-white/50 rounded-xl hover:bg-light-secondary dark:hover:bg-dark-secondary active:scale-95 transition duration-200 hover:text-black dark:hover:text-white"
> >
{focusMode !== 'webSearch' ? ( {focusMode !== 'webSearch' ? (
<div className="flex flex-row items-center space-x-1"> <div className="flex flex-row items-center space-x-1">

13
src/instrumentation.ts Normal file
View File

@@ -0,0 +1,13 @@
export const register = async () => {
if (process.env.NEXT_RUNTIME === 'nodejs') {
try {
console.log('Running database migrations...');
await import('./lib/db/migrate');
console.log('Database migrations completed successfully');
} catch (error) {
console.error('Failed to run database migrations:', error);
}
await import('./lib/config/index');
}
};

View File

@@ -0,0 +1,16 @@
'use client';
const getClientConfig = (key: string, defaultVal?: any) => {
return localStorage.getItem(key) ?? defaultVal ?? undefined;
};
export const getTheme = () => getClientConfig('theme', 'dark');
export const getAutoImageSearch = () =>
Boolean(getClientConfig('autoImageSearch', 'true'));
export const getAutoVideoSearch = () =>
Boolean(getClientConfig('autoVideoSearch', 'true'));
export const getSystemInstructions = () =>
getClientConfig('systemInstructions', '');

213
src/lib/config/index.ts Normal file
View File

@@ -0,0 +1,213 @@
import path from 'node:path';
import fs from 'fs';
import { Config, ConfigModelProvider, UIConfigSections } from './types';
import { hashObj } from '../serverUtils';
import { getModelProvidersUIConfigSection } from '../models/providers';
class ConfigManager {
configPath: string = path.join(
process.env.DATA_DIR || process.cwd(),
'/data/config.json',
);
configVersion = 1;
currentConfig: Config = {
version: this.configVersion,
setupComplete: false,
general: {},
modelProviders: [],
};
uiConfigSections: UIConfigSections = {
general: [],
modelProviders: [],
};
constructor() {
this.initialize();
}
private initialize() {
this.initializeConfig();
this.initializeFromEnv();
}
private saveConfig() {
fs.writeFileSync(
this.configPath,
JSON.stringify(this.currentConfig, null, 2),
);
}
private initializeConfig() {
const exists = fs.existsSync(this.configPath);
if (!exists) {
fs.writeFileSync(
this.configPath,
JSON.stringify(this.currentConfig, null, 2),
);
} else {
try {
this.currentConfig = JSON.parse(
fs.readFileSync(this.configPath, 'utf-8'),
);
} catch (err) {
if (err instanceof SyntaxError) {
console.error(
`Error parsing config file at ${this.configPath}:`,
err,
);
console.log(
'Loading default config and overwriting the existing file.',
);
fs.writeFileSync(
this.configPath,
JSON.stringify(this.currentConfig, null, 2),
);
return;
} else {
console.log('Unknown error reading config file:', err);
}
}
this.currentConfig = this.migrateConfig(this.currentConfig);
}
}
private migrateConfig(config: Config): Config {
/* TODO: Add migrations */
return config;
}
private initializeFromEnv() {
const providerConfigSections = getModelProvidersUIConfigSection();
this.uiConfigSections.modelProviders = providerConfigSections;
const newProviders: ConfigModelProvider[] = [];
providerConfigSections.forEach((provider) => {
const newProvider: ConfigModelProvider & { required?: string[] } = {
id: crypto.randomUUID(),
name: `${provider.name} ${Math.floor(Math.random() * 1000)}`,
type: provider.key,
chatModels: [],
embeddingModels: [],
config: {},
required: [],
hash: '',
};
provider.fields.forEach((field) => {
newProvider.config[field.key] =
process.env[field.env!] ||
field.default ||
''; /* Env var must exist for providers */
if (field.required) newProvider.required?.push(field.key);
});
let configured = true;
newProvider.required?.forEach((r) => {
if (!newProvider.config[r]) {
configured = false;
}
});
if (configured) {
const hash = hashObj(newProvider.config);
newProvider.hash = hash;
delete newProvider.required;
const exists = this.currentConfig.modelProviders.find(
(p) => p.hash === hash,
);
if (!exists) {
newProviders.push(newProvider);
}
}
});
this.currentConfig.modelProviders.push(...newProviders);
this.saveConfig();
}
public getConfig(key: string, defaultValue?: any): any {
const nested = key.split('.');
let obj: any = this.currentConfig;
for (let i = 0; i < nested.length; i++) {
const part = nested[i];
if (obj == null) return defaultValue;
obj = obj[part];
}
return obj === undefined ? defaultValue : obj;
}
public updateConfig(key: string, val: any) {
const parts = key.split('.');
if (parts.length === 0) return;
let target: any = this.currentConfig;
for (let i = 0; i < parts.length - 1; i++) {
const part = parts[i];
if (target[part] === null || typeof target[part] !== 'object') {
target[part] = {};
}
target = target[part];
}
const finalKey = parts[parts.length - 1];
target[finalKey] = val;
this.saveConfig();
}
public addModelProvider(type: string, name: string, config: any) {
const newModelProvider: ConfigModelProvider = {
id: crypto.randomUUID(),
name,
type,
config,
chatModels: [],
embeddingModels: [],
hash: hashObj(config),
};
this.currentConfig.modelProviders.push(newModelProvider);
this.saveConfig();
}
public removeModelProvider(id: string) {
const index = this.currentConfig.modelProviders.findIndex(
(p) => p.id === id,
);
if (index === -1) return;
this.currentConfig.modelProviders =
this.currentConfig.modelProviders.filter((p) => p.id !== id);
this.saveConfig();
}
public isSetupComplete() {
return this.currentConfig.setupComplete
}
public markSetupComplete() {
if (!this.currentConfig.setupComplete) {
this.currentConfig.setupComplete = true
}
this.saveConfig()
}
}
const configManager = new ConfigManager();
export default configManager;

View File

@@ -0,0 +1,12 @@
import configManager from './index';
import { ConfigModelProvider } from './types';
export const getConfiguredModelProviders = (): ConfigModelProvider[] => {
return configManager.getConfig('modelProviders', []);
};
export const getConfiguredModelProviderById = (
id: string,
): ConfigModelProvider | undefined => {
return getConfiguredModelProviders().find((p) => p.id === id) ?? undefined;
};

85
src/lib/config/types.ts Normal file
View File

@@ -0,0 +1,85 @@
import { Model } from '../models/types';
type BaseUIConfigField = {
name: string;
key: string;
required: boolean;
description: string;
scope: 'client' | 'server';
env?: string;
};
type StringUIConfigField = BaseUIConfigField & {
type: 'string';
placeholder?: string;
default?: string;
};
type SelectUIConfigFieldOptions = {
name: string;
key: string;
value: string;
};
type SelectUIConfigField = BaseUIConfigField & {
type: 'select';
default?: string;
options: SelectUIConfigFieldOptions[];
};
type PasswordUIConfigField = BaseUIConfigField & {
type: 'password';
placeholder?: string;
default?: string;
};
type UIConfigField =
| StringUIConfigField
| SelectUIConfigField
| PasswordUIConfigField;
type ConfigModelProvider = {
id: string;
name: string;
type: string;
chatModels: Model[];
embeddingModels: Model[];
config: { [key: string]: any };
hash: string;
};
type Config = {
version: number;
setupComplete: boolean;
general: {
[key: string]: any;
};
modelProviders: ConfigModelProvider[];
};
type EnvMap = {
[key: string]: {
fieldKey: string;
providerKey: string;
};
};
type ModelProviderUISection = {
name: string;
key: string;
fields: UIConfigField[];
};
type UIConfigSections = {
general: UIConfigField[];
modelProviders: ModelProviderUISection[];
};
export type {
UIConfigField,
Config,
EnvMap,
UIConfigSections,
ModelProviderUISection,
ConfigModelProvider,
};

View File

@@ -2,9 +2,12 @@ import Database from 'better-sqlite3';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
const db = new Database(path.join(process.cwd(), 'data', 'db.sqlite')); const DATA_DIR = process.env.DATA_DIR || process.cwd();
const dbPath = path.join(DATA_DIR, './data/db.sqlite');
const migrationsFolder = path.join(process.cwd(), 'drizzle'); const db = new Database(dbPath);
const migrationsFolder = path.join(DATA_DIR, 'drizzle');
db.exec(` db.exec(`
CREATE TABLE IF NOT EXISTS ran_migrations ( CREATE TABLE IF NOT EXISTS ran_migrations (
@@ -54,7 +57,7 @@ fs.readdirSync(migrationsFolder)
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
type TEXT NOT NULL, type TEXT NOT NULL,
chatId TEXT NOT NULL, chatId TEXT NOT NULL,
createdAt TEXT NOT NULL, createdAt TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
messageId TEXT NOT NULL, messageId TEXT NOT NULL,
content TEXT, content TEXT,
sources TEXT DEFAULT '[]' sources TEXT DEFAULT '[]'
@@ -67,8 +70,10 @@ fs.readdirSync(migrationsFolder)
`); `);
messages.forEach((msg: any) => { messages.forEach((msg: any) => {
if (msg.type === 'user') { while (typeof msg.metadata === 'string') {
msg.metadata = JSON.parse(msg.metadata || '{}'); msg.metadata = JSON.parse(msg.metadata || '{}');
}
if (msg.type === 'user') {
insertMessage.run( insertMessage.run(
'user', 'user',
msg.chatId, msg.chatId,
@@ -78,7 +83,6 @@ fs.readdirSync(migrationsFolder)
'[]', '[]',
); );
} else if (msg.type === 'assistant') { } else if (msg.type === 'assistant') {
msg.metadata = JSON.parse(msg.metadata || '{}');
insertMessage.run( insertMessage.run(
'assistant', 'assistant',
msg.chatId, msg.chatId,

View File

@@ -0,0 +1,45 @@
import { Embeddings } from '@langchain/core/embeddings';
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import { UIConfigField } from '@/lib/config/types';
abstract class BaseModelProvider<CONFIG> {
constructor(
protected id: string,
protected name: string,
protected config: CONFIG,
) {}
abstract getDefaultModels(): Promise<ModelList>;
abstract getModelList(): Promise<ModelList>;
abstract loadChatModel(modelName: string): Promise<BaseChatModel>;
abstract loadEmbeddingModel(modelName: string): Promise<Embeddings>;
static getProviderConfigFields(): UIConfigField[] {
throw new Error('Method not implemented.');
}
static getProviderMetadata(): ProviderMetadata {
throw new Error('Method not Implemented.');
}
static parseAndValidate(raw: any): any {
/* Static methods can't access class type parameters */
throw new Error('Method not Implemented.');
}
}
export type ProviderConstructor<CONFIG> = {
new (id: string, name: string, config: CONFIG): BaseModelProvider<CONFIG>;
parseAndValidate(raw: any): CONFIG;
getProviderConfigFields: () => UIConfigField[];
getProviderMetadata: () => ProviderMetadata;
};
export const createProviderInstance = <P extends ProviderConstructor<any>>(
Provider: P,
id: string,
name: string,
rawConfig: unknown,
): InstanceType<P> => {
const cfg = Provider.parseAndValidate(rawConfig);
return new Provider(id, name, cfg) as InstanceType<P>;
};
export default BaseModelProvider;

View File

@@ -0,0 +1,21 @@
import { ModelProviderUISection } from '@/lib/config/types';
import { ProviderConstructor } from './baseProvider';
import OpenAIProvider from './openai';
export const providers: Record<string, ProviderConstructor<any>> = {
openai: OpenAIProvider,
};
export const getModelProvidersUIConfigSection =
(): ModelProviderUISection[] => {
return Object.entries(providers).map(([k, p]) => {
const configFields = p.getProviderConfigFields();
const metadata = p.getProviderMetadata();
return {
fields: configFields,
key: k,
name: metadata.name,
};
});
};

View File

@@ -0,0 +1,214 @@
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import BaseModelProvider from './baseProvider';
import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';
import { Embeddings } from '@langchain/core/embeddings';
import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
interface OpenAIConfig {
apiKey: string;
baseURL: string;
}
const defaultChatModels: Model[] = [
{
name: 'GPT-3.5 Turbo',
key: 'gpt-3.5-turbo',
},
{
name: 'GPT-4',
key: 'gpt-4',
},
{
name: 'GPT-4 turbo',
key: 'gpt-4-turbo',
},
{
name: 'GPT-4 omni',
key: 'gpt-4o',
},
{
name: 'GPT-4o (2024-05-13)',
key: 'gpt-4o-2024-05-13',
},
{
name: 'GPT-4 omni mini',
key: 'gpt-4o-mini',
},
{
name: 'GPT 4.1 nano',
key: 'gpt-4.1-nano',
},
{
name: 'GPT 4.1 mini',
key: 'gpt-4.1-mini',
},
{
name: 'GPT 4.1',
key: 'gpt-4.1',
},
{
name: 'GPT 5 nano',
key: 'gpt-5-nano',
},
{
name: 'GPT 5',
key: 'gpt-5',
},
{
name: 'GPT 5 Mini',
key: 'gpt-5-mini',
},
{
name: 'o1',
key: 'o1',
},
{
name: 'o3',
key: 'o3',
},
{
name: 'o3 Mini',
key: 'o3-mini',
},
{
name: 'o4 Mini',
key: 'o4-mini',
},
];
const defaultEmbeddingModels: Model[] = [
{
name: 'Text Embedding 3 Small',
key: 'text-embedding-3-small',
},
{
name: 'Text Embedding 3 Large',
key: 'text-embedding-3-large',
},
];
const providerConfigFields: UIConfigField[] = [
{
type: 'password',
name: 'API Key',
key: 'apiKey',
description: 'Your OpenAI API key',
required: true,
placeholder: 'OpenAI API Key',
env: 'OPENAI_API_KEY',
scope: 'server',
},
{
type: 'string',
name: 'Base URL',
key: 'baseURL',
description: 'The base URL for the OpenAI API',
required: true,
placeholder: 'OpenAI Base URL',
default: 'https://api.openai.com/v1',
env: 'OPENAI_BASE_URL',
scope: 'server',
},
];
class OpenAIProvider extends BaseModelProvider<OpenAIConfig> {
constructor(id: string, name: string, config: OpenAIConfig) {
super(id, name, config);
}
async getDefaultModels(): Promise<ModelList> {
if (this.config.baseURL === 'https://api.openai.com/v1') {
return {
embedding: defaultEmbeddingModels,
chat: defaultChatModels,
};
}
return {
embedding: [],
chat: [],
};
}
async getModelList(): Promise<ModelList> {
const defaultModels = await this.getDefaultModels();
const configProvider = getConfiguredModelProviderById(this.id)!;
return {
embedding: [
...defaultModels.embedding,
...configProvider.embeddingModels,
],
chat: [...defaultModels.chat, ...configProvider.chatModels],
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
const modelList = await this.getModelList();
const exists = modelList.chat.find((m) => m.key === key);
if (!exists) {
throw new Error(
'Error Loading OpenAI Chat Model. Invalid Model Selected',
);
}
return new ChatOpenAI({
apiKey: this.config.apiKey,
temperature: 0.7,
model: key,
configuration: {
baseURL: this.config.baseURL,
},
});
}
async loadEmbeddingModel(key: string): Promise<Embeddings> {
const modelList = await this.getModelList();
const exists = modelList.embedding.find((m) => m.key === key);
if (!exists) {
throw new Error(
'Error Loading OpenAI Embedding Model. Invalid Model Selected.',
);
}
return new OpenAIEmbeddings({
apiKey: this.config.apiKey,
model: key,
configuration: {
baseURL: this.config.baseURL,
},
});
}
static parseAndValidate(raw: any): OpenAIConfig {
if (!raw || typeof raw !== 'object')
throw new Error('Invalid config provided. Expected object');
if (!raw.apiKey || !raw.baseURL)
throw new Error(
'Invalid config provided. API key and base URL must be provided',
);
return {
apiKey: String(raw.apiKey),
baseURL: String(raw.baseURL),
};
}
static getProviderConfigFields(): UIConfigField[] {
return providerConfigFields;
}
static getProviderMetadata(): ProviderMetadata {
return {
key: 'openai',
name: 'OpenAI',
};
}
}
export default OpenAIProvider;

View File

@@ -0,0 +1,53 @@
import { ConfigModelProvider } from '../config/types';
import BaseModelProvider, {
createProviderInstance,
} from './providers/baseProvider';
import { getConfiguredModelProviders } from '../config/serverRegistry';
import { providers } from './providers';
import { ModelList } from './types';
class ModelRegistry {
activeProviders: (ConfigModelProvider & {
provider: BaseModelProvider<any>;
})[] = [];
constructor() {
this.initializeActiveProviders();
}
private initializeActiveProviders() {
const configuredProviders = getConfiguredModelProviders();
configuredProviders.forEach((p) => {
try {
const provider = providers[p.type];
if (!provider) throw new Error('Invalid provider type');
this.activeProviders.push({
...p,
provider: createProviderInstance(provider, p.id, p.name, p.config),
});
} catch (err) {
console.error(
`Failed to initialize provider. Type: ${p.type}, ID: ${p.id}, Config: ${JSON.stringify(p.config)}, Error: ${err}`,
);
}
});
}
async getActiveModels() {
const models: ModelList[] = [];
await Promise.all(
this.activeProviders.map(async (p) => {
const m = await p.provider.getModelList();
models.push(m);
}),
);
return models;
}
}
export default ModelRegistry;

16
src/lib/models/types.ts Normal file
View File

@@ -0,0 +1,16 @@
type Model = {
name: string;
key: string;
};
type ModelList = {
embedding: Model[];
chat: Model[];
};
type ProviderMetadata = {
name: string;
key: string;
};
export type { Model, ModelList, ProviderMetadata };

7
src/lib/serverUtils.ts Normal file
View File

@@ -0,0 +1,7 @@
import crypto from 'crypto';
export const hashObj = (obj: { [key: string]: any }) => {
const json = JSON.stringify(obj, Object.keys(obj).sort());
const hash = crypto.createHash('sha256').update(json).digest('hex');
return hash;
};

View File

@@ -2,17 +2,17 @@ import type { Config } from 'tailwindcss';
import type { DefaultColors } from 'tailwindcss/types/generated/colors'; import type { DefaultColors } from 'tailwindcss/types/generated/colors';
const themeDark = (colors: DefaultColors) => ({ const themeDark = (colors: DefaultColors) => ({
50: '#111116', 50: '#0d1117',
100: '#1f202b', 100: '#161b22',
200: '#2d2f3f', 200: '#21262d',
300: '#3a3c4c', 300: '#30363d',
}); });
const themeLight = (colors: DefaultColors) => ({ const themeLight = (colors: DefaultColors) => ({
50: '#ffffff', 50: '#ffffff',
100: '#f1f5f9', 100: '#f6f8fa',
200: '#c4c7c5', 200: '#d0d7de',
300: '#9ca3af', 300: '#afb8c1',
}); });
const config: Config = { const config: Config = {
@@ -49,6 +49,9 @@ const config: Config = {
}, },
}, },
}, },
plugins: [require('@tailwindcss/typography')], plugins: [
require('@tailwindcss/typography'),
require('@headlessui/tailwindcss')({ prefix: 'headless' }),
],
}; };
export default config; export default config;

103
yarn.lock
View File

@@ -39,6 +39,13 @@
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0"
integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==
"@cspotcode/source-map-support@^0.8.0":
version "0.8.1"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
"@dabh/diagnostics@^2.0.2": "@dabh/diagnostics@^2.0.2":
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a"
@@ -407,6 +414,11 @@
"@react-aria/interactions" "^3.21.3" "@react-aria/interactions" "^3.21.3"
"@tanstack/react-virtual" "^3.8.1" "@tanstack/react-virtual" "^3.8.1"
"@headlessui/tailwindcss@^0.2.2":
version "0.2.2"
resolved "https://registry.yarnpkg.com/@headlessui/tailwindcss/-/tailwindcss-0.2.2.tgz#8ebde73fabca72d48636ea56ae790209dc5f0d49"
integrity sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==
"@huggingface/jinja@^0.2.2": "@huggingface/jinja@^0.2.2":
version "0.2.2" version "0.2.2"
resolved "https://registry.yarnpkg.com/@huggingface/jinja/-/jinja-0.2.2.tgz#faeb205a9d6995089bef52655ddd8245d3190627" resolved "https://registry.yarnpkg.com/@huggingface/jinja/-/jinja-0.2.2.tgz#faeb205a9d6995089bef52655ddd8245d3190627"
@@ -575,7 +587,7 @@
"@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.24" "@jridgewell/trace-mapping" "^0.3.24"
"@jridgewell/resolve-uri@^3.1.0": "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0":
version "3.1.2" version "3.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
@@ -590,6 +602,14 @@
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@jridgewell/trace-mapping@0.3.9":
version "0.3.9"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping@^0.3.24": "@jridgewell/trace-mapping@^0.3.24":
version "0.3.25" version "0.3.25"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
@@ -927,6 +947,26 @@
resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.10.9.tgz#55710c92b311fdaa8d8c66682a0dbdd684bc77c4" resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.10.9.tgz#55710c92b311fdaa8d8c66682a0dbdd684bc77c4"
integrity sha512-kBknKOKzmeR7lN+vSadaKWXaLS0SZZG+oqpQ/k80Q6g9REn6zRHS/ZYdrIzHnpHgy/eWs00SujveUN/GJT2qTw== integrity sha512-kBknKOKzmeR7lN+vSadaKWXaLS0SZZG+oqpQ/k80Q6g9REn6zRHS/ZYdrIzHnpHgy/eWs00SujveUN/GJT2qTw==
"@tsconfig/node10@^1.0.7":
version "1.0.11"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2"
integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==
"@tsconfig/node12@^1.0.7":
version "1.0.11"
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
"@tsconfig/node14@^1.0.0":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
"@tsconfig/node16@^1.0.2":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9"
integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==
"@types/better-sqlite3@^7.6.12": "@types/better-sqlite3@^7.6.12":
version "7.6.12" version "7.6.12"
resolved "https://registry.yarnpkg.com/@types/better-sqlite3/-/better-sqlite3-7.6.12.tgz#e5712d46d71097dcc2775c0b068072eadc15deb7" resolved "https://registry.yarnpkg.com/@types/better-sqlite3/-/better-sqlite3-7.6.12.tgz#e5712d46d71097dcc2775c0b068072eadc15deb7"
@@ -1119,6 +1159,18 @@ acorn-jsx@^5.3.2:
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
acorn-walk@^8.1.1:
version "8.3.4"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7"
integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==
dependencies:
acorn "^8.11.0"
acorn@^8.11.0, acorn@^8.4.1:
version "8.15.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816"
integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
acorn@^8.9.0: acorn@^8.9.0:
version "8.11.3" version "8.11.3"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
@@ -1181,6 +1233,11 @@ anymatch@~3.1.2:
normalize-path "^3.0.0" normalize-path "^3.0.0"
picomatch "^2.0.4" picomatch "^2.0.4"
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
arg@^5.0.2: arg@^5.0.2:
version "5.0.2" version "5.0.2"
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
@@ -1739,6 +1796,11 @@ core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
cross-fetch@^3.1.5: cross-fetch@^3.1.5:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.2.0.tgz#34e9192f53bc757d6614304d9e5e6fb4edb782e3" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.2.0.tgz#34e9192f53bc757d6614304d9e5e6fb4edb782e3"
@@ -1883,6 +1945,11 @@ didyoumean@^1.2.2:
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
dingbat-to-unicode@^1.0.1: dingbat-to-unicode@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz#5091dd673241453e6b5865e26e5a4452cdef5c83" resolved "https://registry.yarnpkg.com/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz#5091dd673241453e6b5865e26e5a4452cdef5c83"
@@ -3510,6 +3577,11 @@ lucide-react@^0.363.0:
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.363.0.tgz#2bb1f9d09b830dda86f5118fcd097f87247fe0e3" resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.363.0.tgz#2bb1f9d09b830dda86f5118fcd097f87247fe0e3"
integrity sha512-AlsfPCsXQyQx7wwsIgzcKOL9LwC498LIMAo+c0Es5PkHJa33xwmYAkkSoKoJWWWSYQEStqu58/jT4tL2gi32uQ== integrity sha512-AlsfPCsXQyQx7wwsIgzcKOL9LwC498LIMAo+c0Es5PkHJa33xwmYAkkSoKoJWWWSYQEStqu58/jT4tL2gi32uQ==
make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
mammoth@^1.9.1: mammoth@^1.9.1:
version "1.9.1" version "1.9.1"
resolved "https://registry.yarnpkg.com/mammoth/-/mammoth-1.9.1.tgz#b544c26747a412b5b00a11aa80477c6796860eaf" resolved "https://registry.yarnpkg.com/mammoth/-/mammoth-1.9.1.tgz#b544c26747a412b5b00a11aa80477c6796860eaf"
@@ -4971,6 +5043,25 @@ ts-interface-checker@^0.1.9:
resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
ts-node@^10.9.2:
version "10.9.2"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f"
integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==
dependencies:
"@cspotcode/source-map-support" "^0.8.0"
"@tsconfig/node10" "^1.0.7"
"@tsconfig/node12" "^1.0.7"
"@tsconfig/node14" "^1.0.0"
"@tsconfig/node16" "^1.0.2"
acorn "^8.4.1"
acorn-walk "^8.1.1"
arg "^4.1.0"
create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
tsconfig-paths@^3.15.0: tsconfig-paths@^3.15.0:
version "3.15.0" version "3.15.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4"
@@ -5138,6 +5229,11 @@ uuid@^9.0.1:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
v8-compile-cache-lib@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
validate.io-array@^1.0.3, validate.io-array@^1.0.5: validate.io-array@^1.0.3, validate.io-array@^1.0.5:
version "1.0.6" version "1.0.6"
resolved "https://registry.yarnpkg.com/validate.io-array/-/validate.io-array-1.0.6.tgz#5b5a2cafd8f8b85abb2f886ba153f2d93a27774d" resolved "https://registry.yarnpkg.com/validate.io-array/-/validate.io-array-1.0.6.tgz#5b5a2cafd8f8b85abb2f886ba153f2d93a27774d"
@@ -5355,6 +5451,11 @@ yet-another-react-lightbox@^3.17.2:
resolved "https://registry.yarnpkg.com/yet-another-react-lightbox/-/yet-another-react-lightbox-3.17.2.tgz#00474b83189ec4d81302792211ca31ffb808554c" resolved "https://registry.yarnpkg.com/yet-another-react-lightbox/-/yet-another-react-lightbox-3.17.2.tgz#00474b83189ec4d81302792211ca31ffb808554c"
integrity sha512-fM+Br5nR2kt/oBAOHDqVdUmogiHRLCt4iuIJHPS9Q+ME+h+ciME6vEpLt3IPgGU8whib1agEyZBgWJOAKjgadQ== integrity sha512-fM+Br5nR2kt/oBAOHDqVdUmogiHRLCt4iuIJHPS9Q+ME+h+ciME6vEpLt3IPgGU8whib1agEyZBgWJOAKjgadQ==
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
yocto-queue@^0.1.0: yocto-queue@^0.1.0:
version "0.1.0" version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"