diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..1f1f02c --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +node_modules +**/*.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..2476698 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,27 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "prettier" + ], + "rules": { + "@typescript-eslint/no-unused-vars": [ + "error", + { + "args": "all", + "argsIgnorePattern": "^_", + "caughtErrors": "all", + "caughtErrorsIgnorePattern": "^_", + "destructuredArrayIgnorePattern": "^_", + "varsIgnorePattern": "^_", + "ignoreRestSiblings": true + } + ] + } +} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92e3d58..faa5f7d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,8 +19,8 @@ jobs: - name: Set up Node uses: actions/setup-node@v4 with: - node-version: '20' - cache: 'npm' + node-version: "20" + cache: "npm" - name: Install dependencies run: npm install @@ -38,11 +38,11 @@ jobs: - name: Set up Node uses: actions/setup-node@v4 with: - node-version: '20' - cache: 'npm' + node-version: "20" + cache: "npm" - name: Install dependencies run: npm install - name: Build - run: npm run build \ No newline at end of file + run: npm run build diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..e69de29 diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..c83e263 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["esbenp.prettier-vscode"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b55450f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} diff --git a/README.md b/README.md index ce3a421..8f39c96 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,4 @@ This repo uses `vitest` to run tests. There is a pulumi environment called `npm- ```console $ pulumi env run npm-test npm run test -``` \ No newline at end of file +``` diff --git a/api-client.ts b/api-client.ts index 58803f3..a4d54e1 100644 --- a/api-client.ts +++ b/api-client.ts @@ -3,45 +3,47 @@ type Method = "POST" | "GET" | "PUT" | "DELETE"; // body can be any object /* eslint-disable @typescript-eslint/no-explicit-any */ - export class CortexApiClient { - constructor(private org: string, private apiUrl: string, private accessToken: string) { } - - async POST(path: string, body?: any) { - return this.makeRequest("POST", path, body); - } - - async PUT(path: string, body?: any) { - return this.makeRequest("PUT", path, body); - } - - async GET(path: string, body?: any) { - return this.makeRequest("GET", path, body); - } - - async DELETE(path: string, body?: any) { - return this.makeRequest("DELETE", path, body); - } - - async POSTForm(path: string, form: FormData) { - return fetch(`${this.apiUrl}/org/${this.org}${path}`, { - method: "POST", - headers: { - "Authorization": `Bearer ${this.accessToken}` - }, - body: form, - }) - } - - private async makeRequest(method: Method, path: string, body?: any) { - return fetch(`${this.apiUrl}/org/${this.org}${path}`, { - method, - headers: { - "Authorization": `Bearer ${this.accessToken}`, - 'Content-Type': 'application/json' - }, - body: body ? JSON.stringify(body) : undefined, - }) - } - -} \ No newline at end of file + constructor( + private org: string, + private apiUrl: string, + private accessToken: string, + ) {} + + async POST(path: string, body?: any) { + return this.makeRequest("POST", path, body); + } + + async PUT(path: string, body?: any) { + return this.makeRequest("PUT", path, body); + } + + async GET(path: string, body?: any) { + return this.makeRequest("GET", path, body); + } + + async DELETE(path: string, body?: any) { + return this.makeRequest("DELETE", path, body); + } + + async POSTForm(path: string, form: FormData) { + return fetch(`${this.apiUrl}/org/${this.org}${path}`, { + method: "POST", + headers: { + Authorization: `Bearer ${this.accessToken}`, + }, + body: form, + }); + } + + private async makeRequest(method: Method, path: string, body?: any) { + return fetch(`${this.apiUrl}/org/${this.org}${path}`, { + method, + headers: { + Authorization: `Bearer ${this.accessToken}`, + "Content-Type": "application/json", + }, + body: body ? JSON.stringify(body) : undefined, + }); + } +} diff --git a/catalog.test.ts b/catalog.test.ts index a27243a..5ab101d 100644 --- a/catalog.test.ts +++ b/catalog.test.ts @@ -1,4 +1,4 @@ -import { expect, test, afterEach } from 'vitest' +import { expect, test, afterEach } from "vitest"; import { CortexClient } from "./index"; import { Catalog, CatalogConfig } from "./catalog"; @@ -15,15 +15,13 @@ afterEach(async () => { if (catalog) { await catalog.delete(); } - } - catch { - // probably catalog has already been deleted by a test, so ignore + } catch { + // probably catalog has already been deleted by a test, so ignore } }); -test('Catalog CRUD', async () => { - - const catalogName = `catalog-${Math.floor(Math.random() * 10000)}` +test("Catalog CRUD", async () => { + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; const config: CatalogConfig = { description: "foo bar", @@ -39,8 +37,8 @@ test('Catalog CRUD', async () => { expect(catalog.config.description).toBe(config.description); // update - config.description = "buzz 123" - config.instructions = ["1", "2", "3"] + config.description = "buzz 123"; + config.instructions = ["1", "2", "3"]; catalog = await client.configureCatalog(catalogName, config); catalog = await client.getCatalog(catalogName); @@ -54,16 +52,20 @@ test('Catalog CRUD', async () => { // list const catalogList = await client.listCatalogs(); - const catalogFromList = catalogList.find(c => c.name === catalogName); + const catalogFromList = catalogList.find((c) => c.name === catalogName); expect(catalogFromList).toBeDefined(); expect(catalogFromList?.documentCount).toBe(0); expect(catalogFromList?.description).toBe(config.description); // get catalog from list result const getCatalogFromList = await catalogFromList?.Catalog(); - expect(getCatalogFromList?.config.instructions).toStrictEqual(config.instructions); + expect(getCatalogFromList?.config.instructions).toStrictEqual( + config.instructions, + ); - // delete + // delete await catalog.delete(); // assert that the get fails - await expect(async () => { await client.getCatalog(catalogName) }).rejects.toThrowError("Failed to get catalog: Not Found"); + await expect(async () => { + await client.getCatalog(catalogName); + }).rejects.toThrowError("Failed to get catalog: Not Found"); }); diff --git a/catalog.ts b/catalog.ts index 802513d..f57c4b8 100644 --- a/catalog.ts +++ b/catalog.ts @@ -1,256 +1,290 @@ import { CortexApiClient } from "./api-client.js"; -import { DocumentBatch, DocumentInput, FileDocument, Document, DocumentListItem } from "./document.js"; -import * as fs from 'node:fs'; +import { + DocumentBatch, + DocumentInput, + FileDocument, + Document, + DocumentListItem, +} from "./document.js"; +import * as fs from "node:fs"; import { JSONIndexer, JSONIndexerOpts } from "./indexers/json-indexer.js"; -import { DirectoryIndexer, DirectoryIndexerOpts } from "./indexers/directory-indexer.js"; +import { + DirectoryIndexer, + DirectoryIndexerOpts, +} from "./indexers/directory-indexer.js"; import { TSVIndexer, TSVIndexerOpts } from "./indexers/tsv-indexer.js"; -import { ShopifyIndexer, ShopifyIndexerOpts } from "./indexers/shopify-indexer.js"; - +import { + ShopifyIndexer, + ShopifyIndexerOpts, +} from "./indexers/shopify-indexer.js"; export type CatalogConfig = { - description: string; - instructions: string[]; + description: string; + instructions: string[]; }; export type CatalogListResult = { - name: string; - description: string; - documentCount: number; - Catalog(): Promise; + name: string; + description: string; + documentCount: number; + Catalog(): Promise; }; export type DocumentListResult = { - documents: DocumentListItem[]; - nextPage: () => Promise; -} + documents: DocumentListItem[]; + nextPage: () => Promise; +}; export type DocumentPaginationOpts = { - page: number; - pageSize?: number; -} + page: number; + pageSize?: number; +}; -export type CreateCatalogConfig = CatalogConfig & { catalogName: string } +export type CreateCatalogConfig = CatalogConfig & { catalogName: string }; export class Catalog { - private deleted = false; - private constructor(readonly config: CatalogConfig, private apiClient: CortexApiClient, readonly name: string) {} - - static async get(apiClient: CortexApiClient, name: string): Promise { - const res = await apiClient.GET(`/catalogs/${name}`); - if (res.status !== 200) { - throw new Error(`Failed to get catalog: ${res.statusText}`); - } - const body = await res.json(); - const config: CatalogConfig = { - description: body.description, - instructions: body.instructions - }; - return new Catalog(config, apiClient, name); + private deleted = false; + private constructor( + readonly config: CatalogConfig, + private apiClient: CortexApiClient, + readonly name: string, + ) {} + + static async get(apiClient: CortexApiClient, name: string): Promise { + const res = await apiClient.GET(`/catalogs/${name}`); + if (res.status !== 200) { + throw new Error(`Failed to get catalog: ${res.statusText}`); } - - static async configure(apiClient: CortexApiClient, name: string, config: CatalogConfig): Promise { - const createConfig: CreateCatalogConfig = { - ...config, - catalogName: name - } - const getRes = await apiClient.GET(`/catalogs/${name}`); - let res: Response; - if (getRes.status !== 200) { - res = await apiClient.POST("/catalogs", createConfig); - } else { - res = await apiClient.PUT(`/catalogs/${name}`, config); - } - - if (res.status !== 200) { - throw new Error(`Failed to configure catalog: ${res.statusText}`); - } - return new Catalog(config, apiClient, name); + const body = await res.json(); + const config: CatalogConfig = { + description: body.description, + instructions: body.instructions, + }; + return new Catalog(config, apiClient, name); + } + + static async configure( + apiClient: CortexApiClient, + name: string, + config: CatalogConfig, + ): Promise { + const createConfig: CreateCatalogConfig = { + ...config, + catalogName: name, + }; + const getRes = await apiClient.GET(`/catalogs/${name}`); + let res: Response; + if (getRes.status !== 200) { + res = await apiClient.POST("/catalogs", createConfig); + } else { + res = await apiClient.PUT(`/catalogs/${name}`, config); } - static async list(apiClient: CortexApiClient): Promise { - const result: CatalogListResult[] = []; - - const res = await apiClient.GET(`/catalogs`); - if (res.status !== 200) { - throw new Error(`Failed to list catalog: ${res.statusText}`); - } - const body = await res.json(); - for(const catalog of body.catalogs) { - result.push({ - name: catalog.name, - description: catalog.description, - documentCount: parseInt(catalog.documentCount), - Catalog: () => { return Catalog.get(apiClient, catalog.name) } - }) - } - - return result; + if (res.status !== 200) { + throw new Error(`Failed to configure catalog: ${res.statusText}`); } + return new Catalog(config, apiClient, name); + } - public async documentCount() { - this.checkDeleted(); - const res = await this.apiClient.GET(`/catalogs/${this.name}`); - if (res.status !== 200) { - throw new Error(`Failed to get catalog: ${res.statusText}`); - } + static async list(apiClient: CortexApiClient): Promise { + const result: CatalogListResult[] = []; - const body = await res.json(); - return parseInt(body.documentCount); + const res = await apiClient.GET(`/catalogs`); + if (res.status !== 200) { + throw new Error(`Failed to list catalog: ${res.statusText}`); } - - public async truncate() { - this.checkDeleted(); - const res = await this.apiClient.POST(`/catalogs/${this.name}/truncate`); - if (res.status !== 200) { - throw new Error(`Failed to get catalog: ${res.statusText}`); - } + const body = await res.json(); + for (const catalog of body.catalogs) { + result.push({ + name: catalog.name, + description: catalog.description, + documentCount: parseInt(catalog.documentCount), + Catalog: () => { + return Catalog.get(apiClient, catalog.name); + }, + }); } - public async upsertDocuments(batch: DocumentBatch) { - this.checkDeleted(); - let hasText = false; - let hasFile = false; - let hasJson = false; - for(const doc of batch) { - switch(doc.contentType) { - case "markdown": - case "text": - hasText = true; - break; - case "json": - hasJson = true; - break; - case "file": - hasFile = true; - break; - default: - // eslint-disable-next-line @typescript-eslint/no-explicit-any - throw new Error(`unsupported content type: ${(doc as any).contentType}`); - } - } - - if([hasText, hasJson, hasFile].filter(v => v).length > 1) { - throw new Error(`cannot mix file, text, and json content in batch upsert. all documents in batch must have the same contentType.`); - } - - const { blobs, documents } = await mapBatch(batch); - let res: Response; - if(blobs.length === 0) { - res = await this.apiClient.POST(`/catalogs/${this.name}/documents`, { - documents - }); - } else { - const fd = new FormData(); - for(let i = 0; i < blobs.length; i++) { - const blob = blobs[i] - fd.append("files", blob, (batch[i] as FileDocument).filePath); - } - fd.append("documentsJSON", JSON.stringify(documents)) - res = await this.apiClient.POSTForm(`/catalogs/${this.name}/documents`, fd); - } - - if (res.status !== 200) { - throw new Error(`Failed to upsert documents: ${res.statusText}`); - } - } + return result; + } - async delete() { - this.checkDeleted(); - this.deleted = true; - await this.apiClient.DELETE(`/catalogs/${this.name}`); - return; + public async documentCount() { + this.checkDeleted(); + const res = await this.apiClient.GET(`/catalogs/${this.name}`); + if (res.status !== 200) { + throw new Error(`Failed to get catalog: ${res.statusText}`); } - async getDocument(documentId: string): Promise { - this.checkDeleted(); - return Document.get(this.apiClient, this, documentId) - } + const body = await res.json(); + return parseInt(body.documentCount); + } - async deleteDocument(documentId: string) { - this.checkDeleted(); - const doc = await this.getDocument(documentId); - await doc.delete(); + public async truncate() { + this.checkDeleted(); + const res = await this.apiClient.POST(`/catalogs/${this.name}/truncate`); + if (res.status !== 200) { + throw new Error(`Failed to get catalog: ${res.statusText}`); } - - async listDocuments(paginationOpts?: DocumentPaginationOpts): Promise { - const { page, pageSize } = paginationOpts || { page: 1, pageSize: 50}; - const nextPageOpts: DocumentPaginationOpts = { page: page+1, pageSize }; - const nextPage = () => { - return this.listDocuments(nextPageOpts); - } - - this.checkDeleted(); - const res = await this.apiClient.GET(`/catalogs/${this.name}/documents?page=${page}&pageSize=${pageSize}`); - if (res.status !== 200) { - throw new Error(`Failed to get document: ${res.statusText}`); - } - - const body = await res.json(); - - return { - documents: body.documents || [], - nextPage, - }; + } + + public async upsertDocuments(batch: DocumentBatch) { + this.checkDeleted(); + let hasText = false; + let hasFile = false; + let hasJson = false; + for (const doc of batch) { + switch (doc.contentType) { + case "markdown": + case "text": + hasText = true; + break; + case "json": + hasJson = true; + break; + case "file": + hasFile = true; + break; + default: + throw new Error( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + `unsupported content type: ${(doc as any).contentType}`, + ); + } } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - jsonIndexer(documents: any[], opts?: JSONIndexerOpts) { - return new JSONIndexer(this, documents, opts); + if ([hasText, hasJson, hasFile].filter((v) => v).length > 1) { + throw new Error( + `cannot mix file, text, and json content in batch upsert. all documents in batch must have the same contentType.`, + ); } - directoryIndexer(opts: DirectoryIndexerOpts) { - return new DirectoryIndexer(this, opts); + const { blobs, documents } = await mapBatch(batch); + let res: Response; + if (blobs.length === 0) { + res = await this.apiClient.POST(`/catalogs/${this.name}/documents`, { + documents, + }); + } else { + const fd = new FormData(); + for (let i = 0; i < blobs.length; i++) { + const blob = blobs[i]; + fd.append("files", blob, (batch[i] as FileDocument).filePath); + } + fd.append("documentsJSON", JSON.stringify(documents)); + res = await this.apiClient.POSTForm( + `/catalogs/${this.name}/documents`, + fd, + ); } - tsvIndexer(file: string, opts?: TSVIndexerOpts) { - return new TSVIndexer(this, file, opts); + if (res.status !== 200) { + throw new Error(`Failed to upsert documents: ${res.statusText}`); } + } + + async delete() { + this.checkDeleted(); + this.deleted = true; + await this.apiClient.DELETE(`/catalogs/${this.name}`); + return; + } + + async getDocument(documentId: string): Promise { + this.checkDeleted(); + return Document.get(this.apiClient, this, documentId); + } + + async deleteDocument(documentId: string) { + this.checkDeleted(); + const doc = await this.getDocument(documentId); + await doc.delete(); + } + + async listDocuments( + paginationOpts?: DocumentPaginationOpts, + ): Promise { + const { page, pageSize } = paginationOpts || { page: 1, pageSize: 50 }; + const nextPageOpts: DocumentPaginationOpts = { page: page + 1, pageSize }; + const nextPage = () => { + return this.listDocuments(nextPageOpts); + }; - shopifyIndexer(opts: ShopifyIndexerOpts) { - return new ShopifyIndexer(this, opts); + this.checkDeleted(); + const res = await this.apiClient.GET( + `/catalogs/${this.name}/documents?page=${page}&pageSize=${pageSize}`, + ); + if (res.status !== 200) { + throw new Error(`Failed to get document: ${res.statusText}`); } - private checkDeleted() { - if (this.deleted) { - throw new Error(`cortex: ${this.name} has already been deleted`); - } + const body = await res.json(); + + return { + documents: body.documents || [], + nextPage, + }; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + jsonIndexer(documents: any[], opts?: JSONIndexerOpts) { + return new JSONIndexer(this, documents, opts); + } + + directoryIndexer(opts: DirectoryIndexerOpts) { + return new DirectoryIndexer(this, opts); + } + + tsvIndexer(file: string, opts?: TSVIndexerOpts) { + return new TSVIndexer(this, file, opts); + } + + shopifyIndexer(opts: ShopifyIndexerOpts) { + return new ShopifyIndexer(this, opts); + } + + private checkDeleted() { + if (this.deleted) { + throw new Error(`cortex: ${this.name} has already been deleted`); } + } } const mapBatch = async (batch: DocumentBatch) => { - const blobs: Promise[] = []; - const documents: DocumentInput[] = []; - - for(const doc of batch) { - switch(doc.contentType) { - case "markdown": - case "text": - documents.push({ - ...doc, - }); - break; - case "json": - documents.push({ - ...doc, - content: JSON.stringify(doc.content) - }); - break; - case "file": - blobs.push(fs.openAsBlob(doc.filePath)); - documents.push({ - ...doc, - content: undefined, - }); - break; - default: - // eslint-disable-next-line @typescript-eslint/no-explicit-any - throw new Error(`unsupported content type: ${(doc as any).contentType}`); - } + const blobs: Promise[] = []; + const documents: DocumentInput[] = []; + + for (const doc of batch) { + switch (doc.contentType) { + case "markdown": + case "text": + documents.push({ + ...doc, + }); + break; + case "json": + documents.push({ + ...doc, + content: JSON.stringify(doc.content), + }); + break; + case "file": + blobs.push(fs.openAsBlob(doc.filePath)); + documents.push({ + ...doc, + content: undefined, + }); + break; + default: + throw new Error( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + `unsupported content type: ${(doc as any).contentType}`, + ); } - const resolvedBlobs = await Promise.all(blobs); + } + const resolvedBlobs = await Promise.all(blobs); - return { - blobs: resolvedBlobs, - documents, - }; -} \ No newline at end of file + return { + blobs: resolvedBlobs, + documents, + }; +}; diff --git a/chat.test.ts b/chat.test.ts index de86573..ca296c7 100644 --- a/chat.test.ts +++ b/chat.test.ts @@ -1,4 +1,4 @@ -import { expect, test } from 'vitest'; +import { expect, test } from "vitest"; import { CortexClient, TextDocument } from "./index"; import { CatalogConfig } from "./catalog"; import { Readable } from "stream"; @@ -9,21 +9,30 @@ const client = new CortexClient({ apiUrl: "http://localhost:3001", }); - -test('e2e catalog, cortex, and sync chat', { timeout: 60000 }, async () => { - +test("e2e catalog, cortex, and sync chat", { timeout: 60000 }, async () => { client.configureOrg({ companyName: "Cortex Click", - companyInfo: "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", - personality: ["friendly and helpful", "expert sales and marketing professional", "experienced software developer"], - rules: ["never say anything disparaging about AI or LLMs", "do not offer discounts"], - }) + companyInfo: + "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", + personality: [ + "friendly and helpful", + "expert sales and marketing professional", + "experienced software developer", + ], + rules: [ + "never say anything disparaging about AI or LLMs", + "do not offer discounts", + ], + }); - const catalogName = `catalog-${Math.floor(Math.random() * 10000)}` + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; const config: CatalogConfig = { - description: "this catalog contains documentation from the cortex click marketing website", - instructions: ["user this data set to answer user questions about the cortex click platform"] + description: + "this catalog contains documentation from the cortex click marketing website", + instructions: [ + "user this data set to answer user questions about the cortex click platform", + ], }; // create @@ -32,39 +41,44 @@ test('e2e catalog, cortex, and sync chat', { timeout: 60000 }, async () => { const documents: TextDocument[] = [ { documentId: "a", - content: "cortex click solutions: customer support, blog and content writing, technical documentation generation, SEO, sales process automation, AI email marketing", - contentType: "markdown" + content: + "cortex click solutions: customer support, blog and content writing, technical documentation generation, SEO, sales process automation, AI email marketing", + contentType: "markdown", }, { documentId: "b", content: "cortex click customers: reds fly shop, pyxos, ", - contentType: "markdown" + contentType: "markdown", }, { documentId: "c", - content: "cortex click customer verticals and industries: developer tools, e-commerce, SaaS, network security, compliance, and more.", - contentType: "markdown" - } + content: + "cortex click customer verticals and industries: developer tools, e-commerce, SaaS, network security, compliance, and more.", + contentType: "markdown", + }, ]; await catalog.upsertDocuments(documents); - const cortex = await client.configureCortex(`cortex-${Math.floor(Math.random() * 10000)}`, { - catalogs: [catalog.name], - friendlyName: "Cortex AI", - instructions: ["answer questions about the cortex click AI GTM platform"], - public: true, - }); + const cortex = await client.configureCortex( + `cortex-${Math.floor(Math.random() * 10000)}`, + { + catalogs: [catalog.name], + friendlyName: "Cortex AI", + instructions: ["answer questions about the cortex click AI GTM platform"], + public: true, + }, + ); // create chat - const chatInput = "what customers does cortex click have?" + const chatInput = "what customers does cortex click have?"; const chat = await cortex.chat({ message: chatInput }); expect(chat.messages[1].message.length).toBeGreaterThan(0); // get chat const getChatRes = await client.getChat(chat.id); expect(getChatRes.messages.length).toBe(2); - expect(getChatRes.title).toBe(chatInput) + expect(getChatRes.title).toBe(chatInput); // respond to chat await chat.respond({ message: "what about customer verticals" }); @@ -78,24 +92,34 @@ test('e2e catalog, cortex, and sync chat', { timeout: 60000 }, async () => { expect(nextPage.chats.length).toBe(1); expect(nextPage.chats[0].id).not.toBe(chat.id); - // delete + // delete await catalog.delete(); }); -test('streaming chat', { timeout: 60000 }, async () => { - +test("streaming chat", { timeout: 60000 }, async () => { client.configureOrg({ companyName: "Cortex Click", - companyInfo: "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", - personality: ["friendly and helpful", "expert sales and marketing professional", "experienced software developer"], - rules: ["never say anything disparaging about AI or LLMs", "do not offer discounts"], - }) + companyInfo: + "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", + personality: [ + "friendly and helpful", + "expert sales and marketing professional", + "experienced software developer", + ], + rules: [ + "never say anything disparaging about AI or LLMs", + "do not offer discounts", + ], + }); - const catalogName = `catalog-${Math.floor(Math.random() * 10000)}` + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; const config: CatalogConfig = { - description: "this catalog contains documentation from the cortex click marketing website", - instructions: ["user this data set to answer user questions about the cortex click platform"] + description: + "this catalog contains documentation from the cortex click marketing website", + instructions: [ + "user this data set to answer user questions about the cortex click platform", + ], }; // create @@ -104,45 +128,54 @@ test('streaming chat', { timeout: 60000 }, async () => { const documents: TextDocument[] = [ { documentId: "a", - content: "cortex click solutions: customer support, blog and content writing, technical documentation generation, SEO, sales process automation, AI email marketing", - contentType: "markdown" + content: + "cortex click solutions: customer support, blog and content writing, technical documentation generation, SEO, sales process automation, AI email marketing", + contentType: "markdown", }, { documentId: "b", content: "cortex click customers: reds fly shop, pyxos, ", - contentType: "markdown" + contentType: "markdown", }, { documentId: "c", - content: "cortex click customer verticals and industries: developer tools, e-commerce, SaaS, network security, compliance, and more.", - contentType: "markdown" - } + content: + "cortex click customer verticals and industries: developer tools, e-commerce, SaaS, network security, compliance, and more.", + contentType: "markdown", + }, ]; await catalog.upsertDocuments(documents); - const cortex = await client.configureCortex(`cortex-${Math.floor(Math.random() * 10000)}`, { - catalogs: [catalog.name], - friendlyName: "Cortex AI", - instructions: ["answer questions about the cortex click AI GTM platform"], - public: true, - }); + const cortex = await client.configureCortex( + `cortex-${Math.floor(Math.random() * 10000)}`, + { + catalogs: [catalog.name], + friendlyName: "Cortex AI", + instructions: ["answer questions about the cortex click AI GTM platform"], + public: true, + }, + ); // create chat - const chatInput = "what customers does cortex click have?" + const chatInput = "what customers does cortex click have?"; const statusStream = new Readable({ - read() { } + read() {}, + }); + const { responseStream, chat } = await cortex.chat({ + message: chatInput, + stream: true, + statusStream, }); - const { responseStream, chat } = await cortex.chat({ message: chatInput, stream: true, statusStream }); - let fullMessage = "" - responseStream.on('data', (data) => { + let fullMessage = ""; + responseStream.on("data", (data) => { fullMessage += data.toString(); }); let sawChat = false; - statusStream.on('data', (data) => { + statusStream.on("data", (data) => { const message = JSON.parse(data); expect(message.messageType).toBe("status"); switch (message.step) { @@ -156,24 +189,32 @@ test('streaming chat', { timeout: 60000 }, async () => { const chatResult = await chat; - expect(fullMessage).toBe(chatResult.messages[chatResult.messages.length - 1].message); + expect(fullMessage).toBe( + chatResult.messages[chatResult.messages.length - 1].message, + ); expect(chatResult.messages.length).toBe(2); expect(sawChat).toBe(true); // respond to chat - const respondResult = await chatResult.respond({ message: "what about customer verticals", stream: true, statusStream }); + const respondResult = await chatResult.respond({ + message: "what about customer verticals", + stream: true, + statusStream, + }); const respondStream = respondResult.responseStream; - let fullResponse = "" - respondStream.on('data', (data) => { + let fullResponse = ""; + respondStream.on("data", (data) => { fullResponse += data.toString(); }); const response = await respondResult.chat; - expect(fullResponse).toBe(response.messages[response.messages.length - 1].message); + expect(fullResponse).toBe( + response.messages[response.messages.length - 1].message, + ); expect(response.messages.length).toBe(4); - // delete + // delete await catalog.delete(); -}); \ No newline at end of file +}); diff --git a/chat.ts b/chat.ts index 8b2d37d..c1b3551 100644 --- a/chat.ts +++ b/chat.ts @@ -1,220 +1,272 @@ import { Cortex } from "./cortex.js"; import { CortexApiClient } from "./api-client.js"; -import { Readable } from 'stream'; +import { Readable } from "stream"; import { processStream } from "./utils/streaming.js"; export interface CreateChatOptsBase { - client: CortexApiClient; - cortex: Cortex; - message: string; - stream?: boolean; - statusStream?: Readable; + client: CortexApiClient; + cortex: Cortex; + message: string; + stream?: boolean; + statusStream?: Readable; } export interface CreateChatOptsStreaming extends CreateChatOptsBase { - stream?: true + stream?: true; } export interface CreateChatOptsSync extends CreateChatOptsBase { - stream?: false + stream?: false; } export type StreamingChatResult = { - readonly responseStream: Readable; - readonly chat: Promise -} + readonly responseStream: Readable; + readonly chat: Promise; +}; export interface RespondChatOptsBase { - message: string; - cortex?: Cortex; - stream?: boolean; - statusStream?: Readable; + message: string; + cortex?: Cortex; + stream?: boolean; + statusStream?: Readable; } export interface RespondChatOptsStreaming extends RespondChatOptsBase { - stream?: true + stream?: true; } export interface RespondChatOptsSync extends RespondChatOptsBase { - stream?: false + stream?: false; } export interface ChatListItem { - title: string; - id: string; - messageCount: number; - Chat(): Promise; + title: string; + id: string; + messageCount: number; + Chat(): Promise; } export interface ChatListResult { - chats: ChatListItem[]; - nextPage: () => Promise; + chats: ChatListItem[]; + nextPage: () => Promise; } export interface ChatListPaginationOpts { - cursor?: string; - pageSize?: number; + cursor?: string; + pageSize?: number; } export type Message = { - role: "user" | "cortex"; - message: string; + role: "user" | "cortex"; + message: string; }; export class Chat { - private constructor(private apiClient: CortexApiClient, readonly id: string, readonly title: string, readonly messages: Message[]) { - } + private constructor( + private apiClient: CortexApiClient, + readonly id: string, + readonly title: string, + readonly messages: Message[], + ) {} - static async create(opts: CreateChatOptsSync): Promise; - static async create(opts: CreateChatOptsStreaming): Promise; - static async create(opts: CreateChatOptsSync | CreateChatOptsStreaming): Promise { - if (isCreateChatOptsSync(opts)) { - return this.createContentSync(opts); - } else { - return this.createContentStreaming(opts); - } + static async create(opts: CreateChatOptsSync): Promise; + static async create( + opts: CreateChatOptsStreaming, + ): Promise; + static async create( + opts: CreateChatOptsSync | CreateChatOptsStreaming, + ): Promise { + if (isCreateChatOptsSync(opts)) { + return this.createContentSync(opts); + } else { + return this.createContentStreaming(opts); } + } - static async list(client: CortexApiClient, paginationOpts?: ChatListPaginationOpts): Promise { - const chats: ChatListItem[] = []; - - const query = new URLSearchParams(); - if (paginationOpts?.cursor) { - query.set("cursor", paginationOpts.cursor); - } - query.set("pageSize", (paginationOpts?.pageSize || 50).toString()); - const res = await client.GET(`/chats?${query.toString()}`); - if (res.status !== 200) { - throw new Error(`Failed to list chats: ${res.statusText}`); - } - const body = await res.json(); - for (const chat of body.chats) { - chats.push({ - title: chat.title, - id: chat.chatId, - messageCount: chat.messageCount, - Chat: () => { return Chat.get(client, chat.chatId) } - }) - } - - const cursor = body.cursor; - const pageSize = paginationOpts?.pageSize; - return { chats, nextPage: async () => { return Chat.list(client, { cursor, pageSize }) } }; - } + private static async createContentSync( + opts: CreateChatOptsSync, + ): Promise { + const { client, cortex, message } = opts; + const res = await client.POST(`/chats`, { cortex: cortex.name, message }); + const body = await res.json(); + const messages: Message[] = [ + { + role: "user", + message, + }, + { + role: "cortex", + message: body.response, + }, + ]; + return new Chat(client, body.id, body.title, messages); + } - private static async createContentSync(opts: CreateChatOptsSync): Promise { - const { client, cortex, message } = opts; - const res = await client.POST(`/chats`, { cortex: cortex.name, message }); - const body = await res.json(); - const messages: Message[] = [ - { - role: "user", - message, - }, - { - role: "cortex", - message: body.response, - } - ]; - return new Chat(client, body.id, body.title, messages); - } + private static async createContentStreaming( + opts: CreateChatOptsStreaming, + ): Promise { + const { client, cortex, message } = opts; + const res = await client.POST(`/chats`, { + cortex: cortex.name, + message, + stream: true, + }); + const reader = res.body!.getReader(); + const decoder = new TextDecoder("utf-8"); - private static async createContentStreaming(opts: CreateChatOptsStreaming): Promise { - const { client, cortex, message } = opts; - const res = await client.POST(`/chats`, { cortex: cortex.name, message, stream: true }); - const reader = res.body!.getReader(); - const decoder = new TextDecoder('utf-8'); - - const id: string = res.headers.get("id") || ""; - const title: string = res.headers.get("title") || ""; - - const readableStream = new Readable({ - read() { } - }); - - const chatPromise = processStream(reader, decoder, readableStream, opts.statusStream).then(content => { - const messages: Message[] = [ - { - role: "user", - message, - }, - { - role: "cortex", - message: content, - } - ]; - return new Chat(client, id, title, messages); - }); - - return { responseStream: readableStream, chat: chatPromise }; - } + const id: string = res.headers.get("id") || ""; + const title: string = res.headers.get("title") || ""; - static async get(client: CortexApiClient, id: string): Promise { - const res = await client.GET(`/chats/${id}`); - if (res.status !== 200) { - throw new Error(`Failed to get chat: ${res.statusText}`); - } - const body = await res.json(); - return new Chat(client, id, body.title, body.messages); - } + const readableStream = new Readable({ + read() {}, + }); + + const chatPromise = processStream( + reader, + decoder, + readableStream, + opts.statusStream, + ).then((content) => { + const messages: Message[] = [ + { + role: "user", + message, + }, + { + role: "cortex", + message: content, + }, + ]; + return new Chat(client, id, title, messages); + }); - async respond(opts: RespondChatOptsSync): Promise; - async respond(opts: RespondChatOptsStreaming): Promise; - async respond(opts: RespondChatOptsSync | RespondChatOptsStreaming): Promise { - if (isRespondChatOptsSync(opts)) { - return this.respondChatSync(opts); - } else { - return this.respondChatStreaming(opts); - } + return { responseStream: readableStream, chat: chatPromise }; + } + + static async get(client: CortexApiClient, id: string): Promise { + const res = await client.GET(`/chats/${id}`); + if (res.status !== 200) { + throw new Error(`Failed to get chat: ${res.statusText}`); } + const body = await res.json(); + return new Chat(client, id, body.title, body.messages); + } + + static async list( + client: CortexApiClient, + paginationOpts?: ChatListPaginationOpts, + ): Promise { + const chats: ChatListItem[] = []; - private async respondChatSync(opts: RespondChatOptsSync): Promise { - const { message, cortex } = opts; - const res = await this.apiClient.POST(`/chats/${this.id}`, { message, cortex }); - const body = await res.json(); - this.messages.push( - { - role: "user", - message, - }, - { - role: "cortex", - message: body.response, - }); - - return body.response; + const query = new URLSearchParams(); + if (paginationOpts?.cursor) { + query.set("cursor", paginationOpts.cursor); } + query.set("pageSize", (paginationOpts?.pageSize || 50).toString()); + const res = await client.GET(`/chats?${query.toString()}`); + if (res.status !== 200) { + throw new Error(`Failed to list chats: ${res.statusText}`); + } + const body = await res.json(); + for (const chat of body.chats) { + chats.push({ + title: chat.title, + id: chat.chatId, + messageCount: chat.messageCount, + Chat: () => { + return Chat.get(client, chat.chatId); + }, + }); + } + + const cursor = body.cursor; + const pageSize = paginationOpts?.pageSize; + return { + chats, + nextPage: async () => { + return Chat.list(client, { cursor, pageSize }); + }, + }; + } - private async respondChatStreaming(opts: RespondChatOptsStreaming): Promise { - const { message, cortex } = opts; - const res = await this.apiClient.POST(`/chats/${this.id}`, { message, cortex, stream: true }); - const reader = res.body!.getReader(); - const decoder = new TextDecoder('utf-8'); - - const readableStream = new Readable({ - read() { } - }); - - const chatPromise = processStream(reader, decoder, readableStream, opts.statusStream).then(content => { - this.messages.push( - { - role: "user", - message, - }, - { - role: "cortex", - message: content - }); - return this; - }); - - return { responseStream: readableStream, chat: chatPromise }; + async respond(opts: RespondChatOptsSync): Promise; + async respond(opts: RespondChatOptsStreaming): Promise; + async respond( + opts: RespondChatOptsSync | RespondChatOptsStreaming, + ): Promise { + if (isRespondChatOptsSync(opts)) { + return this.respondChatSync(opts); + } else { + return this.respondChatStreaming(opts); } + } + + private async respondChatSync(opts: RespondChatOptsSync): Promise { + const { message, cortex } = opts; + const res = await this.apiClient.POST(`/chats/${this.id}`, { + message, + cortex, + }); + const body = await res.json(); + this.messages.push( + { + role: "user", + message, + }, + { + role: "cortex", + message: body.response, + }, + ); + + return body.response; + } + private async respondChatStreaming( + opts: RespondChatOptsStreaming, + ): Promise { + const { message, cortex } = opts; + const res = await this.apiClient.POST(`/chats/${this.id}`, { + message, + cortex, + stream: true, + }); + const reader = res.body!.getReader(); + const decoder = new TextDecoder("utf-8"); + + const readableStream = new Readable({ + read() {}, + }); + + const chatPromise = processStream( + reader, + decoder, + readableStream, + opts.statusStream, + ).then((content) => { + this.messages.push( + { + role: "user", + message, + }, + { + role: "cortex", + message: content, + }, + ); + return this; + }); + + return { responseStream: readableStream, chat: chatPromise }; + } } -function isCreateChatOptsSync(opts: CreateChatOptsSync | CreateChatOptsStreaming): opts is CreateChatOptsSync { - return opts.stream === false || opts.stream === undefined; +function isCreateChatOptsSync( + opts: CreateChatOptsSync | CreateChatOptsStreaming, +): opts is CreateChatOptsSync { + return opts.stream === false || opts.stream === undefined; } -function isRespondChatOptsSync(opts: RespondChatOptsSync | RespondChatOptsStreaming): opts is RespondChatOptsSync { - return opts.stream === false || opts.stream === undefined; -} \ No newline at end of file +function isRespondChatOptsSync( + opts: RespondChatOptsSync | RespondChatOptsStreaming, +): opts is RespondChatOptsSync { + return opts.stream === false || opts.stream === undefined; +} diff --git a/client.ts b/client.ts index cd78562..fe2ce6a 100644 --- a/client.ts +++ b/client.ts @@ -7,147 +7,154 @@ import { Content, StreamingContentResult } from "./content.js"; import { Readable } from "stream"; export type CortexClientArgs = { - org: string; - accessToken: string; - apiUrl?: string; -} + org: string; + accessToken: string; + apiUrl?: string; +}; export interface ClientCreateContentOptsBase { - cortex: Cortex; - title: string; - prompt: string; - stream?: boolean; - statusStream?: Readable; -}; -export interface ClientCreateContentOptsSync extends ClientCreateContentOptsBase { - stream?: false; -}; -export interface ClientCreateContentOptsStreaming extends ClientCreateContentOptsBase { - stream?: true; -}; + cortex: Cortex; + title: string; + prompt: string; + stream?: boolean; + statusStream?: Readable; +} +export interface ClientCreateContentOptsSync + extends ClientCreateContentOptsBase { + stream?: false; +} +export interface ClientCreateContentOptsStreaming + extends ClientCreateContentOptsBase { + stream?: true; +} export interface ClientCreateChatOptsBase { - message: string; - cortex: Cortex; - stream?: boolean; - statusStream?: Readable; + message: string; + cortex: Cortex; + stream?: boolean; + statusStream?: Readable; } -export interface ClientCreateChatOptsStreaming extends ClientCreateChatOptsBase { - stream?: true +export interface ClientCreateChatOptsStreaming + extends ClientCreateChatOptsBase { + stream?: true; } export interface ClientCreateChatOptsSync extends ClientCreateChatOptsBase { - stream?: false + stream?: false; } export interface ClientListContentPaginationOpts { - pageSize?: number; - cursor?: string; + pageSize?: number; + cursor?: string; } export interface ClientListChatPaginationOpts { - pageSize?: number; - cursor?: string; + pageSize?: number; + cursor?: string; } const apiUrl = process.env.CORTEX_API_URL || "https://api.cortexclick.com"; export class CortexClient { - private apiClient: CortexApiClient; - constructor(args: CortexClientArgs) { - const url: string = args.apiUrl || apiUrl; - this.apiClient = new CortexApiClient(args.org, url, args.accessToken) - } - - async chat(opts: ClientCreateChatOptsSync): Promise; - async chat(opts: ClientCreateChatOptsStreaming): Promise; - async chat(opts: ClientCreateChatOptsSync | ClientCreateChatOptsStreaming): Promise { - if (opts.stream === true) { - return Chat.create({ - client: this.apiClient, - cortex: opts.cortex, - message: opts.message, - stream: true, - statusStream: opts.statusStream, - }); - } else { - return Chat.create({ - client: this.apiClient, - cortex: opts.cortex, - message: opts.message, - stream: false, - statusStream: opts.statusStream, - }); - } + private apiClient: CortexApiClient; + constructor(args: CortexClientArgs) { + const url: string = args.apiUrl || apiUrl; + this.apiClient = new CortexApiClient(args.org, url, args.accessToken); + } + + async chat(opts: ClientCreateChatOptsSync): Promise; + async chat(opts: ClientCreateChatOptsStreaming): Promise; + async chat( + opts: ClientCreateChatOptsSync | ClientCreateChatOptsStreaming, + ): Promise { + if (opts.stream === true) { + return Chat.create({ + client: this.apiClient, + cortex: opts.cortex, + message: opts.message, + stream: true, + statusStream: opts.statusStream, + }); + } else { + return Chat.create({ + client: this.apiClient, + cortex: opts.cortex, + message: opts.message, + stream: false, + statusStream: opts.statusStream, + }); } - - async getChat(id: string) { - return Chat.get(this.apiClient, id); + } + + async getChat(id: string) { + return Chat.get(this.apiClient, id); + } + + async generateContent(opts: ClientCreateContentOptsSync): Promise; + async generateContent( + opts: ClientCreateContentOptsStreaming, + ): Promise; + async generateContent( + opts: ClientCreateContentOptsSync | ClientCreateContentOptsStreaming, + ) { + // note: this if statement is annoying but is necessary to appropriately narrow the return type + if (opts.stream === true) { + return Content.create({ + client: this.apiClient, + cortex: opts.cortex, + prompt: opts.prompt, + title: opts.title, + stream: true, + statusStream: opts.statusStream, + }); + } else { + return Content.create({ + client: this.apiClient, + cortex: opts.cortex, + prompt: opts.prompt, + title: opts.title, + stream: false, + statusStream: opts.statusStream, + }); } - - async generateContent(opts: ClientCreateContentOptsSync): Promise - async generateContent(opts: ClientCreateContentOptsStreaming): Promise - async generateContent(opts: ClientCreateContentOptsSync | ClientCreateContentOptsStreaming) { - // note: this if statement is annoying but is necessary to appropriately narrow the return type - if (opts.stream === true) { - return Content.create({ - client: this.apiClient, - cortex: opts.cortex, - prompt: opts.prompt, - title: opts.title, - stream: true, - statusStream: opts.statusStream - }); - } else { - return Content.create({ - client: this.apiClient, - cortex: opts.cortex, - prompt: opts.prompt, - title: opts.title, - stream: false, - statusStream: opts.statusStream - }); - } - } - - async getContent(id: string, version?: number) { - return Content.get(this.apiClient, id, version); - } - - async listContent(paginationOptions?: ClientListContentPaginationOpts) { - return Content.list(this.apiClient, paginationOptions); - } - - async listChats(paginationOptions?: ClientListChatPaginationOpts) { - return Chat.list(this.apiClient, paginationOptions); - } - - async getCortex(name: string): Promise { - return Cortex.get(this.apiClient, name) - } - - async configureCortex(name: string, opts: CortexConfig): Promise { - return Cortex.configure(this.apiClient, name, opts); - } - - async configureOrg(opts: OrgConfigOpts): Promise { - return OrgConfig.configure(this.apiClient, opts); - } - - async getOrgConfig() { - return OrgConfig.get(this.apiClient); - } - - async getCatalog(name: string) { - return Catalog.get(this.apiClient, name); - } - - async configureCatalog(name: string, opts: CatalogConfig) { - return Catalog.configure(this.apiClient, name, opts); - } - - async listCatalogs() { - return Catalog.list(this.apiClient); - } - -} \ No newline at end of file + } + + async getContent(id: string, version?: number) { + return Content.get(this.apiClient, id, version); + } + + async listContent(paginationOptions?: ClientListContentPaginationOpts) { + return Content.list(this.apiClient, paginationOptions); + } + async listChats(paginationOptions?: ClientListChatPaginationOpts) { + return Chat.list(this.apiClient, paginationOptions); + } + + async getCortex(name: string): Promise { + return Cortex.get(this.apiClient, name); + } + + async configureCortex(name: string, opts: CortexConfig): Promise { + return Cortex.configure(this.apiClient, name, opts); + } + + async configureOrg(opts: OrgConfigOpts): Promise { + return OrgConfig.configure(this.apiClient, opts); + } + + async getOrgConfig() { + return OrgConfig.get(this.apiClient); + } + + async getCatalog(name: string) { + return Catalog.get(this.apiClient, name); + } + + async configureCatalog(name: string, opts: CatalogConfig) { + return Catalog.configure(this.apiClient, name, opts); + } + + async listCatalogs() { + return Catalog.list(this.apiClient); + } +} diff --git a/content.test.ts b/content.test.ts index 4b7defb..fa3244d 100644 --- a/content.test.ts +++ b/content.test.ts @@ -1,4 +1,4 @@ -import { expect, test } from 'vitest'; +import { expect, test } from "vitest"; import { CortexClient, TextDocument } from "./index"; import { CatalogConfig } from "./catalog"; import { Readable } from "stream"; @@ -9,21 +9,162 @@ const client = new CortexClient({ apiUrl: "http://localhost:3001", }); - -test('e2e catalog, cortex, and sync content generation workflow', { timeout: 120000 }, async () => { - +test( + "e2e catalog, cortex, and sync content generation workflow", + { timeout: 120000 }, + async () => { + client.configureOrg({ + companyName: "Cortex Click", + companyInfo: + "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", + personality: [ + "friendly and helpful", + "expert sales and marketing professional", + "experienced software developer", + ], + rules: [ + "never say anything disparaging about AI or LLMs", + "do not offer discounts", + ], + }); + + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; + + const config: CatalogConfig = { + description: + "this catalog contains documentation from the cortex click marketing website", + instructions: [ + "user this data set to answer user questions about the cortex click platform", + ], + }; + + // create + const catalog = await client.configureCatalog(catalogName, config); + + const documents: TextDocument[] = [ + { + documentId: "a", + content: + "cortex click solutions: customer support, blog and content writing, technical documentation generation, SEO, sales process automation, AI email marketing", + contentType: "markdown", + }, + { + documentId: "b", + content: "cortex click customers: reds fly shop, pyxos, ", + contentType: "markdown", + }, + { + documentId: "c", + content: + "cortex click customer verticals and industries: developer tools, e-commerce, SaaS, network security, compliance, and more.", + contentType: "markdown", + }, + ]; + + await catalog.upsertDocuments(documents); + + const cortex = await client.configureCortex( + `cortex-${Math.floor(Math.random() * 10000)}`, + { + catalogs: [catalog.name], + friendlyName: "Cortex AI", + instructions: [ + "answer questions about the cortex click AI GTM platform", + ], + public: true, + }, + ); + + // create content + const title = "Overview of the Cortex Click AI GTM Platform"; + const prompt = + "Write a blog post about the Cortex Click AI GTM Platform. Elaborate on scenarios, customers, and appropriate verticals. Make sure to mention the impact that AI can have on sales and marketing teams."; + const content = await cortex.generateContent({ title, prompt }); + const originalContent = content.content; + const originalTitle = content.title; + expect(content.content.length).toBeGreaterThan(1); + expect(content.title).toBe(title); + expect(content.version).toBe(0); + expect(content.commands.length).toBe(1); + + // get content + const getContent = await client.getContent(content.id); + expect(getContent.content.length).toBe(content.content.length); + expect(getContent.title).toBe(title); + expect(getContent.version).toBe(0); + expect(getContent.commands.length).toBe(1); + + // edit content + const editedContent = await content.edit({ title: "foo", content: "bar" }); + expect(editedContent.content).toBe("bar"); + expect(editedContent.title).toBe("foo"); + expect(editedContent.version).toBe(1); + expect(editedContent.commands.length).toBe(2); + + // get content version + const contentV0 = await client.getContent(content.id, 0); + expect(contentV0.content).toEqual(originalContent); + expect(contentV0.title).toBe(originalTitle); + expect(contentV0.version).toBe(0); + expect(contentV0.commands.length).toBe(1); + + // revert to earlier version + const revertedContent = await contentV0.revert(0); + expect(revertedContent.content).toEqual(originalContent); + expect(revertedContent.title).toBe(originalTitle); + expect(revertedContent.version).toBe(2); + expect(revertedContent.commands.length).toBe(3); + + const refinePrompt = + "add a final paragraph with a joke or pun about cortex click an AI."; + + const refinedContent = await revertedContent.refine({ + prompt: refinePrompt, + }); + expect(refinedContent.content.length).toBeGreaterThan(1); + expect(refinedContent.title).toBe(originalTitle); + expect(refinedContent.version).toBe(3); + expect(refinedContent.commands.length).toBe(4); + + // list content - putting test here to save overhead of generating more content + const contentList = await client.listContent({ pageSize: 1 }); + expect(contentList.content.length).toBe(1); + + const nextPage = await contentList.nextPage(); + expect(nextPage.content.length).toBe(1); + + const contentList2 = await client.listContent(); + expect(contentList2.content.length).toBeGreaterThan(1); + + // delete + await catalog.delete(); + }, +); + +test("test streaming content", { timeout: 120000 }, async () => { client.configureOrg({ companyName: "Cortex Click", - companyInfo: "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", - personality: ["friendly and helpful", "expert sales and marketing professional", "experienced software developer"], - rules: ["never say anything disparaging about AI or LLMs", "do not offer discounts"], - }) + companyInfo: + "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", + personality: [ + "friendly and helpful", + "expert sales and marketing professional", + "experienced software developer", + ], + rules: [ + "never say anything disparaging about AI or LLMs", + "do not offer discounts", + ], + }); - const catalogName = `catalog-${Math.floor(Math.random() * 10000)}` + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; const config: CatalogConfig = { - description: "this catalog contains documentation from the cortex click marketing website", - instructions: ["user this data set to answer user questions about the cortex click platform"] + description: + "this catalog contains documentation from the cortex click marketing website", + instructions: [ + "user this data set to answer user questions about the cortex click platform", + ], }; // create @@ -32,154 +173,59 @@ test('e2e catalog, cortex, and sync content generation workflow', { timeout: 120 const documents: TextDocument[] = [ { documentId: "a", - content: "cortex click solutions: customer support, blog and content writing, technical documentation generation, SEO, sales process automation, AI email marketing", - contentType: "markdown" + content: + "cortex click solutions: customer support, blog and content writing, technical documentation generation, SEO, sales process automation, AI email marketing", + contentType: "markdown", }, { documentId: "b", content: "cortex click customers: reds fly shop, pyxos, ", - contentType: "markdown" + contentType: "markdown", }, { documentId: "c", - content: "cortex click customer verticals and industries: developer tools, e-commerce, SaaS, network security, compliance, and more.", - contentType: "markdown" - } + content: + "cortex click customer verticals and industries: developer tools, e-commerce, SaaS, network security, compliance, and more.", + contentType: "markdown", + }, ]; await catalog.upsertDocuments(documents); - const cortex = await client.configureCortex(`cortex-${Math.floor(Math.random() * 10000)}`, { - catalogs: [catalog.name], - friendlyName: "Cortex AI", - instructions: ["answer questions about the cortex click AI GTM platform"], - public: true, - }); - - // create content - const title = "Overview of the Cortex Click AI GTM Platform"; - const prompt = "Write a blog post about the Cortex Click AI GTM Platform. Elaborate on scenarios, customers, and appropriate verticals. Make sure to mention the impact that AI can have on sales and marketing teams." - const content = await cortex.generateContent({ title, prompt }); - const originalContent = content.content; - const originalTitle = content.title; - expect(content.content.length).toBeGreaterThan(1); - expect(content.title).toBe(title); - expect(content.version).toBe(0); - expect(content.commands.length).toBe(1); - - // get content - const getContent = await client.getContent(content.id); - expect(getContent.content.length).toBe(content.content.length); - expect(getContent.title).toBe(title); - expect(getContent.version).toBe(0); - expect(getContent.commands.length).toBe(1); - - // edit content - const editedContent = await content.edit({ title: "foo", content: "bar" }); - expect(editedContent.content).toBe("bar"); - expect(editedContent.title).toBe("foo"); - expect(editedContent.version).toBe(1); - expect(editedContent.commands.length).toBe(2); - - // get content version - const contentV0 = await client.getContent(content.id, 0); - expect(contentV0.content).toEqual(originalContent); - expect(contentV0.title).toBe(originalTitle); - expect(contentV0.version).toBe(0); - expect(contentV0.commands.length).toBe(1); - - // revert to earlier version - const revertedContent = await contentV0.revert(0); - expect(revertedContent.content).toEqual(originalContent); - expect(revertedContent.title).toBe(originalTitle); - expect(revertedContent.version).toBe(2); - expect(revertedContent.commands.length).toBe(3); - - const refinePrompt = "add a final paragraph with a joke or pun about cortex click an AI." - - const refinedContent = await revertedContent.refine({ prompt: refinePrompt }); - expect(refinedContent.content.length).toBeGreaterThan(1); - expect(refinedContent.title).toBe(originalTitle); - expect(refinedContent.version).toBe(3); - expect(refinedContent.commands.length).toBe(4); - - // list content - putting test here to save overhead of generating more content - const contentList = await client.listContent({ pageSize: 1 }); - expect(contentList.content.length).toBe(1); - - const nextPage = await contentList.nextPage(); - expect(nextPage.content.length).toBe(1); - - const contentList2 = await client.listContent(); - expect(contentList2.content.length).toBeGreaterThan(1); - - // delete - await catalog.delete(); -}); - -test('test streaming content', { timeout: 120000 }, async () => { - - client.configureOrg({ - companyName: "Cortex Click", - companyInfo: "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", - personality: ["friendly and helpful", "expert sales and marketing professional", "experienced software developer"], - rules: ["never say anything disparaging about AI or LLMs", "do not offer discounts"], - }) - - const catalogName = `catalog-${Math.floor(Math.random() * 10000)}` - - const config: CatalogConfig = { - description: "this catalog contains documentation from the cortex click marketing website", - instructions: ["user this data set to answer user questions about the cortex click platform"] - }; - - // create - const catalog = await client.configureCatalog(catalogName, config); - - const documents: TextDocument[] = [ + const cortex = await client.configureCortex( + `cortex-${Math.floor(Math.random() * 10000)}`, { - documentId: "a", - content: "cortex click solutions: customer support, blog and content writing, technical documentation generation, SEO, sales process automation, AI email marketing", - contentType: "markdown" - }, - { - documentId: "b", - content: "cortex click customers: reds fly shop, pyxos, ", - contentType: "markdown" + catalogs: [catalog.name], + friendlyName: "Cortex AI", + instructions: ["answer questions about the cortex click AI GTM platform"], + public: true, }, - { - documentId: "c", - content: "cortex click customer verticals and industries: developer tools, e-commerce, SaaS, network security, compliance, and more.", - contentType: "markdown" - } - ]; - - await catalog.upsertDocuments(documents); - - const cortex = await client.configureCortex(`cortex-${Math.floor(Math.random() * 10000)}`, { - catalogs: [catalog.name], - friendlyName: "Cortex AI", - instructions: ["answer questions about the cortex click AI GTM platform"], - public: true, - }); + ); // create content const title = "Overview of the Cortex Click AI GTM Platform"; - const prompt = "Write a blog post about the Cortex Click AI GTM Platform. Elaborate on scenarios, customers, and appropriate verticals. Make sure to mention the impact that AI can have on sales and marketing teams." + const prompt = + "Write a blog post about the Cortex Click AI GTM Platform. Elaborate on scenarios, customers, and appropriate verticals. Make sure to mention the impact that AI can have on sales and marketing teams."; const statusStream = new Readable({ - read() { } + read() {}, + }); + const { content, contentStream } = await client.generateContent({ + cortex, + prompt, + title, + stream: true, + statusStream, }); - const { content, contentStream } = await client.generateContent({ cortex, prompt, title, stream: true, statusStream }); - let fullContent = "" - contentStream.on('data', (data) => { + let fullContent = ""; + contentStream.on("data", (data) => { fullContent += data.toString(); }); let sawPlan = false; let sawDraft = false; - let sawEditorial = false + let sawEditorial = false; - statusStream.on('data', (data) => { + statusStream.on("data", (data) => { const message = JSON.parse(data); expect(message.messageType).toBe("status"); switch (message.step) { @@ -206,11 +252,15 @@ test('test streaming content', { timeout: 120000 }, async () => { expect(sawDraft).toBe(true); expect(sawEditorial).toBe(true); - const refinePrompt = "add a final paragraph with a joke or pun about cortex click an AI." + const refinePrompt = + "add a final paragraph with a joke or pun about cortex click an AI."; - const refinedContentPromise = await contentResult.refine({ prompt: refinePrompt, stream: true }); + const refinedContentPromise = await contentResult.refine({ + prompt: refinePrompt, + stream: true, + }); let fullRefinedContent = ""; - refinedContentPromise.contentStream.on('data', (data) => { + refinedContentPromise.contentStream.on("data", (data) => { fullRefinedContent += data.toString(); }); @@ -224,23 +274,35 @@ test('test streaming content', { timeout: 120000 }, async () => { await catalog.delete(); }); -test('e2e content without any catalogs', { timeout: 120000 }, async () => { +test("e2e content without any catalogs", { timeout: 120000 }, async () => { client.configureOrg({ companyName: "Cortex Click", - companyInfo: "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", - personality: ["friendly and helpful", "expert sales and marketing professional", "experienced software developer"], - rules: ["never say anything disparaging about AI or LLMs", "do not offer discounts"], - }) - - const cortex = await client.configureCortex(`cortex-${Math.floor(Math.random() * 10000)}`, { - friendlyName: "Cortex AI", - instructions: ["answer questions about the cortex click AI GTM platform"], - public: true, + companyInfo: + "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", + personality: [ + "friendly and helpful", + "expert sales and marketing professional", + "experienced software developer", + ], + rules: [ + "never say anything disparaging about AI or LLMs", + "do not offer discounts", + ], }); + const cortex = await client.configureCortex( + `cortex-${Math.floor(Math.random() * 10000)}`, + { + friendlyName: "Cortex AI", + instructions: ["answer questions about the cortex click AI GTM platform"], + public: true, + }, + ); + // create content const title = "Overview of the Cortex Click AI GTM Platform"; - const prompt = "Write a blog post about the Cortex Click AI GTM Platform. Elaborate on scenarios, customers, and appropriate verticals. Make sure to mention the impact that AI can have on sales and marketing teams." + const prompt = + "Write a blog post about the Cortex Click AI GTM Platform. Elaborate on scenarios, customers, and appropriate verticals. Make sure to mention the impact that AI can have on sales and marketing teams."; const content = await cortex.generateContent({ title, prompt }); expect(content.content.length).toBeGreaterThan(1); diff --git a/content.ts b/content.ts index 4eb00a8..35624bc 100644 --- a/content.ts +++ b/content.ts @@ -1,269 +1,371 @@ import { Cortex } from "./cortex.js"; import { CortexApiClient } from "./api-client.js"; -import { Readable } from 'stream'; +import { Readable } from "stream"; import { processStream } from "./utils/streaming.js"; -export type ContentCommandType = "ai-generate" | "ai-refine" | "ai-regenerate" | "user-edit" | "revert"; +export type ContentCommandType = + | "ai-generate" + | "ai-refine" + | "ai-regenerate" + | "user-edit" + | "revert"; export interface CreateContentOptsBase { - client: CortexApiClient; - cortex: Cortex; - title: string; - prompt: string; - stream?: boolean; - statusStream?: Readable; + client: CortexApiClient; + cortex: Cortex; + title: string; + prompt: string; + stream?: boolean; + statusStream?: Readable; } export interface CreateContentOptsStreaming extends CreateContentOptsBase { - stream?: true + stream?: true; } export interface CreateContentOptsSync extends CreateContentOptsBase { - stream?: false + stream?: false; } export interface RefineContentOptsBase { - prompt: string; - stream?: boolean; - statusStream?: Readable; + prompt: string; + stream?: boolean; + statusStream?: Readable; } export interface RefineContentOptsStreaming extends RefineContentOptsBase { - stream?: true + stream?: true; } export interface RefineContentOptsSync extends RefineContentOptsBase { - stream?: false + stream?: false; } export type StreamingContentResult = { - readonly contentStream: Readable; - readonly content: Promise -} + readonly contentStream: Readable; + readonly content: Promise; +}; type ContentCommand = { - commandType: ContentCommandType; - command?: string; - version: number; + commandType: ContentCommandType; + command?: string; + version: number; }; export type EditContentOpts = { - title?: string; - content?: string; -} + title?: string; + content?: string; +}; export type ContentListItem = { - title: string; - latestVersion: number; - id: string; - Content(): Promise; -} + title: string; + latestVersion: number; + id: string; + Content(): Promise; +}; -export type ContentListResult = { nextPage: () => Promise, content: ContentListItem[] }; +export type ContentListResult = { + nextPage: () => Promise; + content: ContentListItem[]; +}; export type ContentListPaginationOptions = { - cursor?: string; - pageSize?: number; -} + cursor?: string; + pageSize?: number; +}; export class Content { - get id() { - return this._id; + get id() { + return this._id; + } + + get title() { + return this._title; + } + + get content() { + return this._content; + } + + get commands() { + return this._commands; + } + + get version() { + return this._version; + } + + get cortex() { + return this._cortex; + } + + private constructor( + private apiClient: CortexApiClient, + private _id: string, + private _title: string, + private _content: string, + private _commands: ContentCommand[], + private _version: number, + private _cortex?: string, + ) {} + + static async create(opts: CreateContentOptsSync): Promise; + static async create( + opts: CreateContentOptsStreaming, + ): Promise; + static async create( + opts: CreateContentOptsSync | CreateContentOptsStreaming, + ): Promise { + // note: this if statement is annoying but is necessary to appropriately narrow the return type + if (isCreateContentOptsSync(opts)) { + return this.createContentSync(opts); + } else { + return this.createContentStreaming(opts); } - - get title() { - return this._title; - } - - get content() { - return this._content; + } + + private static async createContentSync( + opts: CreateContentOptsSync, + ): Promise { + const { client, cortex, title, prompt } = opts; + const res = await client.POST(`/content`, { + cortex: cortex.name, + title, + prompt, + }); + const body = await res.json(); + + return new Content( + client, + body.id, + body.title, + body.content, + body.commands, + body.version, + ); + } + + private static async createContentStreaming( + opts: CreateContentOptsStreaming, + ): Promise { + const { client, cortex, title, prompt, stream } = opts; + const res = await client.POST(`/content`, { + cortex: cortex.name, + title, + prompt, + stream, + }); + const reader = res.body!.getReader(); + const decoder = new TextDecoder("utf-8"); + + const id: string = res.headers.get("id") || ""; + const version: number = parseInt(res.headers.get("version") || "0"); + const commands: ContentCommand[] = JSON.parse( + res.headers.get("commands") || "[]", + ); + + const readableStream = new Readable({ + read() {}, + }); + + const contentPromise = processStream( + reader, + decoder, + readableStream, + opts.statusStream, + ).then((content) => { + return new Content( + client, + id, + title, + content, + commands, + version, + cortex.name, + ); + }); + + return { contentStream: readableStream, content: contentPromise }; + } + + static async get( + client: CortexApiClient, + id: string, + version?: number, + ): Promise { + let res: Response; + if (version !== undefined) { + res = await client.GET(`/content/${id}/version/${version}`); + } else { + res = await client.GET(`/content/${id}`); } - get commands() { - return this._commands; + if (res.status !== 200) { + throw new Error(`Failed to get content: ${res.statusText}`); } - get version() { - return this._version; - } - - get cortex() { - return this._cortex; - } - - private constructor(private apiClient: CortexApiClient, private _id: string, private _title: string, private _content: string, private _commands: ContentCommand[], private _version: number, private _cortex?: string) { - } - - - static async create(opts: CreateContentOptsSync): Promise; - static async create(opts: CreateContentOptsStreaming): Promise; - static async create(opts: CreateContentOptsSync | CreateContentOptsStreaming): Promise { - // note: this if statement is annoying but is necessary to appropriately narrow the return type - if (isCreateContentOptsSync(opts)) { - return this.createContentSync(opts); - } else { - return this.createContentStreaming(opts); - } - - } - - private static async createContentSync(opts: CreateContentOptsSync): Promise { - const { client, cortex, title, prompt } = opts; - const res = await client.POST(`/content`, { cortex: cortex.name, title, prompt }); - const body = await res.json(); - - return new Content(client, body.id, body.title, body.content, body.commands, body.version); + const body = await res.json(); + return new Content( + client, + id, + body.title, + body.content, + body.commands, + body.version, + body.cortex, + ); + } + + async edit(opts: EditContentOpts) { + if (!opts.title && !opts.content) { + throw new Error( + "must specify one of opts.title or opts.content to edit content", + ); } - private static async createContentStreaming(opts: CreateContentOptsStreaming): Promise { - const { client, cortex, title, prompt, stream } = opts; - const res = await client.POST(`/content`, { cortex: cortex.name, title, prompt, stream }); - const reader = res.body!.getReader(); - const decoder = new TextDecoder('utf-8'); - - const id: string = res.headers.get("id") || ""; - const version: number = parseInt(res.headers.get("version") || "0"); - const commands: ContentCommand[] = JSON.parse(res.headers.get("commands") || "[]"); - - const readableStream = new Readable({ - read() { } - }); - - const contentPromise = processStream(reader, decoder, readableStream, opts.statusStream).then(content => { - return new Content(client, id, title, content, commands, version, cortex.name); - }); - - return { contentStream: readableStream, content: contentPromise }; + const res = await this.apiClient.PUT(`/content/${this._id}`, opts); + const body = await res.json(); + + this._commands = body.commands; + this._content = body.content; + this._title = body.title; + this._version = body.version; + this._cortex = body.cortex; + + return this; + } + + async refine(opts: RefineContentOptsSync): Promise; + async refine( + opts: RefineContentOptsStreaming, + ): Promise; + async refine( + opts: RefineContentOptsSync | RefineContentOptsStreaming, + ): Promise { + if (isRefineContentOptsSync(opts)) { + return this.refineContentSync(opts); + } else { + return this.refineContentStreaming(opts); } - - static async get(client: CortexApiClient, id: string, version?: number): Promise { - let res: Response; - if (version !== undefined) { - res = await client.GET(`/content/${id}/version/${version}`); - } else { - res = await client.GET(`/content/${id}`); - } - - if (res.status !== 200) { - throw new Error(`Failed to get content: ${res.statusText}`); - } - - const body = await res.json(); - return new Content(client, id, body.title, body.content, body.commands, body.version, body.cortex); + } + + private async refineContentSync( + opts: RefineContentOptsSync, + ): Promise { + const res = await this.apiClient.POST(`/content/${this._id}/refine`, { + prompt: opts.prompt, + }); + const body = await res.json(); + + this._commands = body.commands; + this._content = body.content; + this._title = body.title; + this._version = body.version; + this._cortex = body.cortex; + + return this; + } + + private async refineContentStreaming( + opts: RefineContentOptsStreaming, + ): Promise { + const { prompt } = opts; + const res = await this.apiClient.POST(`/content/${this._id}/refine`, { + prompt, + stream: true, + }); + const reader = res.body!.getReader(); + const decoder = new TextDecoder("utf-8"); + + const version: number = parseInt(res.headers.get("version") || "0"); + const commands: ContentCommand[] = JSON.parse( + res.headers.get("commands") || "[]", + ); + this._version = version; + this._commands = commands; + + const readableStream = new Readable({ + read() {}, + }); + + const contentPromise = processStream( + reader, + decoder, + readableStream, + opts.statusStream, + ).then((content) => { + this._content = content; + return this; + }); + + return { contentStream: readableStream, content: contentPromise }; + } + + async revert(version: number) { + const res = await this.apiClient.POST( + `/content/${this._id}/version/${version}`, + ); + + if (res.status !== 200) { + throw new Error(`Failed to revert content: ${res.statusText}`); } - async edit(opts: EditContentOpts) { - if (!opts.title && !opts.content) { - throw new Error("must specify one of opts.title or opts.content to edit content"); - } + const body = await res.json(); - const res = await this.apiClient.PUT(`/content/${this._id}`, opts); - const body = await res.json(); + this._commands = body.commands; + this._content = body.content; + this._title = body.title; + this._version = body.version; + this._cortex = body.cortex; - this._commands = body.commands; - this._content = body.content; - this._title = body.title; - this._version = body.version; - this._cortex = body.cortex; + return this; + } - return this; - } + static async list( + client: CortexApiClient, + paginationOpts?: ContentListPaginationOptions, + ): Promise { + const contentList: ContentListItem[] = []; - async refine(opts: RefineContentOptsSync): Promise; - async refine(opts: RefineContentOptsStreaming): Promise; - async refine(opts: RefineContentOptsSync | RefineContentOptsStreaming): Promise { - if (isRefineContentOptsSync(opts)) { - return this.refineContentSync(opts); - } else { - return this.refineContentStreaming(opts); - } + const query = new URLSearchParams(); + if (paginationOpts?.cursor) { + query.set("cursor", paginationOpts.cursor); } - - private async refineContentSync(opts: RefineContentOptsSync): Promise { - const res = await this.apiClient.POST(`/content/${this._id}/refine`, { prompt: opts.prompt }); - const body = await res.json(); - - this._commands = body.commands; - this._content = body.content; - this._title = body.title; - this._version = body.version; - this._cortex = body.cortex; - - return this; + query.set("pageSize", (paginationOpts?.pageSize || 50).toString()); + const res = await client.GET(`/content?${query.toString()}`); + if (res.status !== 200) { + throw new Error(`Failed to list content: ${res.statusText}`); } - - private async refineContentStreaming(opts: RefineContentOptsStreaming): Promise { - const { prompt } = opts; - const res = await this.apiClient.POST(`/content/${this._id}/refine`, { prompt, stream: true }); - const reader = res.body!.getReader(); - const decoder = new TextDecoder('utf-8'); - - const version: number = parseInt(res.headers.get("version") || "0"); - const commands: ContentCommand[] = JSON.parse(res.headers.get("commands") || "[]"); - this._version = version; - this._commands = commands; - - const readableStream = new Readable({ - read() { } - }); - - const contentPromise = processStream(reader, decoder, readableStream, opts.statusStream).then(content => { - this._content = content; - return this; - }); - - return { contentStream: readableStream, content: contentPromise }; + const body = await res.json(); + for (const content of body.content) { + contentList.push({ + title: content.title, + latestVersion: content.latestVersion, + id: content.contentId, + Content: () => { + return Content.get(client, content.contentId); + }, + }); } - async revert(version: number) { - const res = await this.apiClient.POST(`/content/${this._id}/version/${version}`); - - if (res.status !== 200) { - throw new Error(`Failed to revert content: ${res.statusText}`); - } - - const body = await res.json(); - - this._commands = body.commands; - this._content = body.content; - this._title = body.title; - this._version = body.version; - this._cortex = body.cortex; - - return this; - } - - static async list(client: CortexApiClient, paginationOpts?: ContentListPaginationOptions): Promise { - const contentList: ContentListItem[] = []; - - const query = new URLSearchParams(); - if (paginationOpts?.cursor) { - query.set("cursor", paginationOpts.cursor); - } - query.set("pageSize", (paginationOpts?.pageSize || 50).toString()); - const res = await client.GET(`/content?${query.toString()}`); - if (res.status !== 200) { - throw new Error(`Failed to list content: ${res.statusText}`); - } - const body = await res.json(); - for (const content of body.content) { - contentList.push({ - title: content.title, - latestVersion: content.latestVersion, - id: content.contentId, - Content: () => { return Content.get(client, content.contentId) } - }) - } - - const cursor = body.cursor; - const pageSize = paginationOpts?.pageSize; - return { content: contentList, nextPage: async () => { return Content.list(client, { cursor, pageSize }) } }; - } + const cursor = body.cursor; + const pageSize = paginationOpts?.pageSize; + return { + content: contentList, + nextPage: async () => { + return Content.list(client, { cursor, pageSize }); + }, + }; + } } -function isCreateContentOptsSync(opts: CreateContentOptsSync | CreateContentOptsStreaming): opts is CreateContentOptsSync { - return opts.stream === false || opts.stream === undefined; +function isCreateContentOptsSync( + opts: CreateContentOptsSync | CreateContentOptsStreaming, +): opts is CreateContentOptsSync { + return opts.stream === false || opts.stream === undefined; } -function isRefineContentOptsSync(opts: RefineContentOptsSync | RefineContentOptsStreaming): opts is RefineContentOptsSync { - return opts.stream === false || opts.stream === undefined; +function isRefineContentOptsSync( + opts: RefineContentOptsSync | RefineContentOptsStreaming, +): opts is RefineContentOptsSync { + return opts.stream === false || opts.stream === undefined; } diff --git a/cortex.test.ts b/cortex.test.ts index dc54b38..9b432ff 100644 --- a/cortex.test.ts +++ b/cortex.test.ts @@ -1,7 +1,7 @@ -import { expect, test } from 'vitest' +import { expect, test } from "vitest"; import { CortexClient } from "./index"; -import { OrgConfigOpts } from './org'; -import { CortexConfig } from './cortex'; +import { OrgConfigOpts } from "./org"; +import { CortexConfig } from "./cortex"; const client = new CortexClient({ accessToken: process.env.CORTEX_ACCESS_TOKEN || "", @@ -9,24 +9,31 @@ const client = new CortexClient({ apiUrl: "http://localhost:3001", }); -test('can get and set OrgConfig', async () => { +test("can get and set OrgConfig", async () => { const orgConfigOpts: OrgConfigOpts = { companyName: "Cortex Click", - companyInfo: "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", - personality: [ "friendly and helpful", "expert sales and marketing professional", "experienced software developer"], - rules: ["never say anything disparaging about AI or LLMs", "do not offer discounts"], - } + companyInfo: + "Cortex Click provides an AI platform for go-to-market. Cortex click allows you to index your enterprise knowledge base, and create agents called Cortexes that automate sales and marketing processes like SEO, content writing, RFP generation, customer support, sales document genearation such as security questionairres and more.", + personality: [ + "friendly and helpful", + "expert sales and marketing professional", + "experienced software developer", + ], + rules: [ + "never say anything disparaging about AI or LLMs", + "do not offer discounts", + ], + }; await client.configureOrg(orgConfigOpts); const getOrgConfig = await client.getOrgConfig(); - expect(getOrgConfig.companyName).toBe(orgConfigOpts.companyName) - expect(getOrgConfig.companyInfo).toBe(orgConfigOpts.companyInfo) + expect(getOrgConfig.companyName).toBe(orgConfigOpts.companyName); + expect(getOrgConfig.companyInfo).toBe(orgConfigOpts.companyInfo); }); -test('can configure, get, and delete and Cortexes', async () => { - - const cortexName = `cortex-${Math.floor(Math.random() * 10000)}` +test("can configure, get, and delete and Cortexes", async () => { + const cortexName = `cortex-${Math.floor(Math.random() * 10000)}`; const cortexConfig: CortexConfig = { friendlyName: "Cortex AI", @@ -42,13 +49,13 @@ test('can configure, get, and delete and Cortexes', async () => { chatConfig: { intro: "hello world", examples: ["q1", "q2"], - greeting: "who lives in a pineapple under the sea? CORTEX AI." + greeting: "who lives in a pineapple under the sea? CORTEX AI.", }, overrides: { companyInfo: "a very good company that does AI stuff", companyName: "Cortex Click, Inc. --test", - inheritRules: false - } + inheritRules: false, + }, }; let cortex = await client.configureCortex(cortexName, cortexConfig); @@ -60,5 +67,7 @@ test('can configure, get, and delete and Cortexes', async () => { // delete the cortex await cortex.delete(); // assert that the get failes - await expect(async () => { await client.getCortex(cortexName) }).rejects.toThrowError("Failed to get cortex: Not Found"); + await expect(async () => { + await client.getCortex(cortexName); + }).rejects.toThrowError("Failed to get cortex: Not Found"); }); diff --git a/cortex.ts b/cortex.ts index c80e64f..2a91ba0 100644 --- a/cortex.ts +++ b/cortex.ts @@ -4,244 +4,256 @@ import { Chat, StreamingChatResult } from "./chat.js"; import { Content, StreamingContentResult } from "./content.js"; export type CortexConfig = { + /** + * The name that this Cortex should refer to itself as, (e.g. "Acme Assistant", "Acme AI") + */ + friendlyName: string; // TODO add column to DB + /** + * The catalogs that should be referenced when generating content and answering questions + */ + // TODO: this should accept "string" | Catalog + catalogs?: string[]; + /** + * A complete description of the goal task and a list of steps this cortex should follow when generating content and answering questions. + */ + instructions: string[]; + /** + * Whether or not this Cortex should be available on the internet, without authentication. This is common for scenarios like publishing blog content, and customer support. + */ + public: boolean; + /** + * fine-tuned control over the verbosity, tone, and rules that are used to generate content. + */ + customizations?: { /** - * The name that this Cortex should refer to itself as, (e.g. "Acme Assistant", "Acme AI") + * A list or "dos and dont's" that the cortex should follow. */ - friendlyName: string; // TODO add column to DB + rules?: string[]; + personality?: string[]; + chatVerbosity?: string; + writeVerbosity?: string; + }; + /** + * configuration for the built-in hosted chat UI. + */ + chatConfig?: { /** - * The catalogs that should be referenced when generating content and answering questions + * The initial greeting message rendered in chat. */ - // TODO: this should accept "string" | Catalog - catalogs?: string[]; + greeting: string; /** - * A complete description of the goal task and a list of steps this cortex should follow when generating content and answering questions. + * An introductory message that explains to users the purpose of this Cortex is and what it can help with. */ - instructions: string[]; + intro: string; /** - * Whether or not this Cortex should be available on the internet, without authentication. This is common for scenarios like publishing blog content, and customer support. + * A list of questions that will be rendered and suggested to users when they load the chat window. */ - public: boolean; + examples: string[]; + }; + /** + * override org-level defaults + */ + overrides?: { /** - * fine-tuned control over the verbosity, tone, and rules that are used to generate content. + * Whether or not global org-level rules should be followed. Defaults to 'true'. */ - customizations?: { - /** - * A list or "dos and dont's" that the cortex should follow. - */ - rules?: string[]; - personality?: string[]; - chatVerbosity?: string; - writeVerbosity?: string; - } + inheritRules?: boolean; /** - * configuration for the built-in hosted chat UI. + * The company name */ - chatConfig?: { - /** - * The initial greeting message rendered in chat. - */ - greeting: string; - /** - * An introductory message that explains to users the purpose of this Cortex is and what it can help with. - */ - intro: string; - /** - * A list of questions that will be rendered and suggested to users when they load the chat window. - */ - examples: string[]; - - }, + companyName?: string; /** - * override org-level defaults + * A description of your company, industry, and products and services provided. */ - overrides?: { - /** - * Whether or not global org-level rules should be followed. Defaults to 'true'. - */ - inheritRules?: boolean; - /** - * The company name - */ - companyName?: string; - /** - * A description of your company, industry, and products and services provided. - */ - companyInfo?: string; - } - + companyInfo?: string; + }; }; export interface CortexCreateContentOptsBase { - title: string; - prompt: string; - stream?: boolean; - statusStream?: Readable + title: string; + prompt: string; + stream?: boolean; + statusStream?: Readable; } -export interface CortexContentOptsStreaming extends CortexCreateContentOptsBase { - stream?: true +export interface CortexContentOptsStreaming + extends CortexCreateContentOptsBase { + stream?: true; } -export interface CortexCreateContentOptsSync extends CortexCreateContentOptsBase { - stream?: false +export interface CortexCreateContentOptsSync + extends CortexCreateContentOptsBase { + stream?: false; } export interface CortexCreateChatOptsBase { - message: string; - stream?: boolean; - statusStream?: Readable; + message: string; + stream?: boolean; + statusStream?: Readable; } -export interface CortexCreateChatOptsStreaming extends CortexCreateChatOptsBase { - stream?: true +export interface CortexCreateChatOptsStreaming + extends CortexCreateChatOptsBase { + stream?: true; } export interface CortexCreateChatOptsSync extends CortexCreateChatOptsBase { - stream?: false + stream?: false; } export class Cortex { - private deleted = false; - private constructor(readonly config: CortexConfig, private apiClient: CortexApiClient, readonly name: string) { } - - static async get(apiClient: CortexApiClient, name: string): Promise { - const res = await apiClient.GET(`/cortex-config/${name}`); - if (res.status !== 200) { - throw new Error(`Failed to get cortex: ${res.statusText}`); - } - const body = await res.json(); - const config: CortexConfig = { - catalogs: body.catalogs, - friendlyName: body.friendlyName, - instructions: body.instructions, - public: !!body.public, - chatConfig: { - examples: body.examples, - greeting: body.greeting, - intro: body.intro, - }, - customizations: { - chatVerbosity: body.chatVerbosity, - writeVerbosity: body.writeVerbosity, - personality: body.personality, - }, - overrides: { - companyInfo: body.companyInfo, - companyName: body.companyName, - inheritRules: !!body.inheritRules, - } - }; - return new Cortex(config, apiClient, name); + private deleted = false; + private constructor( + readonly config: CortexConfig, + private apiClient: CortexApiClient, + readonly name: string, + ) {} + + static async get(apiClient: CortexApiClient, name: string): Promise { + const res = await apiClient.GET(`/cortex-config/${name}`); + if (res.status !== 200) { + throw new Error(`Failed to get cortex: ${res.statusText}`); } + const body = await res.json(); + const config: CortexConfig = { + catalogs: body.catalogs, + friendlyName: body.friendlyName, + instructions: body.instructions, + public: !!body.public, + chatConfig: { + examples: body.examples, + greeting: body.greeting, + intro: body.intro, + }, + customizations: { + chatVerbosity: body.chatVerbosity, + writeVerbosity: body.writeVerbosity, + personality: body.personality, + }, + overrides: { + companyInfo: body.companyInfo, + companyName: body.companyName, + inheritRules: !!body.inheritRules, + }, + }; + return new Cortex(config, apiClient, name); + } - static async configure(apiClient: CortexApiClient, name: string, config: CortexConfig): Promise { - const input: CortexConfigInput = { - cortexName: name, - friendlyName: config.friendlyName, - catalogs: config.catalogs, - chatVerbosity: config.customizations?.chatVerbosity, - writeVerbosity: config.customizations?.writeVerbosity, - companyInfo: config.overrides?.companyInfo, - companyName: config.overrides?.companyName, - examples: config.chatConfig?.examples, - greeting: config.chatConfig?.greeting, - intro: config.chatConfig?.intro, - inheritRules: !!config.overrides?.inheritRules, - public: !!config.public, - instructions: config.instructions, - personality: config.customizations?.personality, - rules: config.customizations?.rules, - } - const getRes = await apiClient.GET(`/cortex-config/${name}`); - let res: Response; - if (getRes.status !== 200) { - res = await apiClient.POST("/cortex-config", input); - } else { - res = await apiClient.PUT(`/cortex-config/${name}`, input); - } - - if (res.status !== 200) { - throw new Error(`Failed to configure cortex: ${res.statusText}`); - } - return new Cortex(config, apiClient, name); + static async configure( + apiClient: CortexApiClient, + name: string, + config: CortexConfig, + ): Promise { + const input: CortexConfigInput = { + cortexName: name, + friendlyName: config.friendlyName, + catalogs: config.catalogs, + chatVerbosity: config.customizations?.chatVerbosity, + writeVerbosity: config.customizations?.writeVerbosity, + companyInfo: config.overrides?.companyInfo, + companyName: config.overrides?.companyName, + examples: config.chatConfig?.examples, + greeting: config.chatConfig?.greeting, + intro: config.chatConfig?.intro, + inheritRules: !!config.overrides?.inheritRules, + public: !!config.public, + instructions: config.instructions, + personality: config.customizations?.personality, + rules: config.customizations?.rules, + }; + const getRes = await apiClient.GET(`/cortex-config/${name}`); + let res: Response; + if (getRes.status !== 200) { + res = await apiClient.POST("/cortex-config", input); + } else { + res = await apiClient.PUT(`/cortex-config/${name}`, input); } - async delete() { - this.checkDeleted(); - this.deleted = true; - await this.apiClient.DELETE(`/cortex-config/${this.name}`); - return; + if (res.status !== 200) { + throw new Error(`Failed to configure cortex: ${res.statusText}`); } + return new Cortex(config, apiClient, name); + } + async delete() { + this.checkDeleted(); + this.deleted = true; + await this.apiClient.DELETE(`/cortex-config/${this.name}`); + return; + } - async chat(opts: CortexCreateChatOptsSync): Promise; - async chat(opts: CortexCreateChatOptsStreaming): Promise; - async chat(opts: CortexCreateChatOptsSync | CortexCreateChatOptsStreaming) { - if(opts.stream === true) { - return Chat.create({ - client: this.apiClient, - cortex: this, - message: opts.message, - statusStream: opts.statusStream, - stream: true, - }); - } else { - return Chat.create({ - client: this.apiClient, - cortex: this, - message: opts.message, - statusStream: opts.statusStream, - stream: false, - }); - } + async chat(opts: CortexCreateChatOptsSync): Promise; + async chat(opts: CortexCreateChatOptsStreaming): Promise; + async chat(opts: CortexCreateChatOptsSync | CortexCreateChatOptsStreaming) { + if (opts.stream === true) { + return Chat.create({ + client: this.apiClient, + cortex: this, + message: opts.message, + statusStream: opts.statusStream, + stream: true, + }); + } else { + return Chat.create({ + client: this.apiClient, + cortex: this, + message: opts.message, + statusStream: opts.statusStream, + stream: false, + }); } + } - async generateContent(opts: CortexCreateContentOptsSync): Promise - async generateContent(opts: CortexContentOptsStreaming): Promise - async generateContent(opts: CortexCreateContentOptsSync | CortexContentOptsStreaming) { - // note: this if statement is annoying but is necessary to appropriately narrow the return type - if(opts.stream === true ) { - return Content.create({ - client: this.apiClient, - cortex: this, - prompt: opts.prompt, - title: opts.title, - stream: true, - statusStream: opts.statusStream - }) - } else { - return Content.create({ - client: this.apiClient, - cortex: this, - prompt: opts.prompt, - title: opts.title, - stream: false, - statusStream: opts.statusStream - }) - } + async generateContent(opts: CortexCreateContentOptsSync): Promise; + async generateContent( + opts: CortexContentOptsStreaming, + ): Promise; + async generateContent( + opts: CortexCreateContentOptsSync | CortexContentOptsStreaming, + ) { + // note: this if statement is annoying but is necessary to appropriately narrow the return type + if (opts.stream === true) { + return Content.create({ + client: this.apiClient, + cortex: this, + prompt: opts.prompt, + title: opts.title, + stream: true, + statusStream: opts.statusStream, + }); + } else { + return Content.create({ + client: this.apiClient, + cortex: this, + prompt: opts.prompt, + title: opts.title, + stream: false, + statusStream: opts.statusStream, + }); } + } - private checkDeleted() { - if (this.deleted) { - throw new Error(`cortex: ${this.name} has already been deleted`); - } + private checkDeleted() { + if (this.deleted) { + throw new Error(`cortex: ${this.name} has already been deleted`); } + } } type CortexConfigInput = { - cortexName: string; - friendlyName: string; - public: boolean; - inheritRules: boolean; - companyName?: string; - companyInfo?: string; - rules?: string[]; - instructions: string[]; - personality?: string[]; - chatVerbosity?: string; - writeVerbosity?: string; - catalogs?: string[]; - greeting?: string; - intro?: string; - examples?: string[]; -}; \ No newline at end of file + cortexName: string; + friendlyName: string; + public: boolean; + inheritRules: boolean; + companyName?: string; + companyInfo?: string; + rules?: string[]; + instructions: string[]; + personality?: string[]; + chatVerbosity?: string; + writeVerbosity?: string; + catalogs?: string[]; + greeting?: string; + intro?: string; + examples?: string[]; +}; diff --git a/document.test.ts b/document.test.ts index b5f8328..16adffb 100644 --- a/document.test.ts +++ b/document.test.ts @@ -1,7 +1,7 @@ -import { expect, test } from 'vitest'; +import { expect, test } from "vitest"; import { CortexClient } from "./index"; import { CatalogConfig } from "./catalog"; -import { FileDocument, JSONDocument, TextDocument } from './document'; +import { FileDocument, JSONDocument, TextDocument } from "./document"; const client = new CortexClient({ accessToken: process.env.CORTEX_ACCESS_TOKEN || "", @@ -9,10 +9,8 @@ const client = new CortexClient({ apiUrl: "http://localhost:3001", }); - -test('Test upsertDocuments inline text batch', async () => { - - const catalogName = `catalog-${Math.floor(Math.random() * 10000)}` +test("Test upsertDocuments inline text batch", async () => { + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; const config: CatalogConfig = { description: "foo bar", @@ -27,15 +25,15 @@ test('Test upsertDocuments inline text batch', async () => { contentType: "markdown", content: "# some markdown", url: "https://foo.com", - imageUrl: "https://foo.com/image.jpg" + imageUrl: "https://foo.com/image.jpg", }, { documentId: "2", contentType: "markdown", content: "# some more markdown", url: "https://foo.com/2", - imageUrl: "https://foo.com/image2.jpg" - } + imageUrl: "https://foo.com/image2.jpg", + }, ]; await catalog.upsertDocuments(docs); @@ -46,9 +44,8 @@ test('Test upsertDocuments inline text batch', async () => { await catalog.delete(); }); -test('Test upsertDocuments inline JSON batch', async () => { - - const catalogName = `catalog-${Math.floor(Math.random() * 10000)}` +test("Test upsertDocuments inline JSON batch", async () => { + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; const config: CatalogConfig = { description: "foo bar", @@ -63,21 +60,21 @@ test('Test upsertDocuments inline JSON batch', async () => { contentType: "json", content: { foo: "buzz", - a: [5, 6, 7] + a: [5, 6, 7], }, url: "https://foo.com", - imageUrl: "https://foo.com/image.jpg" + imageUrl: "https://foo.com/image.jpg", }, { documentId: "2", contentType: "json", content: { foo: "bar", - a: [1, 2, 3] + a: [1, 2, 3], }, url: "https://foo.com/2", - imageUrl: "https://foo.com/image2.jpg" - } + imageUrl: "https://foo.com/image2.jpg", + }, ]; await catalog.upsertDocuments(docs); @@ -88,50 +85,52 @@ test('Test upsertDocuments inline JSON batch', async () => { await catalog.delete(); }); -test('Test upsertDocuments with files and catalog.truncate', { timeout: 20000 }, async () => { - - const catalogName = `catalog-${Math.floor(Math.random() * 10000)}` - - const config: CatalogConfig = { - description: "foo bar", - instructions: ["a", "b"], - }; - - const catalog = await client.configureCatalog(catalogName, config); - - const docs: FileDocument[] = [ - { - documentId: "1", - contentType: "file", - filePath: "./test_data/large_markdown_with_code.mdx", - url: "https://foo.com", - imageUrl: "https://foo.com/image.jpg" - }, - { - documentId: "2", - contentType: "file", - filePath: "./test_data/test_large_docx_file.docx", - url: "https://foo.com/2", - imageUrl: "https://foo.com/image2.jpg" - } - ]; - - await catalog.upsertDocuments(docs); +test( + "Test upsertDocuments with files and catalog.truncate", + { timeout: 20000 }, + async () => { + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; + + const config: CatalogConfig = { + description: "foo bar", + instructions: ["a", "b"], + }; + + const catalog = await client.configureCatalog(catalogName, config); + + const docs: FileDocument[] = [ + { + documentId: "1", + contentType: "file", + filePath: "./test_data/large_markdown_with_code.mdx", + url: "https://foo.com", + imageUrl: "https://foo.com/image.jpg", + }, + { + documentId: "2", + contentType: "file", + filePath: "./test_data/test_large_docx_file.docx", + url: "https://foo.com/2", + imageUrl: "https://foo.com/image2.jpg", + }, + ]; - let docCount = await catalog.documentCount(); - expect(docCount).toBe(2); + await catalog.upsertDocuments(docs); - await catalog.truncate(); + let docCount = await catalog.documentCount(); + expect(docCount).toBe(2); - docCount = await catalog.documentCount(); - expect(docCount).toBe(0); + await catalog.truncate(); - await catalog.delete(); -}); + docCount = await catalog.documentCount(); + expect(docCount).toBe(0); -test('Test update documents', { timeout: 10000 }, async () => { + await catalog.delete(); + }, +); - const catalogName = `catalog-${Math.floor(Math.random() * 10000)}` +test("Test update documents", { timeout: 10000 }, async () => { + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; const config: CatalogConfig = { description: "foo bar", @@ -146,15 +145,15 @@ test('Test update documents', { timeout: 10000 }, async () => { contentType: "markdown", content: "# some markdown", url: "https://foo.com", - imageUrl: "https://foo.com/image.jpg" + imageUrl: "https://foo.com/image.jpg", }, { documentId: "2", contentType: "markdown", content: "# some more markdown", url: "https://foo.com/2", - imageUrl: "https://foo.com/image2.jpg" - } + imageUrl: "https://foo.com/image2.jpg", + }, ]; await catalog.upsertDocuments(docs); @@ -176,9 +175,8 @@ test('Test update documents', { timeout: 10000 }, async () => { await catalog.delete(); }); -test('Test get and delete documents', { timeout: 10000 }, async () => { - - const catalogName = `catalog-${Math.floor(Math.random() * 10000)}` +test("Test get and delete documents", { timeout: 10000 }, async () => { + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; const config: CatalogConfig = { description: "foo bar", @@ -193,15 +191,15 @@ test('Test get and delete documents', { timeout: 10000 }, async () => { contentType: "markdown", content: "# some markdown", url: "https://foo.com", - imageUrl: "https://foo.com/image.jpg" + imageUrl: "https://foo.com/image.jpg", }, { documentId: "2", contentType: "markdown", content: "# some more markdown", url: "https://foo.com/2", - imageUrl: "https://foo.com/image2.jpg" - } + imageUrl: "https://foo.com/image2.jpg", + }, ]; await catalog.upsertDocuments(docs); @@ -225,9 +223,8 @@ test('Test get and delete documents', { timeout: 10000 }, async () => { await catalog.delete(); }); -test('Test catalog.listDocuments', { timeout: 10000 }, async () => { - - const catalogName = `catalog-${Math.floor(Math.random() * 10000)}` +test("Test catalog.listDocuments", { timeout: 10000 }, async () => { + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; const config: CatalogConfig = { description: "foo bar", @@ -236,8 +233,7 @@ test('Test catalog.listDocuments', { timeout: 10000 }, async () => { const catalog = await client.configureCatalog(catalogName, config); - const docs: JSONDocument[] = [ - ]; + const docs: JSONDocument[] = []; for (let i = 0; i < 70; i++) { docs.push({ @@ -245,11 +241,11 @@ test('Test catalog.listDocuments', { timeout: 10000 }, async () => { contentType: "json", content: { foo: "buzz", - a: [5, 6, 7] + a: [5, 6, 7], }, url: "https://foo.com", - imageUrl: "https://foo.com/image.jpg" - },) + imageUrl: "https://foo.com/image.jpg", + }); } await catalog.upsertDocuments(docs); diff --git a/document.ts b/document.ts index 2d33a48..d09bb57 100644 --- a/document.ts +++ b/document.ts @@ -1,7 +1,6 @@ import { CortexApiClient } from "./api-client.js"; import { Catalog } from "./catalog.js"; - export type TextContentType = "text" | "markdown"; export type JSONContentType = "json"; export type FileContentType = "file"; @@ -9,69 +8,91 @@ export type FileContentType = "file"; export type ContentType = FileContentType | TextContentType | JSONContentType; export type JSONDocument = { - documentId: string; - content: object; - contentType: JSONContentType; - url?: string; - imageUrl?: string; -} + documentId: string; + content: object; + contentType: JSONContentType; + url?: string; + imageUrl?: string; +}; export type TextDocument = { - documentId: string; - content: string; - contentType: TextContentType; - url?: string; - imageUrl?: string; + documentId: string; + content: string; + contentType: TextContentType; + url?: string; + imageUrl?: string; }; export type FileDocument = { - documentId: string; - contentType: FileContentType; - filePath: string; - url?: string; - imageUrl?: string; + documentId: string; + contentType: FileContentType; + filePath: string; + url?: string; + imageUrl?: string; }; export type DocumentBatch = TextDocument[] | JSONDocument[] | FileDocument[]; export type DocumentInput = { - documentId: string; - content?: string; - contentType: ContentType; - url?: string; - imageUrl?: string; + documentId: string; + content?: string; + contentType: ContentType; + url?: string; + imageUrl?: string; }; export class Document { - private constructor(readonly catalog: Catalog, private apiClient: CortexApiClient, readonly documentId: string, readonly content: string, readonly contentType: ContentType, readonly url?: string, readonly imageUrl?: string){ - - } + private constructor( + readonly catalog: Catalog, + private apiClient: CortexApiClient, + readonly documentId: string, + readonly content: string, + readonly contentType: ContentType, + readonly url?: string, + readonly imageUrl?: string, + ) {} - static async get (apiClient: CortexApiClient, catalog: Catalog, documentId: string): Promise { - encodeURIComponent - const res = await apiClient.GET(`/catalogs/${catalog.name}/documents/${encodeURIComponent(documentId)}`); - if (res.status !== 200) { - throw new Error(`Failed to get document: ${res.statusText}`); - } + static async get( + apiClient: CortexApiClient, + catalog: Catalog, + documentId: string, + ): Promise { + encodeURIComponent; + const res = await apiClient.GET( + `/catalogs/${catalog.name}/documents/${encodeURIComponent(documentId)}`, + ); + if (res.status !== 200) { + throw new Error(`Failed to get document: ${res.statusText}`); + } - const body = await res.json(); + const body = await res.json(); - return new Document(catalog, apiClient, documentId, body.content, body.contentType, body.url, body.imageUrl) - } + return new Document( + catalog, + apiClient, + documentId, + body.content, + body.contentType, + body.url, + body.imageUrl, + ); + } - async delete() { - const res = await this.apiClient.DELETE(`/catalogs/${this.catalog.name}/documents/${encodeURIComponent(this.documentId)}`); - if (res.status !== 200) { - throw new Error(`Failed to delete document: ${res.statusText}`); - } + async delete() { + const res = await this.apiClient.DELETE( + `/catalogs/${this.catalog.name}/documents/${encodeURIComponent(this.documentId)}`, + ); + if (res.status !== 200) { + throw new Error(`Failed to delete document: ${res.statusText}`); } + } } export type DocumentListItem = { - documentId: string; - contentType: ContentType; - url?: string; - imageUrl?: string - get: () => Promise; - delete: () => Promise; -} \ No newline at end of file + documentId: string; + contentType: ContentType; + url?: string; + imageUrl?: string; + get: () => Promise; + delete: () => Promise; +}; diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index cce6a40..0000000 --- a/eslint.config.js +++ /dev/null @@ -1,14 +0,0 @@ -import globals from "globals"; -import pluginJs from "@eslint/js"; -import tseslint from "typescript-eslint"; - - -export default [ - {files: ["**/*.{ts}"]}, - {languageOptions: { globals: globals.node }}, - ...tseslint.configs.recommended, - { rules: { - "@typescript-eslint/no-unused-vars": 0 - }}, -{ignores: ["**/*.js"]} -]; \ No newline at end of file diff --git a/indexers/directory-indexer.ts b/indexers/directory-indexer.ts index 2648723..3acd2a3 100644 --- a/indexers/directory-indexer.ts +++ b/indexers/directory-indexer.ts @@ -1,109 +1,125 @@ -import * as fs from 'node:fs'; +import * as fs from "node:fs"; import { Catalog } from "../catalog.js"; -import { FileDocument } from '../document.js'; +import { FileDocument } from "../document.js"; export type DirectoryIndexerOpts = { - rootDir: string; - urlBase?: string; - getUrl?: (docPathList: string[], sitePathList: string[]) => string; - getId?: (docPathList: string[], sitePathList: string[]) => string; - getImageUrl?: (docPathList: string[], sitePathList: string[]) => string; - includeFile?: (filePath: string) => boolean; - includeDirectory?: (path: string) => boolean; -} + rootDir: string; + urlBase?: string; + getUrl?: (docPathList: string[], sitePathList: string[]) => string; + getId?: (docPathList: string[], sitePathList: string[]) => string; + getImageUrl?: (docPathList: string[], sitePathList: string[]) => string; + includeFile?: (filePath: string) => boolean; + includeDirectory?: (path: string) => boolean; +}; export class DirectoryIndexer { - private parallelism = 25; - private rootDir: string; - private urlBase?: string; - private files: FileDocument[] = []; - constructor(public catalog: Catalog, opts: DirectoryIndexerOpts) { - this.rootDir = opts.rootDir; - this.urlBase = opts.urlBase; - - if (opts.includeFile) { - this.includeFile = opts.includeFile; - } - - if (opts.includeDirectory) { - this.includeDirectory = opts.includeDirectory; - } - - if (opts.getId) { - this.getId = opts.getId; - } - - if (opts.getUrl) { - this.getUrl = opts.getUrl; - } - - if (opts.getImageUrl) { - this.getImageUrl = opts.getImageUrl; - } - } - - public async index() { - const sitePathList = this.urlBase ? [this.urlBase] : []; - await this.processDirectory([this.rootDir], sitePathList); - if(this.files.length) { - await this.catalog.upsertDocuments(this.files); - this.files = []; - } + private parallelism = 25; + private rootDir: string; + private urlBase?: string; + private files: FileDocument[] = []; + constructor( + public catalog: Catalog, + opts: DirectoryIndexerOpts, + ) { + this.rootDir = opts.rootDir; + this.urlBase = opts.urlBase; + + if (opts.includeFile) { + this.includeFile = opts.includeFile; } - private async processDirectory(docPathList: string[], sitePathList: string[]) { - const fileList = fs.readdirSync(docPathList.join("/")); - - for (const f of fileList) { - const path = [...docPathList, f].join("/") - const stat = fs.lstatSync(path) - if (stat.isDirectory() && this.includeDirectory(f)) { - await this.processDirectory([...docPathList, f], [...sitePathList, f]) - } - if (stat.isFile() && this.includeFile(f)) { - await this.processDocument([...docPathList, f], [...sitePathList, f]) - } - } + if (opts.includeDirectory) { + this.includeDirectory = opts.includeDirectory; } - private async processDocument(docPathList: string[], sitePathList: string[]) { - const id = this.getId([...docPathList], [...sitePathList]); - const url = this.getUrl([...docPathList], [...sitePathList]); - const imageUrl = this.getImageUrl([...docPathList], [...sitePathList]); - const docPath = docPathList.join("/") - - this.files.push({ - documentId: id, - contentType: "file", - filePath: docPath, - imageUrl, - url, - }) - - - if (this.files.length >= this.parallelism) { - await this.catalog.upsertDocuments(this.files); - this.files = []; - } + if (opts.getId) { + this.getId = opts.getId; } - private getUrl(docPathList: string[], sitePathList: string[]): string | undefined { - return undefined; + if (opts.getUrl) { + this.getUrl = opts.getUrl; } - private getId(docPathList: string[], sitePathList: string[]): string { - return sitePathList.join("/"); + if (opts.getImageUrl) { + this.getImageUrl = opts.getImageUrl; } - - private getImageUrl(docPathList: string[], sitePathList: string[]): string | undefined { - return undefined + } + + public async index() { + const sitePathList = this.urlBase ? [this.urlBase] : []; + await this.processDirectory([this.rootDir], sitePathList); + if (this.files.length) { + await this.catalog.upsertDocuments(this.files); + this.files = []; } - - private includeFile(filename: string): boolean { - return filename.endsWith(".md") || filename.endsWith(".mdx") || filename.endsWith(".txt") || filename.endsWith(".docx"); + } + + private async processDirectory( + docPathList: string[], + sitePathList: string[], + ) { + const fileList = fs.readdirSync(docPathList.join("/")); + + for (const f of fileList) { + const path = [...docPathList, f].join("/"); + const stat = fs.lstatSync(path); + if (stat.isDirectory() && this.includeDirectory(f)) { + await this.processDirectory([...docPathList, f], [...sitePathList, f]); + } + if (stat.isFile() && this.includeFile(f)) { + await this.processDocument([...docPathList, f], [...sitePathList, f]); + } } - - private includeDirectory(directoryName: string): boolean { - return directoryName !== "."; + } + + private async processDocument(docPathList: string[], sitePathList: string[]) { + const id = this.getId([...docPathList], [...sitePathList]); + const url = this.getUrl([...docPathList], [...sitePathList]); + const imageUrl = this.getImageUrl([...docPathList], [...sitePathList]); + const docPath = docPathList.join("/"); + + this.files.push({ + documentId: id, + contentType: "file", + filePath: docPath, + imageUrl, + url, + }); + + if (this.files.length >= this.parallelism) { + await this.catalog.upsertDocuments(this.files); + this.files = []; } + } + + private getUrl( + _docPathList: string[], + _sitePathList: string[], + ): string | undefined { + return undefined; + } + + private getId(_docPathList: string[], sitePathList: string[]): string { + return sitePathList.join("/"); + } + + private getImageUrl( + _docPathList: string[], + _sitePathList: string[], + ): string | undefined { + return undefined; + } + + private includeFile(filename: string): boolean { + return ( + filename.endsWith(".md") || + filename.endsWith(".mdx") || + filename.endsWith(".txt") || + filename.endsWith(".docx") + ); + } + + private includeDirectory(directoryName: string): boolean { + return directoryName !== "."; + } } diff --git a/indexers/indexers.test.ts b/indexers/indexers.test.ts index 2150444..e8e4cbb 100644 --- a/indexers/indexers.test.ts +++ b/indexers/indexers.test.ts @@ -1,7 +1,7 @@ -import { expect, test, beforeEach, afterEach } from 'vitest' +import { expect, test, beforeEach, afterEach } from "vitest"; import { CortexClient } from "../index"; import { Catalog, CatalogConfig } from "../catalog"; -import { JSONDocument } from '../document'; +import { JSONDocument } from "../document"; const client = new CortexClient({ accessToken: process.env.CORTEX_ACCESS_TOKEN || "", @@ -16,7 +16,7 @@ beforeEach(async () => { description: "foo bar", instructions: ["a", "b"], }; - + const catalogName = `catalog-${Math.floor(Math.random() * 10000)}`; catalog = await client.configureCatalog(catalogName, config); }); @@ -27,58 +27,70 @@ afterEach(async () => { } }); -test('Test catalog.jsonIndexer with custom opts', { timeout: 10000 }, async () => { - const docs: JSONDocument[] = []; - - for (let i = 0; i < 76; i++) { - docs.push({ - documentId: `${i}`, - contentType: "json", - content: { - foo: "buzz", - a: [5, 6, 7] - }, - url: "https://foo.com", - imageUrl: "https://foo.com/image.jpg" +test( + "Test catalog.jsonIndexer with custom opts", + { timeout: 10000 }, + async () => { + const docs: JSONDocument[] = []; + + for (let i = 0; i < 76; i++) { + docs.push({ + documentId: `${i}`, + contentType: "json", + content: { + foo: "buzz", + a: [5, 6, 7], + }, + url: "https://foo.com", + imageUrl: "https://foo.com/image.jpg", + }); + } + + const indexer = catalog.jsonIndexer(docs, { + getId: (doc) => doc.documentId, + getUrl: (doc) => doc.url, + getImageUrl: (doc) => doc.imageUrl, }); - } - - const indexer = catalog.jsonIndexer(docs, { getId: doc => doc.documentId, getUrl: doc => doc.url, getImageUrl: doc => doc.imageUrl }); - - await indexer.index(); - - const docCount = await catalog.documentCount(); - expect(docCount).toBe(76); -}); - -test('Test catalog.jsonIndexer with default opts', { timeout: 10000 }, async () => { - const docs: JSONDocument[] = []; - - for (let i = 0; i < 76; i++) { - docs.push({ - documentId: `${i}`, - contentType: "json", - content: { - foo: "buzz", - a: [5, 6, 7] - }, - url: "https://foo.com", - imageUrl: "https://foo.com/image.jpg" - }); - } - - const indexer = catalog.jsonIndexer(docs); - - await indexer.index(); - - const docCount = await catalog.documentCount(); - expect(docCount).toBe(76); -}); -test('Test catalog.directoryIndexer', { timeout: 10000 }, async () => { + await indexer.index(); + + const docCount = await catalog.documentCount(); + expect(docCount).toBe(76); + }, +); + +test( + "Test catalog.jsonIndexer with default opts", + { timeout: 10000 }, + async () => { + const docs: JSONDocument[] = []; + + for (let i = 0; i < 76; i++) { + docs.push({ + documentId: `${i}`, + contentType: "json", + content: { + foo: "buzz", + a: [5, 6, 7], + }, + url: "https://foo.com", + imageUrl: "https://foo.com/image.jpg", + }); + } + + const indexer = catalog.jsonIndexer(docs); + + await indexer.index(); + + const docCount = await catalog.documentCount(); + expect(docCount).toBe(76); + }, +); + +test("Test catalog.directoryIndexer", { timeout: 10000 }, async () => { const indexer = catalog.directoryIndexer({ rootDir: "./test_data", - }) + }); await indexer.index(); @@ -86,32 +98,42 @@ test('Test catalog.directoryIndexer', { timeout: 10000 }, async () => { expect(docCount).toBe(2); }); -test('Test catalog.tsvIndexer with default opts', { timeout: 10000 }, async () => { - const indexer = catalog.tsvIndexer("./test_data/test.tsv"); - - await indexer.index(); - - const docCount = await catalog.documentCount(); - expect(docCount).toBe(2); -}); +test( + "Test catalog.tsvIndexer with default opts", + { timeout: 10000 }, + async () => { + const indexer = catalog.tsvIndexer("./test_data/test.tsv"); + + await indexer.index(); + + const docCount = await catalog.documentCount(); + expect(docCount).toBe(2); + }, +); + +test( + "Test catalog.tsvIndexer with custom opts", + { timeout: 10000 }, + async () => { + const indexer = catalog.tsvIndexer("./test_data/test.tsv", { + getId: (doc) => doc.id, + }); -test('Test catalog.tsvIndexer with custom opts', { timeout: 10000 }, async () => { - const indexer = catalog.tsvIndexer("./test_data/test.tsv", { getId: doc => doc.id }); + await indexer.index(); - await indexer.index(); + const docCount = await catalog.documentCount(); + expect(docCount).toBe(2); + }, +); - const docCount = await catalog.documentCount(); - expect(docCount).toBe(2); -}); - -test('Test catalog.shopifyIndexer', { timeout: 10000 }, async () => { +test("Test catalog.shopifyIndexer", { timeout: 10000 }, async () => { const indexer = catalog.shopifyIndexer({ shopifyBaseUrl: "https://redsflyfishing.com", maxItems: 5, - }) + }); await indexer.index(); const docCount = await catalog.documentCount(); expect(docCount).toBe(5); -}); \ No newline at end of file +}); diff --git a/indexers/json-indexer.ts b/indexers/json-indexer.ts index 14164ea..0f22fc3 100644 --- a/indexers/json-indexer.ts +++ b/indexers/json-indexer.ts @@ -1,79 +1,96 @@ -import { Catalog } from '../catalog.js'; +import { Catalog } from "../catalog.js"; import { JSONDocument } from "../document.js"; // intentionally operates on any type /* eslint-disable @typescript-eslint/no-explicit-any */ export type JSONIndexerOpts = { - getId?: (document: any) => string; - getUrl?: (document: any) => string | undefined; - getImageUrl?: (document: any) => string | undefined; -} + getId?: (document: any) => string; + getUrl?: (document: any) => string | undefined; + getImageUrl?: (document: any) => string | undefined; +}; export class JSONIndexer { - private readonly parallelism = 50; - private readonly getId: (document: any) => string; - private readonly getImageUrl: (document: any) => string | undefined; - private readonly getUrl: (document: any) => string | undefined; - private batch: JSONDocument[] = []; - - constructor(private catalog: Catalog, private documents: any[], opts?: JSONIndexerOpts) { - this.getId = opts?.getId ?? JSONIndexer.defaultGetId; - this.getUrl = opts?.getUrl ?? JSONIndexer.defaultGetUrl; - this.getImageUrl = opts?.getImageUrl ?? JSONIndexer.defaultGetImageUrl; - } + private readonly parallelism = 50; + private readonly getId: (document: any) => string; + private readonly getImageUrl: (document: any) => string | undefined; + private readonly getUrl: (document: any) => string | undefined; + private batch: JSONDocument[] = []; - public static defaultGetId(document: any): string { - const id = JSONIndexer.findFirstMatchingProperty(document, "id", "Id", "ID", "documentId", "documentID", "DocumentId", "DocumentID"); - if (!id) { - throw new Error("All documents must contain an 'id' or 'documentId' field, or you must provide opts.getId when using JSONIndexer."); - } + constructor( + private catalog: Catalog, + private documents: any[], + opts?: JSONIndexerOpts, + ) { + this.getId = opts?.getId ?? JSONIndexer.defaultGetId; + this.getUrl = opts?.getUrl ?? JSONIndexer.defaultGetUrl; + this.getImageUrl = opts?.getImageUrl ?? JSONIndexer.defaultGetImageUrl; + } - return id; + public static defaultGetId(document: any): string { + const id = JSONIndexer.findFirstMatchingProperty( + document, + "id", + "Id", + "ID", + "documentId", + "documentID", + "DocumentId", + "DocumentID", + ); + if (!id) { + throw new Error( + "All documents must contain an 'id' or 'documentId' field, or you must provide opts.getId when using JSONIndexer.", + ); } - public static defaultGetUrl(document: any): string | undefined { - return JSONIndexer.findFirstMatchingProperty(document, "url"); - } + return id; + } - public static defaultGetImageUrl(document: any): string | undefined { - return JSONIndexer.findFirstMatchingProperty(document, "imageUrl"); - } + public static defaultGetUrl(document: any): string | undefined { + return JSONIndexer.findFirstMatchingProperty(document, "url"); + } - private static findFirstMatchingProperty(document: any, ...propertyNames: string[]) : string | undefined { - for (const prop of propertyNames) { - if (prop in document) { - return document[prop]; - } - } + public static defaultGetImageUrl(document: any): string | undefined { + return JSONIndexer.findFirstMatchingProperty(document, "imageUrl"); + } - return undefined; + private static findFirstMatchingProperty( + document: any, + ...propertyNames: string[] + ): string | undefined { + for (const prop of propertyNames) { + if (prop in document) { + return document[prop]; + } } - public async index() { - await this.indexItems(); - } + return undefined; + } - private async indexItems(): Promise { + public async index() { + await this.indexItems(); + } - for (const document of this.documents) { - if (this.batch.length > this.parallelism) { - await this.catalog.upsertDocuments(this.batch); - this.batch = []; - } + private async indexItems(): Promise { + for (const document of this.documents) { + if (this.batch.length > this.parallelism) { + await this.catalog.upsertDocuments(this.batch); + this.batch = []; + } - this.batch.push({ - documentId: this.getId(document), - imageUrl: this.getImageUrl(document), - url: this.getUrl(document), - content: document, - contentType: "json", - }) - } + this.batch.push({ + documentId: this.getId(document), + imageUrl: this.getImageUrl(document), + url: this.getUrl(document), + content: document, + contentType: "json", + }); + } - if (this.batch.length) { - await this.catalog.upsertDocuments(this.batch); - this.batch = []; - } + if (this.batch.length) { + await this.catalog.upsertDocuments(this.batch); + this.batch = []; } + } } diff --git a/indexers/shopify-indexer.ts b/indexers/shopify-indexer.ts index 480eafe..1a52768 100644 --- a/indexers/shopify-indexer.ts +++ b/indexers/shopify-indexer.ts @@ -1,110 +1,118 @@ -import { Catalog } from '../catalog.js'; +import { Catalog } from "../catalog.js"; type Product = { - id: string; - title: string; - description: string; - productType: string; - imageUrl: string | undefined; - price: string; - vendor: string; - tags: string | undefined; - url: string; + id: string; + title: string; + description: string; + productType: string; + imageUrl: string | undefined; + price: string; + vendor: string; + tags: string | undefined; + url: string; }; export type ShopifyIndexerOpts = { - shopifyBaseUrl: string, - maxItems?: number; -} + shopifyBaseUrl: string; + maxItems?: number; +}; export class ShopifyIndexer { - private parallelism = 25; - private documents: Product[] = []; - private deletes: Promise[] = []; - private idsToDelete: string[] = []; - private page = 1; - constructor(private catalog: Catalog, private opts: ShopifyIndexerOpts) { - } + private parallelism = 25; + private documents: Product[] = []; + private deletes: Promise[] = []; + private idsToDelete: string[] = []; + private page = 1; + constructor( + private catalog: Catalog, + private opts: ShopifyIndexerOpts, + ) {} - private stripHTML(input: string) { - return input.replace(/<\/?[^>]+(>|$)/g, ""); - } - - public async index() { - let moreItems = true; - while (moreItems) { - const req = await fetch(`${this.opts.shopifyBaseUrl}/products.json?page=${this.page}`, { - method: "GET", - }) - - const res = await req.json(); + private stripHTML(input: string) { + return input.replace(/<\/?[^>]+(>|$)/g, ""); + } - if (!res.products || !res.products.length) { - moreItems = false; - continue; - } - this.page = this.page + 1; + public async index() { + let moreItems = true; + while (moreItems) { + const req = await fetch( + `${this.opts.shopifyBaseUrl}/products.json?page=${this.page}`, + { + method: "GET", + }, + ); - for (const item of res.products) { - let available = false; - for (const v of item.variants) { - available = available || v.available - } - if (!available) { - this.idsToDelete.push(item.id) - continue; - } - let imageUrl = undefined; - if (item.images && item.images[0]) { - if (item.images[0].src) { - imageUrl = item.images[0].src; - } else if (item.variants && item.variants[0] && item.variants[0].featured_image) { - imageUrl = item.variants[0].featured_image.src - } - } + const res = await req.json(); - if(this.opts.maxItems && this.documents.length >= this.opts.maxItems) { - moreItems = false; - break; - } + if (!res.products || !res.products.length) { + moreItems = false; + continue; + } + this.page = this.page + 1; - this.documents.push({ - id: item.id, - title: item.title, - description: this.stripHTML(item.body_html), - productType: item.product_type, - imageUrl: imageUrl, - price: item.variants[0].price, - vendor: item.vendor, - tags: item.tags ? JSON.stringify(item.tags) : undefined, - url: `${this.opts.shopifyBaseUrl}/products/${item.handle}` - }) - } + for (const item of res.products) { + let available = false; + for (const v of item.variants) { + available = available || v.available; + } + if (!available) { + this.idsToDelete.push(item.id); + continue; + } + let imageUrl = undefined; + if (item.images && item.images[0]) { + if (item.images[0].src) { + imageUrl = item.images[0].src; + } else if ( + item.variants && + item.variants[0] && + item.variants[0].featured_image + ) { + imageUrl = item.variants[0].featured_image.src; + } } - await this.indexProducts(); - await this.deleteProducts(); - } + if (this.opts.maxItems && this.documents.length >= this.opts.maxItems) { + moreItems = false; + break; + } - private async indexProducts(): Promise { - const indexer = this.catalog.jsonIndexer(this.documents); - await indexer.index(); + this.documents.push({ + id: item.id, + title: item.title, + description: this.stripHTML(item.body_html), + productType: item.product_type, + imageUrl: imageUrl, + price: item.variants[0].price, + vendor: item.vendor, + tags: item.tags ? JSON.stringify(item.tags) : undefined, + url: `${this.opts.shopifyBaseUrl}/products/${item.handle}`, + }); + } } - private async deleteProducts(): Promise { - for (const id of this.idsToDelete) { - if (this.deletes.length >= this.parallelism) { - await Promise.all(this.deletes); - this.deletes = []; - } + await this.indexProducts(); + await this.deleteProducts(); + } - const res = this.catalog.deleteDocument(id).catch(() => {}); - this.deletes.push(res); - } + private async indexProducts(): Promise { + const indexer = this.catalog.jsonIndexer(this.documents); + await indexer.index(); + } + private async deleteProducts(): Promise { + for (const id of this.idsToDelete) { + if (this.deletes.length >= this.parallelism) { await Promise.all(this.deletes); this.deletes = []; - return; + } + + const res = this.catalog.deleteDocument(id).catch(() => {}); + this.deletes.push(res); } + await Promise.all(this.deletes); + this.deletes = []; + return; + } } diff --git a/indexers/tsv-indexer.ts b/indexers/tsv-indexer.ts index 18d6d7b..0ee9b22 100644 --- a/indexers/tsv-indexer.ts +++ b/indexers/tsv-indexer.ts @@ -1,68 +1,71 @@ -import * as fs from 'node:fs'; -import { Catalog } from '../catalog.js'; -import { JSONIndexer } from './json-indexer.js'; +import * as fs from "node:fs"; +import { Catalog } from "../catalog.js"; +import { JSONIndexer } from "./json-indexer.js"; // intentionally operates on any type /* eslint-disable @typescript-eslint/no-explicit-any */ - export type TSVIndexerOpts = { - getId?: (item: any) => string; - getUrl?: (item: any) => string; - getImageUrl?: (item: any) => string; - fieldMapping?: { [key: string]: string }; -} + getId?: (item: any) => string; + getUrl?: (item: any) => string; + getImageUrl?: (item: any) => string; + fieldMapping?: { [key: string]: string }; +}; export class TSVIndexer { - private readonly getId: (document: any) => string; - private readonly getImageUrl: (document: any) => string | undefined; - private readonly getUrl: (document: any) => string | undefined; - private documents: any[] = []; - private fieldMapping: undefined | { [key: string]: string }; - - constructor(public catalog: Catalog, private file: string, opts?: TSVIndexerOpts) { - this.getId = opts?.getId ?? JSONIndexer.defaultGetId; - this.getUrl = opts?.getUrl ?? JSONIndexer.defaultGetUrl; - this.getImageUrl = opts?.getImageUrl ?? JSONIndexer.defaultGetImageUrl; + private readonly getId: (document: any) => string; + private readonly getImageUrl: (document: any) => string | undefined; + private readonly getUrl: (document: any) => string | undefined; + private documents: any[] = []; + private fieldMapping: undefined | { [key: string]: string }; - if(opts?.fieldMapping) { - this.fieldMapping = opts?.fieldMapping; - } - } + constructor( + public catalog: Catalog, + private file: string, + opts?: TSVIndexerOpts, + ) { + this.getId = opts?.getId ?? JSONIndexer.defaultGetId; + this.getUrl = opts?.getUrl ?? JSONIndexer.defaultGetUrl; + this.getImageUrl = opts?.getImageUrl ?? JSONIndexer.defaultGetImageUrl; - public async index() { - await this.indexItems(); + if (opts?.fieldMapping) { + this.fieldMapping = opts?.fieldMapping; } + } - private async indexItems(): Promise { - const content = fs.readFileSync(this.file).toString(); - const rows = content.split("\n"); - const header = rows[0].split("\t"); - for(let i = 1; i < rows.length; i++) { - const row = rows[i].split("\t"); - const document: { [key: string]: string } = {}; - for(let j = 0; j < header.length; j++) { - if(this.fieldMapping) { - if(this.fieldMapping[header[j]]) { - document[this.fieldMapping[header[j]]] = row[j]; - } - } else { - document[header[j]] = row[j]; - } - } + public async index() { + await this.indexItems(); + } - // Note that this should generate a document whose id, imageUrl, url properties can be picked up by JSON indexer using the defaßult options - this.documents.push({ - documentId: this.getId(document), - content: document, - contentType: "json", - imageUrl: this.getImageUrl(document), - url: this.getUrl(document), - }) + private async indexItems(): Promise { + const content = fs.readFileSync(this.file).toString(); + const rows = content.split("\n"); + const header = rows[0].split("\t"); + for (let i = 1; i < rows.length; i++) { + const row = rows[i].split("\t"); + const document: { [key: string]: string } = {}; + for (let j = 0; j < header.length; j++) { + if (this.fieldMapping) { + if (this.fieldMapping[header[j]]) { + document[this.fieldMapping[header[j]]] = row[j]; + } + } else { + document[header[j]] = row[j]; } + } - const jsonIndexer = this.catalog.jsonIndexer(this.documents); - - await jsonIndexer.index(); + // Note that this should generate a document whose id, imageUrl, url properties can be picked up by JSON indexer using the defaßult options + this.documents.push({ + documentId: this.getId(document), + content: document, + contentType: "json", + imageUrl: this.getImageUrl(document), + url: this.getUrl(document), + }); } + + const jsonIndexer = this.catalog.jsonIndexer(this.documents); + + await jsonIndexer.index(); + } } diff --git a/org.ts b/org.ts index 8e819fb..648060a 100644 --- a/org.ts +++ b/org.ts @@ -1,65 +1,67 @@ import { CortexApiClient } from "./api-client.js"; export type OrgConfigOpts = { - companyName: string; - companyInfo: string; - personality?: string[]; - rules?: string[]; + companyName: string; + companyInfo: string; + personality?: string[]; + rules?: string[]; }; - export class OrgConfig { - /** - * The default name that all your company should be referred to in all writen content. - */ - readonly companyName: string; - /** - * A description of your company, industry, and products and services provided. - */ - readonly companyInfo: string; - /** - * Voice and tone descriptors applied to all written content. i.e. ["concise", "professional", "bubbly", ... ] - */ - readonly personality?: string[]; - /** - * A list of dos and don'ts that all written content should follow. i.e. ["do not speak disparigingly about X"] - */ - readonly rules?: string[]; - private constructor(input: OrgConfigOpts) { - this.companyName = input.companyName; - this.companyInfo = input.companyInfo; - this.personality = input.personality; - this.rules = input.rules; - } + /** + * The default name that all your company should be referred to in all writen content. + */ + readonly companyName: string; + /** + * A description of your company, industry, and products and services provided. + */ + readonly companyInfo: string; + /** + * Voice and tone descriptors applied to all written content. i.e. ["concise", "professional", "bubbly", ... ] + */ + readonly personality?: string[]; + /** + * A list of dos and don'ts that all written content should follow. i.e. ["do not speak disparigingly about X"] + */ + readonly rules?: string[]; + private constructor(input: OrgConfigOpts) { + this.companyName = input.companyName; + this.companyInfo = input.companyInfo; + this.personality = input.personality; + this.rules = input.rules; + } - static async get(client: CortexApiClient): Promise { - const res = await client.GET("/org-config"); - if (res.status !== 200) { - throw new Error(`Failed to configure cortex: ${res.statusText}`); - } - const body = await res.json(); - const input: OrgConfigOpts = { - companyName: body.companyName, - companyInfo: body.companyInfo, - personality: body.personality, - rules: body.rules, - } - return new OrgConfig(input); + static async get(client: CortexApiClient): Promise { + const res = await client.GET("/org-config"); + if (res.status !== 200) { + throw new Error(`Failed to configure cortex: ${res.statusText}`); } + const body = await res.json(); + const input: OrgConfigOpts = { + companyName: body.companyName, + companyInfo: body.companyInfo, + personality: body.personality, + rules: body.rules, + }; + return new OrgConfig(input); + } - static async configure(client: CortexApiClient, config: OrgConfigOpts): Promise { - const getRes = await client.GET("/org-config"); - let res: Response; - if (getRes.status !== 200) { - res = await client.POST("/org-config", config); - } else { - res = await client.PUT("/org-config", config); - } - - if (res.status !== 200) { - throw new Error(`Failed to configure org: ${res.statusText}`); - } + static async configure( + client: CortexApiClient, + config: OrgConfigOpts, + ): Promise { + const getRes = await client.GET("/org-config"); + let res: Response; + if (getRes.status !== 200) { + res = await client.POST("/org-config", config); + } else { + res = await client.PUT("/org-config", config); + } - return new OrgConfig(config); + if (res.status !== 200) { + throw new Error(`Failed to configure org: ${res.statusText}`); } -} \ No newline at end of file + + return new OrgConfig(config); + } +} diff --git a/package-lock.json b/package-lock.json index 7aa5ad9..bb876c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,2797 +1,2827 @@ { - "name": "cortex-sdk", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "cortex-sdk", - "version": "0.0.1", - "license": "ISC", - "dependencies": { - "form-data": "^4.0.0" - }, - "devDependencies": { - "@eslint/js": "^8.57.0", - "@types/express": "^4.17.21", - "@types/node": "^20.14.6", - "eslint": "^8.57.0", - "globals": "^15.6.0", - "ts-node": "^10.9.2", - "typescript": "^5.4.5", - "typescript-eslint": "^7.13.1", - "vitest": "^1.6.0" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", - "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.1.tgz", - "integrity": "sha512-ej0phymbFLoCB26dbbq5PGScsf2JAJ4IJHjG10LalgUV36XKTmA4GdA+PVllKvRk0sEKt64X8975qFnkSi0hqA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.6.tgz", - "integrity": "sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", - "dev": true, - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", - "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", - "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", - "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", - "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.13.1", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/@vitest/expect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", - "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", - "dev": true, - "dependencies": { - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", - "chai": "^4.3.10" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", - "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", - "dev": true, - "dependencies": { - "@vitest/utils": "1.6.0", - "p-limit": "^5.0.0", - "pathe": "^1.1.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", - "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", - "dev": true, - "dependencies": { - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", - "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", - "dev": true, - "dependencies": { - "tinyspy": "^2.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", - "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", - "dev": true, - "dependencies": { - "diff-sequences": "^29.6.3", - "estree-walker": "^3.0.3", - "loupe": "^2.3.7", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/acorn": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", - "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/confbox": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", - "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", - "dev": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "15.6.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.6.0.tgz", - "integrity": "sha512-UzcJi88Hw//CurUIRa9Jxb0vgOCcuD/MNjwmXp633cyaRKkCWACkoqHCtfZv43b1kqXGg/fpOa8bwgacCeXsVg==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-tokens": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", - "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/local-pkg": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", - "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", - "dev": true, - "dependencies": { - "mlly": "^1.4.2", - "pkg-types": "^1.0.3" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mlly": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.0.tgz", - "integrity": "sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==", - "dev": true, - "dependencies": { - "acorn": "^8.11.3", - "pathe": "^1.1.2", - "pkg-types": "^1.1.0", - "ufo": "^1.5.3" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", - "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-types": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.1.tgz", - "integrity": "sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==", - "dev": true, - "dependencies": { - "confbox": "^0.1.7", - "mlly": "^1.7.0", - "pathe": "^1.1.2" - } - }, - "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", - "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.18.0", - "@rollup/rollup-android-arm64": "4.18.0", - "@rollup/rollup-darwin-arm64": "4.18.0", - "@rollup/rollup-darwin-x64": "4.18.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", - "@rollup/rollup-linux-arm-musleabihf": "4.18.0", - "@rollup/rollup-linux-arm64-gnu": "4.18.0", - "@rollup/rollup-linux-arm64-musl": "4.18.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", - "@rollup/rollup-linux-riscv64-gnu": "4.18.0", - "@rollup/rollup-linux-s390x-gnu": "4.18.0", - "@rollup/rollup-linux-x64-gnu": "4.18.0", - "@rollup/rollup-linux-x64-musl": "4.18.0", - "@rollup/rollup-win32-arm64-msvc": "4.18.0", - "@rollup/rollup-win32-ia32-msvc": "4.18.0", - "@rollup/rollup-win32-x64-msvc": "4.18.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true - }, - "node_modules/std-env": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", - "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", - "dev": true - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz", - "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", - "dev": true, - "dependencies": { - "js-tokens": "^9.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tinybench": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", - "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", - "dev": true - }, - "node_modules/tinypool": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", - "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "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" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.13.1.tgz", - "integrity": "sha512-pvLEuRs8iS9s3Cnp/Wt//hpK8nKc8hVa3cLljHqzaJJQYP8oys8GUyIFqtlev+2lT/fqMPcyQko+HJ6iYK3nFA==", - "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "7.13.1", - "@typescript-eslint/parser": "7.13.1", - "@typescript-eslint/utils": "7.13.1" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz", - "integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/type-utils": "7.13.1", - "@typescript-eslint/utils": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz", - "integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "7.13.1", - "@typescript-eslint/utils": "7.13.1", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz", - "integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/typescript-estree": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", - "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/typescript-estree": "7.13.1" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/ufo": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", - "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", - "dev": true - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/vite": { - "version": "5.2.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", - "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==", - "dev": true, - "dependencies": { - "esbuild": "^0.20.1", - "postcss": "^8.4.38", - "rollup": "^4.13.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite-node": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", - "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", - "dev": true, - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vitest": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", - "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", - "dev": true, - "dependencies": { - "@vitest/expect": "1.6.0", - "@vitest/runner": "1.6.0", - "@vitest/snapshot": "1.6.0", - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", - "acorn-walk": "^8.3.2", - "chai": "^4.3.10", - "debug": "^4.3.4", - "execa": "^8.0.1", - "local-pkg": "^0.5.0", - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "tinybench": "^2.5.1", - "tinypool": "^0.8.3", - "vite": "^5.0.0", - "vite-node": "1.6.0", - "why-is-node-running": "^2.2.2" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.6.0", - "@vitest/ui": "1.6.0", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", - "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", - "dev": true, - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "name": "cortex-sdk", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cortex-sdk", + "version": "0.0.1", + "license": "ISC", + "dependencies": { + "form-data": "^4.0.0" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "@types/node": "^20.14.6", + "@typescript-eslint/eslint-plugin": "^7.13.1", + "@typescript-eslint/parser": "^7.13.1", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "globals": "^15.6.0", + "prettier": "3.3.2", + "ts-node": "^10.9.2", + "typescript": "^5.4.5", + "typescript-eslint": "^7.13.1", + "vitest": "^1.6.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", + "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.1.tgz", + "integrity": "sha512-ej0phymbFLoCB26dbbq5PGScsf2JAJ4IJHjG10LalgUV36XKTmA4GdA+PVllKvRk0sEKt64X8975qFnkSi0hqA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.6.tgz", + "integrity": "sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz", + "integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/type-utils": "7.13.1", + "@typescript-eslint/utils": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz", + "integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", + "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz", + "integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.13.1", + "@typescript-eslint/utils": "7.13.1", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", + "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", + "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", + "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", + "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.13.1", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitest/expect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", + "dev": true, + "dependencies": { + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", + "dev": true, + "dependencies": { + "@vitest/utils": "1.6.0", + "p-limit": "^5.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", + "dev": true, + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/confbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.6.0.tgz", + "integrity": "sha512-UzcJi88Hw//CurUIRa9Jxb0vgOCcuD/MNjwmXp633cyaRKkCWACkoqHCtfZv43b1kqXGg/fpOa8bwgacCeXsVg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", + "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "dev": true, + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mlly": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.0.tgz", + "integrity": "sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.1.0", + "ufo": "^1.5.3" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.1.tgz", + "integrity": "sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==", + "dev": true, + "dependencies": { + "confbox": "^0.1.7", + "mlly": "^1.7.0", + "pathe": "^1.1.2" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.18.0", + "@rollup/rollup-android-arm64": "4.18.0", + "@rollup/rollup-darwin-arm64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", + "@rollup/rollup-linux-arm-musleabihf": "4.18.0", + "@rollup/rollup-linux-arm64-gnu": "4.18.0", + "@rollup/rollup-linux-arm64-musl": "4.18.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", + "@rollup/rollup-linux-riscv64-gnu": "4.18.0", + "@rollup/rollup-linux-s390x-gnu": "4.18.0", + "@rollup/rollup-linux-x64-gnu": "4.18.0", + "@rollup/rollup-linux-x64-musl": "4.18.0", + "@rollup/rollup-win32-arm64-msvc": "4.18.0", + "@rollup/rollup-win32-ia32-msvc": "4.18.0", + "@rollup/rollup-win32-x64-msvc": "4.18.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "dev": true + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz", + "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", + "dev": true, + "dependencies": { + "js-tokens": "^9.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tinybench": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", + "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", + "dev": true + }, + "node_modules/tinypool": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", + "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "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" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.13.1.tgz", + "integrity": "sha512-pvLEuRs8iS9s3Cnp/Wt//hpK8nKc8hVa3cLljHqzaJJQYP8oys8GUyIFqtlev+2lT/fqMPcyQko+HJ6iYK3nFA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "7.13.1", + "@typescript-eslint/parser": "7.13.1", + "@typescript-eslint/utils": "7.13.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/ufo": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", + "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", + "dev": true + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/vite": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", + "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==", + "dev": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", + "dev": true, + "dependencies": { + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", + "acorn-walk": "^8.3.2", + "chai": "^4.3.10", + "debug": "^4.3.4", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.3", + "vite": "^5.0.0", + "vite-node": "1.6.0", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } + } } diff --git a/package.json b/package.json index 5cba9bc..a93ff3f 100644 --- a/package.json +++ b/package.json @@ -1,32 +1,36 @@ { - "devDependencies": { - "@eslint/js": "^8.57.0", - "@types/express": "^4.17.21", - "@types/node": "^20.14.6", - "eslint": "^8.57.0", - "globals": "^15.6.0", - "ts-node": "^10.9.2", - "typescript": "^5.4.5", - "typescript-eslint": "^7.13.1", - "vitest": "^1.6.0" - }, - "name": "cortex-sdk", - "version": "0.0.1", - "type": "module", - "main": "index.js", - "scripts": { - "build": "tsc", - "lint": "eslint", - "dev": "node --watch -r ts-node/register index.ts", - "run": "npm run build && node index.js", - "test": "pulumi env run npm-test vitest .ts", - "indexer-test": "pulumi env run npm-test vitest indexers.test.ts" - }, - "keywords": [], - "author": "", - "license": "ISC", - "description": "", - "dependencies": { - "form-data": "^4.0.0" - } + "devDependencies": { + "@types/express": "^4.17.21", + "@types/node": "^20.14.6", + "@typescript-eslint/eslint-plugin": "^7.13.1", + "@typescript-eslint/parser": "^7.13.1", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "globals": "^15.6.0", + "prettier": "3.3.2", + "ts-node": "^10.9.2", + "typescript": "^5.4.5", + "typescript-eslint": "^7.13.1", + "vitest": "^1.6.0" + }, + "name": "cortex-sdk", + "version": "0.0.1", + "type": "module", + "main": "index.js", + "scripts": { + "build": "tsc", + "lint": "prettier --list-different . && eslint . --ext .ts || exit 1", + "lint-fix": "prettier --write . && eslint . --ext .ts --fix", + "dev": "node --watch -r ts-node/register index.ts", + "run": "npm run build && node index.js", + "test": "pulumi env run npm-test vitest .ts", + "indexer-test": "pulumi env run npm-test vitest indexers.test.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "form-data": "^4.0.0" + } } diff --git a/test_data/large_markdown_with_code.mdx b/test_data/large_markdown_with_code.mdx index 4d3c35c..608a48b 100644 --- a/test_data/large_markdown_with_code.mdx +++ b/test_data/large_markdown_with_code.mdx @@ -18,19 +18,19 @@ To build a VM machine from this repo's source, see the [instructions](docs/creat ## Available Images -| Image | YAML Label | Included Software | Rollout Status of Latest Image Release | -| --------------------|---------------------|--------------------|--------------------| -| Ubuntu 24.04 beta | `ubuntu-24.04` | [ubuntu-24.04] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fubuntu24.json) | -| Ubuntu 22.04 | `ubuntu-latest` or `ubuntu-22.04` | [ubuntu-22.04] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fubuntu22.json) | -| Ubuntu 20.04 | `ubuntu-20.04` | [ubuntu-20.04] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fubuntu20.json) | -| macOS 14 | `macos-latest-large` or `macos-14-large`| [macOS-14] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fmacos-14.json) | -| macOS 14 Arm64 |`macos-latest`, `macos-14`, `macos-latest-xlarge` or `macos-14-xlarge`| [macOS-14-arm64] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fmacos-14-arm64.json) | -| macOS 13 | `macos-13` or `macos-13-large` | [macOS-13] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fmacos-13.json) | -| macOS 13 Arm64 | `macos-13-xlarge` | [macOS-13-arm64] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fmacos-13-arm64.json) | -| macOS 12 | `macos-12` or `macos-12-large`| [macOS-12] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fmacos-12.json) | -| macOS 11 deprecated | `macos-11`| [macOS-11] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2FmacOS-11.json) | -| Windows Server 2022 | `windows-latest` or `windows-2022` | [windows-2022] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fwin22.json) | -| Windows Server 2019 | `windows-2019` | [windows-2019] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fwin19.json) | +| Image | YAML Label | Included Software | Rollout Status of Latest Image Release | +| ------------------------------ | ---------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Ubuntu 24.04 beta | `ubuntu-24.04` | [ubuntu-24.04] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fubuntu24.json) | +| Ubuntu 22.04 | `ubuntu-latest` or `ubuntu-22.04` | [ubuntu-22.04] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fubuntu22.json) | +| Ubuntu 20.04 | `ubuntu-20.04` | [ubuntu-20.04] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fubuntu20.json) | +| macOS 14 | `macos-latest-large` or `macos-14-large` | [macOS-14] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fmacos-14.json) | +| macOS 14 Arm64 | `macos-latest`, `macos-14`, `macos-latest-xlarge` or `macos-14-xlarge` | [macOS-14-arm64] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fmacos-14-arm64.json) | +| macOS 13 | `macos-13` or `macos-13-large` | [macOS-13] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fmacos-13.json) | +| macOS 13 Arm64 | `macos-13-xlarge` | [macOS-13-arm64] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fmacos-13-arm64.json) | +| macOS 12 | `macos-12` or `macos-12-large` | [macOS-12] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fmacos-12.json) | +| macOS 11 deprecated | `macos-11` | [macOS-11] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2FmacOS-11.json) | +| Windows Server 2022 | `windows-latest` or `windows-2022` | [windows-2022] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fwin22.json) | +| Windows Server 2019 | `windows-2019` | [windows-2019] | ![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fmikhailkoliada%2F35b243dd6e217d041fe3dfa5b4e2e2ed%2Fraw%2Fwin19.json) | ### Label scheme @@ -69,7 +69,7 @@ GA the image must meet the following criteria: 1. Has been through a Beta period (public or private) 2. Most major software we install on the image has a compatible -version for the underlying OS and + version for the underlying OS and 3. All major bugs reported during the Beta period have been addressed. This image type falls under the customer [SLA](https://github.com/customer-terms/github-online-services-sla) for actions. GA images are eventually deprecated according to our guidelines as we only support the @@ -79,22 +79,22 @@ latest 2 versions of an OS. GitHub Actions and Azure DevOps use the `-latest` YAML label (ex: `ubuntu-latest`, `windows-latest`, and `macos-latest`). These labels point towards the newest stable OS version available. - The `-latest` migration process is gradual and happens over 1-2 months in order to allow customers to adapt their workflows to the newest OS version. During this process, any workflow using the `-latest` label, may see changes in the OS version in their workflows or pipelines. To avoid unwanted migration, users can specify a specific OS version in the yaml file (ex: macos-12, windows-2022, ubuntu-22.04). ## Image Releases -*How to best follow along with changes* +_How to best follow along with changes_ 1. Find the latest releases for this repository [here.](https://github.com/actions/runner-images/releases) 2. Subscribe to the releases coming out of this repository, instructions [here.](https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository) 3. Upcoming changes: A pre-release is created when the deployment of an image has started. As soon as the deployment is finished, the pre-release is converted to a release. If you have subscribed to releases, you will get notified of pre-releases as well. - You can also track upcoming changes using the [awaiting-deployment](https://github.com/actions/runner-images/labels/awaiting-deployment) label. + 4. For high impact changes, we will post these in advance to the GitHub Changelog on our [blog](https://github.blog/changelog/) and on [twitter](https://twitter.com/GHchangelog). - Ex: breaking changes, GA or deprecation of images -*Cadence* +_Cadence_ - We typically deploy weekly updates to the software on the runner images. @@ -108,31 +108,32 @@ The `-latest` migration process is gradual and happens over 1-2 months in order - Popular tools can have several versions installed side-by-side with the following strategy: -| Tool name | Installation strategy | -|-----------|-----------------------| -| Docker images | not more than 3 latest LTS OS\tool versions. New images or new versions of current images are added using the standard tool request process | -| Java | all LTS versions | -| Node.js | 3 latest LTS versions | -| Go | 3 latest minor versions | -| Python
Ruby | 5 most popular `major.minor` versions | -| PyPy | 3 most popular `major.minor` versions | -| .NET Core | 2 latest LTS versions and 1 latest version. For each feature version only latest patch is installed | -| GCC
GNU Fortran
Clang
GNU C++ | 3 latest major versions | -| Android NDK | 1 latest non-LTS, 2 latest LTS versions | -| Xcode | - all OS compatible versions side-by-side
- for beta, GM versions - latest beta only
- old patch versions are deprecated in 3 months | +| Tool name | Installation strategy | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| Docker images | not more than 3 latest LTS OS\tool versions. New images or new versions of current images are added using the standard tool request process | +| Java | all LTS versions | +| Node.js | 3 latest LTS versions | +| Go | 3 latest minor versions | +| Python
Ruby | 5 most popular `major.minor` versions | +| PyPy | 3 most popular `major.minor` versions | +| .NET Core | 2 latest LTS versions and 1 latest version. For each feature version only latest patch is installed | +| GCC
GNU Fortran
Clang
GNU C++ | 3 latest major versions | +| Android NDK | 1 latest non-LTS, 2 latest LTS versions | +| Xcode | - all OS compatible versions side-by-side
- for beta, GM versions - latest beta only
- old patch versions are deprecated in 3 months | ### Package managers usage We use third-party package managers to install software during the image generation process. The table below lists the package managers and the software installed. + > **Note**: third-party repositories are re-evaluated every year to identify if they are still useful and secure. -| Operating system | Package manager | Third-party repos and packages | -| :--- | :---: | ---: | -| Ubuntu | [APT](https://wiki.debian.org/Apt) | [containers](https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable) (Ubuntu 20 only)
[docker](https://download.docker.com/linux/ubuntu) (Ubuntu20 0nly)
[Eclipse-Temurin (Adoptium)](https://packages.adoptium.net/artifactory/deb/)
[Erlang](https://packages.erlang-solutions.com/ubuntu)
[Firefox](http://ppa.launchpad.net/mozillateam/ppa/ubuntu)
[git-lfs](https://packagecloud.io/install/repositories/github/git-lfs)
[git](https://launchpad.net/~git-core/+archive/ubuntu/ppa)
[Google Cloud CLI](https://packages.cloud.google.com/apt)
[Heroku](https://cli-assets.heroku.com/channels/stable/apt)
[HHvm](https://dl.hhvm.com/ubuntu)
[MongoDB](https://repo.mongodb.org/apt/ubuntu)
[Mono](https://download.mono-project.com/repo/ubuntu)
[MS Edge](https://packages.microsoft.com/repos/edge)
[PostgreSQL](https://apt.postgresql.org/pub/repos/apt/)
[R](https://cloud.r-project.org/bin/linux/ubuntu) | -| | [pipx](https://pypa.github.io/pipx) | ansible-core
yamllint | -| Windows | [Chocolatey](https://chocolatey.org) | No third-party repos installed | -| macOS | [Homebrew](https://brew.sh) | [aws-cli v2](https://github.com/aws/homebrew-tap)
[azure/bicep](https://github.com/Azure/homebrew-bicep)
[mongodb/brew](https://github.com/mongodb/homebrew-brew) | -| | [pipx](https://pypa.github.io/pipx/) | yamllint | +| Operating system | Package manager | Third-party repos and packages | +| :--------------- | :----------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| Ubuntu | [APT](https://wiki.debian.org/Apt) | [containers](https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable) (Ubuntu 20 only)
[docker](https://download.docker.com/linux/ubuntu) (Ubuntu20 0nly)
[Eclipse-Temurin (Adoptium)](https://packages.adoptium.net/artifactory/deb/)
[Erlang](https://packages.erlang-solutions.com/ubuntu)
[Firefox](http://ppa.launchpad.net/mozillateam/ppa/ubuntu)
[git-lfs](https://packagecloud.io/install/repositories/github/git-lfs)
[git](https://launchpad.net/~git-core/+archive/ubuntu/ppa)
[Google Cloud CLI](https://packages.cloud.google.com/apt)
[Heroku](https://cli-assets.heroku.com/channels/stable/apt)
[HHvm](https://dl.hhvm.com/ubuntu)
[MongoDB](https://repo.mongodb.org/apt/ubuntu)
[Mono](https://download.mono-project.com/repo/ubuntu)
[MS Edge](https://packages.microsoft.com/repos/edge)
[PostgreSQL](https://apt.postgresql.org/pub/repos/apt/)
[R](https://cloud.r-project.org/bin/linux/ubuntu) | +| | [pipx](https://pypa.github.io/pipx) | ansible-core
yamllint | +| Windows | [Chocolatey](https://chocolatey.org) | No third-party repos installed | +| macOS | [Homebrew](https://brew.sh) | [aws-cli v2](https://github.com/aws/homebrew-tap)
[azure/bicep](https://github.com/Azure/homebrew-bicep)
[mongodb/brew](https://github.com/mongodb/homebrew-brew) | +| | [pipx](https://pypa.github.io/pipx/) | yamllint | ### Image Deprecation Policy @@ -170,14 +171,16 @@ In general, these are the guidelines we follow when deciding what to pre-install What images are available for GitHub Actions and Azure DevOps? The availability of images for GitHub Actions and Azure DevOps is the same. However, deprecation policies may differ. See documentation for more details: + - [GitHub Actions](https://docs.github.com/en/free-pro-team@latest/actions/reference/specifications-for-github-hosted-runners#supported-runners-and-hardware-resources) - [Azure DevOps](https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&tabs=yaml#software) - +
What image version is used in my build? Usually, image deployment takes 2-3 days, and documentation in the `main` branch is only updated when deployment is finished. To find out which image version and what software versions are used in a specific build, see `Set up job` (GitHub Actions) or `Initialize job` (Azure DevOps) step log. + actions-runner-image
@@ -185,6 +188,7 @@ Usually, image deployment takes 2-3 days, and documentation in the `main` branch Looking for other Linux distributions? We do not plan to offer other Linux distributions. We recommend using Docker if you'd like to build using other distributions with the hosted runner images. Alternatively, you can leverage [self-hosted runners] and fully customize your VM image to your needs. +
@@ -193,12 +197,14 @@ We do not plan to offer other Linux distributions. We recommend using Docker if macOS source lives in this repository and is available for everyone. However, macOS image-generation CI doesn't support external contributions yet so we are not able to accept pull-requests for now. We are in the process of preparing macOS CI to accept contributions. Until then, we appreciate your patience and ask you to continue to make tool requests by filing issues. +
How does GitHub determine what tools are installed on the images? For some tools, we always install the latest at the time of the deployment; for others, we pin the tool to specific version(s). For more details please see the [Preinstallation Policy](#preinstallation-policy) +
@@ -210,4 +216,4 @@ Please create an issue and get an approval from us to add this tool to the image What branch should I use to build custom image? We strongly encourage customers to build their own images using the main branch. This repository contains multiple branches and releases that serve as document milestones to reflect what software is installed in the images at certain point of time. Current builds are not idempotent and if one tries to build a runner image using the specific tag it is not guaranteed that the build will succeed. -
\ No newline at end of file + diff --git a/tsconfig.json b/tsconfig.json index 4806761..ec60cb2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,110 +1,110 @@ { - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - - /* Modules */ - "module": "es2022", - "moduleResolution": "node", /* Specify what module code is generated. */ - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ - // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ - // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ - // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } - } \ No newline at end of file + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2017" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "es2022", + "moduleResolution": "node" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/utils/streaming.ts b/utils/streaming.ts index 931190e..1f1300f 100644 --- a/utils/streaming.ts +++ b/utils/streaming.ts @@ -1,56 +1,61 @@ import { Readable } from "stream"; -export async function processStream(reader: ReadableStreamDefaultReader, decoder: TextDecoder, contentStream: Readable, statusStream?: Readable): Promise { - let buffer = ''; - let fullContent = ''; - let isStatusStreamOpen = true; - - const processNextChunk = async (): Promise => { - const { done, value } = await reader.read(); - if (done) { - contentStream.push(null); - statusStream?.push(null); - isStatusStreamOpen = false; - return; - } - - buffer += decoder.decode(value, { stream: true }); - const lines = buffer.split('\n'); - - buffer = lines.pop() || ''; - - for (const line of lines) { - if (line.trim()) { - try { - const json = JSON.parse(line); - // t is an abbreviation for "type" - // t:c = content - if (json.messageType === "content") { - if (isStatusStreamOpen) { - statusStream?.push(null); - isStatusStreamOpen = false; - } - - // m is the message - contentStream.push(json.message); - fullContent += json.message; - } - // t:s = status message - else if (json.messageType === "status" && statusStream) { - statusStream.push(line + "\n"); - } - } catch (e) { - console.error('Error parsing JSON:', e); - } +export async function processStream( + reader: ReadableStreamDefaultReader, + decoder: TextDecoder, + contentStream: Readable, + statusStream?: Readable, +): Promise { + let buffer = ""; + let fullContent = ""; + let isStatusStreamOpen = true; + + const processNextChunk = async (): Promise => { + const { done, value } = await reader.read(); + if (done) { + contentStream.push(null); + statusStream?.push(null); + isStatusStreamOpen = false; + return; + } + + buffer += decoder.decode(value, { stream: true }); + const lines = buffer.split("\n"); + + buffer = lines.pop() || ""; + + for (const line of lines) { + if (line.trim()) { + try { + const json = JSON.parse(line); + // t is an abbreviation for "type" + // t:c = content + if (json.messageType === "content") { + if (isStatusStreamOpen) { + statusStream?.push(null); + isStatusStreamOpen = false; } + + // m is the message + contentStream.push(json.message); + fullContent += json.message; + } + // t:s = status message + else if (json.messageType === "status" && statusStream) { + statusStream.push(line + "\n"); + } + } catch (e) { + console.error("Error parsing JSON:", e); } + } + } - await processNextChunk(); - }; + await processNextChunk(); + }; - await processNextChunk().catch((error) => { - contentStream.emit('error', error); - }); + await processNextChunk().catch((error) => { + contentStream.emit("error", error); + }); - return fullContent; -} \ No newline at end of file + return fullContent; +}